package main import ( "errors" "fmt" "os" "path/filepath" "strings" "go.wit.com/dev/alexflint/arg" "go.wit.com/lib/gui/shell" "go.wit.com/lib/protobuf/forgepb" "go.wit.com/lib/protobuf/gitpb" "go.wit.com/log" ) // sent via -ldflags var VERSION string var BUILDTIME string var pp *arg.Parser var forge *forgepb.Forge var check *gitpb.Repo func main() { log.Info("go-clean version", VERSION, "built on", BUILDTIME) pp = arg.MustParse(&argv) // load the ~/.config/forge/ config // this lets you configure repos you have read/write access too forge = forgepb.Init() // rescan just in case (?) todo: decide what forge should default too forge.ScanGoSrc() // figure out what directory we are running in check = findPwdRepo() if check == nil { log.Info("this directory isn't in a golang project (not in ~/go/src nor a go.work file)") os.Exit(-1) } log.Info("starting go-clean for", check.GoPath) log.Info("go src dir is set to", forge.GetGoSrc()) if argv.Recursive { if forge.IsGoWork() { var warning []string warning = append(warning, "go-clean --recursive may not work unless you are in ~/go/src") warning = append(warning, "you can continue anyway, but it hasn't been tested as much.") simpleStdin(true, warning) } var warning []string warning = append(warning, "go-clean will recreate go.mod and go.sum") warning = append(warning, "because you have selected --recursive") warning = append(warning, "this will redo _every_ repo. This is probably fine.") warning = append(warning, fmt.Sprintf("You have %d total repositories in %s", forge.Repos.Len(), forge.GetGoSrc())) warning = append(warning, "") warning = append(warning, "However, this will also do:") warning = append(warning, "") warning = append(warning, "rm -rf ~/go/pkg/") warning = append(warning, "rm -rf ~/.config/go-build/") warning = append(warning, "") warning = append(warning, "Which is also probably fine, but will clear all your build cache and go mod cache") warning = append(warning, "") simpleStdin(false, warning) purgeGoCaches() } else { simpleStdin(true, []string{"go-clean will recreate go.mod and go.sum"}) } // re-create go.sum and go.mod if _, err := check.RedoGoMod(); err != nil { badExit(err) } /* // re-process go deps deps := check.GoDeps.SortByGoPath() for deps.Scan() { depRepo := deps.Next() log.Info("check has dep:", depRepo.GoPath) } */ // check go.sum file if forge.FinalGoDepsCheckOk(check) { log.Info("forge.FinalGoDepsCheck() worked :", check.GoPath) okExit(check.GoPath + " go.sum seems clean") } log.Info("forge.FinalGoDepsCheck() failed. boo. :", check.GoPath) badExit(errors.New(check.GoPath + " go.sum is not perfect")) } func findPwdRepo() *gitpb.Repo { var check *gitpb.Repo // attempt to use the working directory // this is probably what happens most of the time pwd, _ := os.Getwd() if strings.HasPrefix(pwd, forge.GetGoSrc()) { gopath := strings.TrimPrefix(pwd, forge.GetGoSrc()) gopath = strings.Trim(gopath, "/") log.Info("findRepo() trying gopath", gopath) check = forge.Repos.FindByGoPath(gopath) if check != nil { log.Info("findRepo() worked", check.GoPath) return check } } return nil } func okExit(thing string) { log.Info(thing, "ok") log.Info("Finished go-clean on", check.GetGoPath(), "ok") os.Exit(0) } func badExit(err error) { log.Info("Finished go-clean with error", err, forge.GetGoSrc()) os.Exit(-1) } func purgeGoCaches() { homedir, err := os.UserHomeDir() if err != nil { badExit(err) } pkgdir := filepath.Join(homedir, "go/pkg") var cmd []string cmd = []string{"chmod", "700", "-R", pkgdir} runStrict("", cmd) cmd = []string{"rm", "-rf", pkgdir} runStrict("", cmd) builddir := filepath.Join(homedir, ".cache/go-build") cmd = []string{"rm", "-rf", builddir} runStrict("", cmd) // this can't have really happened // echo this still failed in: // echo "Linux hpdev2.grid.wit.com 6.9.8-rt-amd64 #1 SMP PREEMPT_RT Debian 6.9.8-1 (2024-07-07) x86_64 GNU/Linux" // echo and I had to drop the caches after building go install binaries quickly and running them // echo "as an os.Exec() between binaries" // echo sysctl -w vm.drop_caches=3 } func runStrict(wd string, cmd []string) { var err error if wd != "" { if err = os.Chdir(wd); err != nil { log.Info("cd", "wd", "failed", err) badExit(err) } } log.Info(wd, "running:", wd, cmd) // result := shell.Run(cmd) result := shell.RunRealtime(cmd) if result.Error != nil { log.Info("cmd failed", wd, cmd, err) for i, line := range result.Stdout { log.Info("STDOUT:", i, line) } for i, line := range result.Stderr { log.Info("STDERR:", i, line) } badExit(err) } if result.Exit != 0 { log.Info("cmd failed", wd, cmd, err) for i, line := range result.Stdout { log.Info("STDOUT:", i, line) } for i, line := range result.Stderr { log.Info("STDERR:", i, line) } badExit(errors.New(fmt.Sprintf("cmd failed with %d", result.Exit))) } for i, line := range result.Stdout { log.Info(i, line) } }