297 lines
6.7 KiB
Go
297 lines
6.7 KiB
Go
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
|
// Use of this source code is governed by the GPL 3.0
|
|
|
|
package main
|
|
|
|
// An app to submit patches for the 30 GO GUI repos
|
|
|
|
import (
|
|
"embed"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"go.wit.com/dev/alexflint/arg"
|
|
"go.wit.com/gui"
|
|
"go.wit.com/lib/gui/prep"
|
|
"go.wit.com/lib/gui/shell"
|
|
"go.wit.com/lib/protobuf/forgepb"
|
|
"go.wit.com/lib/protobuf/gitpb"
|
|
"go.wit.com/log"
|
|
)
|
|
|
|
// sent via -ldflags
|
|
var VERSION string
|
|
var BUILDTIME string
|
|
|
|
// this optionally can store the GUI plugins
|
|
//
|
|
//go:embed resources/*
|
|
var resources embed.FS
|
|
|
|
// used for shell auto completion
|
|
var ARGNAME string = "forge"
|
|
|
|
// using this for now. triggers config save
|
|
var configSave bool
|
|
|
|
func getVersion(repo *gitpb.Repo, name string) string {
|
|
cmd := []string{"git", "describe", "--tags", "--always", name}
|
|
result, _ := repo.RunQuiet(cmd)
|
|
output := strings.Join(result.Stdout, "\n")
|
|
log.Info("cmd =", cmd, output)
|
|
|
|
return strings.TrimSpace(output)
|
|
}
|
|
|
|
func main() {
|
|
me = new(mainType)
|
|
prep.Bash(ARGNAME, argv.DoAutoComplete) // this line should be: prep.Bash(argv)
|
|
me.myGui = prep.Gui() // prepares the GUI package for go-args
|
|
me.pp = arg.MustParse(&argv)
|
|
|
|
/*
|
|
if argv.Bash {
|
|
fhelp.DoBash(ARGNAME)
|
|
os.Exit(0)
|
|
}
|
|
if len(argv.BashAuto) != 0 {
|
|
argv.doBashAuto()
|
|
os.Exit(0)
|
|
}
|
|
*/
|
|
me.urlbase = argv.URL
|
|
if me.urlbase == "" {
|
|
me.urlbase = "https://go.wit.com/"
|
|
}
|
|
if os.Getenv("FORGE_URL") != "" {
|
|
me.urlbase = os.Getenv("FORGE_URL")
|
|
log.Info("got forge url", me.urlbase)
|
|
}
|
|
me.urlbase = strings.Trim(me.urlbase, "/") // track down why trailing '/' makes http POST not work
|
|
|
|
// internally debugging can be triggered here before Init()
|
|
if argv.Debug != nil {
|
|
doDebug()
|
|
okExit("")
|
|
}
|
|
|
|
if forgepb.FirstTimeUser() {
|
|
log.Info("You are running forge for the first time here")
|
|
}
|
|
// load the ~/.config/forge/ config
|
|
me.forge = forgepb.Init()
|
|
|
|
// initialize patches
|
|
doPatchInit()
|
|
|
|
// first find the repos or gopaths to operate on
|
|
if argv.Config != nil {
|
|
doConfig()
|
|
okExit("")
|
|
}
|
|
|
|
if argv.Commit != nil {
|
|
doCommit()
|
|
okExit("")
|
|
}
|
|
|
|
if argv.BuildForge {
|
|
buildForge()
|
|
okExit("")
|
|
}
|
|
|
|
if argv.Checkout != nil {
|
|
me.forge.Config.Mode = forgepb.ForgeMode_MASTER
|
|
if err := doCheckout(); err != nil {
|
|
badExit(err)
|
|
}
|
|
okExit("")
|
|
}
|
|
|
|
if argv.Build != "" {
|
|
if err := doBuild(); err != nil {
|
|
badExit(err)
|
|
}
|
|
okExit("")
|
|
}
|
|
|
|
if argv.Install != "" {
|
|
if err := doInstall(); err != nil {
|
|
badExit(err)
|
|
}
|
|
okExit("")
|
|
}
|
|
|
|
if argv.Clean != nil {
|
|
me.forge.Config.Mode = forgepb.ForgeMode_CLEAN
|
|
if argv.Clean.Repo != "" {
|
|
log.Info("only looking at repo:", argv.Clean.Repo)
|
|
okExit("")
|
|
}
|
|
|
|
if argv.Clean.GitReset != nil {
|
|
doGitReset()
|
|
okExit("reset")
|
|
}
|
|
|
|
if err := doClean(); err != nil {
|
|
badExit(err)
|
|
}
|
|
me.forge.ConfigSave()
|
|
okExit("")
|
|
}
|
|
|
|
if argv.Help != nil {
|
|
doHelp()
|
|
okExit("")
|
|
}
|
|
|
|
if argv.Dirty != nil {
|
|
doDirty()
|
|
okExit("")
|
|
}
|
|
|
|
if argv.Normal != nil {
|
|
if argv.Normal.On != nil {
|
|
if me.forge.Config.Mode == forgepb.ForgeMode_NORMAL {
|
|
log.Info("you are already in the normal state")
|
|
okExit("")
|
|
}
|
|
me.forge.Config.Mode = forgepb.ForgeMode_NORMAL
|
|
me.forge.Config.ConfigSave()
|
|
log.Info("normal mode on")
|
|
okExit("")
|
|
}
|
|
|
|
if argv.Normal.Off != nil {
|
|
if me.forge.Config.Mode != forgepb.ForgeMode_NORMAL {
|
|
log.Info("you were aleady not in the normal state")
|
|
okExit("")
|
|
}
|
|
me.forge.Config.Mode = forgepb.ForgeMode_MASTER
|
|
me.forge.Config.ConfigSave()
|
|
log.Info("normal mode off")
|
|
okExit("")
|
|
}
|
|
|
|
if doNormal() {
|
|
log.Infof("all %d repos are on your user branch. It is safe to write code now.\n", me.forge.Repos.Len())
|
|
if me.forge.Config.Mode != forgepb.ForgeMode_NORMAL {
|
|
log.Infof("Forge has set the mode to 'Normal'\n")
|
|
me.forge.Config.Mode = forgepb.ForgeMode_NORMAL
|
|
me.forge.ConfigSave()
|
|
}
|
|
okExit("")
|
|
}
|
|
okExit("")
|
|
}
|
|
|
|
// if you are in "normal" mode, always run normal every time to catch accidental errors
|
|
// for example, if you accidentally changed branches from your user branch
|
|
if me.forge.Config.Mode == forgepb.ForgeMode_NORMAL {
|
|
if doNormal() {
|
|
log.Infof("all your %d repos are in a normal stete for development\n", me.forge.Repos.Len())
|
|
}
|
|
}
|
|
|
|
if argv.Merge != nil {
|
|
if argv.Merge.Devel != nil {
|
|
start := time.Now()
|
|
repos, err := doMergeDevel()
|
|
dur := time.Since(start)
|
|
if err != nil {
|
|
badExit(err)
|
|
}
|
|
log.Printf("Merged %d devel branches in %s\n", repos.Len(), shell.FormatDuration(dur))
|
|
okExit("")
|
|
}
|
|
|
|
if argv.Merge.Master != nil {
|
|
start := time.Now()
|
|
repos, err := doMergeMaster()
|
|
dur := time.Since(start)
|
|
if err != nil {
|
|
badExit(err)
|
|
}
|
|
log.Printf("Merged %d master branches in %s\n", repos.Len(), shell.FormatDuration(dur))
|
|
okExit("")
|
|
}
|
|
badExit(fmt.Errorf("You must choose which branch to merge to (devel or master)"))
|
|
}
|
|
|
|
if argv.Pull != nil {
|
|
doPull()
|
|
okExit("")
|
|
}
|
|
|
|
if argv.List != nil {
|
|
found := argv.List.findRepos()
|
|
// print out the repos
|
|
if argv.List.Full {
|
|
me.forge.PrintHumanTableFull(found)
|
|
} else {
|
|
me.forge.PrintHumanTable(found)
|
|
}
|
|
okExit("")
|
|
}
|
|
|
|
if argv.Patch != nil {
|
|
if err := doPatch(); err != nil {
|
|
badExit(err)
|
|
}
|
|
okExit("")
|
|
}
|
|
|
|
// if the user doesn't want to open the GUI and
|
|
// nothing else was specified to be done,
|
|
// then just list the table to stdout
|
|
if gui.NoGui() {
|
|
found := doFind()
|
|
me.forge.PrintHumanTable(found)
|
|
okExit("")
|
|
}
|
|
|
|
// open the gui unless the user performed some other
|
|
// basically, if you run just 'forge' it should open the GUI
|
|
|
|
if argv.Gui != nil {
|
|
// if opening the GUI, always check git for dirty repos
|
|
me.forge.CheckDirty()
|
|
doGui()
|
|
}
|
|
// got to the end with nothing to do (?)
|
|
if dumpWorkRepos() {
|
|
// found some repos at least
|
|
} else {
|
|
// every repo is in a really clean state. no extra files anywhere
|
|
// no dirty repos, no repos that need to be published
|
|
// nothing different between user and master branch version. not common
|
|
log.Info("All of your git repositories appear to be in perfect shape")
|
|
}
|
|
okExit("")
|
|
}
|
|
|
|
// keep this small
|
|
func doHelp() {
|
|
log.Info("")
|
|
log.Info("forge -h : to see the available options")
|
|
log.Info("forge --bash : will create a bash autocomplete file")
|
|
log.Info("forge : with no arguements, forge tries to load a GO GUI plugin")
|
|
log.Info(" : there are two GUI plugins. terminal & GTK")
|
|
log.Info("")
|
|
log.Info("forge list : shows a table of all your repos")
|
|
log.Info("forge checkout : checks out all your repos to the same branch")
|
|
log.Info(" : the default is your user branch")
|
|
log.Info("forge clean : reverts all repos to the master branch")
|
|
log.Info("forge dirty : show all repos git reports as dirty")
|
|
log.Info("")
|
|
okExit("")
|
|
}
|
|
|
|
func doHelpPatches() {
|
|
log.Info("TODO: ?")
|
|
okExit("")
|
|
}
|