// Copyright 2017-2025 WIT.COM Inc. All rights reserved. // Use of this source code is governed by the GPL 3.0 package main import ( "fmt" "os" "path/filepath" "sync" "go.wit.com/gui" "go.wit.com/lib/gadgets" "go.wit.com/lib/protobuf/forgepb" "go.wit.com/lib/protobuf/gitpb" "go.wit.com/log" ) type stdPatchTableWin struct { sync.Mutex win *gadgets.GenericWindow // the machines gui window box *gui.Node // the machines gui parent box widget TB *forgepb.PatchesTable // the gui table buffer update bool // if the window should be updated } func (w *stdPatchTableWin) Toggle() { if w == nil { return } if w.win == nil { return } w.win.Toggle() } func makePatchesWin(patches *forgepb.Patches) *stdPatchTableWin { dwin := new(stdPatchTableWin) dwin.win = gadgets.NewGenericWindow("current patches", "patching options") dwin.win.Custom = func() { log.Info("test delete window here") dwin.win.Hide() // dwin = nil } grid := dwin.win.Group.RawGrid() grid.NewLabel(fmt.Sprintf("%d", patches.Len())) grid.NewLabel(fmt.Sprintf("total patches")) grid.NextRow() repomap := make(map[string]int) all := patches.All() for all.Scan() { patch := all.Next() repomap[patch.Namespace] += 1 } grid.NewLabel(fmt.Sprintf("%d", len(repomap))) grid.NewLabel(fmt.Sprintf("total repos")) grid.NextRow() grid.NewButton("Update", func() { log.Info("TODO: doesn't update this window") me.forge.GetPatches() dwin.win.Custom() // loadUpstreamPatchsets() }) grid.NewButton("Apply All", func() { var count int all := patches.SortByFilename() for all.Scan() { p := all.Next() applyPatchNew(p) /* rn := p.Namespace repo := me.forge.FindByGoPath(rn) if repo == nil { log.Info("Could not figure out repo path", rn) return } count += 1 if _, err := applyAndTrackPatch(repo, p); err != nil { cmd := []string{"git", "am", "--abort"} err := repo.RunVerbose(cmd) log.Info("warn user of git am error", err) return } */ } log.Info("ALL PATCHES WORKED! count =", count) }) // make a box at the bottom of the window for the protobuf table dwin.box = dwin.win.Bottom.Box().SetProgName("TBOX") if patches != nil { dwin.doPatchesTable(patches) } return dwin } func applyPatchNew(p *forgepb.Patch) error { rn := p.Namespace repo := me.forge.FindByGoPath(rn) if repo == nil { log.Info("Could not figure out repo path", rn) return log.Errorf("%s namespace?\n", rn) } if _, err := applyAndTrackPatch(repo, p); err != nil { cmd := []string{"git", "am", "--abort"} err := repo.RunVerbose(cmd) log.Info("warn user of git am error", err) return err } return nil } func (dwin *stdPatchTableWin) doPatchesTable(currentPatches *forgepb.Patches) { dwin.Lock() defer dwin.Unlock() if dwin.TB != nil { dwin.TB.Delete() dwin.TB = nil } // display the protobuf dwin.TB = AddPatchesPB(dwin.box, currentPatches) f := func(p *forgepb.Patch) { log.Info("do something with patch", p.Filename) } dwin.TB.Custom(f) } // used by the PB table func applyPatchLabel(p *forgepb.Patch) string { rn := p.Namespace if repo := me.forge.FindByGoPath(rn); repo == nil { // log.Info("Could not figure out repo path", rn) return "" } if p.NewHash == "na" { return "git am" } if p.NewHash == "" { return "new" } return "done" } func applyPatchClick(p *forgepb.Patch) { if err := applyPatchNew(p); err != nil { log.Info("git am failed on file", p.Filename, "with error", err) return } log.Info("ran: git am", p.Filename, "ok") } // define what rows to have in the protobuf table func AddPatchesPB(tbox *gui.Node, pb *forgepb.Patches) *forgepb.PatchesTable { t := pb.NewTable("PatchesPB") t.NewUuid() t.SetParent(tbox) gitam := t.AddButtonFunc("apply", applyPatchLabel) gitam.Custom = applyPatchClick t.AddCommitHash() t.AddNamespace() // t.AddFilename() t.AddStringFunc("file", func(p *forgepb.Patch) string { _, fname := filepath.Split(p.Filename) return fname }) t.AddCommitHash() t.ShowTable() return t } func applyPatch(repo *gitpb.Repo, filename string) error { cmd := []string{"git", "am", filename} err := repo.RunVerbose(cmd) return err } func savePatch(p *forgepb.Patch) (string, error) { _, filen := filepath.Split(p.Filename) tmpname := filepath.Join("/tmp", filen) log.Info("saving as", tmpname, p.Filename) raw, err := os.OpenFile(tmpname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { return "", err } raw.Write(p.Data) raw.Close() return tmpname, nil } func applyAndTrackPatch(repo *gitpb.Repo, p *forgepb.Patch) (string, error) { _, filen := filepath.Split(p.Filename) tmpname := filepath.Join("/tmp", filen) log.Info("saving as", tmpname, p.Filename) raw, err := os.OpenFile(tmpname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) if err != nil { return "", err } raw.Write(p.Data) raw.Close() cmd := []string{"git", "am", tmpname} err = repo.RunVerbose(cmd) if err != nil { log.Info("git am failed. run 'git am --abort' here") return "", log.Errorf("git am failed") } log.Info("Try to find hash value now") p.NewHash = "fixme applyAndTrack" if setNewHash(p, p.NewHash) { log.Info("setting NewHash worked", p.NewHash) } me.forge.SavePatchsets() return p.NewHash, log.Errorf("did not lookup new hash") } func setNewHash(p *forgepb.Patch, hash string) bool { for pset := range me.forge.Patchsets.IterAll() { for patch := range pset.Patches.IterAll() { if patch.CommitHash == hash { patch.NewHash = hash log.Info("found patch in repo") me.forge.SavePatchsets() return true } } } return false }