From 567ab899e0b0147cb8a81247c4b2a162086d8839 Mon Sep 17 00:00:00 2001 From: Tai Groot Date: Fri, 2 Feb 2024 13:29:27 -0800 Subject: [PATCH] fix conflict --- cmd/mg/cmd/clone.go | 93 +++++++++++++++++++++++++++++++++++++++++++++ parse/mgconf.go | 3 +- parse/myrepos.go | 3 +- 3 files changed, 95 insertions(+), 4 deletions(-) create mode 100644 cmd/mg/cmd/clone.go diff --git a/cmd/mg/cmd/clone.go b/cmd/mg/cmd/clone.go new file mode 100644 index 0000000..0d80adb --- /dev/null +++ b/cmd/mg/cmd/clone.go @@ -0,0 +1,93 @@ +package cmd + +import ( + "fmt" + "log" + "os" + "sync" + + git "github.com/go-git/go-git/v5" + "github.com/spf13/cobra" + + "github.com/taigrr/mg/parse" +) + +// pullCmd represents the pull command +var ( + cloneCmd = &cobra.Command{ + Use: "clone", + Short: "ensure all repos defined in the config are cloned", + Run: func(_ *cobra.Command, args []string) { + type RepoError struct { + Error error + Repo string + } + if jobs < 1 { + log.Println("jobs must be greater than 0") + os.Exit(1) + } + conf := GetConfig() + if len(args) > 0 { + log.Println("too many arguments") + os.Exit(1) + } + repoChan := make(chan parse.Repo, len(conf.Repos)) + errs := []RepoError{} + alreadyUpToDate := 0 + mutex := sync.Mutex{} + wg := sync.WaitGroup{} + wg.Add(len(conf.Repos)) + for i := 0; i < jobs; i++ { + go func() { + for repo := range repoChan { + _, err := git.PlainOpenWithOptions(repo.Remote, &(git.PlainOpenOptions{DetectDotGit: true})) + if err == nil { + log.Printf("already cloned: %s\n", repo.Path) + } else if err == git.ErrRepositoryNotExists { + log.Printf("attempting clone: %s\n", repo) + _, err := git.PlainClone(repo.Path, false, &git.CloneOptions{ + URL: repo.Remote, + }) + if err != nil { + mutex.Lock() + errs = append(errs, RepoError{Error: err, Repo: repo.Path}) + mutex.Unlock() + log.Printf("clone failed for %s: %v\n", repo.Path, err) + wg.Done() + continue + } + fmt.Printf("successfully cloned %s\n", repo) + wg.Done() + continue + } else { + mutex.Lock() + errs = append(errs, RepoError{Error: err, Repo: repo.Path}) + mutex.Unlock() + log.Printf("clone failed for %s: %v\n", repo, err) + wg.Done() + continue + } + } + }() + } + for _, repo := range conf.Repos { + repoChan <- repo + } + close(repoChan) + wg.Wait() + for _, err := range errs { + log.Printf("error pulling %s: %s\n", err.Repo, err.Error) + } + lenErrs := len(errs) + fmt.Println() + fmt.Printf("successfully pulled %d/%d repos\n", len(conf.Repos)-lenErrs, len(conf.Repos)) + fmt.Printf("%d repos already up to date\n", alreadyUpToDate) + fmt.Printf("failed to pull %d/%d repos\n", lenErrs, len(conf.Repos)) + }, + } +) + +func init() { + rootCmd.AddCommand(pullCmd) + pullCmd.Flags().IntVarP(&jobs, "jobs", "j", 1, "number of jobs to run in parallel") +} diff --git a/parse/mgconf.go b/parse/mgconf.go index 7ac6b3a..efba968 100644 --- a/parse/mgconf.go +++ b/parse/mgconf.go @@ -3,7 +3,6 @@ package parse import ( "encoding/json" "fmt" - "io/ioutil" "os" "path/filepath" ) @@ -138,5 +137,5 @@ func (m MGConfig) Save() error { if err != nil { return err } - return ioutil.WriteFile(mgConf, b, 0o644) + return os.WriteFile(mgConf, b, 0o644) } diff --git a/parse/myrepos.go b/parse/myrepos.go index 99ae675..8559b07 100644 --- a/parse/myrepos.go +++ b/parse/myrepos.go @@ -3,7 +3,6 @@ package parse import ( "errors" "fmt" - "io/ioutil" "os" "path/filepath" "strings" @@ -60,7 +59,7 @@ func LoadMRConfig() (MRConfig, error) { if s.IsDir() { return MRConfig{}, errors.New("expected mrconfig file but got a directory") } - f, err := ioutil.ReadFile(mrconfPath) + f, err := os.ReadFile(mrconfPath) if err != nil { return MRConfig{}, err }