Skip to content

Instantly share code, notes, and snippets.

@rodkranz
Last active March 27, 2020 11:24
Show Gist options
  • Save rodkranz/f11b24b9c38ca46261a90587b54e99b9 to your computer and use it in GitHub Desktop.
Save rodkranz/f11b24b9c38ca46261a90587b54e99b9 to your computer and use it in GitHub Desktop.
Update all git repository in subfolders.
package main
import (
"flag"
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"runtime"
"strings"
"sync"
"time"
log "github.com/sirupsen/logrus"
)
const (
targetName = ".git"
version = "1.0"
)
var (
verbose bool
debugMode bool
dir string
cpus int
ver bool
)
type Update struct {
Path string
File os.FileInfo
}
func init() {
flag.IntVar(&cpus, "cpus", runtime.NumCPU(), "Number of process running.")
flag.BoolVar(&verbose, "verbose", false, "Enable verbose mode.")
flag.BoolVar(&debugMode, "debug", false, "Enable debug mode.")
flag.StringVar(&dir, "dir", path.Dir(os.Args[0]), "Directory to search the '"+targetName+"' folder.")
flag.BoolVar(&ver, "v", false, "prints current roxy version")
flag.Parse()
runtime.GOMAXPROCS(cpus)
log.SetLevel(log.InfoLevel)
if debugMode {
log.SetLevel(log.DebugLevel)
}
}
func main() {
if ver {
log.Infof("current version of gitupdate is [%s].", version)
os.Exit(0)
}
log.Info("welcome to git update automatic.")
log.Infof("walking intro %s.", dir)
timeStart := time.Now()
var wg sync.WaitGroup
wg.Add(cpus)
stream := make(chan Update)
if err := filepath.Walk(dir, search(&wg, stream)); err != nil {
log.Errorf("error execute in dir: %s.", err.Error())
}
close(stream)
wg.Wait()
timeEnd := time.Since(timeStart)
log.Infof("[took: %v] finished.", timeEnd)
}
func update(wg *sync.WaitGroup, in chan Update, i int) {
defer wg.Done()
for up := range in {
gitPath := path.Dir(up.Path)
if verbose {
log.Infof("[%d] updating [%s] at [%s].", i, up.File.Name(), gitPath)
}
cmdArgs := []string{"--work-tree=" + gitPath, "--git-dir=" + gitPath + "/" + up.File.Name(), "fetch", "--all"} // Git 1.7
if debugMode {
log.Debugf("[%d] executing git command: [git %s].", i, strings.Join(cmdArgs, " "))
}
timeStart := time.Now()
output, err := exec.Command("git", cmdArgs...).Output()
timeEnd := time.Since(timeStart)
if err != nil {
log.Errorf("[%d] could not update [%s] because: %s.", i, path.Base(gitPath), err)
log.Errorf("[%d] could not update [%s] output: %s.", i, path.Base(gitPath), output)
if verbose {
log.Errorf("[%d] [took: %v] [%s] has been NOT updated -> [path: %s].", i, timeEnd, path.Base(gitPath), gitPath)
} else {
log.Errorf("[%d] [took: %v] [%s] has been NOT updated.", i, timeEnd, path.Base(gitPath))
}
continue
}
if verbose {
log.Infof("[%d] [took: %v] [%s] has been updated -> [path: %s].\n", i, timeEnd, path.Base(gitPath), gitPath)
} else {
log.Infof("[%d] [took: %v] [%s] has been updated.\n", i, timeEnd, path.Base(gitPath))
}
}
}
func search(wg *sync.WaitGroup, stream chan Update) func(p string, f os.FileInfo, err error) error {
for i := 0; i < cpus; i++ {
go update(wg, stream, i)
}
return func(p string, f os.FileInfo, err error) error {
if err != nil {
return fmt.Errorf("search func failed: %s", err)
}
if !f.IsDir() {
if verbose {
log.Infof("[w] file ignored [%s].", p+f.Name())
}
return nil
}
if !strings.EqualFold(f.Name(), targetName) {
if verbose {
log.Infof("[w] dir ignored [%s] at [%s].", f.Name(), p)
}
return nil
}
stream <- Update{
Path: p,
File: f,
}
return nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment