diff --git a/doc/how-to-guides.adoc b/doc/how-to-guides.adoc index aae382c..4e06a9c 100644 --- a/doc/how-to-guides.adoc +++ b/doc/how-to-guides.adoc @@ -93,6 +93,9 @@ wit inspect --dot | dot -Tsvg > graph.svg This SVG file can be directly viewed in most web browsers. +There is also a `--simple` option for `--dot` mode, which constructs a simpler +version of the graph. + == Restore a previous workspace diff --git a/lib/wit/inspect.py b/lib/wit/inspect.py index ef1bec9..c131d5a 100644 --- a/lib/wit/inspect.py +++ b/lib/wit/inspect.py @@ -1,6 +1,7 @@ import sys from .common import print_errors from .witlogger import getLogger +from .workspace import WorkSpace log = getLogger() @@ -18,7 +19,10 @@ def inspect_tree(ws, args): _print_generic_tree(x) if args.dot: - _print_dot_tree(ws, packages) + if args.simple: + _print_simple_dot_tree(ws, packages) + else: + _print_dot_tree(ws, packages) print_errors(errors) @@ -91,6 +95,58 @@ def print_dep(pkg, dep): log.output('}') +def _print_simple_dot_tree(ws, packages_dict): + # This algorithm is based on the normal one except we identify nodes based + # on just the package name and not the revision. + packages = list(packages_dict.values()) + + def sanitize(s): + return s.replace(r"-", "_") + + nodes = set() + for pkg in packages: + nodes.add(sanitize(pkg.name)) + + drawn_connections = set() + + def draw_connection(from_id, to_id): + if from_id == to_id: + return + pair = (from_id, to_id) + if pair not in drawn_connections: + drawn_connections.add(pair) + + def print_dep(pkg, dep): + if isinstance(pkg, WorkSpace): + pkg_name = "root" + else: + pkg_name = sanitize(pkg.name) + dep_name = sanitize(dep.name) + dep.load(packages_dict, ws.repo_paths, ws.root, False) + if dep.package.repo is None: + log.error("Cannot generate graph with missing repo '{}'".format(dep.name)) + sys.exit(1) + draw_connection(pkg_name, dep_name) + + for dep in ws.manifest.dependencies: + print_dep(ws, dep) + + for pkg in packages: + for dep in pkg.get_dependencies(): + print_dep(pkg, dep) + + log.output('digraph dependencies {') + log.output('root [label="[root]"]') + + for node in sorted(nodes): + log.output('{} [label="{}"]'.format(node, node)) + + for from_id, to_id in sorted(drawn_connections): + log.output("{} -> {}".format(from_id, to_id)) + + log.output('}') + + def _print_generic_tree(data): tag = data.pop('') print(tag) diff --git a/lib/wit/main.py b/lib/wit/main.py index a45a2dd..6d01d0e 100644 --- a/lib/wit/main.py +++ b/lib/wit/main.py @@ -108,7 +108,7 @@ def main() -> None: if args.dot or args.tree: inspect_tree(ws, args) else: - log.error('`wit inspect` must be run with a flag') + log.error('`wit inspect` must be run with --dot or --tree') print(parser.parse_args('inspect -h'.split())) sys.exit(1) except WitUserError as e: diff --git a/lib/wit/parser.py b/lib/wit/parser.py index ae441fd..6180c06 100644 --- a/lib/wit/parser.py +++ b/lib/wit/parser.py @@ -117,6 +117,13 @@ def err(msg): inspect_group = inspect_parser.add_mutually_exclusive_group() inspect_group.add_argument('--tree', action="store_true") inspect_group.add_argument('--dot', action="store_true") +# Common to all +inspect_parser.add_argument( + '--simple', + action='store_true', + help='Print simple view. When used with --dot, this will collapse all versions of a dependency' + ' into a single node.' +) # ********** foreach subparser ********** foreach_parser = subparsers.add_parser(