diff options
author | Michael Muré <batolettre@gmail.com> | 2023-03-04 13:27:59 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-04 13:27:59 +0100 |
commit | a1015493875963d75b3ca24caa31a2b65203309e (patch) | |
tree | 8bbd475ca6795ac0cd25f88a51b609a198247eb0 | |
parent | e1899b671e7db6e70644747ae61045b9641ddea0 (diff) | |
parent | 27c96a4044f05a338d6ac6187135e6b9ac487e9f (diff) | |
download | git-bug-a1015493875963d75b3ca24caa31a2b65203309e.tar.gz |
Merge pull request #1004 from Kintar/fix-971-submodule-processing
fix(#971): parse submodule .git files instead of erroring
-rw-r--r-- | repository/gogit.go | 37 | ||||
-rw-r--r-- | repository/gogit_test.go | 15 |
2 files changed, 49 insertions, 3 deletions
diff --git a/repository/gogit.go b/repository/gogit.go index 93806026..96d62665 100644 --- a/repository/gogit.go +++ b/repository/gogit.go @@ -1,9 +1,11 @@ package repository import ( + "bufio" "bytes" "errors" "fmt" + "io" "io/ioutil" "os" "path/filepath" @@ -55,7 +57,7 @@ type GoGitRepo struct { // of "~/myrepo" and a namespace of "git-bug", local storage for the // GoGitRepo will be configured at "~/myrepo/.git/git-bug". func OpenGoGitRepo(path, namespace string, clockLoaders []ClockLoader) (*GoGitRepo, error) { - path, err := detectGitPath(path) + path, err := detectGitPath(path, 0) if err != nil { return nil, err } @@ -159,7 +161,11 @@ func InitBareGoGitRepo(path, namespace string) (*GoGitRepo, error) { }, nil } -func detectGitPath(path string) (string, error) { +func detectGitPath(path string, depth int) (string, error) { + if depth >= 10 { + return "", fmt.Errorf("gitdir loop detected") + } + // normalize the path path, err := filepath.Abs(path) if err != nil { @@ -170,7 +176,32 @@ func detectGitPath(path string) (string, error) { fi, err := os.Stat(filepath.Join(path, ".git")) if err == nil { if !fi.IsDir() { - return "", fmt.Errorf(".git exist but is not a directory") + // See if our .git item is a dotfile that holds a submodule reference + dotfile, err := os.Open(filepath.Join(path, fi.Name())) + if err != nil { + // Can't open error + return "", fmt.Errorf(".git exists but is not a directory or a readable file: %w", err) + } + // We aren't going to defer the dotfile.Close, because we might keep looping, so we have to be sure to + // clean up before returning an error + reader := bufio.NewReader(io.LimitReader(dotfile, 2048)) + line, _, err := reader.ReadLine() + _ = dotfile.Close() + if err != nil { + return "", fmt.Errorf(".git exists but is not a directory and cannot be read: %w", err) + } + dotContent := string(line) + if strings.HasPrefix(dotContent, "gitdir:") { + // This is a submodule parent path link. Strip the prefix, clean the string of whitespace just to + // be safe, and return + dotContent = strings.TrimSpace(strings.TrimPrefix(dotContent, "gitdir: ")) + p, err := detectGitPath(dotContent, depth+1) + if err != nil { + return "", fmt.Errorf(".git gitdir error: %w", err) + } + return p, nil + } + return "", fmt.Errorf(".git exist but is not a directory or module/workspace file") } return filepath.Join(path, ".git"), nil } diff --git a/repository/gogit_test.go b/repository/gogit_test.go index 02bd42fd..21acd5df 100644 --- a/repository/gogit_test.go +++ b/repository/gogit_test.go @@ -1,6 +1,8 @@ package repository import ( + "fmt" + "os" "path" "path/filepath" "testing" @@ -81,3 +83,16 @@ func TestGoGitRepo_Indexes(t *testing.T) { require.NoError(t, err) require.NotZero(t, indexA) } + +func TestGoGit_DetectsSubmodules(t *testing.T) { + repo := CreateGoGitTestRepo(t, false) + expected := filepath.Join(goGitRepoDir(t, repo), "/.git") + + d := t.TempDir() + err := os.WriteFile(filepath.Join(d, ".git"), []byte(fmt.Sprintf("gitdir: %s", expected)), 0600) + require.NoError(t, err) + + result, err := detectGitPath(d, 0) + assert.Empty(t, err) + assert.Equal(t, expected, result) +} |