diff --git a/Makefile b/Makefile index 4a67a5a..2a5b530 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,5 @@ all: - @echo - @echo Run: make redomod - @echo + GO111MODULE=off go build goimports: goimports -w *.go diff --git a/branchesBox.go b/branchesBox.go index d24af80..c1de0e2 100644 --- a/branchesBox.go +++ b/branchesBox.go @@ -1,30 +1,33 @@ package repostatus import ( + "strings" + + "go.wit.com/gui" "go.wit.com/lib/gadgets" "go.wit.com/log" ) -func (rs *RepoStatus) makeBranchesBox() { - rs.gitBranchesGroup = rs.window.Box().NewGroup("branches") +func (rs *RepoStatus) makeBranchesBox(parent *gui.Node) { + rs.gitBranchesGroup = parent.NewGroup("branches") // `progname:"BRANCHES"` // can the toolkits use these for i18n support? newgrid := rs.gitBranchesGroup.NewGrid("gridnuts", 0, 0) - rs.lasttag = gadgets.NewOneLiner(newgrid, "last tag") + rs.lasttag = gadgets.NewOneLiner(newgrid, "last tag") // `progname:"LASTTAG"` newgrid.NextRow() - rs.masterBranchVersion = gadgets.NewOneLiner(newgrid, "master") + rs.masterBranchVersion = gadgets.NewOneLiner(newgrid, "master") // `progname:"MASTERBRANCH"` newgrid.NextRow() - rs.develBranchVersion = gadgets.NewOneLiner(newgrid, "devel") + rs.develBranchVersion = gadgets.NewOneLiner(newgrid, "devel") // `progname:"DEVELBRANCH"` newgrid.NextRow() - rs.userBranchVersion = gadgets.NewOneLiner(newgrid, "user") + rs.userBranchVersion = gadgets.NewOneLiner(newgrid, "user") // `progname:"USERBRANCH"` newgrid.NextRow() - rs.currentBranch = gadgets.NewOneLiner(newgrid, "current branch") + rs.currentBranch = gadgets.NewOneLiner(newgrid, "current branch") // `progname:"CURRENTBRANCH"` newgrid.NextRow() - rs.currentVersion = gadgets.NewOneLiner(newgrid, "current version") + rs.currentVersion = gadgets.NewOneLiner(newgrid, "current version") // `progname:"CURRENTVERSION"` newgrid.NextRow() - rs.switchBranchB = newgrid.NewButton("Switch Branch", func() { + rs.switchBranchB = newgrid.NewButton("Switch Branch", func() { // `progname:"SWITCH"` bname := rs.targetBranch.String() log.Info("Should switch to branch", bname, "here") @@ -38,12 +41,16 @@ func (rs *RepoStatus) makeBranchesBox() { rs.UpdateCurrent() }) - rs.targetBranch = newgrid.NewDropdown() + rs.targetBranch = newgrid.NewDropdown() // `progname:"TARGET"` // rs.targetBranch.AddText("master") newgrid.NextRow() rs.showBranchesButton = newgrid.NewButton("scan branches()", func() { - all := rs.getBranches() + err, out := rs.RunCmd([]string{"git", "branch", "--all"}) + if err != nil { + log.Log(WARN, "git branch failed", rs.String()) + } + all := strings.Split(out, "\n") for i, s := range all { log.Log(WARN, "found branch", i, s) rs.targetBranch.AddText(s) diff --git a/common.go b/common.go index bc518be..1b0f7a6 100644 --- a/common.go +++ b/common.go @@ -17,6 +17,30 @@ func (rs *RepoStatus) Changed() bool { return rs.changed } +// deprecate this. returns the gopath right now +func (rs *RepoStatus) String() string { + log.Warn("RepoStatus.String() is to be deprecated") + return rs.path.String() +} + +// returns the go path for the repo. "go.wit.com/apps/autotypist" +func (rs *RepoStatus) GoName() string { + return rs.goSrcPath.String() +} + +// returns the filesystem path to the repo +func (rs *RepoStatus) Path() string { + return rs.realPath.String() +} + +/* +func (rs *RepoStatus) GetPath() string { + return rs.path.String() +} +*/ + + +/* func (rs *RepoStatus) Draw() { if !rs.Ready() { return @@ -24,6 +48,7 @@ func (rs *RepoStatus) Draw() { log.Log(CHANGE, "Draw() window ready =", rs.ready) rs.window.TestDraw() } +*/ func (rs *RepoStatus) Show() { if !rs.Ready() { @@ -100,7 +125,8 @@ func (rs *RepoStatus) Build() bool { return false } log.Info("need to build here", rs.String()) - rs.RunCmd([]string{"go", "build", "-v", "-x"}) + // rs.RunCmd([]string{"go", "build", "-v", "-x"}) + rs.XtermBash([]string{"go", "build", "-v", "-x"}) if rs.Exists(name) { log.Warn("build worked", name) return true diff --git a/draw.go b/draw.go index 6c8b61a..4790230 100644 --- a/draw.go +++ b/draw.go @@ -4,30 +4,14 @@ import ( "strconv" "strings" + "go.wit.com/gui" "go.wit.com/lib/gadgets" "go.wit.com/log" "go.wit.com/widget" ) -// creates the actual widgets. -// it's assumed you are always passing in a box -func (rs *RepoStatus) draw() { - if !rs.Ready() { - return - } - - // display the status of the git repository - rs.drawGitStatus() - - // display the git branches and options - rs.makeBranchesBox() - - // show standard git commit and merge controls - rs.drawGitCommands() -} - -func (rs *RepoStatus) drawGitStatus() { - rs.gitStatusGroup = rs.window.Box().NewGroup("What GIT Knows It Has") +func (rs *RepoStatus) drawGitStatus(box *gui.Node) { + rs.gitStatusGroup = box.NewGroup("What GIT Knows It Has") newgrid := rs.gitStatusGroup.NewGrid("gridnuts", 2, 2) newgrid.Margin() newgrid.Pad() diff --git a/git.go b/git.go index 3c8efae..4875812 100644 --- a/git.go +++ b/git.go @@ -2,6 +2,7 @@ package repostatus import ( "strings" + "time" "unicode/utf8" "io/ioutil" @@ -9,16 +10,6 @@ import ( "go.wit.com/log" ) -func (rs *RepoStatus) String() string { - return rs.path.String() -} - -/* -func (rs *RepoStatus) GetPath() string { - return rs.path.String() -} -*/ - func (rs *RepoStatus) GetCurrentBranchName() string { return rs.currentBranch.String() } @@ -27,6 +18,10 @@ func (rs *RepoStatus) GetCurrentBranchVersion() string { return rs.currentVersion.String() } +func (rs *RepoStatus) LastTagAge() (time.Time, string) { + return time.Now(), rs.lasttag.String() +} + func (rs *RepoStatus) GetLastTagVersion() string { return rs.lasttag.String() } diff --git a/modifyBox.go b/modifyBox.go index 14b5926..2a294b0 100644 --- a/modifyBox.go +++ b/modifyBox.go @@ -1,12 +1,13 @@ package repostatus import ( + "go.wit.com/gui" "go.wit.com/lib/gadgets" "go.wit.com/log" ) -func (rs *RepoStatus) drawGitCommands() { - rs.gitCommandsGroup = rs.window.Box().NewGroup("modify") +func (rs *RepoStatus) drawGitCommands(box *gui.Node) { + rs.gitCommandsGroup = box.NewGroup("modify") newgrid := rs.gitCommandsGroup.NewGrid("gridnuts", 0, 0) newgrid.NewButton("update", func() { @@ -25,19 +26,6 @@ func (rs *RepoStatus) drawGitCommands() { } }) - newgrid.NewButton("git tags window", func() { - if rs.TagsW == nil { - log.Warn("error: found rs.TagsW == nil") - rs.TagsW = rs.TagWindow() - return - } - if rs.TagsW.Hidden() { - rs.TagsW.Show() - } else { - rs.TagsW.Show() - } - }) - newgrid.NewButton("show .git/config", func() { if rs.gitConfig == nil { log.Log(WARN, "Nonexistant or damaged .git/config", rs.String()) diff --git a/new.go b/new.go index f7f4b86..8d11c8d 100644 --- a/new.go +++ b/new.go @@ -11,6 +11,10 @@ import ( var windowMap map[string]*RepoStatus +func init() { + windowMap = make(map[string]*RepoStatus) +} + func ListAll() { for path, rs := range windowMap { log.Warn(rs.GetMasterVersion(), path) @@ -35,16 +39,27 @@ func NewRepoStatusWindow(path string) *RepoStatus { return windowMap[path] } + var realpath string + homeDir, err := os.UserHomeDir() if err != nil { log.Log(WARN, "Error getting home directory:", err) return nil } - goSrcDir := filepath.Join(homeDir, "go/src") - realpath := filepath.Join(goSrcDir, path) - filename := filepath.Join(goSrcDir, path, ".git/config") + // allow arbitrary paths, otherwise, assume the repo is in ~/go/src + if strings.HasPrefix(path, "/") { + realpath = path + } else if strings.HasPrefix(path, "~") { + // TODO: example this to homedir + tmp := strings.TrimPrefix(path, "~") + realpath = filepath.Join(homeDir, tmp) + } else { + realpath = filepath.Join(goSrcDir, path) + } + + filename := filepath.Join(realpath, ".git/config") _, err = os.Open(filename) if err != nil { @@ -60,18 +75,34 @@ func NewRepoStatusWindow(path string) *RepoStatus { rs.window = gadgets.RawBasicWindow("GO Repo Details " + path) rs.window.Horizontal() rs.window.Make() + basebox := rs.window.Box() + group := basebox.NewGroup("stuff") + primarybox := group.Box() + primarybox.Horizontal() + box2 := group.Box() rs.ready = true rs.window.Custom = func() { rs.Hide() log.Warn("repostatus user closed the window()") } - rs.draw() + + // display the status of the git repository + rs.drawGitStatus(primarybox) + + // display the git branches and options + rs.makeBranchesBox(primarybox) + + // show standard git commit and merge controls + rs.drawGitCommands(primarybox) // save ~/go/src & the whole path strings rs.path.SetValue(path) rs.goSrcPath.SetValue(goSrcDir) rs.realPath.SetValue(realpath) + // add all the tags + rs.makeTagBox(box2) + rs.readGitConfig() rs.readOnly.SetValue("true") @@ -86,7 +117,3 @@ func NewRepoStatusWindow(path string) *RepoStatus { windowMap[path] = rs return rs } - -func init() { - windowMap = make(map[string]*RepoStatus) -} diff --git a/structs.go b/structs.go index b0453b5..a8f4698 100644 --- a/structs.go +++ b/structs.go @@ -13,8 +13,8 @@ type RepoStatus struct { window *gadgets.BasicWindow - // a window to manage your .git tags - TagsW *repoTags + // a box of all the git tags + Tags *gitTagBox dirtyLabel *gadgets.OneLiner readOnly *gadgets.OneLiner diff --git a/tagWindow.go b/tagWindow.go index c92e961..c476f8d 100644 --- a/tagWindow.go +++ b/tagWindow.go @@ -6,7 +6,6 @@ import ( "strings" "go.wit.com/gui" - "go.wit.com/lib/gadgets" "go.wit.com/log" ) @@ -30,13 +29,8 @@ type repoTag struct { deleteB *gui.Node } -type repoTags struct { - // the originating repository - rs *RepoStatus - - // the window for the tags - window *gadgets.BasicWindow - +// a GUI box of all the tags in a repo +type gitTagBox struct { // the box to list all the tags in box *gui.Node group *gui.Node @@ -46,64 +40,43 @@ type repoTags struct { tags []*repoTag } -func (tw *repoTags) Hidden() bool { - return tw.window.Hidden() -} +func (rs *RepoStatus) makeTagBox(box *gui.Node) { + if rs.Tags != nil { + log.Log(WARN, "already scanned tags") + return + } + tagB := new(gitTagBox) + rs.Tags = tagB + tagB.group = box.NewGroup(".git tags for " + rs.String()) -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() + // tagB.group.NewButton("prune tags", func() { + // tagB.Prune() // }) var dups *gui.Node - dups = tagW.group.NewCheckbox("Show duplicate tags").SetChecked(false) + dups = tagB.group.NewCheckbox("Show duplicate tags").SetChecked(false) dups.Custom = func() { if dups.Checked() { - tagW.Prune() + tagB.Prune() } else { - for _, t := range tagW.tags { + for _, t := range tagB.tags { t.Show() } } } - tagW.group.NewButton("delete all", func() { - for i, t := range tagW.tags { + tagB.group.NewButton("delete all", func() { + for i, t := range tagB.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) + rs.DeleteTag(t) } }) - grid := tagW.group.NewGrid("tags", 0, 0) - tagW.grid = grid + grid := tagB.group.NewGrid("tags", 0, 0) + tagB.grid = grid grid.NewLabel("version") grid.NewLabel("ref") @@ -117,11 +90,11 @@ func (tagW *repoTags) newTagBox(box *gui.Node) { // git rev-parse HEAD // if last tag == HEAD, then remove it - tags := []string{"%(tag)", "%(*objectname)", "%(taggerdate:raw)", "%(subject)"} + tags := []string{"%(tag)", "%(*objectname)", "%(taggerdate:raw)", "%(subject)", "%(*authorname)", "%(*authoremail)"} 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) + err, output := rs.RunCmd(cmd) if err != nil { output = "git error_,,,_a_,,,_b_,,,c" } @@ -129,7 +102,7 @@ func (tagW *repoTags) newTagBox(box *gui.Node) { lines := strings.Split(output, "\n") // reverse the git order slices.Reverse(lines) - tagW.tags = make([]*repoTag, 0) + tagB.tags = make([]*repoTag, 0) for i, line := range lines { var parts []string @@ -143,7 +116,7 @@ func (tagW *repoTags) newTagBox(box *gui.Node) { rTag.tag = grid.NewLabel(parts[0]) rTag.ref = grid.NewEntrybox(parts[1]) - stamp, dur := getDateStamp(parts[2]) // + _, stamp, dur := getDateStamp(parts[2]) // rTag.date = grid.NewLabel(stamp) grid.NewLabel(dur) @@ -155,14 +128,14 @@ func (tagW *repoTags) newTagBox(box *gui.Node) { 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) + if rs.DoAll(all) { + log.Info("TAG DELETED", rs.String(), tagversion) } else { - log.Info("TAG DELETE FAILED", tagW.rs.String(), tagversion) + log.Info("TAG DELETE FAILED", rs.String(), tagversion) } }) - tagW.tags = append(tagW.tags, rTag) + tagB.tags = append(tagB.tags, rTag) // works like a typerwriter grid.NextRow() } @@ -170,7 +143,7 @@ func (tagW *repoTags) newTagBox(box *gui.Node) { // slices.Reverse(rtags.tags) } -func (rtags *repoTags) ListAll() []*repoTag { +func (rtags *gitTagBox) ListAll() []*repoTag { var tags []*repoTag for _, t := range rtags.tags { tags = append(tags, t) @@ -178,7 +151,7 @@ func (rtags *repoTags) ListAll() []*repoTag { return tags } -func (rtags *repoTags) List() []*repoTag { +func (rtags *gitTagBox) List() []*repoTag { var tags []*repoTag for _, t := range rtags.tags { if t.hidden { @@ -191,7 +164,7 @@ func (rtags *repoTags) List() []*repoTag { return tags } -func (rtags *repoTags) Prune() { +func (rtags *gitTagBox) Prune() { dups := make(map[string]*repoTag) for i, t := range rtags.tags { if t == nil { @@ -212,7 +185,7 @@ func (rtags *repoTags) Prune() { } // hide tags worth keeping -func (rtags *repoTags) PruneSmart() { +func (rtags *gitTagBox) PruneSmart() { // always keep the first tag var first bool = true @@ -265,9 +238,7 @@ func (rtags *repoTags) PruneSmart() { // 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 - +func (rs *RepoStatus) DeleteTag(rt *repoTag) { cmd := []string{"git", "push", "--delete", "origin", rt.tag.String()} log.Info("RUN:", cmd) err, output := rs.RunCmd(cmd) diff --git a/unix.go b/unix.go index 903adba..7e295e8 100644 --- a/unix.go +++ b/unix.go @@ -119,6 +119,11 @@ func splitVersion(version string) (a, b, c string) { } } +func (rs *RepoStatus) RunCmdEcho(parts []string) (error, string) { + log.Info("RunCmdEcho()", parts) + return rs.RunCmd(parts) +} + func (rs *RepoStatus) RunCmd(parts []string) (error, string) { path := rs.realPath.String() err, _, output := shell.RunCmd(path, parts) @@ -269,22 +274,23 @@ func readFileToString(filename string) (string, error) { return strings.TrimSpace(string(data)), nil } -func getDateStamp(raw string) (string, string) { +func getDateStamp(raw string) (time.Time, string, string) { parts := strings.Split(raw, " ") if len(parts) == 0 { // raw was blank here - return "Jan 4 1977", "40y" // eh, why not. it'll be easy to grep for this + // return "Jan 4 1977", "40y" // eh, why not. it'll be easy to grep for this + return time.Now(), "Jan 4 1977", "40y" // eh, why not. it'll be easy to grep for this } i, err := strconv.ParseInt(parts[0], 10, 64) // base 10 string, return int64 if err != nil { log.Warn("Error converting timestamp:", raw) log.Warn("Error converting timestamp err =", err) - return raw, "" + return time.Now(), "", "" } // Parse the Unix timestamp into a time.Time object gitTagDate := time.Unix(i, 0) - return gitTagDate.UTC().Format("2006/01/02 15:04:05 UTC"), getDurationStamp(gitTagDate) + return gitTagDate, gitTagDate.UTC().Format("2006/01/02 15:04:05 UTC"), getDurationStamp(gitTagDate) } func getDurationStamp(t time.Time) string { @@ -323,16 +329,18 @@ func formatDuration(d time.Duration) string { return result } +func (rs *RepoStatus) XtermNohup(cmdline string) { + shell.XtermCmd(rs.Path(), []string{cmdline}) +} +func (rs *RepoStatus) Xterm(cmdline string) { + shell.XtermCmd(rs.Path(), []string{cmdline}) +} +func (rs *RepoStatus) XtermWait(cmdline string) { + shell.XtermCmdWait(rs.Path(), []string{cmdline}) +} +/* func (rs *RepoStatus) XtermNohup(args []string) { var argsX = []string{"xterm", "-geometry", "120x40"} - /* - if xtermHold.Checked() { - log.Println("hold = true") - argsXterm = append(argsXterm, "-hold") - } else { - log.Println("hold = false") - } - */ argsX = append(argsX, "-e", "bash", "-c") argsX = append(argsX, args...) log.Info("xterm cmd=", argsX) @@ -353,17 +361,11 @@ func (rs *RepoStatus) XtermNohup(args []string) { log.Info("cmd =", argsX) } } +*/ +/* func (rs *RepoStatus) Xterm(args []string) { var argsX = []string{"-geometry", "120x40"} - /* - if xtermHold.Checked() { - log.Println("hold = true") - argsXterm = append(argsXterm, "-hold") - } else { - log.Println("hold = false") - } - */ argsX = append(argsX, "-e", "bash", "-c") argsX = append(argsX, args...) log.Info("xterm cmd=", argsX) @@ -382,18 +384,36 @@ func (rs *RepoStatus) Xterm(args []string) { log.Info("cmd = xterm", argsX) } } +*/ +/* func (rs *RepoStatus) XtermHold(args []string) { var argsX = []string{"-hold", "-geometry", "120x40"} - /* - if xtermHold.Checked() { - log.Println("hold = true") - argsXterm = append(argsXterm, "-hold") - } else { - log.Println("hold = false") - } - */ - argsX = append(argsX, "-e", "bash", "-c") + tmp := strings.Join(args, " ") + ";bash" + argsX = append(argsX, "-e", "bash", "-c", tmp) + argsX = append(argsX, args...) + log.Info("xterm cmd=", argsX) + // set less to not exit on small diff's + os.Setenv("LESS", "-+F -+X -R") + cmd := exec.Command("xterm", argsX...) + path := rs.realPath.String() + cmd.Dir = path + if err := cmd.Run(); err != nil { + log.Info("xterm.Run() failed") + log.Info("path =", path) + log.Info("cmd = xterm", argsX) + } else { + log.Info("xterm.Run() worked") + log.Info("path =", path) + log.Info("cmd = xterm", argsX) + } +} +*/ + +func (rs *RepoStatus) XtermBash(args []string) { + var argsX = []string{"-geometry", "120x40"} + tmp := strings.Join(args, " ") + ";bash" + argsX = append(argsX, "-e", "bash", "-c", tmp) argsX = append(argsX, args...) log.Info("xterm cmd=", argsX) // set less to not exit on small diff's