cleanup argv handling. go-arg saves the day

This commit is contained in:
Jeff Carr 2025-01-28 17:03:56 -06:00
parent 7402aaded7
commit 51ec39d157
8 changed files with 129 additions and 93 deletions

View File

@ -1,11 +1,13 @@
VERSION = $(shell git describe --tags)
BUILDTIME = $(shell date +%Y.%m.%d_%H%M)
info: install
# forge dirty
# forge examine
# forge clean
make andlabs
# make build # go build using your git cloned repos (GO111MODULE=off)
# make install # go install using your git cloned repos (GO111MODULE=off)
# make gocui # try the ncurses gui plugin
# make andlabs # try the andlabs gui plugin (uses GTK)
default: install
forge dirty --verbose
vet:
@GO111MODULE=off go vet
@ -27,7 +29,6 @@ install-raw: goimports vet plugin
go install \
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
plugin:
rm -f resources/*.so
cp ../../toolkits/gocui/gocui.so resources/
@ -35,31 +36,22 @@ plugin:
andlabs:
forge --gui andlabs
gocui: install
forge --gui gocui >/tmp/forge.log 2>&1
goimports:
reset
goimports -w *.go
@# // to globally reset paths:
@# // gofmt -w -r '"go.wit.com/gui/gadgets" -> "go.wit.com/lib/gadgets"' *.go
gocui: install
forge --gui gocui >/tmp/forge.log 2>&1
clean:
-rm -f forge go.*
# -rm -f ~/go/src/repos.pb
go-mod-clean --purge
patches-make: install
forge --patchset "from makefile 2"
identify-protobuf:
autogenpb --identify ~/go/src/repos.pb
patches-list-2233: install
forge --list-patchset --connect "http://go.wit.com:2233/"
patches-list: install
forge --list-patchset
patches-apply-230233: install
forge --apply /tmp/2024.12.27.230233.submitted.pb
restart:
reset
-rm ~/go/src/repos.pb
make private
identify:
autogenpb --identify /home/jcarr/go/src/repos.pb
devel:
forge clean devel --force --verbose

View File

@ -1,10 +1,41 @@
forge
# forge
This can be used to maintain git repositories
expiremental work on federated git
/usr/share/git-gui/lib/tools/
.git/config settings for gitgui
[gui]
wmstate = normal
geometry = 931x515+450+130 197 234
* Scans directories looking for git repositories
* The default behavior is to use 3 branches. 'master or main', 'devel', '<username>'
* shows tags and dirty state
* uses a GUI or the console(console display needs work)
* always wrap around 'git' -- it basically just types 'git' commands really fast
## Notes & Goals:
* use a GUI that also works on the command line
* andlabs GTK gui plugin starts breaking around 200 repos
## Install:
* go install go.wit.com/apps/forge@latest
## building from sources (may work Jan 2026)
```
go install go.wit.com/apps/go-clone@latest # this tool makes it easier to 'git clone' repos and recursively 'git clone' the dependancies
go install go.wit.com/apps/autogenpb@latest # this tool will generate the protobuf *pb.go files (also Marshal(), Sort(), etc.)
go-clone --recursive go.wit.com/apps/forge # this will 'git clone' about 20 repos into ~/go/src (or where your go.work file is)
cd go.wit.com/lib/protobuf/forgepb
make # autogenpb will make .pb.go, marshal.pb.go and sort.pb.go files
cd go.wit.com/lib/protobuf/gitpb
make # autogenpb will make .pb.go, marshal.pb.go and sort.pb.go files
cd go.wit.com/apps/forge
make # this runs GO111MODULE=off go build insuring that your using only your git sources
```
## Debian packages:
Instructions are on https://mirrors.wit.com/

42
argv.go
View File

@ -12,26 +12,22 @@ import (
var argv args
type args struct {
Checkout *CheckoutCmd `arg:"subcommand:checkout" help:"switch git branches"`
Checkout *CheckoutCmd `arg:"subcommand:checkout" help:"switch branches using 'git checkout'"`
Clean *CleanCmd `arg:"subcommand:clean" help:"clean git branches"`
Commit *EmptyCmd `arg:"subcommand:commit" help:"'git commit' but errors out if on wrong branch"`
Config *ConfigCmd `arg:"subcommand:config" help:"show your .config/forge/ settings"`
Dirty *DirtyCmd `arg:"subcommand:dirty" help:"check if your git repos are dirty"`
GitReset *EmptyCmd `arg:"subcommand:hard-reset" help:"hard reset your user git branches"`
List *FindCmd `arg:"subcommand:list" help:"just show a table of the current state"`
Patch *PatchCmd `arg:"subcommand:patch" help:"examine and make patch sets"`
GitPull *FindCmd `arg:"subcommand:pull" help:"run 'git pull'"`
Dirty *DirtyCmd `arg:"subcommand:dirty" help:"show repos git says are dirty"`
GitFetch *FindCmd `arg:"subcommand:fetch" help:"run 'git fetch master'"`
Rescan *EmptyCmd `arg:"subcommand:rescan" help:"recreate the git protobuf repos.pb file"`
Delete *EmptyCmd `arg:"subcommand:delete" help:"untrack a repo"`
Commit *EmptyCmd `arg:"subcommand:commit" help:"smart 'git commit' (errors out if on wrong branch)"`
Clean *CleanCmd `arg:"subcommand:clean" help:"clean out all local branches (safely)"`
Examine *ExamineCmd `arg:"subcommand:examine" help:"examine branches"`
URL string `arg:"--connect" help:"gowebd url"`
List *FindCmd `arg:"subcommand:list" help:"print a table of the current repos"`
Patch *PatchCmd `arg:"subcommand:patch" help:"make patchsets"`
GitPull *FindCmd `arg:"subcommand:pull" help:"run 'git pull'"`
URL string `arg:"--connect" help:"forge url"`
All bool `arg:"--all" help:"git commit --all"`
Show string `arg:"--show" help:"show a repo"`
Bash bool `arg:"--bash" help:"generate bash completion"`
BashAuto []string `arg:"--auto-complete" help:"does the actual autocompletion"`
Force bool `arg:"--force" help:"try to strong arm things"`
Verbose bool `arg:"--verbose" help:"show more output"`
Bash bool `arg:"--bash" help:"generate bash completion"`
BashAuto []string `arg:"--auto-complete" help:"todo: move this to go-arg"`
}
type EmptyCmd struct {
@ -46,9 +42,12 @@ 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:"clean the user branches"`
Devel *CleanDevelCmd `arg:"subcommand:devel" help:"clean and verify the devel branches"`
User *EmptyCmd `arg:"subcommand:user" help:"clean the user branches"`
Devel *CleanDevelCmd `arg:"subcommand:devel" help:"clean and verify the devel branches"`
Force *EmptyCmd `arg:"subcommand:force" help:"try harder to delete things. check your patchsets have been saved first."`
Examine *ExamineCmd `arg:"subcommand:examine" help:"examine branches"`
GitReset *EmptyCmd `arg:"subcommand:git-reset" help:"git reset --hard"`
Delete *EmptyCmd `arg:"subcommand:delete" help:"rescan repo"`
}
type CleanDevelCmd struct {
@ -91,7 +90,6 @@ type CheckoutCmd struct {
}
type DirtyCmd struct {
Show bool `arg:"--show-files" help:"also list every dirty file"`
}
type FindCmd struct {
@ -111,8 +109,13 @@ func (args) Version() string {
func (a args) Description() string {
return `
forge -- in the spirit of things like sourceforge
forge -- a tool to git repos at go.wit.com
but you can probably use it for other things
`
}
/*
This supports GO projects so far.
It will work from ~/go/src or where your go.work file is.
Since I mostly use ~/go/src, that has been tested more.
@ -132,6 +135,7 @@ Examples:
`
}
*/
func (args) doBashHelpDebug() {
fmt.Fprintln(os.Stderr, "")

View File

@ -14,7 +14,8 @@ import (
// var ARGNAME string = "forge" // todo: get this from $0 ?
func (a *EmptyCmd) deleteMatch() {
fmt.Println("go.wit.com/lib/gui/repostatus")
// f := forgedb.InitSimple()
fmt.Println("go.wit.com/lib/gui/repostatus todo: need to do this")
}
func (args) doBashAuto() {
@ -24,15 +25,22 @@ func (args) doBashAuto() {
usr, _ := user.Current()
fmt.Println("user devel master " + usr.Username)
case "clean":
fmt.Println("devel user force")
// me.pp.WriteHelp(os.Stderr)
// me.pp.WriteUsageForSubcommand(os.Stderr, me.pp.SubcommandNames()...)
// me.pp.WriteHelpForSubcommand(os.Stderr, me.pp.SubcommandNames()...)
me.pp.WriteHelpForSubcommand(os.Stderr, "clean")
fmt.Fprintln(os.Stderr, "")
fmt.Fprintln(os.Stderr, "hello world")
fmt.Fprintln(os.Stderr, "")
fmt.Println("devel user force clean examine git-reset")
case "commit":
fmt.Println("--all")
case "config":
fmt.Println("add fix list delete")
fmt.Println("add fix list")
case "delete":
argv.Delete.deleteMatch()
argv.Clean.Delete.deleteMatch()
case "dirty":
fmt.Println("--show-files")
fmt.Println("--verbose")
case "examine":
fmt.Println("fix")
case "list":
@ -50,7 +58,7 @@ func (args) doBashAuto() {
default:
if argv.BashAuto[0] == ARGNAME {
// list the subcommands here
fmt.Println("--bash checkout clean commit config dirty delete examine hard-reset list patch pull rescan")
fmt.Println("--bash list checkout clean commit config dirty fetch patch pull")
}
}
os.Exit(0)
@ -81,8 +89,8 @@ func (args) doBash() {
fmt.Println("")
fmt.Println("# todo: add this to go-arg as a 'hidden' go-arg option --bash")
fmt.Println("#")
fmt.Println("# todo: make this output work/parse with:")
fmt.Println("# complete -C " + ARGNAME + " --bash go")
fmt.Println("# todo: can this output work/parse with:")
fmt.Println("# complete -C `" + ARGNAME + " --bash` " + ARGNAME)
fmt.Println("")
fmt.Println("_" + ARGNAME + "_complete()")
fmt.Println("{")

View File

@ -62,9 +62,9 @@ func doCleanDevel() error {
// log.Info("Cleaning:", repo.GetGoPath())
}
total += 1
if repo.GetCurrentBranchName() != repo.GetDevelBranchName() {
// only process branches in devel
// return nil
if repo.GetCurrentBranchName() != repo.GetMasterBranchName() {
// repos must be in the master branch to clean the devel branch
return nil
}
if repo.IsDirty() {
return nil
@ -110,7 +110,9 @@ func checkhashes(repo *gitpb.Repo, hashes []string, refpath string) ([]string, e
func doCleanDevelRepo(repo *gitpb.Repo) error {
var hashes []string
devel := repo.GetDevelBranchName()
// log.Printf("%s Start verify devel branch: %s\n", repo.GetGoPath(), devel)
if argv.Verbose {
log.Printf("Start clean devel branch: %s %s\n", repo.GetGoPath(), devel)
}
// check if devel branch exists in remote repo
if repo.Exists(filepath.Join(".git/refs/remotes/origin", devel)) {
@ -451,7 +453,6 @@ func forceDeleteUserBranch(repo *gitpb.Repo, branch string) error {
}
log.Info("THIS USER REMOTE BRANCH MUST BE DELETED HERE", branch)
if repo.Exists(filepath.Join(".git/refs/remote/origin", branch)) {
// git push origin --delete jcarr
cmd = []string{"git", "push", "origin", "--delete", branch}
if _, err := repo.RunVerbose(cmd); err != nil {
log.Info("THE GIT BRANCH DELETE ERROR IS:", err)
@ -482,7 +483,6 @@ func BADforceDeleteBranch(repo *gitpb.Repo, branch string) error {
}
log.Info("THIS USER REMOTE BRANCH MUST BE DELETED HERE", branch)
if repo.Exists(filepath.Join(".git/refs/remote/origin", branch)) {
// git push origin --delete jcarr
cmd = []string{"git", "push", "origin", "--delete", branch}
if _, err := repo.RunVerbose(cmd); err != nil {
log.Info("THE GIT BRANCH DELETE ERROR IS:", err)

View File

@ -13,7 +13,11 @@ func doDirty() {
doCheckDirtyAndConfigSave()
me.found = new(gitpb.Repos)
findDirty()
me.forge.PrintHumanTableDirty(me.found)
if argv.Verbose {
me.forge.PrintHumanTableDirty(me.found)
} else {
me.forge.PrintHumanTable(me.found)
}
}
func straightCheckDirty() int {

View File

@ -54,7 +54,7 @@ func doExamine() error {
dur := time.Since(ctime)
log.Printf("UNKNOWN BRANCH %-50s %s %4s %s\n", repo.GetFullPath(), tag.Hash, shell.FormatDuration(dur), tag.Refname)
err := examineBranch(repo)
if argv.Examine.Fix != nil {
if argv.Clean.Examine.Fix != nil {
if err != nil {
badExit(err)
}
@ -112,12 +112,14 @@ func examineBranch(repo *gitpb.Repo) error {
return fmt.Errorf("repo.CurrentTag == nil")
}
if repo.CurrentTag.Refname == "jcarr" {
return requiresGitPush(repo, "jcarr")
userbranch := repo.GetUserBranchName()
if repo.CurrentTag.Refname == userbranch {
return requiresGitPush(repo, userbranch)
}
if repo.CurrentTag.Refname == "origin/jcarr" {
return requiresGitPush(repo, "jcarr")
if repo.CurrentTag.Refname == "origin/"+userbranch {
return requiresGitPush(repo, userbranch)
}
if len(dcount) == 0 {
@ -130,7 +132,7 @@ func examineBranch(repo *gitpb.Repo) error {
err = fmt.Errorf("examineBranch() branch differs. patch diff len == 0. PROBABLY DELETE BRANCH %s", repo.CurrentTag.Refname)
log.Info(err)
cmd := repo.ConstructGitDiffLog(repo.CurrentTag.Refname, repo.GetMasterBranchName())
if argv.Examine.Fix == nil {
if argv.Clean.Examine.Fix == nil {
log.Info(repo.GetGoPath(), cmd)
} else {
if _, err := repo.RunVerbose(cmd); err != nil {
@ -138,7 +140,7 @@ func examineBranch(repo *gitpb.Repo) error {
}
}
cmd = repo.ConstructGitDiffLog(repo.GetMasterBranchName(), repo.CurrentTag.Refname)
if argv.Examine.Fix == nil {
if argv.Clean.Examine.Fix == nil {
log.Info(repo.GetGoPath(), cmd)
} else {
if _, err := repo.RunVerbose(cmd); err != nil {
@ -147,7 +149,7 @@ func examineBranch(repo *gitpb.Repo) error {
}
cmd = []string{"git", "branch", "-D", repo.CurrentTag.Refname}
log.Info(repo.GetGoPath(), "TRY THIS:", cmd)
if argv.Examine.Fix == nil {
if argv.Clean.Examine.Fix == nil {
log.Info(repo.GetGoPath(), "TODO: CHECK REMOTE BRANCH DOES NOT EXIST", repo.CurrentTag.Refname)
repo.RunVerbose([]string{"ls", "-l", ".git/refs/remotes/origin"})
} else {
@ -266,7 +268,7 @@ func requiresGitPush(repo *gitpb.Repo, branchName string) error {
if b1 != 0 {
log.Info(branchName, "vs origin count b1 != 0, b2 ==", b1, b2)
log.Info("THIS MEANS THE LOCAL BRANCH NEEDS GIT PUSH TO ORIGIN BRANCH ==", b1)
if argv.Examine.Fix != nil {
if argv.Clean.Examine.Fix != nil {
return gitPushStrict(repo, branchName)
}
return nil

31
main.go
View File

@ -79,6 +79,18 @@ func main() {
}
if argv.Clean != nil {
if argv.Clean.Examine != nil {
if err := doExamine(); err != nil {
badExit(err)
}
okExit("")
}
if argv.Clean.GitReset != nil {
findAll() // select all the repos
doGitReset()
okExit("reset")
}
if err := doClean(); err != nil {
badExit(err)
}
@ -90,18 +102,6 @@ func main() {
okExit("")
}
if argv.Examine != nil {
if err := doExamine(); err != nil {
badExit(err)
}
okExit("")
}
if argv.Rescan != nil {
me.forge.ScanGoSrc()
okExit("")
}
if argv.Show != "" {
repo := me.forge.FindByGoPath(argv.Show)
me.forge.HumanPrintRepo(repo)
@ -131,18 +131,13 @@ func main() {
okExit("")
}
if argv.GitReset != nil {
findAll() // select all the repos
doGitReset()
okExit("reset")
}
if argv.List != nil {
argv.List.findRepos()
// print out the repos
me.forge.PrintHumanTable(me.found)
okExit("")
}
if argv.Patch != nil {
if argv.Patch.Submit != "" {
doSubmit(argv.Patch.Submit)