From d2041e5b47d5eb239d55b71ef93c3ec3d468e508 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 21 Apr 2020 10:46:36 +0200 Subject: [PATCH] Add a minimal alternative to `cargo graph` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I tried `cargo graph` and some of its successors, but didn’t manage to make them produce what I wanted (or in some cases make them work at all.) This Python script reimplements similar functionality based on parsing the (JSON) output of `cargo metadata`. Graphviz graphs can become hard to read very quickly as the number of nodes grows. Servo’s dependency graph is very large, so pruning as much as possible is important. This only shows `path` dependencies (that have their source in this repo), and can take a parameter to only show recursive dependencies of a given crate. See https://github.com/servo/servo/issues/19422#issuecomment-617038366 for an example. I find that `xdot` is best for visualization since it is interactive. This script is not used by anything. I am making this PR only so that we have it somewhere in case it becomes useful again at some point. --- etc/crates-graph.py | 51 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100755 etc/crates-graph.py diff --git a/etc/crates-graph.py b/etc/crates-graph.py new file mode 100755 index 000000000000..7970c94119ee --- /dev/null +++ b/etc/crates-graph.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +# Copyright 2013 The Servo Project Developers. See the COPYRIGHT +# file at the top-level directory of this distribution. +# +# Licensed under the Apache License, Version 2.0 or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +import json +import os +import subprocess +import sys + + +def main(crate=None): + os.chdir(os.path.join(os.path.dirname(__file__), "..")) + meta = json.loads(subprocess.check_output(["cargo", "metadata", "--format-version", "1"])) + graph = {} + for package in meta["packages"]: + if package["source"] is None: # Lives in this repo + for dependency in package["dependencies"]: + if dependency["source"] is None: # Also lives in this repo + graph.setdefault(package["name"], []).append(dependency["name"]) + + if crate: + filtered = {} + seen = set() + + def traverse(name): + if name not in seen: + seen.add(name) + for dependency in graph.get(name, []): + filtered.setdefault(name, []).append(dependency) + traverse(dependency) + traverse(crate) + else: + filtered = graph + print("// This is in Graphviz DOT format.") + print("// Use the 'dot' or 'xdot' tool to visualize.") + print('digraph "local crates" {') + for package, dependencies in filtered.items(): + for dependency in dependencies: + print(' "%s" -> "%s";' % (package, dependency)) + print("}") + + +if __name__ == "__main__": + sys.exit(main(*sys.argv[1:]))