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