diff --git a/pkg/git/clone.go b/pkg/git/clone.go index 789f9a04..c0197728 100644 --- a/pkg/git/clone.go +++ b/pkg/git/clone.go @@ -1,8 +1,11 @@ package git import ( + "fmt" "os" + "os/signal" "strings" + "syscall" "coopcloud.tech/abra/pkg/log" "github.com/go-git/go-git/v5" @@ -24,44 +27,63 @@ func gitCloneIgnoreErr(err error) bool { // Clone runs a git clone which accounts for different default branches. func Clone(dir, url string) error { - if _, err := os.Stat(dir); os.IsNotExist(err) { - log.Debugf("git clone: %s", url) + sigIntCh := make(chan os.Signal) + signal.Notify(sigIntCh, os.Interrupt, syscall.SIGTERM) + defer signal.Stop(sigIntCh) - _, err := git.PlainClone(dir, false, &git.CloneOptions{ - URL: url, - Tags: git.AllTags, - ReferenceName: plumbing.ReferenceName("refs/heads/main"), - SingleBranch: true, - }) + errCh := make(chan error) - if err != nil && gitCloneIgnoreErr(err) { - log.Debugf("git clone: %s cloned successfully", dir) - return nil - } - - if err != nil { - log.Debug("git clone: main branch failed, attempting master branch") + go func() { + if _, err := os.Stat(dir); os.IsNotExist(err) { + log.Debugf("git clone: %s", url) _, err := git.PlainClone(dir, false, &git.CloneOptions{ URL: url, Tags: git.AllTags, - ReferenceName: plumbing.ReferenceName("refs/heads/master"), + ReferenceName: plumbing.ReferenceName("refs/heads/main"), SingleBranch: true, }) if err != nil && gitCloneIgnoreErr(err) { log.Debugf("git clone: %s cloned successfully", dir) - return nil + errCh <- nil } if err != nil { - return err - } - } + log.Debug("git clone: main branch failed, attempting master branch") - log.Debugf("git clone: %s cloned successfully", dir) - } else { - log.Debugf("git clone: %s already exists", dir) + _, err := git.PlainClone(dir, false, &git.CloneOptions{ + URL: url, + Tags: git.AllTags, + ReferenceName: plumbing.ReferenceName("refs/heads/master"), + SingleBranch: true, + }) + + if err != nil && gitCloneIgnoreErr(err) { + log.Debugf("git clone: %s cloned successfully", dir) + errCh <- nil + } + + if err != nil { + errCh <- err + } + } + + log.Debugf("git clone: %s cloned successfully", dir) + } else { + log.Debugf("git clone: %s already exists", dir) + } + }() + + select { + case <-sigIntCh: + fmt.Println() // NOTE(d1): newline after ^C + if err := os.RemoveAll(dir); err != nil { + return fmt.Errorf("unable to clean up git clone of %s: %s", url, err) + } + return fmt.Errorf("git clone %s: cancelled due to interrupt", url) + case err := <-errCh: + return err } return nil diff --git a/pkg/git/clone_test.go b/pkg/git/clone_test.go new file mode 100644 index 00000000..d97461db --- /dev/null +++ b/pkg/git/clone_test.go @@ -0,0 +1,9 @@ +package git + +import ( + "testing" +) + +func TestCancelGitClone(t *testing.T) { + // TODO +}