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