parse .git/config
This commit is contained in:
parent
80f602c4d9
commit
0c30a9da2f
19
gitTag.proto
19
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -135,7 +135,13 @@ func (repo *Repo) NewestTag() *GitTag {
|
|||
return nil
|
||||
}
|
||||
|
||||
// this should just do is.Exists(".git/refs/heads/findname")
|
||||
func (repo *Repo) LocalTagExists(findname string) bool {
|
||||
fname := filepath.Join(".git/refs/heads", findname)
|
||||
if repo.Exists(fname) {
|
||||
return true
|
||||
}
|
||||
/*
|
||||
loop := repo.Tags.SortByRefname()
|
||||
for loop.Scan() {
|
||||
ref := loop.Next()
|
||||
|
@ -143,13 +149,14 @@ func (repo *Repo) LocalTagExists(findname string) bool {
|
|||
if strings.HasPrefix(ref.Refname, "refs/remotes") {
|
||||
continue
|
||||
}
|
||||
_, tagname := filepath.Split(ref.Refname)
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue