Compare commits
16 Commits
Author | SHA1 | Date |
---|---|---|
|
ab666ddbc3 | |
|
0b30cd36dc | |
|
2a47f1e547 | |
|
719287c3bf | |
|
6654dbb410 | |
|
62e5fc396c | |
|
e793c89712 | |
|
9d968721d0 | |
|
5a98058474 | |
|
1d8380b9e7 | |
|
e395456c53 | |
|
cb60421374 | |
|
c2e3108698 | |
|
bf59b9124a | |
|
33c585f4cf | |
|
7d60a495ca |
10
Makefile
10
Makefile
|
@ -56,3 +56,13 @@ protoc-good:
|
||||||
--go_opt=MgitTag.proto=go.wit.com/lib/protobuf/gitpb \
|
--go_opt=MgitTag.proto=go.wit.com/lib/protobuf/gitpb \
|
||||||
--go_opt=MgoDep.proto=go.wit.com/lib/protobuf/gitpb \
|
--go_opt=MgoDep.proto=go.wit.com/lib/protobuf/gitpb \
|
||||||
go.wit.com/lib/protobuf/gitpb/repo.proto
|
go.wit.com/lib/protobuf/gitpb/repo.proto
|
||||||
|
|
||||||
|
protoc-todo-move-to-this:
|
||||||
|
# I think I should seperate these dirs. ONLY ONE .proto FILE PER DIRECTORY
|
||||||
|
# - httppb.HttpRequest httpRequest = 4; // correct syntax
|
||||||
|
protoc \
|
||||||
|
--proto_path=. \
|
||||||
|
--go_out=. \
|
||||||
|
--go_opt=Mgo.wit.com/lib/protobuf/forgepb/patchset.proto=go.wit.com/lib/protobuf/forgepb \
|
||||||
|
--go_opt=Mgo.wit.com/lib/protobuf/httppb/httpRequest.proto=go.wit.com/lib/protobuf/httppb \
|
||||||
|
go.wit.com/lib/protobuf/forgepb/patchset.proto
|
||||||
|
|
17
checkout.go
17
checkout.go
|
@ -2,7 +2,6 @@ package gitpb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"os/user"
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
@ -11,20 +10,6 @@ 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
|
||||||
}
|
}
|
||||||
|
@ -127,7 +112,7 @@ func (repo *Repo) createUserBranch(branch string) error {
|
||||||
if repo.GetCurrentBranchName() != repo.GetDevelBranchName() {
|
if repo.GetCurrentBranchName() != repo.GetDevelBranchName() {
|
||||||
repo.CheckoutDevel()
|
repo.CheckoutDevel()
|
||||||
}
|
}
|
||||||
repo.Reload()
|
repo.ReloadCheck()
|
||||||
|
|
||||||
if repo.GetCurrentBranchName() != repo.GetDevelBranchName() {
|
if repo.GetCurrentBranchName() != repo.GetDevelBranchName() {
|
||||||
log.Info("create user branch will probably fail", repo.GetGoPath())
|
log.Info("create user branch will probably fail", repo.GetGoPath())
|
||||||
|
|
|
@ -14,7 +14,10 @@ func (repo *Repo) SetMasterBranchName(s string) {
|
||||||
|
|
||||||
func (repo *Repo) GetGoPath() string {
|
func (repo *Repo) GetGoPath() string {
|
||||||
if repo.GoInfo == nil {
|
if repo.GoInfo == nil {
|
||||||
return ""
|
return repo.Namespace
|
||||||
|
}
|
||||||
|
if repo.GoInfo.GoPath == "" {
|
||||||
|
return repo.Namespace
|
||||||
}
|
}
|
||||||
return repo.GoInfo.GoPath
|
return repo.GoInfo.GoPath
|
||||||
}
|
}
|
||||||
|
|
76
config.go
76
config.go
|
@ -12,36 +12,40 @@ import (
|
||||||
"go.wit.com/log"
|
"go.wit.com/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// write to ~/.config/forge/ unless ENV{FORGE_GOSRC} is set
|
// write to ~/.config/forge/ unless ENV{FORGE_REPOSDIR} is set
|
||||||
func (all *Repos) ConfigSave() error {
|
func (all *Repos) ConfigSave(fname string) error {
|
||||||
if os.Getenv("FORGE_GOSRC") == "" {
|
|
||||||
homeDir, _ := os.UserHomeDir()
|
|
||||||
fullpath := filepath.Join(homeDir, ".config/forge")
|
|
||||||
os.Setenv("FORGE_GOSRC", fullpath)
|
|
||||||
}
|
|
||||||
if all == nil {
|
if all == nil {
|
||||||
log.Warn("gitpb all == nil")
|
log.Warn("gitpb repos == nil")
|
||||||
return errors.New("gitpb.ConfigSave() all == nil")
|
return errors.New("gitpb.ConfigSave() repos == nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, s := filepath.Split(fname); s != "repos.pb" {
|
||||||
|
log.Infof("ConfigSave() filename '%s' invalid\n", fname)
|
||||||
|
return log.Errorf("ConfigSave() filename '%s' invalid\n", fname)
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// often this is because strings have invalid UTF-8. This should probably be fixed in the protobuf code
|
||||||
|
// this might be fixed in the create code, but it can't hurt to try this as a last ditch effort here
|
||||||
|
log.Info("gitpb.ConfigSave() ATTEMPTING TO VALIDATE UTF-8 strings in the protobuf file")
|
||||||
if err := all.tryValidate(); err != nil {
|
if err := all.tryValidate(); err != nil {
|
||||||
|
log.Info("gitpb.ConfigSave() STILL FAILEd", err)
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
// re-attempt Marshal() here
|
// re-attempt Marshal() here
|
||||||
data, err = all.Marshal()
|
data, err = all.Marshal()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// validate & sanitize strings worked
|
// validate & sanitize strings worked
|
||||||
configWrite("repos.pb", data)
|
configWrite(fname, data)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
log.Info("gitpb.ConfigSave() STILL FAILEd", err)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
configWrite("repos.pb", data)
|
configWrite(fname, data)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,16 +85,43 @@ func (all *Repos) tryValidate() error {
|
||||||
// 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
|
||||||
func (all *Repos) ConfigLoad() error {
|
func (all *Repos) ConfigLoadOld() error {
|
||||||
if os.Getenv("FORGE_GOSRC") == "" {
|
if os.Getenv("FORGE_REPOSDIR") == "" {
|
||||||
homeDir, _ := os.UserHomeDir()
|
homeDir, _ := os.UserHomeDir()
|
||||||
fullpath := filepath.Join(homeDir, ".config/forge")
|
fullpath := filepath.Join(homeDir, ".config/forge")
|
||||||
os.Setenv("FORGE_GOSRC", fullpath)
|
os.Setenv("FORGE_REPOSDIR", fullpath)
|
||||||
}
|
}
|
||||||
var data []byte
|
var data []byte
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
cfgname := filepath.Join(os.Getenv("FORGE_GOSRC"), "repos.pb")
|
cfgname := filepath.Join(os.Getenv("FORGE_REPOSDIR"), "repos.pb")
|
||||||
|
if data, err = loadFile(cfgname); err != nil {
|
||||||
|
// something went wrong loading the file
|
||||||
|
// all.sampleConfig() // causes nil panic
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// this means the forge.pb file exists and was read
|
||||||
|
if len(data) == 0 {
|
||||||
|
return errors.New("gitpb.ConfigLoad() repos.pb is empty")
|
||||||
|
}
|
||||||
|
err = all.Unmarshal(data)
|
||||||
|
test := NewRepos()
|
||||||
|
if test.Uuid != all.Uuid {
|
||||||
|
log.Log(WARN, "uuids do not match", test.Uuid, all.Uuid)
|
||||||
|
deleteProtobufFile(cfgname)
|
||||||
|
}
|
||||||
|
if test.Version != all.Version {
|
||||||
|
log.Log(WARN, "versions do not match", test.Version, all.Version)
|
||||||
|
deleteProtobufFile(cfgname)
|
||||||
|
}
|
||||||
|
log.Log(INFO, cfgname, "protobuf versions and uuid match", all.Uuid, all.Version)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (all *Repos) ConfigLoad(cfgname string) error {
|
||||||
|
var data []byte
|
||||||
|
var err error
|
||||||
|
|
||||||
if data, err = loadFile(cfgname); err != nil {
|
if data, err = loadFile(cfgname); err != nil {
|
||||||
// something went wrong loading the file
|
// something went wrong loading the file
|
||||||
// all.sampleConfig() // causes nil panic
|
// all.sampleConfig() // causes nil panic
|
||||||
|
@ -98,7 +129,6 @@ func (all *Repos) ConfigLoad() error {
|
||||||
}
|
}
|
||||||
// this means the forge.pb file exists and was read
|
// this means the forge.pb file exists and was read
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
all.sampleConfig() // causes nil panic
|
|
||||||
return errors.New("gitpb.ConfigLoad() repos.pb is empty")
|
return errors.New("gitpb.ConfigLoad() repos.pb is empty")
|
||||||
}
|
}
|
||||||
err = all.Unmarshal(data)
|
err = all.Unmarshal(data)
|
||||||
|
@ -146,9 +176,7 @@ func loadFile(fullname string) ([]byte, error) {
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func configWrite(filename string, data []byte) error {
|
func configWrite(fullname string, data []byte) error {
|
||||||
fullname := filepath.Join(os.Getenv("FORGE_GOSRC"), filename)
|
|
||||||
|
|
||||||
log.Infof("%s your repos have changed state. cached state. (%d) bytes\n", fullname, len(data))
|
log.Infof("%s your repos have changed state. cached state. (%d) bytes\n", fullname, len(data))
|
||||||
cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
|
||||||
defer cfgfile.Close()
|
defer cfgfile.Close()
|
||||||
|
@ -156,16 +184,6 @@ func configWrite(filename string, data []byte) error {
|
||||||
log.Warn("open config file :", err)
|
log.Warn("open config file :", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if filename == "forge.text" {
|
|
||||||
// add header
|
|
||||||
cfgfile.Write([]byte("# this file is automatically re-generated from forge.pb, however,\n"))
|
|
||||||
cfgfile.Write([]byte("# if you want to edit it by hand, you can:\n"))
|
|
||||||
cfgfile.Write([]byte("# stop forge; remove forge.pb; edit forge.text; start forge\n"))
|
|
||||||
cfgfile.Write([]byte("# this will cause the default behavior to fallback to parsing this file for the config\n"))
|
|
||||||
cfgfile.Write([]byte("\n"))
|
|
||||||
cfgfile.Write([]byte("# this file is intended to be used to customize settings on what\n"))
|
|
||||||
cfgfile.Write([]byte("# git repos you have write access to. That is, where you can run 'git push'\n"))
|
|
||||||
}
|
|
||||||
cfgfile.Write(data)
|
cfgfile.Write(data)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,6 @@ func (repo *Repo) setMasterVersion() {
|
||||||
repo.MasterVersion = v
|
repo.MasterVersion = v
|
||||||
} else {
|
} else {
|
||||||
log.Log(WARN, "gitpb.GitMasterVersion() error:", err)
|
log.Log(WARN, "gitpb.GitMasterVersion() error:", err)
|
||||||
repo.MasterVersion = "giterr"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,11 +89,11 @@ func (repo *Repo) gitDescribeByHash(hash string) (string, error) {
|
||||||
if hash == "" {
|
if hash == "" {
|
||||||
return "", errors.New("hash was blank")
|
return "", errors.New("hash was blank")
|
||||||
}
|
}
|
||||||
r, err := repo.RunQuiet([]string{"git", "describe", "--tags", "--always", hash})
|
r, err := repo.RunQuiet([]string{"git", "describe", "--tags", hash})
|
||||||
out := strings.Join(r.Stdout, "\n")
|
out := strings.Join(r.Stdout, "\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("not in a git repo or bad hash?", err, repo.GetGoPath())
|
// log.Warn("not in a git repo or bad hash?", err, repo.GetGoPath())
|
||||||
return out, err
|
return "gitpb err", err
|
||||||
}
|
}
|
||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
@ -134,28 +133,27 @@ func (repo *Repo) gitVersionByName(name string) (string, error) {
|
||||||
|
|
||||||
if name == "" {
|
if name == "" {
|
||||||
// git will return the current tag
|
// git will return the current tag
|
||||||
r, err := repo.RunQuiet([]string{"git", "describe", "--tags", "--always"})
|
cmd := []string{"git", "describe", "--tags"}
|
||||||
|
r, err := repo.RunQuiet(cmd)
|
||||||
output := strings.Join(r.Stdout, "\n")
|
output := strings.Join(r.Stdout, "\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log(WARN, "gitDescribeByName() output might have worked anyway:", output)
|
log.Log(WARN, repo.FullPath, "gitDescribeByName() ", output, err, cmd)
|
||||||
log.Log(WARN, "gitDescribeByName() not in a git repo?", err, repo.GetGoPath())
|
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(output), nil
|
return strings.TrimSpace(output), nil
|
||||||
}
|
}
|
||||||
if !repo.IsBranch(name) {
|
if !repo.IsBranch(name) {
|
||||||
// tag does not exist
|
// branch does 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", name}
|
||||||
result, err := repo.RunQuiet(cmd)
|
result, err := repo.RunQuiet(cmd)
|
||||||
output := strings.Join(result.Stdout, "\n")
|
output := strings.Join(result.Stdout, "\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log(WARN, "cmd =", cmd)
|
//log.Log(WARN, "cmd =", cmd)
|
||||||
log.Log(WARN, "err =", err)
|
//log.Log(WARN, "err =", err)
|
||||||
log.Log(WARN, "output (might have worked with error?) =", output)
|
//log.Log(WARN, "output (might have worked with error?) =", output)
|
||||||
log.Log(WARN, "not in a git repo or bad tag?", repo.GetGoPath())
|
//log.Log(WARN, "not in a git repo or bad tag?", repo.GetGoPath())
|
||||||
return "", result.Error
|
return "", result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -83,8 +83,6 @@ func (repo *Repo) IsDevelRemote() bool {
|
||||||
// eventually this will be worked out by forge in some future code that hasn't been made yet
|
// eventually this will be worked out by forge in some future code that hasn't been made yet
|
||||||
func (repo *Repo) IsBranch(findname string) bool {
|
func (repo *Repo) IsBranch(findname string) bool {
|
||||||
for t := range repo.Tags.IterAll() {
|
for t := range repo.Tags.IterAll() {
|
||||||
// log.Info("LocalTagExists() tag:", t.Refname)
|
|
||||||
|
|
||||||
tagname := t.Refname
|
tagname := t.Refname
|
||||||
if strings.HasPrefix(tagname, "refs/remotes") {
|
if strings.HasPrefix(tagname, "refs/remotes") {
|
||||||
continue
|
continue
|
||||||
|
@ -103,10 +101,8 @@ func (repo *Repo) IsBranch(findname string) bool {
|
||||||
func (repo *Repo) IsLocalBranch(findname string) bool {
|
func (repo *Repo) IsLocalBranch(findname string) bool {
|
||||||
for t := range repo.Tags.IterAll() {
|
for t := range repo.Tags.IterAll() {
|
||||||
if !strings.HasPrefix(t.Refname, "refs/heads") {
|
if !strings.HasPrefix(t.Refname, "refs/heads") {
|
||||||
// log.Info("LocalTagExists() skip tag:", t.Refname)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// log.Info("LocalTagExists() check tag:", t.Refname)
|
|
||||||
path, filename := filepath.Split(t.Refname)
|
path, filename := filepath.Split(t.Refname)
|
||||||
log.Log(INFO, "gitpb.IsBranch() tag:", path, filename, "from", repo.GetGoPath())
|
log.Log(INFO, "gitpb.IsBranch() tag:", path, filename, "from", repo.GetGoPath())
|
||||||
if filename == findname {
|
if filename == findname {
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Code generated by go.wit.com/apps/autogenpb DO NOT EDIT.
|
||||||
|
// This file was autogenerated with autogenpb v0.5.1 2025-09-12_15:24:32_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
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go.wit.com/lib/cobol"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (mt *GitTagsTable) PrintTable() {
|
||||||
|
// log.Info("ShowTable() SENDING TO GUI")
|
||||||
|
mt.MakeTable()
|
||||||
|
cobol.PrintTable(mt.pb)
|
||||||
|
}
|
|
@ -15,7 +15,6 @@ message GitBranch { // `autogenpb:nomutex`
|
||||||
string name = 3; // the branch name from the config file
|
string name = 3; // the branch name from the config file
|
||||||
}
|
}
|
||||||
|
|
||||||
// readGitConfig reads and parses the .git/config file
|
|
||||||
message GitConfig { // `autogenpb:nomutex`
|
message GitConfig { // `autogenpb:nomutex`
|
||||||
map<string, string> core = 1; // map[origin] = "https:/git.wit.org/gui/gadgets"
|
map<string, string> core = 1; // map[origin] = "https:/git.wit.org/gui/gadgets"
|
||||||
map<string, GitRemote> remotes = 2; // map[origin] = "https:/git.wit.org/gui/gadgets"
|
map<string, GitRemote> remotes = 2; // map[origin] = "https:/git.wit.org/gui/gadgets"
|
||||||
|
@ -34,7 +33,7 @@ message GitTag { // `autogenpb:nomutex`
|
||||||
string subject = 5; // git tag subject
|
string subject = 5; // git tag subject
|
||||||
}
|
}
|
||||||
|
|
||||||
message GitTags { // `autogenpb:marshal` `autogenpb:nomutex`
|
message GitTags { // `autogenpb:marshal` `autogenpb:nomutex` `autogenpb:gui`
|
||||||
string uuid = 1; // `autogenpb:uuid:ffdff813-0316-4372-9e82-4c1c7d202526`
|
string uuid = 1; // `autogenpb:uuid:ffdff813-0316-4372-9e82-4c1c7d202526`
|
||||||
string version = 2; // `autogenpb:version:v0.0.47`
|
string version = 2; // `autogenpb:version:v0.0.47`
|
||||||
repeated GitTag gitTags = 3;
|
repeated GitTag gitTags = 3;
|
||||||
|
|
55
reload.go
55
reload.go
|
@ -4,23 +4,42 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"go.wit.com/lib/config"
|
||||||
"go.wit.com/log"
|
"go.wit.com/log"
|
||||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// sets a flag that the repos have changed
|
||||||
|
// used later by applications on exit to test if
|
||||||
|
// the protobuf needs to be written to disk
|
||||||
|
func reposChanged(b bool) {
|
||||||
|
config.SetChanged("repos", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true based on os.Stat() only checks
|
||||||
|
// seems to kinda work ok. goal is to avoid os.Exec() here for speed
|
||||||
|
// this might be the 1 place where libgit2 would be a good idea
|
||||||
|
func (repo *Repo) HasChanged() bool {
|
||||||
|
return repo.DidRepoChange()
|
||||||
|
}
|
||||||
|
|
||||||
// does a fast check with os.Stat()
|
// does a fast check with os.Stat()
|
||||||
// if the mtimes changed, does a full repo.Reload()
|
// if the mtimes changed, does a full repo.ReloadForce()
|
||||||
func (repo *Repo) ReloadCheck() error {
|
func (repo *Repo) ReloadCheck() error {
|
||||||
if !repo.DidRepoChange() {
|
if !repo.DidRepoChange() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// f.configSave = true
|
reposChanged(true)
|
||||||
err := repo.Reload()
|
err := repo.ReloadForce()
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return log.Errorf("gitpb.ReloadCheck() detected a change in the repo")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) ReloadForce() error {
|
||||||
|
reposChanged(true)
|
||||||
// sometimes, on new repos, if .git/HEAD does not exist
|
// sometimes, on new repos, if .git/HEAD does not exist
|
||||||
// defective git daemons or badly configured repos, 'git clone' can fail
|
// defective git daemons or badly configured repos, 'git clone' can fail
|
||||||
// if so, 'git fetch origin' can repair the state
|
// if so, 'git fetch origin' can repair the state
|
||||||
|
@ -54,12 +73,30 @@ func (repo *Repo) Reload() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repo.VerifyRemoteAndLocalBranches(repo.GetDevelBranchName())
|
||||||
|
repo.VerifyRemoteAndLocalBranches(repo.GetMasterBranchName())
|
||||||
|
|
||||||
// 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()
|
repo.ValidateUTF8()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (repo *Repo) VerifyRemoteAndLocalBranches(bname string) bool {
|
||||||
|
if !repo.IsBranchRemote(bname) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
lh := repo.GetLocalHash(bname)
|
||||||
|
rh := repo.GetRemoteHash(bname)
|
||||||
|
if lh == rh {
|
||||||
|
// log.Info(r.FullPath, "local devel == remote devel", lh, rh)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
log.Info(lh, rh, "local != remote", repo.FullPath, bname)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (repo *Repo) SetDevelBranchName(bname string) {
|
func (repo *Repo) SetDevelBranchName(bname string) {
|
||||||
repo.DevelBranchName = bname
|
repo.DevelBranchName = bname
|
||||||
}
|
}
|
||||||
|
@ -91,11 +128,13 @@ func (repo *Repo) setCurrentBranchVersion() {
|
||||||
log.Info("repo.GetCurrentBranchVersion() repo == nil")
|
log.Info("repo.GetCurrentBranchVersion() repo == nil")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
r, err := repo.RunQuiet([]string{"git", "describe", "--tags", "--always"})
|
r, err := repo.RunQuiet([]string{"git", "describe", "--tags"})
|
||||||
output := strings.Join(r.Stdout, "\n")
|
output := strings.Join(r.Stdout, "\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log(WARN, "GetCurrentBranchVersion() not in a git repo?", err, repo.GetGoPath())
|
// log.Log(WARN, "GetCurrentBranchVersion() not in a git repo?", err, repo.GetGoPath())
|
||||||
log.Log(WARN, "GetCurrentBranchVersion() output might have worked anyway:", output)
|
// log.Log(WARN, "GetCurrentBranchVersion() output might have worked anyway:", output)
|
||||||
|
repo.CurrentBranchVersion = "gitpb err"
|
||||||
|
return
|
||||||
}
|
}
|
||||||
repo.CurrentBranchVersion = strings.TrimSpace(output)
|
repo.CurrentBranchVersion = strings.TrimSpace(output)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,16 +27,28 @@ func (repo *Repo) updateGitConfig() error {
|
||||||
repo.GitConfig.Submodules = make(map[string]string)
|
repo.GitConfig.Submodules = make(map[string]string)
|
||||||
repo.GitConfig.Versions = make(map[string]string)
|
repo.GitConfig.Versions = make(map[string]string)
|
||||||
repo.GitConfig.Hashes = make(map[string]string)
|
repo.GitConfig.Hashes = make(map[string]string)
|
||||||
return repo.readGitConfig()
|
url, err := repo.readGitConfig()
|
||||||
|
if repo.URL != "" {
|
||||||
|
log.Info("gitpb: url already set", url, repo.URL)
|
||||||
|
}
|
||||||
|
|
||||||
|
if url == "" {
|
||||||
|
log.Info(repo.FullPath, "url was blank. warn user this repo is only on the local disk")
|
||||||
|
} else {
|
||||||
|
repo.URL = url
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// readGitConfig reads and parses the .git/config file
|
// readGitConfig reads and parses the .git/config file
|
||||||
func (repo *Repo) readGitConfig() error {
|
func (repo *Repo) readGitConfig() (string, error) {
|
||||||
|
var foundURL string
|
||||||
filename := filepath.Join(repo.GetFullPath(), ".git/config")
|
filename := filepath.Join(repo.GetFullPath(), ".git/config")
|
||||||
file, err := os.Open(filename)
|
file, err := os.Open(filename)
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentSection string = ""
|
var currentSection string = ""
|
||||||
|
@ -92,6 +104,13 @@ func (repo *Repo) readGitConfig() error {
|
||||||
log.Log(INFO, "switch currentSection", currentSection, currentName)
|
log.Log(INFO, "switch currentSection", currentSection, currentName)
|
||||||
switch key {
|
switch key {
|
||||||
case "url":
|
case "url":
|
||||||
|
if foundURL == "" {
|
||||||
|
foundURL = value
|
||||||
|
} else {
|
||||||
|
if foundURL != value {
|
||||||
|
log.Info("TODO: gitpb: handle multiple remotes in the parser", foundURL, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
if test.Url == value {
|
if test.Url == value {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -164,10 +183,10 @@ func (repo *Repo) readGitConfig() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := scanner.Err(); err != nil {
|
if err := scanner.Err(); err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return foundURL, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repo) processBranch(branch string) {
|
func (repo *Repo) processBranch(branch string) {
|
|
@ -168,11 +168,16 @@ func (repo *Repo) NewestTag() *GitTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
// this should just do is.Exists(".git/refs/heads/findname")
|
// this should just do is.Exists(".git/refs/heads/findname")
|
||||||
|
// this is a simple check and doesn't work all the time
|
||||||
func (repo *Repo) LocalTagExists(findname string) bool {
|
func (repo *Repo) LocalTagExists(findname string) bool {
|
||||||
fname := filepath.Join(".git/refs/heads", findname)
|
fname := filepath.Join(".git/refs/heads", findname)
|
||||||
if repo.Exists(fname) {
|
if repo.Exists(fname) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
fname = filepath.Join(".git/refs/tags", findname)
|
||||||
|
if repo.Exists(fname) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
loop := repo.Tags.SortByRefname()
|
loop := repo.Tags.SortByRefname()
|
||||||
for loop.Scan() {
|
for loop.Scan() {
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
package gitpb
|
package gitpb
|
||||||
|
|
||||||
func (t *ReposTable) MyMasterBranch() *RepoStringFunc {
|
func (t *ReposTable) MyMasterBranch() *RepoAnyFunc {
|
||||||
sf := t.AddStringFunc("master", func(m *Repo) string {
|
sf := t.AddStringFunc("master", func(m *Repo) string {
|
||||||
return m.MasterBranchName
|
return m.MasterBranchName
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *Repo) MergeToDevel() (*cmd.Status, error) {
|
func (r *Repo) MergeToDevel() (*cmd.Status, error) {
|
||||||
r.Reload()
|
r.ReloadCheck()
|
||||||
if r.GetCurrentBranchName() != r.GetDevelBranchName() {
|
if r.GetCurrentBranchName() != r.GetDevelBranchName() {
|
||||||
return nil, fmt.Errorf("repo not on devel branch")
|
return nil, fmt.Errorf("repo not on devel branch")
|
||||||
}
|
}
|
||||||
|
@ -28,15 +28,10 @@ func (r *Repo) MergeToDevel() (*cmd.Status, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !r.IsBranchRemote(devel) {
|
if !r.IsBranchRemote(devel) {
|
||||||
r.Reload() // rescan the repo
|
r.ReloadCheck() // rescan the repo
|
||||||
// devel branch is not remote. do not try 'git push'
|
// devel branch is not remote. do not try 'git push'
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
if r.GetReadOnly() {
|
|
||||||
r.Reload() // rescan the repo
|
|
||||||
// devel branch is read only. you can not git push
|
|
||||||
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"}
|
||||||
|
@ -45,21 +40,31 @@ func (r *Repo) MergeToDevel() (*cmd.Status, error) {
|
||||||
log.Log(WARN, "GitPushToDevel() failed", r.GetFullPath())
|
log.Log(WARN, "GitPushToDevel() failed", r.GetFullPath())
|
||||||
return nil, result.Error
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
r.Reload() // rescan the repo
|
r.ReloadCheck() // rescan the repo
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repo) MergeToMaster() (*cmd.Status, error) {
|
func (r *Repo) MergeToMaster() (*cmd.Status, error) {
|
||||||
r.Reload()
|
r.ReloadCheck()
|
||||||
|
|
||||||
if r.GetCurrentBranchName() != r.GetMasterBranchName() {
|
if r.GetCurrentBranchName() != r.GetMasterBranchName() {
|
||||||
return nil, fmt.Errorf("repo not on master branch")
|
return nil, fmt.Errorf("repo not on master branch")
|
||||||
}
|
}
|
||||||
if r.GetReadOnly() {
|
/*
|
||||||
r.Reload() // rescan the repo
|
if r.GetReadOnly() {
|
||||||
// master branch is read only. you can not git push
|
r.ReloadCheck() // rescan the repo
|
||||||
return nil, fmt.Errorf("can't merge to master on read only() repos")
|
// master branch is read only. you can not git push
|
||||||
}
|
lh := r.GetLocalHash("devel")
|
||||||
|
rh := r.GetRemoteHash("devel")
|
||||||
|
if lh == rh {
|
||||||
|
// log.Info(r.FullPath, "local devel == remote devel", lh, rh)
|
||||||
|
} else {
|
||||||
|
log.Info(r.FullPath, "local devel != remote devel", lh, rh)
|
||||||
|
}
|
||||||
|
log.Info("can't merge to master on read only() repos. trying anyway")
|
||||||
|
// return nil, fmt.Errorf("can't merge to master on read only() repos")
|
||||||
|
}
|
||||||
|
*/
|
||||||
if r.CheckDirty() {
|
if r.CheckDirty() {
|
||||||
return nil, fmt.Errorf("repo is dirty")
|
return nil, fmt.Errorf("repo is dirty")
|
||||||
}
|
}
|
||||||
|
@ -75,12 +80,6 @@ func (r *Repo) MergeToMaster() (*cmd.Status, error) {
|
||||||
return nil, result.Error
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.GetReadOnly() {
|
|
||||||
r.Reload() // rescan the repo
|
|
||||||
// master branch is read only. you can not git push
|
|
||||||
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 = r.RunRealtimeVerbose(cmd)
|
result = r.RunRealtimeVerbose(cmd)
|
||||||
|
@ -88,6 +87,6 @@ func (r *Repo) MergeToMaster() (*cmd.Status, error) {
|
||||||
log.Log(WARN, "GitPushToMaster() failed", r.GetFullPath())
|
log.Log(WARN, "GitPushToMaster() failed", r.GetFullPath())
|
||||||
return nil, result.Error
|
return nil, result.Error
|
||||||
}
|
}
|
||||||
r.Reload() // rescan the repo
|
r.ReloadCheck() // rescan the repo
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
35
repo.new.go
35
repo.new.go
|
@ -2,6 +2,8 @@ package gitpb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"go.wit.com/log"
|
"go.wit.com/log"
|
||||||
)
|
)
|
||||||
|
@ -33,7 +35,7 @@ func (all *Repos) NewGoRepo(fullpath string, gopath string) (*Repo, error) {
|
||||||
newr.GoInfo = new(GoInfo)
|
newr.GoInfo = new(GoInfo)
|
||||||
newr.GoInfo.GoPath = gopath
|
newr.GoInfo.GoPath = gopath
|
||||||
// everything happens in here
|
// everything happens in here
|
||||||
newr.Reload()
|
newr.ReloadForce()
|
||||||
|
|
||||||
newr.ValidateUTF8()
|
newr.ValidateUTF8()
|
||||||
if all.AppendByFullPath(&newr) {
|
if all.AppendByFullPath(&newr) {
|
||||||
|
@ -89,7 +91,7 @@ func (all *Repos) NewRepo(fullpath string, namespace string) (*Repo, error) {
|
||||||
newr.Times = new(GitTimes)
|
newr.Times = new(GitTimes)
|
||||||
|
|
||||||
// everything happens in here
|
// everything happens in here
|
||||||
newr.Reload()
|
newr.ReloadForce()
|
||||||
|
|
||||||
newr.ValidateUTF8()
|
newr.ValidateUTF8()
|
||||||
if all.AppendByFullPath(&newr) {
|
if all.AppendByFullPath(&newr) {
|
||||||
|
@ -100,3 +102,32 @@ func (all *Repos) NewRepo(fullpath string, namespace string) (*Repo, error) {
|
||||||
// todo: use Repos.Lock()
|
// todo: use Repos.Lock()
|
||||||
return nil, errors.New("gitpb.NewRepo() append failed " + fullpath)
|
return nil, errors.New("gitpb.NewRepo() append failed " + fullpath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewRepo(fullpath string) (*Repo, error) {
|
||||||
|
// add a new one here
|
||||||
|
repo := Repo{
|
||||||
|
FullPath: fullpath,
|
||||||
|
}
|
||||||
|
repo.Times = new(GitTimes)
|
||||||
|
|
||||||
|
// everything happens in here
|
||||||
|
repo.ReloadForce()
|
||||||
|
repo.ValidateUTF8()
|
||||||
|
if repo.Namespace == "" {
|
||||||
|
giturl := repo.GetURL()
|
||||||
|
if giturl == "" {
|
||||||
|
log.Info(repo.FullPath, "Namespace & URL are both blank. Warn the user of a local repo.")
|
||||||
|
return &repo, nil
|
||||||
|
}
|
||||||
|
// log.Info("GET Namespace from URL", giturl)
|
||||||
|
tmpURL, err := url.Parse(giturl)
|
||||||
|
if err != nil {
|
||||||
|
log.Info(repo.FullPath, "URL parse failed", giturl, err)
|
||||||
|
return &repo, nil
|
||||||
|
}
|
||||||
|
// log.Info(repo.FullPath, "namespace might be:", tmpURL.Hostname(), tmpURL.Path)
|
||||||
|
repo.Namespace = filepath.Join(tmpURL.Hostname(), tmpURL.Path)
|
||||||
|
// log.Info(repo.FullPath, "Namesapce =", repo.Namespace)
|
||||||
|
}
|
||||||
|
return &repo, nil
|
||||||
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ message Repo { // `autogenpb
|
||||||
GitConfig gitConfig = 25; // protobuf of the current .git/config
|
GitConfig gitConfig = 25; // protobuf of the current .git/config
|
||||||
string MasterHash = 26; // hash of the current master branch
|
string MasterHash = 26; // hash of the current master branch
|
||||||
string DevelHash = 27; // hash of the current devel branch
|
string DevelHash = 27; // hash of the current devel branch
|
||||||
|
map<string, string> control = 28; // control values. can be used to make packages (like .deb or .rpm)
|
||||||
}
|
}
|
||||||
|
|
||||||
message Repos { // `autogenpb:marshal` `autogenpb:sort` `autogenpb:gui` `autogenpb:nomutex` `autogenpb:http`
|
message Repos { // `autogenpb:marshal` `autogenpb:sort` `autogenpb:gui` `autogenpb:nomutex` `autogenpb:http`
|
||||||
|
|
|
@ -33,7 +33,7 @@ func (repo *Repo) RevertMasterToDevel() bool {
|
||||||
|
|
||||||
if repo.RunAll(all) {
|
if repo.RunAll(all) {
|
||||||
log.Info("EVERYTHING OK. RERELEASED", repo.GetGoPath())
|
log.Info("EVERYTHING OK. RERELEASED", repo.GetGoPath())
|
||||||
repo.Reload()
|
repo.ReloadCheck()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue