summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2025-01-19 16:07:17 -0600
committerJeff Carr <[email protected]>2025-01-19 16:07:17 -0600
commit835c000aefc6eb702bd326d77d08ac47abba675b (patch)
treefee37fb35bd928ad3f12081813793f60e8963b1d
parent4c38b052fd936cd9fc9484811ceae4fd5b24e12d (diff)
check devel branches
-rw-r--r--argv.go9
-rw-r--r--argvAutoshell.go2
-rw-r--r--doCheckout.go24
-rw-r--r--doClean.go166
-rw-r--r--doPull.go20
-rw-r--r--main.go4
-rw-r--r--windowPatches.go2
7 files changed, 183 insertions, 44 deletions
diff --git a/argv.go b/argv.go
index f5551b3..13bedd9 100644
--- a/argv.go
+++ b/argv.go
@@ -45,8 +45,13 @@ type ExamineCmd struct {
}
type CleanCmd struct {
- Force *EmptyCmd `arg:"subcommand:force" help:"dangerously delete things that are not pushed upstream"`
- User *EmptyCmd `arg:"subcommand:user" help:"dump all the user branches"`
+ Force *EmptyCmd `arg:"subcommand:force" help:"dangerously delete things that are not pushed upstream"`
+ User *EmptyCmd `arg:"subcommand:user" help:"clean the user branches"`
+ Devel *CleanDevelCmd `arg:"subcommand:devel" help:"clean and verify the devel branches"`
+}
+
+type CleanDevelCmd struct {
+ Force bool `arg:"--force" help:"try to strong arm things"`
}
type PatchCmd struct {
diff --git a/argvAutoshell.go b/argvAutoshell.go
index 1cdb613..96c5e14 100644
--- a/argvAutoshell.go
+++ b/argvAutoshell.go
@@ -24,7 +24,7 @@ func (args) doBashAuto() {
usr, _ := user.Current()
fmt.Println("user devel master " + usr.Username)
case "clean":
- fmt.Println("force user")
+ fmt.Println("devel user force")
case "commit":
fmt.Println("--all")
case "config":
diff --git a/doCheckout.go b/doCheckout.go
index a4d6b2a..85e4fdb 100644
--- a/doCheckout.go
+++ b/doCheckout.go
@@ -11,7 +11,7 @@ var ErrorNotAllReposOnMaster error = fmt.Errorf("not all repos on are on the mas
var ErrorNotAllReposOnDevel error = fmt.Errorf("not all repos on are on the devel branch")
var ErrorNotAllReposOnUser error = fmt.Errorf("not all repos on are on the user branch")
-func IsEverythingOnMaster() error {
+func IsEverythingOnMaster() (int, int, error) {
var total int
var count int
var nope int
@@ -30,12 +30,12 @@ func IsEverythingOnMaster() error {
log.Printf("Master branch check. %d total repos. (%d ok) (%d not on master branch)\n", total, count, nope)
if total != count {
// log.Info(ErrorNotAllReposOnMaster)
- return ErrorNotAllReposOnMaster
+ return total, count, ErrorNotAllReposOnMaster
}
- return nil
+ return total, count, nil
}
-func IsEverythingOnDevel() error {
+func IsEverythingOnDevel() (int, int, error) {
var total int
var count int
@@ -50,12 +50,12 @@ func IsEverythingOnDevel() error {
}
log.Printf("Devel branch check. %d total repos. %d repos on the devel branch\n", total, count)
if total != count {
- return ErrorNotAllReposOnDevel
+ return total, count, ErrorNotAllReposOnDevel
}
- return nil
+ return total, count, nil
}
-func IsEverythingOnUser() error {
+func IsEverythingOnUser() (int, int, error) {
var total int
var count int
@@ -70,9 +70,9 @@ func IsEverythingOnUser() error {
}
log.Printf("User branch check. %d total repos. %d repos on the user branch\n", total, count)
if total != count {
- return ErrorNotAllReposOnUser
+ return total, count, ErrorNotAllReposOnUser
}
- return nil
+ return total, count, nil
}
func doGitReset() {
@@ -113,7 +113,7 @@ func doAllCheckoutUser() error {
if count != 0 {
me.forge.ConfigSave()
}
- if err := IsEverythingOnUser(); err != nil {
+ if _, _, err := IsEverythingOnUser(); err != nil {
// display all repos not on user
me.found = new(gitpb.Repos)
all := me.forge.Repos.SortByFullPath()
@@ -149,7 +149,7 @@ func doAllCheckoutDevel() error {
if count != 0 {
me.forge.ConfigSave()
}
- if err := IsEverythingOnDevel(); err != nil {
+ if _, _, err := IsEverythingOnDevel(); err != nil {
// display all repos not on user
me.found = new(gitpb.Repos)
all := me.forge.Repos.SortByFullPath()
@@ -206,7 +206,7 @@ func doAllCheckoutMaster() error {
me.forge.ConfigSave()
}
- if err := IsEverythingOnMaster(); err != nil {
+ if _, _, err := IsEverythingOnMaster(); err != nil {
// display all repos not on master
me.found = new(gitpb.Repos)
all := me.forge.Repos.SortByFullPath()
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)
+}
diff --git a/doPull.go b/doPull.go
index 44a1b82..09ade34 100644
--- a/doPull.go
+++ b/doPull.go
@@ -29,3 +29,23 @@ func doGitPull() {
}
}
+
+// git fetch origin master:master
+func rillFetchMaster(repo *gitpb.Repo) error {
+ if repo.GetCurrentBranchName() != repo.GetUserBranchName() {
+ // only fetch when branch is on the user branch
+ return nil
+ }
+ branch := repo.GetMasterBranchName()
+ cmd := []string{"git", "fetch", "origin", branch + ":" + branch}
+ _, err := repo.RunVerbose(cmd)
+ return err
+}
+
+func doGitFetch() {
+ me.forge.RillFuncError(rillFetchMaster)
+ count := me.forge.RillReload()
+ if count != 0 {
+ me.forge.ConfigSave()
+ }
+}
diff --git a/main.go b/main.go
index 53a96a7..eb25299 100644
--- a/main.go
+++ b/main.go
@@ -136,8 +136,8 @@ func main() {
}
if argv.GitPull != nil {
- argv.GitPull.findRepos()
- doGitPull()
+ // argv.GitPull.findRepos()
+ doGitFetch()
okExit("")
}
diff --git a/windowPatches.go b/windowPatches.go
index 916ab66..eeae1e8 100644
--- a/windowPatches.go
+++ b/windowPatches.go
@@ -104,7 +104,7 @@ func submitPatchesBox(box *gui.Node) *patchSummary {
if err != nil {
return
}
- if err := IsEverythingOnDevel(); err != nil {
+ if _, _, err := IsEverythingOnDevel(); err != nil {
log.Info("You can only apply patches to the devel branch")
return
}