From 87346d9452b38db517e76e070f11928060bc2b99 Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Tue, 9 Jan 2024 15:34:53 -0600 Subject: initial commit --- args.go | 32 +++++++++++++++++++++++ common.go | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ draw.go | 48 +++++++++++++++++++++++++++++++++++ git.go | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ new.go | 35 ++++++++++++++++++++++++++ structs.go | 38 ++++++++++++++++++++++++++++ timer.go | 17 +++++++++++++ unix.go | 54 +++++++++++++++++++++++++++++++++++++++ update.go | 57 +++++++++++++++++++++++++++++++++++++++++ 9 files changed, 447 insertions(+) create mode 100644 args.go create mode 100644 common.go create mode 100644 draw.go create mode 100644 git.go create mode 100644 new.go create mode 100644 structs.go create mode 100644 timer.go create mode 100644 unix.go create mode 100644 update.go diff --git a/args.go b/args.go new file mode 100644 index 0000000..d342ac8 --- /dev/null +++ b/args.go @@ -0,0 +1,32 @@ +package repostatus + +/* + this enables command line options from other packages like 'gui' and 'log' +*/ + +import ( + "go.wit.com/log" +) + +var NOW *log.LogFlag +var INFO *log.LogFlag + +var SPEW *log.LogFlag +var WARN *log.LogFlag + +var CHANGE *log.LogFlag +var STATUS *log.LogFlag + +func init() { + full := "go.wit.com/gui/gadgets/repostatus" + short := "repostatus" + + NOW = log.NewFlag( "NOW", true, full, short, "temp debugging stuff") + INFO = log.NewFlag("INFO", false, full, short, "normal debugging stuff") + + WARN = log.NewFlag("WARN", true, full, short, "bad things") + SPEW = log.NewFlag("SPEW", false, full, short, "spew stuff") + + CHANGE = log.NewFlag("CHANGE", true, full, short, "when repo changes") + STATUS = log.NewFlag("STATUS", false, full, short, "current status") +} diff --git a/common.go b/common.go new file mode 100644 index 0000000..c70356e --- /dev/null +++ b/common.go @@ -0,0 +1,85 @@ +package repostatus + +import ( + "go.wit.com/log" + "go.wit.com/gui/gui" +) + +// reports externally if something has changed +// since the last time it was asked about it +func (ls *RepoStatus) Changed() bool { + if ! ls.Ready() {return false} + if ls.changed { + ls.changed = false + return true + } + return false +} + +func (ls *RepoStatus) Make() { + if ! ls.Ready() {return} + log.Log(CHANGE, "Make() window ready =", ls.ready) + ls.window.Make() + ls.ready = true +} +func (ls *RepoStatus) Draw() { + if ! ls.Ready() {return} + log.Log(CHANGE, "Draw() window ready =", ls.ready) + ls.window.Draw() + ls.ready = true +} +func (ls *RepoStatus) Draw2() { + if ! ls.Ready() {return} + log.Log(CHANGE, "draw(ls) ready =", ls.ready) + draw(ls) +} + +func (ls *RepoStatus) Show() { + if ! ls.Ready() {return} + log.Log(CHANGE, "Show() window ready =", ls.ready) + ls.window.Show() + ls.hidden = false +} + +func (ls *RepoStatus) Hide() { + if ! ls.Ready() {return} + log.Log(CHANGE, "Hide() window ready =", ls.ready) + ls.window.Hide() + ls.hidden = true +} + +func (ls *RepoStatus) Toggle() { + if ! ls.Ready() {return} + log.Log(CHANGE, "Toggle() window ready =", ls.ready) + if ls.hidden { + ls.Show() + } else { + ls.Hide() + } +} + +func (ls *RepoStatus) Ready() bool { + log.Log(SPEW, "Ready() maybe not ready? ls =", ls) + if ls == nil {return false} + if ls.window == nil {return false} + return ls.ready +} + +func (ls *RepoStatus) Initialized() bool { + log.Log(CHANGE, "checking Initialized()") + if ls == nil {return false} + if ls.parent == nil {return false} + return true +} + +func (ls *RepoStatus) SetParent(p *gui.Node) { + log.Log(CHANGE, "Attempting SetParent") + if ls == nil {return} + if ls.parent == nil { + log.Log(CHANGE, "SetParent =", p) + ls.parent = p + return + } else { + log.Log(CHANGE, "SetParent was already set to =", ls.parent) + } +} diff --git a/draw.go b/draw.go new file mode 100644 index 0000000..33d655f --- /dev/null +++ b/draw.go @@ -0,0 +1,48 @@ +package repostatus + +import ( + "go.wit.com/log" + "go.wit.com/gui/gadgets" +) + +// creates the actual widgets. +// it's assumed you are always passing in a box +func draw(rs *RepoStatus) { + if ! rs.Ready() {return} + rs.group = rs.window.Box().NewGroup("What GO Knows It Has") + + rs.grid = rs.group.NewGrid("gridnuts", 2, 2) + + rs.grid.SetNext(1,1) + + rs.path = gadgets.NewOneLiner(rs.grid, "path") + rs.currentBranch = gadgets.NewOneLiner(rs.grid, "branch") + rs.lasttag = gadgets.NewOneLiner(rs.grid, "last tag") + rs.currentVersion = gadgets.NewOneLiner(rs.grid, "Version") + + rs.grid.NewLabel("tags") + rs.tagsDrop = rs.grid.NewDropdown("tags") + rs.masterBranch = gadgets.NewOneLiner(rs.grid, "master") + rs.develBranch = gadgets.NewOneLiner(rs.grid, "devel") + rs.jcarrBranch = gadgets.NewOneLiner(rs.grid, "jcarr") + + rs.dirtyLabel = gadgets.NewOneLiner(rs.grid, "dirty") + + rs.speed = gadgets.NewOneLiner(rs.grid, "refresh speed =") + rs.speedActual = gadgets.NewOneLiner(rs.grid, "speed actual =") + + rs.grid.NewButton("update", func() { + rs.Update() + }) + rs.grid.NewButton("recommend", func() { + log.Warn("Is repo dirty?", rs.dirtyLabel.Get()) + log.Warn("list the known tags") + rs.populateTags() + log.Warn("Does master == devel? ") + log.Warn("Does devel == jcarr?") + log.Warn("Is repo pushed upstream? git.wit.org or github?") + }) + + rs.grid.Margin() + rs.grid.Pad() +} diff --git a/git.go b/git.go new file mode 100644 index 0000000..477e956 --- /dev/null +++ b/git.go @@ -0,0 +1,81 @@ +package repostatus + +import ( + "go.wit.com/log" +) + +func (rs *RepoStatus) getCurrentBranchName() string { + out := run(rs.repopath, "git", "branch --show-current") + log.Warn("getCurrentBranchName() =", out) + rs.currentBranch.Set(out) + return out +} + +func (rs *RepoStatus) getCurrentBranchVersion() string { + out := run(rs.repopath, "git", "describe --tags") + log.Warn("getCurrentBranchVersion()", out) + rs.currentVersion.Set(out) + return out +} + +func (rs *RepoStatus) getLastTagVersion() string { + out := run(rs.repopath, "git", "rev-list --tags --max-count=1") + log.Warn("getLastTagVersion()", out) + rs.lasttagrev = out + + lastreal := "describe --tags " + out + // out = run(r.path, "git", "describe --tags c871d5ecf051a7dc4e3a77157cdbc0a457eb9ae1") + out = run(rs.repopath, "git", lastreal) + rs.lasttag.Set(out) + // rs.lastLabel.Set(out) + return out +} + +func (rs *RepoStatus) populateTags() { + tmp := fullpath(rs.repopath + "/.git/refs/tags") + log.Warn("populateTags() path =", tmp) + for _, tag := range listFiles(tmp) { + if rs.tags[tag] == "" { + log.Warn("populateTags() Adding new tag", tag) + rs.tagsDrop.AddText(tag) + rs.tags[tag] = "origin" + } + } + rs.tagsDrop.SetText(rs.lasttagrev) +} + +func (rs *RepoStatus) checkDirty() bool { + out := run(rs.repopath, "git", "diff-index HEAD") + if out == "" { + log.Warn("checkDirty() no", rs.repopath) + rs.dirtyLabel.Set("no") + return false + } else { + log.Warn("checkDirty() true", rs.repopath) + rs.dirtyLabel.Set("dirty") + return true + } + +} + +func (rs *RepoStatus) checkoutBranch(branch string) { + if rs.checkDirty() { + log.Warn("checkoutBranch() checkDirty() == true for repo", rs.repopath, "looking for branch:", branch) + return + } + out := run(rs.repopath, "git", "checkout " + branch) + log.Warn(rs.repopath, "git checkout " + branch, "returned", out) + + realname := rs.getCurrentBranchName() + realversion := rs.getCurrentBranchVersion() + log.Warn(rs.repopath, "realname =", realname, "realversion =", realversion) + if realname == "jcarr" { + rs.jcarrBranch.Set(realversion) + } + if realname == "devel" { + rs.develBranch.Set(realversion) + } + if realname == "master" { + rs.masterBranch.Set(realversion) + } +} diff --git a/new.go b/new.go new file mode 100644 index 0000000..c18480e --- /dev/null +++ b/new.go @@ -0,0 +1,35 @@ +package repostatus + +import ( + "go.wit.com/log" + + "go.wit.com/gui/gui" + "go.wit.com/gui/gadgets" +) + +func New(p *gui.Node, path string) *RepoStatus { + rs := &RepoStatus { + hidden: true, + ready: false, + parent: p, + repopath: path, + } + rs.tags = make(map[string]string) + return rs +} + +func (rs *RepoStatus) InitWindow() { + if ! rs.Initialized() { + log.Log(WARN, "not initalized yet (no parent for the window?)") + return + } + if rs.window != nil { + log.Log(WARN, "You already have a window") + rs.ready = true + return + } + + log.Log(WARN, "Creating the Window") + rs.window = gadgets.NewBasicWindow(rs.parent, "GO Repo Details") + rs.ready = true +} diff --git a/structs.go b/structs.go new file mode 100644 index 0000000..b2b8b94 --- /dev/null +++ b/structs.go @@ -0,0 +1,38 @@ +package repostatus + +import ( + "go.wit.com/gui/gui" + "go.wit.com/gui/gadgets" +) + +type RepoStatus struct { + ready bool + hidden bool + changed bool + + repopath string + lasttagrev string + tags map[string]string + + parent *gui.Node + + window *gadgets.BasicWindow + group *gui.Node + grid *gui.Node + +// status *gadgets.OneLiner + dirtyLabel *gadgets.OneLiner + path *gadgets.OneLiner + + currentBranch *gadgets.OneLiner + currentVersion *gadgets.OneLiner + tagsDrop *gui.Node + + lasttag *gadgets.OneLiner + masterBranch *gadgets.OneLiner + develBranch *gadgets.OneLiner + jcarrBranch *gadgets.OneLiner + + speed *gadgets.OneLiner + speedActual *gadgets.OneLiner +} diff --git a/timer.go b/timer.go new file mode 100644 index 0000000..9e9e589 --- /dev/null +++ b/timer.go @@ -0,0 +1,17 @@ +package repostatus + +import ( + "time" +) + +// timeFunction takes a function as an argument and returns the execution time. +func timeFunction(f func()) time.Duration { + startTime := time.Now() // Record the start time + f() // Execute the function + return time.Since(startTime) // Calculate the elapsed time +} + +func (ls *RepoStatus) SetSpeedActual(s string) { + if ! ls.Ready() {return} + ls.speedActual.Set(s) +} diff --git a/unix.go b/unix.go new file mode 100644 index 0000000..1f31700 --- /dev/null +++ b/unix.go @@ -0,0 +1,54 @@ +// This is a simple example +package repostatus + +import ( + "os" + "os/exec" + "strings" + + "go.wit.com/log" +) + +func fullpath(repo string) string { + return "/home/jcarr/go/src/" + repo +} + +func run(path string, thing string, cmdline string) string { + parts := strings.Split(cmdline, " ") + // Create the command + cmd := exec.Command(thing, parts...) + + // Set the working directory + cmd.Dir = fullpath(path) + + // Execute the command + output, err := cmd.CombinedOutput() + if err != nil { + log.Error(err, "cmd error'd out", parts) + return "" + } + + tmp := string(output) + tmp = strings.TrimSpace(tmp) + + // Print the output + log.Log(WARN, "run()", path, thing, cmdline, "=", tmp) + return tmp +} + +func listFiles(directory string) []string { + var files []string + fileInfo, err := os.ReadDir(directory) + if err != nil { + log.Error(err) + return nil + } + + for _, file := range fileInfo { + if !file.IsDir() { + files = append(files, file.Name()) + } + } + + return files +} diff --git a/update.go b/update.go new file mode 100644 index 0000000..e7544d6 --- /dev/null +++ b/update.go @@ -0,0 +1,57 @@ +package repostatus + +import ( + "fmt" + "time" + "errors" + + "go.wit.com/log" +) + +func (rs *RepoStatus) Update() { + if ! rs.Ready() { + log.Log(WARN, "can't update yet. ready is false") + log.Error(errors.New("Update() is not ready yet")) + return + } + log.Log(WARN, "Update() START") + duration := timeFunction(func () { + rs.path.Set(rs.repopath) + rs.getCurrentBranchName() + rs.window.Title(rs.repopath + " GO repo Details") + rs.getCurrentBranchVersion() + + rs.getLastTagVersion() + rs.populateTags() + + // rs.checkDirty() this runs + log.Log(WARN, "") + log.Log(WARN, "checkoutBranch master") + rs.checkoutBranch("master") + log.Log(WARN, "") + log.Log(WARN, "checkoutBranch devel") + rs.checkoutBranch("devel") + log.Log(WARN, "") + log.Log(WARN, "checkoutBranch jcarr") + rs.checkoutBranch("jcarr") + }) + rs.setSpeed(duration) + log.Log(WARN, "Update() END") +} + +func (rs *RepoStatus) setSpeed(duration time.Duration) { + s := fmt.Sprint(duration) + if rs.speedActual == nil { + log.Log(WARN, "can't actually warn") + return + } + rs.speedActual.Set(s) + + if (duration > 500 * time.Millisecond ) { + rs.speed.Set("SLOW") + } else if (duration > 100 * time.Millisecond ) { + rs.speed.Set("OK") + } else { + rs.speed.Set("FAST") + } +} -- cgit v1.2.3