Compare commits
27 Commits
Author | SHA1 | Date |
---|---|---|
|
722ebeeef8 | |
|
5f882d1388 | |
|
658a2ce1a2 | |
|
db05f8a8aa | |
|
193f27ec30 | |
|
e7c6156562 | |
|
1e0f1e8e88 | |
|
a4a48d7480 | |
|
6b1e922aaa | |
|
46d61345af | |
|
434f62a7e6 | |
|
f585edc192 | |
|
d47d25e3a6 | |
|
5460316daf | |
|
72b5864000 | |
|
aef107af0d | |
|
f08a517bc4 | |
|
1ead02a6d3 | |
|
68af638f9e | |
|
1c43978294 | |
|
d0616fae03 | |
|
33399f18e5 | |
|
e2ca78cfb3 | |
|
683522ee46 | |
|
d4f9878298 | |
|
fcc5a36ad0 | |
|
7297b63339 |
2
Makefile
2
Makefile
|
@ -22,7 +22,7 @@ goimports:
|
||||||
# dump autogenerated files and potential patches
|
# dump autogenerated files and potential patches
|
||||||
clean:
|
clean:
|
||||||
rm -f *.pb.go go.* *.patch
|
rm -f *.pb.go go.* *.patch
|
||||||
go-mod-clean --purge
|
go-mod-clean purge
|
||||||
|
|
||||||
#refs.pb.go: refs.proto
|
#refs.pb.go: refs.proto
|
||||||
# cd ~/go/src && protoc --go_out=. --proto_path=go.wit.com/lib/protobuf/gitpb \
|
# cd ~/go/src && protoc --go_out=. --proto_path=go.wit.com/lib/protobuf/gitpb \
|
||||||
|
|
45
branches.go
45
branches.go
|
@ -7,7 +7,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"go.wit.com/log"
|
"github.com/go-cmd/cmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
// returns true if 'git pull' will work
|
// returns true if 'git pull' will work
|
||||||
|
@ -64,6 +64,18 @@ func (repo *Repo) GetTagHash(t string) string {
|
||||||
return result.Stdout[0]
|
return result.Stdout[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lookup a hash from a tag with 'git rev-list'
|
||||||
|
func (repo *Repo) GetBranchDifferences(to string, from string) []string {
|
||||||
|
// git rev-list -n 1 v0.0.66
|
||||||
|
cmd := []string{"git", "rev-list", to + "..." + from}
|
||||||
|
result, _ := repo.RunStrict(cmd)
|
||||||
|
// log.Info("getLastTagVersion()", result.Stdout)
|
||||||
|
|
||||||
|
// tmp := strings.TrimSpace(strings.Join(result.Stdout, "\n"))
|
||||||
|
// return shell.SplitNewLines(tmp)
|
||||||
|
return result.Stdout
|
||||||
|
}
|
||||||
|
|
||||||
// deletes the devel local branch if it is a subset of the remote devel branch
|
// deletes the devel local branch if it is a subset of the remote devel branch
|
||||||
func (repo *Repo) DeleteLocalDevelBranch() error {
|
func (repo *Repo) DeleteLocalDevelBranch() error {
|
||||||
branch := repo.GetDevelBranchName()
|
branch := repo.GetDevelBranchName()
|
||||||
|
@ -72,13 +84,40 @@ func (repo *Repo) DeleteLocalDevelBranch() error {
|
||||||
if !repo.IsDevelRemote() {
|
if !repo.IsDevelRemote() {
|
||||||
return fmt.Errorf("no remote branch")
|
return fmt.Errorf("no remote branch")
|
||||||
}
|
}
|
||||||
|
|
||||||
b1 := repo.CountDiffObjects(branch, remote) // should be zero
|
b1 := repo.CountDiffObjects(branch, remote) // should be zero
|
||||||
if b1 == 0 {
|
if b1 == 0 {
|
||||||
cmd := []string{"git", "branch", "-D", repo.GetDevelBranchName()}
|
cmd := []string{"git", "branch", "-D", repo.GetDevelBranchName()}
|
||||||
log.Info("DEVEL IS IN REMOTE", repo.GetGoPath(), cmd)
|
_, err := repo.RunVerboseOnError(cmd)
|
||||||
err := repo.RunVerbose(cmd)
|
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("local branch has patches not in remote")
|
return fmt.Errorf("local branch has patches not in remote")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// makes a local branch based off of the master branch
|
||||||
|
// (unless a remote devel branch exists. then it uses that)
|
||||||
|
func (repo *Repo) MakeLocalDevelBranch() (*cmd.Status, error) {
|
||||||
|
branch := repo.GetDevelBranchName()
|
||||||
|
if branch == "" {
|
||||||
|
// hard coded default
|
||||||
|
branch = "devel"
|
||||||
|
}
|
||||||
|
|
||||||
|
if repo.Exists(filepath.Join(".git/refs/heads", branch)) {
|
||||||
|
// local devel branch already exists
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if repo.Exists(filepath.Join(".git/refs/remotes/origin", branch)) {
|
||||||
|
// remote devel branch exists, but local does not
|
||||||
|
cmd := []string{"git", "checkout", branch}
|
||||||
|
return repo.RunVerboseOnError(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
master := repo.GetMasterBranchName()
|
||||||
|
cmd := []string{"git", "branch", branch, master}
|
||||||
|
repo.RunVerboseOnError(cmd)
|
||||||
|
cmd = []string{"git", "checkout", branch}
|
||||||
|
return repo.RunVerboseOnError(cmd)
|
||||||
|
}
|
||||||
|
|
49
checkout.go
49
checkout.go
|
@ -1,6 +1,9 @@
|
||||||
package gitpb
|
package gitpb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"go.wit.com/log"
|
"go.wit.com/log"
|
||||||
|
@ -8,6 +11,20 @@ import (
|
||||||
|
|
||||||
func (repo *Repo) CheckoutMaster() bool {
|
func (repo *Repo) CheckoutMaster() bool {
|
||||||
bName := repo.GetMasterBranchName()
|
bName := repo.GetMasterBranchName()
|
||||||
|
if bName == "giterr" {
|
||||||
|
cmd := []string{"git", "checkout", "main"} // todo: figure out main
|
||||||
|
repo.RunVerboseOnError(cmd)
|
||||||
|
os.Exit(-1)
|
||||||
|
// TODO: try to fix this
|
||||||
|
if repo.checkoutBranch("main") {
|
||||||
|
repo.MasterBranchName = "main"
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
cmd := []string{"git", "checkout", "main"} // todo: figure out main
|
||||||
|
repo.RunVerboseOnError(cmd)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
if repo.checkoutBranch(bName) {
|
if repo.checkoutBranch(bName) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -26,12 +43,20 @@ func (repo *Repo) CheckoutDevel() bool {
|
||||||
|
|
||||||
func (repo *Repo) CheckoutUser() error {
|
func (repo *Repo) CheckoutUser() error {
|
||||||
bName := repo.GetUserBranchName()
|
bName := repo.GetUserBranchName()
|
||||||
// log.Info("attempting checkout user", repo.GetGoPath(), bName)
|
if bName == "uerr" {
|
||||||
err := repo.createUserBranchNew(bName)
|
usr, _ := user.Current()
|
||||||
if err != nil {
|
repo.SetUserBranchName(usr.Username)
|
||||||
log.Info("attempting checkout user error", repo.GetGoPath(), bName, err)
|
bName = usr.Username
|
||||||
|
log.Info("gitpb CheckoutUser() somehow got user 'uerr'")
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
|
return repo.createUserBranch(bName)
|
||||||
|
/*
|
||||||
|
if err != nil {
|
||||||
|
log.Info("attempting checkout user error", repo.GetGoPath(), bName, err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repo) BranchExists(bName string) bool {
|
func (repo *Repo) BranchExists(bName string) bool {
|
||||||
|
@ -67,16 +92,16 @@ func (repo *Repo) checkoutBranch(bName string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repo) createUserBranchNew(branch string) error {
|
// actually creates a local user branch
|
||||||
if branch == "" || branch == "uerr" {
|
func (repo *Repo) createUserBranch(branch string) error {
|
||||||
log.Info("forge.gitpb logic err. branch name was:", branch)
|
if branch == "" {
|
||||||
return nil
|
// get the username here?
|
||||||
|
return fmt.Errorf("gitpb createuserBranch() logic err. git branch name can not be blank")
|
||||||
}
|
}
|
||||||
if repo.IsDirty() {
|
if repo.IsDirty() {
|
||||||
// never change repos on dirty branches
|
// never change repos on dirty branches
|
||||||
return nil
|
return fmt.Errorf("repo is dirty")
|
||||||
}
|
}
|
||||||
// log.Info("forge.gitpb look for branch name was:", branch, repo.GetGoPath())
|
|
||||||
|
|
||||||
if repo.Exists(filepath.Join(".git/refs/heads", branch)) {
|
if repo.Exists(filepath.Join(".git/refs/heads", branch)) {
|
||||||
var err error
|
var err error
|
||||||
|
@ -110,8 +135,6 @@ func (repo *Repo) createUserBranchNew(branch string) error {
|
||||||
// return fmt.Errorf("repo must be on devel branch %s", repo.GetGoPath())
|
// return fmt.Errorf("repo must be on devel branch %s", repo.GetGoPath())
|
||||||
}
|
}
|
||||||
|
|
||||||
// log.Info("forge.gitpb try to create", branch, repo.GetGoPath())
|
|
||||||
|
|
||||||
// create the branch from devel
|
// create the branch from devel
|
||||||
cmd := []string{"git", "branch", branch}
|
cmd := []string{"git", "branch", branch}
|
||||||
if _, err := repo.RunVerboseOnError(cmd); err != nil {
|
if _, err := repo.RunVerboseOnError(cmd); err != nil {
|
||||||
|
|
56
config.go
56
config.go
|
@ -8,6 +8,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"go.wit.com/lib/protobuf/bugpb"
|
||||||
"go.wit.com/log"
|
"go.wit.com/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,6 +27,19 @@ func (all *Repos) ConfigSave() error {
|
||||||
data, err := all.Marshal()
|
data, err := all.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Info("gitpb proto.Marshal() failed len", len(data), err)
|
log.Info("gitpb proto.Marshal() failed len", len(data), err)
|
||||||
|
// often this is because strings have invalid UTF-8. This should probably be fixed in the protobuf code
|
||||||
|
if err := all.tryValidate(); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
// re-attempt Marshal() here
|
||||||
|
data, err = all.Marshal()
|
||||||
|
if err == nil {
|
||||||
|
// validate & sanitize strings worked
|
||||||
|
log.Info("gitpb.ConfigSave() repos.Marshal() worked len", len(all.Repos), "repos")
|
||||||
|
configWrite("repos.pb", data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Info("gitpb.ConfigSave() repos.Marshal() worked len", len(all.Repos), "repos")
|
log.Info("gitpb.ConfigSave() repos.Marshal() worked len", len(all.Repos), "repos")
|
||||||
|
@ -33,6 +47,39 @@ func (all *Repos) ConfigSave() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: move this to Marshal() functions automatically in autogenpb?
|
||||||
|
func (repo *Repo) ValidateUTF8() error {
|
||||||
|
if _, err := repo.Marshal(); err == nil {
|
||||||
|
// exit if Marshal() works
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
// log.Printf("%s repo.Marshal() failed: %v\n", repo.GetFullPath(), err)
|
||||||
|
}
|
||||||
|
// you only need to do this if Marshal() fails
|
||||||
|
err := bugpb.ValidateProtoUTF8(repo)
|
||||||
|
if err != nil {
|
||||||
|
// log.Printf("Protobuf UTF-8 validation failed: %v\n", err)
|
||||||
|
}
|
||||||
|
if err := bugpb.SanitizeProtoUTF8(repo); err != nil {
|
||||||
|
log.Warn("gitpb.ValidateUTF8()( failed:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (all *Repos) tryValidate() error {
|
||||||
|
err := bugpb.ValidateProtoUTF8(all)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Protobuf UTF-8 validation failed: %v\n", err)
|
||||||
|
}
|
||||||
|
if err := bugpb.SanitizeProtoUTF8(all); err != nil {
|
||||||
|
log.Warn("Sanitation failed:", err)
|
||||||
|
// log.Fatalf("Sanitization failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// load the repos.pb file. I shouldn't really matter if this
|
// load the repos.pb file. I shouldn't really matter if this
|
||||||
// fails. the file should be autogenerated. This is used
|
// fails. the file should be autogenerated. This is used
|
||||||
// locally just for speed
|
// locally just for speed
|
||||||
|
@ -72,9 +119,12 @@ func (all *Repos) ConfigLoad() error {
|
||||||
|
|
||||||
func deleteProtobufFile(filename string) {
|
func deleteProtobufFile(filename string) {
|
||||||
log.Log(WARN, "The protobuf file format has changed for", filename)
|
log.Log(WARN, "The protobuf file format has changed for", filename)
|
||||||
log.Log(WARN, "You must delete", filename)
|
log.Log(WARN, "Deleting old file:", filename)
|
||||||
log.Log(WARN, "This file will be recreated")
|
log.Log(WARN, "This file will be recreated on the next run.")
|
||||||
os.Exit(-1)
|
err := os.Remove(filename)
|
||||||
|
if err != nil {
|
||||||
|
log.Log(WARN, "failed to remove old protobuf file", "err", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (all *Repos) sampleConfig() {
|
func (all *Repos) sampleConfig() {
|
||||||
|
|
|
@ -145,7 +145,7 @@ func (repo *Repo) gitVersionByName(name string) (string, error) {
|
||||||
}
|
}
|
||||||
if !repo.IsBranch(name) {
|
if !repo.IsBranch(name) {
|
||||||
// tag does not exist
|
// tag does not exist
|
||||||
log.Log(WARN, "LocalTagExists()", name, "did not exist")
|
// log.Log(WARN, "LocalTagExists()", name, "did not exist")
|
||||||
return "", errors.New("gitDescribeByName() git fatal: Not a valid object name: " + name)
|
return "", errors.New("gitDescribeByName() git fatal: Not a valid object name: " + name)
|
||||||
}
|
}
|
||||||
cmd := []string{"git", "describe", "--tags", "--always", name}
|
cmd := []string{"git", "describe", "--tags", "--always", name}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
// todo: probably switch to using slices. new things added in 1.23
|
// todo: probably switch to using slices. new things added in 1.23
|
||||||
// https://pkg.go.dev/slices
|
// https://pkg.go.dev/slices
|
||||||
|
|
||||||
func (all *GitTags) newSort() *GitTagIterator {
|
func (all *GitTags) newSort() *GitTagScanner {
|
||||||
slices.SortFunc(all.GitTags, func(a, b *GitTag) int {
|
slices.SortFunc(all.GitTags, func(a, b *GitTag) int {
|
||||||
if n := strings.Compare(a.Name, b.Name); n != 0 {
|
if n := strings.Compare(a.Name, b.Name); n != 0 {
|
||||||
return n
|
return n
|
||||||
|
@ -44,12 +44,12 @@ func (all *GitTags) GetAge(name string) time.Time {
|
||||||
return newest
|
return newest
|
||||||
}
|
}
|
||||||
|
|
||||||
func (all *GitTags) SortByAge() *GitTagIterator {
|
func (all *GitTags) SortByAge() *GitTagScanner {
|
||||||
packs := all.selectAllGitTags()
|
packs := all.selectAllGitTags()
|
||||||
|
|
||||||
sort.Sort(GitTagAge(packs))
|
sort.Sort(GitTagAge(packs))
|
||||||
|
|
||||||
iterator := newGitTagIterator(packs)
|
iterator := newGitTagScanner(packs)
|
||||||
return iterator
|
return iterator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,8 +14,8 @@ import (
|
||||||
"go.wit.com/log"
|
"go.wit.com/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// reads and parses the go.sum file
|
// reads and parses the go.sum file into a protobuf struct
|
||||||
// does not change anything
|
// this function isn't supposed to change anything, just parse the existing files
|
||||||
func (repo *Repo) ParseGoSum() bool {
|
func (repo *Repo) ParseGoSum() bool {
|
||||||
// empty out what was there before
|
// empty out what was there before
|
||||||
repo.GoDeps = nil
|
repo.GoDeps = nil
|
||||||
|
@ -75,7 +75,7 @@ func (repo *Repo) ParseGoSum() bool {
|
||||||
|
|
||||||
// attempt to parse go.* files in a directory
|
// attempt to parse go.* files in a directory
|
||||||
func GoSumParseDir(moddir string) (*GoDeps, error) {
|
func GoSumParseDir(moddir string) (*GoDeps, error) {
|
||||||
isprim, err := computePrimitiveNew(moddir)
|
isprim, err := computePrimitive(moddir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// "go mod init" failed
|
// "go mod init" failed
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -85,14 +85,14 @@ func GoSumParseDir(moddir string) (*GoDeps, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
// go.sum exists. parse the go.sum file
|
// go.sum exists. parse the go.sum file
|
||||||
return parseGoSumNew(moddir)
|
return parseGoSum(moddir)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect a 'Primitive' package. Sets the isPrimitive flag
|
// Detect a 'Primitive' package. Sets the isPrimitive flag
|
||||||
// will return true if the repo is truly not dependent on _anything_ else
|
// will return true if the repo is truly not dependent on _anything_ else
|
||||||
// like spew or lib/widget
|
// like spew or lib/widget
|
||||||
// it assumes 'go mod init' and 'go mod tidy' ran without error
|
// it assumes 'go mod init' and 'go mod tidy' ran without error
|
||||||
func computePrimitiveNew(moddir string) (bool, error) {
|
func computePrimitive(moddir string) (bool, error) {
|
||||||
// go mod init & go mod tidy ran without errors
|
// go mod init & go mod tidy ran without errors
|
||||||
log.Log(INFO, "isPrimitiveGoMod()", moddir)
|
log.Log(INFO, "isPrimitiveGoMod()", moddir)
|
||||||
gomod, err := os.Open(filepath.Join(moddir, "go.mod"))
|
gomod, err := os.Open(filepath.Join(moddir, "go.mod"))
|
||||||
|
@ -131,7 +131,8 @@ func computePrimitiveNew(moddir string) (bool, error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseGoSumNew(moddir string) (*GoDeps, error) {
|
// parse the go.sum file into a protobuf
|
||||||
|
func parseGoSum(moddir string) (*GoDeps, error) {
|
||||||
godeps := new(GoDeps)
|
godeps := new(GoDeps)
|
||||||
|
|
||||||
tmp, err := os.Open(filepath.Join(moddir, "go.sum"))
|
tmp, err := os.Open(filepath.Join(moddir, "go.sum"))
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
// Copyright 1994-2025 WIT.COM Inc Licensed GPL 3.0
|
||||||
|
|
||||||
|
package gitpb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os/user"
|
||||||
|
|
||||||
|
"go.wit.com/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func httpPost(url string, data []byte) ([]byte, error) {
|
||||||
|
var err error
|
||||||
|
var req *http.Request
|
||||||
|
|
||||||
|
req, err = http.NewRequest(http.MethodPost, url, bytes.NewBuffer(data))
|
||||||
|
log.Info("httpPost() with len", len(data), "url", url)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
usr, _ := user.Current()
|
||||||
|
req.Header.Set("author", usr.Username)
|
||||||
|
req.Header.Set("hostname", "fixme:hostname")
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return []byte("client.Do(req) error"), err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
// log.Info("httpPost() with len", len(data))
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return body, err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("gitpb.httpPost() worked", url)
|
||||||
|
return body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Repos) SubmitReposPB(url string) (*Repos, error) {
|
||||||
|
msg, err := r.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
log.Info("Marshal() failed:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Info("proto.Marshal() msg len", len(msg))
|
||||||
|
body, err := httpPost(url, msg)
|
||||||
|
if err != nil {
|
||||||
|
log.Info("httpPost() failed:", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Info("httpPost() worked with url:", url, "len(body) =", len(body))
|
||||||
|
if err := r.Unmarshal(body); err != nil {
|
||||||
|
log.Info("SubmitReposPB() Unmarshal() failed:", err)
|
||||||
|
log.Printf("%s\n", body)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Repos) SendPB(w http.ResponseWriter) error {
|
||||||
|
data, err := r.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
log.Info("Marshal() failed:", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Info("SendPB() Marshal() len(data)", len(data))
|
||||||
|
fmt.Fprintf(w, "%s", data)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
10
reload.go
10
reload.go
|
@ -21,6 +21,15 @@ func (repo *Repo) ReloadCheck() error {
|
||||||
|
|
||||||
// TODO: clean this up more, but it is working now more or less
|
// TODO: clean this up more, but it is working now more or less
|
||||||
func (repo *Repo) Reload() error {
|
func (repo *Repo) Reload() error {
|
||||||
|
// sometimes, on new repos, if .git/HEAD does not exist
|
||||||
|
// defective git daemons or badly configured repos, 'git clone' can fail
|
||||||
|
// if so, 'git fetch origin' can repair the state
|
||||||
|
if !repo.Exists(".git/HEAD") {
|
||||||
|
cmd := []string{"git", "fetch", "origin"}
|
||||||
|
repo.RunVerbose(cmd)
|
||||||
|
cmd = []string{"git", "checkout", "main"} // todo: figure out main
|
||||||
|
repo.RunVerbose(cmd)
|
||||||
|
}
|
||||||
// log.Info("in reload", repo.FullPath)
|
// log.Info("in reload", repo.FullPath)
|
||||||
repo.Tags = new(GitTags)
|
repo.Tags = new(GitTags)
|
||||||
repo.reloadGitTags()
|
repo.reloadGitTags()
|
||||||
|
@ -47,6 +56,7 @@ func (repo *Repo) Reload() error {
|
||||||
|
|
||||||
// LastUpdate should always be the newest time
|
// LastUpdate should always be the newest time
|
||||||
repo.Times.LastUpdate = timestamppb.New(time.Now())
|
repo.Times.LastUpdate = timestamppb.New(time.Now())
|
||||||
|
repo.ValidateUTF8()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ func (repo *Repo) CheckBranches() bool {
|
||||||
if hash == hashCheck {
|
if hash == hashCheck {
|
||||||
// log.Info("notsure why this git show is here", hash)
|
// log.Info("notsure why this git show is here", hash)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("UNKNOWN BRANCH %-50s %s %s %s\n", repo.GetFullPath(), r.Stdout, cmd, b)
|
// log.Printf("UNKNOWN BRANCH %-50s %s %s %s\n", repo.GetFullPath(), r.Stdout, cmd, b)
|
||||||
perfect = false
|
perfect = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ func (repo *Repo) ExamineBranches() *GitTag {
|
||||||
if hash == hashCheck {
|
if hash == hashCheck {
|
||||||
// log.Info("notsure why this git show is here", hash)
|
// log.Info("notsure why this git show is here", hash)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("UNKNOWN BRANCH %-50s %s %s %s\n", repo.GetFullPath(), r.Stdout, cmd, b)
|
// log.Printf("UNKNOWN BRANCH %-50s %s %s %s\n", repo.GetFullPath(), r.Stdout, cmd, b)
|
||||||
tag := new(GitTag)
|
tag := new(GitTag)
|
||||||
tag.Refname = b
|
tag.Refname = b
|
||||||
tag.Hash = hash
|
tag.Hash = hash
|
||||||
|
|
|
@ -62,5 +62,4 @@ func (repo *Repo) CheckDirty() bool {
|
||||||
repo.State = "dirty"
|
repo.State = "dirty"
|
||||||
}
|
}
|
||||||
return bad
|
return bad
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,8 +138,28 @@ func (repo *Repo) readGitConfig() error {
|
||||||
default:
|
default:
|
||||||
log.Log(WARN, "unknown submodule line:", line)
|
log.Log(WARN, "unknown submodule line:", line)
|
||||||
}
|
}
|
||||||
|
case "diff":
|
||||||
|
// test, ok := rs.gitConfig.submodules[currentName]
|
||||||
|
switch key {
|
||||||
|
case "renameLimit":
|
||||||
|
log.Log(INFO, "name:", line)
|
||||||
|
default:
|
||||||
|
log.Log(WARN, "unknown name line:", filename, line)
|
||||||
|
}
|
||||||
|
case "user":
|
||||||
|
// test, ok := rs.gitConfig.submodules[currentName]
|
||||||
|
switch key {
|
||||||
|
case "name":
|
||||||
|
log.Log(INFO, "name:", line)
|
||||||
|
case "email":
|
||||||
|
log.Log(INFO, "email:", line)
|
||||||
|
default:
|
||||||
|
log.Log(WARN, "unknown name line:", filename, line)
|
||||||
|
}
|
||||||
|
case "git-bug":
|
||||||
|
log.Log(WARN, "repo uses git-bug!", filename)
|
||||||
default:
|
default:
|
||||||
log.Log(WARN, "unknown line:", line)
|
log.Log(WARN, filename, "unknown line:", line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (repo *Repo) RepoIgnoresGoMod() error {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ignored {
|
if ignored {
|
||||||
fmt.Printf("%s %s is ignored by Git.\n", repo.GetGoPath(), file)
|
// fmt.Printf("%s %s is ignored by Git.\n", repo.GetGoPath(), file)
|
||||||
repo.GoInfo.GitIgnoresGoSum = true
|
repo.GoInfo.GitIgnoresGoSum = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,9 @@ func (repo *Repo) setRepoState() {
|
||||||
repo.State = "merge to main"
|
repo.State = "merge to main"
|
||||||
// log.Info("master vs devel count is normal b1 == 0", b1)
|
// log.Info("master vs devel count is normal b1 == 0", b1)
|
||||||
} else {
|
} else {
|
||||||
repo.State = "DEVEL < MASTER"
|
repo.State = "DEVEL behind MASTER"
|
||||||
// log.Info("master vs devel count b1 != 0", b1)
|
// log.Info("master vs devel count b1 != 0", b1)
|
||||||
log.Info("SERIOUS ERROR. DEVEL BRANCH NEEDS MERGE FROM MASTER b1 ==", b1, repo.GetGoPath())
|
log.Infof("%s devel branch is behind master branch (missing %d commits)\n", repo.GetGoPath(), b1)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -53,9 +53,6 @@ func (repo *Repo) setRepoState() {
|
||||||
repo.State = "PERFECT"
|
repo.State = "PERFECT"
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Info("Branches are not Perfect", repo.GetFullPath())
|
|
||||||
log.Info("Branches are not Perfect", repo.GetFullPath())
|
|
||||||
log.Info("Branches are not Perfect", repo.GetFullPath())
|
|
||||||
repo.State = "unknown branches"
|
repo.State = "unknown branches"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,13 @@ import (
|
||||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// redo this. use go-git2 ?
|
||||||
|
func (repo *Repo) allCommits() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// this is dumb
|
||||||
func (repo *Repo) AllCommits() error {
|
func (repo *Repo) AllCommits() error {
|
||||||
// tags := []string{"cd", "%(creatordate)", "%(*authordate)", "%(refname)", "%(subject)"}
|
// tags := []string{"cd", "%(creatordate)", "%(*authordate)", "%(refname)", "%(subject)"}
|
||||||
// format := strings.Join(tags, "_,,,_%")
|
// format := strings.Join(tags, "_,,,_%")
|
||||||
|
@ -27,6 +34,7 @@ func (repo *Repo) AllCommits() error {
|
||||||
repo.Times.NewestCommit = timestamppb.New(tmp)
|
repo.Times.NewestCommit = timestamppb.New(tmp)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// reload the tags
|
// reload the tags
|
||||||
func (repo *Repo) reloadGitTags() error {
|
func (repo *Repo) reloadGitTags() error {
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
// Code generated by go.wit.com/apps/autogenpb DO NOT EDIT.
|
||||||
|
// This file was autogenerated with autogenpb v0.0.78 2025-08-31_15:49:04_UTC
|
||||||
|
// go install go.wit.com/apps/autogenpb@latest
|
||||||
|
//
|
||||||
|
// define which structs (messages) you want to use in the .proto file
|
||||||
|
// Then sort.pb.go and marshal.pb.go files are autogenerated
|
||||||
|
//
|
||||||
|
// autogenpb uses it and has an example .proto file with instructions
|
||||||
|
//
|
||||||
|
|
||||||
|
package gitpb
|
||||||
|
|
||||||
|
func (t *ReposTable) MyMasterBranch() *RepoStringFunc {
|
||||||
|
sf := t.AddStringFunc("master", func(m *Repo) string {
|
||||||
|
return m.MasterBranchName
|
||||||
|
})
|
||||||
|
sf.Width = 30
|
||||||
|
return sf
|
||||||
|
}
|
|
@ -18,35 +18,35 @@ func (r *Repo) MergeToDevel() (*cmd.Status, error) {
|
||||||
devel := r.GetDevelBranchName()
|
devel := r.GetDevelBranchName()
|
||||||
user := r.GetUserBranchName()
|
user := r.GetUserBranchName()
|
||||||
|
|
||||||
log.Info("MergeToDevel() merging from", user, "into", devel)
|
log.Info(r.FullPath, "MergeToDevel() merging from", user, "into", devel)
|
||||||
|
|
||||||
cmd := []string{"git", "merge", user}
|
cmd := []string{"git", "merge", user}
|
||||||
result, err := r.RunQuiet(cmd)
|
result := r.RunRealtimeVerbose(cmd)
|
||||||
if err != nil {
|
if result.Error != nil {
|
||||||
log.Log(WARN, "MergeToDevel() failed", r.GetFullPath())
|
log.Log(WARN, "MergeToDevel() failed", r.GetFullPath())
|
||||||
return result, err
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
if !r.IsBranchRemote(devel) {
|
if !r.IsBranchRemote(devel) {
|
||||||
r.Reload() // rescan the repo
|
r.Reload() // rescan the repo
|
||||||
// devel branch is not remote. do not try 'git push'
|
// devel branch is not remote. do not try 'git push'
|
||||||
return result, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
if r.GetReadOnly() {
|
if r.GetReadOnly() {
|
||||||
r.Reload() // rescan the repo
|
r.Reload() // rescan the repo
|
||||||
// devel branch is read only. you can not git push
|
// devel branch is read only. you can not git push
|
||||||
return result, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// it seems like we have write access. lets find out!
|
// it seems like we have write access. lets find out!
|
||||||
cmd = []string{"git", "push"}
|
cmd = []string{"git", "push"}
|
||||||
result, err = r.RunQuiet(cmd)
|
result = r.RunRealtimeVerbose(cmd)
|
||||||
if err != nil {
|
if result.Error != nil {
|
||||||
log.Log(WARN, "GitPushToDevel() failed", r.GetFullPath())
|
log.Log(WARN, "GitPushToDevel() failed", r.GetFullPath())
|
||||||
return result, err
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
r.Reload() // rescan the repo
|
r.Reload() // rescan the repo
|
||||||
return result, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repo) MergeToMaster() (*cmd.Status, error) {
|
func (r *Repo) MergeToMaster() (*cmd.Status, error) {
|
||||||
|
@ -69,25 +69,25 @@ func (r *Repo) MergeToMaster() (*cmd.Status, error) {
|
||||||
log.Info("MergeToMaster() merging from", devel, "into", master)
|
log.Info("MergeToMaster() merging from", devel, "into", master)
|
||||||
|
|
||||||
cmd := []string{"git", "merge", devel}
|
cmd := []string{"git", "merge", devel}
|
||||||
result, err := r.RunQuiet(cmd)
|
result := r.RunRealtimeVerbose(cmd)
|
||||||
if err != nil {
|
if result.Error != nil {
|
||||||
log.Log(WARN, "MergeToMaster() failed", r.GetFullPath())
|
log.Log(WARN, "MergeToMaster() failed", r.GetFullPath())
|
||||||
return result, err
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.GetReadOnly() {
|
if r.GetReadOnly() {
|
||||||
r.Reload() // rescan the repo
|
r.Reload() // rescan the repo
|
||||||
// master branch is read only. you can not git push
|
// master branch is read only. you can not git push
|
||||||
return result, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// it seems like we have write access. lets find out!
|
// it seems like we have write access. lets find out!
|
||||||
cmd = []string{"git", "push"}
|
cmd = []string{"git", "push"}
|
||||||
result, err = r.RunQuiet(cmd)
|
result = r.RunRealtimeVerbose(cmd)
|
||||||
if err != nil {
|
if result.Error != nil {
|
||||||
log.Log(WARN, "GitPushToMaster() failed", r.GetFullPath())
|
log.Log(WARN, "GitPushToMaster() failed", r.GetFullPath())
|
||||||
return result, err
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
r.Reload() // rescan the repo
|
r.Reload() // rescan the repo
|
||||||
return result, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
39
repo.new.go
39
repo.new.go
|
@ -25,7 +25,8 @@ func (all *Repos) NewGoRepo(fullpath string, gopath string) (*Repo, error) {
|
||||||
|
|
||||||
// add a new one here
|
// add a new one here
|
||||||
newr := Repo{
|
newr := Repo{
|
||||||
FullPath: fullpath,
|
FullPath: fullpath,
|
||||||
|
Namespace: gopath,
|
||||||
}
|
}
|
||||||
newr.Times = new(GitTimes)
|
newr.Times = new(GitTimes)
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ func (all *Repos) NewGoRepo(fullpath string, gopath string) (*Repo, error) {
|
||||||
// everything happens in here
|
// everything happens in here
|
||||||
newr.Reload()
|
newr.Reload()
|
||||||
|
|
||||||
|
newr.ValidateUTF8()
|
||||||
if all.AppendByFullPath(&newr) {
|
if all.AppendByFullPath(&newr) {
|
||||||
// worked
|
// worked
|
||||||
return &newr, nil
|
return &newr, nil
|
||||||
|
@ -49,7 +51,10 @@ func (all *Repos) NewGoRepo(fullpath string, gopath string) (*Repo, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// enforces GoPath is unique
|
// enforces GoPath is unique
|
||||||
func (all *Repos) AppendByGoPath(newr *Repo) bool {
|
// TODO: deprecate this (?)
|
||||||
|
// mutex's should finally work in the autogenpb protobuf code
|
||||||
|
/*
|
||||||
|
func (all *Repos) AppendByGoPathOld(newr *Repo) bool {
|
||||||
// all.RLock()
|
// all.RLock()
|
||||||
repoMu.RLock()
|
repoMu.RLock()
|
||||||
|
|
||||||
|
@ -63,7 +68,35 @@ func (all *Repos) AppendByGoPath(newr *Repo) bool {
|
||||||
// all.RUnlock()
|
// all.RUnlock()
|
||||||
repoMu.RUnlock()
|
repoMu.RUnlock()
|
||||||
|
|
||||||
// all.Repos = append(all.Repos, newr)
|
|
||||||
all.Append(newr)
|
all.Append(newr)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func (all *Repos) NewRepo(fullpath string, namespace string) (*Repo, error) {
|
||||||
|
if r := all.FindByFullPath(fullpath); r != nil {
|
||||||
|
log.Info("gitpb.NewRepo() might already have namespace", r.GetNamespace())
|
||||||
|
log.Info("gitpb.NewRepo() already has FullPath", r.FullPath)
|
||||||
|
// already had this gopath
|
||||||
|
return r, errors.New("gitpb.NewRepo() duplicate path " + fullpath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a new one here
|
||||||
|
newr := Repo{
|
||||||
|
FullPath: fullpath,
|
||||||
|
Namespace: namespace,
|
||||||
|
}
|
||||||
|
newr.Times = new(GitTimes)
|
||||||
|
|
||||||
|
// everything happens in here
|
||||||
|
newr.Reload()
|
||||||
|
|
||||||
|
newr.ValidateUTF8()
|
||||||
|
if all.AppendByFullPath(&newr) {
|
||||||
|
// worked
|
||||||
|
return &newr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: use Repos.Lock()
|
||||||
|
return nil, errors.New("gitpb.NewRepo() append failed " + fullpath)
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import "google/protobuf/timestamp.proto"; // Import the well-known type for Time
|
||||||
// global settings for autogenpb `autogenpb:mutex`
|
// global settings for autogenpb `autogenpb:mutex`
|
||||||
|
|
||||||
// should it be done this way?
|
// should it be done this way?
|
||||||
|
|
||||||
message GitTimes { // `autogenpb:nomutex`
|
message GitTimes { // `autogenpb:nomutex`
|
||||||
google.protobuf.Timestamp lastPull = 1; // last time a git pull was done
|
google.protobuf.Timestamp lastPull = 1; // last time a git pull was done
|
||||||
google.protobuf.Timestamp lastUpdate = 2; // when was ReloadGit() last done
|
google.protobuf.Timestamp lastUpdate = 2; // when was ReloadGit() last done
|
||||||
|
@ -42,7 +43,8 @@ message GoInfo { // `autogenpb
|
||||||
}
|
}
|
||||||
|
|
||||||
message Repo { // `autogenpb:marshal` `autogenpb:nomutex`
|
message Repo { // `autogenpb:marshal` `autogenpb:nomutex`
|
||||||
string fullPath = 1; // `autogenpb:unique` `autogenpb:sort` // the actual path to the .git directory: '/home/devel/golang.org/x/tools'
|
string namespace = 1; // `autogenpb:unique` `autogenpb:sort` // this repo is 'go.wit.com/lib/protobuf/gitpb'
|
||||||
|
string fullPath = 2; // `autogenpb:unique` `autogenpb:sort` // the OS path to the .git directory: '/home/devel/golang.org/x/tools'
|
||||||
string masterBranchName = 3; // git 'main' or 'master' branch name
|
string masterBranchName = 3; // git 'main' or 'master' branch name
|
||||||
string develBranchName = 4; // whatever the git 'devel' branch name is
|
string develBranchName = 4; // whatever the git 'devel' branch name is
|
||||||
string userBranchName = 5; // whatever your username branch is
|
string userBranchName = 5; // whatever your username branch is
|
||||||
|
@ -68,9 +70,9 @@ message Repo { // `autogenpb
|
||||||
GitConfig gitConfig = 25; // protobuf of the current .git/config
|
GitConfig gitConfig = 25; // protobuf of the current .git/config
|
||||||
}
|
}
|
||||||
|
|
||||||
message Repos { // `autogenpb:marshal` `autogenpb:sort` `autogenpb:nomutex` `autogenpb:gui`
|
message Repos { // `autogenpb:marshal` `autogenpb:sort` `autogenpb:gui` `autogenpb:nomutex`
|
||||||
string uuid = 1; // `autogenpb:uuid:8daaeba1-fb1f-4762-ae6e-95a55d352673`
|
string uuid = 1; // `autogenpb:uuid:8daaeba1-fb1f-4762-ae6e-95a55d352673`
|
||||||
string version = 2; // `autogenpb:version:v3`
|
string version = 2; // `autogenpb:version:v4`
|
||||||
repeated Repo repos = 3; // `autogenpb:append` // generate AppendUnique() function for this
|
repeated Repo repos = 3; // `autogenpb:append` // generate AppendUnique() function for this
|
||||||
bool hasFullScan = 4; // a full repo scan has been saved to disk
|
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
|
google.protobuf.Timestamp fullScan = 5; // mtime of the last full scan saved to disk
|
||||||
|
|
4
shell.go
4
shell.go
|
@ -43,7 +43,7 @@ func (repo *Repo) RunRealtime(cmd []string) cmd.Status {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repo) RunRealtimeVerbose(cmd []string) cmd.Status {
|
func (repo *Repo) RunRealtimeVerbose(cmd []string) cmd.Status {
|
||||||
log.Log(NOW, "Run:", repo.GetFullPath(), cmd)
|
log.Log(NOW, "EXEC: cd", repo.GetFullPath(), ";", cmd)
|
||||||
return shell.PathRunRealtime(repo.GetFullPath(), cmd)
|
return shell.PathRunRealtime(repo.GetFullPath(), cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ func (repo *Repo) RunStrictAll(all [][]string) (*cmd.Status, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repo) RunVerbose(cmd []string) error {
|
func (repo *Repo) RunVerbose(cmd []string) error {
|
||||||
log.Info("EXEC Running:", repo.GetGoPath(), cmd)
|
// log.Info("EXEC Running:", repo.GetGoPath(), cmd)
|
||||||
err := shell.PathExecVerbose(repo.GetFullPath(), cmd)
|
err := shell.PathExecVerbose(repo.GetFullPath(), cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Info("Error", cmd, err)
|
log.Info("Error", cmd, err)
|
||||||
|
|
Loading…
Reference in New Issue