From 6825ee17a23754ac56a1fb9d4c09f321070c29b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Cort=C3=A9s?= Date: Thu, 21 Jan 2016 03:00:41 +0100 Subject: [PATCH 1/2] Fix commit.File() gorutine leak Commit.File() was leaking a goroutine because it was looping over an iterator without closing its channel. Now commit.File() calls the new Tree.File() method that searches the file in the repository by trasversing the dir tree instead of using the tree.Files() iterator. This not only prevent the goroutine leak, but also speeds up file searching. --- commit.go | 11 +- .../fixtures/alcortesm-binary-relations.pack | Bin 0 -> 12565 bytes .../packfile/fixtures/git-fixture.ofs-delta | Bin .../packfile/fixtures/git-fixture.ref-delta | Bin tree.go | 80 +++++++++++ tree_test.go | 134 ++++++++++++++++++ 6 files changed, 215 insertions(+), 10 deletions(-) create mode 100644 formats/packfile/fixtures/alcortesm-binary-relations.pack mode change 100755 => 100644 formats/packfile/fixtures/git-fixture.ofs-delta mode change 100755 => 100644 formats/packfile/fixtures/git-fixture.ref-delta create mode 100644 tree_test.go diff --git a/commit.go b/commit.go index 1dd09ab6b..ea6419f1d 100644 --- a/commit.go +++ b/commit.go @@ -3,7 +3,6 @@ package git import ( "bufio" "bytes" - "errors" "fmt" "io" "sort" @@ -11,9 +10,6 @@ import ( "gopkg.in/src-d/go-git.v2/core" ) -// New errors defined by this package. -var ErrFileNotFound = errors.New("file not found") - type Hash core.Hash // Commit points to a single tree, marking it as what the project looked like @@ -59,12 +55,7 @@ func (c *Commit) NumParents() int { // nil error if the file exists. If the file does not exists, it returns // a nil file and the ErrFileNotFound error. func (c *Commit) File(path string) (file *File, err error) { - for file := range c.Tree().Files() { - if file.Name == path { - return file, nil - } - } - return nil, ErrFileNotFound + return c.Tree().File(path) } // Decode transform an core.Object into a Blob struct diff --git a/formats/packfile/fixtures/alcortesm-binary-relations.pack b/formats/packfile/fixtures/alcortesm-binary-relations.pack new file mode 100644 index 0000000000000000000000000000000000000000..136273797d5ec0990783690ff1ce948520feea6a GIT binary patch literal 12565 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 LhR2fysf7Op6w 1; pathParts = pathParts[1:] { + if tree, err = tree.dir(pathParts[0]); err != nil { + return nil, err + } + } + + entry, err := tree.entry(pathParts[0]) + if err != nil { + return nil, err + } + + return &entry.Hash, nil +} + +var errDirNotFound = errors.New("directory not found") + +func (t *Tree) dir(baseName string) (*Tree, error) { + entry, err := t.entry(baseName) + if err != nil { + return nil, errDirNotFound + } + + obj, ok := t.r.Storage.Get(entry.Hash) + if !ok { // git submodule + return nil, errDirNotFound + } + + if obj.Type() != core.TreeObject { + return nil, errDirNotFound // a file + } + + tree := &Tree{r: t.r} + tree.Decode(obj) + + return tree, nil +} + +var errEntryNotFound = errors.New("entry not found") + +func (t *Tree) entry(baseName string) (*TreeEntry, error) { + for _, entry := range t.Entries { + if entry.Name == baseName { + return &entry, nil + } + } + + return nil, errEntryNotFound +} + func (t *Tree) Files() chan *File { ch := make(chan *File, 1) diff --git a/tree_test.go b/tree_test.go new file mode 100644 index 000000000..049161c12 --- /dev/null +++ b/tree_test.go @@ -0,0 +1,134 @@ +package git + +import ( + "os" + + "gopkg.in/src-d/go-git.v2/core" + "gopkg.in/src-d/go-git.v2/formats/packfile" + + . "gopkg.in/check.v1" +) + +type SuiteTree struct { + repos map[string]*Repository +} + +var _ = Suite(&SuiteTree{}) + +// create the repositories of the fixtures +func (s *SuiteTree) SetUpSuite(c *C) { + fixtureRepos := [...]struct { + url string + packfile string + }{ + {"https://github.com/tyba/git-fixture.git", "formats/packfile/fixtures/git-fixture.ofs-delta"}, + {"https://github.com/cpcs499/Final_Pres_P.git", "formats/packfile/fixtures/Final_Pres_P.ofs-delta"}, + {"https://github.com/jamesob/desk.git", "formats/packfile/fixtures/jamesob-desk.pack"}, + {"https://github.com/spinnaker/spinnaker.git", "formats/packfile/fixtures/spinnaker-spinnaker.pack"}, + {"https://github.com/alcortesm/binary-relations.git", "formats/packfile/fixtures/alcortesm-binary-relations.pack"}, + } + s.repos = make(map[string]*Repository, 0) + for _, fixRepo := range fixtureRepos { + s.repos[fixRepo.url] = NewPlainRepository() + + d, err := os.Open(fixRepo.packfile) + c.Assert(err, IsNil) + + r := packfile.NewReader(d) + r.Format = packfile.OFSDeltaFormat // TODO: how to know the format of a pack file ahead of time? + + _, err = r.Read(s.repos[fixRepo.url].Storage) + c.Assert(err, IsNil) + + c.Assert(d.Close(), IsNil) + } +} + +func (s *SuiteTree) TestFile(c *C) { + for i, t := range []struct { + repo string // the repo name as in localRepos + commit string // the commit to search for the file + path string // the path of the file to find + blobHash string // expected hash of the returned file + found bool // expected found value + }{ + // use git ls-tree commit to get the hash of the blobs + {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", "not-found", + "", false}, + {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", ".gitignore", + "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88", true}, + {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", "LICENSE", + "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f", true}, + + {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "not-found", + "", false}, + {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", ".gitignore", + "32858aad3c383ed1ff0a0f9bdf231d54a00c9e88", true}, + {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "binary.jpg", + "d5c0f4ab811897cadf03aec358ae60d21f91c50d", true}, + {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "LICENSE", + "c192bd6a24ea1ab01d78686e417c8bdc7c3d197f", true}, + + {"https://github.com/tyba/git-fixture.git", "35e85108805c84807bc66a02d91535e1e24b38b9", "binary.jpg", + "d5c0f4ab811897cadf03aec358ae60d21f91c50d", true}, + {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", "binary.jpg", + "", false}, + + {"https://github.com/tyba/git-fixture.git", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5", "CHANGELOG", + "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", true}, + {"https://github.com/tyba/git-fixture.git", "1669dce138d9b841a518c64b10914d88f5e488ea", "CHANGELOG", + "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", true}, + {"https://github.com/tyba/git-fixture.git", "a5b8b09e2f8fcb0bb99d3ccb0958157b40890d69", "CHANGELOG", + "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", true}, + {"https://github.com/tyba/git-fixture.git", "35e85108805c84807bc66a02d91535e1e24b38b9", "CHANGELOG", + "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", false}, + {"https://github.com/tyba/git-fixture.git", "b8e471f58bcbca63b07bda20e428190409c2db47", "CHANGELOG", + "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", true}, + {"https://github.com/tyba/git-fixture.git", "b029517f6300c2da0f4b651b8642506cd6aaf45d", "CHANGELOG", + "d3ff53e0564a9f87d8e84b6e28e5060e517008aa", false}, + + // git submodule + {"https://github.com/cpcs499/Final_Pres_P.git", "70bade703ce556c2c7391a8065c45c943e8b6bc3", "Final", + "", false}, + {"https://github.com/cpcs499/Final_Pres_P.git", "70bade703ce556c2c7391a8065c45c943e8b6bc3", "Final/not-found", + "", false}, + + {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "LICENSE", + "49c45e6cc893d6f5ebd5c9343fe4492360f339bf", true}, + {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "examples", + "", false}, + {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "examples/desk.sh", + "d9c7751138824cd2d539c23d5afe3f9d29836854", true}, + {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "examples/not-found", + "", false}, + {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "test/bashrc", + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", true}, + {"https://github.com/jamesob/desk.git", "d4edaf0e8101fcea437ebd982d899fe2cc0f9f7b", "test/not-found", + "", false}, + + {"https://github.com/spinnaker/spinnaker.git", "b32b2aecae2cfca4840dd480f8082da206a538da", "etc/apache2/sites-available/spinnaker.conf", + "1d452c616be4fb16d2cc6b8a7e7a2208a6e64d2d", true}, + + {"https://github.com/alcortesm/binary-relations.git", "c44b5176e99085c8fe36fa27b045590a7b9d34c9", "Makefile", + "2dd2ad8c14de6612ed15813679a6554bad99330b", true}, + {"https://github.com/alcortesm/binary-relations.git", "c44b5176e99085c8fe36fa27b045590a7b9d34c9", "src/binrels", + "", false}, + {"https://github.com/alcortesm/binary-relations.git", "c44b5176e99085c8fe36fa27b045590a7b9d34c9", "src/map-slice", + "", false}, + {"https://github.com/alcortesm/binary-relations.git", "c44b5176e99085c8fe36fa27b045590a7b9d34c9", "src/map-slice/map-slice.go", + "12431e98381dd5097e1a19fe53429c72ef1f328e", true}, + {"https://github.com/alcortesm/binary-relations.git", "c44b5176e99085c8fe36fa27b045590a7b9d34c9", "src/map-slice/map-slice.go/not-found", + "", false}, + } { + commit, err := s.repos[t.repo].Commit(core.NewHash(t.commit)) + c.Assert(err, IsNil, Commentf("subtest %d: %v (%s)", i, err, t.commit)) + + tree := commit.Tree() + file, err := tree.File(t.path) + found := err == nil + c.Assert(found, Equals, t.found, Commentf("subtest %d, path=%s, commit=%s", i, t.path, t.commit)) + if found { + c.Assert(file.Hash.String(), Equals, t.blobHash, Commentf("subtest %d, commit=%s, path=%s", i, t.commit, t.path)) + } + } +} From c526d5273bb1f3ddc3cc744aa3900a40c3d49dbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Cort=C3=A9s?= Date: Thu, 21 Jan 2016 11:39:24 +0100 Subject: [PATCH 2/2] Readability improvements --- tree.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tree.go b/tree.go index 232bfc257..523baac08 100644 --- a/tree.go +++ b/tree.go @@ -31,8 +31,10 @@ type TreeEntry struct { // New errors defined by this package. var ErrFileNotFound = errors.New("file not found") +// File returns the hash of the file identified by the `path` argument. +// The path is interpreted as relative to the tree receiver. func (t *Tree) File(path string) (*File, error) { - hash, err := t.hashOf(path) + hash, err := t.findHash(path) if err != nil { return nil, ErrFileNotFound } @@ -52,7 +54,7 @@ func (t *Tree) File(path string) (*File, error) { return &File{Name: path, Reader: blob.Reader(), Hash: *hash}, nil } -func (t *Tree) hashOf(path string) (*core.Hash, error) { +func (t *Tree) findHash(path string) (*core.Hash, error) { pathParts := strings.Split(path, "/") var tree *Tree