Attempt conversion to subcommit structure

This commit is contained in:
Nathan McRae 2024-07-12 20:44:07 -07:00
parent 3f49d9f7db
commit fad314edd8

View File

@ -581,13 +581,14 @@ def ls_tree(repo, ref, recursive=None, prefix=""):
type = item.mode[0:2] type = item.mode[0:2]
match type: match type:
case b'04': type = "tree" case b'04': raise Exception("Trees should point to subcommits, not other trees")
case b'10': type = "blob" case b'10': type = "blob"
case b'12': type = "blob" # a symlink case b'12': type = "blob" # a symlink
case b'16': type = "commit" # a submodule case b'16': type = "commit" # a submodule
case b'sc': type = "subcommit"
case _: raise Exception(f"Weird tree leaf mode {item.mode}") case _: raise Exception(f"Weird tree leaf mode {item.mode}")
if not (recursive and type=='tree'): # This is a leaf if not (recursive and type=='subcommit'): # This is a leaf
print("{0} {1} {2}\t{3}".format( print("{0} {1} {2}\t{3}".format(
"0" * (6 - len(item.mode)) + item.mode.decode("ascii"), "0" * (6 - len(item.mode)) + item.mode.decode("ascii"),
# Git's ls-tree displays the type # Git's ls-tree displays the type
@ -596,8 +597,11 @@ def ls_tree(repo, ref, recursive=None, prefix=""):
item.sha, item.sha,
join_path(prefix, item.path) join_path(prefix, item.path)
)) ))
else: # This is a branch (vs. leaf), recurse else: # This is a subcommit
ls_tree(repo, item.sha, recursive, join_path(prefix, item.path)) commit_obj = object_read(repo, item.sha)
tree_sha = commit_obj.kvlm[b'tree'].decode("ascii")
ls_tree(repo, tree_sha, recursive, join_path(prefix, item.path))
argsp = argsubparsers.add_parser("checkout", help="Checkout a commit inside of a directory.") argsp = argsubparsers.add_parser("checkout", help="Checkout a commit inside of a directory.")
@ -1112,13 +1116,19 @@ def tree_to_dict(repo, ref, prefix=""):
# We read the object to extract its type (this is uselessly # We read the object to extract its type (this is uselessly
# expensive: we could just open it as a file and read the # expensive: we could just open it as a file and read the
# first few bytes) # first few bytes)
is_subtree = leaf.mode.startswith(b'04') if (leaf.mode.startswith(b'04')):
raise Exception("Tree should not be child of tree")
is_subcommit = leaf.mode.startswitch(b'sc')
# Depending on the type, we either store the path (if it's a # Depending on the type, we either store the path (if it's a
# blob, so a regular file), or recurse (if it's another tree, # blob, so a regular file), or recurse (if it's another tree,
# so a subdir) # so a subdir)
if is_subtree: if is_subcommit:
ret.update(tree_to_dict(repo, leaf.sha, full_path)) commit_obj = object_read(repo, leaf.sha)
tree_sha = commit_obj.kvlm[b'tree'].decode("ascii")
ret.update(tree_to_dict(repo, tree_sha, full_path))
else: else:
ret[full_path] = leaf.sha ret[full_path] = leaf.sha
@ -1367,7 +1377,42 @@ def gitconfig_user_get(config):
return f"{config['user']['name']} <{config['user']['email']}>" return f"{config['user']['name']} <{config['user']['email']}>"
return None return None
def tree_from_index(repo, index): def create_commit_map(repo, commit):
commit_map = dict()
create_commit_map_recurse(repo, commit, commit_map, "")
return commit_map
def create_commit_map_recurse(repo, commit, commit_map, path):
"""From a root commit, walk down the tree of subcommits. Returns a dict mapping
directory paths to commit objects. Note: doesn't include root commit."""
tree_sha = commit.kvlm["tree"].decode('ascii')
obj = object_read(repo, tree_sha)
for item in obj.items:
if len(item.mode) == 5:
type = item.mode[0:1]
else:
type = item.mode[0:2]
match type:
case b'04': raise Exception("Trees should point to subcommits, not other trees")
case b'10': type = "blob"
case b'12': type = "blob" # a symlink
case b'16': type = "commit" # a submodule
case b'sc': type = "subcommit"
case _: raise Exception(f"Weird tree leaf mode {item.mode}")
if type == "subcommit":
fullpath = f"{path}/{item.path}"
subcommit = object_read(repo, item.sha)
commit_map[fullpath] = subcommit
create_commit_map_recurse(repo, subcommit, commit_map, fullpath)
def tree_from_index(repo, index, commit_map, author, commit_time, message):
contents = dict() contents = dict()
contents[""] = list() contents[""] = list()
@ -1411,6 +1456,15 @@ def tree_from_index(repo, index):
sha = object_write(tree, repo) sha = object_write(tree, repo)
subcommit = commit_map[path]
new_subcommit = commit_create(repo,
sha,
subcommit,
author,
commit_time,
message)
parent = os.path.dirname(path).replace("\\", "/") parent = os.path.dirname(path).replace("\\", "/")
base = os.path.basename(path) base = os.path.basename(path)
contents[parent].append((base, sha)) contents[parent].append((base, sha))
@ -1441,13 +1495,25 @@ def commit_create(repo, tree, parent, author, timestamp, message):
def cmd_commit(args): def cmd_commit(args):
repo = repo_find() repo = repo_find()
index = index_read(repo) index = index_read(repo)
tree = tree_from_index(repo, index) root_commit = object_find(repo, "HEAD")
commit_time = datetime.now()
author = gitconfig_user_get(gitconfig_read())
commit_map = create_commit_map(repo, root_commit)
tree = tree_from_index(repo,
index,
commit_map,
author,
commit_time,
args.message)
commit = commit_create(repo, commit = commit_create(repo,
tree, tree,
object_find(repo, "HEAD"), root_commit,
gitconfig_user_get(gitconfig_read()), author,
datetime.now(), commit_time,
args.message) args.message)
# Update HEAD so our commit is now the tip of the active branch. # Update HEAD so our commit is now the tip of the active branch.