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
diff --git a/bin/soongdbg b/bin/soongdbg
index 6531e1b..c091c97 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 @@
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 @@
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 @@
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 @@
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: