summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2025-01-18 10:34:58 -0600
committerJeff Carr <[email protected]>2025-01-18 10:34:58 -0600
commit0c30a9da2f9a30a9f41c755879ea5be266180ce0 (patch)
tree6cea2ef505f0cb92db890fd6a10f55f22f860c05
parent80f602c4d91fa84cfbafd3787cf255d2832ed588 (diff)
parse .git/configv0.0.57
-rw-r--r--gitTag.proto19
-rw-r--r--reload.go6
-rw-r--r--reloadGitConfig.go176
-rw-r--r--reloadMtime.go31
-rw-r--r--reloadTags.go33
-rw-r--r--repo.proto2
6 files changed, 254 insertions, 13 deletions
diff --git a/gitTag.proto b/gitTag.proto
index baae552..dbc28de 100644
--- a/gitTag.proto
+++ b/gitTag.proto
@@ -4,6 +4,25 @@ package gitpb;
import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp
+message GitRemote { // `autogenpb:nomutex`
+ string url = 1;
+ string fetch = 2;
+}
+
+message GitBranch { // `autogenpb:nomutex`
+ string remote = 1;
+ string merge = 2;
+}
+
+// readGitConfig reads and parses the .git/config file
+message GitConfig { // `autogenpb:nomutex`
+ 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, GitBranch> branches = 3; // map[guimaster] = origin guimaster
+ map<string, string> submodules = 4;
+ map<string, string> hashes = 5;
+ map<string, string> versions = 6;
+}
message GitTag { // `autogenpb:nomutex`
string refname = 1; // `autogenpb:unique` `autogenpb:sort` // tag name. treated as unique
diff --git a/reload.go b/reload.go
index 3ac55c1..bb122c0 100644
--- a/reload.go
+++ b/reload.go
@@ -28,6 +28,12 @@ func (repo *Repo) Reload() error {
repo.CheckDirty()
repo.setRepoState()
+ if repo.GitConfig == nil {
+ if err := repo.updateGitConfig(); err != nil {
+ return err
+ }
+ }
+
// LastUpdate should always be the newest time
repo.Times.LastUpdate = timestamppb.New(time.Now())
return nil
diff --git a/reloadGitConfig.go b/reloadGitConfig.go
new file mode 100644
index 0000000..367bd69
--- /dev/null
+++ b/reloadGitConfig.go
@@ -0,0 +1,176 @@
+package gitpb
+
+import (
+ "bufio"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "go.wit.com/log"
+)
+
+// does processing on the go.mod and go.sum files
+
+func (repo *Repo) updateGitConfig() error {
+ if repo == nil {
+ return fmt.Errorf("gitpb.updateGitConfig() repo == nil")
+ }
+ if repo.GitConfig == nil {
+ repo.GitConfig = new(GitConfig)
+ }
+
+ repo.GitConfig.Core = make(map[string]string)
+ repo.GitConfig.Remotes = make(map[string]*GitRemote)
+ repo.GitConfig.Branches = make(map[string]*GitBranch)
+ repo.GitConfig.Submodules = make(map[string]string)
+ repo.GitConfig.Versions = make(map[string]string)
+ repo.GitConfig.Hashes = make(map[string]string)
+ return repo.readGitConfig()
+}
+
+// readGitConfig reads and parses the .git/config file
+func (repo *Repo) readGitConfig() error {
+ filename := filepath.Join(repo.GetFullPath(), ".git/config")
+ file, err := os.Open(filename)
+ defer file.Close()
+ if err != nil {
+ return err
+ }
+
+ var currentSection string = ""
+ var currentName string = ""
+
+ scanner := bufio.NewScanner(file)
+ for scanner.Scan() {
+ line := strings.TrimSpace(scanner.Text())
+
+ // Skip empty lines and comments
+ if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") {
+ continue
+ }
+
+ // Check for section headers
+ if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
+ line = strings.Trim(line, "[]")
+ parts := strings.Split(line, " ")
+ currentSection = parts[0]
+
+ if len(parts) == 2 {
+ line = strings.Trim(line, "[]")
+ currentName = strings.Trim(parts[1], "\"")
+ }
+ continue
+ }
+
+ partsNew := strings.SplitN(line, "=", 2)
+ if len(partsNew) != 2 {
+ log.Log(WARN, "error on config section:", currentSection, "line:", line)
+ }
+
+ key := strings.TrimSpace(partsNew[0])
+ key = strings.TrimSuffix(key, "\"")
+
+ value := strings.TrimSpace(partsNew[1])
+ value = strings.TrimSuffix(value, "\"")
+
+ switch currentSection {
+ case "core":
+ repo.GitConfig.Core[key] = value
+ case "gui":
+ // don't really need gui stuff right now
+ case "pull":
+ // don't store git config pull settings here
+ // git config probably has 'rebase = false'
+ case "remote":
+ test, ok := repo.GitConfig.Remotes[currentName]
+ if !ok {
+ test = new(GitRemote)
+ repo.GitConfig.Remotes[currentName] = test
+ }
+ log.Log(INFO, "switch currentSection", currentSection, currentName)
+ switch key {
+ case "url":
+ if test.Url == value {
+ continue
+ }
+ if test.Url == "" {
+ test.Url = value
+ continue
+ }
+ log.Log(INFO, "error url mismatch", test.Url, value)
+ case "fetch":
+ if test.Fetch == value {
+ continue
+ }
+ if test.Fetch == "" {
+ test.Fetch = value
+ continue
+ }
+ log.Log(INFO, "error fetch mismatch", test.Fetch, value)
+ default:
+ log.Log(INFO, "unknown remote:", line)
+ }
+ case "branch":
+ test, ok := repo.GitConfig.Branches[currentName]
+ if !ok {
+ test = new(GitBranch)
+ repo.GitConfig.Branches[currentName] = test
+ repo.processBranch(currentName)
+ }
+ switch key {
+ case "remote":
+ repo.GitConfig.Branches[currentName].Remote = value
+ case "merge":
+ repo.GitConfig.Branches[currentName].Merge = value
+ default:
+ log.Log(INFO, "error unknown remote:", currentSection, currentName, key, value)
+ log.Log(INFO, "unknown branch:", line)
+ }
+ case "submodule":
+ // test, ok := rs.gitConfig.submodules[currentName]
+ switch key {
+ case "active":
+ // probably 'true' or 'false'
+ case "url":
+ repo.GitConfig.Submodules[currentName] = value
+ default:
+ log.Log(WARN, "unknown submodule line:", line)
+ }
+ default:
+ log.Log(WARN, "unknown line:", line)
+ }
+ }
+
+ if err := scanner.Err(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (repo *Repo) processBranch(branch string) {
+ log.Log(INFO, " ", branch)
+ hash, ok := repo.GitConfig.Hashes[branch]
+ filename := filepath.Join(repo.GetFullPath() + "/.git/refs/heads/" + branch)
+ log.Log(INFO, " hash: need to open", filename)
+
+ data, err := ioutil.ReadFile(filename)
+ if err != nil {
+ log.Log(WARN, "hash: read failed", filename)
+ return
+ }
+ newhash := strings.TrimSpace(string(data))
+ log.Log(INFO, " hash:", newhash)
+ repo.GitConfig.Hashes[branch] = newhash
+ if ok {
+ if hash != newhash {
+ log.Log(WARN, "hash changed", hash)
+ }
+ }
+
+ name, _ := repo.gitDescribeByHash(newhash)
+ repo.GitConfig.Versions[newhash] = name
+ log.Log(INFO, " hash: version", name)
+}
diff --git a/reloadMtime.go b/reloadMtime.go
index 7c18e9f..99869a7 100644
--- a/reloadMtime.go
+++ b/reloadMtime.go
@@ -119,6 +119,31 @@ func (repo *Repo) changedHead() bool {
return true
}
+// check the mtime of the .git/config file
+func (repo *Repo) changedConfig() bool {
+ fname := ".git/config"
+ fileTime := repo.Mtime(fname)
+ if fileTime == nil {
+ // .git/config doesn't exist. something is wrong!
+ log.Info("gitpb .git/config is missing", repo.GetGoPath())
+ return false
+ }
+ mtime := timestamppb.New(*fileTime)
+ pbtime := repo.Times.MtimeConfig
+ if pbtime == nil { // this can happen?
+ repo.Times.MtimeConfig = mtime
+ return true
+ }
+
+ if (pbtime.Seconds == mtime.Seconds) && (pbtime.Nanos == mtime.Nanos) {
+ return false
+ }
+ dur := mtime.AsTime().Sub(pbtime.AsTime())
+ repo.StateChange = fmt.Sprintf("%s changed %s", fname, shell.FormatDuration(dur))
+ repo.Times.MtimeConfig = mtime
+ return true
+}
+
func (repo *Repo) changedIndex() bool {
fname := ".git/index"
fileTime := repo.Mtime(fname)
@@ -154,6 +179,9 @@ func (repo *Repo) reloadMtimes() bool {
if repo.changedIndex() {
changed = true
}
+ if repo.changedConfig() {
+ changed = true
+ }
if repo.changedDir() {
// changed = true
}
@@ -171,6 +199,9 @@ func (repo *Repo) DidRepoChange() bool {
if repo.didFileChange(".git/index", repo.Times.MtimeIndex) {
return true
}
+ if repo.didFileChange(".git/config", repo.Times.MtimeConfig) {
+ return true
+ }
if repo.didFileChange(".git", repo.Times.MtimeDir) {
// todo: do something with CheckDirty()
// return true
diff --git a/reloadTags.go b/reloadTags.go
index eb4731e..3b574ac 100644
--- a/reloadTags.go
+++ b/reloadTags.go
@@ -135,21 +135,28 @@ func (repo *Repo) NewestTag() *GitTag {
return nil
}
+// this should just do is.Exists(".git/refs/heads/findname")
func (repo *Repo) LocalTagExists(findname string) bool {
- loop := repo.Tags.SortByRefname()
- for loop.Scan() {
- ref := loop.Next()
- // log.Info(repo.GoPath, ref.Refname)
- if strings.HasPrefix(ref.Refname, "refs/remotes") {
- continue
- }
- _, tagname := filepath.Split(ref.Refname)
- // log.Info("tag:", path, tagname, "from", repo.GoPath)
- if tagname == findname {
- // log.Info("found tag:", path, tagname, "from", repo.GoPath)
- return true
- }
+ fname := filepath.Join(".git/refs/heads", findname)
+ if repo.Exists(fname) {
+ return true
}
+ /*
+ loop := repo.Tags.SortByRefname()
+ for loop.Scan() {
+ ref := loop.Next()
+ // log.Info(repo.GoPath, ref.Refname)
+ if strings.HasPrefix(ref.Refname, "refs/remotes") {
+ continue
+ }
+ tagname := filepath.Base(ref.Refname)
+ // log.Info("tag:", path, tagname, "from", repo.GoPath)
+ if tagname == findname {
+ // log.Info("found tag:", path, tagname, "from", repo.GoPath)
+ return true
+ }
+ }
+ */
return false
}
diff --git a/repo.proto b/repo.proto
index 80583b9..a21b899 100644
--- a/repo.proto
+++ b/repo.proto
@@ -35,6 +35,7 @@ message Repo { // `autogenpb:marshal` `autogenpb:2nomutex`
repeated string dirtyList = 22; // store the list from git status --porcelain
string state = 23; // status or state. useful for building tooling
GitTag currentTag = 24; // used to examine repo branches
+ GitConfig gitConfig = 25; // protobuf of the current .git/config
}
message Repos { // `autogenpb:marshal` `autogenpb:sort` `autogenpb:2nomutex`
@@ -54,6 +55,7 @@ message GitTimes { // `autogenpb:2nomutex`
google.protobuf.Timestamp mtimeFetch = 7; // mtime for ./git/FETCH_HEAD // last time 'git fetch' or 'git pull' was run on current branch?
google.protobuf.Timestamp lastGoDep = 8; // mtime for last go.sum scan
google.protobuf.Timestamp newestCommit = 9; // when the newest commit was
+ google.protobuf.Timestamp mtimeConfig = 10; // mtime for the .git/config file
}
// this is probably better. think about moving to this instead