forked from tangled.org/core
this repo has no description
1package git 2 3import ( 4 "context" 5 "errors" 6 "fmt" 7 "path" 8 "time" 9 10 "github.com/go-git/go-git/v5/plumbing/object" 11 "tangled.org/core/types" 12) 13 14func (g *GitRepo) FileTree(ctx context.Context, path string) ([]types.NiceTree, error) { 15 c, err := g.r.CommitObject(g.h) 16 if err != nil { 17 return nil, fmt.Errorf("commit object: %w", err) 18 } 19 20 files := []types.NiceTree{} 21 tree, err := c.Tree() 22 if err != nil { 23 return nil, fmt.Errorf("file tree: %w", err) 24 } 25 26 if path == "" { 27 files = g.makeNiceTree(ctx, tree, "") 28 } else { 29 o, err := tree.FindEntry(path) 30 if err != nil { 31 return nil, err 32 } 33 34 if !o.Mode.IsFile() { 35 subtree, err := tree.Tree(path) 36 if err != nil { 37 return nil, err 38 } 39 40 files = g.makeNiceTree(ctx, subtree, path) 41 } 42 } 43 44 return files, nil 45} 46 47func (g *GitRepo) makeNiceTree(ctx context.Context, subtree *object.Tree, parent string) []types.NiceTree { 48 nts := []types.NiceTree{} 49 50 times, err := g.calculateCommitTimeIn(ctx, subtree, parent, 2*time.Second) 51 if err != nil { 52 return nts 53 } 54 55 for _, e := range subtree.Entries { 56 mode, _ := e.Mode.ToOSFileMode() 57 sz, _ := subtree.Size(e.Name) 58 59 fpath := path.Join(parent, e.Name) 60 61 var lastCommit *types.LastCommitInfo 62 if t, ok := times[fpath]; ok { 63 lastCommit = &types.LastCommitInfo{ 64 Hash: t.hash, 65 Message: t.message, 66 When: t.when, 67 } 68 } 69 70 nts = append(nts, types.NiceTree{ 71 Name: e.Name, 72 Mode: mode.String(), 73 IsFile: e.Mode.IsFile(), 74 Size: sz, 75 LastCommit: lastCommit, 76 }) 77 78 } 79 80 return nts 81} 82 83var ( 84 TerminateWalk error = errors.New("terminate walk") 85) 86 87type callback = func(node object.TreeEntry, parent *object.Tree, fullPath string) error 88 89func (g *GitRepo) Walk( 90 ctx context.Context, 91 root string, 92 cb callback, 93) error { 94 c, err := g.r.CommitObject(g.h) 95 if err != nil { 96 return fmt.Errorf("commit object: %w", err) 97 } 98 99 tree, err := c.Tree() 100 if err != nil { 101 return fmt.Errorf("file tree: %w", err) 102 } 103 104 subtree := tree 105 if root != "" { 106 subtree, err = tree.Tree(root) 107 if err != nil { 108 return fmt.Errorf("sub tree: %w", err) 109 } 110 } 111 112 return g.walkHelper(ctx, root, subtree, cb) 113} 114 115func (g *GitRepo) walkHelper( 116 ctx context.Context, 117 root string, 118 currentTree *object.Tree, 119 cb callback, 120) error { 121 for _, e := range currentTree.Entries { 122 // check if context hits deadline before processing 123 select { 124 case <-ctx.Done(): 125 return ctx.Err() 126 default: 127 } 128 129 mode, err := e.Mode.ToOSFileMode() 130 if err != nil { 131 // TODO: log this 132 continue 133 } 134 135 if e.Mode.IsFile() { 136 err = cb(e, currentTree, root) 137 if errors.Is(err, TerminateWalk) { 138 return err 139 } 140 } 141 142 // e is a directory 143 if mode.IsDir() { 144 subtree, err := currentTree.Tree(e.Name) 145 if err != nil { 146 return fmt.Errorf("sub tree %s: %w", e.Name, err) 147 } 148 149 fullPath := path.Join(root, e.Name) 150 151 err = g.walkHelper(ctx, fullPath, subtree, cb) 152 if err != nil { 153 return err 154 } 155 } 156 } 157 158 return nil 159}