loading up the forgejo repo on tangled to test page performance
at forgejo 189 lines 4.7 kB view raw
1// Copyright 2015 The Gogs Authors. All rights reserved. 2// Copyright 2019 The Gitea Authors. All rights reserved. 3// SPDX-License-Identifier: MIT 4 5package git 6 7import ( 8 "bytes" 9 "io" 10 "strings" 11) 12 13// Tree represents a flat directory listing. 14type 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// NewTree create a new tree according the repository and tree id 30func NewTree(repo *Repository, id ObjectID) *Tree { 31 return &Tree{ 32 ID: id, 33 repo: repo, 34 } 35} 36 37// ListEntries returns all entries of current tree. 38func (t *Tree) ListEntries() (Entries, error) { 39 if t.entriesParsed { 40 return t.entries, nil 41 } 42 43 if t.repo != nil { 44 wr, rd, cancel, err := t.repo.CatFileBatch(t.repo.Ctx) 45 if err != nil { 46 return nil, err 47 } 48 defer cancel() 49 50 _, _ = wr.Write([]byte(t.ID.String() + "\n")) 51 _, typ, sz, err := ReadBatchLine(rd) 52 if err != nil { 53 return nil, err 54 } 55 if typ == "commit" { 56 treeID, err := ReadTreeID(rd, sz) 57 if err != nil && err != io.EOF { 58 return nil, err 59 } 60 _, _ = wr.Write([]byte(treeID + "\n")) 61 _, typ, sz, err = ReadBatchLine(rd) 62 if err != nil { 63 return nil, err 64 } 65 } 66 if typ == "tree" { 67 t.entries, err = catBatchParseTreeEntries(t.ID.Type(), t, rd, sz) 68 if err != nil { 69 return nil, err 70 } 71 t.entriesParsed = true 72 return t.entries, nil 73 } 74 75 // Not a tree just use ls-tree instead 76 if err := DiscardFull(rd, sz+1); err != nil { 77 return nil, err 78 } 79 } 80 81 stdout, _, runErr := NewCommand(t.repo.Ctx, "ls-tree", "-l").AddDynamicArguments(t.ID.String()).RunStdBytes(&RunOpts{Dir: t.repo.Path}) 82 if runErr != nil { 83 if strings.Contains(runErr.Error(), "fatal: Not a valid object name") || strings.Contains(runErr.Error(), "fatal: not a tree object") { 84 return nil, ErrNotExist{ 85 ID: t.ID.String(), 86 } 87 } 88 return nil, runErr 89 } 90 91 var err error 92 t.entries, err = parseTreeEntries(stdout, t) 93 if err == nil { 94 t.entriesParsed = true 95 } 96 97 return t.entries, err 98} 99 100// listEntriesRecursive returns all entries of current tree recursively including all subtrees 101// extraArgs could be "-l" to get the size, which is slower 102func (t *Tree) listEntriesRecursive(extraArgs TrustedCmdArgs) (Entries, error) { 103 if t.entriesRecursiveParsed { 104 return t.entriesRecursive, nil 105 } 106 107 stdout, _, runErr := NewCommand(t.repo.Ctx, "ls-tree", "-t", "-r"). 108 AddArguments(extraArgs...). 109 AddDynamicArguments(t.ID.String()). 110 RunStdBytes(&RunOpts{Dir: t.repo.Path}) 111 if runErr != nil { 112 return nil, runErr 113 } 114 115 var err error 116 t.entriesRecursive, err = parseTreeEntries(stdout, t) 117 if err == nil { 118 t.entriesRecursiveParsed = true 119 } 120 121 return t.entriesRecursive, err 122} 123 124// ListEntriesRecursiveFast returns all entries of current tree recursively including all subtrees, no size 125func (t *Tree) ListEntriesRecursiveFast() (Entries, error) { 126 return t.listEntriesRecursive(nil) 127} 128 129// ListEntriesRecursiveWithSize returns all entries of current tree recursively including all subtrees, with size 130func (t *Tree) ListEntriesRecursiveWithSize() (Entries, error) { 131 return t.listEntriesRecursive(TrustedCmdArgs{"--long"}) 132} 133 134// SubTree get a sub tree by the sub dir path 135func (t *Tree) SubTree(rpath string) (*Tree, error) { 136 if len(rpath) == 0 { 137 return t, nil 138 } 139 140 paths := strings.Split(rpath, "/") 141 var ( 142 err error 143 g = t 144 p = t 145 te *TreeEntry 146 ) 147 for _, name := range paths { 148 te, err = p.GetTreeEntryByPath(name) 149 if err != nil { 150 return nil, err 151 } 152 153 g, err = t.repo.getTree(te.ID) 154 if err != nil { 155 return nil, err 156 } 157 g.ptree = p 158 p = g 159 } 160 return g, nil 161} 162 163// LsTree checks if the given filenames are in the tree 164func (repo *Repository) LsTree(ref string, filenames ...string) ([]string, error) { 165 cmd := NewCommand(repo.Ctx, "ls-tree", "-z", "--name-only"). 166 AddDashesAndList(append([]string{ref}, filenames...)...) 167 168 res, _, err := cmd.RunStdBytes(&RunOpts{Dir: repo.Path}) 169 if err != nil { 170 return nil, err 171 } 172 filelist := make([]string, 0, len(filenames)) 173 for _, line := range bytes.Split(res, []byte{'\000'}) { 174 filelist = append(filelist, string(line)) 175 } 176 177 return filelist, err 178} 179 180// GetTreePathLatestCommitID returns the latest commit of a tree path 181func (repo *Repository) GetTreePathLatestCommit(refName, treePath string) (*Commit, error) { 182 stdout, _, err := NewCommand(repo.Ctx, "rev-list", "-1"). 183 AddDynamicArguments(refName).AddDashesAndList(treePath). 184 RunStdString(&RunOpts{Dir: repo.Path}) 185 if err != nil { 186 return nil, err 187 } 188 return repo.GetCommit(strings.TrimSpace(stdout)) 189}