Skip to content

Commit

Permalink
Merge pull request #141 from motemen/refactor-local-repo
Browse files Browse the repository at this point in the history
Streamline VCS detection for local repositories
  • Loading branch information
Songmu committed Apr 30, 2019
2 parents 7d74fb3 + e05bf96 commit 0f76c2e
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 68 deletions.
6 changes: 4 additions & 2 deletions commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func withFakeGitBackend(t *testing.T, block func(string, *_cloneArgs, *_updateAr
var updateArgs _updateArgs

var originalGitBackend = GitBackend
GitBackend = &VCSBackend{
tmpBackend := &VCSBackend{
Clone: func(remote *url.URL, local string, shallow, silent bool) error {
cloneArgs = _cloneArgs{
remote: remote,
Expand All @@ -138,7 +138,9 @@ func withFakeGitBackend(t *testing.T, block func(string, *_cloneArgs, *_updateAr
return nil
},
}
defer func() { GitBackend = originalGitBackend }()
GitBackend = tmpBackend
vcsDirsMap[".git"] = tmpBackend
defer func() { GitBackend = originalGitBackend; vcsDirsMap[".git"] = originalGitBackend }()

block(tmpRoot, &cloneArgs, &updateArgs)
}
Expand Down
108 changes: 44 additions & 64 deletions local_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ import (
"os"
"path"
"path/filepath"
"sort"
"strings"
)

type LocalRepository struct {
FullPath string
RelPath string
PathParts []string

vcsBackend *VCSBackend
}

func LocalRepositoryFromFullPath(fullPath string) (*LocalRepository, error) {
func LocalRepositoryFromFullPath(fullPath string, backend *VCSBackend) (*LocalRepository, error) {
var relPath string

roots, err := localRepositoryRoots()
Expand All @@ -41,9 +44,10 @@ func LocalRepositoryFromFullPath(fullPath string) (*LocalRepository, error) {
pathParts := strings.Split(relPath, string(filepath.Separator))

return &LocalRepository{
FullPath: fullPath,
RelPath: filepath.ToSlash(relPath),
PathParts: pathParts,
FullPath: fullPath,
RelPath: filepath.ToSlash(relPath),
PathParts: pathParts,
vcsBackend: backend,
}, nil
}

Expand Down Expand Up @@ -115,76 +119,61 @@ func (repo *LocalRepository) Matches(pathQuery string) bool {
return false
}

// TODO return err
func (repo *LocalRepository) VCS() *VCSBackend {
var (
fi os.FileInfo
err error
)

fi, err = os.Stat(filepath.Join(repo.FullPath, ".git/svn"))
if err == nil && fi.IsDir() {
return GitsvnBackend
}

fi, err = os.Stat(filepath.Join(repo.FullPath, ".git"))
if err == nil && fi.IsDir() {
return GitBackend
}

fi, err = os.Stat(filepath.Join(repo.FullPath, ".svn"))
if err == nil && fi.IsDir() {
return SubversionBackend
}

fi, err = os.Stat(filepath.Join(repo.FullPath, ".hg"))
if err == nil && fi.IsDir() {
return MercurialBackend
}

fi, err = os.Stat(filepath.Join(repo.FullPath, "_darcs"))
if err == nil && fi.IsDir() {
return DarcsBackend
if repo.vcsBackend == nil {
repo.vcsBackend = findVCSBackend(repo.FullPath)
}
return repo.vcsBackend
}

fi, err = os.Stat(filepath.Join(repo.FullPath, ".fslckout"))
if err == nil && fi.IsDir() {
return FossilBackend
}
var vcsDirsMap = map[string]*VCSBackend{
".git/svn": GitsvnBackend,
".git": GitBackend,
".svn": SubversionBackend,
".hg": MercurialBackend,
"_darcs": DarcsBackend,
".fslckout": FossilBackend,
"_FOSSIL_": FossilBackend,
"CVS": cvsDummyBackend,
".bzr": BazaarBackend,
}

fi, err = os.Stat(filepath.Join(repo.FullPath, "_FOSSIL_"))
if err == nil && fi.IsDir() {
return FossilBackend
}
var vcsDirs = make([]string, 0, len(vcsDirsMap))

fi, err = os.Stat(filepath.Join(repo.FullPath, "CVS"))
if err == nil && fi.IsDir() {
return cvsDummyBackend
func init() {
for k := range vcsDirsMap {
vcsDirs = append(vcsDirs, k)
}
// Sort in order of length.
// This is to check git/svn before git.
sort.Slice(vcsDirs, func(i, j int) bool {
return len(vcsDirs[i]) > len(vcsDirs[j])
})
}

fi, err = os.Stat(filepath.Join(repo.FullPath, ".bzr"))
if err == nil && fi.IsDir() {
return BazaarBackend
func findVCSBackend(fpath string) *VCSBackend {
for _, d := range vcsDirs {
fi, err := os.Stat(filepath.Join(fpath, d))
if err == nil && fi.IsDir() {
return vcsDirsMap[d]
}
}

return nil
}

var vcsDirs = []string{".git", ".svn", ".hg", "_darcs", ".fslckout", "_FOSSIL_", "CVS", ".bzr"}

func walkLocalRepositories(callback func(*LocalRepository)) error {
roots, err := localRepositoryRoots()
if err != nil {
return err
}
for _, root := range roots {
if err := filepath.Walk(root, func(path string, fileInfo os.FileInfo, err error) error {
if err := filepath.Walk(root, func(fpath string, fileInfo os.FileInfo, err error) error {
if err != nil || fileInfo == nil {
return nil
}

if fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink {
realpath, err := filepath.EvalSymlinks(path)
realpath, err := filepath.EvalSymlinks(fpath)
if err != nil {
return nil
}
Expand All @@ -196,21 +185,12 @@ func walkLocalRepositories(callback func(*LocalRepository)) error {
if !fileInfo.IsDir() {
return nil
}

vcsDirFound := false
for _, d := range vcsDirs {
_, err := os.Stat(filepath.Join(path, d))
if err == nil {
vcsDirFound = true
break
}
}

if !vcsDirFound {
vcsBackend := findVCSBackend(fpath)
if vcsBackend == nil {
return nil
}

repo, err := LocalRepositoryFromFullPath(path)
repo, err := LocalRepositoryFromFullPath(fpath, vcsBackend)
if err != nil {
return nil
}
Expand Down
4 changes: 2 additions & 2 deletions local_repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ func TestNewLocalRepository(t *testing.T) {

_localRepositoryRoots = []string{"/repos"}

r, err := LocalRepositoryFromFullPath("/repos/github.com/motemen/ghq")
r, err := LocalRepositoryFromFullPath("/repos/github.com/motemen/ghq", nil)
Expect(err).To(BeNil())
Expect(r.NonHostPath()).To(Equal("motemen/ghq"))
Expect(r.Subpaths()).To(Equal([]string{"ghq", "motemen/ghq", "github.com/motemen/ghq"}))

r, err = LocalRepositoryFromFullPath("/repos/stash.com/scm/motemen/ghq")
r, err = LocalRepositoryFromFullPath("/repos/stash.com/scm/motemen/ghq", nil)
Expect(err).To(BeNil())
Expect(r.NonHostPath()).To(Equal("scm/motemen/ghq"))
Expect(r.Subpaths()).To(Equal([]string{"ghq", "motemen/ghq", "scm/motemen/ghq", "stash.com/scm/motemen/ghq"}))
Expand Down

0 comments on commit 0f76c2e

Please sign in to comment.