diff options
| -rw-r--r-- | stat.makeRemoteRefs.go | 144 | ||||
| -rw-r--r-- | stat.proto | 19 | ||||
| -rw-r--r-- | stat.updateRefs.go | 66 | ||||
| -rw-r--r-- | tableStats.go | 16 |
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 +} @@ -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 } |
