github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/git/tree_nogogit.go (about) 1 // Copyright 2023 The GitBundle Inc. All rights reserved. 2 // Copyright 2017 The Gitea Authors. All rights reserved. 3 // Use of this source code is governed by a MIT-style 4 // license that can be found in the LICENSE file. 5 6 //go:build !gogit 7 8 package git 9 10 import ( 11 "io" 12 "math" 13 "strings" 14 ) 15 16 // Tree represents a flat directory listing. 17 type Tree struct { 18 ID SHA1 19 ResolvedID SHA1 20 repo *Repository 21 22 // parent tree 23 ptree *Tree 24 25 entries Entries 26 entriesParsed bool 27 28 entriesRecursive Entries 29 entriesRecursiveParsed bool 30 } 31 32 // ListEntries returns all entries of current tree. 33 func (t *Tree) ListEntries() (Entries, error) { 34 if t.entriesParsed { 35 return t.entries, nil 36 } 37 38 if t.repo != nil { 39 wr, rd, cancel := t.repo.CatFileBatch(t.repo.Ctx) 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, 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 for sz > math.MaxInt32 { 69 discarded, err := rd.Discard(math.MaxInt32) 70 sz -= int64(discarded) 71 if err != nil { 72 return nil, err 73 } 74 } 75 for sz > 0 { 76 discarded, err := rd.Discard(int(sz)) 77 sz -= int64(discarded) 78 if err != nil { 79 return nil, err 80 } 81 } 82 } 83 84 stdout, _, runErr := NewCommand(t.repo.Ctx, "ls-tree", "-l", t.ID.String()).RunStdBytes(&RunOpts{Dir: t.repo.Path}) 85 if runErr != nil { 86 if strings.Contains(runErr.Error(), "fatal: Not a valid object name") || strings.Contains(runErr.Error(), "fatal: not a tree object") { 87 return nil, ErrNotExist{ 88 ID: t.ID.String(), 89 } 90 } 91 return nil, runErr 92 } 93 94 var err error 95 t.entries, err = parseTreeEntries(stdout, t) 96 if err == nil { 97 t.entriesParsed = true 98 } 99 100 return t.entries, err 101 } 102 103 // ListEntriesRecursive returns all entries of current tree recursively including all subtrees 104 func (t *Tree) ListEntriesRecursive() (Entries, error) { 105 if t.entriesRecursiveParsed { 106 return t.entriesRecursive, nil 107 } 108 109 stdout, _, runErr := NewCommand(t.repo.Ctx, "ls-tree", "-t", "-l", "-r", t.ID.String()).RunStdBytes(&RunOpts{Dir: t.repo.Path}) 110 if runErr != nil { 111 return nil, runErr 112 } 113 114 var err error 115 t.entriesRecursive, err = parseTreeEntries(stdout, t) 116 if err == nil { 117 t.entriesRecursiveParsed = true 118 } 119 120 return t.entriesRecursive, err 121 }