From 28115d8776a952d9a0c32cf639cdffb2eff19ca2 Mon Sep 17 00:00:00 2001 From: Stefan Majewsky Date: Fri, 6 Oct 2017 22:35:24 +0200 Subject: fix handling of Git submodules --- pkg/prompt/git.go | 58 +++++++++++++++++++++++++++++++++++++++++++----------- pkg/prompt/main.go | 2 +- pkg/prompt/pwd.go | 10 ++++++---- 3 files changed, 53 insertions(+), 17 deletions(-) diff --git a/pkg/prompt/git.go b/pkg/prompt/git.go index 054df36..144beb5 100644 --- a/pkg/prompt/git.go +++ b/pkg/prompt/git.go @@ -19,30 +19,64 @@ package prompt import ( + "fmt" "io/ioutil" "os" "path/filepath" "strings" ) -//Returns empty string if `path` is not inside a Git repo. -func findRepoRootPath(path string) string { - _, err := os.Stat(filepath.Join(path, ".git")) - if err == nil { - return path +type gitRepo struct { + RootPath string + GitDir string +} + +//Returns two empty strings if `path` is not inside a Git repo. +func findRepo(path string) (*gitRepo, error) { + //find .git directory or file + gitEntry := filepath.Join(path, ".git") + fi, err := os.Stat(gitEntry) + switch { + case err == nil: + //found - continue below with further checks + case !os.IsNotExist(err): + return nil, err + case path == "/": + return nil, nil + default: + return findRepo(filepath.Dir(path)) } - if path == "/" { - return "" + + //found .git - what is it? + if fi.Mode().IsDir() { + //normal case - .git is a directory + return &gitRepo{RootPath: path, GitDir: gitEntry}, nil + } + + //.git is a file (e.g. for submodules) - it contains a line like "gitdir: path/to/gitdir" + bytes, err := ioutil.ReadFile(gitEntry) + if err != nil { + return nil, err } - return findRepoRootPath(filepath.Dir(path)) + for _, line := range strings.Split(string(bytes), "\n") { + line = strings.TrimSpace(line) + if strings.HasPrefix(line, "gitdir:") { + return &gitRepo{ + RootPath: path, + GitDir: filepath.Join(path, strings.TrimSpace(strings.TrimPrefix(line, "gitdir:"))), + }, nil + } + } + + return nil, fmt.Errorf("read %s: missing gitdir directive", gitEntry) } -func getRepoStatusField(repoRootPath string) string { - if repoRootPath == "" { +func getRepoStatusField(repo *gitRepo) string { + if repo == nil { return "" } - bytes, err := ioutil.ReadFile(filepath.Join(repoRootPath, ".git/HEAD")) + bytes, err := ioutil.ReadFile(filepath.Join(repo.GitDir, "HEAD")) if err != nil { handleError(err) return withType("git", withColor("1;41", "unknown")) @@ -60,7 +94,7 @@ func getRepoStatusField(repoRootPath string) string { refSpecDisplay = strings.TrimPrefix(refSpecDisplay, "heads/") //read file corresponding to refspec to find commit - bytes, err = ioutil.ReadFile(filepath.Join(repoRootPath, ".git", refSpec)) + bytes, err = ioutil.ReadFile(filepath.Join(repo.GitDir, refSpec)) commitID := strings.TrimSpace(string(bytes)) if err != nil { if os.IsNotExist(err) { diff --git a/pkg/prompt/main.go b/pkg/prompt/main.go index 1dcbbc7..1fc60d9 100644 --- a/pkg/prompt/main.go +++ b/pkg/prompt/main.go @@ -37,7 +37,7 @@ func Exec(args []string) int { cwd := CurrentDirectory() fields = appendUnlessEmpty(fields, getDirectoryField(cwd)) fields = appendUnlessEmpty(fields, getDeletedMessageField(cwd)) - fields = appendUnlessEmpty(fields, getRepoStatusField(cwd.RepoRootPath)) + fields = appendUnlessEmpty(fields, getRepoStatusField(cwd.Repo)) fields = appendUnlessEmpty(fields, getTerminalField()) fields = appendUnlessEmpty(fields, getOpenstackField()) fields = appendUnlessEmpty(fields, getKubernetesField()) diff --git a/pkg/prompt/pwd.go b/pkg/prompt/pwd.go index 969a8ce..1b93987 100644 --- a/pkg/prompt/pwd.go +++ b/pkg/prompt/pwd.go @@ -30,7 +30,7 @@ type Directory struct { DisplayPath string InBuildTree bool InRepoTree bool - RepoRootPath string + Repo *gitRepo NearestAccessiblePath string } @@ -78,7 +78,9 @@ func NewDirectory(path string) (dir Directory) { dir.stripHomeDirFromDisplay() //check if we are inside a Git repository - dir.RepoRootPath = findRepoRootPath(dir.Path) + var err error + dir.Repo, err = findRepo(dir.Path) + handleError(err) } return @@ -124,8 +126,8 @@ func getDirectoryField(dir Directory) string { txt := withColor("1;36", dir.DisplayPath) if dir.NearestAccessiblePath == "" { //cwd accessible -> highlight path elements inside the repo (if any) - if dir.RepoRootPath != "" && dir.RepoRootPath != dir.Path { - rel, _ := filepath.Rel(dir.RepoRootPath, dir.Path) + if dir.Repo != nil && dir.Repo.RootPath != dir.Path { + rel, _ := filepath.Rel(dir.Repo.RootPath, dir.Path) if strings.HasSuffix(dir.DisplayPath, rel) { base := strings.TrimSuffix(dir.DisplayPath, rel) txt = withColor("0;36", base) + withColor("1;36", rel) -- cgit v1.3.1