// Copyright 2017-2025 WIT.COM Inc. All rights reserved. // Use of this source code is governed by the GPL 3.0 package main import ( "errors" "fmt" "os" "path/filepath" "strings" "go.wit.com/lib/fhelp" "go.wit.com/lib/gui/shell" "go.wit.com/lib/protobuf/gitpb" "go.wit.com/log" ) func doGitCreate(namespace string) (string, error) { var s string var err error templateDir := "/var/lib/git/lib/templates/golib" if !shell.IsDir(templateDir) { return "", errors.New("no template/golib") } fullpath := filepath.Join("/var/lib/git", namespace) if shell.IsDir(fullpath) { return "", errors.New("dir " + fullpath + " already exists") } basepath, _ := filepath.Split(fullpath) if err := os.MkdirAll(basepath, os.ModePerm); err != nil { return "", err } cmd := []string{"cp", "-a", templateDir, fullpath} shell.RunVerbose(cmd) return s, err } func doGit() (string, error) { var s string var err error if argv.Git.Log != nil { fstr := "--format=\"%h %>(24)%ar %>(20)%an %s" cmd := []string{"git", "log", fstr} shell.RunVerbose(cmd) s = "git log" } if argv.Git.Create != "" { s = "attmepting to create new repo" } if argv.Git.Tag != nil { cmd := []string{"git", "for-each-ref", "--sort=taggerdate", "--format"} cmd = append(cmd, "%(tag)%00%(taggerdate:raw)%00%(taggername)%00%(subject)") cmd = append(cmd, "refs/tags") result := shell.RunQuiet(cmd) for i, line := range result.Stdout { parts := strings.Split(line, "\x00") log.Infof("LINE: %d len(%d) %v\n", i, len(parts), parts) } s = "git tags" } if argv.Git.Who != nil { if _, err := fhelp.CheckCmd("git-who"); err != nil { if fhelp.QuestionUser("install git-who") { log.Info("go install -v -x github.com/sinclairtarget/git-who@latest") } else { log.Info("not installing") } me.sh.GoodExit("git who should be installed") } cmd := []string{"git", "who"} shell.RunVerbose(cmd) s = "git who" } if argv.Git.Pull != nil { doPull(".config/wit") doPull("tools") s = "git pull" } if argv.Git.Push != nil { doPush(".config/wit") doPush("tools") s = "git push" } if argv.Git.DeleteUntracked { initForge() var totals, repos int for repo := range me.forge.Repos.IterAll() { if !strings.HasPrefix(repo.Namespace, "go.wit.com") { continue } files, _ := repo.GitDeleteOthers() if len(files) == 0 { continue } totals += len(files) repos += 1 log.Info(len(files), repo.Namespace) log.Info(strings.Join(files, "\n")) if argv.Force { if len(files) > 0 { cmd := []string{"rm"} cmd = append(cmd, files...) _, err := fhelp.RunRealtimeError(cmd) if err != nil { log.Info("cmd failed", cmd, repo.FullPath, err) return "rm failed", err } } } } s = log.Sprintf("total files to delete: (%d) in (%d) repos", totals, repos) } return s, err } func findRepo(wpath string) (*gitpb.Repo, bool) { d := filepath.Join(me.homedir, wpath) if !shell.IsDir(d) { return nil, false } repo, err := gitpb.NewRepo(d) if err != nil { log.Info("path error", d, err) return nil, false } return repo, true } func doPull(wpath string) { repo, ok := findRepo(wpath) if !ok { return } os.Chdir(repo.FullPath) cmd := []string{"git", "pull"} log.Info("Run", repo.FullPath, cmd) exitOnErrorRealtime(cmd) } func doPush(wpath string) { doPull(wpath) d := filepath.Join(me.homedir, wpath) if !shell.IsDir(d) { return } repo, err := gitpb.NewRepo(d) if err != nil { log.Info("path error", d, err) return } if repo == nil { log.Info("repo is nil", d, err) return } if err := repo.GitCommit(); err != nil { msg := fmt.Sprintf("repo.GitCommit() %s", repo.FullPath) me.sh.BadExit(msg, err) } repo.RunRealtime([]string{"git", "push"}) } /* ┌─────────────┬───────────────────────────┬──────────────────────────────────────────┐ │ Placeholder │ Description │ Example Output │ ├─────────────┼───────────────────────────┼──────────────────────────────────────────┤ │ %H │ Full commit hash │ a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2 │ │ %h │ Abbreviated commit hash │ a1b2c3d │ │ %T │ Full tree hash │ f1e2d3c4b5a6f1e2d3c4b5a6f1e2d3c4b5a6f1e2 │ │ %t │ Abbreviated tree hash │ f1e2d3c │ │ %P │ Full parent hashes │ a1b2... f1e2... (space-separated) │ │ %p │ Abbreviated parent hashes │ a1b2c3d f1e2d3c │ └─────────────┴───────────────────────────┴──────────────────────────────────────────┘ Author and Committer Information (Note: "Author" is who originally wrote the code. "Committer" is who last applied it to the branch. They are often the same.) ┌─────────────┬───────────────────────────────────┬────────────────────────────────┐ │ Placeholder │ Description │ Example Output │ ├─────────────┼───────────────────────────────────┼────────────────────────────────┤ │ %an │ Author name │ Jane Doe │ │ %ae │ Author email │ jane.doe@example.com │ │ %aN │ Author name (respecting .mailmap) │ Jane Doe │ │ %ad │ Author date │ Tue Oct 14 10:30:00 2025 -0700 │ │ %ar │ Author date, relative │ 3 days ago │ │ %at │ Author date, UNIX timestamp │ 1760453400 │ │ %cn │ Committer name │ John Smith │ │ %ce │ Committer email │ john.smith@example.com │ │ %cd │ Committer date │ Wed Oct 15 11:00:00 2025 -0700 │ │ %cr │ Committer date, relative │ 2 days ago │ │ %ct │ Committer date, UNIX timestamp │ 1760541600 │ └─────────────┴───────────────────────────────────┴────────────────────────────────┘ Commit Message ┌─────────────┬──────────────────────────────────────────────────────────┐ │ Placeholder │ Description │ ├─────────────┼──────────────────────────────────────────────────────────┤ │ %s │ Subject (first line of the commit message) │ │ %f │ "Sanitized" subject line, suitable for a filename │ │ %b │ Body (the rest of the commit message, after the subject) │ │ %B │ Raw full commit message (subject + body) │ │ %N │ Commit notes (from git notes) │ └─────────────┴──────────────────────────────────────────────────────────┘ Ref Names (Branches and Tags) ┌────────────┬─────────────────────────────────────────────────────────────┬──────────────────────────────────────┐ │ Placeho... │ Description │ Example Output │ ├────────────┼─────────────────────────────────────────────────────────────┼──────────────────────────────────────┤ │ %d │ All ref names pointing to this commit │ `(HEAD -> main, tag: v1.0, origin... │ │ %D │ Like %d, but without the parentheses/commas │ HEAD -> main, tag: v1.0, origin/main │ │ %S │ The ref name given on the command line (e.g., the branch... │ main │ └────────────┴─────────────────────────────────────────────────────────────┴──────────────────────────────────────┘ */