// RemoveRepo removes go-gettable repo with no local changes (by moving it into trash). // importPathPattern must match exactly with the repo root. // For example, "github.com/user/repo/...". func RemoveRepo(importPathPattern string) error { // TODO: Use an official Go package for `go list` functionality whenever possible. importPaths := gotool.ImportPaths([]string{importPathPattern}) if len(importPaths) == 0 { return errors.New("no packages to remove") } var firstGoPackage *gist7480523.GoPackage for i, importPath := range importPaths { goPackage := gist7480523.GoPackageFromImportPath(importPath) if goPackage == nil { return errors.New("Import Path not found: " + importPath) } if goPackage.Bpkg.Goroot { return errors.New("can't remove packages from GOROOT") } goPackage.UpdateVcs() if goPackage.Dir.Repo == nil { return errors.New("can't get repo status") } if i == 0 { firstGoPackage = goPackage } else if firstGoPackage.Dir.Repo != goPackage.Dir.Repo { return errors.New("matched Go Packages span more than 1 repo: " + firstGoPackage.Dir.Repo.Vcs.RootPath() + " != " + goPackage.Dir.Repo.Vcs.RootPath()) } else if !strings.HasPrefix(goPackage.Bpkg.Dir, firstGoPackage.Dir.Repo.Vcs.RootPath()) { // TODO: This is probably not neccessary... return errors.New("Go Package not inside repo: " + goPackage.Bpkg.Dir + " doesn't have prefix " + firstGoPackage.Dir.Repo.Vcs.RootPath()) } } if repoImportPathPattern := gist7480523.GetRepoImportPathPattern(firstGoPackage.Dir.Repo.Vcs.RootPath(), firstGoPackage.Bpkg.SrcRoot); repoImportPathPattern != importPathPattern { return errors.New("importPathPattern not exact repo root match: " + importPathPattern + " != " + repoImportPathPattern) } firstGoPackage.UpdateVcsFields() cleanStatus := func(goPackage *gist7480523.GoPackage) bool { packageStatus := status.PlumbingPresenterV2(goPackage)[:4] return packageStatus == " " || packageStatus == " + " // Updates are okay to ignore. } if !cleanStatus(firstGoPackage) { return errors.New("non-clean status: " + status.PorcelainPresenter(firstGoPackage)) } err := trash.MoveTo(firstGoPackage.Dir.Repo.Vcs.RootPath()) return err // TODO: Clean up /pkg folder contents, if any, etc. }
func main() { runtime.GOMAXPROCS(runtime.NumCPU()) flag.Usage = usage flag.Parse() // Get current directory. wd, err := os.Getwd() if err != nil { panic(err) } shouldShow := func(goPackage *gist7480523.GoPackage) bool { // Check for notable status. return status.PorcelainPresenter(goPackage)[:4] != " " } if *vFlag == true { shouldShow = func(_ *gist7480523.GoPackage) bool { return true } } var presenter gist7480523.GoPackageStringer = status.PorcelainPresenter if *debugFlag == true { presenter = status.DebugPresenter } else if *plumbingFlag == true { presenter = status.PlumbingPresenter } // A map of repos that have been checked, to avoid doing same repo more than once. var lock sync.Mutex checkedRepos := map[string]bool{} // Input: Go package Import Path // Output: If a valid Go package and not inside GOROOT, output a status string, else nil. reduceFunc := func(in string) interface{} { goPackage, err := gist7480523.GoPackageFromPath(in, wd) if err != nil { fmt.Fprintf(os.Stderr, "can't load package: %s\n", err) return nil } if goPackage == nil { return nil } if goPackage.Bpkg.Goroot { return nil } goPackage.UpdateVcs() // Check that the same repo hasn't already been done. if goPackage.Dir.Repo != nil { rootPath := goPackage.Dir.Repo.Vcs.RootPath() lock.Lock() if !checkedRepos[rootPath] { checkedRepos[rootPath] = true lock.Unlock() } else { lock.Unlock() // Skip repos that were done. return nil } } goPackage.UpdateVcsFields() if shouldShow(goPackage) == false { return nil } return presenter(goPackage) } // Run reduceFunc on all import paths in parallel. var outChan <-chan interface{} switch *stdinFlag { case false: importPathPatterns := flag.Args() importPaths := gotool.ImportPaths(importPathPatterns) outChan = gist7651991.GoReduceLinesFromSlice(importPaths, numWorkers, reduceFunc) case true: outChan = gist7651991.GoReduceLinesFromReader(os.Stdin, numWorkers, reduceFunc) } // Output results. for out := range outChan { fmt.Println(out.(string)) } }