summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--stat.makeRemoteRefs.go144
-rw-r--r--stat.proto19
-rw-r--r--stat.updateRefs.go66
-rw-r--r--tableStats.go16
4 files changed, 230 insertions, 15 deletions
diff --git a/stat.makeRemoteRefs.go b/stat.makeRemoteRefs.go
new file mode 100644
index 0000000..e47938a
--- /dev/null
+++ b/stat.makeRemoteRefs.go
@@ -0,0 +1,144 @@
+package gitpb
+
+import (
+ "errors"
+ "fmt"
+ "path/filepath"
+ "slices"
+ "strings"
+
+ "go.wit.com/lib/config"
+ "go.wit.com/lib/env"
+ "go.wit.com/log"
+)
+
+// returns err if anything changes or anything is wrong (todo: should these be different?)
+func (r *Repo) LoadRemoteRefs(remoteName string) (*Stats, error) {
+ fullname := filepath.Join(r.FullPath, ".git", remoteName+".refs.pb")
+ stats := NewStats()
+ stats.Filename = fullname
+ err := config.ForceCreatePB(stats)
+ return stats, err
+}
+
+// cmd := []string{"git", "show-ref"} // must use 'master' as queried from the git server
+// cmd := []string{"git", "log", "-n", "100", makeFmts(), "origin/HEAD"} // HEAD is _NOT_ always set
+// cmd := []string{"git", "show-ref"} // must use 'master' as queried from the git server
+// cmd := []string{"git", "log", "-n", "100", makeFmts(), "origin/HEAD"} // HEAD is _NOT_ always set
+
+// returns err if anything changes or anything is wrong (todo: should these be different?)
+func (r *Repo) MakeRemoteRefs(remoteName string) (*Stats, error) {
+ stats, err := r.LoadRemoteRefs(remoteName)
+ if err != nil {
+ return stats, err
+ }
+ if stats.Len() != 0 {
+ return stats, errors.New("refs file was already created")
+ }
+ cmd := []string{"git", "ls-remote", remoteName} // must use 'master' as queried from the git server // GO has 250k remote refs
+ if env.True("stats") {
+ log.Info("STATS VERBOSE Run:", cmd)
+ }
+ cmdout := r.Run(cmd)
+ if len(cmdout.Stdout) == 0 {
+ return stats, errors.New("got nothing from git ls-remote")
+ }
+ var counter int
+ for _, line := range cmdout.Stdout {
+ line = strings.TrimSpace(line)
+ parts := strings.Fields(line)
+ if len(parts) != 2 {
+ log.Printf("Repo: %s\n", r.FullPath)
+ log.Printf("CMD: %v\n", cmd)
+ log.Printf("LINE:%s\n", line)
+ return stats, errors.New(line)
+ }
+ if env.True("stats") {
+ log.Printf("LINE:%v %d %s\n", parts, counter, r.FullPath)
+ }
+ counter += 1
+ newstat := new(Stat)
+ newstat.Hash = parts[0]
+ stats.Append(newstat)
+ }
+ if counter > 0 {
+ stats.SaveByHash()
+ }
+ return stats, nil
+}
+
+func (x *Stats) SaveByHash() error {
+ newx := NewStats()
+
+ all := x.SortByHash()
+ for all.Scan() {
+ r := all.Next()
+ newx.Clone(r)
+ }
+
+ newx.Filename = x.Filename
+ err := newx.Save()
+
+ return err
+}
+
+// returns err if anything changes or anything is wrong (todo: should these be different?)
+func (r *Repo) UpdateRemoteRefs(remoteName string) error {
+ stats, err := r.LoadRemoteRefs(remoteName)
+ if err != nil {
+ return err
+ }
+ if stats.Len() == 0 {
+ return errors.New("need to make file instead")
+ }
+ cmd := []string{"git", "ls-remote", remoteName} // must use 'master' as queried from the git server // GO has 250k remote refs
+ if env.True("stats") {
+ log.Info("STATS VERBOSE Run:", cmd)
+ }
+ cmdout := r.Run(cmd)
+ if len(cmdout.Stdout) == 0 {
+ return errors.New("got nothing back")
+ }
+ var ticker int
+ var counter int
+ var allnew []*Stat
+ for _, line := range cmdout.Stdout {
+ line = strings.TrimSpace(line)
+ parts := strings.Fields(line)
+ if len(parts) != 2 {
+ log.Printf("Repo: %s\n", r.FullPath)
+ log.Printf("CMD: %v\n", cmd)
+ log.Printf("LINE:%s\n", line)
+ return errors.New(line)
+ }
+ if env.True("stats") {
+ log.Printf("LINE:%v %d %s\n", parts, ticker, r.FullPath)
+ }
+ // refpath := filepath.Join("refs/remote", remoteName)
+ // if strings.HasPrefix(parts[1], refpath) {
+ // this ref is not from the remote
+ // continue
+ // }
+ counter += 1
+ newstat := new(Stat)
+ newstat.Hash = parts[0]
+ n, found := slices.BinarySearchFunc(stats.Stats, newstat, func(a, b *Stat) int {
+ return strings.Compare(a.Hash, b.Hash)
+ })
+ _ = n
+
+ if found {
+ // log.Info("found", n)
+ continue
+ }
+ ticker += 1
+ log.Info("not found", newstat)
+ allnew = append(allnew, newstat)
+ }
+ if ticker > 0 {
+ stats.Stats = append(stats.Stats, allnew...)
+ stats.SaveByHash()
+ return errors.New(fmt.Sprintf("len(%d), ticker(%d) counter(%d) refs changed", stats.Len(), ticker, counter))
+ }
+ return nil
+}
diff --git a/stat.proto b/stat.proto
index dbf9e46..39a0e28 100644
--- a/stat.proto
+++ b/stat.proto
@@ -6,25 +6,30 @@ package gitpb;
import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp
-message Stat {
+message GitRef {
enum RefType {
UNKNOWN = 0;
LOCAL = 1;
REMOTE = 2;
TAG = 3;
}
+
+ string name = 1; //
+ string remote = 2; // blank unless REMOTE
+ RefType type = 3; // is set by git as the master branch
+ string subject = 4; // git tag subject
+}
+message Stat {
string patchId = 1; // `autogenpb:unique` `autogenpb:sort`
string hash = 2; // `autogenpb:unique` `autogenpb:sort`
google.protobuf.Timestamp ctime = 3; // `autogenpb:unique` `autogenpb:sort`
- string name = 4; //
- string remote = 5; // blank unless REMOTE
- RefType type = 6; // is set by git as the master branch
- string subject = 7; // git tag subject
+ repeated GitRef refs = 4; //
}
-// .git/ stats
+
+// normally stored as .git/*.pb cache files
message Stats { // `autogenpb:marshal` `autogenpb:gui` `autogenpb:http`
string uuid = 1; // `autogenpb:uuid:ba236558-f8a1-4c47-a14a-8856a24d3f72`
- string version = 2; // `autogenpb:version:v0.0.1`
+ string version = 2; // `autogenpb:version:v0.0.2`
repeated Stat stats = 3;
string filename = 4; // `autogenpb:save` -- this enables autogenerated pb.Load() and pb.Save()
string head = 5; // the current origin hash
diff --git a/stat.updateRefs.go b/stat.updateRefs.go
new file mode 100644
index 0000000..1405303
--- /dev/null
+++ b/stat.updateRefs.go
@@ -0,0 +1,66 @@
+package gitpb
+
+import (
+ "errors"
+ "fmt"
+ "path/filepath"
+ "strings"
+
+ "go.wit.com/lib/config"
+ "go.wit.com/lib/env"
+ "go.wit.com/log"
+)
+
+// returns err if anything changes or anything is wrong (todo: should these be different?)
+func (r *Repo) LoadRefs() (*Stats, error) {
+ fullname := filepath.Join(r.FullPath, ".git", "refs.pb")
+ stats := NewStats()
+ stats.Filename = fullname
+ err := config.ForceCreatePB(stats)
+ return stats, err
+}
+
+// cmd := []string{"git", "log", "-n", "100", makeFmts(), "origin/HEAD"} // HEAD is _NOT_ always set
+// cmd := []string{"git", "log", "-n", "100", makeFmts(), "origin/HEAD"} // HEAD is _NOT_ always set
+
+// parses "git show-ref" into a protobuf
+// returns err if anything changes or anything is wrong (todo: should these be different?)
+// todo: purge old ones
+func (r *Repo) UpdateRefs(stats *Stats) error {
+ cmd := []string{"git", "show-ref"} // must use 'master' as queried from the git server
+ if env.True("stats") {
+ log.Info("STATS VERBOSE Run:", cmd)
+ }
+ cmdout := r.Run(cmd)
+ if len(cmdout.Stdout) == 0 {
+ return errors.New("got nothing back")
+ }
+ var counter int // any new refs?
+ for _, line := range cmdout.Stdout {
+ line = strings.TrimSpace(line)
+ parts := strings.Fields(line)
+ if len(parts) != 2 {
+ log.Printf("Repo: %s\n", r.FullPath)
+ log.Printf("CMD: %v\n", cmd)
+ log.Printf("LINE:%s\n", line)
+ return errors.New(line)
+ }
+ if env.True("stats") {
+ log.Printf("LINE:%v %d %s\n", parts, counter, r.FullPath)
+ }
+ newstat := new(Stat)
+ newstat.Hash = parts[0]
+ // newstat.Name = parts[1]
+
+ teststat := stats.FindByHash(newstat.Hash)
+ if teststat == nil {
+ counter += 1
+ stats.Append(newstat)
+ }
+ }
+ if counter > 0 {
+ stats.SaveByHash()
+ return errors.New(fmt.Sprintf("len(%d) refs changed: (%d)", stats.Len(), counter))
+ }
+ return nil
+}
diff --git a/tableStats.go b/tableStats.go
index 0a278e0..3bd209a 100644
--- a/tableStats.go
+++ b/tableStats.go
@@ -33,21 +33,21 @@ func (pb *Stats) MakeTable(name string) *StatsTable {
col.Width = 10
col = t.AddHash()
- col.Width = 10
+ col.Width = 20
col.Header.Name = "Git Hash"
- col = t.AddStringFunc("something", func(r *Stat) string {
- return "notsure"
- })
- col.Width = 9
-
col = t.AddStringFunc("age", func(r *Stat) string {
return cobol.Time(r.Ctime)
})
col.Width = 28
- col = t.AddSubject()
- col.Width = -1
+ col = t.AddStringFunc("Name", func(r *Stat) string {
+ return "todo from []slice"
+ })
+ col.Width = 20
+
+ // col = t.AddSubject()
+ // col.Width = -1
return t
}