Skip to content

Latest commit

 

History

History
 
 

guppy

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

guppy

Build Status

Track and query Cargo dependency graphs.

guppy provides a Rust interface to run queries over Cargo dependency graphs. guppy parses the output of cargo metadata, then presents a graph interface over it.

Usage

Add the following to Cargo.toml:

[dependencies]
guppy = "0.1"

Examples

Print out all direct and transitive dependencies of a package:

use guppy::graph::PackageGraph;
use cargo_metadata::PackageId;
use std::iter;

// `guppy` accepts `cargo metadata` JSON output. Use a pre-existing fixture for these examples.
let fixture = include_str!("../fixtures/metadata1.json");
let package_graph = PackageGraph::from_json(fixture).unwrap();

// `guppy` provides several ways to get hold of package IDs. Use a pre-defined one for this
// example.
let package_id = PackageId { repr: "testcrate 0.1.0 (path+file:///fakepath/testcrate)".into() };
// dep_links returns all direct dependencies of a package, and it returns `None` if the package
// ID isn't recognized.
for link in package_graph.dep_links(&package_id).unwrap() {
    // A dependency link contains `from`, `to` and `edge`. The edge has information about e.g.
    // whether this is a build dependency.
    println!("direct dependency: {}", link.to.id());
}

// Transitive dependencies are obtained through the `select_` APIs. They are always presented in
// topological order.
let select = package_graph.select_transitive_deps(iter::once(&package_id)).unwrap();
for dep_id in select.into_iter_ids(None) {
    // The select API also has an `into_iter_links()` method which returns links instead of IDs.
    println!("transitive dependency: {}", dep_id);
}

Remove all links that are dev-only, except for links within workspace packages.

use guppy::graph::PackageGraph;

// `guppy` accepts `cargo metadata` JSON output. Use a pre-existing fixture for these examples.
let fixture = include_str!("../fixtures/metadata_libra.json");
let mut package_graph = PackageGraph::from_json(fixture).unwrap();

// `retain_edges` takes a closure that returns `true` if this edge should be kept in the graph.
package_graph.retain_edges(|data, link| {
    // 'data' contains metadata for every package. It isn't used in this example but some
    // complex filters may make use of it.
    if link.from.in_workspace() && link.to.in_workspace() {
        return true;
    }
    !link.edge.dev_only()
});

// Iterate over all links and assert that there are no dev-only links.
for link in package_graph.select_all().into_iter_links(None) {
    if !link.from.in_workspace() || !link.to.in_workspace() {
        assert!(!link.edge.dev_only());
    }
}

Print out a dot graph representing workspace packages, for formatting with graphviz.

use guppy::graph::{DependencyLink, DotWrite, PackageDotVisitor, PackageGraph, PackageMetadata};
use std::fmt;

// `guppy` accepts `cargo metadata` JSON output. Use a pre-existing fixture for these examples.
let fixture = include_str!("../fixtures/metadata_libra.json");
let package_graph = PackageGraph::from_json(fixture).unwrap();

// Non-workspace packages cannot depend on packages within the workspace, so the reverse
// transitive deps of workspace packages are exactly the set of workspace packages.
let select = package_graph
    .select_transitive_reverse_deps(package_graph.workspace().member_ids())
    .unwrap();

// Define a visitor, which specifies what strings to print out for the graph.
struct PackageNameVisitor;

impl PackageDotVisitor for PackageNameVisitor {
    fn visit_package(&self, package: &PackageMetadata, mut f: DotWrite<'_, '_>) -> fmt::Result {
        write!(f, "{}", package.name())
    }

    fn visit_link(&self, link: DependencyLink<'_>, f: DotWrite<'_, '_>) -> fmt::Result {
        // Don't print out anything for links. One could print out e.g. whether this is
        // a dev-only link.
        Ok(())
    }
}

// select.into_dot() implements `std::fmt::Display`, so it can be written out to a file, a
// string, stdout, etc.
let dot_graph = format!("{}", select.into_dot(PackageNameVisitor));

Contributing

See the CONTRIBUTING file for how to help out.

License

This project is available under the terms of either the Apache 2.0 license or the MIT license.