diff options
| author | Jeff Carr <[email protected]> | 2025-03-23 08:51:06 -0500 |
|---|---|---|
| committer | Jeff Carr <[email protected]> | 2025-03-23 08:51:06 -0500 |
| commit | edc362f4b981ed466c8d9038c42e9bda8a5dbe41 (patch) | |
| tree | afd9e1e37c205481311757c4b5ffd21f3403125e /windowPatchsets.go | |
| parent | 033e81bb224fc1369ac26cc4e5c38bf261b86b46 (diff) | |
rename
Diffstat (limited to 'windowPatchsets.go')
| -rw-r--r-- | windowPatchsets.go | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/windowPatchsets.go b/windowPatchsets.go new file mode 100644 index 0000000..36ee7ba --- /dev/null +++ b/windowPatchsets.go @@ -0,0 +1,384 @@ +// Copyright 2017-2025 WIT.COM Inc. All rights reserved. +// Use of this source code is governed by the GPL 3.0 + +package main + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "regexp" + "strings" + "sync" + + "go.wit.com/gui" + "go.wit.com/lib/gadgets" + "go.wit.com/lib/protobuf/forgepb" + "go.wit.com/log" +) + +type stdPatchsetTableWin struct { + sync.Mutex + win *gadgets.GenericWindow // the machines gui window + box *gui.Node // the machines gui parent box widget + TB *forgepb.PatchsetsTable // the gui table buffer + update bool // if the window should be updated +} + +func (w *stdPatchsetTableWin) Toggle() { + if w == nil { + return + } + if w.win == nil { + return + } + w.win.Toggle() +} + +func makePatchsetsWin() *stdPatchsetTableWin { + dwin := new(stdPatchsetTableWin) + dwin.win = gadgets.NewGenericWindow("forge current patchsets", "patchset options") + dwin.win.Custom = func() { + log.Info("test delete window here") + } + grid := dwin.win.Group.RawGrid() + + grid.NewButton("ondisk", func() { + openPatchsets() + if me.psets == nil { + log.Info("No Patchsets loaded") + return + } + dwin.doPatchsetsTable(me.psets) + }) + + grid.NewButton("upstream", func() { + psets, err := me.forge.GetPatchesets() + if err != nil { + log.Info("Get Patchsets failed", err) + return + } + + var foundnew bool + all := psets.All() + for all.Scan() { + pset := all.Next() + found := me.psets.FindByUuid(pset.Uuid) + if found == nil { + log.Info("new patchset", pset.Name, pset.Uuid) + pset.State = "new" + foundnew = true + } else { + log.Info("patchset already on disk", found.Name, found.State) + pset.State = found.State + if pset.State == "" { + pset.State = "new" + } + } + } + dwin.doPatchsetsTable(psets) + if foundnew { + log.Info("should save these here") + me.psets = psets + savePatchsets() + } + }) + + grid.NewButton("save", func() { + if me.psets == nil { + log.Info("No Patchsets loaded") + return + } + savePatchsets() + }) + + grid.NewButton("set patchset state", func() { + if me.psets == nil { + log.Info("No Patchsets loaded") + return + } + all := me.psets.All() + for all.Scan() { + pset := all.Next() + if pset.State == "" { + log.Info("What is up with?", pset.Name) + setPatchsetState(pset) + } else { + log.Info("patchset already had state", pset.Name, pset.State) + } + } + savePatchsets() + }) + + grid.NewButton("find commit hashes", func() { + if me.psets == nil { + log.Info("No Patchsets loaded") + return + } + all := me.psets.All() + for all.Scan() { + pset := all.Next() + if pset.State != "new" { + log.Info("patchset already had state", pset.Name, pset.State) + continue + } + if setNewCommitHash(pset) { + // everything in this patchset is applied + pset.State = "APPLIED" + } + } + savePatchsets() + }) + + grid.NewButton("show pending patches", func() { + if me.psets == nil { + log.Info("No Patchsets loaded") + return + } + notdone := new(forgepb.Patches) + + all := me.psets.All() + for all.Scan() { + pset := all.Next() + AddNotDonePatches(notdone, pset) + } + + for patch := range notdone.IterAll() { + comment := cleanSubject(patch.Comment) + log.Info("new patch:", patch.NewHash, "commithash:", patch.CommitHash, patch.RepoNamespace, comment) + } + // savePatchsets() + makePatchesWin(notdone) + }) + + // make a box at the bottom of the window for the protobuf table + dwin.box = dwin.win.Bottom.Box().SetProgName("TBOX") + + // load and show the current patch sets + openPatchsets() + if me.psets == nil { + log.Info("Open Patchsets failed") + return dwin + } + dwin.doPatchsetsTable(me.psets) + + return dwin +} + +func (dwin *stdPatchsetTableWin) doPatchsetsTable(currentPatchsets *forgepb.Patchsets) { + dwin.Lock() + defer dwin.Unlock() + if dwin.TB != nil { + dwin.TB.Delete() + dwin.TB = nil + } + + // display the protobuf + dwin.TB = AddPatchsetsPB(dwin.box, currentPatchsets) + f := func(pset *forgepb.Patchset) { + log.Info("Triggered. do something here", pset.Name) + /* + win := makePatchWindow(pset) + win.Show() + */ + } + dwin.TB.Custom(f) +} + +func AddPatchsetsPB(tbox *gui.Node, pb *forgepb.Patchsets) *forgepb.PatchsetsTable { + t := pb.NewTable("PatchsetsPB") + t.NewUuid() + t.SetParent(tbox) + + t.AddStringFunc("#", func(p *forgepb.Patchset) string { + return fmt.Sprintf("%d", p.Patches.Len()) + }) + + vp := t.AddButtonFunc("View Patchset", func(p *forgepb.Patchset) string { + return p.Name + }) + vp.Custom = func(pset *forgepb.Patchset) { + log.Info("show patches here", pset.Name) + makePatchesWin(pset.Patches) + // patchwin := makePatchesWin() + // patchwin.doPatchesTable(pset.Patches) + /* + win := makePatchWindow(pset) + win.Show() + */ + } + + t.AddComment() + t.AddState() + t.AddHostname() + + ctimef := func(p *forgepb.Patchset) string { + ctime := p.Ctime.AsTime() + return ctime.Format("2006/01/02 15:04") + } + t.AddStringFunc("ctime", ctimef) + + /* + etimef := func(e *forgepb.Patchset) string { + etime := e.Etime.AsTime() + s := etime.Format("2006/01/02 15:04") + if strings.HasPrefix(s, "1970/") { + // just show a blank if it's not set + return "" + } + return s + } + t.AddStringFunc("etime", etimef) + */ + + t.AddStringFunc("Author", func(p *forgepb.Patchset) string { + return fmt.Sprintf("%s <%s>", p.GitAuthorName, p.GitAuthorEmail) + }) + + t.AddUuid() + + newCommit := t.AddButtonFunc("new hash", func(p *forgepb.Patchset) string { + return "find" + }) + newCommit.Custom = func(pset *forgepb.Patchset) { + log.Info("find new commits here", pset.Name) + // makePatchesWin(pset.Patches) + setNewCommitHash(pset) + } + + t.ShowTable() + return t +} + +func setPatchsetState(p *forgepb.Patchset) { + var bad bool + var good bool + var done bool = true + + all := p.Patches.All() + for all.Scan() { + patch := all.Next() + // log.Info("patch:", patch.StartHash, patch.CommitHash, patch.RepoNamespace, patch.Filename) + repo := me.forge.FindByGoPath(patch.RepoNamespace) + if repo == nil { + log.Info("couldn't find repo", patch.RepoNamespace) + bad = true + continue + } + if _, err := repo.GetHashName(patch.CommitHash); err == nil { + // this patch has been applied + patch.Applied = true + done = true + continue + } + if name, err := repo.GetHashName(patch.StartHash); err == nil { + // it might be possible to apply this patch + log.Info("patch may be good:", patch.RepoNamespace, name, patch.CommitHash, patch.Filename) + good = true + } else { + // probably screwed up git trees + log.Info("patch with unknown origin:", patch.RepoNamespace, name, err, patch.CommitHash, patch.Filename) + bad = true + } + } + if bad { + p.State = "BAD" + return + } + if good { + p.State = "TRY" + return + } + if done { + p.State = "DONE" + return + } +} + +func cleanSubject(line string) string { + // Regular expression to remove "Subject:" and "[PATCH...]" patterns + re := regexp.MustCompile(`(?i)^Subject:\s*(\[\s*PATCH[^\]]*\]\s*)?`) + cleaned := re.ReplaceAllString(line, "") + return strings.TrimSpace(cleaned) +} + +func findCommitBySubject(subject string) (string, error) { + cmd := exec.Command("git", "log", "--pretty=format:%H %s", "--grep="+subject, "-i") + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() + if err != nil { + return "", err + } + + lines := strings.Split(out.String(), "\n") + for _, line := range lines { + if strings.Contains(strings.ToLower(line), strings.ToLower(subject)) { + return strings.Fields(line)[0], nil // return the commit hash + } + } + return "", fmt.Errorf("no commit found for subject: %s", subject) +} + +func setNewCommitHash(p *forgepb.Patchset) bool { + var done bool = true + for patch := range p.Patches.IterAll() { + // parts := strings.Fields(patch.Comment) + + repo := me.forge.FindByGoPath(patch.RepoNamespace) + if repo == nil { + log.Info("couldn't find repo", patch.RepoNamespace) + continue + } + + comment := cleanSubject(patch.Comment) + + if patch.NewHash != "na" { + log.Info("patch: newhash:", patch.NewHash, "commithash:", patch.CommitHash, patch.RepoNamespace, comment) + continue + } + done = false + os.Chdir(repo.GetFullPath()) + newhash, err := findCommitBySubject(comment) + if err != nil { + log.Info("patch: not found hash:", patch.CommitHash, patch.RepoNamespace, comment, newhash, err) + continue + } + patch.NewHash = newhash + log.Info("patch: found hash:", patch.CommitHash, newhash, patch.RepoNamespace, comment) + } + + return done +} + +func AddNotDonePatches(notdone *forgepb.Patches, pset *forgepb.Patchset) { + for patch := range pset.Patches.IterAll() { + // parts := strings.Fields(patch.Comment) + + repo := me.forge.FindByGoPath(patch.RepoNamespace) + if repo == nil { + log.Info("couldn't find repo", patch.RepoNamespace) + notdone.Append(patch) + continue + } + + comment := cleanSubject(patch.Comment) + + if patch.NewHash != "na" { + log.Info("already applied patch: newhash:", patch.NewHash, "commithash:", patch.CommitHash, patch.RepoNamespace, comment) + continue + } + os.Chdir(repo.GetFullPath()) + newhash, err := findCommitBySubject(comment) + if err == nil { + patch.NewHash = newhash + log.Info("patch: found hash:", patch.CommitHash, newhash, patch.RepoNamespace, comment) + continue + } + + // this patch has not been applied yet + log.Info("patch: not found hash:", patch.CommitHash, patch.RepoNamespace, comment, newhash, err) + notdone.Append(patch) + } +} |
