diff options
author | Máximo Cuadros <mcuadros@gmail.com> | 2017-04-27 14:14:28 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-27 14:14:28 +0200 |
commit | bc6b1c429f5a6f4d78a17cbe0e1a9927416f4f1b (patch) | |
tree | 9cbb03df820bf0f7f303ffe9c02d4895ef3d1851 | |
parent | 026ce1b2cff0aae82b7f8d4f4413e2479479ea37 (diff) | |
parent | 4060f60af044ce085a097e12bf19cb3fdd123076 (diff) | |
download | go-git-bc6b1c429f5a6f4d78a17cbe0e1a9927416f4f1b.tar.gz |
Merge pull request #363 from smola/dotgit-file
add support for .git as file, fixes #348
-rw-r--r-- | repository.go | 64 | ||||
-rw-r--r-- | repository_test.go | 87 |
2 files changed, 142 insertions, 9 deletions
diff --git a/repository.go b/repository.go index bb59afe..8a7b348 100644 --- a/repository.go +++ b/repository.go @@ -3,8 +3,10 @@ package git import ( "errors" "fmt" + stdioutil "io/ioutil" "os" "path/filepath" + "strings" "gopkg.in/src-d/go-git.v4/config" "gopkg.in/src-d/go-git.v4/internal/revision" @@ -13,6 +15,7 @@ import ( "gopkg.in/src-d/go-git.v4/plumbing/storer" "gopkg.in/src-d/go-git.v4/storage" "gopkg.in/src-d/go-git.v4/storage/filesystem" + "gopkg.in/src-d/go-git.v4/utils/ioutil" "gopkg.in/src-d/go-billy.v2" "gopkg.in/src-d/go-billy.v2/osfs" @@ -193,26 +196,69 @@ func PlainInit(path string, isBare bool) (*Repository, error) { // repository is bare or a normal one. If the path doesn't contain a valid // repository ErrRepositoryNotExists is returned func PlainOpen(path string) (*Repository, error) { - var wt, dot billy.Filesystem + dot, wt, err := dotGitToFilesystems(path) + if err != nil { + return nil, err + } + + s, err := filesystem.NewStorage(dot) + if err != nil { + return nil, err + } + return Open(s, wt) +} + +func dotGitToFilesystems(path string) (dot, wt billy.Filesystem, err error) { fs := osfs.New(path) - if _, err := fs.Stat(".git"); err != nil { + fi, err := fs.Stat(".git") + if err != nil { if !os.IsNotExist(err) { - return nil, err + return nil, nil, err } - dot = fs - } else { - wt = fs - dot = fs.Dir(".git") + return fs, nil, nil } - s, err := filesystem.NewStorage(dot) + if fi.IsDir() { + return fs.Dir(".git"), fs, nil + } + + dot, err = dotGitFileToFilesystem(fs) + if err != nil { + return nil, nil, err + } + + return dot, fs, nil +} + +func dotGitFileToFilesystem(fs billy.Filesystem) (billy.Filesystem, error) { + var err error + + f, err := fs.Open(".git") if err != nil { return nil, err } + defer ioutil.CheckClose(f, &err) - return Open(s, wt) + b, err := stdioutil.ReadAll(f) + if err != nil { + return nil, err + } + + line := string(b) + const prefix = "gitdir: " + if !strings.HasPrefix(line, prefix) { + return nil, fmt.Errorf(".git file has no %s prefix", prefix) + } + + gitdir := line[len(prefix):] + gitdir = strings.TrimSpace(gitdir) + if filepath.IsAbs(gitdir) { + return osfs.New(gitdir), nil + } + + return fs.Dir(gitdir), err } // PlainClone a repository into the path with the given options, isBare defines diff --git a/repository_test.go b/repository_test.go index 77bfde2..fd8d405 100644 --- a/repository_test.go +++ b/repository_test.go @@ -272,6 +272,93 @@ func (s *RepositorySuite) TestPlainOpenNotBare(c *C) { c.Assert(r, IsNil) } +func (s *RepositorySuite) testPlainOpenGitFile(c *C, f func(string, string) string) { + dir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, err := PlainInit(dir, true) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + altDir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + defer os.RemoveAll(altDir) + + err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(f(dir, altDir)), 0644) + c.Assert(err, IsNil) + + r, err = PlainOpen(altDir) + c.Assert(err, IsNil) + c.Assert(r, NotNil) +} + +func (s *RepositorySuite) TestPlainOpenBareAbsoluteGitDirFile(c *C) { + s.testPlainOpenGitFile(c, func(dir, altDir string) string { + return fmt.Sprintf("gitdir: %s\n", dir) + }) +} + +func (s *RepositorySuite) TestPlainOpenBareAbsoluteGitDirFileNoEOL(c *C) { + s.testPlainOpenGitFile(c, func(dir, altDir string) string { + return fmt.Sprintf("gitdir: %s", dir) + }) +} + +func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFile(c *C) { + s.testPlainOpenGitFile(c, func(dir, altDir string) string { + dir, err := filepath.Rel(altDir, dir) + c.Assert(err, IsNil) + return fmt.Sprintf("gitdir: %s\n", dir) + }) +} + +func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileNoEOL(c *C) { + s.testPlainOpenGitFile(c, func(dir, altDir string) string { + dir, err := filepath.Rel(altDir, dir) + c.Assert(err, IsNil) + return fmt.Sprintf("gitdir: %s\n", dir) + }) +} + +func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileTrailingGarbage(c *C) { + dir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, err := PlainInit(dir, true) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + altDir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(fmt.Sprintf("gitdir: %s\nTRAILING", dir)), 0644) + c.Assert(err, IsNil) + + r, err = PlainOpen(altDir) + c.Assert(err, Equals, ErrRepositoryNotExists) + c.Assert(r, IsNil) +} + +func (s *RepositorySuite) TestPlainOpenBareRelativeGitDirFileBadPrefix(c *C) { + dir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + defer os.RemoveAll(dir) + + r, err := PlainInit(dir, true) + c.Assert(err, IsNil) + c.Assert(r, NotNil) + + altDir, err := ioutil.TempDir("", "plain-open") + c.Assert(err, IsNil) + err = ioutil.WriteFile(filepath.Join(altDir, ".git"), []byte(fmt.Sprintf("xgitdir: %s\n", dir)), 0644) + c.Assert(err, IsNil) + + r, err = PlainOpen(altDir) + c.Assert(err, ErrorMatches, ".*gitdir.*") + c.Assert(r, IsNil) +} + func (s *RepositorySuite) TestPlainOpenNotExists(c *C) { r, err := PlainOpen("/not-exists/") c.Assert(err, Equals, ErrRepositoryNotExists) |