mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-25 11:14:46 +00:00
refactor(resolve): allow multiple resolved feature sets in workspace resolve
This commit is contained in:
parent
403f1e12f6
commit
73b5b33e1d
@ -96,7 +96,7 @@ pub fn resolve_std<'gctx>(
|
|||||||
&features, /*all_features*/ false, /*uses_default_features*/ false,
|
&features, /*all_features*/ false, /*uses_default_features*/ false,
|
||||||
)?;
|
)?;
|
||||||
let dry_run = false;
|
let dry_run = false;
|
||||||
let resolve = ops::resolve_ws_with_opts(
|
let mut resolve = ops::resolve_ws_with_opts(
|
||||||
&std_ws,
|
&std_ws,
|
||||||
target_data,
|
target_data,
|
||||||
&build_config.requested_kinds,
|
&build_config.requested_kinds,
|
||||||
@ -106,10 +106,15 @@ pub fn resolve_std<'gctx>(
|
|||||||
crate::core::resolver::features::ForceAllTargets::No,
|
crate::core::resolver::features::ForceAllTargets::No,
|
||||||
dry_run,
|
dry_run,
|
||||||
)?;
|
)?;
|
||||||
|
debug_assert_eq!(resolve.specs_and_features.len(), 1);
|
||||||
Ok((
|
Ok((
|
||||||
resolve.pkg_set,
|
resolve.pkg_set,
|
||||||
resolve.targeted_resolve,
|
resolve.targeted_resolve,
|
||||||
resolve.resolved_features,
|
resolve
|
||||||
|
.specs_and_features
|
||||||
|
.pop()
|
||||||
|
.expect("resolve should have a single spec with resolved features")
|
||||||
|
.resolved_features,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@ use crate::core::resolver::{HasDevUnits, Resolve};
|
|||||||
use crate::core::{PackageId, PackageSet, SourceId, TargetKind, Workspace};
|
use crate::core::{PackageId, PackageSet, SourceId, TargetKind, Workspace};
|
||||||
use crate::drop_println;
|
use crate::drop_println;
|
||||||
use crate::ops;
|
use crate::ops;
|
||||||
use crate::ops::resolve::WorkspaceResolve;
|
use crate::ops::resolve::{SpecsAndResolvedFeatures, WorkspaceResolve};
|
||||||
use crate::util::context::{GlobalContext, WarningHandling};
|
use crate::util::context::{GlobalContext, WarningHandling};
|
||||||
use crate::util::interning::InternedString;
|
use crate::util::interning::InternedString;
|
||||||
use crate::util::{CargoResult, StableHasher};
|
use crate::util::{CargoResult, StableHasher};
|
||||||
@ -284,7 +284,7 @@ pub fn create_bcx<'a, 'gctx>(
|
|||||||
mut pkg_set,
|
mut pkg_set,
|
||||||
workspace_resolve,
|
workspace_resolve,
|
||||||
targeted_resolve: resolve,
|
targeted_resolve: resolve,
|
||||||
resolved_features,
|
specs_and_features,
|
||||||
} = resolve;
|
} = resolve;
|
||||||
|
|
||||||
let std_resolve_features = if let Some(crates) = &gctx.cli_unstable().build_std {
|
let std_resolve_features = if let Some(crates) = &gctx.cli_unstable().build_std {
|
||||||
@ -363,72 +363,91 @@ pub fn create_bcx<'a, 'gctx>(
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Passing `build_config.requested_kinds` instead of
|
let mut units = Vec::new();
|
||||||
// `explicit_host_kinds` here so that `generate_root_units` can do
|
let mut unit_graph = HashMap::new();
|
||||||
// its own special handling of `CompileKind::Host`. It will
|
let mut scrape_units = Vec::new();
|
||||||
// internally replace the host kind by the `explicit_host_kind`
|
|
||||||
// before setting as a unit.
|
|
||||||
let generator = UnitGenerator {
|
|
||||||
ws,
|
|
||||||
packages: &to_builds,
|
|
||||||
spec,
|
|
||||||
target_data: &target_data,
|
|
||||||
filter,
|
|
||||||
requested_kinds: &build_config.requested_kinds,
|
|
||||||
explicit_host_kind,
|
|
||||||
intent: build_config.intent,
|
|
||||||
resolve: &resolve,
|
|
||||||
workspace_resolve: &workspace_resolve,
|
|
||||||
resolved_features: &resolved_features,
|
|
||||||
package_set: &pkg_set,
|
|
||||||
profiles: &profiles,
|
|
||||||
interner,
|
|
||||||
has_dev_units,
|
|
||||||
};
|
|
||||||
let mut units = generator.generate_root_units()?;
|
|
||||||
|
|
||||||
if let Some(args) = target_rustc_crate_types {
|
for SpecsAndResolvedFeatures {
|
||||||
override_rustc_crate_types(&mut units, args, interner)?;
|
specs,
|
||||||
}
|
resolved_features,
|
||||||
|
} in &specs_and_features
|
||||||
let should_scrape = build_config.intent.is_doc() && gctx.cli_unstable().rustdoc_scrape_examples;
|
{
|
||||||
let mut scrape_units = if should_scrape {
|
// Passing `build_config.requested_kinds` instead of
|
||||||
generator.generate_scrape_units(&units)?
|
// `explicit_host_kinds` here so that `generate_root_units` can do
|
||||||
} else {
|
// its own special handling of `CompileKind::Host`. It will
|
||||||
Vec::new()
|
// internally replace the host kind by the `explicit_host_kind`
|
||||||
};
|
// before setting as a unit.
|
||||||
|
let spec_names = specs.iter().map(|spec| spec.name()).collect::<Vec<_>>();
|
||||||
let std_roots = if let Some(crates) = gctx.cli_unstable().build_std.as_ref() {
|
let packages = to_builds
|
||||||
let (std_resolve, std_features) = std_resolve_features.as_ref().unwrap();
|
.iter()
|
||||||
standard_lib::generate_std_roots(
|
.filter(|package| spec_names.contains(&package.name().as_str()))
|
||||||
&crates,
|
.cloned()
|
||||||
&units,
|
.collect::<Vec<_>>();
|
||||||
std_resolve,
|
let generator = UnitGenerator {
|
||||||
std_features,
|
ws,
|
||||||
&explicit_host_kinds,
|
packages: &packages,
|
||||||
&pkg_set,
|
spec,
|
||||||
|
target_data: &target_data,
|
||||||
|
filter,
|
||||||
|
requested_kinds: &build_config.requested_kinds,
|
||||||
|
explicit_host_kind,
|
||||||
|
intent: build_config.intent,
|
||||||
|
resolve: &resolve,
|
||||||
|
workspace_resolve: &workspace_resolve,
|
||||||
|
resolved_features: &resolved_features,
|
||||||
|
package_set: &pkg_set,
|
||||||
|
profiles: &profiles,
|
||||||
interner,
|
interner,
|
||||||
&profiles,
|
has_dev_units,
|
||||||
&target_data,
|
};
|
||||||
)?
|
let mut targeted_root_units = generator.generate_root_units()?;
|
||||||
} else {
|
|
||||||
Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut unit_graph = build_unit_dependencies(
|
if let Some(args) = target_rustc_crate_types {
|
||||||
ws,
|
override_rustc_crate_types(&mut targeted_root_units, args, interner)?;
|
||||||
&pkg_set,
|
}
|
||||||
&resolve,
|
|
||||||
&resolved_features,
|
let should_scrape =
|
||||||
std_resolve_features.as_ref(),
|
build_config.intent.is_doc() && gctx.cli_unstable().rustdoc_scrape_examples;
|
||||||
&units,
|
let targeted_scrape_units = if should_scrape {
|
||||||
&scrape_units,
|
generator.generate_scrape_units(&targeted_root_units)?
|
||||||
&std_roots,
|
} else {
|
||||||
build_config.intent,
|
Vec::new()
|
||||||
&target_data,
|
};
|
||||||
&profiles,
|
|
||||||
interner,
|
let std_roots = if let Some(crates) = gctx.cli_unstable().build_std.as_ref() {
|
||||||
)?;
|
let (std_resolve, std_features) = std_resolve_features.as_ref().unwrap();
|
||||||
|
standard_lib::generate_std_roots(
|
||||||
|
&crates,
|
||||||
|
&targeted_root_units,
|
||||||
|
std_resolve,
|
||||||
|
std_features,
|
||||||
|
&explicit_host_kinds,
|
||||||
|
&pkg_set,
|
||||||
|
interner,
|
||||||
|
&profiles,
|
||||||
|
&target_data,
|
||||||
|
)?
|
||||||
|
} else {
|
||||||
|
Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
unit_graph.extend(build_unit_dependencies(
|
||||||
|
ws,
|
||||||
|
&pkg_set,
|
||||||
|
&resolve,
|
||||||
|
&resolved_features,
|
||||||
|
std_resolve_features.as_ref(),
|
||||||
|
&targeted_root_units,
|
||||||
|
&targeted_scrape_units,
|
||||||
|
&std_roots,
|
||||||
|
build_config.intent,
|
||||||
|
&target_data,
|
||||||
|
&profiles,
|
||||||
|
interner,
|
||||||
|
)?);
|
||||||
|
units.extend(targeted_root_units);
|
||||||
|
scrape_units.extend(targeted_scrape_units);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: In theory, Cargo should also dedupe the roots, but I'm uncertain
|
// TODO: In theory, Cargo should also dedupe the roots, but I'm uncertain
|
||||||
// what heuristics to use in that case.
|
// what heuristics to use in that case.
|
||||||
|
@ -588,7 +588,15 @@ fn check_resolver_change<'gctx>(
|
|||||||
feature_opts,
|
feature_opts,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let diffs = v2_features.compare_legacy(&ws_resolve.resolved_features);
|
if ws_resolve.specs_and_features.len() != 1 {
|
||||||
|
bail!(r#"cannot fix edition when using `feature-unification = "package"`."#);
|
||||||
|
}
|
||||||
|
let resolved_features = &ws_resolve
|
||||||
|
.specs_and_features
|
||||||
|
.first()
|
||||||
|
.expect("We've already checked that there is exactly one.")
|
||||||
|
.resolved_features;
|
||||||
|
let diffs = v2_features.compare_legacy(resolved_features);
|
||||||
Ok((ws_resolve, diffs))
|
Ok((ws_resolve, diffs))
|
||||||
};
|
};
|
||||||
let (_, without_dev_diffs) = resolve_differences(HasDevUnits::No)?;
|
let (_, without_dev_diffs) = resolve_differences(HasDevUnits::No)?;
|
||||||
|
@ -81,7 +81,9 @@ use crate::util::CanonicalUrl;
|
|||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use cargo_util::paths;
|
use cargo_util::paths;
|
||||||
use cargo_util_schemas::core::PartialVersion;
|
use cargo_util_schemas::core::PartialVersion;
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use std::rc::Rc;
|
||||||
use tracing::{debug, trace};
|
use tracing::{debug, trace};
|
||||||
|
|
||||||
/// Filter for keep using Package ID from previous lockfile.
|
/// Filter for keep using Package ID from previous lockfile.
|
||||||
@ -96,9 +98,18 @@ pub struct WorkspaceResolve<'gctx> {
|
|||||||
/// This may be `None` for things like `cargo install` and `-Zavoid-dev-deps`.
|
/// This may be `None` for things like `cargo install` and `-Zavoid-dev-deps`.
|
||||||
/// This does not include `paths` overrides.
|
/// This does not include `paths` overrides.
|
||||||
pub workspace_resolve: Option<Resolve>,
|
pub workspace_resolve: Option<Resolve>,
|
||||||
/// The narrowed resolve, with the specific features enabled, and only the
|
/// The narrowed resolve, with the specific features enabled.
|
||||||
/// given package specs requested.
|
|
||||||
pub targeted_resolve: Resolve,
|
pub targeted_resolve: Resolve,
|
||||||
|
/// Package specs requested for compilation along with specific features enabled. This usually
|
||||||
|
/// has the length of one but there may be more specs with different features when using the
|
||||||
|
/// `package` feature resolver.
|
||||||
|
pub specs_and_features: Vec<SpecsAndResolvedFeatures>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pair of package specs requested for compilation along with enabled features.
|
||||||
|
pub struct SpecsAndResolvedFeatures {
|
||||||
|
/// Packages that are supposed to be built.
|
||||||
|
pub specs: Vec<PackageIdSpec>,
|
||||||
/// The features activated per package.
|
/// The features activated per package.
|
||||||
pub resolved_features: ResolvedFeatures,
|
pub resolved_features: ResolvedFeatures,
|
||||||
}
|
}
|
||||||
@ -145,10 +156,20 @@ pub fn resolve_ws_with_opts<'gctx>(
|
|||||||
force_all_targets: ForceAllTargets,
|
force_all_targets: ForceAllTargets,
|
||||||
dry_run: bool,
|
dry_run: bool,
|
||||||
) -> CargoResult<WorkspaceResolve<'gctx>> {
|
) -> CargoResult<WorkspaceResolve<'gctx>> {
|
||||||
let specs = match ws.resolve_feature_unification() {
|
let feature_unification = ws.resolve_feature_unification();
|
||||||
FeatureUnification::Selected => specs,
|
let individual_specs = match feature_unification {
|
||||||
FeatureUnification::Workspace => &ops::Packages::All(Vec::new()).to_package_id_specs(ws)?,
|
FeatureUnification::Selected => vec![specs.to_owned()],
|
||||||
|
FeatureUnification::Workspace => {
|
||||||
|
vec![ops::Packages::All(Vec::new()).to_package_id_specs(ws)?]
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
let specs: Vec<_> = individual_specs
|
||||||
|
.iter()
|
||||||
|
.map(|specs| specs.iter())
|
||||||
|
.flatten()
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
let specs = &specs[..];
|
||||||
let mut registry = ws.package_registry()?;
|
let mut registry = ws.package_registry()?;
|
||||||
let (resolve, resolved_with_overrides) = if ws.ignore_lock() {
|
let (resolve, resolved_with_overrides) = if ws.ignore_lock() {
|
||||||
let add_patches = true;
|
let add_patches = true;
|
||||||
@ -229,9 +250,9 @@ pub fn resolve_ws_with_opts<'gctx>(
|
|||||||
|
|
||||||
let pkg_set = get_resolved_packages(&resolved_with_overrides, registry)?;
|
let pkg_set = get_resolved_packages(&resolved_with_overrides, registry)?;
|
||||||
|
|
||||||
let member_ids = ws
|
let members_with_features = ws.members_with_features(specs, cli_features)?;
|
||||||
.members_with_features(specs, cli_features)?
|
let member_ids = members_with_features
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|(p, _fts)| p.package_id())
|
.map(|(p, _fts)| p.package_id())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
pkg_set.download_accessible(
|
pkg_set.download_accessible(
|
||||||
@ -243,33 +264,49 @@ pub fn resolve_ws_with_opts<'gctx>(
|
|||||||
force_all_targets,
|
force_all_targets,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let feature_opts = FeatureOpts::new(ws, has_dev_units, force_all_targets)?;
|
let mut specs_and_features = Vec::new();
|
||||||
let resolved_features = FeatureResolver::resolve(
|
|
||||||
ws,
|
|
||||||
target_data,
|
|
||||||
&resolved_with_overrides,
|
|
||||||
&pkg_set,
|
|
||||||
cli_features,
|
|
||||||
specs,
|
|
||||||
requested_targets,
|
|
||||||
feature_opts,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
pkg_set.warn_no_lib_packages_and_artifact_libs_overlapping_deps(
|
for specs in individual_specs {
|
||||||
ws,
|
let feature_opts = FeatureOpts::new(ws, has_dev_units, force_all_targets)?;
|
||||||
&resolved_with_overrides,
|
|
||||||
&member_ids,
|
let narrowed_features = match feature_unification {
|
||||||
has_dev_units,
|
FeatureUnification::Selected | FeatureUnification::Workspace => {
|
||||||
requested_targets,
|
Cow::Borrowed(cli_features)
|
||||||
target_data,
|
}
|
||||||
force_all_targets,
|
};
|
||||||
)?;
|
|
||||||
|
let resolved_features = FeatureResolver::resolve(
|
||||||
|
ws,
|
||||||
|
target_data,
|
||||||
|
&resolved_with_overrides,
|
||||||
|
&pkg_set,
|
||||||
|
&*narrowed_features,
|
||||||
|
&specs,
|
||||||
|
requested_targets,
|
||||||
|
feature_opts,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
pkg_set.warn_no_lib_packages_and_artifact_libs_overlapping_deps(
|
||||||
|
ws,
|
||||||
|
&resolved_with_overrides,
|
||||||
|
&member_ids,
|
||||||
|
has_dev_units,
|
||||||
|
requested_targets,
|
||||||
|
target_data,
|
||||||
|
force_all_targets,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
specs_and_features.push(SpecsAndResolvedFeatures {
|
||||||
|
specs,
|
||||||
|
resolved_features,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Ok(WorkspaceResolve {
|
Ok(WorkspaceResolve {
|
||||||
pkg_set,
|
pkg_set,
|
||||||
workspace_resolve: resolve,
|
workspace_resolve: resolve,
|
||||||
targeted_resolve: resolved_with_overrides,
|
targeted_resolve: resolved_with_overrides,
|
||||||
resolved_features,
|
specs_and_features,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ use crate::core::compiler::{CompileKind, RustcTargetData};
|
|||||||
use crate::core::dependency::DepKind;
|
use crate::core::dependency::DepKind;
|
||||||
use crate::core::resolver::{features::CliFeatures, ForceAllTargets, HasDevUnits};
|
use crate::core::resolver::{features::CliFeatures, ForceAllTargets, HasDevUnits};
|
||||||
use crate::core::{Package, PackageId, PackageIdSpec, PackageIdSpecQuery, Workspace};
|
use crate::core::{Package, PackageId, PackageIdSpec, PackageIdSpecQuery, Workspace};
|
||||||
|
use crate::ops::resolve::SpecsAndResolvedFeatures;
|
||||||
use crate::ops::{self, Packages};
|
use crate::ops::{self, Packages};
|
||||||
use crate::util::CargoResult;
|
use crate::util::CargoResult;
|
||||||
use crate::{drop_print, drop_println};
|
use crate::{drop_print, drop_println};
|
||||||
@ -179,61 +180,67 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
|
|||||||
.map(|pkg| (pkg.package_id(), pkg))
|
.map(|pkg| (pkg.package_id(), pkg))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut graph = graph::build(
|
for SpecsAndResolvedFeatures {
|
||||||
ws,
|
specs,
|
||||||
&ws_resolve.targeted_resolve,
|
resolved_features,
|
||||||
&ws_resolve.resolved_features,
|
} in ws_resolve.specs_and_features
|
||||||
&specs,
|
{
|
||||||
&opts.cli_features,
|
let mut graph = graph::build(
|
||||||
&target_data,
|
ws,
|
||||||
&requested_kinds,
|
&ws_resolve.targeted_resolve,
|
||||||
package_map,
|
&resolved_features,
|
||||||
opts,
|
&specs,
|
||||||
)?;
|
&opts.cli_features,
|
||||||
|
&target_data,
|
||||||
let root_specs = if opts.invert.is_empty() {
|
&requested_kinds,
|
||||||
specs
|
package_map.clone(),
|
||||||
} else {
|
opts,
|
||||||
opts.invert
|
|
||||||
.iter()
|
|
||||||
.map(|p| PackageIdSpec::parse(p))
|
|
||||||
.collect::<Result<Vec<PackageIdSpec>, _>>()?
|
|
||||||
};
|
|
||||||
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 {
|
|
||||||
// `-d -p foo` will only show duplicates within foo's subtree
|
|
||||||
graph = graph.from_reachable(root_indexes.as_slice());
|
|
||||||
graph.find_duplicates()
|
|
||||||
} else {
|
|
||||||
root_indexes
|
|
||||||
};
|
|
||||||
|
|
||||||
if !opts.invert.is_empty() || opts.duplicates {
|
|
||||||
graph.invert();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Packages to prune.
|
|
||||||
let pkgs_to_prune = opts
|
|
||||||
.pkgs_to_prune
|
|
||||||
.iter()
|
|
||||||
.map(|p| PackageIdSpec::parse(p).map_err(Into::into))
|
|
||||||
.map(|r| {
|
|
||||||
// Provide an error message if pkgid is not within the resolved
|
|
||||||
// dependencies graph.
|
|
||||||
r.and_then(|spec| spec.query(ws_resolve.targeted_resolve.iter()).and(Ok(spec)))
|
|
||||||
})
|
|
||||||
.collect::<CargoResult<Vec<PackageIdSpec>>>()?;
|
|
||||||
|
|
||||||
if root_indexes.len() == 0 {
|
|
||||||
ws.gctx().shell().warn(
|
|
||||||
"nothing to print.\n\n\
|
|
||||||
To find dependencies that require specific target platforms, \
|
|
||||||
try to use option `--target all` first, and then narrow your search scope accordingly.",
|
|
||||||
)?;
|
)?;
|
||||||
} else {
|
|
||||||
print(ws, opts, root_indexes, &pkgs_to_prune, &graph)?;
|
let root_specs = if opts.invert.is_empty() {
|
||||||
|
specs
|
||||||
|
} else {
|
||||||
|
opts.invert
|
||||||
|
.iter()
|
||||||
|
.map(|p| PackageIdSpec::parse(p))
|
||||||
|
.collect::<Result<Vec<PackageIdSpec>, _>>()?
|
||||||
|
};
|
||||||
|
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 {
|
||||||
|
// `-d -p foo` will only show duplicates within foo's subtree
|
||||||
|
graph = graph.from_reachable(root_indexes.as_slice());
|
||||||
|
graph.find_duplicates()
|
||||||
|
} else {
|
||||||
|
root_indexes
|
||||||
|
};
|
||||||
|
|
||||||
|
if !opts.invert.is_empty() || opts.duplicates {
|
||||||
|
graph.invert();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Packages to prune.
|
||||||
|
let pkgs_to_prune = opts
|
||||||
|
.pkgs_to_prune
|
||||||
|
.iter()
|
||||||
|
.map(|p| PackageIdSpec::parse(p).map_err(Into::into))
|
||||||
|
.map(|r| {
|
||||||
|
// Provide an error message if pkgid is not within the resolved
|
||||||
|
// dependencies graph.
|
||||||
|
r.and_then(|spec| spec.query(ws_resolve.targeted_resolve.iter()).and(Ok(spec)))
|
||||||
|
})
|
||||||
|
.collect::<CargoResult<Vec<PackageIdSpec>>>()?;
|
||||||
|
|
||||||
|
if root_indexes.len() == 0 {
|
||||||
|
ws.gctx().shell().warn(
|
||||||
|
"nothing to print.\n\n\
|
||||||
|
To find dependencies that require specific target platforms, \
|
||||||
|
try to use option `--target all` first, and then narrow your search scope accordingly.",
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
print(ws, opts, root_indexes, &pkgs_to_prune, &graph)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user