From 96a393719b855989ff63eaa563884d4fc44d8eff Mon Sep 17 00:00:00 2001
From: Eric Huss
Date: Thu, 19 Mar 2020 10:51:25 -0700
Subject: [PATCH 01/14] Add `cargo tree` command.
---
src/bin/cargo/commands/mod.rs | 3 +
src/bin/cargo/commands/tree.rs | 84 ++
src/cargo/core/compiler/build_config.rs | 20 +-
src/cargo/core/compiler/compile_kind.rs | 27 +
src/cargo/core/profiles.rs | 6 +-
src/cargo/core/resolver/features.rs | 12 +-
src/cargo/core/resolver/resolve.rs | 4 +
src/cargo/ops/cargo_compile.rs | 22 +-
src/cargo/ops/cargo_doc.rs | 5 +-
src/cargo/ops/mod.rs | 1 +
src/cargo/ops/tree/format/mod.rs | 108 ++
src/cargo/ops/tree/format/parse.rs | 97 ++
src/cargo/ops/tree/graph.rs | 562 +++++++++
src/cargo/ops/tree/mod.rs | 333 +++++
src/cargo/util/command_prelude.rs | 31 +-
src/doc/man/cargo-tree.adoc | 193 +++
src/doc/man/cargo.adoc | 3 +
src/doc/man/generated/cargo-tree.html | 443 +++++++
src/doc/man/generated/cargo.html | 4 +
src/doc/man/options-packages.adoc | 2 +
src/doc/src/SUMMARY.md | 1 +
src/doc/src/commands/cargo-tree.md | 3 +
src/doc/src/commands/manifest-commands.md | 1 +
src/etc/_cargo | 15 +
src/etc/cargo.bashcomp.sh | 1 +
src/etc/man/cargo-tree.1 | 491 ++++++++
src/etc/man/cargo.1 | 9 +-
tests/testsuite/main.rs | 2 +
tests/testsuite/tree.rs | 1371 +++++++++++++++++++++
tests/testsuite/tree_graph_features.rs | 364 ++++++
30 files changed, 4165 insertions(+), 53 deletions(-)
create mode 100644 src/bin/cargo/commands/tree.rs
create mode 100644 src/cargo/ops/tree/format/mod.rs
create mode 100644 src/cargo/ops/tree/format/parse.rs
create mode 100644 src/cargo/ops/tree/graph.rs
create mode 100644 src/cargo/ops/tree/mod.rs
create mode 100644 src/doc/man/cargo-tree.adoc
create mode 100644 src/doc/man/generated/cargo-tree.html
create mode 100644 src/doc/src/commands/cargo-tree.md
create mode 100644 src/etc/man/cargo-tree.1
create mode 100644 tests/testsuite/tree.rs
create mode 100644 tests/testsuite/tree_graph_features.rs
diff --git a/src/bin/cargo/commands/mod.rs b/src/bin/cargo/commands/mod.rs
index 7d4fe68c6e2..2c118f7eb54 100644
--- a/src/bin/cargo/commands/mod.rs
+++ b/src/bin/cargo/commands/mod.rs
@@ -27,6 +27,7 @@ pub fn builtin() -> Vec {
rustdoc::cli(),
search::cli(),
test::cli(),
+ tree::cli(),
uninstall::cli(),
update::cli(),
vendor::cli(),
@@ -63,6 +64,7 @@ pub fn builtin_exec(cmd: &str) -> Option) -> Cli
"rustdoc" => rustdoc::exec,
"search" => search::exec,
"test" => test::exec,
+ "tree" => tree::exec,
"uninstall" => uninstall::exec,
"update" => update::exec,
"vendor" => vendor::exec,
@@ -99,6 +101,7 @@ pub mod rustc;
pub mod rustdoc;
pub mod search;
pub mod test;
+pub mod tree;
pub mod uninstall;
pub mod update;
pub mod vendor;
diff --git a/src/bin/cargo/commands/tree.rs b/src/bin/cargo/commands/tree.rs
new file mode 100644
index 00000000000..b37a7787622
--- /dev/null
+++ b/src/bin/cargo/commands/tree.rs
@@ -0,0 +1,84 @@
+use crate::command_prelude::*;
+use cargo::ops::tree;
+use std::str::FromStr;
+
+pub fn cli() -> App {
+ subcommand("tree")
+ .about("Display a tree visualization of a dependency graph")
+ .arg(opt("quiet", "Suppress status messages").short("q"))
+ .arg_manifest_path()
+ .arg_package_spec_no_all(
+ "Package to be used as the root of the tree",
+ "Display the tree for all packages in the workspace",
+ "Exclude specific workspace members",
+ )
+ .arg_features()
+ .arg_target_triple(
+ "Filter dependencies matching the given target-triple (default host platform)",
+ )
+ .arg(opt(
+ "no-filter-targets",
+ "Return dependencies for all targets",
+ ))
+ .arg(opt("no-dev-dependencies", "Skip dev dependencies"))
+ .arg(opt("invert", "Invert the tree direction").short("i"))
+ .arg(opt(
+ "no-indent",
+ "Display the dependencies as a list (rather than a tree)",
+ ))
+ .arg(opt(
+ "prefix-depth",
+ "Display the dependencies as a list (rather than a tree), but prefixed with the depth",
+ ))
+ .arg(opt(
+ "no-dedupe",
+ "Do not de-duplicate (repeats all shared dependencies)",
+ ))
+ .arg(
+ opt(
+ "duplicates",
+ "Show only dependencies which come in multiple versions (implies -i)",
+ )
+ .short("d")
+ .alias("duplicate"),
+ )
+ .arg(
+ opt("charset", "Character set to use in output: utf8, ascii")
+ .value_name("CHARSET")
+ .possible_values(&["utf8", "ascii"])
+ .default_value("utf8"),
+ )
+ .arg(
+ opt("format", "Format string used for printing dependencies")
+ .value_name("FORMAT")
+ .short("f")
+ .default_value("{p}"),
+ )
+ .arg(opt("graph-features", "Include features in the tree"))
+}
+
+pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
+ let ws = args.workspace(config)?;
+ let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
+ .map_err(|e| anyhow::anyhow!("{}", e))?;
+ let opts = tree::TreeOptions {
+ features: values(args, "features"),
+ all_features: args.is_present("all-features"),
+ no_default_features: args.is_present("no-default-features"),
+ packages: args.packages_from_flags()?,
+ target: args.target(),
+ no_filter_targets: args.is_present("no-filter-targets"),
+ no_dev_dependencies: args.is_present("no-dev-dependencies"),
+ invert: args.is_present("invert"),
+ no_indent: args.is_present("no-indent"),
+ prefix_depth: args.is_present("prefix-depth"),
+ no_dedupe: args.is_present("no-dedupe"),
+ duplicates: args.is_present("duplicates"),
+ charset,
+ format: args.value_of("format").unwrap().to_string(),
+ graph_features: args.is_present("graph-features"),
+ };
+
+ tree::build_and_print(&ws, &opts)?;
+ Ok(())
+}
diff --git a/src/cargo/core/compiler/build_config.rs b/src/cargo/core/compiler/build_config.rs
index 8df5db2f71f..77b7810a594 100644
--- a/src/cargo/core/compiler/build_config.rs
+++ b/src/cargo/core/compiler/build_config.rs
@@ -1,4 +1,4 @@
-use crate::core::compiler::{CompileKind, CompileTarget};
+use crate::core::compiler::CompileKind;
use crate::core::interning::InternedString;
use crate::util::ProcessBuilder;
use crate::util::{CargoResult, Config, RustfixDiagnosticServer};
@@ -45,22 +45,8 @@ impl BuildConfig {
mode: CompileMode,
) -> CargoResult {
let cfg = config.build_config()?;
- let requested_kind = match requested_target {
- Some(s) => CompileKind::Target(CompileTarget::new(s)?),
- None => match &cfg.target {
- Some(val) => {
- let value = if val.raw_value().ends_with(".json") {
- let path = val.clone().resolve_path(config);
- path.to_str().expect("must be utf-8 in toml").to_string()
- } else {
- val.raw_value().to_string()
- };
- CompileKind::Target(CompileTarget::new(&value)?)
- }
- None => CompileKind::Host,
- },
- };
-
+ let requested_kind =
+ CompileKind::from_requested_target(config, requested_target.as_deref())?;
if jobs == Some(0) {
anyhow::bail!("jobs must be at least 1")
}
diff --git a/src/cargo/core/compiler/compile_kind.rs b/src/cargo/core/compiler/compile_kind.rs
index 4ef30039da7..fd5537b4abb 100644
--- a/src/cargo/core/compiler/compile_kind.rs
+++ b/src/cargo/core/compiler/compile_kind.rs
@@ -1,5 +1,6 @@
use crate::core::{InternedString, Target};
use crate::util::errors::{CargoResult, CargoResultExt};
+use crate::util::Config;
use serde::Serialize;
use std::path::Path;
@@ -39,6 +40,32 @@ impl CompileKind {
CompileKind::Target(n) => CompileKind::Target(n),
}
}
+
+ /// Creates a new `CompileKind` based on the requested target.
+ ///
+ /// If no target is given, this consults the config if the default is set.
+ /// Otherwise returns `CompileKind::Host`.
+ pub fn from_requested_target(
+ config: &Config,
+ target: Option<&str>,
+ ) -> CargoResult {
+ let kind = match target {
+ Some(s) => CompileKind::Target(CompileTarget::new(s)?),
+ None => match &config.build_config()?.target {
+ Some(val) => {
+ let value = if val.raw_value().ends_with(".json") {
+ let path = val.clone().resolve_path(config);
+ path.to_str().expect("must be utf-8 in toml").to_string()
+ } else {
+ val.raw_value().to_string()
+ };
+ CompileKind::Target(CompileTarget::new(&value)?)
+ }
+ None => CompileKind::Host,
+ },
+ };
+ Ok(kind)
+ }
}
impl serde::ser::Serialize for CompileKind {
diff --git a/src/cargo/core/profiles.rs b/src/cargo/core/profiles.rs
index 30a612bf95f..6083842cf99 100644
--- a/src/cargo/core/profiles.rs
+++ b/src/cargo/core/profiles.rs
@@ -998,11 +998,7 @@ impl UnitFor {
}
pub(crate) fn map_to_features_for(&self) -> FeaturesFor {
- if self.is_for_host_features() {
- FeaturesFor::HostDep
- } else {
- FeaturesFor::NormalOrDev
- }
+ FeaturesFor::from_for_host(self.is_for_host_features())
}
}
diff --git a/src/cargo/core/resolver/features.rs b/src/cargo/core/resolver/features.rs
index 7c16010ab9c..bccb6f4d086 100644
--- a/src/cargo/core/resolver/features.rs
+++ b/src/cargo/core/resolver/features.rs
@@ -92,13 +92,23 @@ pub enum HasDevUnits {
}
/// Flag to indicate if features are requested for a build dependency or not.
-#[derive(Debug, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq)]
pub enum FeaturesFor {
NormalOrDev,
/// Build dependency or proc-macro.
HostDep,
}
+impl FeaturesFor {
+ pub fn from_for_host(for_host: bool) -> FeaturesFor {
+ if for_host {
+ FeaturesFor::HostDep
+ } else {
+ FeaturesFor::NormalOrDev
+ }
+ }
+}
+
impl FeatureOpts {
fn new(config: &Config, has_dev_units: HasDevUnits) -> CargoResult {
let mut opts = FeatureOpts::default();
diff --git a/src/cargo/core/resolver/resolve.rs b/src/cargo/core/resolver/resolve.rs
index 1b823dc7b9f..2d442c0214a 100644
--- a/src/cargo/core/resolver/resolve.rs
+++ b/src/cargo/core/resolver/resolve.rs
@@ -305,6 +305,10 @@ unable to verify that `{0}` is the same as when the lockfile was generated
PackageIdSpec::query_str(spec, self.iter())
}
+ pub fn specs_to_ids(&self, specs: &[PackageIdSpec]) -> CargoResult> {
+ specs.iter().map(|s| s.query(self.iter())).collect()
+ }
+
pub fn unused_patches(&self) -> &[PackageId] {
&self.unused_patches
}
diff --git a/src/cargo/ops/cargo_compile.rs b/src/cargo/ops/cargo_compile.rs
index 332c83831c0..85786aebd67 100644
--- a/src/cargo/ops/cargo_compile.rs
+++ b/src/cargo/ops/cargo_compile.rs
@@ -351,12 +351,8 @@ pub fn compile_ws<'a>(
// Find the packages in the resolver that the user wants to build (those
// passed in with `-p` or the defaults from the workspace), and convert
- // Vec to a Vec<&PackageId>.
- let to_build_ids = specs
- .iter()
- .map(|s| s.query(resolve.iter()))
- .collect::>>()?;
-
+ // Vec to a Vec.
+ let to_build_ids = resolve.specs_to_ids(&specs)?;
// Now get the `Package` for each `PackageId`. This may trigger a download
// if the user specified `-p` for a dependency that is not downloaded.
// Dependencies will be downloaded during build_unit_dependencies.
@@ -753,12 +749,8 @@ fn generate_targets<'a>(
bcx.profiles
.get_profile(pkg.package_id(), ws.is_member(pkg), unit_for, target_mode);
- let features_for = if target.proc_macro() {
- FeaturesFor::HostDep
- } else {
- // Root units are never build dependencies.
- FeaturesFor::NormalOrDev
- };
+ // No need to worry about build-dependencies, roots are never build dependencies.
+ let features_for = FeaturesFor::from_for_host(target.proc_macro());
let features =
Vec::from(resolved_features.activated_features(pkg.package_id(), features_for));
bcx.units.intern(
@@ -969,11 +961,7 @@ pub fn resolve_all_features(
.expect("packages downloaded")
.proc_macro();
for dep in deps {
- let features_for = if is_proc_macro || dep.is_build() {
- FeaturesFor::HostDep
- } else {
- FeaturesFor::NormalOrDev
- };
+ let features_for = FeaturesFor::from_for_host(is_proc_macro || dep.is_build());
for feature in resolved_features.activated_features_unverified(dep_id, features_for) {
features.insert(format!("{}/{}", dep.name_in_toml(), feature));
}
diff --git a/src/cargo/ops/cargo_doc.rs b/src/cargo/ops/cargo_doc.rs
index 07b3eabdf6d..85b2e0909bd 100644
--- a/src/cargo/ops/cargo_doc.rs
+++ b/src/cargo/ops/cargo_doc.rs
@@ -36,10 +36,7 @@ pub fn doc(ws: &Workspace<'_>, options: &DocOptions) -> CargoResult<()> {
HasDevUnits::No,
)?;
- let ids = specs
- .iter()
- .map(|s| s.query(ws_resolve.targeted_resolve.iter()))
- .collect::>>()?;
+ let ids = ws_resolve.targeted_resolve.specs_to_ids(&specs)?;
let pkgs = ws_resolve.pkg_set.get_many(ids)?;
let mut lib_names = HashMap::new();
diff --git a/src/cargo/ops/mod.rs b/src/cargo/ops/mod.rs
index e4bc419e3a0..eed36c7867f 100644
--- a/src/cargo/ops/mod.rs
+++ b/src/cargo/ops/mod.rs
@@ -48,4 +48,5 @@ mod fix;
mod lockfile;
mod registry;
mod resolve;
+pub mod tree;
mod vendor;
diff --git a/src/cargo/ops/tree/format/mod.rs b/src/cargo/ops/tree/format/mod.rs
new file mode 100644
index 00000000000..1d835e961cc
--- /dev/null
+++ b/src/cargo/ops/tree/format/mod.rs
@@ -0,0 +1,108 @@
+use self::parse::{Parser, RawChunk};
+use super::{Graph, Node};
+use anyhow::{anyhow, Error};
+use std::fmt;
+
+mod parse;
+
+enum Chunk {
+ Raw(String),
+ Package,
+ License,
+ Repository,
+ Features,
+}
+
+pub struct Pattern(Vec);
+
+impl Pattern {
+ pub fn new(format: &str) -> Result {
+ let mut chunks = vec![];
+
+ for raw in Parser::new(format) {
+ let chunk = match raw {
+ RawChunk::Text(text) => Chunk::Raw(text.to_owned()),
+ RawChunk::Argument("p") => Chunk::Package,
+ RawChunk::Argument("l") => Chunk::License,
+ RawChunk::Argument("r") => Chunk::Repository,
+ RawChunk::Argument("f") => Chunk::Features,
+ RawChunk::Argument(a) => {
+ return Err(anyhow!("unsupported pattern `{}`", a));
+ }
+ RawChunk::Error(err) => return Err(anyhow!("{}", err)),
+ };
+ chunks.push(chunk);
+ }
+
+ Ok(Pattern(chunks))
+ }
+
+ pub fn display<'a>(&'a self, graph: &'a Graph<'a>, node_index: usize) -> Display<'a> {
+ Display {
+ pattern: self,
+ graph,
+ node_index,
+ }
+ }
+}
+
+pub struct Display<'a> {
+ pattern: &'a Pattern,
+ graph: &'a Graph<'a>,
+ node_index: usize,
+}
+
+impl<'a> fmt::Display for Display<'a> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let node = self.graph.node(self.node_index);
+ match node {
+ Node::Package {
+ package_id,
+ features,
+ ..
+ } => {
+ let package = self.graph.package_for_id(*package_id);
+ for chunk in &self.pattern.0 {
+ match *chunk {
+ Chunk::Raw(ref s) => fmt.write_str(s)?,
+ Chunk::Package => {
+ write!(fmt, "{} v{}", package.name(), package.version())?;
+
+ let source_id = package.package_id().source_id();
+ if !source_id.is_default_registry() {
+ write!(fmt, " ({})", source_id)?;
+ }
+ }
+ Chunk::License => {
+ if let Some(ref license) = package.manifest().metadata().license {
+ write!(fmt, "{}", license)?;
+ }
+ }
+ Chunk::Repository => {
+ if let Some(ref repository) = package.manifest().metadata().repository {
+ write!(fmt, "{}", repository)?;
+ }
+ }
+ Chunk::Features => {
+ write!(fmt, "{}", features.join(","))?;
+ }
+ }
+ }
+ }
+ Node::Feature { name, node_index } => {
+ let for_node = self.graph.node(*node_index);
+ match for_node {
+ Node::Package { package_id, .. } => {
+ write!(fmt, "{} feature \"{}\"", package_id.name(), name)?;
+ if self.graph.is_cli_feature(self.node_index) {
+ write!(fmt, " (command-line)")?;
+ }
+ }
+ _ => panic!("unexpected feature node {:?}", for_node),
+ }
+ }
+ }
+
+ Ok(())
+ }
+}
diff --git a/src/cargo/ops/tree/format/parse.rs b/src/cargo/ops/tree/format/parse.rs
new file mode 100644
index 00000000000..15f875ca865
--- /dev/null
+++ b/src/cargo/ops/tree/format/parse.rs
@@ -0,0 +1,97 @@
+use std::iter;
+use std::str;
+
+pub enum RawChunk<'a> {
+ Text(&'a str),
+ Argument(&'a str),
+ Error(&'static str),
+}
+
+pub struct Parser<'a> {
+ s: &'a str,
+ it: iter::Peekable>,
+}
+
+impl<'a> Parser<'a> {
+ pub fn new(s: &'a str) -> Parser<'a> {
+ Parser {
+ s,
+ it: s.char_indices().peekable(),
+ }
+ }
+
+ fn consume(&mut self, ch: char) -> bool {
+ match self.it.peek() {
+ Some(&(_, c)) if c == ch => {
+ self.it.next();
+ true
+ }
+ _ => false,
+ }
+ }
+
+ fn argument(&mut self) -> RawChunk<'a> {
+ RawChunk::Argument(self.name())
+ }
+
+ fn name(&mut self) -> &'a str {
+ let start = match self.it.peek() {
+ Some(&(pos, ch)) if ch.is_alphabetic() => {
+ self.it.next();
+ pos
+ }
+ _ => return "",
+ };
+
+ loop {
+ match self.it.peek() {
+ Some(&(_, ch)) if ch.is_alphanumeric() => {
+ self.it.next();
+ }
+ Some(&(end, _)) => return &self.s[start..end],
+ None => return &self.s[start..],
+ }
+ }
+ }
+
+ fn text(&mut self, start: usize) -> RawChunk<'a> {
+ while let Some(&(pos, ch)) = self.it.peek() {
+ match ch {
+ '{' | '}' | ')' => return RawChunk::Text(&self.s[start..pos]),
+ _ => {
+ self.it.next();
+ }
+ }
+ }
+ RawChunk::Text(&self.s[start..])
+ }
+}
+
+impl<'a> Iterator for Parser<'a> {
+ type Item = RawChunk<'a>;
+
+ fn next(&mut self) -> Option> {
+ match self.it.peek() {
+ Some(&(_, '{')) => {
+ self.it.next();
+ if self.consume('{') {
+ Some(RawChunk::Text("{"))
+ } else {
+ let chunk = self.argument();
+ if self.consume('}') {
+ Some(chunk)
+ } else {
+ for _ in &mut self.it {}
+ Some(RawChunk::Error("expected '}'"))
+ }
+ }
+ }
+ Some(&(_, '}')) => {
+ self.it.next();
+ Some(RawChunk::Error("unexpected '}'"))
+ }
+ Some(&(i, _)) => Some(self.text(i)),
+ None => None,
+ }
+ }
+}
diff --git a/src/cargo/ops/tree/graph.rs b/src/cargo/ops/tree/graph.rs
new file mode 100644
index 00000000000..d9d947619b7
--- /dev/null
+++ b/src/cargo/ops/tree/graph.rs
@@ -0,0 +1,562 @@
+//! Code for building the graph used by `cargo tree`.
+
+use super::TreeOptions;
+use crate::core::compiler::{CompileKind, RustcTargetData};
+use crate::core::dependency::DepKind;
+use crate::core::resolver::features::{FeaturesFor, RequestedFeatures, ResolvedFeatures};
+use crate::core::resolver::Resolve;
+use crate::core::{
+ FeatureMap, FeatureValue, InternedString, Package, PackageId, PackageIdSpec, Workspace,
+};
+use crate::util::CargoResult;
+use std::collections::{HashMap, HashSet};
+
+#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
+pub enum Node {
+ Package {
+ package_id: PackageId,
+ /// Features that are enabled on this package.
+ features: Vec,
+ kind: CompileKind,
+ },
+ Feature {
+ /// Index of the package node this feature is for.
+ node_index: usize,
+ /// Name of the feature.
+ name: InternedString,
+ },
+}
+
+#[derive(Debug, Copy, Hash, Eq, Clone, PartialEq)]
+pub enum Edge {
+ Dep(DepKind),
+ Feature,
+}
+
+#[derive(Clone)]
+struct Edges(HashMap>);
+
+impl Edges {
+ fn new() -> Edges {
+ Edges(HashMap::new())
+ }
+
+ fn add_edge(&mut self, kind: Edge, index: usize) {
+ let indexes = self.0.entry(kind).or_default();
+ if !indexes.contains(&index) {
+ indexes.push(index)
+ }
+ }
+}
+
+/// A graph of dependencies.
+pub struct Graph<'a> {
+ nodes: Vec,
+ edges: Vec,
+ /// Index maps a node to an index, for fast lookup.
+ index: HashMap,
+ /// Map for looking up packages.
+ package_map: HashMap,
+ /// Set of indexes of feature nodes that were added via the command-line.
+ ///
+ /// For example `--features foo` will mark the "foo" node here.
+ cli_features: HashSet,
+ /// Map of dependency names, used for building internal feature map for
+ /// dep_name/feat_name syntax.
+ ///
+ /// Key is the index of a package node, value is a map of dep_name to a
+ /// set of `(pkg_node_index, is_optional)`.
+ dep_name_map: HashMap>>,
+}
+
+impl<'a> Graph<'a> {
+ fn new(package_map: HashMap) -> Graph<'a> {
+ Graph {
+ nodes: Vec::new(),
+ edges: Vec::new(),
+ index: HashMap::new(),
+ package_map,
+ cli_features: HashSet::new(),
+ dep_name_map: HashMap::new(),
+ }
+ }
+
+ /// Adds a new node to the graph, returning its new index.
+ fn add_node(&mut self, node: Node) -> usize {
+ let from_index = self.nodes.len();
+ self.nodes.push(node);
+ self.edges.push(Edges::new());
+ self.index
+ .insert(self.nodes[from_index].clone(), from_index);
+ from_index
+ }
+
+ /// Returns a list of nodes the given node index points to for the given kind.
+ ///
+ /// Returns None if there are none.
+ pub fn connected_nodes(&self, from: usize, kind: &Edge) -> Option> {
+ match self.edges[from].0.get(kind) {
+ Some(indexes) => {
+ // Created a sorted list for consistent output.
+ let mut indexes = indexes.clone();
+ indexes.sort_unstable_by(|a, b| self.nodes[*a].cmp(&self.nodes[*b]));
+ Some(indexes)
+ }
+ None => None,
+ }
+ }
+
+ /// Gets a node by index.
+ pub fn node(&self, index: usize) -> &Node {
+ &self.nodes[index]
+ }
+
+ /// Given a slice of PackageIds, returns the indexes of all nodes that match.
+ pub fn indexes_from_ids(&self, package_ids: &[PackageId]) -> Vec {
+ let mut result: Vec<(&Node, usize)> = self
+ .nodes
+ .iter()
+ .enumerate()
+ .filter(|(_i, node)| match node {
+ Node::Package { package_id, .. } => package_ids.contains(package_id),
+ _ => false,
+ })
+ .map(|(i, node)| (node, i))
+ .collect();
+ result.sort_unstable();
+ result.into_iter().map(|(_node, i)| i).collect()
+ }
+
+ pub fn package_for_id(&self, id: PackageId) -> &Package {
+ self.package_map[&id]
+ }
+
+ fn package_id_for_index(&self, index: usize) -> PackageId {
+ match self.nodes[index] {
+ Node::Package { package_id, .. } => package_id,
+ Node::Feature { .. } => panic!("unexpected feature node"),
+ }
+ }
+
+ /// Returns `true` if the given feature node index is a feature enabled
+ /// via the command-line.
+ pub fn is_cli_feature(&self, index: usize) -> bool {
+ self.cli_features.contains(&index)
+ }
+
+ /// Returns a new graph by removing all nodes not reachable from the
+ /// given nodes.
+ pub fn from_reachable(&self, roots: &[usize]) -> Graph<'a> {
+ // Graph built with features does not (yet) support --duplicates.
+ assert!(self.dep_name_map.is_empty());
+ let mut new_graph = Graph::new(self.package_map.clone());
+ // Maps old index to new index. None if not yet visited.
+ let mut remap: Vec
--graph-features
diff --git a/src/etc/man/cargo-tree.1 b/src/etc/man/cargo-tree.1
index 30a5181f3ae..c6fcde393ee 100644
--- a/src/etc/man/cargo-tree.1
+++ b/src/etc/man/cargo-tree.1
@@ -95,13 +95,8 @@ Do not include dev\-dependencies.
\fB\-\-target\fP \fITRIPLE\fP
.RS 4
Filter dependencies matching the given target\-triple.
-The default is the host platform.
-.RE
-.sp
-\fB\-\-no\-filter\-targets\fP
-.RS 4
-Show dependencies for all target platforms. Cannot be specified with
-\fB\-\-target\fP.
+The default is the host platform. Use the value \fBall\fP to include \fBall\fP
+targets.
.RE
.sp
\fB\-\-graph\-features\fP
diff --git a/tests/testsuite/tree.rs b/tests/testsuite/tree.rs
index bec947ba573..5fc8faf24bd 100644
--- a/tests/testsuite/tree.rs
+++ b/tests/testsuite/tree.rs
@@ -414,13 +414,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree --no-filter-targets --target")
- .arg(alternate())
- .with_status(101)
- .with_stderr("[ERROR] cannot specify both `--target` and `--no-filter-targets`")
- .run();
-
- p.cargo("tree --no-filter-targets")
+ p.cargo("tree --target=all")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
diff --git a/tests/testsuite/tree_graph_features.rs b/tests/testsuite/tree_graph_features.rs
index 4087ace5112..c7b0840b1ec 100644
--- a/tests/testsuite/tree_graph_features.rs
+++ b/tests/testsuite/tree_graph_features.rs
@@ -344,7 +344,7 @@ foo v0.1.0 ([..]/foo)
",
)
.run();
- p.cargo("tree --graph-features --all-features --no-filter-targets")
+ p.cargo("tree --graph-features --all-features --target=all")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
From afdcab7ced4b3218fc5f68f1fa8b336ef8f0081c Mon Sep 17 00:00:00 2001
From: Eric Huss
Date: Thu, 2 Apr 2020 13:00:33 -0700
Subject: [PATCH 09/14] Catch and display error about the --all flag.
---
src/bin/cargo/commands/tree.rs | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/bin/cargo/commands/tree.rs b/src/bin/cargo/commands/tree.rs
index 9534b805265..bb23d647a2b 100644
--- a/src/bin/cargo/commands/tree.rs
+++ b/src/bin/cargo/commands/tree.rs
@@ -12,6 +12,7 @@ pub fn cli() -> App {
"Display the tree for all packages in the workspace",
"Exclude specific workspace members",
)
+ .arg(Arg::with_name("all").long("all").short("a").hidden(true))
.arg_features()
.arg_target_triple(
"Filter dependencies matching the given target-triple (default host platform)",
@@ -72,6 +73,13 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
)
.into());
}
+ if args.is_present("all") {
+ return Err(anyhow::format_err!(
+ "The `cargo tree` --all flag has been changed to --no-dedupe.\n\
+ If you are looking to display all workspace members, use the --workspace flag."
+ )
+ .into());
+ }
let ws = args.workspace(config)?;
let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
.map_err(|e| anyhow::anyhow!("{}", e))?;
From dd10b597ed79d726c266f8ba9a16001a1bcd30fb Mon Sep 17 00:00:00 2001
From: Eric Huss
Date: Thu, 2 Apr 2020 13:09:35 -0700
Subject: [PATCH 10/14] Add hint about removal of --all-targets
---
src/bin/cargo/commands/tree.rs | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/src/bin/cargo/commands/tree.rs b/src/bin/cargo/commands/tree.rs
index bb23d647a2b..42b44fc1d4c 100644
--- a/src/bin/cargo/commands/tree.rs
+++ b/src/bin/cargo/commands/tree.rs
@@ -13,6 +13,11 @@ pub fn cli() -> App {
"Exclude specific workspace members",
)
.arg(Arg::with_name("all").long("all").short("a").hidden(true))
+ .arg(
+ Arg::with_name("all-targets")
+ .long("all-targets")
+ .hidden(true),
+ )
.arg_features()
.arg_target_triple(
"Filter dependencies matching the given target-triple (default host platform)",
@@ -80,6 +85,11 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
)
.into());
}
+ if args.is_present("all-targets") {
+ return Err(
+ anyhow::format_err!("the --all-targets flag has been changed to --target=all").into(),
+ );
+ }
let ws = args.workspace(config)?;
let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
.map_err(|e| anyhow::anyhow!("{}", e))?;
From 3b1df3a46f16084722096b5f6418e5268fdf6eef Mon Sep 17 00:00:00 2001
From: Eric Huss
Date: Thu, 2 Apr 2020 15:12:17 -0700
Subject: [PATCH 11/14] Change --no-dev-dependencies to --dep-kinds.
---
src/bin/cargo/commands/tree.rs | 94 +++++++++++++++++++++++----
src/cargo/ops/tree/graph.rs | 2 +-
src/cargo/ops/tree/mod.rs | 9 +--
src/doc/man/cargo-tree.adoc | 14 +++-
src/doc/man/generated/cargo-tree.html | 32 ++++++++-
src/etc/man/cargo-tree.1 | 83 ++++++++++++++++++++++-
tests/testsuite/tree.rs | 84 ++++++++++++++++++++++--
7 files changed, 287 insertions(+), 31 deletions(-)
diff --git a/src/bin/cargo/commands/tree.rs b/src/bin/cargo/commands/tree.rs
index 42b44fc1d4c..db90b0e3dd6 100644
--- a/src/bin/cargo/commands/tree.rs
+++ b/src/bin/cargo/commands/tree.rs
@@ -1,5 +1,9 @@
use crate::command_prelude::*;
+use anyhow::{bail, format_err};
+use cargo::core::dependency::DepKind;
use cargo::ops::tree;
+use cargo::util::CargoResult;
+use std::collections::HashSet;
use std::str::FromStr;
pub fn cli() -> App {
@@ -22,7 +26,19 @@ pub fn cli() -> App {
.arg_target_triple(
"Filter dependencies matching the given target-triple (default host platform)",
)
- .arg(opt("no-dev-dependencies", "Skip dev dependencies"))
+ .arg(
+ Arg::with_name("no-dev-dependencies")
+ .long("no-dev-dependencies")
+ .hidden(true),
+ )
+ .arg(
+ opt(
+ "dep-kinds",
+ "Dependency kinds to display \
+ (normal, build, dev, no-dev, no-build, no-normal, all)",
+ )
+ .value_name("KINDS"),
+ )
.arg(opt("invert", "Invert the tree direction").short("i"))
.arg(Arg::with_name("no-indent").long("no-indent").hidden(true))
.arg(
@@ -68,27 +84,28 @@ pub fn cli() -> App {
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
if args.is_present("no-indent") {
- return Err(
- anyhow::format_err!("the --no-indent flag has been changed to --prefix=none").into(),
- );
+ return Err(format_err!("the --no-indent flag has been changed to --prefix=none").into());
}
if args.is_present("prefix-depth") {
- return Err(anyhow::format_err!(
- "the --prefix-depth flag has been changed to --prefix=depth"
- )
- .into());
+ return Err(
+ format_err!("the --prefix-depth flag has been changed to --prefix=depth").into(),
+ );
}
if args.is_present("all") {
- return Err(anyhow::format_err!(
+ return Err(format_err!(
"The `cargo tree` --all flag has been changed to --no-dedupe.\n\
If you are looking to display all workspace members, use the --workspace flag."
)
.into());
}
if args.is_present("all-targets") {
- return Err(
- anyhow::format_err!("the --all-targets flag has been changed to --target=all").into(),
- );
+ return Err(format_err!("the --all-targets flag has been changed to --target=all").into());
+ }
+ if args.is_present("no-dev-dependencies") {
+ return Err(format_err!(
+ "the --no-dev-dependencies flag has changed to --dep-kinds=no-dev"
+ )
+ .into());
}
let ws = args.workspace(config)?;
let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
@@ -96,13 +113,14 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
let prefix = tree::Prefix::from_str(args.value_of("prefix").unwrap())
.map_err(|e| anyhow::anyhow!("{}", e))?;
let target = tree::Target::from_cli(args.value_of("target"));
+ let dep_kinds = parse_dep_kinds(args.value_of("dep-kinds"))?;
let opts = tree::TreeOptions {
features: values(args, "features"),
all_features: args.is_present("all-features"),
no_default_features: args.is_present("no-default-features"),
packages: args.packages_from_flags()?,
target,
- no_dev_dependencies: args.is_present("no-dev-dependencies"),
+ dep_kinds,
invert: args.is_present("invert"),
prefix,
no_dedupe: args.is_present("no-dedupe"),
@@ -115,3 +133,53 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
tree::build_and_print(&ws, &opts)?;
Ok(())
}
+
+fn parse_dep_kinds(kinds: Option<&str>) -> CargoResult> {
+ let kinds: Vec<&str> = kinds.unwrap_or("all").split(',').collect();
+ let mut result = HashSet::new();
+ let insert_all = |result: &mut HashSet| {
+ result.insert(DepKind::Normal);
+ result.insert(DepKind::Build);
+ result.insert(DepKind::Development);
+ };
+ let unknown = |k| {
+ bail!(
+ "unknown dependency kind `{}`, valid values are \
+ \"normal\", \"build\", \"dev\", \
+ \"no-normal\", \"no-build\", \"no-dev\", \
+ or \"all\"",
+ k
+ )
+ };
+ if kinds.iter().any(|k| k.starts_with("no-")) {
+ insert_all(&mut result);
+ for kind in &kinds {
+ match *kind {
+ "no-normal" => result.remove(&DepKind::Normal),
+ "no-build" => result.remove(&DepKind::Build),
+ "no-dev" => result.remove(&DepKind::Development),
+ "normal" | "build" | "dev" | "all" => {
+ bail!("`no-` dependency kinds cannot be mixed with other dependency kinds")
+ }
+ k => return unknown(k),
+ };
+ }
+ return Ok(result);
+ }
+ for kind in kinds {
+ match kind {
+ "all" => insert_all(&mut result),
+ "normal" => {
+ result.insert(DepKind::Normal);
+ }
+ "build" => {
+ result.insert(DepKind::Build);
+ }
+ "dev" => {
+ result.insert(DepKind::Development);
+ }
+ k => return unknown(k),
+ }
+ }
+ Ok(result)
+}
diff --git a/src/cargo/ops/tree/graph.rs b/src/cargo/ops/tree/graph.rs
index a537c9da560..8046cf752b2 100644
--- a/src/cargo/ops/tree/graph.rs
+++ b/src/cargo/ops/tree/graph.rs
@@ -333,7 +333,7 @@ fn add_pkg(
return false;
}
// Filter out dev-dependencies if requested.
- if opts.no_dev_dependencies && dep.kind() == DepKind::Development {
+ if !opts.dep_kinds.contains(&dep.kind()) {
return false;
}
if dep.is_optional() {
diff --git a/src/cargo/ops/tree/mod.rs b/src/cargo/ops/tree/mod.rs
index 20125786c22..7a3347662b5 100644
--- a/src/cargo/ops/tree/mod.rs
+++ b/src/cargo/ops/tree/mod.rs
@@ -25,7 +25,8 @@ pub struct TreeOptions {
pub packages: Packages,
/// The platform to filter for.
pub target: Target,
- pub no_dev_dependencies: bool,
+ /// The dependency kinds to display.
+ pub dep_kinds: HashSet,
pub invert: bool,
/// The style of prefix for each line.
pub prefix: Prefix,
@@ -140,10 +141,10 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
opts.all_features,
!opts.no_default_features,
);
- let has_dev = if opts.no_dev_dependencies {
- HasDevUnits::No
- } else {
+ let has_dev = if opts.dep_kinds.contains(&DepKind::Development) {
HasDevUnits::Yes
+ } else {
+ HasDevUnits::No
};
let ws_resolve = ops::resolve_ws_with_opts(
ws,
diff --git a/src/doc/man/cargo-tree.adoc b/src/doc/man/cargo-tree.adoc
index f3f18a5dfe1..6e285d807d9 100644
--- a/src/doc/man/cargo-tree.adoc
+++ b/src/doc/man/cargo-tree.adoc
@@ -63,8 +63,18 @@ packages. You can then investigate if the package that depends on the
duplicate with the older version can be updated to the newer version so that
only one instance is built.
-*--no-dev-dependencies*::
- Do not include dev-dependencies.
+*--dep-kinds* KINDS::
+ The dependency kinds to display. Takes a comma separated list of values:
+
+ - `all` (default) — Show all dependency kinds.
+ - `normal` — Show normal dependencies.
+ - `build` — Show build dependencies.
+ - `dev` — Show development dependencies.
+ - `no-normal` — Do not include normal dependencies.
+ - `no-build` — Do not include build dependencies.
+ - `no-dev` — Do not include development dependencies.
++
+The `no-` prefixed options cannot be mixed with the other kinds.
*--target* _TRIPLE_::
Filter dependencies matching the given target-triple.
diff --git a/src/doc/man/generated/cargo-tree.html b/src/doc/man/generated/cargo-tree.html
index 50df0e0696d..d88c2893992 100644
--- a/src/doc/man/generated/cargo-tree.html
+++ b/src/doc/man/generated/cargo-tree.html
@@ -74,9 +74,37 @@
Tree Options
only one instance is built.
-
--no-dev-dependencies
+
--dep-kinds KINDS
-
Do not include dev-dependencies.
+
The dependency kinds to display. Takes a comma separated list of values:
+
+
+
+
all (default) — Show all dependency kinds.
+
+
+
normal — Show normal dependencies.
+
+
+
build — Show build dependencies.
+
+
+
dev — Show development dependencies.
+
+
+
no-normal — Do not include normal dependencies.
+
+
+
no-build — Do not include build dependencies.
+
+
+
no-dev — Do not include development dependencies.
+
+
The no- prefixed options cannot be mixed with the other kinds.
+
+
+
+
--targetTRIPLE
diff --git a/src/etc/man/cargo-tree.1 b/src/etc/man/cargo-tree.1
index c6fcde393ee..eaa9ad9599e 100644
--- a/src/etc/man/cargo-tree.1
+++ b/src/etc/man/cargo-tree.1
@@ -87,9 +87,88 @@ duplicate with the older version can be updated to the newer version so that
only one instance is built.
.RE
.sp
-\fB\-\-no\-dev\-dependencies\fP
+\fB\-\-dep\-kinds\fP KINDS
.RS 4
-Do not include dev\-dependencies.
+The dependency kinds to display. Takes a comma separated list of values:
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+. sp -1
+. IP \(bu 2.3
+.\}
+\fBall\fP (default) — Show all dependency kinds.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+. sp -1
+. IP \(bu 2.3
+.\}
+\fBnormal\fP — Show normal dependencies.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+. sp -1
+. IP \(bu 2.3
+.\}
+\fBbuild\fP — Show build dependencies.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+. sp -1
+. IP \(bu 2.3
+.\}
+\fBdev\fP — Show development dependencies.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+. sp -1
+. IP \(bu 2.3
+.\}
+\fBno\-normal\fP — Do not include normal dependencies.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+. sp -1
+. IP \(bu 2.3
+.\}
+\fBno\-build\fP — Do not include build dependencies.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+. sp -1
+. IP \(bu 2.3
+.\}
+\fBno\-dev\fP — Do not include development dependencies.
+.sp
+The \fBno\-\fP prefixed options cannot be mixed with the other kinds.
+.RE
.RE
.sp
\fB\-\-target\fP \fITRIPLE\fP
diff --git a/tests/testsuite/tree.rs b/tests/testsuite/tree.rs
index 5fc8faf24bd..f588e53fb98 100644
--- a/tests/testsuite/tree.rs
+++ b/tests/testsuite/tree.rs
@@ -435,8 +435,25 @@ foo v0.1.0 ([..]/foo)
}
#[cargo_test]
-fn no_dev_dependencies() {
- Package::new("devdep", "1.0.0").publish();
+fn dep_kinds() {
+ Package::new("inner-devdep", "1.0.0").publish();
+ Package::new("inner-builddep", "1.0.0").publish();
+ Package::new("inner-normal", "1.0.0").publish();
+ Package::new("normaldep", "1.0.0")
+ .dep("inner-normal", "1.0")
+ .dev_dep("inner-devdep", "1.0")
+ .build_dep("inner-builddep", "1.0")
+ .publish();
+ Package::new("devdep", "1.0.0")
+ .dep("inner-normal", "1.0")
+ .dev_dep("inner-devdep", "1.0")
+ .build_dep("inner-builddep", "1.0")
+ .publish();
+ Package::new("builddep", "1.0.0")
+ .dep("inner-normal", "1.0")
+ .dev_dep("inner-devdep", "1.0")
+ .build_dep("inner-builddep", "1.0")
+ .publish();
let p = project()
.file(
"Cargo.toml",
@@ -445,8 +462,14 @@ fn no_dev_dependencies() {
name = "foo"
version = "0.1.0"
+ [dependencies]
+ normaldep = "1.0"
+
[dev-dependencies]
devdep = "1.0"
+
+ [build-dependencies]
+ builddep = "1.0"
"#,
)
.file("src/lib.rs", "")
@@ -455,17 +478,64 @@ fn no_dev_dependencies() {
p.cargo("tree")
.with_stdout(
"\
-foo v0.1.0 ([..]foo)
+foo v0.1.0 ([..]/foo)
+└── normaldep v1.0.0
+ └── inner-normal v1.0.0
+ [build-dependencies]
+ └── inner-builddep v1.0.0
+[build-dependencies]
+└── builddep v1.0.0
+ └── inner-normal v1.0.0
+ [build-dependencies]
+ └── inner-builddep v1.0.0
[dev-dependencies]
└── devdep v1.0.0
+ └── inner-normal v1.0.0
+ [build-dependencies]
+ └── inner-builddep v1.0.0
+",
+ )
+ .run();
+
+ p.cargo("tree --dep-kinds=no-dev")
+ .with_stdout(
+ "\
+foo v0.1.0 ([..]/foo)
+└── normaldep v1.0.0
+ └── inner-normal v1.0.0
+ [build-dependencies]
+ └── inner-builddep v1.0.0
+[build-dependencies]
+└── builddep v1.0.0
+ └── inner-normal v1.0.0
+ [build-dependencies]
+ └── inner-builddep v1.0.0
+",
+ )
+ .run();
+
+ p.cargo("tree --dep-kinds=normal")
+ .with_stdout(
+ "\
+foo v0.1.0 ([..]/foo)
+└── normaldep v1.0.0
+ └── inner-normal v1.0.0
",
)
.run();
- p.cargo("tree --no-dev-dependencies")
+ p.cargo("tree --dep-kinds=dev,build")
.with_stdout(
"\
-foo v0.1.0 ([..]foo)
+foo v0.1.0 ([..]/foo)
+[build-dependencies]
+└── builddep v1.0.0
+ [build-dependencies]
+ └── inner-builddep v1.0.0
+[dev-dependencies]
+└── devdep v1.0.0
+ [build-dependencies]
+ └── inner-builddep v1.0.0
",
)
.run();
@@ -959,7 +1029,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree --no-dev-dependencies")
+ p.cargo("tree --dep-kinds=normal")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
@@ -982,7 +1052,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree --no-dev-dependencies -Zfeatures=dev_dep")
+ p.cargo("tree --dep-kinds=normal -Zfeatures=dev_dep")
.masquerade_as_nightly_cargo()
.with_stdout(
"\
From 5ccc5e01775d1322f0cd6f8ad395c9536a6b7012 Mon Sep 17 00:00:00 2001
From: Eric Huss
Date: Thu, 2 Apr 2020 15:23:48 -0700
Subject: [PATCH 12/14] Change old flags to warnings instead of errors.
Except --all which is ambiguous which flag it means.
---
src/bin/cargo/commands/tree.rs | 57 +++++++++++++++++++++-------------
1 file changed, 36 insertions(+), 21 deletions(-)
diff --git a/src/bin/cargo/commands/tree.rs b/src/bin/cargo/commands/tree.rs
index db90b0e3dd6..64411c3dd6b 100644
--- a/src/bin/cargo/commands/tree.rs
+++ b/src/bin/cargo/commands/tree.rs
@@ -83,14 +83,21 @@ pub fn cli() -> App {
}
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
- if args.is_present("no-indent") {
- return Err(format_err!("the --no-indent flag has been changed to --prefix=none").into());
- }
- if args.is_present("prefix-depth") {
- return Err(
- format_err!("the --prefix-depth flag has been changed to --prefix=depth").into(),
- );
- }
+ let prefix = if args.is_present("no-indent") {
+ config
+ .shell()
+ .warn("the --no-indent flag has been changed to --prefix=none")?;
+ "none"
+ } else if args.is_present("prefix-depth") {
+ config
+ .shell()
+ .warn("the --prefix-depth flag has been changed to --prefix=depth")?;
+ "depth"
+ } else {
+ args.value_of("prefix").unwrap()
+ };
+ let prefix = tree::Prefix::from_str(prefix).map_err(|e| anyhow::anyhow!("{}", e))?;
+
if args.is_present("all") {
return Err(format_err!(
"The `cargo tree` --all flag has been changed to --no-dedupe.\n\
@@ -98,22 +105,30 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
)
.into());
}
- if args.is_present("all-targets") {
- return Err(format_err!("the --all-targets flag has been changed to --target=all").into());
- }
- if args.is_present("no-dev-dependencies") {
- return Err(format_err!(
- "the --no-dev-dependencies flag has changed to --dep-kinds=no-dev"
- )
- .into());
- }
+
+ let target = if args.is_present("all-targets") {
+ config
+ .shell()
+ .warn("the --all-targets flag has been changed to --target=all")?;
+ Some("all")
+ } else {
+ args.value_of("target")
+ };
+ let target = tree::Target::from_cli(target);
+
+ let dep_kinds = if args.is_present("no-dev-dependencies") {
+ config
+ .shell()
+ .warn("the --no-dev-dependencies flag has changed to --dep-kinds=no-dev")?;
+ Some("no-dev")
+ } else {
+ args.value_of("dep-kinds")
+ };
+ let dep_kinds = parse_dep_kinds(dep_kinds)?;
+
let ws = args.workspace(config)?;
let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
.map_err(|e| anyhow::anyhow!("{}", e))?;
- let prefix = tree::Prefix::from_str(args.value_of("prefix").unwrap())
- .map_err(|e| anyhow::anyhow!("{}", e))?;
- let target = tree::Target::from_cli(args.value_of("target"));
- let dep_kinds = parse_dep_kinds(args.value_of("dep-kinds"))?;
let opts = tree::TreeOptions {
features: values(args, "features"),
all_features: args.is_present("all-features"),
From 96ff434cb96bd386309f811147bc3a52fbfcbf24 Mon Sep 17 00:00:00 2001
From: Eric Huss
Date: Fri, 3 Apr 2020 17:48:09 -0700
Subject: [PATCH 13/14] Rename --dep-kinds to --edges and fold in
--graph-features.
---
src/bin/cargo/commands/tree.rs | 87 +++++++++++++++-----------
src/cargo/ops/tree/graph.rs | 2 +-
src/cargo/ops/tree/mod.rs | 9 ++-
src/doc/man/cargo-tree.adoc | 54 +++++++++++-----
src/doc/man/generated/cargo-tree.html | 63 +++++++++++++------
src/etc/man/cargo-tree.1 | 71 ++++++++++++++-------
tests/testsuite/tree.rs | 10 +--
tests/testsuite/tree_graph_features.rs | 26 ++++----
8 files changed, 207 insertions(+), 115 deletions(-)
diff --git a/src/bin/cargo/commands/tree.rs b/src/bin/cargo/commands/tree.rs
index 64411c3dd6b..831d54849da 100644
--- a/src/bin/cargo/commands/tree.rs
+++ b/src/bin/cargo/commands/tree.rs
@@ -1,7 +1,7 @@
use crate::command_prelude::*;
use anyhow::{bail, format_err};
use cargo::core::dependency::DepKind;
-use cargo::ops::tree;
+use cargo::ops::tree::{self, EdgeKind};
use cargo::util::CargoResult;
use std::collections::HashSet;
use std::str::FromStr;
@@ -32,12 +32,13 @@ pub fn cli() -> App {
.hidden(true),
)
.arg(
- opt(
- "dep-kinds",
- "Dependency kinds to display \
- (normal, build, dev, no-dev, no-build, no-normal, all)",
+ multi_opt(
+ "edges",
+ "KINDS",
+ "The kinds of dependencies to display \
+ (features, normal, build, dev, all, no-dev, no-build, no-normal)",
)
- .value_name("KINDS"),
+ .short("e"),
)
.arg(opt("invert", "Invert the tree direction").short("i"))
.arg(Arg::with_name("no-indent").long("no-indent").hidden(true))
@@ -79,7 +80,6 @@ pub fn cli() -> App {
.short("f")
.default_value("{p}"),
)
- .arg(opt("graph-features", "Include features in the tree"))
}
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
@@ -116,15 +116,8 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
};
let target = tree::Target::from_cli(target);
- let dep_kinds = if args.is_present("no-dev-dependencies") {
- config
- .shell()
- .warn("the --no-dev-dependencies flag has changed to --dep-kinds=no-dev")?;
- Some("no-dev")
- } else {
- args.value_of("dep-kinds")
- };
- let dep_kinds = parse_dep_kinds(dep_kinds)?;
+ let edge_kinds = parse_edge_kinds(config, args)?;
+ let graph_features = edge_kinds.contains(&EdgeKind::Feature);
let ws = args.workspace(config)?;
let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
@@ -135,44 +128,57 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
no_default_features: args.is_present("no-default-features"),
packages: args.packages_from_flags()?,
target,
- dep_kinds,
+ edge_kinds,
invert: args.is_present("invert"),
prefix,
no_dedupe: args.is_present("no-dedupe"),
duplicates: args.is_present("duplicates"),
charset,
format: args.value_of("format").unwrap().to_string(),
- graph_features: args.is_present("graph-features"),
+ graph_features,
};
tree::build_and_print(&ws, &opts)?;
Ok(())
}
-fn parse_dep_kinds(kinds: Option<&str>) -> CargoResult> {
- let kinds: Vec<&str> = kinds.unwrap_or("all").split(',').collect();
+fn parse_edge_kinds(config: &Config, args: &ArgMatches<'_>) -> CargoResult> {
+ let mut kinds: Vec<&str> = args
+ .values_of("edges")
+ .map_or_else(|| Vec::new(), |es| es.flat_map(|e| e.split(',')).collect());
+ if args.is_present("no-dev-dependencies") {
+ config
+ .shell()
+ .warn("the --no-dev-dependencies flag has changed to -e=no-dev")?;
+ kinds.push("no-dev");
+ }
+ if kinds.len() == 0 {
+ kinds.extend(&["normal", "build", "dev"]);
+ }
+
let mut result = HashSet::new();
- let insert_all = |result: &mut HashSet| {
- result.insert(DepKind::Normal);
- result.insert(DepKind::Build);
- result.insert(DepKind::Development);
+ let insert_defaults = |result: &mut HashSet| {
+ result.insert(EdgeKind::Dep(DepKind::Normal));
+ result.insert(EdgeKind::Dep(DepKind::Build));
+ result.insert(EdgeKind::Dep(DepKind::Development));
};
let unknown = |k| {
bail!(
- "unknown dependency kind `{}`, valid values are \
+ "unknown edge kind `{}`, valid values are \
\"normal\", \"build\", \"dev\", \
\"no-normal\", \"no-build\", \"no-dev\", \
- or \"all\"",
+ \"features\", or \"all\"",
k
)
};
if kinds.iter().any(|k| k.starts_with("no-")) {
- insert_all(&mut result);
+ insert_defaults(&mut result);
for kind in &kinds {
match *kind {
- "no-normal" => result.remove(&DepKind::Normal),
- "no-build" => result.remove(&DepKind::Build),
- "no-dev" => result.remove(&DepKind::Development),
+ "no-normal" => result.remove(&EdgeKind::Dep(DepKind::Normal)),
+ "no-build" => result.remove(&EdgeKind::Dep(DepKind::Build)),
+ "no-dev" => result.remove(&EdgeKind::Dep(DepKind::Development)),
+ "features" => result.insert(EdgeKind::Feature),
"normal" | "build" | "dev" | "all" => {
bail!("`no-` dependency kinds cannot be mixed with other dependency kinds")
}
@@ -181,20 +187,29 @@ fn parse_dep_kinds(kinds: Option<&str>) -> CargoResult> {
}
return Ok(result);
}
- for kind in kinds {
- match kind {
- "all" => insert_all(&mut result),
+ for kind in &kinds {
+ match *kind {
+ "all" => {
+ insert_defaults(&mut result);
+ result.insert(EdgeKind::Feature);
+ }
+ "features" => {
+ result.insert(EdgeKind::Feature);
+ }
"normal" => {
- result.insert(DepKind::Normal);
+ result.insert(EdgeKind::Dep(DepKind::Normal));
}
"build" => {
- result.insert(DepKind::Build);
+ result.insert(EdgeKind::Dep(DepKind::Build));
}
"dev" => {
- result.insert(DepKind::Development);
+ result.insert(EdgeKind::Dep(DepKind::Development));
}
k => return unknown(k),
}
}
+ if kinds.len() == 1 && kinds[0] == "features" {
+ insert_defaults(&mut result);
+ }
Ok(result)
}
diff --git a/src/cargo/ops/tree/graph.rs b/src/cargo/ops/tree/graph.rs
index 8046cf752b2..a221da9ea7f 100644
--- a/src/cargo/ops/tree/graph.rs
+++ b/src/cargo/ops/tree/graph.rs
@@ -333,7 +333,7 @@ fn add_pkg(
return false;
}
// Filter out dev-dependencies if requested.
- if !opts.dep_kinds.contains(&dep.kind()) {
+ if !opts.edge_kinds.contains(&EdgeKind::Dep(dep.kind())) {
return false;
}
if dep.is_optional() {
diff --git a/src/cargo/ops/tree/mod.rs b/src/cargo/ops/tree/mod.rs
index 7a3347662b5..5d603a16a79 100644
--- a/src/cargo/ops/tree/mod.rs
+++ b/src/cargo/ops/tree/mod.rs
@@ -26,7 +26,7 @@ pub struct TreeOptions {
/// The platform to filter for.
pub target: Target,
/// The dependency kinds to display.
- pub dep_kinds: HashSet,
+ pub edge_kinds: HashSet,
pub invert: bool,
/// The style of prefix for each line.
pub prefix: Prefix,
@@ -124,7 +124,7 @@ static ASCII_SYMBOLS: Symbols = Symbols {
/// Entry point for the `cargo tree` command.
pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()> {
if opts.graph_features && opts.duplicates {
- bail!("the `--graph-features` flag does not support `--duplicates`");
+ bail!("the `-e features` flag does not support `--duplicates`");
}
let requested_target = match &opts.target {
Target::All | Target::Host => None,
@@ -141,7 +141,10 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
opts.all_features,
!opts.no_default_features,
);
- let has_dev = if opts.dep_kinds.contains(&DepKind::Development) {
+ let has_dev = if opts
+ .edge_kinds
+ .contains(&EdgeKind::Dep(DepKind::Development))
+ {
HasDevUnits::Yes
} else {
HasDevUnits::No
diff --git a/src/doc/man/cargo-tree.adoc b/src/doc/man/cargo-tree.adoc
index 6e285d807d9..f7086044814 100644
--- a/src/doc/man/cargo-tree.adoc
+++ b/src/doc/man/cargo-tree.adoc
@@ -14,7 +14,8 @@ cargo-tree - Display a tree visualization of a dependency graph
== DESCRIPTION
-This command will display a tree of dependencies to the terminal. An example of a simple project that depends on the "rand" package:
+This command will display a tree of dependencies to the terminal. An example
+of a simple project that depends on the "rand" package:
----
myproject v0.1.0 (/myproject)
@@ -36,6 +37,24 @@ Packages marked with `(*)` have been "de-duplicated". The dependencies for the
package have already been shown elswhere in the graph, and so are not
repeated. Use the `--no-dedupe` option to repeat the duplicates.
+The `-e` flag can be used to select the dependency kinds to display. The
+"features" kind changes the output to display the features enabled by
+each dependency. For example, `cargo tree -e features`:
+
+----
+myproject v0.1.0 (/myproject)
+└── log feature "serde"
+ └── log v0.4.8
+ ├── serde v1.0.106
+ └── cfg-if feature "default"
+ └── cfg-if v0.1.10
+----
+
+In this tree, `myproject` depends on `log` with the `serde` feature. `log` in
+turn depends on `cfg-if` with "default" features. When using `-e features` it
+can be helpful to use `-i` and `-p` flags to show how the features flow into a
+package. See the examples below for more detail.
+
== OPTIONS
=== Tree Options
@@ -63,31 +82,30 @@ packages. You can then investigate if the package that depends on the
duplicate with the older version can be updated to the newer version so that
only one instance is built.
-*--dep-kinds* KINDS::
+*-e* _KINDS_::
+*--edges* _KINDS_::
The dependency kinds to display. Takes a comma separated list of values:
-
- - `all` (default) — Show all dependency kinds.
++
+ - `all` — Show all edge kinds.
- `normal` — Show normal dependencies.
- `build` — Show build dependencies.
- `dev` — Show development dependencies.
+ - `features` — Show features enabled by each dependency. If this is
+ the only kind given, then it will automatically include the other
+ dependency kinds.
- `no-normal` — Do not include normal dependencies.
- `no-build` — Do not include build dependencies.
- `no-dev` — Do not include development dependencies.
+
-The `no-` prefixed options cannot be mixed with the other kinds.
+The `no-` prefixed options cannot be mixed with the other dependency kinds.
++
+The default is `normal,build,dev`.
*--target* _TRIPLE_::
Filter dependencies matching the given target-triple.
The default is the host platform. Use the value `all` to include *all*
targets.
-*--graph-features*::
- Runs in a special mode where features are included as individual nodes.
- This is intended to be used to help explain why a feature is enabled on
- any particular package. It is recommended to use with the `-p` and `-i`
- flags to show how the features flow into the package. See the examples
- below for more detail.
-
=== Tree Formatting Options
*--charset* _CHARSET_::
@@ -158,9 +176,11 @@ include::section-exit-status.adoc[]
. Explain why features are enabled for the given package:
- cargo tree --graph-features -i -p syn
+ cargo tree -e features -i -p syn
+
-An example of what this would display:
+The `-e features` flag is used to show features. The `-i` flag is used to
+invert the graph so that it displays the packages that depend on `syn` (not
+what `syn` depends on). An example of what this would display:
+
----
syn v1.0.17
@@ -187,9 +207,9 @@ syn v1.0.17
----
+
To read this graph, you can follow the chain for each feature from the root to
-see why it was included. For example, the "full" feature was added by the
-`rustversion` crate which was included from `myproject` (with the default
-features), and `myproject` was the package selected on the command-line. All
+see why it is included. For example, the "full" feature is added by the
+`rustversion` crate which is included from `myproject` (with the default
+features), and `myproject` is the package selected on the command-line. All
of the other `syn` features are added by the "default" feature ("quote" is
added by "printing" and "proc-macro", both of which are default features).
+
diff --git a/src/doc/man/generated/cargo-tree.html b/src/doc/man/generated/cargo-tree.html
index d88c2893992..2c000d327af 100644
--- a/src/doc/man/generated/cargo-tree.html
+++ b/src/doc/man/generated/cargo-tree.html
@@ -14,7 +14,8 @@
SYNOPSIS
DESCRIPTION
-
This command will display a tree of dependencies to the terminal. An example of a simple project that depends on the "rand" package:
+
This command will display a tree of dependencies to the terminal. An example
+of a simple project that depends on the "rand" package:
@@ -38,6 +39,27 @@
DESCRIPTION
package have already been shown elswhere in the graph, and so are not
repeated. Use the --no-dedupe option to repeat the duplicates.
+
+
The -e flag can be used to select the dependency kinds to display. The
+"features" kind changes the output to display the features enabled by
+each dependency. For example, cargo tree -e features:
In this tree, myproject depends on log with the serde feature. log in
+turn depends on cfg-if with "default" features. When using -e features it
+can be helpful to use -i and -p flags to show how the features flow into a
+package. See the examples below for more detail.
+
@@ -74,13 +96,14 @@
Tree Options
only one instance is built.
-
--dep-kinds KINDS
+
-eKINDS
+
--edgesKINDS
The dependency kinds to display. Takes a comma separated list of values:
-
all (default) — Show all dependency kinds.
+
all — Show all edge kinds.
normal — Show normal dependencies.
@@ -92,6 +115,11 @@
Tree Options
dev — Show development dependencies.
+
features — Show features enabled by each dependency. If this is
+the only kind given, then it will automatically include the other
+dependency kinds.
+
+
no-normal — Do not include normal dependencies.
@@ -99,12 +127,15 @@
Tree Options
no-dev — Do not include development dependencies.
-
-
The no- prefixed options cannot be mixed with the other kinds.
-
+
+
The no- prefixed options cannot be mixed with the other dependency kinds.
+
+
+
The default is normal,build,dev.
+
--targetTRIPLE
@@ -112,14 +143,6 @@
Tree Options
The default is the host platform. Use the value all to include all
targets.
-
--graph-features
-
-
Runs in a special mode where features are included as individual nodes.
-This is intended to be used to help explain why a feature is enabled on
-any particular package. It is recommended to use with the -p and -i
-flags to show how the features flow into the package. See the examples
-below for more detail.
-
@@ -417,11 +440,13 @@
EXAMPLES
Explain why features are enabled for the given package:
-
cargo tree --graph-features -i -p syn
+
cargo tree -e features -i -p syn
-
An example of what this would display:
+
The -e features flag is used to show features. The -i flag is used to
+invert the graph so that it displays the packages that depend on syn (not
+what syn depends on). An example of what this would display:
@@ -450,9 +475,9 @@
EXAMPLES
To read this graph, you can follow the chain for each feature from the root to
-see why it was included. For example, the "full" feature was added by the
-rustversion crate which was included from myproject (with the default
-features), and myproject was the package selected on the command-line. All
+see why it is included. For example, the "full" feature is added by the
+rustversion crate which is included from myproject (with the default
+features), and myproject is the package selected on the command-line. All
of the other syn features are added by the "default" feature ("quote" is
added by "printing" and "proc-macro", both of which are default features).
diff --git a/src/etc/man/cargo-tree.1 b/src/etc/man/cargo-tree.1
index eaa9ad9599e..0cadfaaeb2b 100644
--- a/src/etc/man/cargo-tree.1
+++ b/src/etc/man/cargo-tree.1
@@ -2,12 +2,12 @@
.\" Title: cargo-tree
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.10
-.\" Date: 2020-04-02
+.\" Date: 2020-04-03
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
-.TH "CARGO\-TREE" "1" "2020-04-02" "\ \&" "\ \&"
+.TH "CARGO\-TREE" "1" "2020-04-03" "\ \&" "\ \&"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
@@ -34,7 +34,8 @@ cargo\-tree \- Display a tree visualization of a dependency graph
\fBcargo tree [\fIOPTIONS\fP]\fP
.SH "DESCRIPTION"
.sp
-This command will display a tree of dependencies to the terminal. An example of a simple project that depends on the "rand" package:
+This command will display a tree of dependencies to the terminal. An example
+of a simple project that depends on the "rand" package:
.sp
.if n .RS 4
.nf
@@ -57,6 +58,26 @@ myproject v0.1.0 (/myproject)
Packages marked with \fB(*)\fP have been "de\-duplicated". The dependencies for the
package have already been shown elswhere in the graph, and so are not
repeated. Use the \fB\-\-no\-dedupe\fP option to repeat the duplicates.
+.sp
+The \fB\-e\fP flag can be used to select the dependency kinds to display. The
+"features" kind changes the output to display the features enabled by
+each dependency. For example, \fBcargo tree \-e features\fP:
+.sp
+.if n .RS 4
+.nf
+myproject v0.1.0 (/myproject)
+└── log feature "serde"
+ └── log v0.4.8
+ ├── serde v1.0.106
+ └── cfg\-if feature "default"
+ └── cfg\-if v0.1.10
+.fi
+.if n .RE
+.sp
+In this tree, \fBmyproject\fP depends on \fBlog\fP with the \fBserde\fP feature. \fBlog\fP in
+turn depends on \fBcfg\-if\fP with "default" features. When using \fB\-e features\fP it
+can be helpful to use \fB\-i\fP and \fB\-p\fP flags to show how the features flow into a
+package. See the examples below for more detail.
.SH "OPTIONS"
.SS "Tree Options"
.sp
@@ -87,7 +108,7 @@ duplicate with the older version can be updated to the newer version so that
only one instance is built.
.RE
.sp
-\fB\-\-dep\-kinds\fP KINDS
+\fB\-e\fP \fIKINDS\fP, \fB\-\-edges\fP \fIKINDS\fP
.RS 4
The dependency kinds to display. Takes a comma separated list of values:
.sp
@@ -99,7 +120,7 @@ The dependency kinds to display. Takes a comma separated list of values:
. sp -1
. IP \(bu 2.3
.\}
-\fBall\fP (default) — Show all dependency kinds.
+\fBall\fP — Show all edge kinds.
.RE
.sp
.RS 4
@@ -143,6 +164,19 @@ The dependency kinds to display. Takes a comma separated list of values:
. sp -1
. IP \(bu 2.3
.\}
+\fBfeatures\fP — Show features enabled by each dependency. If this is
+the only kind given, then it will automatically include the other
+dependency kinds.
+.RE
+.sp
+.RS 4
+.ie n \{\
+\h'-04'\(bu\h'+03'\c
+.\}
+.el \{\
+. sp -1
+. IP \(bu 2.3
+.\}
\fBno\-normal\fP — Do not include normal dependencies.
.RE
.sp
@@ -166,9 +200,11 @@ The dependency kinds to display. Takes a comma separated list of values:
. IP \(bu 2.3
.\}
\fBno\-dev\fP — Do not include development dependencies.
-.sp
-The \fBno\-\fP prefixed options cannot be mixed with the other kinds.
.RE
+.sp
+The \fBno\-\fP prefixed options cannot be mixed with the other dependency kinds.
+.sp
+The default is \fBnormal,build,dev\fP.
.RE
.sp
\fB\-\-target\fP \fITRIPLE\fP
@@ -177,15 +213,6 @@ Filter dependencies matching the given target\-triple.
The default is the host platform. Use the value \fBall\fP to include \fBall\fP
targets.
.RE
-.sp
-\fB\-\-graph\-features\fP
-.RS 4
-Runs in a special mode where features are included as individual nodes.
-This is intended to be used to help explain why a feature is enabled on
-any particular package. It is recommended to use with the \fB\-p\fP and \fB\-i\fP
-flags to show how the features flow into the package. See the examples
-below for more detail.
-.RE
.SS "Tree Formatting Options"
.sp
\fB\-\-charset\fP \fICHARSET\fP
@@ -545,11 +572,13 @@ Explain why features are enabled for the given package:
.sp
.if n .RS 4
.nf
-cargo tree \-\-graph\-features \-i \-p syn
+cargo tree \-e features \-i \-p syn
.fi
.if n .RE
.sp
-An example of what this would display:
+The \fB\-e features\fP flag is used to show features. The \fB\-i\fP flag is used to
+invert the graph so that it displays the packages that depend on \fBsyn\fP (not
+what \fBsyn\fP depends on). An example of what this would display:
.sp
.if n .RS 4
.nf
@@ -578,9 +607,9 @@ syn v1.0.17
.if n .RE
.sp
To read this graph, you can follow the chain for each feature from the root to
-see why it was included. For example, the "full" feature was added by the
-\fBrustversion\fP crate which was included from \fBmyproject\fP (with the default
-features), and \fBmyproject\fP was the package selected on the command\-line. All
+see why it is included. For example, the "full" feature is added by the
+\fBrustversion\fP crate which is included from \fBmyproject\fP (with the default
+features), and \fBmyproject\fP is the package selected on the command\-line. All
of the other \fBsyn\fP features are added by the "default" feature ("quote" is
added by "printing" and "proc\-macro", both of which are default features).
.sp
diff --git a/tests/testsuite/tree.rs b/tests/testsuite/tree.rs
index f588e53fb98..097f7c0ba39 100644
--- a/tests/testsuite/tree.rs
+++ b/tests/testsuite/tree.rs
@@ -497,7 +497,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree --dep-kinds=no-dev")
+ p.cargo("tree -e no-dev")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
@@ -514,7 +514,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree --dep-kinds=normal")
+ p.cargo("tree -e normal")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
@@ -524,7 +524,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree --dep-kinds=dev,build")
+ p.cargo("tree -e dev,build")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
@@ -1029,7 +1029,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree --dep-kinds=normal")
+ p.cargo("tree -e normal")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
@@ -1052,7 +1052,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree --dep-kinds=normal -Zfeatures=dev_dep")
+ p.cargo("tree -e normal -Zfeatures=dev_dep")
.masquerade_as_nightly_cargo()
.with_stdout(
"\
diff --git a/tests/testsuite/tree_graph_features.rs b/tests/testsuite/tree_graph_features.rs
index c7b0840b1ec..e7ee106a3b9 100644
--- a/tests/testsuite/tree_graph_features.rs
+++ b/tests/testsuite/tree_graph_features.rs
@@ -1,4 +1,4 @@
-//! Tests for the `cargo tree` command with --graph-features option.
+//! Tests for the `cargo tree` command with -e features option.
use cargo_test_support::project;
use cargo_test_support::registry::{Dependency, Package};
@@ -49,7 +49,7 @@ fn dep_feature_various() {
.file("src/lib.rs", "")
.build();
- p.cargo("tree --graph-features")
+ p.cargo("tree -e features")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
@@ -132,7 +132,7 @@ fn graph_features_ws_interdependent() {
.file("b/src/lib.rs", "")
.build();
- p.cargo("tree --graph-features")
+ p.cargo("tree -e features")
.with_stdout(
"\
a v0.1.0 ([..]/foo/a)
@@ -148,7 +148,7 @@ b v0.1.0 ([..]/foo/b)
)
.run();
- p.cargo("tree --graph-features -i")
+ p.cargo("tree -e features -i")
.with_stdout(
"\
a v0.1.0 ([..]/foo/a)
@@ -199,7 +199,7 @@ fn slash_feature_name() {
.file("src/lib.rs", "")
.build();
- p.cargo("tree --graph-features --features f1")
+ p.cargo("tree -e features --features f1")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
@@ -211,7 +211,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree --graph-features --features f1 -i")
+ p.cargo("tree -e features --features f1 -i")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
@@ -223,7 +223,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree --graph-features --features f1 -p notopt -i")
+ p.cargo("tree -e features --features f1 -p notopt -i")
.with_stdout(
"\
notopt v1.0.0
@@ -241,7 +241,7 @@ notopt v1.0.0
)
.run();
- p.cargo("tree --graph-features --features notopt/animal -p notopt -i")
+ p.cargo("tree -e features --features notopt/animal -p notopt -i")
.with_stdout(
"\
notopt v1.0.0
@@ -255,7 +255,7 @@ notopt v1.0.0
)
.run();
- p.cargo("tree --graph-features --all-features")
+ p.cargo("tree -e features --all-features")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
@@ -269,7 +269,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree --graph-features --all-features -p opt2 -i")
+ p.cargo("tree -e features --all-features -p opt2 -i")
.with_stdout(
"\
opt2 v1.0.0
@@ -326,7 +326,7 @@ fn features_enables_inactive_target() {
)
.file("src/lib.rs", "")
.build();
- p.cargo("tree --graph-features")
+ p.cargo("tree -e features")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
@@ -335,7 +335,7 @@ foo v0.1.0 ([..]/foo)
",
)
.run();
- p.cargo("tree --graph-features --all-features")
+ p.cargo("tree -e features --all-features")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
@@ -344,7 +344,7 @@ foo v0.1.0 ([..]/foo)
",
)
.run();
- p.cargo("tree --graph-features --all-features --target=all")
+ p.cargo("tree -e features --all-features --target=all")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
From 7c403447bdc9caff42f1521c2436fe8e53e38e33 Mon Sep 17 00:00:00 2001
From: Eric Huss
Date: Fri, 3 Apr 2020 19:52:21 -0700
Subject: [PATCH 14/14] Switch --invert to take the package name as an
argument.
---
src/bin/cargo/commands/tree.rs | 45 ++++++++++-
src/cargo/ops/tree/mod.rs | 16 +++-
src/doc/asciidoc-extension.rb | 15 ++++
src/doc/man/cargo-tree.adoc | 31 +++++---
src/doc/man/generated/cargo-tree.html | 32 +++++---
src/etc/man/cargo-tree.1 | 101 +++++++++++++------------
tests/testsuite/tree.rs | 20 ++---
tests/testsuite/tree_graph_features.rs | 10 +--
8 files changed, 177 insertions(+), 93 deletions(-)
diff --git a/src/bin/cargo/commands/tree.rs b/src/bin/cargo/commands/tree.rs
index 831d54849da..a20bb9bfa2b 100644
--- a/src/bin/cargo/commands/tree.rs
+++ b/src/bin/cargo/commands/tree.rs
@@ -2,6 +2,7 @@ use crate::command_prelude::*;
use anyhow::{bail, format_err};
use cargo::core::dependency::DepKind;
use cargo::ops::tree::{self, EdgeKind};
+use cargo::ops::Packages;
use cargo::util::CargoResult;
use std::collections::HashSet;
use std::str::FromStr;
@@ -40,7 +41,14 @@ pub fn cli() -> App {
)
.short("e"),
)
- .arg(opt("invert", "Invert the tree direction").short("i"))
+ .arg(
+ optional_multi_opt(
+ "invert",
+ "SPEC",
+ "Invert the tree direction and focus on the given package",
+ )
+ .short("i"),
+ )
.arg(Arg::with_name("no-indent").long("no-indent").hidden(true))
.arg(
Arg::with_name("prefix-depth")
@@ -119,6 +127,37 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
let edge_kinds = parse_edge_kinds(config, args)?;
let graph_features = edge_kinds.contains(&EdgeKind::Feature);
+ let packages = args.packages_from_flags()?;
+ let mut invert = args
+ .values_of("invert")
+ .map_or_else(|| Vec::new(), |is| is.map(|s| s.to_string()).collect());
+ if args.is_present_with_zero_values("invert") {
+ match &packages {
+ Packages::Packages(ps) => {
+ // Backwards compatibility with old syntax of `cargo tree -i -p foo`.
+ invert.extend(ps.clone());
+ }
+ _ => {
+ return Err(format_err!(
+ "The `-i` flag requires a package name.\n\
+\n\
+The `-i` flag is used to inspect the reverse dependencies of a specific\n\
+package. It will invert the tree and display the packages that depend on the\n\
+given package.\n\
+\n\
+Note that in a workspace, by default it will only display the package's\n\
+reverse dependencies inside the tree of the workspace member in the current\n\
+directory. The --workspace flag can be used to extend it so that it will show\n\
+the package's reverse dependencies across the entire workspace. The -p flag\n\
+can be used to display the package's reverse dependencies only with the\n\
+subtree of the package given to -p.\n\
+"
+ )
+ .into());
+ }
+ }
+ }
+
let ws = args.workspace(config)?;
let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
.map_err(|e| anyhow::anyhow!("{}", e))?;
@@ -126,10 +165,10 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
features: values(args, "features"),
all_features: args.is_present("all-features"),
no_default_features: args.is_present("no-default-features"),
- packages: args.packages_from_flags()?,
+ packages,
target,
edge_kinds,
- invert: args.is_present("invert"),
+ invert,
prefix,
no_dedupe: args.is_present("no-dedupe"),
duplicates: args.is_present("duplicates"),
diff --git a/src/cargo/ops/tree/mod.rs b/src/cargo/ops/tree/mod.rs
index 5d603a16a79..fe4f56d1f25 100644
--- a/src/cargo/ops/tree/mod.rs
+++ b/src/cargo/ops/tree/mod.rs
@@ -4,7 +4,7 @@ use self::format::Pattern;
use crate::core::compiler::{CompileKind, RustcTargetData};
use crate::core::dependency::DepKind;
use crate::core::resolver::{HasDevUnits, ResolveOpts};
-use crate::core::{Package, PackageId, Workspace};
+use crate::core::{Package, PackageId, PackageIdSpec, Workspace};
use crate::ops::{self, Packages};
use crate::util::CargoResult;
use anyhow::{bail, Context};
@@ -27,7 +27,7 @@ pub struct TreeOptions {
pub target: Target,
/// The dependency kinds to display.
pub edge_kinds: HashSet,
- pub invert: bool,
+ pub invert: Vec,
/// The style of prefix for each line.
pub prefix: Prefix,
/// If `true`, duplicates will be repeated.
@@ -177,7 +177,15 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
opts,
)?;
- let root_ids = ws_resolve.targeted_resolve.specs_to_ids(&specs)?;
+ let root_specs = if opts.invert.is_empty() {
+ specs
+ } else {
+ opts.invert
+ .iter()
+ .map(|p| PackageIdSpec::parse(p))
+ .collect::>>()?
+ };
+ let root_ids = ws_resolve.targeted_resolve.specs_to_ids(&root_specs)?;
let root_indexes = graph.indexes_from_ids(&root_ids);
let root_indexes = if opts.duplicates {
@@ -188,7 +196,7 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
root_indexes
};
- if opts.invert || opts.duplicates {
+ if !opts.invert.is_empty() || opts.duplicates {
graph.invert();
}
diff --git a/src/doc/asciidoc-extension.rb b/src/doc/asciidoc-extension.rb
index 87f4f2a2731..1fc8e99d96b 100644
--- a/src/doc/asciidoc-extension.rb
+++ b/src/doc/asciidoc-extension.rb
@@ -84,6 +84,20 @@ def process document, output
end
end
+# Man pages are ASCII only. Unfortunately asciidoc doesn't process these
+# characters for us. The `cargo tree` manpage needs a little assistance.
+class SpecialCharPostprocessor < Extensions::Postprocessor
+ def process document, output
+ if document.basebackend? 'manpage'
+ output = output.gsub(/│/, '|')
+ .gsub(/├/, '|')
+ .gsub(/└/, '`')
+ .gsub(/─/, '\-')
+ end
+ output
+ end
+end
+
# General utility for converting text. Example:
#
# convert:lowercase[{somevar}]
@@ -107,4 +121,5 @@ def process parent, target, attrs
inline_macro LinkCargoInlineMacro
inline_macro ConvertInlineMacro
postprocessor MonoPostprocessor
+ postprocessor SpecialCharPostprocessor
end
diff --git a/src/doc/man/cargo-tree.adoc b/src/doc/man/cargo-tree.adoc
index f7086044814..86b3276a48e 100644
--- a/src/doc/man/cargo-tree.adoc
+++ b/src/doc/man/cargo-tree.adoc
@@ -52,17 +52,24 @@ myproject v0.1.0 (/myproject)
In this tree, `myproject` depends on `log` with the `serde` feature. `log` in
turn depends on `cfg-if` with "default" features. When using `-e features` it
-can be helpful to use `-i` and `-p` flags to show how the features flow into a
-package. See the examples below for more detail.
+can be helpful to use `-i` flag to show how the features flow into a package.
+See the examples below for more detail.
== OPTIONS
=== Tree Options
-*-i*::
-*--invert*::
- Invert the tree. Typically this flag is used with the `-p` flag to show
- the dependencies for a specific package.
+*-i* _SPEC_::
+*--invert* _SPEC_::
+ Show the reverse dependencies for the given package. This flag will invert
+ the tree and display the packages that depend on the given package.
++
+Note that in a workspace, by default it will only display the package's
+reverse dependencies inside the tree of the workspace member in the current
+directory. The `--workspace` flag can be used to extend it so that it will
+show the package's reverse dependencies across the entire workspace. The `-p`
+flag can be used to display the package's reverse dependencies only with the
+subtree of the package given to `-p`.
*--no-dedupe*::
Do not de-duplicate repeated dependencies. Usually, when a package has
@@ -161,9 +168,9 @@ include::section-exit-status.adoc[]
cargo tree
-. Display all the packages that depend on the specified package:
+. Display all the packages that depend on the `syn` package:
- cargo tree -i -p syn
+ cargo tree -i syn
. Show the features enabled on each package:
@@ -174,13 +181,13 @@ include::section-exit-status.adoc[]
cargo tree -d
-. Explain why features are enabled for the given package:
+. Explain why features are enabled for the `syn` package:
- cargo tree -e features -i -p syn
+ cargo tree -e features -i syn
+
The `-e features` flag is used to show features. The `-i` flag is used to
-invert the graph so that it displays the packages that depend on `syn` (not
-what `syn` depends on). An example of what this would display:
+invert the graph so that it displays the packages that depend on `syn`. An
+example of what this would display:
+
----
syn v1.0.17
diff --git a/src/doc/man/generated/cargo-tree.html b/src/doc/man/generated/cargo-tree.html
index 2c000d327af..8b822936a7a 100644
--- a/src/doc/man/generated/cargo-tree.html
+++ b/src/doc/man/generated/cargo-tree.html
@@ -57,8 +57,8 @@
DESCRIPTION
In this tree, myproject depends on log with the serde feature. log in
turn depends on cfg-if with "default" features. When using -e features it
-can be helpful to use -i and -p flags to show how the features flow into a
-package. See the examples below for more detail.
+can be helpful to use -i flag to show how the features flow into a package.
+See the examples below for more detail.
@@ -69,11 +69,19 @@
OPTIONS
Tree Options
-
-i
-
--invert
+
-iSPEC
+
--invertSPEC
-
Invert the tree. Typically this flag is used with the -p flag to show
-the dependencies for a specific package.
+
Show the reverse dependencies for the given package. This flag will invert
+the tree and display the packages that depend on the given package.
+
+
Note that in a workspace, by default it will only display the package’s
+reverse dependencies inside the tree of the workspace member in the current
+directory. The --workspace flag can be used to extend it so that it will
+show the package’s reverse dependencies across the entire workspace. The -p
+flag can be used to display the package’s reverse dependencies only with the
+subtree of the package given to -p.
+
--no-dedupe
@@ -412,10 +420,10 @@
EXAMPLES
-
Display all the packages that depend on the specified package:
+
Display all the packages that depend on the syn package:
-
cargo tree -i -p syn
+
cargo tree -i syn
@@ -437,16 +445,16 @@
EXAMPLES
-
Explain why features are enabled for the given package:
+
Explain why features are enabled for the syn package:
-
cargo tree -e features -i -p syn
+
cargo tree -e features -i syn
The -e features flag is used to show features. The -i flag is used to
-invert the graph so that it displays the packages that depend on syn (not
-what syn depends on). An example of what this would display:
+invert the graph so that it displays the packages that depend on syn. An
+example of what this would display:
diff --git a/src/etc/man/cargo-tree.1 b/src/etc/man/cargo-tree.1
index 0cadfaaeb2b..24031b3e29e 100644
--- a/src/etc/man/cargo-tree.1
+++ b/src/etc/man/cargo-tree.1
@@ -40,18 +40,18 @@ of a simple project that depends on the "rand" package:
.if n .RS 4
.nf
myproject v0.1.0 (/myproject)
-└── rand v0.7.3
- ├── getrandom v0.1.14
- │ ├── cfg\-if v0.1.10
- │ └── libc v0.2.68
- ├── libc v0.2.68 (*)
- ├── rand_chacha v0.2.2
- │ ├── ppv\-lite86 v0.2.6
- │ └── rand_core v0.5.1
- │ └── getrandom v0.1.14 (*)
- └── rand_core v0.5.1 (*)
+`\-\- rand v0.7.3
+ |\-\- getrandom v0.1.14
+ | |\-\- cfg\-if v0.1.10
+ | `\-\- libc v0.2.68
+ |\-\- libc v0.2.68 (*)
+ |\-\- rand_chacha v0.2.2
+ | |\-\- ppv\-lite86 v0.2.6
+ | `\-\- rand_core v0.5.1
+ | `\-\- getrandom v0.1.14 (*)
+ `\-\- rand_core v0.5.1 (*)
[build\-dependencies]
-└── cc v1.0.50
+`\-\- cc v1.0.50
.fi
.if n .RE
.sp
@@ -66,25 +66,32 @@ each dependency. For example, \fBcargo tree \-e features\fP:
.if n .RS 4
.nf
myproject v0.1.0 (/myproject)
-└── log feature "serde"
- └── log v0.4.8
- ├── serde v1.0.106
- └── cfg\-if feature "default"
- └── cfg\-if v0.1.10
+`\-\- log feature "serde"
+ `\-\- log v0.4.8
+ |\-\- serde v1.0.106
+ `\-\- cfg\-if feature "default"
+ `\-\- cfg\-if v0.1.10
.fi
.if n .RE
.sp
In this tree, \fBmyproject\fP depends on \fBlog\fP with the \fBserde\fP feature. \fBlog\fP in
turn depends on \fBcfg\-if\fP with "default" features. When using \fB\-e features\fP it
-can be helpful to use \fB\-i\fP and \fB\-p\fP flags to show how the features flow into a
-package. See the examples below for more detail.
+can be helpful to use \fB\-i\fP flag to show how the features flow into a package.
+See the examples below for more detail.
.SH "OPTIONS"
.SS "Tree Options"
.sp
-\fB\-i\fP, \fB\-\-invert\fP
+\fB\-i\fP \fISPEC\fP, \fB\-\-invert\fP \fISPEC\fP
.RS 4
-Invert the tree. Typically this flag is used with the \fB\-p\fP flag to show
-the dependencies for a specific package.
+Show the reverse dependencies for the given package. This flag will invert
+the tree and display the packages that depend on the given package.
+.sp
+Note that in a workspace, by default it will only display the package\(cqs
+reverse dependencies inside the tree of the workspace member in the current
+directory. The \fB\-\-workspace\fP flag can be used to extend it so that it will
+show the package\(cqs reverse dependencies across the entire workspace. The \fB\-p\fP
+flag can be used to display the package\(cqs reverse dependencies only with the
+subtree of the package given to \fB\-p\fP.
.RE
.sp
\fB\-\-no\-dedupe\fP
@@ -516,11 +523,11 @@ cargo tree
. sp -1
. IP " 2." 4.2
.\}
-Display all the packages that depend on the specified package:
+Display all the packages that depend on the \fBsyn\fP package:
.sp
.if n .RS 4
.nf
-cargo tree \-i \-p syn
+cargo tree \-i syn
.fi
.if n .RE
.RE
@@ -568,41 +575,41 @@ cargo tree \-d
. sp -1
. IP " 5." 4.2
.\}
-Explain why features are enabled for the given package:
+Explain why features are enabled for the \fBsyn\fP package:
.sp
.if n .RS 4
.nf
-cargo tree \-e features \-i \-p syn
+cargo tree \-e features \-i syn
.fi
.if n .RE
.sp
The \fB\-e features\fP flag is used to show features. The \fB\-i\fP flag is used to
-invert the graph so that it displays the packages that depend on \fBsyn\fP (not
-what \fBsyn\fP depends on). An example of what this would display:
+invert the graph so that it displays the packages that depend on \fBsyn\fP. An
+example of what this would display:
.sp
.if n .RS 4
.nf
syn v1.0.17
-├── syn feature "clone\-impls"
-│ └── syn feature "default"
-│ └── rustversion v1.0.2
-│ └── rustversion feature "default"
-│ └── myproject v0.1.0 (/myproject)
-│ └── myproject feature "default" (command\-line)
-├── syn feature "default" (*)
-├── syn feature "derive"
-│ └── syn feature "default" (*)
-├── syn feature "full"
-│ └── rustversion v1.0.2 (*)
-├── syn feature "parsing"
-│ └── syn feature "default" (*)
-├── syn feature "printing"
-│ └── syn feature "default" (*)
-├── syn feature "proc\-macro"
-│ └── syn feature "default" (*)
-└── syn feature "quote"
- ├── syn feature "printing" (*)
- └── syn feature "proc\-macro" (*)
+|\-\- syn feature "clone\-impls"
+| `\-\- syn feature "default"
+| `\-\- rustversion v1.0.2
+| `\-\- rustversion feature "default"
+| `\-\- myproject v0.1.0 (/myproject)
+| `\-\- myproject feature "default" (command\-line)
+|\-\- syn feature "default" (*)
+|\-\- syn feature "derive"
+| `\-\- syn feature "default" (*)
+|\-\- syn feature "full"
+| `\-\- rustversion v1.0.2 (*)
+|\-\- syn feature "parsing"
+| `\-\- syn feature "default" (*)
+|\-\- syn feature "printing"
+| `\-\- syn feature "default" (*)
+|\-\- syn feature "proc\-macro"
+| `\-\- syn feature "default" (*)
+`\-\- syn feature "quote"
+ |\-\- syn feature "printing" (*)
+ `\-\- syn feature "proc\-macro" (*)
.fi
.if n .RE
.sp
diff --git a/tests/testsuite/tree.rs b/tests/testsuite/tree.rs
index 097f7c0ba39..a8059228d7f 100644
--- a/tests/testsuite/tree.rs
+++ b/tests/testsuite/tree.rs
@@ -582,7 +582,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree --invert")
+ p.cargo("tree --invert foo")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
@@ -630,7 +630,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree --invert -p c")
+ p.cargo("tree --invert c")
.with_stdout(
"\
c v1.0.0
@@ -644,7 +644,7 @@ c v1.0.0
#[cargo_test]
fn invert_with_build_dep() {
- // -i with -p for a common dependency between normal and build deps.
+ // -i for a common dependency between normal and build deps.
Package::new("common", "1.0.0").publish();
Package::new("bdep", "1.0.0").dep("common", "1.0").publish();
let p = project()
@@ -677,7 +677,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree -i -p common")
+ p.cargo("tree -i common")
.with_stdout(
"\
common v1.0.0
@@ -1136,8 +1136,8 @@ bar v1.0.0
)
.run();
- // invert -p
- p.cargo("tree -i -p optdep")
+ // invert
+ p.cargo("tree -i optdep")
.with_stdout(
"\
optdep v1.0.0
@@ -1149,7 +1149,7 @@ optdep v1.0.0
)
.run();
- p.cargo("tree -i -p optdep -Zfeatures=host_dep")
+ p.cargo("tree -i optdep -Zfeatures=host_dep")
.masquerade_as_nightly_cargo()
.with_stdout(
"\
@@ -1252,8 +1252,8 @@ somedep v1.0.0
)
.run();
- // invert -p
- p.cargo("tree -i -p somedep")
+ // invert
+ p.cargo("tree -i somedep")
.with_stdout(
"\
somedep v1.0.0
@@ -1264,7 +1264,7 @@ somedep v1.0.0
)
.run();
- p.cargo("tree -i -p somedep -Zfeatures=host_dep")
+ p.cargo("tree -i somedep -Zfeatures=host_dep")
.masquerade_as_nightly_cargo()
.with_stdout(
"\
diff --git a/tests/testsuite/tree_graph_features.rs b/tests/testsuite/tree_graph_features.rs
index e7ee106a3b9..2c90482ef80 100644
--- a/tests/testsuite/tree_graph_features.rs
+++ b/tests/testsuite/tree_graph_features.rs
@@ -148,7 +148,7 @@ b v0.1.0 ([..]/foo/b)
)
.run();
- p.cargo("tree -e features -i")
+ p.cargo("tree -e features -i a -i b")
.with_stdout(
"\
a v0.1.0 ([..]/foo/a)
@@ -211,7 +211,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree -e features --features f1 -i")
+ p.cargo("tree -e features --features f1 -i foo")
.with_stdout(
"\
foo v0.1.0 ([..]/foo)
@@ -223,7 +223,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree -e features --features f1 -p notopt -i")
+ p.cargo("tree -e features --features f1 -i notopt")
.with_stdout(
"\
notopt v1.0.0
@@ -241,7 +241,7 @@ notopt v1.0.0
)
.run();
- p.cargo("tree -e features --features notopt/animal -p notopt -i")
+ p.cargo("tree -e features --features notopt/animal -i notopt")
.with_stdout(
"\
notopt v1.0.0
@@ -269,7 +269,7 @@ foo v0.1.0 ([..]/foo)
)
.run();
- p.cargo("tree -e features --all-features -p opt2 -i")
+ p.cargo("tree -e features --all-features -i opt2")
.with_stdout(
"\
opt2 v1.0.0