github.com/driusan/dgit@v0.0.0-20221118233547-f39f0c15edbb/git/expandtree.go (about) 1 package git 2 3 import ( 4 "sort" 5 ) 6 7 // Converts a git Tree-ish object to a slice of IndexEntrys. 8 // The most significant difference between trees and indexes are that indexes 9 // have fully expanded paths for all children, while trees only have their direct 10 // descendants available. 11 // 12 // If recurse is true, this will go into subtrees, and if not it will only expand 13 // direct descendants. If showTreeEntry is true, it will include a fake IndexEntry 14 // for the tree object (which is not valid in an index, but useful for commands 15 // like git ls-tree.) 16 // 17 // If treeOnly is true, expandGitTreeIntoIndexes will only retrieve metadata directly in the 18 // tree object, and not other data which is necessary for reading into an index (ie. file 19 // size) 20 func expandGitTreeIntoIndexes(c *Client, tree Treeish, recurse, showTreeEntry, treeOnly bool) ([]*IndexEntry, error) { 21 sha1, err := tree.TreeID(c) 22 if err != nil { 23 return nil, err 24 } 25 t, err := sha1.TreeID(c) 26 if err != nil { 27 return nil, err 28 } 29 30 newEntries, err := expandGitTreeIntoIndexesRecursive(c, t, "", recurse, showTreeEntry, treeOnly) 31 if err != nil { 32 return nil, err 33 } 34 35 sort.Sort(ByPath(newEntries)) 36 return newEntries, nil 37 } 38 39 // This should not be called directly. It recurses into sub-trees to fully expand 40 // all child trees. After calling this function the IndexEntries are *not* sorted 41 // as the git index format requires. 42 func expandGitTreeIntoIndexesRecursive(c *Client, t TreeID, prefix string, recurse bool, showTreeEntry, treeOnly bool) ([]*IndexEntry, error) { 43 vals, err := t.GetAllObjects(c, "", false, showTreeEntry) 44 if err != nil { 45 return nil, err 46 } 47 48 newEntries := make([]*IndexEntry, 0, len(vals)) 49 for path, treeEntry := range vals { 50 var dirname IndexPath 51 if prefix == "" { 52 dirname = path 53 } else { 54 dirname = IndexPath(prefix) + "/" + path 55 } 56 57 if (treeEntry.FileMode.TreeType() != "tree") || showTreeEntry || !recurse { 58 newEntry := IndexEntry{} 59 newEntry.Sha1 = treeEntry.Sha1 60 newEntry.Mode = treeEntry.FileMode 61 newEntry.PathName = dirname 62 63 if !treeOnly { 64 // We need to read the object to see the size. It's 65 // not in the tree. 66 obj, err := c.GetObject(treeEntry.Sha1) 67 if err != nil { 68 return nil, err 69 } 70 newEntry.Fsize = uint32(obj.GetSize()) 71 72 // The git tree object doesn't include the mod time, so 73 // we take the current mtime of the file (if possible) 74 // for the index that we return. 75 if fname, err := dirname.FilePath(c); err != nil { 76 newEntry.Mtime = 0 77 } else if fname.Exists() { 78 if mtime, err := fname.MTime(); err == nil { 79 newEntry.Mtime = mtime 80 } 81 } 82 83 newEntry.FixedIndexEntry.Flags = uint16(len(dirname)) & 0xFFF 84 } 85 newEntries = append(newEntries, &newEntry) 86 } 87 if treeEntry.FileMode.TreeType() == "tree" && recurse { 88 subindexes, err := expandGitTreeIntoIndexesRecursive(c, TreeID(treeEntry.Sha1), dirname.String(), recurse, showTreeEntry, treeOnly) 89 if err != nil { 90 return nil, err 91 } 92 newEntries = append(newEntries, subindexes...) 93 } 94 } 95 return newEntries, nil 96 }