diff options
| -rw-r--r-- | repo.proto | 11 | ||||
| -rw-r--r-- | stat.SortCtime.go | 67 | ||||
| -rw-r--r-- | stat.makeRemote.go | 82 | ||||
| -rw-r--r-- | stat.makeRemoteRefs.go | 7 | ||||
| -rw-r--r-- | stat.proto | 26 | ||||
| -rw-r--r-- | stat.updateRefs.go | 13 | ||||
| -rw-r--r-- | tableStats.go | 44 | ||||
| -rw-r--r-- | versions.go | 182 |
8 files changed, 358 insertions, 74 deletions
@@ -45,8 +45,8 @@ message GoInfo { // `autogenpb } message Repo { // `autogenpb:marshal` `autogenpb:nomutex` - string uuid = 1; // `autogenpb:uuid:8daaeba1-fb1f-4762-ae6e-95a55d352673` - string namespace = 2; // `autogenpb:unique` `autogenpb:sort` // this repo is 'go.wit.com/lib/protobuf/gitpb' + string uuid = 1; // `autogenpb:unique` `autogenpb:sort` + string namespace = 2; // `autogenpb:unique` `autogenpb:sort` string fullPath = 3; // `autogenpb:unique` `autogenpb:sort` // the OS path to the .git directory: '/home/devel/golang.org/x/tools' string masterBranchName = 4; // git 'main' or 'master' branch name string develBranchName = 5; // whatever the git 'devel' branch name is @@ -70,12 +70,15 @@ message Repo { // `autogenpb GoInfo goInfo = 23; // put all the go specifcs here GitTag currentTag = 24; // used to examine repo branches GitTags tags = 25; // known tags - // GoDeps goDeps = 11; // what is in the go.sum file + Stat masterStat = 26; // just store this for now + Stat develStat = 27; // just store this for now + Stat userStat = 28; // just store this for now + Stats refs = 29; // just store this for now } message Repos { // `autogenpb:marshal` `autogenpb:sort` `autogenpb:gui` `autogenpb:nomutex` `autogenpb:http` string uuid = 1; // `autogenpb:uuid:8daaeba1-fb1f-4762-ae6e-95a55d352673` - string version = 2; // `autogenpb:version:v6` + string version = 2; // `autogenpb:version:v0.0.8 go.wit.com/protobuf/gitpb` repeated Repo repos = 3; // `autogenpb:append` // generate AppendUnique() function for this bool hasFullScan = 4; // a full repo scan has been saved to disk google.protobuf.Timestamp fullScan = 5; // mtime of the last full scan saved to disk diff --git a/stat.SortCtime.go b/stat.SortCtime.go index b8045d2..7e3b41a 100644 --- a/stat.SortCtime.go +++ b/stat.SortCtime.go @@ -10,7 +10,12 @@ package gitpb import ( + "fmt" "sort" + "strings" + + "go.wit.com/lib/env" + "go.wit.com/log" ) func (pb *Stats) SortCtime() { @@ -30,3 +35,65 @@ func (a sortStatCtime) Less(i, j int) bool { return itime.Before(jtime) } func (a sortStatCtime) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +// sort tags by Version() +// returns true if anything changed +var wasSorted bool + +func (pb *Stats) SortVersion() bool { + statMu.Lock() + defer statMu.Unlock() + + wasSorted = true + + sort.Sort(sortStatVersion(pb.Stats)) + + return wasSorted +} + +func tokVersion(r *Stat) (*Vers, error) { + var ver string + if strings.HasPrefix(r.Name, "refs/tags/") { + ver = strings.TrimPrefix(r.Name, "refs/tags/") + } else if strings.HasPrefix(r.Name, "refs/heads/") { + ver = strings.TrimPrefix(r.Name, "refs/heads/") + } else if strings.HasPrefix(r.Name, "refs/remotes/") { + ver = strings.TrimPrefix(r.Name, "refs/remotes/") + } else if strings.HasPrefix(r.Name, "refs/") { + ver = strings.TrimPrefix(r.Name, "refs/") + } else { + ver = fmt.Sprintf("%s", r.Name) + } + tok, err := TokenVersions(ver) + return tok, err +} + +// sort struct by Version +type sortStatVersion []*Stat + +func (a sortStatVersion) Len() int { return len(a) } +func (a sortStatVersion) Less(i, j int) bool { + atok, err1 := tokVersion(a[i]) + btok, err2 := tokVersion(a[j]) + _, _ = err1, err2 + cint := CompareVers(atok, btok) + if cint == 1 { + if env.True("stats") { + log.Info("false one", atok, "vs", btok, err1, err2, a[i].Name, a[j].Name) + } + return false + } + if cint == -1 { + if env.True("stats") { + log.Info("true less", atok, "vs", btok, err1, err2, err2, a[i].Name, a[j].Name) + } + wasSorted = false + return true + } + if env.True("stats") { + log.Info("false 0 ", atok, "vs", btok, err1, err2, err2, a[i].Name, a[j].Name) + } + return false +} + +func (a sortStatVersion) Swap(i, j int) { a[i], a[j] = a[j], a[i] } diff --git a/stat.makeRemote.go b/stat.makeRemote.go index 685238a..f583d2d 100644 --- a/stat.makeRemote.go +++ b/stat.makeRemote.go @@ -22,7 +22,7 @@ func (r *Repo) LoadRemote(remoteName string) (*Stats, error) { return stats, err } -var standardFmts []string = []string{"H", "T", "at", "ct", "f"} +var standardFmts []string = []string{"H", "T", "at", "ct", "f", "d"} var standardSeperator string = "___FORGE___" func makeFmts() string { @@ -35,6 +35,31 @@ func makeFmts() string { return "--format=" + strings.Join(all, standardSeperator) } +func makeStat(line string) *Stat { + line = strings.TrimSpace(line) + parts := strings.Split(line, standardSeperator) + if len(parts) != 6 { + log.Printf("BAD LINE: len(%d) %s\n", len(parts), line) + return nil + } + newstat := new(Stat) + newstat.Hash = parts[0] + newstat.TreeHash = parts[1] + t, err := cobol.GetTime(parts[2]) + _ = err + if t != nil { + newstat.AuthorTime = timestamppb.New(*t) + } + t, err = cobol.GetTime(parts[3]) + if t != nil { + newstat.CommitTime = timestamppb.New(*t) + } + newstat.SanitizedSubject = parts[4] + newstat.Tags = parts[5] + + return newstat +} + // makes a new file. File must be empty at start func (r *Repo) MakeRemote(remoteName string) (*Stats, error) { stats, err := r.LoadRemote(remoteName) @@ -42,9 +67,10 @@ func (r *Repo) MakeRemote(remoteName string) (*Stats, error) { return stats, err } if stats.Len() != 0 { - return stats, errors.New("refs file was already created") + // file was already created and populated with data + return stats, nil } - cmd := []string{"git", "log", "-n", "100", makeFmts(), "origin/HEAD"} // HEAD is _NOT_ always set + cmd := []string{"git", "log", makeFmts(), "origin/HEAD"} // HEAD is _NOT_ always set if env.True("stats") { log.Info("STATS VERBOSE Run:", cmd) } @@ -54,31 +80,11 @@ func (r *Repo) MakeRemote(remoteName string) (*Stats, error) { } var counter int for _, line := range cmdout.Stdout { - line = strings.TrimSpace(line) - parts := strings.Split(line, standardSeperator) - if len(parts) != 5 { - log.Printf("Repo: %s len(%d)\n", r.FullPath, len(parts)) - 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) + log.Printf("LINE:%s %d %s\n", line, counter, r.FullPath) } counter += 1 - newstat := new(Stat) - newstat.Hash = parts[0] - newstat.TreeHash = parts[1] - t, err := cobol.GetTime(parts[2]) - _ = err - if t != nil { - newstat.AuthorTime = timestamppb.New(*t) - } - t, err = cobol.GetTime(parts[3]) - if t != nil { - newstat.CommitTime = timestamppb.New(*t) - } - newstat.SanitizedSubject = parts[4] + newstat := makeStat(line) stats.Append(newstat) } if counter > 0 { @@ -107,20 +113,12 @@ func (r *Repo) UpdateRemote(remoteName string) error { } var counter int for _, line := range cmdout.Stdout { - line = strings.TrimSpace(line) - parts := strings.Split(line, standardSeperator) - if len(parts) != 5 { - log.Printf("Repo: %s len(%d)\n", r.FullPath, len(parts)) - 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) + log.Printf("LINE:%s %d %s\n", line, counter, r.FullPath) } counter += 1 - newstat := new(Stat) - newstat.Hash = parts[0] + newstat := makeStat(line) + // TODO: convert this protobuf to raw binary, then do a raw BinarySearch() on the hash n, found := slices.BinarySearchFunc(stats.Stats, newstat, func(a, b *Stat) int { return strings.Compare(a.Hash, b.Hash) }) @@ -130,18 +128,6 @@ func (r *Repo) UpdateRemote(remoteName string) error { // log.Info("found", n) continue } - - newstat.TreeHash = parts[1] - t, err := cobol.GetTime(parts[2]) - _ = err - if t != nil { - newstat.AuthorTime = timestamppb.New(*t) - } - t, err = cobol.GetTime(parts[3]) - if t != nil { - newstat.CommitTime = timestamppb.New(*t) - } - newstat.SanitizedSubject = parts[4] stats.Append(newstat) } if counter > 0 { diff --git a/stat.makeRemoteRefs.go b/stat.makeRemoteRefs.go index b1a5736..571843f 100644 --- a/stat.makeRemoteRefs.go +++ b/stat.makeRemoteRefs.go @@ -28,7 +28,8 @@ func (r *Repo) MakeRemoteRefs(remoteName string) (*Stats, error) { return stats, err } if stats.Len() != 0 { - return stats, errors.New("refs file was already created") + // file was already created and populated with data + return stats, nil } cmd := []string{"git", "ls-remote", remoteName} // must use 'master' as queried from the git server // GO has 250k remote refs if env.True("stats") { @@ -53,7 +54,7 @@ func (r *Repo) MakeRemoteRefs(remoteName string) (*Stats, error) { } counter += 1 newstat := new(Stat) - newstat.Hash = parts[0] + newstat.TagHash = parts[0] stats.Append(newstat) } if counter > 0 { @@ -116,7 +117,7 @@ func (r *Repo) UpdateRemoteRefs(remoteName string) error { // } counter += 1 newstat := new(Stat) - newstat.Hash = parts[0] + newstat.TagHash = parts[0] n, found := slices.BinarySearchFunc(stats.Stats, newstat, func(a, b *Stat) int { return strings.Compare(a.Hash, b.Hash) }) @@ -23,24 +23,26 @@ message GitRef { } // TODO: use patch.proto instead message Stat { - string patchId = 1; // `autogenpb:unique` `autogenpb:sort` - string hash = 2; // `autogenpb:unique` `autogenpb:sort` - string treeHash = 3; // `autogenpb:unique` `autogenpb:sort` - google.protobuf.Timestamp authorTime = 4; // `autogenpb:unique` `autogenpb:sort` - google.protobuf.Timestamp commitTime = 5; // `autogenpb:unique` `autogenpb:sort` - string sanitizedSubject = 6; // - string name = 7; // - string remote = 8; // blank unless REMOTE - string subject = 9; // git tag subject - GitRef.RefType type = 10; // is set by git as the master branch - repeated GitRef refs = 11; // this is dumb, but works for now. duplicate information is stored sometimes + string patchId = 1; // `autogenpb:sort` + string hash = 2; // `autogenpb:sort` + string treeHash = 3; // `autogenpb:sort` + string tagHash = 4; // `autogenpb:unique` `autogenpb:sort` + google.protobuf.Timestamp authorTime = 5; // `autogenpb:sort` + google.protobuf.Timestamp commitTime = 6; // `autogenpb:sort` + string sanitizedSubject = 7; // `autogenpb:sort` + string name = 8; // `autogenpb:unique` `autogenpb:sort` + string remote = 9; // blank unless REMOTE + string subject = 10; // git tag subject + GitRef.RefType type = 11; // is set by git as the master branch + repeated GitRef refs = 12; // this is dumb, but works for now. duplicate information is stored sometimes + string tags = 13; // git tag subject } // normally stored as .git/*.pb cache files // TODO: use patch.proto instead 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.3` + string version = 2; // `autogenpb:version:v0.0.7 go.wit.com/lib/protobuf/gitpb` 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 index 4676fe9..84f95f9 100644 --- a/stat.updateRefs.go +++ b/stat.updateRefs.go @@ -46,18 +46,23 @@ func (r *Repo) UpdateRefs(stats *Stats) error { log.Printf("LINE:%v %d %s\n", parts, counter, r.FullPath) } newstat := new(Stat) - newstat.Hash = parts[0] - // newstat.Name = parts[1] + newstat.TagHash = parts[0] + newstat.Name = parts[1] - teststat := stats.FindByHash(newstat.Hash) + teststat := stats.FindByName(newstat.Name) if teststat == nil { counter += 1 stats.Append(newstat) + } else { + if teststat.Name == "" { + counter += 1 + teststat.Name = parts[1] + } } } if counter > 0 { stats.SaveByHash() - return errors.New(fmt.Sprintf("len(%d) refs changed: (%d)", stats.Len(), counter)) + return errors.New(fmt.Sprintf("%s: len(%d) saved. changed %d refs.", stats.Filename, stats.Len(), counter)) } return nil } diff --git a/tableStats.go b/tableStats.go index f229553..06115dd 100644 --- a/tableStats.go +++ b/tableStats.go @@ -3,6 +3,9 @@ package gitpb import ( + "fmt" + "strings" + "go.wit.com/lib/cobol" "go.wit.com/log" ) @@ -32,17 +35,52 @@ func (pb *Stats) MakeTable(name string) *StatsTable { col = t.AddPatchId() col.Width = 10 - col = t.AddHash() + col = t.AddStringFunc("Hash", func(r *Stat) string { + if r.Hash != "" { + return fmt.Sprintf("Hash(%8.8s)", r.Hash) + } + if r.TreeHash != "" { + return fmt.Sprintf("Tree(%8.8s)", r.TreeHash) + } + if r.TagHash != "" { + return fmt.Sprintf("Tag (%8.8s)", r.TagHash) + } + return fmt.Sprintf(" (%8.8s)", "") + }) col.Width = 20 col.Header.Name = "Git Hash" col = t.AddStringFunc("age", func(r *Stat) string { return cobol.Time(r.CommitTime) }) - col.Width = 28 + col.Width = 27 + + col = t.AddTags() + col.Width = 20 + + // col = t.AddName() + // col.Width = 30 col = t.AddStringFunc("Name", func(r *Stat) string { - return r.SanitizedSubject + if strings.HasPrefix(r.Name, "refs/tags/") { + return strings.TrimPrefix(r.Name, "refs/tags/") + } + if strings.HasPrefix(r.Name, "refs/heads/") { + return strings.TrimPrefix(r.Name, "refs/heads/") + } + if strings.HasPrefix(r.Name, "refs/remotes/") { + return strings.TrimPrefix(r.Name, "refs/remotes/") + } + if strings.HasPrefix(r.Name, "refs/") { + return strings.TrimPrefix(r.Name, "refs/") + } + return fmt.Sprintf("%s", r.Name) + }) + col.Width = 16 + + col = t.AddStringFunc("Submect", func(r *Stat) string { + // return fmt.Sprintf("subject(%s) name(%s)", r.SanitizedSubject, r.Name) + return fmt.Sprintf("%s", r.SanitizedSubject) }) col.Width = -1 diff --git a/versions.go b/versions.go new file mode 100644 index 0000000..9f860c5 --- /dev/null +++ b/versions.go @@ -0,0 +1,182 @@ +package gitpb + +import ( + "errors" + "fmt" + "strconv" + "strings" + + "go.wit.com/log" +) + +// newver(0.25.101-1+b10) +// a == 0 +// b == 25 +// c == 101 +// pnum == 1 +// bnum == 10 +type Vers struct { + a int // major + b int + c int + pnum int + bnum int +} + +func TokenVersions(ver string) (*Vers, error) { + var err error + tok := new(Vers) + var golang bool + if strings.HasPrefix(ver, "v") { + golang = true + ver = strings.TrimPrefix(ver, "v") + } + parts := strings.Split(ver, "-") + if len(parts) == 0 { + return nil, errors.New("version was empty") + } + abc := strings.Split(parts[0], ".") + if len(abc) != 3 { + return nil, errors.New("abc != 3 parts") + } + tok.a, err = strconv.Atoi(abc[0]) + if err != nil { + return nil, errors.New("tok.a failed") + } + tok.b, err = strconv.Atoi(abc[1]) + if err != nil { + return nil, errors.New("tok.b failed") + } + tok.c, err = strconv.Atoi(abc[2]) + if err != nil { + return nil, errors.New("tok.c failed") + } + if golang { + return tok, nil + } + + if len(parts) != 2 { + return nil, errors.Join(err, errors.New("len != 2 parts")) + } + bb := strings.Split(parts[1], "+") + if len(bb) != 2 { + return nil, errors.Join(err, errors.New(fmt.Sprintf("parts(%v) abc(%v)", parts, abc))) + } + tok.pnum, err = strconv.Atoi(bb[0]) + if err != nil { + return nil, errors.Join(err, errors.New(fmt.Sprintf("parts(%v) abc(%v)", parts, abc))) + } + tok.bnum, err = strconv.Atoi(strings.TrimPrefix(bb[1], "b")) + if err != nil { + return nil, errors.Join(err, errors.New(fmt.Sprintf("parts(%v) abc(%v)", parts, abc))) + } + return tok, nil +} + +func CompareVers(atok *Vers, btok *Vers) int { + if (atok == nil) || (btok == nil) { + return 0 + } + // CHECK A + if atok.a > btok.a { + return 1 + } + if btok.a > atok.a { + return -1 + } + + // CHECK B + if atok.b > btok.b { + return 1 + } + if btok.b > atok.b { + return -1 + } + + // CHECK C + if atok.c > btok.c { + return 1 + } + if btok.c > atok.c { + return -1 + } + + // CHECK PATCH # + if atok.pnum > btok.pnum { + return 1 + } + if btok.pnum > atok.pnum { + return -1 + } + + // CHECK BUILD # + if atok.bnum > btok.bnum { + return 1 + } + if btok.bnum > atok.bnum { + return -1 + } + + // CHECK IS EQUAL + if atok.bnum == btok.bnum { + return 0 + } + return 0 // compare should not have gotten here (%v) to curver (%v)", newver, curver)) +} + +// compares newver(0.25.101-1+b10) curver(0.25.101-5+b1) +// returns true only if it's newer. returns false if equal +// used for .deb mirrors +func NewerVersion(newver string, curver string) (bool, error) { + newtok, err1 := TokenVersions(newver) + curtok, err2 := TokenVersions(curver) + if (newtok == nil) || (curtok == nil) { + s := log.Sprintf("token on the railroad failed (%v) to curver (%v) err(%v)(%v)", newtok, curtok, err1, err2) + return false, errors.New(s) + } + // CHECK A + if newtok.a > curtok.a { + return true, nil + } + if curtok.a > newtok.a { + return false, errors.New(log.Sprintf("A.x.x lower (%v) to curver (%v)", newver, curver)) + } + + // CHECK B + if newtok.b > curtok.b { + return true, nil + } + if curtok.b > newtok.b { + return false, errors.New(log.Sprintf("x.B.x lower (%v) to curver (%v)", newver, curver)) + } + + // CHECK C + if newtok.c > curtok.c { + return true, nil + } + if curtok.c > newtok.c { + return false, errors.New(log.Sprintf("x.x.C lower (%v) to curver (%v)", newver, curver)) + } + + // CHECK PATCH # + if newtok.pnum > curtok.pnum { + return true, nil + } + if curtok.pnum > newtok.pnum { + return false, errors.New(log.Sprintf("patch # lower (%v) to curver (%v)", newver, curver)) + } + + // CHECK BUILD # + if newtok.bnum > curtok.bnum { + return true, nil + } + if curtok.bnum > newtok.bnum { + return false, errors.New(log.Sprintf("build # lower (%v) to curver (%v)", newver, curver)) + } + + // CHECK IS EQUAL + if curtok.bnum == newtok.bnum { + return false, errors.New(log.Sprintf("new is equal (%v) to curver (%v)", newver, curver)) + } + return false, errors.New(log.Sprintf("compare should not have gotten here (%v) to curver (%v)", newver, curver)) +} |
