summaryrefslogtreecommitdiff
path: root/doClean.go
diff options
context:
space:
mode:
Diffstat (limited to 'doClean.go')
-rw-r--r--doClean.go166
1 files changed, 140 insertions, 26 deletions
diff --git a/doClean.go b/doClean.go
index a1c6275..7a04cac 100644
--- a/doClean.go
+++ b/doClean.go
@@ -10,41 +10,129 @@ import (
)
var ErrorReposHasLocalBranches error = fmt.Errorf("repo still has local branches")
+var ErrorMergeBranch error = fmt.Errorf("trunk has things not in the branch")
+var ErrorMergeTrunk error = fmt.Errorf("branch has things not in trunk")
func doClean() error {
- if err := IsEverythingOnMaster(); err != nil {
- log.Info("Not all repos are on the master branch")
- // return err
+ if argv.Clean.Devel != nil {
+ if err := doCleanDevel(); err != nil {
+ badExit(err)
+ }
+ log.Info("finished attempt at cleaning devel branches")
+ return nil
+ }
+ if argv.Clean.User != nil {
+ if err := doCleanUser(); err != nil {
+ log.Info(err)
+ okExit("")
+ }
+ return nil
}
+ return nil
+}
+func doCleanUser() error {
all := me.forge.Repos.SortByFullPath()
for all.Scan() {
repo := all.Next()
- if repo.GetCurrentBranchName() != repo.GetMasterBranchName() {
- // skip this while in devel
- continue
+ if _, count, err := IsEverythingOnMaster(); err != nil {
+ if count == 0 {
+ log.Info("No repos are on the master branch")
+ return nil
+ }
+ log.Info("Not all repos are on the master branch")
+ // return err
+ }
+
+ if err := doCleanUserRepo(repo); err != nil {
+ log.Info(repo.GetGoPath(), err)
+ return err
+ }
+ }
+ return nil
+}
+
+func doCleanDevel() error {
+ var total int
+ var count int
+ all := me.forge.Repos.SortByFullPath()
+ for all.Scan() {
+ repo := all.Next()
+ if argv.Verbose {
+ log.Info("Cleaning:", repo.GetGoPath())
+ }
+ total += 1
+ if repo.GetCurrentBranchName() != repo.GetDevelBranchName() {
+ // only process branches in devel
+ // return nil
}
if repo.IsDirty() {
- continue
+ return nil
}
- if err := doCleanRepo(repo); err != nil {
+ count += 1
+ if err := doCleanDevelRepo(repo); err != nil {
log.Info(repo.GetGoPath(), err)
- okExit("")
+ return err
+ }
+ }
+ log.Printf("attempted cleaning %d branches of %d total branches\n", count, total)
+ return nil
+}
+
+func doCleanDevelRepo(repo *gitpb.Repo) error {
+ devel := repo.GetDevelBranchName()
+ // log.Printf("%s Start verify devel branch: %s\n", repo.GetGoPath(), devel)
+
+ // check if devel branch exists in remote repo
+ if repo.Exists(filepath.Join(".git/refs/remotes/origin", devel)) {
+ remote := filepath.Join("origin", devel)
+ if err := isBranchSubsetOfTrunk(repo, devel, remote); err != nil {
+ if err == ErrorMergeBranch {
+ log.Info("can not do this yet. need push to upstream", repo.GetGoPath())
+ return nil
+ }
+ return err
}
+ // log.Info("todo: verify against remote devel branch", repo.GetGoPath())
}
- log.Info("All repos on the master branch are clean")
+
+ // verify devel branch is subset of master branch
+ master := repo.GetMasterBranchName()
+ if err := isBranchSubsetOfTrunk(repo, devel, master); err != nil {
+ if err == ErrorMergeBranch {
+ if argv.Force {
+ if repo.GetCurrentBranchName() == devel {
+ cmd := []string{"git", "merge", master}
+ // only run this if branch is local
+ _, err := repo.RunVerbose(cmd)
+ return err
+ } else {
+ cmd := []string{"git", "merge", master}
+ log.Info("can't run. on wrong branch.", cmd, repo.GetGoPath(), "current branch =", repo.GetCurrentBranchName())
+ }
+ }
+ return nil
+ }
+ return err
+ }
+ // log.Info("todo: verify against remote devel branch", repo.GetGoPath())
+
return nil
}
// removes all local branches
-func doCleanRepo(repo *gitpb.Repo) error {
+func doCleanUserRepo(repo *gitpb.Repo) error {
var hasLocal bool
- if argv.Verbose {
- log.Info("Cleaning:", repo.GetGoPath())
- }
if repo.GitConfig == nil {
return fmt.Errorf("GitConfig == nil")
}
+ if repo.GetCurrentBranchName() != repo.GetMasterBranchName() {
+ // skip this while in devel
+ return nil
+ }
+ if repo.IsDirty() {
+ return nil
+ }
for _, l := range repo.GitConfig.Local {
log.Info("\tlocal branch name:", l.Name)
@@ -83,13 +171,9 @@ func doCleanRepo(repo *gitpb.Repo) error {
continue
}
if name == repo.GetDevelBranchName() {
- /*
- if err := doCleanDevelBranch(repo, b); err != nil {
- log.Info("\tLOCAL BRANCH ERROR devel")
- return err
- }
- log.Info("\tLOCAL BRANCH devel")
- */
+ continue
+ }
+ if name == repo.GetMasterBranchName() {
continue
}
if err := verifyLocalBranchIsMerged(repo, b); err != nil {
@@ -150,11 +234,6 @@ func verifyLocalBranchIsMerged(repo *gitpb.Repo, branch *gitpb.GitBranch) error
return err
}
-func doCleanDevelBranch(repo *gitpb.Repo, branch *gitpb.GitBranch) error {
- log.Printf("\tDo something %s on branch name:%s merge:%s remote:%s\n", repo.GetGoPath(), branch.Name, branch.Merge, branch.Remote)
- return nil
-}
-
func doCleanUserBranch(repo *gitpb.Repo, branch *gitpb.GitBranch) error {
if branch.Name != repo.GetUserBranchName() {
return fmt.Errorf("repo %s was not user branch %s", repo.GetGoPath(), branch.Name)
@@ -364,3 +443,38 @@ func BADforceDeleteBranch(repo *gitpb.Repo, branch string) error {
// return fmt.Errorf("one at a time %s", repo.GetGoPath())
return nil
}
+
+// verifies that the branch is a pure subset of the other branch
+// sorry about the 'master' 'slave' nameing thing. I guess that isn't
+// 'cool' to use anymore. I can't think of other terms that aren't reserved words.
+func isBranchSubsetOfTrunk(repo *gitpb.Repo, branch string, trunk string) error {
+ b1 := countGitDiffLog(repo, branch, trunk) // should be zero
+ b2 := countGitDiffLog(repo, trunk, branch) // can be greater than 1
+ // log.Info(branch, "vs", trunk, "count", b1, b2)
+ if b1 == 0 && b2 == 0 {
+ // log.Info("branch and trunk are identical ==", branch, b1, trunk, b2)
+ return nil
+ }
+ if b1 == 0 {
+ cmd := []string{"git", "merge", trunk}
+ log.Printf("%-40s branch %s needs merge with trunk %s len(%d) %s\n", repo.GetGoPath(), branch, trunk, b2, cmd)
+ return ErrorMergeBranch
+ }
+ if b2 == 0 {
+ log.Printf("%-40s trunk %s needs merge with branch %s len(%d)\n", repo.GetGoPath(), branch, trunk, b2)
+ return ErrorMergeTrunk
+ }
+ return fmt.Errorf("branch not clean to delete. needs merge %d %d", b1, b2)
+}
+
+// count all objects only in branch1
+// if zero, that means branch1 is entirely contained in branch2 and can be safely deleted
+func countGitDiffLog(repo *gitpb.Repo, branch1, branch2 string) int {
+ cmd := repo.ConstructGitDiffLog(branch1, branch2)
+ r, err := repo.RunStrictNew(cmd)
+ if err != nil {
+ return -1
+ }
+ // log.Info("countDiffObjects()", cmd, len(r.Stdout), strings.Join(r.Stdout, " "))
+ return len(r.Stdout)
+}