From be952da37044b86032d7c8119c4201288ade2bed Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Fri, 9 Feb 2024 11:43:57 -0800 Subject: [PATCH] Add --svg and --dot args to soongdbg so you don't have to run graphviz by hand Test: soongdbg between --svg ~/Desktop/foo.svg --label '"sdk_version="+.properties.Sdk_version' MODULE_1 MODULE_2 Change-Id: Idf5ee9a3ca2dc4b1fd3aa941fe641225336438fc --- bin/soongdbg | 49 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/bin/soongdbg b/bin/soongdbg index 6531e1b6d..c091c972b 100755 --- a/bin/soongdbg +++ b/bin/soongdbg @@ -3,6 +3,7 @@ import argparse import fnmatch import html +import io import json import os import pathlib @@ -192,14 +193,41 @@ def load_and_filter_modules(args): yield m -def print_nodes(nodes, module_formatter): - print("digraph {") +def print_args(parser): + parser.add_argument("--label", action="append", metavar="JQ_FILTER", + help="jq query for each module metadata") + + group = parser.add_argument_group("output formats", + "If no format is provided, a dot file will be written to" + + " stdout.") + output = group.add_mutually_exclusive_group() + output.add_argument("--dot", type=str, metavar="FILENAME", + help="Write the graph to this file as dot (graphviz format)") + output.add_argument("--svg", type=str, metavar="FILENAME", + help="Write the graph to this file as svg") + + +def print_nodes(args, nodes, module_formatter): + # Generate the graphviz + dot = io.StringIO() + dot.write("digraph {\n") for node in nodes: - print(f"\"{node.id}\"[label={format_node_label(node, module_formatter)}];") + dot.write(f"\"{node.id}\"[label={format_node_label(node, module_formatter)}];\n") for dep in node.deps: if dep in nodes: - print(f"\"{node.id}\" -> \"{dep.id}\";") - print("}") + dot.write(f"\"{node.id}\" -> \"{dep.id}\";\n") + dot.write("}\n") + text = dot.getvalue() + + # Write it somewhere + if args.dot: + with open(args.dot, "w") as f: + f.write(text) + elif args.svg: + subprocess.run(["dot", "-Tsvg", "-Nshape=box", "-o", args.svg], + input=text, text=True, check=True) + else: + sys.stdout.write(text) def get_deps(nodes, root): @@ -240,12 +268,12 @@ class BetweenCommand: def args(self, parser): parser.add_argument("module", nargs=2, help="the two modules") - parser.add_argument("--label", action="append", - help="jq query for each module metadata") + print_args(parser) def run(self, args): graph = load_graph() - print_nodes(graph.find_paths(args.module[0], args.module[1]), new_module_formatter(args)) + print_nodes(args, graph.find_paths(args.module[0], args.module[1]), + new_module_formatter(args)) class DepsCommand: @@ -254,8 +282,7 @@ class DepsCommand: def args(self, parser): parser.add_argument("module", nargs="+", help="Module to print dependencies of") - parser.add_argument("--label", action="append", - help="jq query for each module metadata") + print_args(parser) def run(self, args): graph = load_graph() @@ -270,7 +297,7 @@ class DepsCommand: get_deps(nodes, root) if err: sys.exit(1) - print_nodes(nodes, new_module_formatter(args)) + print_nodes(args, nodes, new_module_formatter(args)) class IdCommand: