Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit c4ace4d

Browse files
authored
Merge pull request #784 from mvdan/open-detect
add PlainOpen variant to find .git in parent dirs
2 parents 247cf69 + 5e8e011 commit c4ace4d

File tree

3 files changed

+73
-6
lines changed

3 files changed

+73
-6
lines changed

options.go

+11
Original file line numberDiff line numberDiff line change
@@ -420,3 +420,14 @@ func (o *GrepOptions) Validate(w *Worktree) error {
420420

421421
return nil
422422
}
423+
424+
// PlainOpenOptions describes how opening a plain repository should be
425+
// performed.
426+
type PlainOpenOptions struct {
427+
// DetectDotGit defines whether parent directories should be
428+
// walked until a .git directory or file is found.
429+
DetectDotGit bool
430+
}
431+
432+
// Validate validates the fields and sets the default values.
433+
func (o *PlainOpenOptions) Validate() error { return nil }

repository.go

+32-6
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,14 @@ func PlainInit(path string, isBare bool) (*Repository, error) {
225225
// repository is bare or a normal one. If the path doesn't contain a valid
226226
// repository ErrRepositoryNotExists is returned
227227
func PlainOpen(path string) (*Repository, error) {
228-
dot, wt, err := dotGitToOSFilesystems(path)
228+
return PlainOpenWithOptions(path, &PlainOpenOptions{})
229+
}
230+
231+
// PlainOpen opens a git repository from the given path. It detects if the
232+
// repository is bare or a normal one. If the path doesn't contain a valid
233+
// repository ErrRepositoryNotExists is returned
234+
func PlainOpenWithOptions(path string, o *PlainOpenOptions) (*Repository, error) {
235+
dot, wt, err := dotGitToOSFilesystems(path, o.DetectDotGit)
229236
if err != nil {
230237
return nil, err
231238
}
@@ -246,14 +253,33 @@ func PlainOpen(path string) (*Repository, error) {
246253
return Open(s, wt)
247254
}
248255

249-
func dotGitToOSFilesystems(path string) (dot, wt billy.Filesystem, err error) {
250-
fs := osfs.New(path)
251-
fi, err := fs.Stat(".git")
252-
if err != nil {
256+
func dotGitToOSFilesystems(path string, detect bool) (dot, wt billy.Filesystem, err error) {
257+
if path, err = filepath.Abs(path); err != nil {
258+
return nil, nil, err
259+
}
260+
var fs billy.Filesystem
261+
var fi os.FileInfo
262+
for {
263+
fs = osfs.New(path)
264+
fi, err = fs.Stat(".git")
265+
if err == nil {
266+
// no error; stop
267+
break
268+
}
253269
if !os.IsNotExist(err) {
270+
// unknown error; stop
254271
return nil, nil, err
255272
}
256-
273+
if detect {
274+
// try its parent as long as we haven't reached
275+
// the root dir
276+
if dir := filepath.Dir(path); dir != path {
277+
path = dir
278+
continue
279+
}
280+
}
281+
// not detecting via parent dirs and the dir does not exist;
282+
// stop
257283
return fs, nil, nil
258284
}
259285

repository_test.go

+30
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,36 @@ func (s *RepositorySuite) TestPlainOpenNotExists(c *C) {
407407
c.Assert(r, IsNil)
408408
}
409409

410+
func (s *RepositorySuite) TestPlainOpenDetectDotGit(c *C) {
411+
dir, err := ioutil.TempDir("", "plain-open")
412+
c.Assert(err, IsNil)
413+
defer os.RemoveAll(dir)
414+
415+
subdir := filepath.Join(dir, "a", "b")
416+
err = os.MkdirAll(subdir, 0755)
417+
c.Assert(err, IsNil)
418+
419+
r, err := PlainInit(dir, false)
420+
c.Assert(err, IsNil)
421+
c.Assert(r, NotNil)
422+
423+
opt := &PlainOpenOptions{DetectDotGit: true}
424+
r, err = PlainOpenWithOptions(subdir, opt)
425+
c.Assert(err, IsNil)
426+
c.Assert(r, NotNil)
427+
}
428+
429+
func (s *RepositorySuite) TestPlainOpenNotExistsDetectDotGit(c *C) {
430+
dir, err := ioutil.TempDir("", "plain-open")
431+
c.Assert(err, IsNil)
432+
defer os.RemoveAll(dir)
433+
434+
opt := &PlainOpenOptions{DetectDotGit: true}
435+
r, err := PlainOpenWithOptions(dir, opt)
436+
c.Assert(err, Equals, ErrRepositoryNotExists)
437+
c.Assert(r, IsNil)
438+
}
439+
410440
func (s *RepositorySuite) TestPlainClone(c *C) {
411441
r, err := PlainClone(c.MkDir(), false, &CloneOptions{
412442
URL: s.GetBasicLocalRepositoryURL(),

0 commit comments

Comments
 (0)