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  }