tree.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. package object
  2. import (
  3. "bufio"
  4. "context"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "path"
  9. "path/filepath"
  10. "strings"
  11. "gopkg.in/src-d/go-git.v4/plumbing"
  12. "gopkg.in/src-d/go-git.v4/plumbing/filemode"
  13. "gopkg.in/src-d/go-git.v4/plumbing/storer"
  14. "gopkg.in/src-d/go-git.v4/utils/ioutil"
  15. )
  16. const (
  17. maxTreeDepth = 1024
  18. startingStackSize = 8
  19. )
  20. // New errors defined by this package.
  21. var (
  22. ErrMaxTreeDepth = errors.New("maximum tree depth exceeded")
  23. ErrFileNotFound = errors.New("file not found")
  24. ErrDirectoryNotFound = errors.New("directory not found")
  25. ErrEntryNotFound = errors.New("entry not found")
  26. )
  27. // Tree is basically like a directory - it references a bunch of other trees
  28. // and/or blobs (i.e. files and sub-directories)
  29. type Tree struct {
  30. Entries []TreeEntry
  31. Hash plumbing.Hash
  32. s storer.EncodedObjectStorer
  33. m map[string]*TreeEntry
  34. t map[string]*Tree // tree path cache
  35. }
  36. // GetTree gets a tree from an object storer and decodes it.
  37. func GetTree(s storer.EncodedObjectStorer, h plumbing.Hash) (*Tree, error) {
  38. o, err := s.EncodedObject(plumbing.TreeObject, h)
  39. if err != nil {
  40. return nil, err
  41. }
  42. return DecodeTree(s, o)
  43. }
  44. // DecodeTree decodes an encoded object into a *Tree and associates it to the
  45. // given object storer.
  46. func DecodeTree(s storer.EncodedObjectStorer, o plumbing.EncodedObject) (*Tree, error) {
  47. t := &Tree{s: s}
  48. if err := t.Decode(o); err != nil {
  49. return nil, err
  50. }
  51. return t, nil
  52. }
  53. // TreeEntry represents a file
  54. type TreeEntry struct {
  55. Name string
  56. Mode filemode.FileMode
  57. Hash plumbing.Hash
  58. }
  59. // File returns the hash of the file identified by the `path` argument.
  60. // The path is interpreted as relative to the tree receiver.
  61. func (t *Tree) File(path string) (*File, error) {
  62. e, err := t.FindEntry(path)
  63. if err != nil {
  64. return nil, ErrFileNotFound
  65. }
  66. blob, err := GetBlob(t.s, e.Hash)
  67. if err != nil {
  68. if err == plumbing.ErrObjectNotFound {
  69. return nil, ErrFileNotFound
  70. }
  71. return nil, err
  72. }
  73. return NewFile(path, e.Mode, blob), nil
  74. }
  75. // Size returns the plaintext size of an object, without reading it
  76. // into memory.
  77. func (t *Tree) Size(path string) (int64, error) {
  78. e, err := t.FindEntry(path)
  79. if err != nil {
  80. return 0, ErrEntryNotFound
  81. }
  82. return t.s.EncodedObjectSize(e.Hash)
  83. }
  84. // Tree returns the tree identified by the `path` argument.
  85. // The path is interpreted as relative to the tree receiver.
  86. func (t *Tree) Tree(path string) (*Tree, error) {
  87. e, err := t.FindEntry(path)
  88. if err != nil {
  89. return nil, ErrDirectoryNotFound
  90. }
  91. tree, err := GetTree(t.s, e.Hash)
  92. if err == plumbing.ErrObjectNotFound {
  93. return nil, ErrDirectoryNotFound
  94. }
  95. return tree, err
  96. }
  97. // TreeEntryFile returns the *File for a given *TreeEntry.
  98. func (t *Tree) TreeEntryFile(e *TreeEntry) (*File, error) {
  99. blob, err := GetBlob(t.s, e.Hash)
  100. if err != nil {
  101. return nil, err
  102. }
  103. return NewFile(e.Name, e.Mode, blob), nil
  104. }
  105. // FindEntry search a TreeEntry in this tree or any subtree.
  106. func (t *Tree) FindEntry(path string) (*TreeEntry, error) {
  107. if t.t == nil {
  108. t.t = make(map[string]*Tree)
  109. }
  110. pathParts := strings.Split(path, "/")
  111. startingTree := t
  112. pathCurrent := ""
  113. // search for the longest path in the tree path cache
  114. for i := len(pathParts); i > 1; i-- {
  115. path := filepath.Join(pathParts[:i]...)
  116. tree, ok := t.t[path]
  117. if ok {
  118. startingTree = tree
  119. pathParts = pathParts[i:]
  120. pathCurrent = path
  121. break
  122. }
  123. }
  124. var tree *Tree
  125. var err error
  126. for tree = startingTree; len(pathParts) > 1; pathParts = pathParts[1:] {
  127. if tree, err = tree.dir(pathParts[0]); err != nil {
  128. return nil, err
  129. }
  130. pathCurrent = filepath.Join(pathCurrent, pathParts[0])
  131. t.t[pathCurrent] = tree
  132. }
  133. return tree.entry(pathParts[0])
  134. }
  135. func (t *Tree) dir(baseName string) (*Tree, error) {
  136. entry, err := t.entry(baseName)
  137. if err != nil {
  138. return nil, ErrDirectoryNotFound
  139. }
  140. obj, err := t.s.EncodedObject(plumbing.TreeObject, entry.Hash)
  141. if err != nil {
  142. return nil, err
  143. }
  144. tree := &Tree{s: t.s}
  145. err = tree.Decode(obj)
  146. return tree, err
  147. }
  148. func (t *Tree) entry(baseName string) (*TreeEntry, error) {
  149. if t.m == nil {
  150. t.buildMap()
  151. }
  152. entry, ok := t.m[baseName]
  153. if !ok {
  154. return nil, ErrEntryNotFound
  155. }
  156. return entry, nil
  157. }
  158. // Files returns a FileIter allowing to iterate over the Tree
  159. func (t *Tree) Files() *FileIter {
  160. return NewFileIter(t.s, t)
  161. }
  162. // ID returns the object ID of the tree. The returned value will always match
  163. // the current value of Tree.Hash.
  164. //
  165. // ID is present to fulfill the Object interface.
  166. func (t *Tree) ID() plumbing.Hash {
  167. return t.Hash
  168. }
  169. // Type returns the type of object. It always returns plumbing.TreeObject.
  170. func (t *Tree) Type() plumbing.ObjectType {
  171. return plumbing.TreeObject
  172. }
  173. // Decode transform an plumbing.EncodedObject into a Tree struct
  174. func (t *Tree) Decode(o plumbing.EncodedObject) (err error) {
  175. if o.Type() != plumbing.TreeObject {
  176. return ErrUnsupportedObject
  177. }
  178. t.Hash = o.Hash()
  179. if o.Size() == 0 {
  180. return nil
  181. }
  182. t.Entries = nil
  183. t.m = nil
  184. reader, err := o.Reader()
  185. if err != nil {
  186. return err
  187. }
  188. defer ioutil.CheckClose(reader, &err)
  189. r := bufio.NewReader(reader)
  190. for {
  191. str, err := r.ReadString(' ')
  192. if err != nil {
  193. if err == io.EOF {
  194. break
  195. }
  196. return err
  197. }
  198. str = str[:len(str)-1] // strip last byte (' ')
  199. mode, err := filemode.New(str)
  200. if err != nil {
  201. return err
  202. }
  203. name, err := r.ReadString(0)
  204. if err != nil && err != io.EOF {
  205. return err
  206. }
  207. var hash plumbing.Hash
  208. if _, err = io.ReadFull(r, hash[:]); err != nil {
  209. return err
  210. }
  211. baseName := name[:len(name)-1]
  212. t.Entries = append(t.Entries, TreeEntry{
  213. Hash: hash,
  214. Mode: mode,
  215. Name: baseName,
  216. })
  217. }
  218. return nil
  219. }
  220. // Encode transforms a Tree into a plumbing.EncodedObject.
  221. func (t *Tree) Encode(o plumbing.EncodedObject) (err error) {
  222. o.SetType(plumbing.TreeObject)
  223. w, err := o.Writer()
  224. if err != nil {
  225. return err
  226. }
  227. defer ioutil.CheckClose(w, &err)
  228. for _, entry := range t.Entries {
  229. if _, err = fmt.Fprintf(w, "%o %s", entry.Mode, entry.Name); err != nil {
  230. return err
  231. }
  232. if _, err = w.Write([]byte{0x00}); err != nil {
  233. return err
  234. }
  235. if _, err = w.Write([]byte(entry.Hash[:])); err != nil {
  236. return err
  237. }
  238. }
  239. return err
  240. }
  241. func (t *Tree) buildMap() {
  242. t.m = make(map[string]*TreeEntry)
  243. for i := 0; i < len(t.Entries); i++ {
  244. t.m[t.Entries[i].Name] = &t.Entries[i]
  245. }
  246. }
  247. // Diff returns a list of changes between this tree and the provided one
  248. func (from *Tree) Diff(to *Tree) (Changes, error) {
  249. return DiffTree(from, to)
  250. }
  251. // Diff returns a list of changes between this tree and the provided one
  252. // Error will be returned if context expires
  253. // Provided context must be non nil
  254. func (from *Tree) DiffContext(ctx context.Context, to *Tree) (Changes, error) {
  255. return DiffTreeContext(ctx, from, to)
  256. }
  257. // Patch returns a slice of Patch objects with all the changes between trees
  258. // in chunks. This representation can be used to create several diff outputs.
  259. func (from *Tree) Patch(to *Tree) (*Patch, error) {
  260. return from.PatchContext(context.Background(), to)
  261. }
  262. // Patch returns a slice of Patch objects with all the changes between trees
  263. // in chunks. This representation can be used to create several diff outputs.
  264. // If context expires, an error will be returned
  265. // Provided context must be non-nil
  266. func (from *Tree) PatchContext(ctx context.Context, to *Tree) (*Patch, error) {
  267. changes, err := DiffTreeContext(ctx, from, to)
  268. if err != nil {
  269. return nil, err
  270. }
  271. return changes.PatchContext(ctx)
  272. }
  273. // treeEntryIter facilitates iterating through the TreeEntry objects in a Tree.
  274. type treeEntryIter struct {
  275. t *Tree
  276. pos int
  277. }
  278. func (iter *treeEntryIter) Next() (TreeEntry, error) {
  279. if iter.pos >= len(iter.t.Entries) {
  280. return TreeEntry{}, io.EOF
  281. }
  282. iter.pos++
  283. return iter.t.Entries[iter.pos-1], nil
  284. }
  285. // TreeWalker provides a means of walking through all of the entries in a Tree.
  286. type TreeWalker struct {
  287. stack []*treeEntryIter
  288. base string
  289. recursive bool
  290. seen map[plumbing.Hash]bool
  291. s storer.EncodedObjectStorer
  292. t *Tree
  293. }
  294. // NewTreeWalker returns a new TreeWalker for the given tree.
  295. //
  296. // It is the caller's responsibility to call Close() when finished with the
  297. // tree walker.
  298. func NewTreeWalker(t *Tree, recursive bool, seen map[plumbing.Hash]bool) *TreeWalker {
  299. stack := make([]*treeEntryIter, 0, startingStackSize)
  300. stack = append(stack, &treeEntryIter{t, 0})
  301. return &TreeWalker{
  302. stack: stack,
  303. recursive: recursive,
  304. seen: seen,
  305. s: t.s,
  306. t: t,
  307. }
  308. }
  309. // Next returns the next object from the tree. Objects are returned in order
  310. // and subtrees are included. After the last object has been returned further
  311. // calls to Next() will return io.EOF.
  312. //
  313. // In the current implementation any objects which cannot be found in the
  314. // underlying repository will be skipped automatically. It is possible that this
  315. // may change in future versions.
  316. func (w *TreeWalker) Next() (name string, entry TreeEntry, err error) {
  317. var obj Object
  318. for {
  319. current := len(w.stack) - 1
  320. if current < 0 {
  321. // Nothing left on the stack so we're finished
  322. err = io.EOF
  323. return
  324. }
  325. if current > maxTreeDepth {
  326. // We're probably following bad data or some self-referencing tree
  327. err = ErrMaxTreeDepth
  328. return
  329. }
  330. entry, err = w.stack[current].Next()
  331. if err == io.EOF {
  332. // Finished with the current tree, move back up to the parent
  333. w.stack = w.stack[:current]
  334. w.base, _ = path.Split(w.base)
  335. w.base = path.Clean(w.base) // Remove trailing slash
  336. continue
  337. }
  338. if err != nil {
  339. return
  340. }
  341. if w.seen[entry.Hash] {
  342. continue
  343. }
  344. if entry.Mode == filemode.Dir {
  345. obj, err = GetTree(w.s, entry.Hash)
  346. }
  347. name = path.Join(w.base, entry.Name)
  348. if err != nil {
  349. err = io.EOF
  350. return
  351. }
  352. break
  353. }
  354. if !w.recursive {
  355. return
  356. }
  357. if t, ok := obj.(*Tree); ok {
  358. w.stack = append(w.stack, &treeEntryIter{t, 0})
  359. w.base = path.Join(w.base, entry.Name)
  360. }
  361. return
  362. }
  363. // Tree returns the tree that the tree walker most recently operated on.
  364. func (w *TreeWalker) Tree() *Tree {
  365. current := len(w.stack) - 1
  366. if w.stack[current].pos == 0 {
  367. current--
  368. }
  369. if current < 0 {
  370. return nil
  371. }
  372. return w.stack[current].t
  373. }
  374. // Close releases any resources used by the TreeWalker.
  375. func (w *TreeWalker) Close() {
  376. w.stack = nil
  377. }
  378. // TreeIter provides an iterator for a set of trees.
  379. type TreeIter struct {
  380. storer.EncodedObjectIter
  381. s storer.EncodedObjectStorer
  382. }
  383. // NewTreeIter takes a storer.EncodedObjectStorer and a
  384. // storer.EncodedObjectIter and returns a *TreeIter that iterates over all
  385. // tree contained in the storer.EncodedObjectIter.
  386. //
  387. // Any non-tree object returned by the storer.EncodedObjectIter is skipped.
  388. func NewTreeIter(s storer.EncodedObjectStorer, iter storer.EncodedObjectIter) *TreeIter {
  389. return &TreeIter{iter, s}
  390. }
  391. // Next moves the iterator to the next tree and returns a pointer to it. If
  392. // there are no more trees, it returns io.EOF.
  393. func (iter *TreeIter) Next() (*Tree, error) {
  394. for {
  395. obj, err := iter.EncodedObjectIter.Next()
  396. if err != nil {
  397. return nil, err
  398. }
  399. if obj.Type() != plumbing.TreeObject {
  400. continue
  401. }
  402. return DecodeTree(iter.s, obj)
  403. }
  404. }
  405. // ForEach call the cb function for each tree contained on this iter until
  406. // an error happens or the end of the iter is reached. If ErrStop is sent
  407. // the iteration is stop but no error is returned. The iterator is closed.
  408. func (iter *TreeIter) ForEach(cb func(*Tree) error) error {
  409. return iter.EncodedObjectIter.ForEach(func(obj plumbing.EncodedObject) error {
  410. if obj.Type() != plumbing.TreeObject {
  411. return nil
  412. }
  413. t, err := DecodeTree(iter.s, obj)
  414. if err != nil {
  415. return err
  416. }
  417. return cb(t)
  418. })
  419. }