616 lines
14 KiB
Go
616 lines
14 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 (
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
|
|
"go.wit.com/gui"
|
|
"go.wit.com/lib/debugger"
|
|
"go.wit.com/lib/gadgets"
|
|
"go.wit.com/lib/protobuf/gitpb"
|
|
"go.wit.com/log"
|
|
)
|
|
|
|
type stdReposTableWin struct {
|
|
sync.Mutex
|
|
win *gadgets.GenericWindow // the machines gui window
|
|
boxTB *gui.Node // the machines gui parent box widget
|
|
TB *gitpb.ReposTable // the gui table buffer
|
|
pb *gitpb.Repos // the current repos protobuf
|
|
update bool // if the window should be updated
|
|
}
|
|
|
|
func (w *stdReposTableWin) Toggle() {
|
|
if w == nil {
|
|
return
|
|
}
|
|
if w.win == nil {
|
|
return
|
|
}
|
|
w.win.Toggle()
|
|
}
|
|
|
|
func makeReposWin() *stdReposTableWin {
|
|
rwin := new(stdReposTableWin)
|
|
win := gadgets.NewGenericWindow("git repos", "All about git repos")
|
|
rwin.win = win
|
|
grid := win.Group.RawGrid()
|
|
|
|
me.repoDirtyB = grid.NewButton("dirty", func() {
|
|
doCheckDirtyAndConfigSave()
|
|
found := findDirty()
|
|
tb, box := makeStandardReposWindow("dirty repos", found)
|
|
hbox := box.Box().Horizontal()
|
|
hbox.NewButton("commit all", func() {
|
|
for repo := range found.IterByFullPath() {
|
|
log.Info("do commit here on", repo.GetGoPath())
|
|
}
|
|
log.Info("TODO: fix this")
|
|
log.Info("run 'forge commit --all'")
|
|
})
|
|
hbox.NewButton("update table", func() {
|
|
me.forge.PrintHumanTable(found)
|
|
found2 := findDirty()
|
|
me.forge.PrintHumanTable(found2)
|
|
// tb.Update()
|
|
// tb.UpdateTable(found2)
|
|
})
|
|
hbox.NewButton("delete table", func() {
|
|
tb.Delete()
|
|
})
|
|
})
|
|
|
|
var writeWin *gadgets.GenericWindow
|
|
me.repoWritableB = grid.NewButton("writable", func() {
|
|
// if the window exists, just toggle it open or closed
|
|
if writeWin != nil {
|
|
writeWin.Toggle()
|
|
return
|
|
}
|
|
|
|
// make the window for the first time
|
|
found := new(gitpb.Repos)
|
|
for repo := range me.forge.Repos.IterByFullPath() {
|
|
if me.forge.Config.IsReadOnly(repo.GetGoPath()) {
|
|
continue
|
|
}
|
|
|
|
found.AppendByGoPath(repo)
|
|
|
|
}
|
|
writeWin, _ = makeWritableWindow(found)
|
|
writeWin.Win.Custom = func() {
|
|
log.Info("closing window. could do somethine here")
|
|
}
|
|
})
|
|
|
|
me.repoAllB = grid.NewButton("All", func() {
|
|
me.found = new(gitpb.Repos)
|
|
all := me.forge.Repos.SortByFullPath()
|
|
for all.Scan() {
|
|
repo := all.Next()
|
|
me.found.AppendByGoPath(repo)
|
|
|
|
}
|
|
makeStandardReposWindow("All repos", me.found)
|
|
})
|
|
|
|
var insertWin *gadgets.GenericWindow
|
|
me.repoWritableB = grid.NewButton("insert test", func() {
|
|
// if the window exists, just toggle it open or closed
|
|
if insertWin != nil {
|
|
insertWin.Toggle()
|
|
return
|
|
}
|
|
|
|
insertWin = makeWindowForPB()
|
|
insertWin.Win.Custom = func() {
|
|
log.Info("test delete window here")
|
|
}
|
|
grid := insertWin.Group.RawGrid()
|
|
|
|
var t *gitpb.ReposTable
|
|
grid.NewButton("dirty", func() {
|
|
if t != nil {
|
|
t.Delete()
|
|
t = nil
|
|
}
|
|
found := findDirty()
|
|
|
|
// display the protobuf
|
|
t = addWindowPB(insertWin, found)
|
|
f := func(repo *gitpb.Repo) {
|
|
log.Info("got to ReposTable.Custom() id =", repo.GetGoPath(), repo.GetCurrentVersion())
|
|
}
|
|
t.Custom(f)
|
|
log.Info("table has uuid", t.GetUuid())
|
|
})
|
|
|
|
grid.NewButton("all", func() {
|
|
if t != nil {
|
|
t.Delete()
|
|
t = nil
|
|
}
|
|
found := new(gitpb.Repos)
|
|
all := me.forge.Repos.SortByFullPath()
|
|
for all.Scan() {
|
|
repo := all.Next()
|
|
found.AppendByGoPath(repo)
|
|
|
|
}
|
|
// display the protobuf
|
|
t = addWindowPB(insertWin, found)
|
|
f := func(repo *gitpb.Repo) {
|
|
log.Info("got to ReposTable.Custom() id =", repo.GetGoPath(), repo.GetCurrentVersion())
|
|
}
|
|
t.Custom(f)
|
|
log.Info("table has uuid", t.GetUuid())
|
|
})
|
|
|
|
grid.NewButton("writeable", func() {
|
|
if t != nil {
|
|
t.Delete()
|
|
t = nil
|
|
}
|
|
found := new(gitpb.Repos)
|
|
all := me.forge.Repos.SortByFullPath()
|
|
for all.Scan() {
|
|
repo := all.Next()
|
|
if me.forge.Config.IsReadOnly(repo.GetGoPath()) {
|
|
continue
|
|
}
|
|
|
|
found.AppendByGoPath(repo)
|
|
|
|
}
|
|
|
|
// make the window for the first time
|
|
t = addWindowPB(insertWin, found)
|
|
f := func(repo *gitpb.Repo) {
|
|
log.Info("got to ReposTable.Custom() id =", repo.GetGoPath(), repo.GetCurrentVersion())
|
|
}
|
|
t.Custom(f)
|
|
log.Info("table has uuid", t.GetUuid())
|
|
})
|
|
})
|
|
|
|
grid.NewButton("Configure", func() {
|
|
log.Info("add a forge config window here")
|
|
})
|
|
|
|
win.Top.NewGroup("misc (works in progress)")
|
|
|
|
grid = win.Top.RawGrid()
|
|
var found *gitpb.Repos
|
|
var txt string
|
|
|
|
found = develBehindMasterProblem()
|
|
txt = fmt.Sprintf("devel is behind master (%d)", found.Len())
|
|
grid.NewButton(txt, func() {
|
|
win := gadgets.RawBasicWindow("devel branches that are out of sync with master")
|
|
win.Make()
|
|
win.Show()
|
|
win.Custom = func() {
|
|
// sets the hidden flag to false so Toggle() works
|
|
win.Hide()
|
|
}
|
|
box := win.Box().NewBox("bw vbox", false)
|
|
|
|
found := develBehindMasterProblem()
|
|
group := box.NewGroup("test buttons")
|
|
hbox := group.Box().Horizontal()
|
|
hbox.NewButton("git merge master devel", func() {
|
|
all := found.SortByFullPath()
|
|
for all.Scan() {
|
|
repo := all.Next()
|
|
mname := repo.GetMasterBranchName()
|
|
dname := repo.GetDevelBranchName()
|
|
if dname != repo.GetCurrentBranchName() {
|
|
log.Info("Repo is not on the devel branch", repo.GetGoPath())
|
|
}
|
|
cmd := []string{"git", "merge", mname}
|
|
log.Info(repo.GetGoPath(), cmd)
|
|
repo.RunVerbose(cmd)
|
|
}
|
|
})
|
|
hbox.NewButton("test", func() {
|
|
})
|
|
|
|
t := makeDevelBehindMaster(found)
|
|
t.SetParent(box)
|
|
t.ShowTable()
|
|
})
|
|
|
|
found = remoteUserBranchProblem()
|
|
txt = fmt.Sprintf("user branch is remote (%d)", found.Len())
|
|
grid.NewButton(txt, func() {
|
|
win := gadgets.RawBasicWindow("repos that seem to have remote user branches")
|
|
win.Make()
|
|
win.Show()
|
|
win.Custom = func() {
|
|
// sets the hidden flag to false so Toggle() works
|
|
win.Hide()
|
|
}
|
|
box := win.Box().NewBox("bw vbox", false)
|
|
|
|
found := remoteUserBranchProblem()
|
|
group := box.NewGroup("test buttons")
|
|
hbox := group.Box().Horizontal()
|
|
hbox.NewButton("git branch delete", func() {
|
|
win.Disable()
|
|
defer win.Enable()
|
|
all := found.SortByFullPath()
|
|
for all.Scan() {
|
|
repo := all.Next()
|
|
brname := repo.GetUserBranchName()
|
|
// git push origin --delete jcarr
|
|
os.Setenv("GIT_TERMINAL_PROMPT", "0")
|
|
cmd := []string{"git", "push", "origin", "--delete", brname}
|
|
log.Info("You may want to run:", repo.GetGoPath(), cmd)
|
|
repo.RunVerbose(cmd)
|
|
os.Unsetenv("GIT_TERMINAL_PROMPT")
|
|
|
|
// git branch --delete --remote origin/jcarr
|
|
cmd = []string{"git", "branch", "--delete", "--remote", "origin/" + brname}
|
|
log.Info(repo.GetGoPath(), cmd)
|
|
repo.RunVerbose(cmd)
|
|
repo.Reload()
|
|
}
|
|
me.forge.SetConfigSave(true)
|
|
me.forge.ConfigSave()
|
|
})
|
|
|
|
t := makeStandardReposGrid(found)
|
|
t.SetParent(box)
|
|
t.ShowTable()
|
|
})
|
|
|
|
rwin.boxTB = win.Bottom.Box()
|
|
|
|
grid.NewButton("dirty on bottom", func() {
|
|
log.Info("try to show dirty repos on bottom")
|
|
found := findDirty()
|
|
rwin.doReposTable(found)
|
|
|
|
})
|
|
grid.NextRow()
|
|
|
|
found = develRemoteProblem()
|
|
txt = fmt.Sprintf("remote devel != local devel (%d)", found.Len())
|
|
grid.NewButton(txt, func() {
|
|
found := develRemoteProblem()
|
|
makeStandardReposWindow(txt, found)
|
|
})
|
|
|
|
found = masterRemoteProblem()
|
|
txt = fmt.Sprintf("remote master != local master (%d)", found.Len())
|
|
grid.NewButton(txt, func() {
|
|
found := masterRemoteProblem()
|
|
makeStandardReposWindow(txt, found)
|
|
})
|
|
grid.NextRow()
|
|
|
|
makeHackModeWindow(win)
|
|
return rwin
|
|
}
|
|
|
|
// table of devel errors behind master
|
|
func makeDevelBehindMaster(pb *gitpb.Repos) *gitpb.ReposTable {
|
|
t := pb.NewTable("testDirty")
|
|
t.NewUuid()
|
|
sf := t.AddStringFunc("repo", func(r *gitpb.Repo) string {
|
|
return r.GetGoPath()
|
|
})
|
|
sf.Custom = func(r *gitpb.Repo) {
|
|
log.Info("merge master into devel here", r.GetGoPath())
|
|
}
|
|
t.AddTimeFunc("age", func(repo *gitpb.Repo) time.Time {
|
|
return repo.NewestTime()
|
|
})
|
|
t.AddMasterVersion()
|
|
t.AddDevelVersion()
|
|
t.AddState()
|
|
return t
|
|
}
|
|
|
|
// default window for active running droplets
|
|
func (rwin *stdReposTableWin) doReposTable(pb *gitpb.Repos) {
|
|
rwin.Lock()
|
|
defer rwin.Unlock()
|
|
if rwin.TB != nil {
|
|
rwin.TB.Delete()
|
|
rwin.TB = nil
|
|
}
|
|
|
|
rwin.pb = pb
|
|
|
|
t := makeStandardReposGrid(pb)
|
|
t.SetParent(rwin.boxTB)
|
|
t.ShowTable()
|
|
rwin.TB = t
|
|
}
|
|
|
|
func makeHackModeWindow(win *gadgets.GenericWindow) {
|
|
group := win.Top.NewGroup("This is a work in progress")
|
|
grid := group.RawGrid()
|
|
grid.NewButton("git pull", func() {
|
|
log.Info("todo: run git pull on each repo")
|
|
})
|
|
|
|
me.repoDevelMergeB = grid.NewButton("merge", func() {
|
|
found := findMergeToDevel()
|
|
_, box := makeStandardReposWindow("repos to merge from user to devel", found)
|
|
hbox := box.Box().Horizontal()
|
|
hbox.NewButton("merge all", func() {
|
|
win.Disable()
|
|
defer win.Enable()
|
|
all := found.SortByFullPath()
|
|
for all.Scan() {
|
|
repo := all.Next()
|
|
if repo.CheckDirty() {
|
|
log.Info("repo is dirty", repo.GetGoPath())
|
|
continue
|
|
}
|
|
log.Info("Starting merge on", repo.GetGoPath())
|
|
if repo.CheckoutDevel() {
|
|
log.Info("checkout devel failed", repo.GetGoPath())
|
|
return
|
|
}
|
|
if _, err := repo.MergeToDevel(); err != nil {
|
|
log.Info("merge from user failed", repo.GetGoPath(), err)
|
|
// log.Info(strings.Join(r.Stdout, "\n"))
|
|
// log.Info(strings.Join(r.Stderr, "\n"))
|
|
return
|
|
}
|
|
if repo.CheckoutMaster() {
|
|
log.Info("checkout master failed", repo.GetGoPath())
|
|
return
|
|
}
|
|
if _, err := repo.MergeToMaster(); err != nil {
|
|
log.Info("merge from devel failed", repo.GetGoPath(), err)
|
|
return
|
|
}
|
|
|
|
}
|
|
})
|
|
})
|
|
grid.NextRow()
|
|
|
|
group2 := win.Top.NewGroup("Merge")
|
|
grid = group2.RawGrid()
|
|
|
|
grid.NewButton("merge to devel", func() {
|
|
win.Disable()
|
|
defer win.Enable()
|
|
|
|
mergeUserToDevel(true)
|
|
})
|
|
|
|
grid.NewButton("merge to master", func() {
|
|
win.Disable()
|
|
defer win.Enable()
|
|
|
|
mergeDevelToMaster(true)
|
|
})
|
|
|
|
grid.NewButton("merge all", func() {
|
|
win.Disable()
|
|
defer win.Enable()
|
|
|
|
me.argvCheckoutUser = false
|
|
me.argvCheckoutDevel = true
|
|
me.argvCheckoutMaster = false
|
|
if err := doCheckoutShared(); err != nil {
|
|
log.Info("checkout error:", err)
|
|
} else {
|
|
log.Info("checkout was ok")
|
|
}
|
|
|
|
mergeUserToDevel(true)
|
|
|
|
me.argvCheckoutUser = false
|
|
me.argvCheckoutDevel = false
|
|
me.argvCheckoutMaster = true
|
|
if err := doCheckoutShared(); err != nil {
|
|
log.Info("checkout error:", err)
|
|
} else {
|
|
log.Info("checkout was ok")
|
|
}
|
|
|
|
mergeDevelToMaster(true)
|
|
})
|
|
|
|
group3 := win.Top.NewGroup("work in progress")
|
|
grid = group3.RawGrid()
|
|
|
|
grid.NewButton("forge ConfigSave()", func() {
|
|
me.forge.ConfigSave()
|
|
})
|
|
|
|
grid.NewButton("debugger()", func() {
|
|
debugger.DebugWindow()
|
|
})
|
|
}
|
|
|
|
func develBehindMasterProblem() *gitpb.Repos {
|
|
found := new(gitpb.Repos)
|
|
all := me.forge.Repos.SortByFullPath()
|
|
for all.Scan() {
|
|
repo := all.Next()
|
|
if repo.GetDevelVersion() == repo.GetMasterVersion() {
|
|
continue
|
|
}
|
|
found.AppendByGoPath(repo)
|
|
|
|
}
|
|
return found
|
|
}
|
|
|
|
func remoteUserBranchProblem() *gitpb.Repos {
|
|
found := new(gitpb.Repos)
|
|
all := me.forge.Repos.SortByFullPath()
|
|
for all.Scan() {
|
|
repo := all.Next()
|
|
username := repo.GetUserBranchName()
|
|
if repo.IsBranchRemote(username) {
|
|
found.AppendByGoPath(repo)
|
|
}
|
|
|
|
}
|
|
return found
|
|
}
|
|
|
|
func develRemoteProblem() *gitpb.Repos {
|
|
found := new(gitpb.Repos)
|
|
all := me.forge.Repos.SortByFullPath()
|
|
for all.Scan() {
|
|
repo := all.Next()
|
|
brname := repo.GetDevelBranchName()
|
|
if !repo.IsBranchRemote(brname) {
|
|
// log.Info("repo does not have remote devel branch", repo.GetGoPath())
|
|
continue
|
|
}
|
|
lhash := repo.GetLocalHash(brname)
|
|
rhash := repo.GetRemoteHash(brname)
|
|
// log.Info(lhash, rhash, repo.GetGoPath())
|
|
if lhash == "" || rhash == "" {
|
|
// something is wrong if either of these are blank
|
|
found.AppendByGoPath(repo)
|
|
continue
|
|
}
|
|
if lhash == rhash {
|
|
continue
|
|
}
|
|
found.AppendByGoPath(repo)
|
|
|
|
}
|
|
return found
|
|
}
|
|
|
|
func masterRemoteProblem() *gitpb.Repos {
|
|
found := new(gitpb.Repos)
|
|
all := me.forge.Repos.SortByFullPath()
|
|
for all.Scan() {
|
|
repo := all.Next()
|
|
brname := repo.GetMasterBranchName()
|
|
if !repo.IsBranchRemote(brname) {
|
|
// log.Info("repo does not have remote devel branch", repo.GetGoPath())
|
|
continue
|
|
}
|
|
lhash := repo.GetLocalHash(brname)
|
|
rhash := repo.GetRemoteHash(brname)
|
|
// log.Info(lhash, rhash, repo.GetGoPath())
|
|
if lhash == "" || rhash == "" {
|
|
// something is wrong if either of these are blank
|
|
found.AppendByGoPath(repo)
|
|
continue
|
|
}
|
|
if lhash == rhash {
|
|
continue
|
|
}
|
|
found.AppendByGoPath(repo)
|
|
|
|
}
|
|
return found
|
|
}
|
|
|
|
func makeWritableWindow(pb *gitpb.Repos) (*gadgets.GenericWindow, *gitpb.ReposTable) {
|
|
win := gadgets.NewGenericWindow("Repos You have write access to", "Configure")
|
|
t := pb.NewTable("testForgeRepos")
|
|
t.NewUuid()
|
|
|
|
grid := win.Group.RawGrid()
|
|
grid.NewButton("git pull", func() {
|
|
log.Info("todo: run git pull on each repo")
|
|
})
|
|
|
|
/*
|
|
grid.NewButton("do repos.ReScan()", func() {
|
|
t.Update()
|
|
})
|
|
*/
|
|
|
|
tbox := win.Bottom.Box()
|
|
t.SetParent(tbox)
|
|
|
|
sf := t.AddStringFunc("repo", func(r *gitpb.Repo) string {
|
|
return r.GetGoPath()
|
|
})
|
|
sf.Custom = func(r *gitpb.Repo) {
|
|
log.Info("do button click on", r.GetGoPath())
|
|
}
|
|
t.AddTimeFunc("age", func(repo *gitpb.Repo) time.Time {
|
|
return repo.NewestTime()
|
|
})
|
|
t.AddMasterVersion()
|
|
t.AddDevelVersion()
|
|
t.AddUserVersion()
|
|
t.AddCurrentBranchName()
|
|
t.AddState()
|
|
t.ShowTable()
|
|
return win, t
|
|
}
|
|
|
|
func makeWindowForPB() *gadgets.GenericWindow {
|
|
win := gadgets.NewGenericWindow("Raw PB View", "Configure")
|
|
|
|
return win
|
|
}
|
|
|
|
func addWindowPB(win *gadgets.GenericWindow, pb *gitpb.Repos) *gitpb.ReposTable {
|
|
t := pb.NewTable("testForgeRepos")
|
|
t.NewUuid()
|
|
tbox := win.Bottom.Box().SetProgName("TBOX")
|
|
t.SetParent(tbox)
|
|
|
|
sf := t.AddStringFunc("repo", func(r *gitpb.Repo) string {
|
|
return r.GetGoPath()
|
|
})
|
|
sf.Custom = func(r *gitpb.Repo) {
|
|
log.Info("do button click on", r.GetGoPath())
|
|
}
|
|
t.AddTimeFunc("age", func(repo *gitpb.Repo) time.Time {
|
|
return repo.NewestTime()
|
|
})
|
|
t.AddMasterVersion()
|
|
t.AddDevelVersion()
|
|
t.AddUserVersion()
|
|
t.AddCurrentBranchName()
|
|
t.AddState()
|
|
f := func(repo *gitpb.Repo) string {
|
|
log.Info("repo =", repo.GetGoPath(), repo.GetCurrentVersion())
|
|
return repo.GetGoPath()
|
|
}
|
|
t.AddButtonFunc("cur version", f)
|
|
t.ShowTable()
|
|
return t
|
|
}
|
|
|
|
func makeReposWindowNew() *gadgets.GenericWindow {
|
|
win := gadgets.NewGenericWindow("git repos", "Filter")
|
|
win.Custom = func() {
|
|
// sets the hidden flag to false so Toggle() works
|
|
win.Hide()
|
|
}
|
|
|
|
hbox := win.Group.Box().Horizontal()
|
|
hbox.NewCheckbox("broken")
|
|
hbox.NewCheckbox("dirty")
|
|
hbox.NewCheckbox("mine")
|
|
hbox.NewButton("fix all", func() {
|
|
log.Info("try to fix everything here")
|
|
})
|
|
|
|
t := makeStandardReposGrid(me.forge.Repos)
|
|
t.SetParent(win.Bottom)
|
|
t.ShowTable()
|
|
return win
|
|
}
|