diff options
Diffstat (limited to 'plumbing/revlist/revlist.go')
-rw-r--r-- | plumbing/revlist/revlist.go | 113 |
1 files changed, 67 insertions, 46 deletions
diff --git a/plumbing/revlist/revlist.go b/plumbing/revlist/revlist.go index f1d66b4..5731474 100644 --- a/plumbing/revlist/revlist.go +++ b/plumbing/revlist/revlist.go @@ -3,6 +3,7 @@ package revlist import ( + "fmt" "io" "srcd.works/go-git.v4/plumbing" @@ -11,29 +12,26 @@ import ( ) // Objects applies a complementary set. It gets all the hashes from all -// the reachable objects from the given commits. Ignore param are object hashes -// that we want to ignore on the result. It is a list because is -// easier to interact with other porcelain elements, but internally it is -// converted to a map. All that objects must be accessible from the object -// storer. +// the reachable objects from the given objects. Ignore param are object hashes +// that we want to ignore on the result. All that objects must be accessible +// from the object storer. func Objects( s storer.EncodedObjectStorer, - commits []*object.Commit, + objects []plumbing.Hash, ignore []plumbing.Hash) ([]plumbing.Hash, error) { seen := hashListToSet(ignore) result := make(map[plumbing.Hash]bool) - for _, c := range commits { - err := reachableObjects(s, c, seen, func(h plumbing.Hash) error { - if !seen[h] { - result[h] = true - seen[h] = true - } - return nil - }) + walkerFunc := func(h plumbing.Hash) { + if !seen[h] { + result[h] = true + seen[h] = true + } + } - if err != nil { + for _, h := range objects { + if err := processObject(s, h, seen, walkerFunc); err != nil { return nil, err } } @@ -41,56 +39,76 @@ func Objects( return hashSetToList(result), nil } +// processObject obtains the object using the hash an process it depending of its type +func processObject( + s storer.EncodedObjectStorer, + h plumbing.Hash, + seen map[plumbing.Hash]bool, + walkerFunc func(h plumbing.Hash), +) error { + o, err := s.EncodedObject(plumbing.AnyObject, h) + if err != nil { + return err + } + + do, err := object.DecodeObject(s, o) + if err != nil { + return err + } + + switch do := do.(type) { + case *object.Commit: + return reachableObjects(do, seen, walkerFunc) + case *object.Tree: + return iterateCommitTrees(seen, do, walkerFunc) + case *object.Tag: + walkerFunc(do.Hash) + return processObject(s, do.Target, seen, walkerFunc) + case *object.Blob: + walkerFunc(do.Hash) + default: + return fmt.Errorf("object type not valid: %s. "+ + "Object reference: %s", o.Type(), o.Hash()) + } + + return nil +} + // reachableObjects returns, using the callback function, all the reachable // objects from the specified commit. To avoid to iterate over seen commits, // if a commit hash is into the 'seen' set, we will not iterate all his trees // and blobs objects. func reachableObjects( - s storer.EncodedObjectStorer, commit *object.Commit, seen map[plumbing.Hash]bool, - cb func(h plumbing.Hash) error) error { - - return iterateCommits(commit, func(commit *object.Commit) error { + cb func(h plumbing.Hash)) error { + return object.WalkCommitHistory(commit, func(commit *object.Commit) error { if seen[commit.Hash] { return nil } - if err := cb(commit.Hash); err != nil { + cb(commit.Hash) + + tree, err := commit.Tree() + if err != nil { return err } - return iterateCommitTrees(s, commit, func(h plumbing.Hash) error { - return cb(h) - }) - }) -} - -// iterateCommits iterate all reachable commits from the given one -func iterateCommits(commit *object.Commit, cb func(c *object.Commit) error) error { - if err := cb(commit); err != nil { - return err - } - - return object.WalkCommitHistory(commit, func(c *object.Commit) error { - return cb(c) + return iterateCommitTrees(seen, tree, cb) }) } // iterateCommitTrees iterate all reachable trees from the given commit func iterateCommitTrees( - s storer.EncodedObjectStorer, - commit *object.Commit, - cb func(h plumbing.Hash) error) error { - - tree, err := commit.Tree() - if err != nil { - return err - } - if err := cb(tree.Hash); err != nil { - return err + seen map[plumbing.Hash]bool, + tree *object.Tree, + cb func(h plumbing.Hash)) error { + if seen[tree.Hash] { + return nil } + cb(tree.Hash) + treeWalker := object.NewTreeWalker(tree, true) for { @@ -101,9 +119,12 @@ func iterateCommitTrees( if err != nil { return err } - if err := cb(e.Hash); err != nil { - return err + + if seen[e.Hash] { + continue } + + cb(e.Hash) } return nil |