gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // Copyright 2020 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. //go:build !gogit
  4. package git
  5. import (
  6. "io"
  7. "strings"
  8. "code.gitea.io/gitea/modules/git/gitcmd"
  9. )
  10. // Tree represents a flat directory listing.
  11. type Tree struct {
  12. ID ObjectID
  13. ResolvedID ObjectID
  14. repo *Repository
  15. // parent tree
  16. ptree *Tree
  17. entries Entries
  18. entriesParsed bool
  19. entriesRecursive Entries
  20. entriesRecursiveParsed bool
  21. }
  22. // ListEntries returns all entries of current tree.
  23. func (t *Tree) ListEntries() (Entries, error) {
  24. if t.entriesParsed {
  25. return t.entries, nil
  26. }
  27. if t.repo != nil {
  28. wr, rd, cancel, err := t.repo.CatFileBatch(t.repo.Ctx)
  29. if err != nil {
  30. return nil, err
  31. }
  32. defer cancel()
  33. _, _ = wr.Write([]byte(t.ID.String() + "\n"))
  34. _, typ, sz, err := ReadBatchLine(rd)
  35. if err != nil {
  36. return nil, err
  37. }
  38. if typ == "commit" {
  39. treeID, err := ReadTreeID(rd, sz)
  40. if err != nil && err != io.EOF {
  41. return nil, err
  42. }
  43. _, _ = wr.Write([]byte(treeID + "\n"))
  44. _, typ, sz, err = ReadBatchLine(rd)
  45. if err != nil {
  46. return nil, err
  47. }
  48. }
  49. if typ == "tree" {
  50. t.entries, err = catBatchParseTreeEntries(t.ID.Type(), t, rd, sz)
  51. if err != nil {
  52. return nil, err
  53. }
  54. t.entriesParsed = true
  55. return t.entries, nil
  56. }
  57. // Not a tree just use ls-tree instead
  58. if err := DiscardFull(rd, sz+1); err != nil {
  59. return nil, err
  60. }
  61. }
  62. stdout, _, runErr := gitcmd.NewCommand("ls-tree", "-l").AddDynamicArguments(t.ID.String()).RunStdBytes(t.repo.Ctx, &gitcmd.RunOpts{Dir: t.repo.Path})
  63. if runErr != nil {
  64. if strings.Contains(runErr.Error(), "fatal: Not a valid object name") || strings.Contains(runErr.Error(), "fatal: not a tree object") {
  65. return nil, ErrNotExist{
  66. ID: t.ID.String(),
  67. }
  68. }
  69. return nil, runErr
  70. }
  71. var err error
  72. t.entries, err = parseTreeEntries(stdout, t)
  73. if err == nil {
  74. t.entriesParsed = true
  75. }
  76. return t.entries, err
  77. }
  78. // listEntriesRecursive returns all entries of current tree recursively including all subtrees
  79. // extraArgs could be "-l" to get the size, which is slower
  80. func (t *Tree) listEntriesRecursive(extraArgs gitcmd.TrustedCmdArgs) (Entries, error) {
  81. if t.entriesRecursiveParsed {
  82. return t.entriesRecursive, nil
  83. }
  84. stdout, _, runErr := gitcmd.NewCommand("ls-tree", "-t", "-r").
  85. AddArguments(extraArgs...).
  86. AddDynamicArguments(t.ID.String()).
  87. RunStdBytes(t.repo.Ctx, &gitcmd.RunOpts{Dir: t.repo.Path})
  88. if runErr != nil {
  89. return nil, runErr
  90. }
  91. var err error
  92. t.entriesRecursive, err = parseTreeEntries(stdout, t)
  93. if err == nil {
  94. t.entriesRecursiveParsed = true
  95. }
  96. return t.entriesRecursive, err
  97. }
  98. // ListEntriesRecursiveFast returns all entries of current tree recursively including all subtrees, no size
  99. func (t *Tree) ListEntriesRecursiveFast() (Entries, error) {
  100. return t.listEntriesRecursive(nil)
  101. }
  102. // ListEntriesRecursiveWithSize returns all entries of current tree recursively including all subtrees, with size
  103. func (t *Tree) ListEntriesRecursiveWithSize() (Entries, error) {
  104. return t.listEntriesRecursive(gitcmd.TrustedCmdArgs{"--long"})
  105. }