This is looking like a much better implementation of what has been hacked together so far. The only concern is storing timings output cleanly, but I think guppy's architecture will make it easier!
ZPFD3275NTWST7F5YCWYOOUS3QB5HE23LUOZXZIND4HBFSX62NCQC
#[derive(Clone, Debug)]
struct CrateMetadata<'metadata> {
data: &'metadata cargo_metadata::Metadata,
packages: &'metadata Vec<Node>,
root: &'metadata PackageId,
dependency_tree: Graph<&'metadata PackageId, usize>,
}
impl<'metadata> CrateMetadata<'metadata> {
fn new(metadata: &'metadata cargo_metadata::Metadata) -> Self {
let resolve = metadata
.resolve
.as_ref()
.expect("Cargo did not resolve dependencies");
let root = resolve.root.as_ref().expect("Must select a root crate");
let edge_count = resolve.nodes.iter().map(|node| node.deps.len()).count();
let mut dependency_tree = Graph::with_capacity(metadata.packages.len(), edge_count);
let mut node_indexes = HashMap::new();
fn graph_data(graph: &PackageGraph) -> charming::series::GraphData {
let categories = vec![charming::series::GraphCategory {
name: String::from("default"),
}];
for node in &metadata.packages {
let node_index = dependency_tree.add_node(&node.id);
node_indexes.insert(&node.id, node_index);
}
for resolved_dependency in &resolve.nodes {
let parent_index = node_indexes.get(&resolved_dependency.id).unwrap();
for child in &resolved_dependency.deps {
let child_index = node_indexes.get(&child.pkg).unwrap();
dependency_tree.add_edge(*parent_index, *child_index, 1);
}
}
Self {
data: metadata,
packages: &resolve.nodes,
root,
dependency_tree,
}
}
fn graph_data(&self) -> charming::series::GraphData {
let categories = vec![charming::series::GraphCategory {
name: String::from("default"),
}];
let nodes = self
.dependency_tree
.node_weights()
.enumerate()
.map(|(coords, id)| charming::series::GraphNode {
id: id.to_string(),
name: self.data[*id].name.clone(),
x: coords as f64,
y: coords as f64,
value: 1_f64,
category: 0,
symbol_size: 1_f64,
label: None,
})
.collect();
let nodes = graph
.packages()
.enumerate()
.map(|(coords, package)| charming::series::GraphNode {
id: package.id().repr().to_string(),
name: package.name().to_string(),
x: coords as f64,
y: coords as f64,
value: 1_f64,
category: 0,
symbol_size: 1_f64,
label: None,
})
.collect();
let links = self
.dependency_tree
.edge_indices()
.map(|edge_idx| self.dependency_tree.edge_endpoints(edge_idx))
.filter_map(|optional_endpoints| optional_endpoints)
.map(|(source_idx, target_idx)| {
(
&self.dependency_tree[source_idx],
&self.dependency_tree[target_idx],
)
})
.map(|(source, target)| charming::series::GraphLink {
source: source.repr.clone(),
target: target.repr.clone(),
value: None,
})
.collect();
let links = graph
.query_forward(graph.package_ids())
.unwrap()
.resolve()
.links(DependencyDirection::Forward)
.map(|link| link.endpoints())
.map(|(source, target)| charming::series::GraphLink {
source: source.id().repr().to_string(),
target: target.id().repr().to_string(),
value: None,
})
.collect();
let cmd = cargo_metadata::MetadataCommand::new();
let metadata = cmd.exec().expect("Cargo did not resolve metadata");
let root_crate = CrateMetadata::new(&metadata);
let mut cmd = MetadataCommand::new();
let package_graph = PackageGraph::from_command(&mut cmd).unwrap();
[[package]]
name = "getrandom"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "guppy"
version = "0.17.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34e99a7734579b834a076ef11789783c153c6eb5fb3520ed15bc41f483f0f317"
dependencies = [
"ahash",
"camino",
"cargo_metadata",
"cfg-if",
"debug-ignore",
"fixedbitset",
"guppy-workspace-hack",
"indexmap",
"itertools",
"nested",
"once_cell",
"pathdiff",
"petgraph",
"semver",
"serde",
"serde_json",
"smallvec",
"static_assertions",
"target-spec",
]
[[package]]
name = "guppy-workspace-hack"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92620684d99f750bae383ecb3be3748142d6095760afd5cbcf2261e9a279d780"
[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
name = "target-lexicon"
version = "0.12.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f"
[[package]]
name = "target-spec"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36a8e795b1824524d13cdf04f73cf8b4f244ce86c96b4d2a83a6ca1a753d2752"
dependencies = [
"cfg-expr",
"guppy-workspace-hack",
"target-lexicon",
"unicode-ident",
]
[[package]]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "zerocopy"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]