Use pkg.in/src-d/go-git.v4/ for Git indexing
This library is written in pure Go, so:
* it simplifies compilation and deployment
* no more memory leaks due forgotten Free() calls
* potential for lower memory use in large superprojects, since
Repository objects don't have to be Free()d individually.
This comes at the cost of a 30% end-to-end slowdown indexing the
Gerrit repo.
Change-Id: Id0e51e5cf9e6bc4cfe1bdbff0adb381a3814fab8
diff --git a/cmd/zoekt-git-index/main.go b/cmd/zoekt-git-index/main.go
index 09fb3ea..02127a3 100644
--- a/cmd/zoekt-git-index/main.go
+++ b/cmd/zoekt-git-index/main.go
@@ -67,9 +67,6 @@
gitRepos := map[string]string{}
for _, repoDir := range flag.Args() {
- if _, err := os.Lstat(filepath.Join(repoDir, ".git")); err == nil {
- repoDir = filepath.Join(repoDir, ".git")
- }
repoDir, err := filepath.Abs(repoDir)
if err != nil {
log.Fatal(err)
diff --git a/cmd/zoekt-repo-index/main.go b/cmd/zoekt-repo-index/main.go
index 71a3010..95dd5c1 100644
--- a/cmd/zoekt-repo-index/main.go
+++ b/cmd/zoekt-repo-index/main.go
@@ -32,6 +32,7 @@
"crypto/sha1"
"flag"
"fmt"
+ "io/ioutil"
"log"
"net/url"
"path"
@@ -44,7 +45,9 @@
"github.com/google/zoekt"
"github.com/google/zoekt/build"
"github.com/google/zoekt/gitindex"
- git "github.com/libgit2/git2go"
+
+ git "gopkg.in/src-d/go-git.v4"
+ "gopkg.in/src-d/go-git.v4/plumbing"
)
var _ = log.Println
@@ -67,6 +70,7 @@
if err != nil {
return nil, err
}
+
for _, f := range args {
fs := strings.SplitN(f, ":", 2)
if len(fs) != 2 {
@@ -81,7 +85,7 @@
branch: fs[0],
file: fs[1],
mf: mf,
- manifestPath: repo.Path(),
+ manifestPath: cache.Path(u),
})
}
} else {
@@ -169,7 +173,7 @@
opts.SubRepositories = map[string]*zoekt.Repository{}
// branch => repo => version
- versionMap := map[string]map[string]git.Oid{}
+ versionMap := map[string]map[string]plumbing.Hash{}
for _, br := range branches {
br.mf.Filter()
files, versions, err := iterateManifest(br.mf, *baseURL, *revPrefix, repoCache)
@@ -276,24 +280,46 @@
// getManifest parses the manifest XML at the given branch/path inside a Git repository.
func getManifest(repo *git.Repository, branch, path string) (*manifest.Manifest, error) {
- obj, err := repo.RevparseSingle(branch + ":" + path)
+ ref, err := repo.Reference(plumbing.ReferenceName("refs/heads/"+branch), true)
if err != nil {
return nil, err
}
- defer obj.Free()
- blob, err := obj.AsBlob()
+
+ commit, err := repo.CommitObject(ref.Hash())
if err != nil {
return nil, err
}
- return manifest.Parse(blob.Contents())
+
+ tree, err := repo.TreeObject(commit.TreeHash)
+ if err != nil {
+ return nil, err
+ }
+
+ entry, err := tree.FindEntry(path)
+ if err != nil {
+ return nil, err
+ }
+
+ blob, err := repo.BlobObject(entry.Hash)
+ if err != nil {
+ return nil, err
+ }
+ r, err := blob.Reader()
+ if err != nil {
+ return nil, err
+ }
+ defer r.Close()
+
+ content, err := ioutil.ReadAll(r)
+ return manifest.Parse(content)
}
// iterateManifest constructs a complete tree from the given Manifest.
func iterateManifest(mf *manifest.Manifest,
baseURL url.URL, revPrefix string,
- cache *gitindex.RepoCache) (map[gitindex.FileKey]gitindex.BlobLocation, map[string]git.Oid, error) {
+ cache *gitindex.RepoCache) (map[gitindex.FileKey]gitindex.BlobLocation, map[string]plumbing.Hash, error) {
allFiles := map[gitindex.FileKey]gitindex.BlobLocation{}
- allVersions := map[string]git.Oid{}
+ allVersions := map[string]plumbing.Hash{}
for _, p := range mf.Project {
rev := mf.ProjectRevision(&p)
@@ -305,24 +331,25 @@
return nil, nil, err
}
- obj, err := topRepo.RevparseSingle(revPrefix + rev)
- if err != nil {
- return nil, nil, err
- }
- defer obj.Free()
-
- commit, err := obj.AsCommit()
+ ref, err := topRepo.Reference(plumbing.ReferenceName(revPrefix+rev), true)
if err != nil {
return nil, nil, err
}
- allVersions[p.GetPath()] = *commit.Id()
+ commit, err := topRepo.CommitObject(ref.Hash())
+ if err != nil {
+ return nil, nil, err
+ }
+ if err != nil {
+ return nil, nil, err
+ }
+
+ allVersions[p.GetPath()] = commit.Hash
tree, err := commit.Tree()
if err != nil {
return nil, nil, err
}
- defer tree.Free()
files, versions, err := gitindex.TreeToFiles(topRepo, tree, projURL.String(), cache)
if err != nil {
diff --git a/gitindex/cache.go b/gitindex/cache.go
index 25e9ed5..0d150d0 100644
--- a/gitindex/cache.go
+++ b/gitindex/cache.go
@@ -20,7 +20,7 @@
"strings"
"sync"
- "github.com/libgit2/git2go"
+ git "gopkg.in/src-d/go-git.v4"
)
type RepoCache struct {
@@ -40,9 +40,6 @@
func (rc *RepoCache) Close() {
rc.reposMu.Lock()
defer rc.reposMu.Unlock()
- for _, v := range rc.repos {
- v.Free()
- }
}
func repoKey(u *url.URL) string {
@@ -59,21 +56,26 @@
return filepath.Join(baseDir, key)
}
+func (rc *RepoCache) Path(u *url.URL) string {
+ key := repoKey(u)
+ return filepath.Join(rc.baseDir, key)
+}
+
// Open opens a git repository. The cache retains a pointer to the
// repository, so it cannot be freed.
func (rc *RepoCache) Open(u *url.URL) (*git.Repository, error) {
- key := repoKey(u)
- dir := filepath.Join(rc.baseDir, key)
+ dir := rc.Path(u)
rc.reposMu.Lock()
defer rc.reposMu.Unlock()
+ key := repoKey(u)
r := rc.repos[key]
if r != nil {
return r, nil
}
- repo, err := git.OpenRepository(dir)
+ repo, err := git.PlainOpen(dir)
if err == nil {
rc.repos[key] = repo
}
diff --git a/gitindex/git.go b/gitindex/git.go
index a09086c..c856028 100644
--- a/gitindex/git.go
+++ b/gitindex/git.go
@@ -16,6 +16,8 @@
import (
"fmt"
+ "io"
+ "io/ioutil"
"log"
"net/url"
"os"
@@ -28,7 +30,11 @@
"github.com/google/zoekt"
"github.com/google/zoekt/build"
- git "github.com/libgit2/git2go"
+ "gopkg.in/src-d/go-git.v4/config"
+ "gopkg.in/src-d/go-git.v4/plumbing"
+ "gopkg.in/src-d/go-git.v4/plumbing/object"
+
+ git "gopkg.in/src-d/go-git.v4"
)
// RepoModTime returns the time of last fetch of a git repository.
@@ -129,55 +135,64 @@
}
// getCommit returns a tree object for the given reference.
-func getCommit(repo *git.Repository, ref string) (*git.Commit, error) {
- obj, err := repo.RevparseSingle(ref)
+func getCommit(repo *git.Repository, ref string) (*object.Commit, error) {
+ sha1, err := repo.ResolveRevision(plumbing.Revision(ref))
if err != nil {
return nil, err
}
- defer obj.Free()
- commitObj, err := obj.Peel(git.ObjectCommit)
+ commitObj, err := repo.CommitObject(*sha1)
if err != nil {
return nil, err
}
- return commitObj.AsCommit()
+ return commitObj, nil
}
-func clearEmptyConfig(err error) error {
- if git.IsErrorClass(err, git.ErrClassConfig) && git.IsErrorCode(err, git.ErrNotFound) {
- return nil
+func configLookupRemoteURL(cfg *config.Config, key string) string {
+ rc := cfg.Remotes[key]
+ if rc == nil || len(rc.URLs) == 0 {
+ return ""
}
- return err
+ return rc.URLs[0]
+}
+
+func configLookupString(cfg *config.Config, key string) string {
+ fields := strings.Split(key, ".")
+ for _, s := range cfg.Raw.Sections {
+ if s.Name != fields[0] {
+ continue
+ }
+
+ for _, o := range s.Options {
+ if o.Key != fields[1] {
+ continue
+ }
+ return o.Value
+ }
+ }
+
+ return ""
}
func isMissingBranchError(err error) bool {
- return git.IsErrorClass(err, git.ErrClassReference) && git.IsErrorCode(err, git.ErrNotFound)
+ return err != nil && err.Error() == "reference not found"
}
func setTemplatesFromConfig(desc *zoekt.Repository, repoDir string) error {
- base, err := git.NewConfig()
- if err != nil {
- return err
- }
- defer base.Free()
- cfg, err := git.OpenOndisk(base, filepath.Join(repoDir, "config"))
- if err != nil {
- return err
- }
- defer cfg.Free()
-
- webURLStr, err := cfg.LookupString("zoekt.web-url")
- err = clearEmptyConfig(err)
+ repo, err := git.PlainOpen(repoDir)
if err != nil {
return err
}
- webURLType, err := cfg.LookupString("zoekt.web-url-type")
- err = clearEmptyConfig(err)
+ cfg, err := repo.Config()
if err != nil {
return err
}
+ webURLStr := configLookupString(cfg, "zoekt.web-url")
+
+ webURLType := configLookupString(cfg, "zoekt.web-url-type")
+
if webURLType != "" && webURLStr != "" {
webURL, err := url.Parse(webURLStr)
if err != nil {
@@ -188,19 +203,13 @@
}
}
- name, err := cfg.LookupString("zoekt.name")
- err = clearEmptyConfig(err)
- if err != nil {
- return err
- }
-
+ name := configLookupString(cfg, "zoekt.name")
if name != "" {
desc.Name = name
} else {
- remoteURL, err := cfg.LookupString("remote.origin.url")
- err = clearEmptyConfig(err)
- if err != nil || remoteURL == "" {
- return err
+ remoteURL := configLookupRemoteURL(cfg, "origin")
+ if remoteURL == "" {
+ return nil
}
u, err := url.Parse(remoteURL)
if err != nil {
@@ -255,36 +264,32 @@
var result []string
for _, b := range bs {
if b == "HEAD" {
- _, ref, err := repo.RevparseExt(b)
+ ref, err := repo.Head()
if err != nil {
return nil, err
}
- result = append(result, strings.TrimPrefix(ref.Name(), prefix))
+ result = append(result, strings.TrimPrefix(ref.Name().String(), prefix))
continue
}
if strings.Contains(b, "*") {
- iter, err := repo.NewBranchIterator(git.BranchAll)
+ iter, err := repo.Branches()
if err != nil {
- log.Println("boem")
return nil, err
}
+ defer iter.Close()
for {
- br, _, err := iter.Next()
- if git.IsErrorCode(err, git.ErrIterOver) {
+ ref, err := iter.Next()
+ if err == io.EOF {
break
}
if err != nil {
- log.Printf("bam %#v", err)
return nil, err
}
- name, err := br.Name()
- if err != nil {
- return nil, err
- }
+ name := ref.Name().Short()
if matched, err := filepath.Match(b, name); err != nil {
return nil, err
} else if !matched {
@@ -300,12 +305,11 @@
}
return result, nil
-
}
// IndexGitRepo indexes the git repository as specified by the options.
func IndexGitRepo(opts Options) error {
- repo, err := git.OpenRepository(opts.BuildOptions.RepoDir)
+ repo, err := git.PlainOpen(opts.BuildOptions.RepoDir)
if err != nil {
return err
}
@@ -324,7 +328,7 @@
branchMap := map[FileKey][]string{}
// Branch => Repo => SHA1
- branchVersions := map[string]map[string]git.Oid{}
+ branchVersions := map[string]map[string]plumbing.Hash{}
branches, err := expandBranches(repo, opts.Branches, opts.BranchPrefix)
if err != nil {
@@ -341,17 +345,15 @@
if err != nil {
return err
}
- defer commit.Free()
opts.BuildOptions.RepositoryDescription.Branches = append(opts.BuildOptions.RepositoryDescription.Branches, zoekt.RepositoryBranch{
Name: b,
- Version: commit.Id().String(),
+ Version: commit.Hash.String(),
})
tree, err := commit.Tree()
if err != nil {
return err
}
- defer tree.Free()
files, subVersions, err := TreeToFiles(repo, tree, opts.BuildOptions.RepositoryDescription.URL, repoCache)
if err != nil {
@@ -417,22 +419,40 @@
keys := fileKeys[name]
for _, key := range keys {
brs := branchMap[key]
- blob, err := repos[key].Repo.LookupBlob(&key.ID)
+ blob, err := repos[key].Repo.BlobObject(key.ID)
if err != nil {
return err
}
- if blob.Size() > int64(opts.BuildOptions.SizeMax) {
+ if blob.Size > int64(opts.BuildOptions.SizeMax) {
continue
}
+ contents, err := blobContents(blob)
+ if err != nil {
+ return err
+ }
builder.Add(zoekt.Document{
SubRepositoryPath: key.SubRepoPath,
Name: key.FullPath(),
- Content: blob.Contents(),
+ Content: contents,
Branches: brs,
})
}
}
return builder.Finish()
}
+
+func blobContents(blob *object.Blob) ([]byte, error) {
+ r, err := blob.Reader()
+ if err != nil {
+ return nil, err
+ }
+ defer r.Close()
+
+ c, err := ioutil.ReadAll(r)
+ if err != nil {
+ return nil, err
+ }
+ return c, nil
+}
diff --git a/gitindex/submodule.go b/gitindex/submodule.go
index a6c3f85..ac05e6f 100644
--- a/gitindex/submodule.go
+++ b/gitindex/submodule.go
@@ -15,11 +15,9 @@
package gitindex
import (
- "io/ioutil"
- "os"
- "regexp"
+ "bytes"
- "github.com/libgit2/git2go"
+ "gopkg.in/src-d/go-git.v4/plumbing/format/config"
)
type SubmoduleEntry struct {
@@ -28,64 +26,36 @@
Branch string
}
-const submodREStr = "^submodule.([^.]*)\\.(.*)"
-
-var submodRE = regexp.MustCompile(submodREStr)
-
// ParseGitModules parses the contents of a .gitmodules file.
func ParseGitModules(content []byte) (map[string]*SubmoduleEntry, error) {
- base, err := git.NewConfig()
- if err != nil {
- return nil, err
- }
- defer base.Free()
+ dec := config.NewDecoder(bytes.NewBuffer(content))
+ cfg := &config.Config{}
- // git2go has no API for parsing from contents. Sigh.
- f, err := ioutil.TempFile("", "")
- if err != nil {
- return nil, err
- }
- defer os.Remove(f.Name())
- if _, err := f.Write(content); err != nil {
- return nil, err
- }
- f.Close()
-
- cfg, err := git.OpenOndisk(base, f.Name())
- if err != nil {
- return nil, err
- }
- defer cfg.Free()
- iter, err := cfg.NewIteratorGlob(submodREStr)
- if err != nil {
+ if err := dec.Decode(cfg); err != nil {
return nil, err
}
result := map[string]*SubmoduleEntry{}
- for {
- entry, err := iter.Next()
- if err != nil {
- if ge, ok := err.(*git.GitError); ok && ge.Code == git.ErrIterOver {
- break
+ for _, s := range cfg.Sections {
+ if s.Name != "submodule" {
+ continue
+ }
+
+ for _, ss := range s.Subsections {
+ name := ss.Name
+ e := &SubmoduleEntry{}
+ for _, o := range ss.Options {
+ switch o.Key {
+ case "branch":
+ e.Branch = o.Value
+ case "path":
+ e.Path = o.Value
+ case "url":
+ e.URL = o.Value
+ }
}
- return nil, err
- }
- m := submodRE.FindStringSubmatch(entry.Name)
-
- name := m[1]
- if result[name] == nil {
- result[name] = &SubmoduleEntry{}
- }
-
- e := result[name]
- switch m[2] {
- case "branch":
- e.Branch = entry.Value
- case "path":
- e.Path = entry.Value
- case "url":
- e.URL = entry.Value
+ result[name] = e
}
}
diff --git a/gitindex/tree.go b/gitindex/tree.go
index a9d9efa..9fbd180 100644
--- a/gitindex/tree.go
+++ b/gitindex/tree.go
@@ -16,13 +16,18 @@
import (
"fmt"
+ "io"
"log"
"net/url"
"path"
"path/filepath"
"strings"
- git "github.com/libgit2/git2go"
+ "gopkg.in/src-d/go-git.v4/plumbing"
+ "gopkg.in/src-d/go-git.v4/plumbing/filemode"
+ "gopkg.in/src-d/go-git.v4/plumbing/object"
+
+ git "gopkg.in/src-d/go-git.v4"
)
// repoWalker walks a tree, recursing into submodules.
@@ -36,7 +41,7 @@
submodules map[string]*SubmoduleEntry
// Path => commit SHA1
- subRepoVersions map[string]git.Oid
+ subRepoVersions map[string]plumbing.Hash
err error
repoCache *RepoCache
@@ -66,21 +71,20 @@
repoURL: u,
tree: map[FileKey]BlobLocation{},
repoCache: repoCache,
- subRepoVersions: map[string]git.Oid{},
+ subRepoVersions: map[string]plumbing.Hash{},
ignoreMissingSubmodules: true,
}
}
// parseModuleMap initializes rw.submodules.
-func (rw *repoWalker) parseModuleMap(t *git.Tree) error {
- modEntry := t.EntryByName(".gitmodules")
+func (rw *repoWalker) parseModuleMap(t *object.Tree) error {
+ modEntry, _ := t.File(".gitmodules")
if modEntry != nil {
- blob, err := rw.repo.LookupBlob(modEntry.Id)
+ c, err := blobContents(&modEntry.Blob)
if err != nil {
return err
}
-
- mods, err := ParseGitModules(blob.Contents())
+ mods, err := ParseGitModules(c)
if err != nil {
return err
}
@@ -95,22 +99,29 @@
// TreeToFiles fetches the blob SHA1s for a tree. If repoCache is
// non-nil, recurse into submodules. In addition, it returns a mapping
// that indicates in which repo each SHA1 can be found.
-func TreeToFiles(r *git.Repository, t *git.Tree,
- repoURL string, repoCache *RepoCache) (map[FileKey]BlobLocation, map[string]git.Oid, error) {
- ref := newRepoWalker(r, repoURL, repoCache)
+func TreeToFiles(r *git.Repository, t *object.Tree,
+ repoURL string, repoCache *RepoCache) (map[FileKey]BlobLocation, map[string]plumbing.Hash, error) {
+ rw := newRepoWalker(r, repoURL, repoCache)
- if err := ref.parseModuleMap(t); err != nil {
+ if err := rw.parseModuleMap(t); err != nil {
return nil, nil, err
}
- t.Walk(ref.cbInt)
- if ref.err != nil {
- return nil, nil, ref.err
+ tw := object.NewTreeWalker(t, true, make(map[plumbing.Hash]bool))
+ defer tw.Close()
+ for {
+ name, entry, err := tw.Next()
+ if err == io.EOF {
+ break
+ }
+ if err := rw.handleEntry(name, &entry); err != nil {
+ return nil, nil, err
+ }
}
- return ref.tree, ref.subRepoVersions, nil
+ return rw.tree, rw.subRepoVersions, nil
}
-func (r *repoWalker) tryHandleSubmodule(p string, id *git.Oid) error {
+func (r *repoWalker) tryHandleSubmodule(p string, id *plumbing.Hash) error {
err := r.handleSubmodule(p, id)
if r.ignoreMissingSubmodules && err != nil {
log.Printf("submodule %s: ignoring error %v", p, err)
@@ -120,7 +131,7 @@
return nil
}
-func (r *repoWalker) handleSubmodule(p string, id *git.Oid) error {
+func (r *repoWalker) handleSubmodule(p string, id *plumbing.Hash) error {
submod := r.submodules[p]
if submod == nil {
return fmt.Errorf("no entry for submodule path %q", r.repoURL)
@@ -136,24 +147,17 @@
return err
}
- obj, err := subRepo.Lookup(id)
+ obj, err := subRepo.CommitObject(*id)
if err != nil {
return err
}
- defer obj.Free()
+ tree, err := subRepo.TreeObject(obj.TreeHash)
+ if err != nil {
+ return err
+ }
r.subRepoVersions[p] = *id
- treeObj, err := obj.Peel(git.ObjectTree)
- if err != nil {
- return err
- }
- if treeObj != obj {
- defer treeObj.Free()
- }
- tree, err := treeObj.AsTree()
- if err != nil {
- return err
- }
+
subTree, subVersions, err := TreeToFiles(subRepo, tree, subURL.String(), r.repoCache)
if err != nil {
return err
@@ -172,26 +176,22 @@
}
// cb is the git2go callback
-func (r *repoWalker) cb(n string, e *git.TreeEntry) error {
- p := filepath.Join(n, e.Name)
- if e.Type == git.ObjectCommit && r.repoCache != nil {
- if err := r.tryHandleSubmodule(p, e.Id); err != nil {
+func (r *repoWalker) handleEntry(p string, e *object.TreeEntry) error {
+ if e.Mode == filemode.Submodule && r.repoCache != nil {
+ if err := r.tryHandleSubmodule(p, &e.Hash); err != nil {
return fmt.Errorf("submodule %s: %v", p, err)
}
}
- switch e.Filemode {
- case git.FilemodeBlob, git.FilemodeBlobExecutable:
+ switch e.Mode {
+ case filemode.Regular, filemode.Executable:
default:
return nil
}
- if e.Type != git.ObjectBlob {
- return nil
- }
r.tree[FileKey{
Path: p,
- ID: *e.Id,
+ ID: e.Hash,
}] = BlobLocation{
Repo: r.repo,
URL: r.repoURL,
@@ -199,22 +199,12 @@
return nil
}
-// cbInt is the callback suitable for use with git2go.
-func (r *repoWalker) cbInt(n string, e *git.TreeEntry) int {
- err := r.cb(n, e)
- if err != nil {
- r.err = err
- return 1
- }
- return 0
-}
-
// FileKey describes a blob at a location in the final tree. We also
// record the subrepository from where it came.
type FileKey struct {
SubRepoPath string
Path string
- ID git.Oid
+ ID plumbing.Hash
}
func (k *FileKey) FullPath() string {
@@ -227,11 +217,10 @@
URL *url.URL
}
-func (l *BlobLocation) Blob(id *git.Oid) ([]byte, error) {
- blob, err := l.Repo.LookupBlob(id)
+func (l *BlobLocation) Blob(id *plumbing.Hash) ([]byte, error) {
+ blob, err := l.Repo.BlobObject(*id)
if err != nil {
return nil, err
}
- defer blob.Free()
- return blob.Contents(), nil
+ return blobContents(blob)
}
diff --git a/gitindex/tree_test.go b/gitindex/tree_test.go
index 2650ac9..30e7e43 100644
--- a/gitindex/tree_test.go
+++ b/gitindex/tree_test.go
@@ -31,6 +31,8 @@
"github.com/google/zoekt/build"
"github.com/google/zoekt/query"
"github.com/google/zoekt/shards"
+
+ "gopkg.in/src-d/go-git.v4/plumbing"
)
func createSubmoduleRepo(dir string) error {
@@ -101,13 +103,16 @@
t.Fatalf("Open: %v", err)
}
- obj, err := repo.RevparseSingle("HEAD:")
+ headRef, err := repo.Head()
if err != nil {
t.Fatalf("HEAD tree: %v", err)
}
+ commit, err := repo.CommitObject(headRef.Hash())
+ if err != nil {
+ t.Fatalf("commit obj HEAD: %v", err)
+ }
- defer obj.Free()
- tree, err := obj.AsTree()
+ tree, err := repo.TreeObject(commit.TreeHash)
if err != nil {
t.Fatalf("AsTree: %v", err)
}
@@ -116,9 +121,13 @@
if err != nil {
t.Fatalf("TreeToFiles: %v", err)
}
+ var bnameHash plumbing.Hash
- if e, v := tree.EntryByName("bname"), versions["bname"]; e == nil || bytes.Compare(e.Id[:], v[:]) != 0 {
- t.Fatalf("got 'bname' versions %v, want %v", v, e)
+ bnameHash = versions["bname"]
+ if entry, err := tree.FindEntry("bname"); err != nil {
+ t.Fatalf("FindEntry %v", err)
+ } else if bytes.Compare(bnameHash[:], entry.Hash[:]) != 0 {
+ t.Fatalf("got 'bname' versions %v, want %v", bnameHash, entry.Hash)
}
var paths []string
@@ -181,7 +190,7 @@
}
if len(results.Files) != 1 {
- t.Fatalf("got %v, want 1 file", results.Files)
+ t.Fatalf("got search result %v, want 1 file", results.Files)
}
file := results.Files[0]