本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

521 lines
12KB

  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) - 1; 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 := bufPool.Get().(*bufio.Reader)
  190. defer bufPool.Put(r)
  191. r.Reset(reader)
  192. for {
  193. str, err := r.ReadString(' ')
  194. if err != nil {
  195. if err == io.EOF {
  196. break
  197. }
  198. return err
  199. }
  200. str = str[:len(str)-1] // strip last byte (' ')
  201. mode, err := filemode.New(str)
  202. if err != nil {
  203. return err
  204. }
  205. name, err := r.ReadString(0)
  206. if err != nil && err != io.EOF {
  207. return err
  208. }
  209. var hash plumbing.Hash
  210. if _, err = io.ReadFull(r, hash[:]); err != nil {
  211. return err
  212. }
  213. baseName := name[:len(name)-1]
  214. t.Entries = append(t.Entries, TreeEntry{
  215. Hash: hash,
  216. Mode: mode,
  217. Name: baseName,
  218. })
  219. }
  220. return nil
  221. }
  222. // Encode transforms a Tree into a plumbing.EncodedObject.
  223. func (t *Tree) Encode(o plumbing.EncodedObject) (err error) {
  224. o.SetType(plumbing.TreeObject)
  225. w, err := o.Writer()
  226. if err != nil {
  227. return err
  228. }
  229. defer ioutil.CheckClose(w, &err)
  230. for _, entry := range t.Entries {
  231. if _, err = fmt.Fprintf(w, "%o %s", entry.Mode, entry.Name); err != nil {
  232. return err
  233. }
  234. if _, err = w.Write([]byte{0x00}); err != nil {
  235. return err
  236. }
  237. if _, err = w.Write(entry.Hash[:]); err != nil {
  238. return err
  239. }
  240. }
  241. return err
  242. }
  243. func (t *Tree) buildMap() {
  244. t.m = make(map[string]*TreeEntry)
  245. for i := 0; i < len(t.Entries); i++ {
  246. t.m[t.Entries[i].Name] = &t.Entries[i]
  247. }
  248. }
  249. // Diff returns a list of changes between this tree and the provided one
  250. func (from *Tree) Diff(to *Tree) (Changes, error) {
  251. return DiffTree(from, to)
  252. }
  253. // Diff returns a list of changes between this tree and the provided one
  254. // Error will be returned if context expires
  255. // Provided context must be non nil
  256. func (from *Tree) DiffContext(ctx context.Context, to *Tree) (Changes, error) {
  257. return DiffTreeContext(ctx, from, to)
  258. }
  259. // Patch returns a slice of Patch objects with all the changes between trees
  260. // in chunks. This representation can be used to create several diff outputs.
  261. func (from *Tree) Patch(to *Tree) (*Patch, error) {
  262. return from.PatchContext(context.Background(), to)
  263. }
  264. // Patch returns a slice of Patch objects with all the changes between trees
  265. // in chunks. This representation can be used to create several diff outputs.
  266. // If context expires, an error will be returned
  267. // Provided context must be non-nil
  268. func (from *Tree) PatchContext(ctx context.Context, to *Tree) (*Patch, error) {
  269. changes, err := DiffTreeContext(ctx, from, to)
  270. if err != nil {
  271. return nil, err
  272. }
  273. return changes.PatchContext(ctx)
  274. }
  275. // treeEntryIter facilitates iterating through the TreeEntry objects in a Tree.
  276. type treeEntryIter struct {
  277. t *Tree
  278. pos int
  279. }
  280. func (iter *treeEntryIter) Next() (TreeEntry, error) {
  281. if iter.pos >= len(iter.t.Entries) {
  282. return TreeEntry{}, io.EOF
  283. }
  284. iter.pos++
  285. return iter.t.Entries[iter.pos-1], nil
  286. }
  287. // TreeWalker provides a means of walking through all of the entries in a Tree.
  288. type TreeWalker struct {
  289. stack []*treeEntryIter
  290. base string
  291. recursive bool
  292. seen map[plumbing.Hash]bool
  293. s storer.EncodedObjectStorer
  294. t *Tree
  295. }
  296. // NewTreeWalker returns a new TreeWalker for the given tree.
  297. //
  298. // It is the caller's responsibility to call Close() when finished with the
  299. // tree walker.
  300. func NewTreeWalker(t *Tree, recursive bool, seen map[plumbing.Hash]bool) *TreeWalker {
  301. stack := make([]*treeEntryIter, 0, startingStackSize)
  302. stack = append(stack, &treeEntryIter{t, 0})
  303. return &TreeWalker{
  304. stack: stack,
  305. recursive: recursive,
  306. seen: seen,
  307. s: t.s,
  308. t: t,
  309. }
  310. }
  311. // Next returns the next object from the tree. Objects are returned in order
  312. // and subtrees are included. After the last object has been returned further
  313. // calls to Next() will return io.EOF.
  314. //
  315. // In the current implementation any objects which cannot be found in the
  316. // underlying repository will be skipped automatically. It is possible that this
  317. // may change in future versions.
  318. func (w *TreeWalker) Next() (name string, entry TreeEntry, err error) {
  319. var obj *Tree
  320. for {
  321. current := len(w.stack) - 1
  322. if current < 0 {
  323. // Nothing left on the stack so we're finished
  324. err = io.EOF
  325. return
  326. }
  327. if current > maxTreeDepth {
  328. // We're probably following bad data or some self-referencing tree
  329. err = ErrMaxTreeDepth
  330. return
  331. }
  332. entry, err = w.stack[current].Next()
  333. if err == io.EOF {
  334. // Finished with the current tree, move back up to the parent
  335. w.stack = w.stack[:current]
  336. w.base, _ = path.Split(w.base)
  337. w.base = strings.TrimSuffix(w.base, "/")
  338. continue
  339. }
  340. if err != nil {
  341. return
  342. }
  343. if w.seen[entry.Hash] {
  344. continue
  345. }
  346. if entry.Mode == filemode.Dir {
  347. obj, err = GetTree(w.s, entry.Hash)
  348. }
  349. name = simpleJoin(w.base, entry.Name)
  350. if err != nil {
  351. err = io.EOF
  352. return
  353. }
  354. break
  355. }
  356. if !w.recursive {
  357. return
  358. }
  359. if obj != nil {
  360. w.stack = append(w.stack, &treeEntryIter{obj, 0})
  361. w.base = simpleJoin(w.base, entry.Name)
  362. }
  363. return
  364. }
  365. // Tree returns the tree that the tree walker most recently operated on.
  366. func (w *TreeWalker) Tree() *Tree {
  367. current := len(w.stack) - 1
  368. if w.stack[current].pos == 0 {
  369. current--
  370. }
  371. if current < 0 {
  372. return nil
  373. }
  374. return w.stack[current].t
  375. }
  376. // Close releases any resources used by the TreeWalker.
  377. func (w *TreeWalker) Close() {
  378. w.stack = nil
  379. }
  380. // TreeIter provides an iterator for a set of trees.
  381. type TreeIter struct {
  382. storer.EncodedObjectIter
  383. s storer.EncodedObjectStorer
  384. }
  385. // NewTreeIter takes a storer.EncodedObjectStorer and a
  386. // storer.EncodedObjectIter and returns a *TreeIter that iterates over all
  387. // tree contained in the storer.EncodedObjectIter.
  388. //
  389. // Any non-tree object returned by the storer.EncodedObjectIter is skipped.
  390. func NewTreeIter(s storer.EncodedObjectStorer, iter storer.EncodedObjectIter) *TreeIter {
  391. return &TreeIter{iter, s}
  392. }
  393. // Next moves the iterator to the next tree and returns a pointer to it. If
  394. // there are no more trees, it returns io.EOF.
  395. func (iter *TreeIter) Next() (*Tree, error) {
  396. for {
  397. obj, err := iter.EncodedObjectIter.Next()
  398. if err != nil {
  399. return nil, err
  400. }
  401. if obj.Type() != plumbing.TreeObject {
  402. continue
  403. }
  404. return DecodeTree(iter.s, obj)
  405. }
  406. }
  407. // ForEach call the cb function for each tree contained on this iter until
  408. // an error happens or the end of the iter is reached. If ErrStop is sent
  409. // the iteration is stop but no error is returned. The iterator is closed.
  410. func (iter *TreeIter) ForEach(cb func(*Tree) error) error {
  411. return iter.EncodedObjectIter.ForEach(func(obj plumbing.EncodedObject) error {
  412. if obj.Type() != plumbing.TreeObject {
  413. return nil
  414. }
  415. t, err := DecodeTree(iter.s, obj)
  416. if err != nil {
  417. return err
  418. }
  419. return cb(t)
  420. })
  421. }
  422. func simpleJoin(parent, child string) string {
  423. if len(parent) > 0 {
  424. return parent + "/" + child
  425. }
  426. return child
  427. }
上海开阖软件有限公司 沪ICP备12045867号-1