repostatus/tagWindow.go

312 lines
6.4 KiB
Go

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
// the tag comment
subject *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 (tw *repoTags) Hidden() bool {
return tw.window.Hidden()
}
func (tw *repoTags) Show() {
log.Info("tw *repoTags Show()")
tw.window.Show()
}
func (tw *repoTags) Hide() {
log.Info("tw *repoTags Hide()")
tw.window.Hide()
}
func (rs *RepoStatus) TagWindow() *repoTags {
// return the window if it was already created
tags := new(repoTags)
rs.TagsW = tags
tags.rs = rs
tags.window = gadgets.RawBasicWindow("tags " + rs.String()).Make()
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()
// })
var dups *gui.Node
dups = tagW.group.NewCheckbox("Show duplicate tags").SetChecked(false)
dups.Custom = func() {
if dups.Checked() {
tagW.Prune()
} else {
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", 0, 0)
tagW.grid = grid
grid.NewLabel("version")
grid.NewLabel("ref")
grid.NewLabel("date")
grid.NewLabel("release subject")
// 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)", "%(subject)"}
format := strings.Join(tags, "_,,,_")
cmd := []string{"git", "for-each-ref", "--sort=taggerdate", "--format", format}
log.Info("RUNNING:", strings.Join(cmd, " "))
err, output := tagW.rs.RunCmd(cmd)
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])
stamp, dur := getDateStamp(parts[2]) //
rTag.date = grid.NewLabel(stamp)
grid.NewLabel(dur)
rTag.subject = grid.NewLabel(parts[3])
rTag.deleteB = grid.NewButton("delete", func() {
tagversion := parts[0]
log.Info("remove tag", tagversion)
var all [][]string
all = append(all, []string{"git", "tag", "--delete", tagversion})
all = append(all, []string{"git", "push", "--delete", "origin", tagversion})
if tagW.rs.DoAll(all) {
log.Info("TAG DELETED", tagW.rs.String(), tagversion)
} else {
log.Info("TAG DELETE FAILED", tagW.rs.String(), tagversion)
}
})
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()) {
if first {
log.Info("keep first tag", i, t.tag.String())
t.Hide()
first = false
continue
}
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.subject.Hide()
rt.deleteB.Hide()
}
func (rt *repoTag) Show() {
rt.hidden = false
rt.tag.Show()
rt.ref.Show()
rt.date.Show()
rt.subject.Show()
rt.deleteB.Show()
}