func assertBlobInTree(t *testing.T, repo *git.Repository, tree *git.Tree, key, value string) { e, err := tree.EntryByPath(key) if err != nil || e == nil { t.Fatalf("No blob at key %v.\n\ttree=%#v\n", key, tree) } blob, err := lookupBlob(repo, e.Id) if err != nil { t.Fatalf("No blob at key %v.\\n\terr=%v\n\ttree=%#v\n", key, err, tree) } if string(blob.Contents()) != value { t.Fatalf("blob at key %v != %v.\n\ttree=%#v\n\treal val = %v\n", key, value, tree, string(blob.Contents())) } blob.Free() }
func TreeScope(repo *git.Repository, tree *git.Tree, name string) (*git.Tree, error) { if tree == nil { return nil, fmt.Errorf("tree undefined") } name = TreePath(name) if name == "/" { // Allocate a new Tree object so that the caller // can always call Free() on the result return lookupTree(repo, tree.Id()) } entry, err := tree.EntryByPath(name) if err != nil { return nil, err } return lookupTree(repo, entry.Id) }
func TreeGet(r *git.Repository, t *git.Tree, key string) (string, error) { if t == nil { return "", os.ErrNotExist } key = TreePath(key) e, err := t.EntryByPath(key) if err != nil { return "", err } blob, err := lookupBlob(r, e.Id) if err != nil { return "", err } defer blob.Free() return string(blob.Contents()), nil }
func (fs *gitFSLibGit2) ReadDir(path string) ([]os.FileInfo, error) { fs.repoEditLock.RLock() defer fs.repoEditLock.RUnlock() path = filepath.Clean(internal.Rel(path)) var subtree *git2go.Tree if path == "." { subtree = fs.tree } else { e, err := fs.getEntry(path) if err != nil { return nil, err } subtree, err = fs.repo.LookupTree(e.Id) if err != nil { return nil, err } } fis := make([]os.FileInfo, int(subtree.EntryCount())) for i := uint64(0); i < subtree.EntryCount(); i++ { e := subtree.EntryByIndex(i) fi, err := fs.makeFileInfo(filepath.Join(path, e.Name), e) if err != nil { return nil, err } fis[i] = fi } return fis, nil }
func (t *treeFS) recurse(tree *git.Tree, n nodefs.Node) error { for i := uint64(0); ; i++ { e := tree.EntryByIndex(i) if e == nil { break } isdir := e.Filemode&syscall.S_IFDIR != 0 var chNode nodefs.Node if isdir { chNode = t.newDirNode(e.Id) } else if e.Filemode&^07777 == syscall.S_IFLNK { l, err := t.newLinkNode(e.Id) if err != nil { return err } chNode = l } else if e.Filemode&^07777 == syscall.S_IFREG { b, err := t.newBlobNode(e.Id, e.Filemode) if err != nil { return err } chNode = b } else { panic(e) } n.Inode().NewChild(e.Name, isdir, chNode) if isdir { tree, err := t.repo.LookupTree(e.Id) if err != nil { return err } if err := t.recurse(tree, chNode); err != nil { return nil } } } return nil }
// treeAdd creates a new Git tree by adding a new object // to it at the specified path. // Intermediary subtrees are created as needed. // If an object already exists at key or any intermediary path, // it is overwritten. // // - If merge is true, new trees are merged into existing ones at the // file granularity (similar to 'cp -R'). // - If it is false, existing trees are completely shadowed (similar to 'mount') // // Since git trees are immutable, base is not modified. The new // tree is returned. // If an error is encountered, intermediary objects may be left // behind in the git repository. It is the caller's responsibility // to perform garbage collection, if any. // FIXME: manage garbage collection, or provide a list of created // objects. func treeAdd(repo *git.Repository, tree *git.Tree, key string, valueId *git.Oid, merge bool) (t *git.Tree, err error) { /* ** // Primitive but convenient tracing for debugging recursive calls to treeAdd. ** // Uncomment this block for debug output. ** ** var callString string ** if tree != nil { ** callString = fmt.Sprintf(" treeAdd %v:\t\t%s\t\t\t= %v", tree.Id(), key, valueId) ** } else { ** callString = fmt.Sprintf(" treeAdd %v:\t\t%s\t\t\t= %v", tree, key, valueId) ** } ** fmt.Printf(" %s\n", callString) ** defer func() { ** if t != nil { ** fmt.Printf("-> %s => %v\n", callString, t.Id()) ** } else { ** fmt.Printf("-> %s => %v\n", callString, err) ** } ** }() */ if valueId == nil { return tree, nil } key = TreePath(key) base, leaf := path.Split(key) o, err := repo.Lookup(valueId) if err != nil { return nil, err } var builder *git.TreeBuilder if tree == nil { builder, err = repo.TreeBuilder() if err != nil { return nil, err } } else { builder, err = repo.TreeBuilderFromTree(tree) if err != nil { return nil, err } } defer builder.Free() // The specified path has only 1 component (the "leaf") if base == "" || base == "/" { // If val is a string, set it and we're done. // Any old value is overwritten. if _, isBlob := o.(*git.Blob); isBlob { if err := builder.Insert(leaf, valueId, 0100644); err != nil { return nil, err } newTreeId, err := builder.Write() if err != nil { return nil, err } newTree, err := lookupTree(repo, newTreeId) if err != nil { return nil, err } return newTree, nil } // If val is not a string, it must be a subtree. // Return an error if it's any other type than Tree. oTree, ok := o.(*git.Tree) if !ok { return nil, fmt.Errorf("value must be a blob or subtree") } var subTree *git.Tree var oldSubTree *git.Tree if tree != nil { oldSubTree, err = TreeScope(repo, tree, leaf) // FIXME: distinguish "no such key" error (which // FIXME: distinguish a non-existing previous tree (continue with oldTree==nil) // from other errors (abort and return an error) if err == nil { defer oldSubTree.Free() } } // If that subtree already exists, merge the new one in. if merge && oldSubTree != nil { subTree = oldSubTree for i := uint64(0); i < oTree.EntryCount(); i++ { var err error e := oTree.EntryByIndex(i) subTree, err = treeAdd(repo, subTree, e.Name, e.Id, merge) if err != nil { return nil, err } } } else { subTree = oTree } // If the key is /, we're replacing the current tree if key == "/" { return subTree, nil } // Otherwise we're inserting into the current tree if err := builder.Insert(leaf, subTree.Id(), 040000); err != nil { return nil, err } newTreeId, err := builder.Write() if err != nil { return nil, err } newTree, err := lookupTree(repo, newTreeId) if err != nil { return nil, err } return newTree, nil } subtree, err := treeAdd(repo, nil, leaf, valueId, merge) if err != nil { return nil, err } return treeAdd(repo, tree, base, subtree.Id(), merge) }
// FindReviewers returns up to 3 of the top reviewers information as determined // by cumulative commit count across all files in `paths`. func (r *Reviewer) FindReviewers(paths []string) (string, error) { var ( rg runGuard rw *gg.RevWalk since time.Time reviewers map[string]int final Stats ) reviewers = make(map[string]int) if len(r.Since) > 0 { var err error since, err = time.Parse("2006-01-02", r.Since) if err != nil { if r.Verbose { fmt.Println("Unable to parse 'since'") } return "", err } } else { // Calculate 6 months ago from today's date and set the 'since' argument since = time.Now().AddDate(0, -6, 0) } // Cleanup defer func() { objs := [...]freeable{ rw, } for _, obj := range objs { if obj != nil { obj.Free() } } }() // Iterate through commits in the review period rg.maybeRun(func() { var err error if rw, err = r.Repo.Walk(); err != nil { rg.err = err rg.msg = "Issue opening revwalk" } rw.Sorting(gg.SortTime | gg.SortTopological) }) rg.maybeRun(func() { var err error // TODO push master, not HEAD if err = rw.PushHead(); err != nil { rg.err = err rg.msg = "Issue pushing HEAD onto revwalk" } }) // For each of our commits in the review period, see if it affects // at least one of the paths changed in the branch. If so, the commit // author is added to the count of contributors with experience with one // of the changed files in our branch. rg.maybeRun(func() { var err error // Revwalk.Iterate walks through commits until the // RevWalkIterator returns false. err = rw.Iterate(func(c *gg.Commit) bool { var ( err error tree *gg.Tree ) defer c.Free() sig := c.Committer() // Stop walking commits since we've passed 'since' if sig.When.Before(since) { return false } tree, err = c.Tree() if err != nil { rg.err = err return false } // Check desired paths to see if one exists in the commit tree for _, p := range paths { te, err := tree.EntryByPath(p) if err != nil { continue } if te != nil { k := reviewerKey(sig) if _, ok := reviewers[k]; ok { reviewers[k]++ } else { reviewers[k] = 1 } // We found a path on the commit, no need to double-count break } } return true }) if err != nil { rg.err = err rg.msg = "Error iterating through rev walk" } }) if rg.err != nil { fmt.Println(rg.msg) fmt.Println(rg.err) return "", rg.err } final = make(Stats, len(reviewers)) idx := 0 for reviewer, count := range reviewers { final[idx] = &Stat{reviewer, count} idx++ } maxStats := 3 if l := len(final); l < maxStats { maxStats = l } topN := chooseTopN(maxStats, final) var buffer bytes.Buffer for i := range topN { buffer.WriteString(topN[i].String()) buffer.WriteString("\n") } return buffer.String(), nil }
func assertBlobNotInTree(t *testing.T, repo *git.Repository, tree *git.Tree, key string) { _, err := tree.EntryByPath(key) if err == nil { t.Fatalf("Key %q still exists in tree", key) } }