Add graph-objects command

This commit is contained in:
Nathan McRae 2024-07-14 13:28:42 -07:00
parent cc32d87d4d
commit e7838a5294

View File

@ -23,22 +23,23 @@ argsubparsers.required = True
def main(argv=sys.argv[1:]):
args = argparser.parse_args(argv)
match args.command:
case "add" : cmd_add(args)
case "cat-file" : cmd_cat_file(args)
case "check-ignore" : cmd_check_ignore(args)
case "checkout" : cmd_checkout(args)
case "commit" : cmd_commit(args)
case "hash-object" : cmd_hash_object(args)
case "init" : cmd_init(args)
case "log" : cmd_log(args)
case "ls-files" : cmd_ls_files(args)
case "ls-tree" : cmd_ls_tree(args)
case "rev-parse" : cmd_rev_parse(args)
case "rm" : cmd_rm(args)
case "show-ref" : cmd_show_ref(args)
case "status" : cmd_status(args)
case "tag" : cmd_tag(args)
case _ : print("Bad command.")
case "add" : cmd_add(args)
case "cat-file" : cmd_cat_file(args)
case "check-ignore" : cmd_check_ignore(args)
case "checkout" : cmd_checkout(args)
case "commit" : cmd_commit(args)
case "hash-object" : cmd_hash_object(args)
case "init" : cmd_init(args)
case "log" : cmd_log(args)
case "ls-files" : cmd_ls_files(args)
case "ls-tree" : cmd_ls_tree(args)
case "rev-parse" : cmd_rev_parse(args)
case "rm" : cmd_rm(args)
case "show-ref" : cmd_show_ref(args)
case "status" : cmd_status(args)
case "tag" : cmd_tag(args)
case "graph-objects" : cmd_graph_objects(args)
case _ : print("Bad command.")
class GitRepository (object):
"""A git repo"""
@ -1542,3 +1543,78 @@ def cmd_commit(args):
else: # Otherwise, we update HEAD itself.
with open(repo_file(repo, "HEAD"), "w") as fd:
fd.write(commit + "\n")
argsp = argsubparsers.add_parser("graph-objects", help="Show git objects in a dot graph")
argsp.add_argument("object",
nargs="?",
metavar="object",
help="The object the graph will start from")
def graph_objects_tree(repo, sha, seen):
if sha in seen:
return
seen.append(sha)
yield f"t_{sha} [label=\"tree {sha[0:7]}\"]"
# TODO: inefficient
obj = object_read(repo, 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': type = "tree"
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 == "tree":
yield f"t_{sha} -> t_{item.sha}"
yield from graph_objects_tree(repo, item.sha, seen)
if type == "commit" or type == "subcommit":
yield f"t_{sha} -> c_{item.sha}"
yield from graph_objects(repo, item.sha, seen)
if type == "blob":
yield f"b_{item.sha} [label=\"{item.sha[0:7]} {item.path}\"]"
yield f"t_{sha} -> b_{item.sha}"
def graph_objects(repo, sha, seen):
if sha in seen:
return
seen.append(sha)
obj = object_read(repo, sha)
match obj.fmt:
case b"commit": #
message = obj.kvlm[None]
yield f"c_{sha} [label=\"{sha[0:7]}: {message.decode('utf8')}\"]"
tree_sha = obj.kvlm[b"tree"].decode("ascii")
yield f"c_{sha} -> t_{tree_sha}"
yield from graph_objects_tree(repo, tree_sha, seen)
case b"tree":
yield from graph_objects_tree(repo, sha, seen)
def cmd_graph_objects(args):
repo = repo_find()
if args.object == None:
obj_name = "HEAD"
else:
obj_name = args.object
obj_sha = object_find(repo, obj_name)
graph = "digraph objectgraph{\n"
graph += " node[shape=rect]\n"
for str in graph_objects(repo, obj_sha, list()):
graph += " " + str + "\n"
graph += "}"
print(graph)