Skip to content

Commit 8b6ded6

Browse files
authored
Merge pull request go-git#1008 from smola/clone-cleanup
cleanup after failed clone
2 parents dfd6c82 + 3332e8d commit 8b6ded6

File tree

2 files changed

+156
-6
lines changed

2 files changed

+156
-6
lines changed

Diff for: repository.go

+71-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"errors"
77
"fmt"
8+
"io"
89
stdioutil "io/ioutil"
910
"os"
1011
"path"
@@ -342,12 +343,22 @@ func PlainClone(path string, isBare bool, o *CloneOptions) (*Repository, error)
342343
//
343344
// TODO(mcuadros): move isBare to CloneOptions in v5
344345
func PlainCloneContext(ctx context.Context, path string, isBare bool, o *CloneOptions) (*Repository, error) {
346+
dirExists, err := checkExistsAndIsEmptyDir(path)
347+
if err != nil {
348+
return nil, err
349+
}
350+
345351
r, err := PlainInit(path, isBare)
346352
if err != nil {
347353
return nil, err
348354
}
349355

350-
return r, r.clone(ctx, o)
356+
err = r.clone(ctx, o)
357+
if err != nil && err != ErrRepositoryAlreadyExists {
358+
cleanUpDir(path, !dirExists)
359+
}
360+
361+
return r, err
351362
}
352363

353364
func newRepository(s storage.Storer, worktree billy.Filesystem) *Repository {
@@ -358,6 +369,65 @@ func newRepository(s storage.Storer, worktree billy.Filesystem) *Repository {
358369
}
359370
}
360371

372+
func checkExistsAndIsEmptyDir(path string) (exists bool, err error) {
373+
fi, err := os.Stat(path)
374+
if err != nil {
375+
if os.IsNotExist(err) {
376+
return false, nil
377+
}
378+
379+
return false, err
380+
}
381+
382+
if !fi.IsDir() {
383+
return false, fmt.Errorf("path is not a directory: %s", path)
384+
}
385+
386+
f, err := os.Open(path)
387+
if err != nil {
388+
return false, err
389+
}
390+
391+
defer ioutil.CheckClose(f, &err)
392+
393+
_, err = f.Readdirnames(1)
394+
if err == io.EOF {
395+
return true, nil
396+
}
397+
398+
if err != nil {
399+
return true, err
400+
}
401+
402+
return true, fmt.Errorf("directory is not empty: %s", path)
403+
}
404+
405+
func cleanUpDir(path string, all bool) error {
406+
if all {
407+
return os.RemoveAll(path)
408+
}
409+
410+
f, err := os.Open(path)
411+
if err != nil {
412+
return err
413+
}
414+
415+
defer ioutil.CheckClose(f, &err)
416+
417+
names, err := f.Readdirnames(-1)
418+
if err != nil {
419+
return err
420+
}
421+
422+
for _, name := range names {
423+
if err := os.RemoveAll(filepath.Join(path, name)); err != nil {
424+
return err
425+
}
426+
}
427+
428+
return nil
429+
}
430+
361431
// Config return the repository config
362432
func (r *Repository) Config() (*config.Config, error) {
363433
return r.Storer.Config()

Diff for: repository_test.go

+85-5
Original file line numberDiff line numberDiff line change
@@ -581,14 +581,94 @@ func (s *RepositorySuite) TestPlainCloneWithRemoteName(c *C) {
581581
c.Assert(remote, NotNil)
582582
}
583583

584-
func (s *RepositorySuite) TestPlainCloneContext(c *C) {
584+
func (s *RepositorySuite) TestPlainCloneContextWithProperParameters(c *C) {
585585
ctx, cancel := context.WithCancel(context.Background())
586586
cancel()
587587

588-
_, err := PlainCloneContext(ctx, c.MkDir(), false, &CloneOptions{
588+
r, err := PlainCloneContext(ctx, c.MkDir(), false, &CloneOptions{
589589
URL: s.GetBasicLocalRepositoryURL(),
590590
})
591591

592+
c.Assert(r, NotNil)
593+
c.Assert(err, NotNil)
594+
}
595+
596+
func (s *RepositorySuite) TestPlainCloneContextNonExistentWithExistentDir(c *C) {
597+
ctx, cancel := context.WithCancel(context.Background())
598+
cancel()
599+
600+
tmpDir := c.MkDir()
601+
repoDir := tmpDir
602+
603+
r, err := PlainCloneContext(ctx, repoDir, false, &CloneOptions{
604+
URL: "incorrectOnPurpose",
605+
})
606+
c.Assert(r, NotNil)
607+
c.Assert(err, NotNil)
608+
609+
_, err = os.Stat(repoDir)
610+
c.Assert(os.IsNotExist(err), Equals, false)
611+
612+
names, err := ioutil.ReadDir(repoDir)
613+
c.Assert(err, IsNil)
614+
c.Assert(names, HasLen, 0)
615+
}
616+
617+
func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNonExistentDir(c *C) {
618+
ctx, cancel := context.WithCancel(context.Background())
619+
cancel()
620+
621+
tmpDir := c.MkDir()
622+
repoDir := filepath.Join(tmpDir, "repoDir")
623+
624+
r, err := PlainCloneContext(ctx, repoDir, false, &CloneOptions{
625+
URL: "incorrectOnPurpose",
626+
})
627+
c.Assert(r, NotNil)
628+
c.Assert(err, NotNil)
629+
630+
_, err = os.Stat(repoDir)
631+
c.Assert(os.IsNotExist(err), Equals, true)
632+
}
633+
634+
func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNotDir(c *C) {
635+
ctx, cancel := context.WithCancel(context.Background())
636+
cancel()
637+
638+
tmpDir := c.MkDir()
639+
repoDir := filepath.Join(tmpDir, "repoDir")
640+
f, err := os.Create(repoDir)
641+
c.Assert(err, IsNil)
642+
c.Assert(f.Close(), IsNil)
643+
644+
r, err := PlainCloneContext(ctx, repoDir, false, &CloneOptions{
645+
URL: "incorrectOnPurpose",
646+
})
647+
c.Assert(r, IsNil)
648+
c.Assert(err, NotNil)
649+
650+
fi, err := os.Stat(repoDir)
651+
c.Assert(err, IsNil)
652+
c.Assert(fi.IsDir(), Equals, false)
653+
}
654+
655+
func (s *RepositorySuite) TestPlainCloneContextNonExistentWithNotEmptyDir(c *C) {
656+
ctx, cancel := context.WithCancel(context.Background())
657+
cancel()
658+
659+
tmpDir := c.MkDir()
660+
repoDirPath := filepath.Join(tmpDir, "repoDir")
661+
err := os.Mkdir(repoDirPath, 0777)
662+
c.Assert(err, IsNil)
663+
664+
dummyFile := filepath.Join(repoDirPath, "dummyFile")
665+
err = ioutil.WriteFile(dummyFile, []byte(fmt.Sprint("dummyContent")), 0644)
666+
c.Assert(err, IsNil)
667+
668+
r, err := PlainCloneContext(ctx, repoDirPath, false, &CloneOptions{
669+
URL: "incorrectOnPurpose",
670+
})
671+
c.Assert(r, IsNil)
592672
c.Assert(err, NotNil)
593673
}
594674

@@ -2104,9 +2184,9 @@ func (s *RepositorySuite) TestResolveRevisionWithErrors(c *C) {
21042184
c.Assert(err, IsNil)
21052185

21062186
datas := map[string]string{
2107-
"efs/heads/master~": "reference not found",
2108-
"HEAD^3": `Revision invalid : "3" found must be 0, 1 or 2 after "^"`,
2109-
"HEAD^{/whatever}": `No commit message match regexp : "whatever"`,
2187+
"efs/heads/master~": "reference not found",
2188+
"HEAD^3": `Revision invalid : "3" found must be 0, 1 or 2 after "^"`,
2189+
"HEAD^{/whatever}": `No commit message match regexp : "whatever"`,
21102190
"4e1243bd22c66e76c2ba9eddc1f91394e57f9f83": "reference not found",
21112191
"918c48b83bd081e863dbe1b80f8998f058cd8294": `refname "918c48b83bd081e863dbe1b80f8998f058cd8294" is ambiguous`,
21122192
}

0 commit comments

Comments
 (0)