Skip to content

Commit

Permalink
Auto merge of #26241 - servo:graph, r=nox
Browse files Browse the repository at this point in the history
Add a minimal alternative to `cargo graph`

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 #19422 (comment) 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.
  • Loading branch information
bors-servo committed Apr 21, 2020
2 parents 354001a + d2041e5 commit b60c70b
Showing 1 changed file with 51 additions and 0 deletions.
51 changes: 51 additions & 0 deletions 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 <LICENSE-APACHE or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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:]))

0 comments on commit b60c70b

Please sign in to comment.