From 49724b16e81d114c7024c4c446cfcb76013c57dc Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Wed, 7 Feb 2024 08:51:45 -0600 Subject: [PATCH] more on tags Signed-off-by: Jeff Carr --- draw.go | 39 ++++---- structs.go | 3 + tagWindow.go | 266 +++++++++++++++++++++++++++++++++++++++++++++++++++ unix.go | 1 - 4 files changed, 292 insertions(+), 17 deletions(-) create mode 100644 tagWindow.go diff --git a/draw.go b/draw.go index 96c4aa3..8a89255 100644 --- a/draw.go +++ b/draw.go @@ -53,23 +53,21 @@ func (rs *RepoStatus) drawGitBranches() { } }) - /* - newgrid.NewButton("show .git/config", func() { - if rs.gitConfig == nil { - log.Log(WARN, "Nonexistant or damaged .git/config", rs.String()) - return - } - log.Log(WARN, ".git/config:", rs.realPath.String()) + newgrid.NewButton("show .git/config", func() { + if rs.gitConfig == nil { + log.Log(WARN, "Nonexistant or damaged .git/config", rs.String()) + return + } + log.Log(WARN, ".git/config:", rs.realPath.String()) - // The info: - for name, remote := range rs.gitConfig.remotes { - log.Log(WARN, " ", name, "url:", remote.url) - } - for name, branch := range rs.gitConfig.branches { - log.Log(WARN, " ", name, "remote:", branch.remote, "merge", branch.merge) - } - }) - */ + // The info: + for name, remote := range rs.gitConfig.remotes { + log.Log(WARN, " ", name, "url:", remote.url) + } + for name, branch := range rs.gitConfig.branches { + log.Log(WARN, " ", name, "remote:", branch.remote, "merge", branch.merge) + } + }) newgrid.NewButton("CheckDirty()", func() { if rs.CheckDirty() { @@ -79,6 +77,15 @@ func (rs *RepoStatus) drawGitBranches() { } }) + newgrid.NewButton("Show tags", func() { + tw := rs.TagWindow() + tw.Prune() + // git tag --list --sort=taggerdate + // git for-each-ref --sort=taggerdate --format '%(tag) %(*objectname) %(taggerdate)' + // git rev-parse HEAD + // if last tag == HEAD, then remove it + }) + /* newgrid.NewButton("CheckSafeGoSumRemake()", func() { if ok, bad := rs.CheckSafeGoSumRemake(); ok { diff --git a/structs.go b/structs.go index c23f480..a21d92f 100644 --- a/structs.go +++ b/structs.go @@ -17,6 +17,9 @@ type RepoStatus struct { window *gadgets.BasicWindow + // a window to manage your .git tags + TagsW *repoTags + dirtyLabel *gadgets.OneLiner readOnly *gadgets.OneLiner goSumStatus *gadgets.OneLiner diff --git a/tagWindow.go b/tagWindow.go new file mode 100644 index 0000000..fcf1d56 --- /dev/null +++ b/tagWindow.go @@ -0,0 +1,266 @@ +package repostatus + +import ( + "regexp" + "slices" + "strings" + + "go.wit.com/gui" + "go.wit.com/lib/gadgets" + "go.wit.com/log" +) + +type repoTag struct { + // tracks if the tag is displayed + hidden bool + + // the tag "v0.1.3" + tag *gui.Node + + // the .git/ref hash + ref *gui.Node + + // the .git/ref date + date *gui.Node + + // a button to delete the tag + deleteB *gui.Node +} + +type repoTags struct { + // the originating repository + rs *RepoStatus + + // the window for the tags + window *gadgets.BasicWindow + + // the box to list all the tags in + box *gui.Node + group *gui.Node + grid *gui.Node + + // all the tags + tags []*repoTag +} + +func (rs *RepoStatus) TagWindow() *repoTags { + // return the window if it was already created + if rs.TagsW != nil { + rs.TagsW.window.Toggle() + return rs.TagsW + } + tags := new(repoTags) + rs.TagsW = tags + tags.rs = rs + + tags.window = gadgets.RawBasicWindow("tags " + rs.String()) + vbox := tags.window.Box() + + tags.newTagBox(vbox) + return tags +} + +func (tagW *repoTags) newTagBox(box *gui.Node) { + tagW.group = box.NewGroup(".git tags for " + tagW.rs.String()) + + tagW.group.NewButton("prune tags", func() { + tagW.Prune() + }) + tagW.group.NewButton("show all", func() { + for _, t := range tagW.tags { + t.Show() + } + }) + tagW.group.NewButton("delete all", func() { + for i, t := range tagW.tags { + if t.hidden { + // log.Info("tag is hidden", i, t.tag.String()) + continue + } + log.Info("tag is shown", i, t.tag.String()) + tagW.Delete(t) + } + }) + + grid := tagW.group.NewGrid("tags", 4, 1) + tagW.grid = grid + + grid.NewLabel("version") + grid.NewLabel("ref") + grid.NewLabel("date") + grid.NewLabel("delete") + // works like a typerwriter + // grid.NextRow() + + // git tag --list --sort=taggerdate + // git for-each-ref --sort=taggerdate --format '%(tag) %(*objectname) %(taggerdate)' + // git rev-parse HEAD + // if last tag == HEAD, then remove it + + tags := []string{"%(tag)", "%(*objectname)", "%(taggerdate:raw)"} + format := strings.Join(tags, "_,,,_") + err, output := tagW.rs.RunCmd([]string{"git", "for-each-ref", "--sort=taggerdate", "--format", format}) + if err != nil { + output = "git error_,,,_a_,,,_b_,,,c" + } + + lines := strings.Split(output, "\n") + // reverse the git order + slices.Reverse(lines) + tagW.tags = make([]*repoTag, 0) + + for i, line := range lines { + var parts []string + parts = make([]string, 6) + parts = strings.Split(line, "_,,,_") + log.Info("found tag:", i, parts) + if parts[0] == "" { + continue + } + rTag := new(repoTag) + rTag.tag = grid.NewLabel(parts[0]) + rTag.ref = grid.NewEntrybox(parts[1]) + rTag.date = grid.NewLabel(parts[2]) + rTag.deleteB = grid.NewButton("delete", func() { + log.Info("remove tag") + }) + + tagW.tags = append(tagW.tags, rTag) + // works like a typerwriter + // grid.NextRow() + } + // reverse the git order + // slices.Reverse(rtags.tags) +} + +func (rtags *repoTags) ListAll() []*repoTag { + var tags []*repoTag + for _, t := range rtags.tags { + tags = append(tags, t) + } + return tags +} + +func (rtags *repoTags) List() []*repoTag { + var tags []*repoTag + for _, t := range rtags.tags { + if t.hidden { + // log.Info("tag is hidden", i, t.tag.String()) + continue + } + // log.Info("tag is shown", t.tag.String(), rtags.rs.String()) + tags = append(tags, t) + } + return tags +} + +func (rtags *repoTags) Prune() { + dups := make(map[string]*repoTag) + for i, t := range rtags.tags { + if t == nil { + log.Info("tag empty:", i) + continue + } + ref := t.ref.String() + _, ok := dups[ref] + if ok { + log.Info("tag is duplicate:", i, t.tag.String()) + } else { + log.Info("new tag", i, t.tag.String()) + dups[ref] = t + t.Hide() + } + + } +} + +// hide tags worth keeping +func (rtags *repoTags) PruneSmart() { + // always keep the first tag + var first bool = true + + dups := make(map[string]*repoTag) + for i, t := range rtags.tags { + if t == nil { + log.Info("tag empty:", i) + continue + } + + // check for duplicate tags + ref := t.ref.String() + _, ok := dups[ref] + if ok { + log.Info("tag is duplicate:", i, t.tag.String()) + continue + } + dups[ref] = t + + // dump any tags that don't start with 'v' + //if !strings.HasPrefix(t.tag.String(), "v") { + // log.Info("tag does not start with v", i, t.tag.String()) + // continue + //} + + isVersion := regexp.MustCompile("v[0-9]+.[0-9]+.[0-9]+").MatchString + if isVersion(t.tag.String()) { + log.Info("valid tag", i, t.tag.String()) + t.Hide() + continue + } + + if first { + log.Info("keep first tag", i, t.tag.String()) + t.Hide() + first = false + continue + } + + log.Info("keep tag", i, t.tag.String()) + } +} + +// deleting it locally triggers some but when +// the git server was uncontactable (over IPv6 if that matters, probably it doesn't) +// and then the local delete re-added it into the tag +func (rtags *repoTags) Delete(rt *repoTag) { + rs := rtags.rs + + cmd := []string{"git", "push", "--delete", "origin", rt.tag.String()} + log.Info("RUN:", cmd) + err, output := rs.RunCmd(cmd) + if err != nil { + log.Info("cmd failed", err) + log.Info("output:", output) + } + log.Info("output:", output) + + cmd = []string{"git", "tag", "--delete", rt.tag.String()} + log.Info("RUN:", cmd) + err, output = rs.RunCmd(cmd) + if err != nil { + log.Info("cmd failed", err) + log.Info("output:", output) + } + log.Info("output:", output) + +} + +func (rt *repoTag) TagString() string { + return rt.tag.String() +} + +func (rt *repoTag) Hide() { + rt.hidden = true + rt.tag.Hide() + rt.ref.Hide() + rt.date.Hide() + rt.deleteB.Hide() +} + +func (rt *repoTag) Show() { + rt.hidden = false + rt.tag.Show() + rt.ref.Show() + rt.date.Show() + rt.deleteB.Show() +} diff --git a/unix.go b/unix.go index ddd9379..1126a1b 100644 --- a/unix.go +++ b/unix.go @@ -1,4 +1,3 @@ -// This is a simple example package repostatus import (