mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
Refactor feature handling, and improve error messages.
This commit is contained in:
parent
cc70d60a9e
commit
85854b1884
@ -44,9 +44,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let options = OutputMetadataOptions {
|
let options = OutputMetadataOptions {
|
||||||
features: values(args, "features"),
|
cli_features: args.cli_features()?,
|
||||||
all_features: args.is_present("all-features"),
|
|
||||||
no_default_features: args.is_present("no-default-features"),
|
|
||||||
no_deps: args.is_present("no-deps"),
|
no_deps: args.is_present("no-deps"),
|
||||||
filter_platforms: args._values_of("filter-platform"),
|
filter_platforms: args._values_of("filter-platform"),
|
||||||
version,
|
version,
|
||||||
|
@ -45,9 +45,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
|||||||
allow_dirty: args.is_present("allow-dirty"),
|
allow_dirty: args.is_present("allow-dirty"),
|
||||||
targets: args.targets(),
|
targets: args.targets(),
|
||||||
jobs: args.jobs()?,
|
jobs: args.jobs()?,
|
||||||
features: args._values_of("features"),
|
cli_features: args.cli_features()?,
|
||||||
all_features: args.is_present("all-features"),
|
|
||||||
no_default_features: args.is_present("no-default-features"),
|
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -45,9 +45,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
|
|||||||
jobs: args.jobs()?,
|
jobs: args.jobs()?,
|
||||||
dry_run: args.is_present("dry-run"),
|
dry_run: args.is_present("dry-run"),
|
||||||
registry,
|
registry,
|
||||||
features: args._values_of("features"),
|
cli_features: args.cli_features()?,
|
||||||
all_features: args.is_present("all-features"),
|
|
||||||
no_default_features: args.is_present("no-default-features"),
|
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -190,9 +190,7 @@ subtree of the package given to -p.\n\
|
|||||||
let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
|
let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
|
||||||
.map_err(|e| anyhow::anyhow!("{}", e))?;
|
.map_err(|e| anyhow::anyhow!("{}", e))?;
|
||||||
let opts = tree::TreeOptions {
|
let opts = tree::TreeOptions {
|
||||||
features: values(args, "features"),
|
cli_features: args.cli_features()?,
|
||||||
all_features: args.is_present("all-features"),
|
|
||||||
no_default_features: args.is_present("no-default-features"),
|
|
||||||
packages,
|
packages,
|
||||||
target,
|
target,
|
||||||
edge_kinds,
|
edge_kinds,
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
use crate::core::compiler::UnitInterner;
|
use crate::core::compiler::UnitInterner;
|
||||||
use crate::core::compiler::{CompileKind, CompileMode, RustcTargetData, Unit};
|
use crate::core::compiler::{CompileKind, CompileMode, RustcTargetData, Unit};
|
||||||
use crate::core::profiles::{Profiles, UnitFor};
|
use crate::core::profiles::{Profiles, UnitFor};
|
||||||
use crate::core::resolver::features::{FeaturesFor, RequestedFeatures, ResolvedFeatures};
|
use crate::core::resolver::features::{CliFeatures, FeaturesFor, ResolvedFeatures};
|
||||||
use crate::core::resolver::{HasDevUnits, ResolveOpts};
|
use crate::core::resolver::HasDevUnits;
|
||||||
use crate::core::{Dependency, PackageId, PackageSet, Resolve, SourceId, Workspace};
|
use crate::core::{Dependency, PackageId, PackageSet, Resolve, SourceId, Workspace};
|
||||||
use crate::ops::{self, Packages};
|
use crate::ops::{self, Packages};
|
||||||
use crate::util::errors::CargoResult;
|
use crate::util::errors::CargoResult;
|
||||||
@ -107,18 +107,14 @@ pub fn resolve_std<'cfg>(
|
|||||||
"default".to_string(),
|
"default".to_string(),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
// dev_deps setting shouldn't really matter here.
|
let cli_features = CliFeatures::from_command_line(
|
||||||
let opts = ResolveOpts::new(
|
&features, /*all_features*/ false, /*uses_default_features*/ false,
|
||||||
/*dev_deps*/ false,
|
)?;
|
||||||
RequestedFeatures::from_command_line(
|
|
||||||
&features, /*all_features*/ false, /*uses_default_features*/ false,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
let resolve = ops::resolve_ws_with_opts(
|
let resolve = ops::resolve_ws_with_opts(
|
||||||
&std_ws,
|
&std_ws,
|
||||||
target_data,
|
target_data,
|
||||||
requested_targets,
|
requested_targets,
|
||||||
&opts,
|
&cli_features,
|
||||||
&specs,
|
&specs,
|
||||||
HasDevUnits::No,
|
HasDevUnits::No,
|
||||||
crate::core::resolver::features::ForceAllTargets::No,
|
crate::core::resolver::features::ForceAllTargets::No,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::dep_cache::RegistryQueryer;
|
use super::dep_cache::RegistryQueryer;
|
||||||
use super::errors::ActivateResult;
|
use super::errors::ActivateResult;
|
||||||
use super::types::{ConflictMap, ConflictReason, FeaturesSet, ResolveOpts};
|
use super::types::{ConflictMap, ConflictReason, FeaturesSet, ResolveOpts};
|
||||||
|
use super::RequestedFeatures;
|
||||||
use crate::core::{Dependency, PackageId, SourceId, Summary};
|
use crate::core::{Dependency, PackageId, SourceId, Summary};
|
||||||
use crate::util::interning::InternedString;
|
use crate::util::interning::InternedString;
|
||||||
use crate::util::Graph;
|
use crate::util::Graph;
|
||||||
@ -160,23 +161,32 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!("checking if {} is already activated", summary.package_id());
|
debug!("checking if {} is already activated", summary.package_id());
|
||||||
if opts.features.all_features {
|
match &opts.features {
|
||||||
return Ok(false);
|
// This returns `false` for CliFeatures just for simplicity. It
|
||||||
|
// would take a bit of work to compare since they are not in the
|
||||||
|
// same format as DepFeatures (and that may be expensive
|
||||||
|
// performance-wise). Also, it should only occur once for a root
|
||||||
|
// package. The only drawback is that it may re-activate a root
|
||||||
|
// package again, which should only affect performance, but that
|
||||||
|
// should be rare. Cycles should still be detected since those
|
||||||
|
// will have `DepFeatures` edges.
|
||||||
|
RequestedFeatures::CliFeatures(_) => return Ok(false),
|
||||||
|
RequestedFeatures::DepFeatures {
|
||||||
|
features,
|
||||||
|
uses_default_features,
|
||||||
|
} => {
|
||||||
|
let has_default_feature = summary.features().contains_key("default");
|
||||||
|
Ok(match self.resolve_features.get(&id) {
|
||||||
|
Some(prev) => {
|
||||||
|
features.is_subset(prev)
|
||||||
|
&& (!uses_default_features
|
||||||
|
|| prev.contains("default")
|
||||||
|
|| !has_default_feature)
|
||||||
|
}
|
||||||
|
None => features.is_empty() && (!uses_default_features || !has_default_feature),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let has_default_feature = summary.features().contains_key("default");
|
|
||||||
Ok(match self.resolve_features.get(&id) {
|
|
||||||
Some(prev) => {
|
|
||||||
opts.features.features.is_subset(prev)
|
|
||||||
&& (!opts.features.uses_default_features
|
|
||||||
|| prev.contains("default")
|
|
||||||
|| !has_default_feature)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
opts.features.features.is_empty()
|
|
||||||
&& (!opts.features.uses_default_features || !has_default_feature)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the package is active returns the `ContextAge` when it was added
|
/// If the package is active returns the `ContextAge` when it was added
|
||||||
|
@ -12,7 +12,9 @@
|
|||||||
use crate::core::resolver::context::Context;
|
use crate::core::resolver::context::Context;
|
||||||
use crate::core::resolver::errors::describe_path;
|
use crate::core::resolver::errors::describe_path;
|
||||||
use crate::core::resolver::types::{ConflictReason, DepInfo, FeaturesSet};
|
use crate::core::resolver::types::{ConflictReason, DepInfo, FeaturesSet};
|
||||||
use crate::core::resolver::{ActivateError, ActivateResult, ResolveOpts};
|
use crate::core::resolver::{
|
||||||
|
ActivateError, ActivateResult, CliFeatures, RequestedFeatures, ResolveOpts,
|
||||||
|
};
|
||||||
use crate::core::{Dependency, FeatureValue, PackageId, PackageIdSpec, Registry, Summary};
|
use crate::core::{Dependency, FeatureValue, PackageId, PackageIdSpec, Registry, Summary};
|
||||||
use crate::util::errors::{CargoResult, CargoResultExt};
|
use crate::util::errors::{CargoResult, CargoResultExt};
|
||||||
use crate::util::interning::InternedString;
|
use crate::util::interning::InternedString;
|
||||||
@ -281,15 +283,6 @@ pub fn resolve_features<'b>(
|
|||||||
.unwrap_or(&default_dep)
|
.unwrap_or(&default_dep)
|
||||||
.clone();
|
.clone();
|
||||||
base.extend(dep.features().iter());
|
base.extend(dep.features().iter());
|
||||||
for feature in base.iter() {
|
|
||||||
if feature.contains('/') {
|
|
||||||
return Err(anyhow::format_err!(
|
|
||||||
"feature names may not contain slashes: `{}`",
|
|
||||||
feature
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret.push((dep.clone(), Rc::new(base)));
|
ret.push((dep.clone(), Rc::new(base)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,30 +310,46 @@ fn build_requirements<'a, 'b: 'a>(
|
|||||||
) -> ActivateResult<Requirements<'a>> {
|
) -> ActivateResult<Requirements<'a>> {
|
||||||
let mut reqs = Requirements::new(s);
|
let mut reqs = Requirements::new(s);
|
||||||
|
|
||||||
if opts.features.all_features {
|
let handle_default = |uses_default_features, reqs: &mut Requirements<'_>| {
|
||||||
for key in s.features().keys() {
|
if uses_default_features && s.features().contains_key("default") {
|
||||||
if let Err(e) = reqs.require_feature(*key) {
|
if let Err(e) = reqs.require_feature(InternedString::new("default")) {
|
||||||
return Err(e.into_activate_error(parent, s));
|
return Err(e.into_activate_error(parent, s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
Ok(())
|
||||||
for &f in opts.features.features.iter() {
|
};
|
||||||
let fv = FeatureValue::new(f);
|
|
||||||
if fv.has_dep_prefix() {
|
|
||||||
return Err(ActivateError::Fatal(anyhow::format_err!(
|
|
||||||
"feature value `{}` is not allowed to use explicit `dep:` syntax",
|
|
||||||
fv
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
if let Err(e) = reqs.require_value(&fv) {
|
|
||||||
return Err(e.into_activate_error(parent, s));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.features.uses_default_features && s.features().contains_key("default") {
|
match &opts.features {
|
||||||
if let Err(e) = reqs.require_feature(InternedString::new("default")) {
|
RequestedFeatures::CliFeatures(CliFeatures {
|
||||||
return Err(e.into_activate_error(parent, s));
|
features,
|
||||||
|
all_features,
|
||||||
|
uses_default_features,
|
||||||
|
}) => {
|
||||||
|
if *all_features {
|
||||||
|
for key in s.features().keys() {
|
||||||
|
if let Err(e) = reqs.require_feature(*key) {
|
||||||
|
return Err(e.into_activate_error(parent, s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for fv in features.iter() {
|
||||||
|
if let Err(e) = reqs.require_value(&fv) {
|
||||||
|
return Err(e.into_activate_error(parent, s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handle_default(*uses_default_features, &mut reqs)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RequestedFeatures::DepFeatures {
|
||||||
|
features,
|
||||||
|
uses_default_features,
|
||||||
|
} => {
|
||||||
|
for feature in features.iter() {
|
||||||
|
if let Err(e) = reqs.require_feature(*feature) {
|
||||||
|
return Err(e.into_activate_error(parent, s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handle_default(*uses_default_features, &mut reqs)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ use crate::core::resolver::{Resolve, ResolveBehavior};
|
|||||||
use crate::core::{FeatureValue, PackageId, PackageIdSpec, PackageSet, Workspace};
|
use crate::core::{FeatureValue, PackageId, PackageIdSpec, PackageSet, Workspace};
|
||||||
use crate::util::interning::InternedString;
|
use crate::util::interning::InternedString;
|
||||||
use crate::util::CargoResult;
|
use crate::util::CargoResult;
|
||||||
|
use anyhow::bail;
|
||||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -144,7 +145,7 @@ impl FeatureOpts {
|
|||||||
}
|
}
|
||||||
"compare" => opts.compare = true,
|
"compare" => opts.compare = true,
|
||||||
"ws" => unimplemented!(),
|
"ws" => unimplemented!(),
|
||||||
s => anyhow::bail!("-Zfeatures flag `{}` is not supported", s),
|
s => bail!("-Zfeatures flag `{}` is not supported", s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -197,44 +198,93 @@ impl FeatureOpts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Features flags requested for a package.
|
/// Features flags requested for a package.
|
||||||
|
///
|
||||||
|
/// This should be cheap and fast to clone, it is used in the resolver for
|
||||||
|
/// various caches.
|
||||||
|
///
|
||||||
|
/// This is split into enum variants because the resolver needs to handle
|
||||||
|
/// features coming from different places (command-line and dependency
|
||||||
|
/// declarations), but those different places have different constraints on
|
||||||
|
/// which syntax is allowed. This helps ensure that every place dealing with
|
||||||
|
/// features is properly handling those syntax restrictions.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct RequestedFeatures {
|
pub enum RequestedFeatures {
|
||||||
pub features: FeaturesSet,
|
/// Features requested on the command-line with flags.
|
||||||
|
CliFeatures(CliFeatures),
|
||||||
|
/// Features specified in a dependency declaration.
|
||||||
|
DepFeatures {
|
||||||
|
/// The `features` dependency field.
|
||||||
|
features: FeaturesSet,
|
||||||
|
/// The `default-features` dependency field.
|
||||||
|
uses_default_features: bool,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Features specified on the command-line.
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
|
pub struct CliFeatures {
|
||||||
|
/// Features from the `--features` flag.
|
||||||
|
pub features: Rc<BTreeSet<FeatureValue>>,
|
||||||
|
/// The `--all-features` flag.
|
||||||
pub all_features: bool,
|
pub all_features: bool,
|
||||||
|
/// Inverse of `--no-default-features` flag.
|
||||||
pub uses_default_features: bool,
|
pub uses_default_features: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RequestedFeatures {
|
impl CliFeatures {
|
||||||
/// Creates a new RequestedFeatures from the given command-line flags.
|
/// Creates a new CliFeatures from the given command-line flags.
|
||||||
pub fn from_command_line(
|
pub fn from_command_line(
|
||||||
features: &[String],
|
features: &[String],
|
||||||
all_features: bool,
|
all_features: bool,
|
||||||
uses_default_features: bool,
|
uses_default_features: bool,
|
||||||
) -> RequestedFeatures {
|
) -> CargoResult<CliFeatures> {
|
||||||
RequestedFeatures {
|
let features = Rc::new(CliFeatures::split_features(features));
|
||||||
features: Rc::new(RequestedFeatures::split_features(features)),
|
// Some early validation to ensure correct syntax.
|
||||||
|
for feature in features.iter() {
|
||||||
|
match feature {
|
||||||
|
// Maybe call validate_feature_name here once it is an error?
|
||||||
|
FeatureValue::Feature(_) => {}
|
||||||
|
FeatureValue::Dep { .. }
|
||||||
|
| FeatureValue::DepFeature {
|
||||||
|
dep_prefix: true, ..
|
||||||
|
} => {
|
||||||
|
bail!(
|
||||||
|
"feature `{}` is not allowed to use explicit `dep:` syntax",
|
||||||
|
feature
|
||||||
|
);
|
||||||
|
}
|
||||||
|
FeatureValue::DepFeature { dep_feature, .. } => {
|
||||||
|
if dep_feature.contains('/') {
|
||||||
|
bail!("multiple slashes in feature `{}` is not allowed", feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(CliFeatures {
|
||||||
|
features,
|
||||||
all_features,
|
all_features,
|
||||||
uses_default_features,
|
uses_default_features,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new RequestedFeatures with the given `all_features` setting.
|
/// Creates a new CliFeatures with the given `all_features` setting.
|
||||||
pub fn new_all(all_features: bool) -> RequestedFeatures {
|
pub fn new_all(all_features: bool) -> CliFeatures {
|
||||||
RequestedFeatures {
|
CliFeatures {
|
||||||
features: Rc::new(BTreeSet::new()),
|
features: Rc::new(BTreeSet::new()),
|
||||||
all_features,
|
all_features,
|
||||||
uses_default_features: true,
|
uses_default_features: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split_features(features: &[String]) -> BTreeSet<InternedString> {
|
fn split_features(features: &[String]) -> BTreeSet<FeatureValue> {
|
||||||
features
|
features
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|s| s.split_whitespace())
|
.flat_map(|s| s.split_whitespace())
|
||||||
.flat_map(|s| s.split(','))
|
.flat_map(|s| s.split(','))
|
||||||
.filter(|s| !s.is_empty())
|
.filter(|s| !s.is_empty())
|
||||||
.map(InternedString::new)
|
.map(InternedString::new)
|
||||||
.collect::<BTreeSet<InternedString>>()
|
.map(FeatureValue::new)
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,7 +346,7 @@ impl ResolvedFeatures {
|
|||||||
if let Some(fs) = self.activated_features.get(&(pkg_id, is_build)) {
|
if let Some(fs) = self.activated_features.get(&(pkg_id, is_build)) {
|
||||||
Ok(fs.iter().cloned().collect())
|
Ok(fs.iter().cloned().collect())
|
||||||
} else {
|
} else {
|
||||||
anyhow::bail!("features did not find {:?} {:?}", pkg_id, is_build)
|
bail!("features did not find {:?} {:?}", pkg_id, is_build)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -405,7 +455,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
|||||||
target_data: &RustcTargetData,
|
target_data: &RustcTargetData,
|
||||||
resolve: &Resolve,
|
resolve: &Resolve,
|
||||||
package_set: &'a PackageSet<'cfg>,
|
package_set: &'a PackageSet<'cfg>,
|
||||||
requested_features: &RequestedFeatures,
|
cli_features: &CliFeatures,
|
||||||
specs: &[PackageIdSpec],
|
specs: &[PackageIdSpec],
|
||||||
requested_targets: &[CompileKind],
|
requested_targets: &[CompileKind],
|
||||||
opts: FeatureOpts,
|
opts: FeatureOpts,
|
||||||
@ -437,7 +487,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
|||||||
track_for_host,
|
track_for_host,
|
||||||
deferred_weak_dependencies: HashMap::new(),
|
deferred_weak_dependencies: HashMap::new(),
|
||||||
};
|
};
|
||||||
r.do_resolve(specs, requested_features)?;
|
r.do_resolve(specs, cli_features)?;
|
||||||
log::debug!("features={:#?}", r.activated_features);
|
log::debug!("features={:#?}", r.activated_features);
|
||||||
if r.opts.compare {
|
if r.opts.compare {
|
||||||
r.compare();
|
r.compare();
|
||||||
@ -455,11 +505,11 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
|||||||
fn do_resolve(
|
fn do_resolve(
|
||||||
&mut self,
|
&mut self,
|
||||||
specs: &[PackageIdSpec],
|
specs: &[PackageIdSpec],
|
||||||
requested_features: &RequestedFeatures,
|
cli_features: &CliFeatures,
|
||||||
) -> CargoResult<()> {
|
) -> CargoResult<()> {
|
||||||
let member_features = self.ws.members_with_features(specs, requested_features)?;
|
let member_features = self.ws.members_with_features(specs, cli_features)?;
|
||||||
for (member, requested_features) in &member_features {
|
for (member, cli_features) in &member_features {
|
||||||
let fvs = self.fvs_from_requested(member.package_id(), requested_features);
|
let fvs = self.fvs_from_requested(member.package_id(), cli_features);
|
||||||
let for_host = self.track_for_host && self.is_proc_macro(member.package_id());
|
let for_host = self.track_for_host && self.is_proc_macro(member.package_id());
|
||||||
self.activate_pkg(member.package_id(), for_host, &fvs)?;
|
self.activate_pkg(member.package_id(), for_host, &fvs)?;
|
||||||
if for_host {
|
if for_host {
|
||||||
@ -725,24 +775,19 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
|||||||
fn fvs_from_requested(
|
fn fvs_from_requested(
|
||||||
&self,
|
&self,
|
||||||
pkg_id: PackageId,
|
pkg_id: PackageId,
|
||||||
requested_features: &RequestedFeatures,
|
cli_features: &CliFeatures,
|
||||||
) -> Vec<FeatureValue> {
|
) -> Vec<FeatureValue> {
|
||||||
let summary = self.resolve.summary(pkg_id);
|
let summary = self.resolve.summary(pkg_id);
|
||||||
let feature_map = summary.features();
|
let feature_map = summary.features();
|
||||||
if requested_features.all_features {
|
if cli_features.all_features {
|
||||||
feature_map
|
feature_map
|
||||||
.keys()
|
.keys()
|
||||||
.map(|k| FeatureValue::Feature(*k))
|
.map(|k| FeatureValue::Feature(*k))
|
||||||
.collect()
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
let mut result: Vec<FeatureValue> = requested_features
|
let mut result: Vec<FeatureValue> = cli_features.features.iter().cloned().collect();
|
||||||
.features
|
|
||||||
.as_ref()
|
|
||||||
.iter()
|
|
||||||
.map(|f| FeatureValue::new(*f))
|
|
||||||
.collect();
|
|
||||||
let default = InternedString::new("default");
|
let default = InternedString::new("default");
|
||||||
if requested_features.uses_default_features && feature_map.contains_key(&default) {
|
if cli_features.uses_default_features && feature_map.contains_key(&default) {
|
||||||
result.push(FeatureValue::Feature(default));
|
result.push(FeatureValue::Feature(default));
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
|
@ -69,7 +69,7 @@ use self::types::{FeaturesSet, RcVecIter, RemainingDeps, ResolverProgress};
|
|||||||
pub use self::encode::Metadata;
|
pub use self::encode::Metadata;
|
||||||
pub use self::encode::{EncodableDependency, EncodablePackageId, EncodableResolve};
|
pub use self::encode::{EncodableDependency, EncodablePackageId, EncodableResolve};
|
||||||
pub use self::errors::{ActivateError, ActivateResult, ResolveError};
|
pub use self::errors::{ActivateError, ActivateResult, ResolveError};
|
||||||
pub use self::features::{ForceAllTargets, HasDevUnits};
|
pub use self::features::{CliFeatures, ForceAllTargets, HasDevUnits};
|
||||||
pub use self::resolve::{Resolve, ResolveVersion};
|
pub use self::resolve::{Resolve, ResolveVersion};
|
||||||
pub use self::types::{ResolveBehavior, ResolveOpts};
|
pub use self::types::{ResolveBehavior, ResolveOpts};
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ fn activate_deps_loop(
|
|||||||
// Activate all the initial summaries to kick off some work.
|
// Activate all the initial summaries to kick off some work.
|
||||||
for &(ref summary, ref opts) in summaries {
|
for &(ref summary, ref opts) in summaries {
|
||||||
debug!("initial activation: {}", summary.package_id());
|
debug!("initial activation: {}", summary.package_id());
|
||||||
let res = activate(&mut cx, registry, None, summary.clone(), opts.clone());
|
let res = activate(&mut cx, registry, None, summary.clone(), opts);
|
||||||
match res {
|
match res {
|
||||||
Ok(Some((frame, _))) => remaining_deps.push(frame),
|
Ok(Some((frame, _))) => remaining_deps.push(frame),
|
||||||
Ok(None) => (),
|
Ok(None) => (),
|
||||||
@ -378,9 +378,8 @@ fn activate_deps_loop(
|
|||||||
let pid = candidate.package_id();
|
let pid = candidate.package_id();
|
||||||
let opts = ResolveOpts {
|
let opts = ResolveOpts {
|
||||||
dev_deps: false,
|
dev_deps: false,
|
||||||
features: RequestedFeatures {
|
features: RequestedFeatures::DepFeatures {
|
||||||
features: Rc::clone(&features),
|
features: Rc::clone(&features),
|
||||||
all_features: false,
|
|
||||||
uses_default_features: dep.uses_default_features(),
|
uses_default_features: dep.uses_default_features(),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -391,7 +390,7 @@ fn activate_deps_loop(
|
|||||||
dep.package_name(),
|
dep.package_name(),
|
||||||
candidate.version()
|
candidate.version()
|
||||||
);
|
);
|
||||||
let res = activate(&mut cx, registry, Some((&parent, &dep)), candidate, opts);
|
let res = activate(&mut cx, registry, Some((&parent, &dep)), candidate, &opts);
|
||||||
|
|
||||||
let successfully_activated = match res {
|
let successfully_activated = match res {
|
||||||
// Success! We've now activated our `candidate` in our context
|
// Success! We've now activated our `candidate` in our context
|
||||||
@ -603,7 +602,7 @@ fn activate(
|
|||||||
registry: &mut RegistryQueryer<'_>,
|
registry: &mut RegistryQueryer<'_>,
|
||||||
parent: Option<(&Summary, &Dependency)>,
|
parent: Option<(&Summary, &Dependency)>,
|
||||||
candidate: Summary,
|
candidate: Summary,
|
||||||
opts: ResolveOpts,
|
opts: &ResolveOpts,
|
||||||
) -> ActivateResult<Option<(DepsFrame, Duration)>> {
|
) -> ActivateResult<Option<(DepsFrame, Duration)>> {
|
||||||
let candidate_pid = candidate.package_id();
|
let candidate_pid = candidate.package_id();
|
||||||
cx.age += 1;
|
cx.age += 1;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use super::features::RequestedFeatures;
|
use super::features::{CliFeatures, RequestedFeatures};
|
||||||
use crate::core::{Dependency, PackageId, Summary};
|
use crate::core::{Dependency, PackageId, Summary};
|
||||||
use crate::util::errors::CargoResult;
|
use crate::util::errors::CargoResult;
|
||||||
use crate::util::interning::InternedString;
|
use crate::util::interning::InternedString;
|
||||||
@ -133,6 +133,7 @@ pub struct ResolveOpts {
|
|||||||
/// Whether or not dev-dependencies should be included.
|
/// Whether or not dev-dependencies should be included.
|
||||||
///
|
///
|
||||||
/// This may be set to `false` by things like `cargo install` or `-Z avoid-dev-deps`.
|
/// This may be set to `false` by things like `cargo install` or `-Z avoid-dev-deps`.
|
||||||
|
/// It also gets set to `false` when activating dependencies in the resolver.
|
||||||
pub dev_deps: bool,
|
pub dev_deps: bool,
|
||||||
/// Set of features requested on the command-line.
|
/// Set of features requested on the command-line.
|
||||||
pub features: RequestedFeatures,
|
pub features: RequestedFeatures,
|
||||||
@ -143,7 +144,7 @@ impl ResolveOpts {
|
|||||||
pub fn everything() -> ResolveOpts {
|
pub fn everything() -> ResolveOpts {
|
||||||
ResolveOpts {
|
ResolveOpts {
|
||||||
dev_deps: true,
|
dev_deps: true,
|
||||||
features: RequestedFeatures::new_all(true),
|
features: RequestedFeatures::CliFeatures(CliFeatures::new_all(true)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,6 +250,12 @@ fn build_feature_map(
|
|||||||
feature
|
feature
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if feature.contains('/') {
|
||||||
|
bail!(
|
||||||
|
"feature named `{}` is not allowed to contain slashes",
|
||||||
|
feature
|
||||||
|
);
|
||||||
|
}
|
||||||
validate_feature_name(config, pkg_id, feature)?;
|
validate_feature_name(config, pkg_id, feature)?;
|
||||||
for fv in fvs {
|
for fv in fvs {
|
||||||
// Find data for the referenced dependency...
|
// Find data for the referenced dependency...
|
||||||
@ -316,7 +322,20 @@ fn build_feature_map(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DepFeature { dep_name, weak, .. } => {
|
DepFeature {
|
||||||
|
dep_name,
|
||||||
|
dep_feature,
|
||||||
|
weak,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
// Early check for some unlikely syntax.
|
||||||
|
if dep_feature.contains('/') {
|
||||||
|
bail!(
|
||||||
|
"multiple slashes in feature `{}` (included by feature `{}`) are not allowed",
|
||||||
|
fv,
|
||||||
|
feature
|
||||||
|
);
|
||||||
|
}
|
||||||
// Validation of the feature name will be performed in the resolver.
|
// Validation of the feature name will be performed in the resolver.
|
||||||
if !is_any_dep {
|
if !is_any_dep {
|
||||||
bail!(
|
bail!(
|
||||||
@ -362,7 +381,7 @@ fn build_feature_map(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// FeatureValue represents the types of dependencies a feature can have.
|
/// FeatureValue represents the types of dependencies a feature can have.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
|
||||||
pub enum FeatureValue {
|
pub enum FeatureValue {
|
||||||
/// A feature enabling another feature.
|
/// A feature enabling another feature.
|
||||||
Feature(InternedString),
|
Feature(InternedString),
|
||||||
|
@ -12,9 +12,9 @@ use url::Url;
|
|||||||
|
|
||||||
use crate::core::features::Features;
|
use crate::core::features::Features;
|
||||||
use crate::core::registry::PackageRegistry;
|
use crate::core::registry::PackageRegistry;
|
||||||
use crate::core::resolver::features::RequestedFeatures;
|
use crate::core::resolver::features::CliFeatures;
|
||||||
use crate::core::resolver::ResolveBehavior;
|
use crate::core::resolver::ResolveBehavior;
|
||||||
use crate::core::{Dependency, Edition, PackageId, PackageIdSpec};
|
use crate::core::{Dependency, Edition, FeatureValue, PackageId, PackageIdSpec};
|
||||||
use crate::core::{EitherManifest, Package, SourceId, VirtualManifest};
|
use crate::core::{EitherManifest, Package, SourceId, VirtualManifest};
|
||||||
use crate::ops;
|
use crate::ops;
|
||||||
use crate::sources::{PathSource, CRATES_IO_INDEX, CRATES_IO_REGISTRY};
|
use crate::sources::{PathSource, CRATES_IO_INDEX, CRATES_IO_REGISTRY};
|
||||||
@ -1047,10 +1047,10 @@ impl<'cfg> Workspace<'cfg> {
|
|||||||
pub fn members_with_features(
|
pub fn members_with_features(
|
||||||
&self,
|
&self,
|
||||||
specs: &[PackageIdSpec],
|
specs: &[PackageIdSpec],
|
||||||
requested_features: &RequestedFeatures,
|
cli_features: &CliFeatures,
|
||||||
) -> CargoResult<Vec<(&Package, RequestedFeatures)>> {
|
) -> CargoResult<Vec<(&Package, CliFeatures)>> {
|
||||||
assert!(
|
assert!(
|
||||||
!specs.is_empty() || requested_features.all_features,
|
!specs.is_empty() || cli_features.all_features,
|
||||||
"no specs requires all_features"
|
"no specs requires all_features"
|
||||||
);
|
);
|
||||||
if specs.is_empty() {
|
if specs.is_empty() {
|
||||||
@ -1058,13 +1058,13 @@ impl<'cfg> Workspace<'cfg> {
|
|||||||
// all features enabled.
|
// all features enabled.
|
||||||
return Ok(self
|
return Ok(self
|
||||||
.members()
|
.members()
|
||||||
.map(|m| (m, RequestedFeatures::new_all(true)))
|
.map(|m| (m, CliFeatures::new_all(true)))
|
||||||
.collect());
|
.collect());
|
||||||
}
|
}
|
||||||
if self.allows_new_cli_feature_behavior() {
|
if self.allows_new_cli_feature_behavior() {
|
||||||
self.members_with_features_new(specs, requested_features)
|
self.members_with_features_new(specs, cli_features)
|
||||||
} else {
|
} else {
|
||||||
Ok(self.members_with_features_old(specs, requested_features))
|
Ok(self.members_with_features_old(specs, cli_features))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1073,17 +1073,17 @@ impl<'cfg> Workspace<'cfg> {
|
|||||||
fn members_with_features_new(
|
fn members_with_features_new(
|
||||||
&self,
|
&self,
|
||||||
specs: &[PackageIdSpec],
|
specs: &[PackageIdSpec],
|
||||||
requested_features: &RequestedFeatures,
|
cli_features: &CliFeatures,
|
||||||
) -> CargoResult<Vec<(&Package, RequestedFeatures)>> {
|
) -> CargoResult<Vec<(&Package, CliFeatures)>> {
|
||||||
// Keep track of which features matched *any* member, to produce an error
|
// Keep track of which features matched *any* member, to produce an error
|
||||||
// if any of them did not match anywhere.
|
// if any of them did not match anywhere.
|
||||||
let mut found: BTreeSet<InternedString> = BTreeSet::new();
|
let mut found: BTreeSet<FeatureValue> = BTreeSet::new();
|
||||||
|
|
||||||
// Returns the requested features for the given member.
|
// Returns the requested features for the given member.
|
||||||
// This filters out any named features that the member does not have.
|
// This filters out any named features that the member does not have.
|
||||||
let mut matching_features = |member: &Package| -> RequestedFeatures {
|
let mut matching_features = |member: &Package| -> CliFeatures {
|
||||||
if requested_features.features.is_empty() || requested_features.all_features {
|
if cli_features.features.is_empty() || cli_features.all_features {
|
||||||
return requested_features.clone();
|
return cli_features.clone();
|
||||||
}
|
}
|
||||||
// Only include features this member defines.
|
// Only include features this member defines.
|
||||||
let summary = member.summary();
|
let summary = member.summary();
|
||||||
@ -1099,40 +1099,54 @@ impl<'cfg> Workspace<'cfg> {
|
|||||||
.any(|dep| dep.is_optional() && dep.name_in_toml() == feature)
|
.any(|dep| dep.is_optional() && dep.name_in_toml() == feature)
|
||||||
};
|
};
|
||||||
|
|
||||||
for feature in requested_features.features.iter() {
|
for feature in cli_features.features.iter() {
|
||||||
let mut split = feature.splitn(2, '/');
|
match feature {
|
||||||
let split = (split.next().unwrap(), split.next());
|
FeatureValue::Feature(f) => {
|
||||||
if let (pkg, Some(pkg_feature)) = split {
|
if contains(*f) {
|
||||||
let pkg = InternedString::new(pkg);
|
// feature exists in this member.
|
||||||
let pkg_feature = InternedString::new(pkg_feature);
|
features.insert(feature.clone());
|
||||||
if summary
|
found.insert(feature.clone());
|
||||||
.dependencies()
|
}
|
||||||
.iter()
|
}
|
||||||
.any(|dep| dep.name_in_toml() == pkg)
|
// This should be enforced by CliFeatures.
|
||||||
{
|
FeatureValue::Dep { .. }
|
||||||
// pkg/feat for a dependency.
|
| FeatureValue::DepFeature {
|
||||||
// Will rely on the dependency resolver to validate `feat`.
|
dep_prefix: true, ..
|
||||||
features.insert(*feature);
|
} => panic!("unexpected dep: syntax {}", feature),
|
||||||
found.insert(*feature);
|
FeatureValue::DepFeature {
|
||||||
} else if pkg == member.name() && contains(pkg_feature) {
|
dep_name,
|
||||||
// member/feat where "feat" is a feature in member.
|
dep_feature,
|
||||||
features.insert(pkg_feature);
|
dep_prefix: _,
|
||||||
found.insert(*feature);
|
weak: _,
|
||||||
|
} => {
|
||||||
|
if summary
|
||||||
|
.dependencies()
|
||||||
|
.iter()
|
||||||
|
.any(|dep| dep.name_in_toml() == *dep_name)
|
||||||
|
{
|
||||||
|
// pkg/feat for a dependency.
|
||||||
|
// Will rely on the dependency resolver to validate `dep_feature`.
|
||||||
|
features.insert(feature.clone());
|
||||||
|
found.insert(feature.clone());
|
||||||
|
} else if *dep_name == member.name() && contains(*dep_feature) {
|
||||||
|
// member/feat where "feat" is a feature in member.
|
||||||
|
//
|
||||||
|
// `weak` can be ignored here, because the member
|
||||||
|
// either is or isn't being built.
|
||||||
|
features.insert(FeatureValue::Feature(*dep_feature));
|
||||||
|
found.insert(feature.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if contains(*feature) {
|
|
||||||
// feature exists in this member.
|
|
||||||
features.insert(*feature);
|
|
||||||
found.insert(*feature);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RequestedFeatures {
|
CliFeatures {
|
||||||
features: Rc::new(features),
|
features: Rc::new(features),
|
||||||
all_features: false,
|
all_features: false,
|
||||||
uses_default_features: requested_features.uses_default_features,
|
uses_default_features: cli_features.uses_default_features,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let members: Vec<(&Package, RequestedFeatures)> = self
|
let members: Vec<(&Package, CliFeatures)> = self
|
||||||
.members()
|
.members()
|
||||||
.filter(|m| specs.iter().any(|spec| spec.matches(m.package_id())))
|
.filter(|m| specs.iter().any(|spec| spec.matches(m.package_id())))
|
||||||
.map(|m| (m, matching_features(m)))
|
.map(|m| (m, matching_features(m)))
|
||||||
@ -1140,9 +1154,9 @@ impl<'cfg> Workspace<'cfg> {
|
|||||||
if members.is_empty() {
|
if members.is_empty() {
|
||||||
// `cargo build -p foo`, where `foo` is not a member.
|
// `cargo build -p foo`, where `foo` is not a member.
|
||||||
// Do not allow any command-line flags (defaults only).
|
// Do not allow any command-line flags (defaults only).
|
||||||
if !(requested_features.features.is_empty()
|
if !(cli_features.features.is_empty()
|
||||||
&& !requested_features.all_features
|
&& !cli_features.all_features
|
||||||
&& requested_features.uses_default_features)
|
&& cli_features.uses_default_features)
|
||||||
{
|
{
|
||||||
bail!("cannot specify features for packages outside of workspace");
|
bail!("cannot specify features for packages outside of workspace");
|
||||||
}
|
}
|
||||||
@ -1150,15 +1164,16 @@ impl<'cfg> Workspace<'cfg> {
|
|||||||
// is in the resolve graph.
|
// is in the resolve graph.
|
||||||
return Ok(self
|
return Ok(self
|
||||||
.members()
|
.members()
|
||||||
.map(|m| (m, RequestedFeatures::new_all(false)))
|
.map(|m| (m, CliFeatures::new_all(false)))
|
||||||
.collect());
|
.collect());
|
||||||
}
|
}
|
||||||
if *requested_features.features != found {
|
if *cli_features.features != found {
|
||||||
let missing: Vec<_> = requested_features
|
let mut missing: Vec<_> = cli_features
|
||||||
.features
|
.features
|
||||||
.difference(&found)
|
.difference(&found)
|
||||||
.copied()
|
.map(|fv| fv.to_string())
|
||||||
.collect();
|
.collect();
|
||||||
|
missing.sort();
|
||||||
// TODO: typo suggestions would be good here.
|
// TODO: typo suggestions would be good here.
|
||||||
bail!(
|
bail!(
|
||||||
"none of the selected packages contains these features: {}",
|
"none of the selected packages contains these features: {}",
|
||||||
@ -1173,28 +1188,46 @@ impl<'cfg> Workspace<'cfg> {
|
|||||||
fn members_with_features_old(
|
fn members_with_features_old(
|
||||||
&self,
|
&self,
|
||||||
specs: &[PackageIdSpec],
|
specs: &[PackageIdSpec],
|
||||||
requested_features: &RequestedFeatures,
|
cli_features: &CliFeatures,
|
||||||
) -> Vec<(&Package, RequestedFeatures)> {
|
) -> Vec<(&Package, CliFeatures)> {
|
||||||
// Split off any features with the syntax `member-name/feature-name` into a map
|
// Split off any features with the syntax `member-name/feature-name` into a map
|
||||||
// so that those features can be applied directly to those workspace-members.
|
// so that those features can be applied directly to those workspace-members.
|
||||||
let mut member_specific_features: HashMap<&str, BTreeSet<InternedString>> = HashMap::new();
|
let mut member_specific_features: HashMap<InternedString, BTreeSet<FeatureValue>> =
|
||||||
|
HashMap::new();
|
||||||
// Features for the member in the current directory.
|
// Features for the member in the current directory.
|
||||||
let mut cwd_features = BTreeSet::new();
|
let mut cwd_features = BTreeSet::new();
|
||||||
for feature in requested_features.features.iter() {
|
for feature in cli_features.features.iter() {
|
||||||
if let Some(index) = feature.find('/') {
|
match feature {
|
||||||
let name = &feature[..index];
|
FeatureValue::Feature(_) => {
|
||||||
let is_member = self.members().any(|member| member.name() == name);
|
cwd_features.insert(feature.clone());
|
||||||
if is_member && specs.iter().any(|spec| spec.name() == name) {
|
|
||||||
member_specific_features
|
|
||||||
.entry(name)
|
|
||||||
.or_default()
|
|
||||||
.insert(InternedString::new(&feature[index + 1..]));
|
|
||||||
} else {
|
|
||||||
cwd_features.insert(*feature);
|
|
||||||
}
|
}
|
||||||
} else {
|
// This should be enforced by CliFeatures.
|
||||||
cwd_features.insert(*feature);
|
FeatureValue::Dep { .. }
|
||||||
};
|
| FeatureValue::DepFeature {
|
||||||
|
dep_prefix: true, ..
|
||||||
|
} => panic!("unexpected dep: syntax {}", feature),
|
||||||
|
FeatureValue::DepFeature {
|
||||||
|
dep_name,
|
||||||
|
dep_feature,
|
||||||
|
dep_prefix: _,
|
||||||
|
weak: _,
|
||||||
|
} => {
|
||||||
|
// I think weak can be ignored here.
|
||||||
|
// * With `--features member?/feat -p member`, the ? doesn't
|
||||||
|
// really mean anything (either the member is built or it isn't).
|
||||||
|
// * With `--features nonmember?/feat`, cwd_features will
|
||||||
|
// handle processing it correctly.
|
||||||
|
let is_member = self.members().any(|member| member.name() == *dep_name);
|
||||||
|
if is_member && specs.iter().any(|spec| spec.name() == *dep_name) {
|
||||||
|
member_specific_features
|
||||||
|
.entry(*dep_name)
|
||||||
|
.or_default()
|
||||||
|
.insert(FeatureValue::Feature(*dep_feature));
|
||||||
|
} else {
|
||||||
|
cwd_features.insert(feature.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ms = self.members().filter_map(|member| {
|
let ms = self.members().filter_map(|member| {
|
||||||
@ -1203,10 +1236,10 @@ impl<'cfg> Workspace<'cfg> {
|
|||||||
// The features passed on the command-line only apply to
|
// The features passed on the command-line only apply to
|
||||||
// the "current" package (determined by the cwd).
|
// the "current" package (determined by the cwd).
|
||||||
Some(current) if member_id == current.package_id() => {
|
Some(current) if member_id == current.package_id() => {
|
||||||
let feats = RequestedFeatures {
|
let feats = CliFeatures {
|
||||||
features: Rc::new(cwd_features.clone()),
|
features: Rc::new(cwd_features.clone()),
|
||||||
all_features: requested_features.all_features,
|
all_features: cli_features.all_features,
|
||||||
uses_default_features: requested_features.uses_default_features,
|
uses_default_features: cli_features.uses_default_features,
|
||||||
};
|
};
|
||||||
Some((member, feats))
|
Some((member, feats))
|
||||||
}
|
}
|
||||||
@ -1222,14 +1255,14 @@ impl<'cfg> Workspace<'cfg> {
|
|||||||
// "current" package. As an extension, this allows
|
// "current" package. As an extension, this allows
|
||||||
// member-name/feature-name to set member-specific
|
// member-name/feature-name to set member-specific
|
||||||
// features, which should be backwards-compatible.
|
// features, which should be backwards-compatible.
|
||||||
let feats = RequestedFeatures {
|
let feats = CliFeatures {
|
||||||
features: Rc::new(
|
features: Rc::new(
|
||||||
member_specific_features
|
member_specific_features
|
||||||
.remove(member.name().as_str())
|
.remove(member.name().as_str())
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
),
|
),
|
||||||
uses_default_features: true,
|
uses_default_features: true,
|
||||||
all_features: requested_features.all_features,
|
all_features: cli_features.all_features,
|
||||||
};
|
};
|
||||||
Some((member, feats))
|
Some((member, feats))
|
||||||
} else {
|
} else {
|
||||||
|
@ -33,8 +33,8 @@ use crate::core::compiler::{BuildConfig, BuildContext, Compilation, Context};
|
|||||||
use crate::core::compiler::{CompileKind, CompileMode, CompileTarget, RustcTargetData, Unit};
|
use crate::core::compiler::{CompileKind, CompileMode, CompileTarget, RustcTargetData, Unit};
|
||||||
use crate::core::compiler::{DefaultExecutor, Executor, UnitInterner};
|
use crate::core::compiler::{DefaultExecutor, Executor, UnitInterner};
|
||||||
use crate::core::profiles::{Profiles, UnitFor};
|
use crate::core::profiles::{Profiles, UnitFor};
|
||||||
use crate::core::resolver::features::{self, FeaturesFor, RequestedFeatures};
|
use crate::core::resolver::features::{self, CliFeatures, FeaturesFor};
|
||||||
use crate::core::resolver::{HasDevUnits, Resolve, ResolveOpts};
|
use crate::core::resolver::{HasDevUnits, Resolve};
|
||||||
use crate::core::{FeatureValue, Package, PackageSet, Shell, Summary, Target};
|
use crate::core::{FeatureValue, Package, PackageSet, Shell, Summary, Target};
|
||||||
use crate::core::{PackageId, PackageIdSpec, SourceId, TargetKind, Workspace};
|
use crate::core::{PackageId, PackageIdSpec, SourceId, TargetKind, Workspace};
|
||||||
use crate::drop_println;
|
use crate::drop_println;
|
||||||
@ -59,12 +59,8 @@ use anyhow::Context as _;
|
|||||||
pub struct CompileOptions {
|
pub struct CompileOptions {
|
||||||
/// Configuration information for a rustc build
|
/// Configuration information for a rustc build
|
||||||
pub build_config: BuildConfig,
|
pub build_config: BuildConfig,
|
||||||
/// Extra features to build for the root package
|
/// Feature flags requested by the user.
|
||||||
pub features: Vec<String>,
|
pub cli_features: CliFeatures,
|
||||||
/// Flag whether all available features should be built for the root package
|
|
||||||
pub all_features: bool,
|
|
||||||
/// Flag if the default feature should be built for the root package
|
|
||||||
pub no_default_features: bool,
|
|
||||||
/// A set of packages to build.
|
/// A set of packages to build.
|
||||||
pub spec: Packages,
|
pub spec: Packages,
|
||||||
/// Filter to apply to the root package to select which targets will be
|
/// Filter to apply to the root package to select which targets will be
|
||||||
@ -89,9 +85,7 @@ impl<'a> CompileOptions {
|
|||||||
pub fn new(config: &Config, mode: CompileMode) -> CargoResult<CompileOptions> {
|
pub fn new(config: &Config, mode: CompileMode) -> CargoResult<CompileOptions> {
|
||||||
Ok(CompileOptions {
|
Ok(CompileOptions {
|
||||||
build_config: BuildConfig::new(config, None, &[], mode)?,
|
build_config: BuildConfig::new(config, None, &[], mode)?,
|
||||||
features: Vec::new(),
|
cli_features: CliFeatures::new_all(false),
|
||||||
all_features: false,
|
|
||||||
no_default_features: false,
|
|
||||||
spec: ops::Packages::Packages(Vec::new()),
|
spec: ops::Packages::Packages(Vec::new()),
|
||||||
filter: CompileFilter::Default {
|
filter: CompileFilter::Default {
|
||||||
required_features_filterable: false,
|
required_features_filterable: false,
|
||||||
@ -334,9 +328,7 @@ pub fn create_bcx<'a, 'cfg>(
|
|||||||
let CompileOptions {
|
let CompileOptions {
|
||||||
ref build_config,
|
ref build_config,
|
||||||
ref spec,
|
ref spec,
|
||||||
ref features,
|
ref cli_features,
|
||||||
all_features,
|
|
||||||
no_default_features,
|
|
||||||
ref filter,
|
ref filter,
|
||||||
ref target_rustdoc_args,
|
ref target_rustdoc_args,
|
||||||
ref target_rustc_args,
|
ref target_rustc_args,
|
||||||
@ -372,11 +364,6 @@ pub fn create_bcx<'a, 'cfg>(
|
|||||||
let target_data = RustcTargetData::new(ws, &build_config.requested_kinds)?;
|
let target_data = RustcTargetData::new(ws, &build_config.requested_kinds)?;
|
||||||
|
|
||||||
let specs = spec.to_package_id_specs(ws)?;
|
let specs = spec.to_package_id_specs(ws)?;
|
||||||
let dev_deps = ws.require_optional_deps() || filter.need_dev_deps(build_config.mode);
|
|
||||||
let opts = ResolveOpts::new(
|
|
||||||
dev_deps,
|
|
||||||
RequestedFeatures::from_command_line(features, all_features, !no_default_features),
|
|
||||||
);
|
|
||||||
let has_dev_units = if filter.need_dev_deps(build_config.mode) {
|
let has_dev_units = if filter.need_dev_deps(build_config.mode) {
|
||||||
HasDevUnits::Yes
|
HasDevUnits::Yes
|
||||||
} else {
|
} else {
|
||||||
@ -386,7 +373,7 @@ pub fn create_bcx<'a, 'cfg>(
|
|||||||
ws,
|
ws,
|
||||||
&target_data,
|
&target_data,
|
||||||
&build_config.requested_kinds,
|
&build_config.requested_kinds,
|
||||||
&opts,
|
cli_features,
|
||||||
&specs,
|
&specs,
|
||||||
has_dev_units,
|
has_dev_units,
|
||||||
crate::core::resolver::features::ForceAllTargets::No,
|
crate::core::resolver::features::ForceAllTargets::No,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::core::compiler::RustcTargetData;
|
use crate::core::compiler::RustcTargetData;
|
||||||
use crate::core::resolver::{features::RequestedFeatures, HasDevUnits, ResolveOpts};
|
use crate::core::resolver::HasDevUnits;
|
||||||
use crate::core::{Shell, Workspace};
|
use crate::core::{Shell, Workspace};
|
||||||
use crate::ops;
|
use crate::ops;
|
||||||
use crate::util::CargoResult;
|
use crate::util::CargoResult;
|
||||||
@ -19,20 +19,12 @@ pub struct DocOptions {
|
|||||||
/// Main method for `cargo doc`.
|
/// Main method for `cargo doc`.
|
||||||
pub fn doc(ws: &Workspace<'_>, options: &DocOptions) -> CargoResult<()> {
|
pub fn doc(ws: &Workspace<'_>, options: &DocOptions) -> CargoResult<()> {
|
||||||
let specs = options.compile_opts.spec.to_package_id_specs(ws)?;
|
let specs = options.compile_opts.spec.to_package_id_specs(ws)?;
|
||||||
let opts = ResolveOpts::new(
|
|
||||||
/*dev_deps*/ true,
|
|
||||||
RequestedFeatures::from_command_line(
|
|
||||||
&options.compile_opts.features,
|
|
||||||
options.compile_opts.all_features,
|
|
||||||
!options.compile_opts.no_default_features,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
let target_data = RustcTargetData::new(ws, &options.compile_opts.build_config.requested_kinds)?;
|
let target_data = RustcTargetData::new(ws, &options.compile_opts.build_config.requested_kinds)?;
|
||||||
let ws_resolve = ops::resolve_ws_with_opts(
|
let ws_resolve = ops::resolve_ws_with_opts(
|
||||||
ws,
|
ws,
|
||||||
&target_data,
|
&target_data,
|
||||||
&options.compile_opts.build_config.requested_kinds,
|
&options.compile_opts.build_config.requested_kinds,
|
||||||
&opts,
|
&options.compile_opts.cli_features,
|
||||||
&specs,
|
&specs,
|
||||||
HasDevUnits::No,
|
HasDevUnits::No,
|
||||||
crate::core::resolver::features::ForceAllTargets::No,
|
crate::core::resolver::features::ForceAllTargets::No,
|
||||||
|
@ -4,7 +4,7 @@ use log::debug;
|
|||||||
use termcolor::Color::{self, Cyan, Green, Red};
|
use termcolor::Color::{self, Cyan, Green, Red};
|
||||||
|
|
||||||
use crate::core::registry::PackageRegistry;
|
use crate::core::registry::PackageRegistry;
|
||||||
use crate::core::resolver::ResolveOpts;
|
use crate::core::resolver::features::{CliFeatures, HasDevUnits};
|
||||||
use crate::core::{PackageId, PackageIdSpec};
|
use crate::core::{PackageId, PackageIdSpec};
|
||||||
use crate::core::{Resolve, SourceId, Workspace};
|
use crate::core::{Resolve, SourceId, Workspace};
|
||||||
use crate::ops;
|
use crate::ops;
|
||||||
@ -25,7 +25,8 @@ pub fn generate_lockfile(ws: &Workspace<'_>) -> CargoResult<()> {
|
|||||||
let mut resolve = ops::resolve_with_previous(
|
let mut resolve = ops::resolve_with_previous(
|
||||||
&mut registry,
|
&mut registry,
|
||||||
ws,
|
ws,
|
||||||
&ResolveOpts::everything(),
|
&CliFeatures::new_all(true),
|
||||||
|
HasDevUnits::Yes,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
&[],
|
&[],
|
||||||
@ -61,7 +62,8 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
|
|||||||
ops::resolve_with_previous(
|
ops::resolve_with_previous(
|
||||||
&mut registry,
|
&mut registry,
|
||||||
ws,
|
ws,
|
||||||
&ResolveOpts::everything(),
|
&CliFeatures::new_all(true),
|
||||||
|
HasDevUnits::Yes,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
&[],
|
&[],
|
||||||
@ -115,7 +117,8 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
|
|||||||
let mut resolve = ops::resolve_with_previous(
|
let mut resolve = ops::resolve_with_previous(
|
||||||
&mut registry,
|
&mut registry,
|
||||||
ws,
|
ws,
|
||||||
&ResolveOpts::everything(),
|
&CliFeatures::new_all(true),
|
||||||
|
HasDevUnits::Yes,
|
||||||
Some(&previous_resolve),
|
Some(&previous_resolve),
|
||||||
Some(&to_avoid),
|
Some(&to_avoid),
|
||||||
&[],
|
&[],
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::core::compiler::{CompileKind, RustcTargetData};
|
use crate::core::compiler::{CompileKind, RustcTargetData};
|
||||||
use crate::core::dependency::DepKind;
|
use crate::core::dependency::DepKind;
|
||||||
use crate::core::package::SerializedPackage;
|
use crate::core::package::SerializedPackage;
|
||||||
use crate::core::resolver::{features::RequestedFeatures, HasDevUnits, Resolve, ResolveOpts};
|
use crate::core::resolver::{features::CliFeatures, HasDevUnits, Resolve};
|
||||||
use crate::core::{Dependency, Package, PackageId, Workspace};
|
use crate::core::{Dependency, Package, PackageId, Workspace};
|
||||||
use crate::ops::{self, Packages};
|
use crate::ops::{self, Packages};
|
||||||
use crate::util::interning::InternedString;
|
use crate::util::interning::InternedString;
|
||||||
@ -14,9 +14,7 @@ use std::path::PathBuf;
|
|||||||
const VERSION: u32 = 1;
|
const VERSION: u32 = 1;
|
||||||
|
|
||||||
pub struct OutputMetadataOptions {
|
pub struct OutputMetadataOptions {
|
||||||
pub features: Vec<String>,
|
pub cli_features: CliFeatures,
|
||||||
pub no_default_features: bool,
|
|
||||||
pub all_features: bool,
|
|
||||||
pub no_deps: bool,
|
pub no_deps: bool,
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
pub filter_platforms: Vec<String>,
|
pub filter_platforms: Vec<String>,
|
||||||
@ -115,12 +113,6 @@ fn build_resolve_graph(
|
|||||||
let target_data = RustcTargetData::new(ws, &requested_kinds)?;
|
let target_data = RustcTargetData::new(ws, &requested_kinds)?;
|
||||||
// Resolve entire workspace.
|
// Resolve entire workspace.
|
||||||
let specs = Packages::All.to_package_id_specs(ws)?;
|
let specs = Packages::All.to_package_id_specs(ws)?;
|
||||||
let requested_features = RequestedFeatures::from_command_line(
|
|
||||||
&metadata_opts.features,
|
|
||||||
metadata_opts.all_features,
|
|
||||||
!metadata_opts.no_default_features,
|
|
||||||
);
|
|
||||||
let resolve_opts = ResolveOpts::new(/*dev_deps*/ true, requested_features);
|
|
||||||
let force_all = if metadata_opts.filter_platforms.is_empty() {
|
let force_all = if metadata_opts.filter_platforms.is_empty() {
|
||||||
crate::core::resolver::features::ForceAllTargets::Yes
|
crate::core::resolver::features::ForceAllTargets::Yes
|
||||||
} else {
|
} else {
|
||||||
@ -133,7 +125,7 @@ fn build_resolve_graph(
|
|||||||
ws,
|
ws,
|
||||||
&target_data,
|
&target_data,
|
||||||
&requested_kinds,
|
&requested_kinds,
|
||||||
&resolve_opts,
|
&metadata_opts.cli_features,
|
||||||
&specs,
|
&specs,
|
||||||
HasDevUnits::Yes,
|
HasDevUnits::Yes,
|
||||||
force_all,
|
force_all,
|
||||||
|
@ -12,6 +12,7 @@ use log::debug;
|
|||||||
use tar::{Archive, Builder, EntryType, Header, HeaderMode};
|
use tar::{Archive, Builder, EntryType, Header, HeaderMode};
|
||||||
|
|
||||||
use crate::core::compiler::{BuildConfig, CompileMode, DefaultExecutor, Executor};
|
use crate::core::compiler::{BuildConfig, CompileMode, DefaultExecutor, Executor};
|
||||||
|
use crate::core::resolver::CliFeatures;
|
||||||
use crate::core::{Feature, Shell, Verbosity, Workspace};
|
use crate::core::{Feature, Shell, Verbosity, Workspace};
|
||||||
use crate::core::{Package, PackageId, PackageSet, Resolve, Source, SourceId};
|
use crate::core::{Package, PackageId, PackageSet, Resolve, Source, SourceId};
|
||||||
use crate::sources::PathSource;
|
use crate::sources::PathSource;
|
||||||
@ -29,9 +30,7 @@ pub struct PackageOpts<'cfg> {
|
|||||||
pub verify: bool,
|
pub verify: bool,
|
||||||
pub jobs: Option<u32>,
|
pub jobs: Option<u32>,
|
||||||
pub targets: Vec<String>,
|
pub targets: Vec<String>,
|
||||||
pub features: Vec<String>,
|
pub cli_features: CliFeatures,
|
||||||
pub all_features: bool,
|
|
||||||
pub no_default_features: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const VCS_INFO_FILE: &str = ".cargo_vcs_info.json";
|
const VCS_INFO_FILE: &str = ".cargo_vcs_info.json";
|
||||||
@ -690,9 +689,7 @@ fn run_verify(ws: &Workspace<'_>, tar: &FileLock, opts: &PackageOpts<'_>) -> Car
|
|||||||
&ws,
|
&ws,
|
||||||
&ops::CompileOptions {
|
&ops::CompileOptions {
|
||||||
build_config: BuildConfig::new(config, opts.jobs, &opts.targets, CompileMode::Build)?,
|
build_config: BuildConfig::new(config, opts.jobs, &opts.targets, CompileMode::Build)?,
|
||||||
features: opts.features.clone(),
|
cli_features: opts.cli_features.clone(),
|
||||||
no_default_features: opts.no_default_features,
|
|
||||||
all_features: opts.all_features,
|
|
||||||
spec: ops::Packages::Packages(Vec::new()),
|
spec: ops::Packages::Packages(Vec::new()),
|
||||||
filter: ops::CompileFilter::Default {
|
filter: ops::CompileFilter::Default {
|
||||||
required_features_filterable: true,
|
required_features_filterable: true,
|
||||||
|
@ -3,12 +3,13 @@ use std::env;
|
|||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::io::SeekFrom;
|
use std::io::SeekFrom;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use anyhow::{bail, format_err};
|
use anyhow::{bail, format_err};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::core::compiler::Freshness;
|
use crate::core::compiler::Freshness;
|
||||||
use crate::core::{Dependency, Package, PackageId, Source, SourceId};
|
use crate::core::{Dependency, FeatureValue, Package, PackageId, Source, SourceId};
|
||||||
use crate::ops::{self, CompileFilter, CompileOptions};
|
use crate::ops::{self, CompileFilter, CompileOptions};
|
||||||
use crate::sources::PathSource;
|
use crate::sources::PathSource;
|
||||||
use crate::util::errors::{CargoResult, CargoResultExt};
|
use crate::util::errors::{CargoResult, CargoResultExt};
|
||||||
@ -422,9 +423,9 @@ impl CrateListingV2 {
|
|||||||
if let Some(info) = self.installs.get_mut(&pkg.package_id()) {
|
if let Some(info) = self.installs.get_mut(&pkg.package_id()) {
|
||||||
info.bins.append(&mut bins.clone());
|
info.bins.append(&mut bins.clone());
|
||||||
info.version_req = version_req;
|
info.version_req = version_req;
|
||||||
info.features = feature_set(&opts.features);
|
info.features = feature_set(&opts.cli_features.features);
|
||||||
info.all_features = opts.all_features;
|
info.all_features = opts.cli_features.all_features;
|
||||||
info.no_default_features = opts.no_default_features;
|
info.no_default_features = !opts.cli_features.uses_default_features;
|
||||||
info.profile = opts.build_config.requested_profile.to_string();
|
info.profile = opts.build_config.requested_profile.to_string();
|
||||||
info.target = Some(target.to_string());
|
info.target = Some(target.to_string());
|
||||||
info.rustc = Some(rustc.to_string());
|
info.rustc = Some(rustc.to_string());
|
||||||
@ -434,9 +435,9 @@ impl CrateListingV2 {
|
|||||||
InstallInfo {
|
InstallInfo {
|
||||||
version_req,
|
version_req,
|
||||||
bins: bins.clone(),
|
bins: bins.clone(),
|
||||||
features: feature_set(&opts.features),
|
features: feature_set(&opts.cli_features.features),
|
||||||
all_features: opts.all_features,
|
all_features: opts.cli_features.all_features,
|
||||||
no_default_features: opts.no_default_features,
|
no_default_features: !opts.cli_features.uses_default_features,
|
||||||
profile: opts.build_config.requested_profile.to_string(),
|
profile: opts.build_config.requested_profile.to_string(),
|
||||||
target: Some(target.to_string()),
|
target: Some(target.to_string()),
|
||||||
rustc: Some(rustc.to_string()),
|
rustc: Some(rustc.to_string()),
|
||||||
@ -489,9 +490,9 @@ impl InstallInfo {
|
|||||||
///
|
///
|
||||||
/// This does not do Package/Source/Version checking.
|
/// This does not do Package/Source/Version checking.
|
||||||
fn is_up_to_date(&self, opts: &CompileOptions, target: &str, exes: &BTreeSet<String>) -> bool {
|
fn is_up_to_date(&self, opts: &CompileOptions, target: &str, exes: &BTreeSet<String>) -> bool {
|
||||||
self.features == feature_set(&opts.features)
|
self.features == feature_set(&opts.cli_features.features)
|
||||||
&& self.all_features == opts.all_features
|
&& self.all_features == opts.cli_features.all_features
|
||||||
&& self.no_default_features == opts.no_default_features
|
&& self.no_default_features == !opts.cli_features.uses_default_features
|
||||||
&& self.profile.as_str() == opts.build_config.requested_profile.as_str()
|
&& self.profile.as_str() == opts.build_config.requested_profile.as_str()
|
||||||
&& (self.target.is_none() || self.target.as_deref() == Some(target))
|
&& (self.target.is_none() || self.target.as_deref() == Some(target))
|
||||||
&& &self.bins == exes
|
&& &self.bins == exes
|
||||||
@ -641,9 +642,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper to convert features Vec to a BTreeSet.
|
/// Helper to convert features to a BTreeSet.
|
||||||
fn feature_set(features: &[String]) -> BTreeSet<String> {
|
fn feature_set(features: &Rc<BTreeSet<FeatureValue>>) -> BTreeSet<String> {
|
||||||
features.iter().cloned().collect()
|
features.iter().map(|s| s.to_string()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper to get the executable names from a filter.
|
/// Helper to get the executable names from a filter.
|
||||||
|
@ -51,8 +51,8 @@ use rustfix::diagnostics::Diagnostic;
|
|||||||
use rustfix::{self, CodeFix};
|
use rustfix::{self, CodeFix};
|
||||||
|
|
||||||
use crate::core::compiler::RustcTargetData;
|
use crate::core::compiler::RustcTargetData;
|
||||||
use crate::core::resolver::features::{FeatureOpts, FeatureResolver, RequestedFeatures};
|
use crate::core::resolver::features::{FeatureOpts, FeatureResolver};
|
||||||
use crate::core::resolver::{HasDevUnits, ResolveBehavior, ResolveOpts};
|
use crate::core::resolver::{HasDevUnits, ResolveBehavior};
|
||||||
use crate::core::{Edition, MaybePackage, Workspace};
|
use crate::core::{Edition, MaybePackage, Workspace};
|
||||||
use crate::ops::{self, CompileOptions};
|
use crate::ops::{self, CompileOptions};
|
||||||
use crate::util::diagnostic_server::{Message, RustfixDiagnosticServer};
|
use crate::util::diagnostic_server::{Message, RustfixDiagnosticServer};
|
||||||
@ -227,14 +227,6 @@ fn check_resolver_change(ws: &Workspace<'_>, opts: &FixOptions) -> CargoResult<(
|
|||||||
// 2018 without `resolver` set must be V1
|
// 2018 without `resolver` set must be V1
|
||||||
assert_eq!(ws.resolve_behavior(), ResolveBehavior::V1);
|
assert_eq!(ws.resolve_behavior(), ResolveBehavior::V1);
|
||||||
let specs = opts.compile_opts.spec.to_package_id_specs(ws)?;
|
let specs = opts.compile_opts.spec.to_package_id_specs(ws)?;
|
||||||
let resolve_opts = ResolveOpts::new(
|
|
||||||
/*dev_deps*/ true,
|
|
||||||
RequestedFeatures::from_command_line(
|
|
||||||
&opts.compile_opts.features,
|
|
||||||
opts.compile_opts.all_features,
|
|
||||||
!opts.compile_opts.no_default_features,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
let target_data = RustcTargetData::new(ws, &opts.compile_opts.build_config.requested_kinds)?;
|
let target_data = RustcTargetData::new(ws, &opts.compile_opts.build_config.requested_kinds)?;
|
||||||
// HasDevUnits::No because that may uncover more differences.
|
// HasDevUnits::No because that may uncover more differences.
|
||||||
// This is not the same as what `cargo fix` is doing, since it is doing
|
// This is not the same as what `cargo fix` is doing, since it is doing
|
||||||
@ -243,7 +235,7 @@ fn check_resolver_change(ws: &Workspace<'_>, opts: &FixOptions) -> CargoResult<(
|
|||||||
ws,
|
ws,
|
||||||
&target_data,
|
&target_data,
|
||||||
&opts.compile_opts.build_config.requested_kinds,
|
&opts.compile_opts.build_config.requested_kinds,
|
||||||
&resolve_opts,
|
&opts.compile_opts.cli_features,
|
||||||
&specs,
|
&specs,
|
||||||
HasDevUnits::No,
|
HasDevUnits::No,
|
||||||
crate::core::resolver::features::ForceAllTargets::No,
|
crate::core::resolver::features::ForceAllTargets::No,
|
||||||
@ -255,7 +247,7 @@ fn check_resolver_change(ws: &Workspace<'_>, opts: &FixOptions) -> CargoResult<(
|
|||||||
&target_data,
|
&target_data,
|
||||||
&ws_resolve.targeted_resolve,
|
&ws_resolve.targeted_resolve,
|
||||||
&ws_resolve.pkg_set,
|
&ws_resolve.pkg_set,
|
||||||
&resolve_opts.features,
|
&opts.compile_opts.cli_features,
|
||||||
&specs,
|
&specs,
|
||||||
&opts.compile_opts.build_config.requested_kinds,
|
&opts.compile_opts.build_config.requested_kinds,
|
||||||
feature_opts,
|
feature_opts,
|
||||||
|
@ -15,6 +15,7 @@ use percent_encoding::{percent_encode, NON_ALPHANUMERIC};
|
|||||||
|
|
||||||
use crate::core::dependency::DepKind;
|
use crate::core::dependency::DepKind;
|
||||||
use crate::core::manifest::ManifestMetadata;
|
use crate::core::manifest::ManifestMetadata;
|
||||||
|
use crate::core::resolver::CliFeatures;
|
||||||
use crate::core::source::Source;
|
use crate::core::source::Source;
|
||||||
use crate::core::{Package, SourceId, Workspace};
|
use crate::core::{Package, SourceId, Workspace};
|
||||||
use crate::ops;
|
use crate::ops;
|
||||||
@ -51,9 +52,7 @@ pub struct PublishOpts<'cfg> {
|
|||||||
pub targets: Vec<String>,
|
pub targets: Vec<String>,
|
||||||
pub dry_run: bool,
|
pub dry_run: bool,
|
||||||
pub registry: Option<String>,
|
pub registry: Option<String>,
|
||||||
pub features: Vec<String>,
|
pub cli_features: CliFeatures,
|
||||||
pub all_features: bool,
|
|
||||||
pub no_default_features: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
|
pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
|
||||||
@ -111,9 +110,7 @@ pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
|
|||||||
allow_dirty: opts.allow_dirty,
|
allow_dirty: opts.allow_dirty,
|
||||||
targets: opts.targets.clone(),
|
targets: opts.targets.clone(),
|
||||||
jobs: opts.jobs,
|
jobs: opts.jobs,
|
||||||
features: opts.features.clone(),
|
cli_features: opts.cli_features.clone(),
|
||||||
all_features: opts.all_features,
|
|
||||||
no_default_features: opts.no_default_features,
|
|
||||||
},
|
},
|
||||||
)?
|
)?
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
use crate::core::compiler::{CompileKind, RustcTargetData};
|
use crate::core::compiler::{CompileKind, RustcTargetData};
|
||||||
use crate::core::registry::PackageRegistry;
|
use crate::core::registry::PackageRegistry;
|
||||||
use crate::core::resolver::features::{
|
use crate::core::resolver::features::{
|
||||||
FeatureOpts, FeatureResolver, ForceAllTargets, ResolvedFeatures,
|
CliFeatures, FeatureOpts, FeatureResolver, ForceAllTargets, RequestedFeatures, ResolvedFeatures,
|
||||||
};
|
};
|
||||||
use crate::core::resolver::{self, HasDevUnits, Resolve, ResolveOpts, ResolveVersion};
|
use crate::core::resolver::{self, HasDevUnits, Resolve, ResolveOpts, ResolveVersion};
|
||||||
use crate::core::summary::Summary;
|
use crate::core::summary::Summary;
|
||||||
@ -80,7 +80,7 @@ pub fn resolve_ws_with_opts<'cfg>(
|
|||||||
ws: &Workspace<'cfg>,
|
ws: &Workspace<'cfg>,
|
||||||
target_data: &RustcTargetData,
|
target_data: &RustcTargetData,
|
||||||
requested_targets: &[CompileKind],
|
requested_targets: &[CompileKind],
|
||||||
opts: &ResolveOpts,
|
cli_features: &CliFeatures,
|
||||||
specs: &[PackageIdSpec],
|
specs: &[PackageIdSpec],
|
||||||
has_dev_units: HasDevUnits,
|
has_dev_units: HasDevUnits,
|
||||||
force_all_targets: ForceAllTargets,
|
force_all_targets: ForceAllTargets,
|
||||||
@ -122,7 +122,8 @@ pub fn resolve_ws_with_opts<'cfg>(
|
|||||||
let resolved_with_overrides = resolve_with_previous(
|
let resolved_with_overrides = resolve_with_previous(
|
||||||
&mut registry,
|
&mut registry,
|
||||||
ws,
|
ws,
|
||||||
opts,
|
cli_features,
|
||||||
|
has_dev_units,
|
||||||
resolve.as_ref(),
|
resolve.as_ref(),
|
||||||
None,
|
None,
|
||||||
specs,
|
specs,
|
||||||
@ -132,7 +133,7 @@ pub fn resolve_ws_with_opts<'cfg>(
|
|||||||
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 member_ids = ws
|
||||||
.members_with_features(specs, &opts.features)?
|
.members_with_features(specs, cli_features)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(p, _fts)| p.package_id())
|
.map(|(p, _fts)| p.package_id())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@ -151,7 +152,7 @@ pub fn resolve_ws_with_opts<'cfg>(
|
|||||||
target_data,
|
target_data,
|
||||||
&resolved_with_overrides,
|
&resolved_with_overrides,
|
||||||
&pkg_set,
|
&pkg_set,
|
||||||
&opts.features,
|
cli_features,
|
||||||
specs,
|
specs,
|
||||||
requested_targets,
|
requested_targets,
|
||||||
feature_opts,
|
feature_opts,
|
||||||
@ -173,7 +174,8 @@ fn resolve_with_registry<'cfg>(
|
|||||||
let mut resolve = resolve_with_previous(
|
let mut resolve = resolve_with_previous(
|
||||||
registry,
|
registry,
|
||||||
ws,
|
ws,
|
||||||
&ResolveOpts::everything(),
|
&CliFeatures::new_all(true),
|
||||||
|
HasDevUnits::Yes,
|
||||||
prev.as_ref(),
|
prev.as_ref(),
|
||||||
None,
|
None,
|
||||||
&[],
|
&[],
|
||||||
@ -204,7 +206,8 @@ fn resolve_with_registry<'cfg>(
|
|||||||
pub fn resolve_with_previous<'cfg>(
|
pub fn resolve_with_previous<'cfg>(
|
||||||
registry: &mut PackageRegistry<'cfg>,
|
registry: &mut PackageRegistry<'cfg>,
|
||||||
ws: &Workspace<'cfg>,
|
ws: &Workspace<'cfg>,
|
||||||
opts: &ResolveOpts,
|
cli_features: &CliFeatures,
|
||||||
|
has_dev_units: HasDevUnits,
|
||||||
previous: Option<&Resolve>,
|
previous: Option<&Resolve>,
|
||||||
to_avoid: Option<&HashSet<PackageId>>,
|
to_avoid: Option<&HashSet<PackageId>>,
|
||||||
specs: &[PackageIdSpec],
|
specs: &[PackageIdSpec],
|
||||||
@ -316,16 +319,17 @@ pub fn resolve_with_previous<'cfg>(
|
|||||||
registry.add_sources(Some(member.package_id().source_id()))?;
|
registry.add_sources(Some(member.package_id().source_id()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let dev_deps = ws.require_optional_deps() || has_dev_units == HasDevUnits::Yes;
|
||||||
let summaries: Vec<(Summary, ResolveOpts)> = ws
|
let summaries: Vec<(Summary, ResolveOpts)> = ws
|
||||||
.members_with_features(specs, &opts.features)?
|
.members_with_features(specs, cli_features)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(member, features)| {
|
.map(|(member, features)| {
|
||||||
let summary = registry.lock(member.summary().clone());
|
let summary = registry.lock(member.summary().clone());
|
||||||
(
|
(
|
||||||
summary,
|
summary,
|
||||||
ResolveOpts {
|
ResolveOpts {
|
||||||
dev_deps: opts.dev_deps,
|
dev_deps,
|
||||||
features,
|
features: RequestedFeatures::CliFeatures(features),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use super::TreeOptions;
|
use super::TreeOptions;
|
||||||
use crate::core::compiler::{CompileKind, RustcTargetData};
|
use crate::core::compiler::{CompileKind, RustcTargetData};
|
||||||
use crate::core::dependency::DepKind;
|
use crate::core::dependency::DepKind;
|
||||||
use crate::core::resolver::features::{FeaturesFor, RequestedFeatures, ResolvedFeatures};
|
use crate::core::resolver::features::{CliFeatures, FeaturesFor, ResolvedFeatures};
|
||||||
use crate::core::resolver::Resolve;
|
use crate::core::resolver::Resolve;
|
||||||
use crate::core::{FeatureMap, FeatureValue, Package, PackageId, PackageIdSpec, Workspace};
|
use crate::core::{FeatureMap, FeatureValue, Package, PackageId, PackageIdSpec, Workspace};
|
||||||
use crate::util::interning::InternedString;
|
use crate::util::interning::InternedString;
|
||||||
@ -248,16 +248,16 @@ pub fn build<'a>(
|
|||||||
resolve: &Resolve,
|
resolve: &Resolve,
|
||||||
resolved_features: &ResolvedFeatures,
|
resolved_features: &ResolvedFeatures,
|
||||||
specs: &[PackageIdSpec],
|
specs: &[PackageIdSpec],
|
||||||
requested_features: &RequestedFeatures,
|
cli_features: &CliFeatures,
|
||||||
target_data: &RustcTargetData,
|
target_data: &RustcTargetData,
|
||||||
requested_kinds: &[CompileKind],
|
requested_kinds: &[CompileKind],
|
||||||
package_map: HashMap<PackageId, &'a Package>,
|
package_map: HashMap<PackageId, &'a Package>,
|
||||||
opts: &TreeOptions,
|
opts: &TreeOptions,
|
||||||
) -> CargoResult<Graph<'a>> {
|
) -> CargoResult<Graph<'a>> {
|
||||||
let mut graph = Graph::new(package_map);
|
let mut graph = Graph::new(package_map);
|
||||||
let mut members_with_features = ws.members_with_features(specs, requested_features)?;
|
let mut members_with_features = ws.members_with_features(specs, cli_features)?;
|
||||||
members_with_features.sort_unstable_by_key(|e| e.0.package_id());
|
members_with_features.sort_unstable_by_key(|e| e.0.package_id());
|
||||||
for (member, requested_features) in members_with_features {
|
for (member, cli_features) in members_with_features {
|
||||||
let member_id = member.package_id();
|
let member_id = member.package_id();
|
||||||
let features_for = FeaturesFor::from_for_host(member.proc_macro());
|
let features_for = FeaturesFor::from_for_host(member.proc_macro());
|
||||||
for kind in requested_kinds {
|
for kind in requested_kinds {
|
||||||
@ -273,7 +273,7 @@ pub fn build<'a>(
|
|||||||
);
|
);
|
||||||
if opts.graph_features {
|
if opts.graph_features {
|
||||||
let fmap = resolve.summary(member_id).features();
|
let fmap = resolve.summary(member_id).features();
|
||||||
add_cli_features(&mut graph, member_index, &requested_features, fmap);
|
add_cli_features(&mut graph, member_index, &cli_features, fmap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,7 +392,7 @@ fn add_pkg(
|
|||||||
EdgeKind::Dep(dep.kind()),
|
EdgeKind::Dep(dep.kind()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for feature in dep.features() {
|
for feature in dep.features().iter() {
|
||||||
add_feature(
|
add_feature(
|
||||||
graph,
|
graph,
|
||||||
*feature,
|
*feature,
|
||||||
@ -459,48 +459,66 @@ fn add_feature(
|
|||||||
fn add_cli_features(
|
fn add_cli_features(
|
||||||
graph: &mut Graph<'_>,
|
graph: &mut Graph<'_>,
|
||||||
package_index: usize,
|
package_index: usize,
|
||||||
requested_features: &RequestedFeatures,
|
cli_features: &CliFeatures,
|
||||||
feature_map: &FeatureMap,
|
feature_map: &FeatureMap,
|
||||||
) {
|
) {
|
||||||
// NOTE: Recursive enabling of features will be handled by
|
// NOTE: Recursive enabling of features will be handled by
|
||||||
// add_internal_features.
|
// add_internal_features.
|
||||||
|
|
||||||
// Create a list of feature names requested on the command-line.
|
// Create a set of feature names requested on the command-line.
|
||||||
let mut to_add: Vec<InternedString> = Vec::new();
|
let mut to_add: HashSet<FeatureValue> = HashSet::new();
|
||||||
if requested_features.all_features {
|
if cli_features.all_features {
|
||||||
to_add.extend(feature_map.keys().copied());
|
to_add.extend(feature_map.keys().map(|feat| FeatureValue::Feature(*feat)));
|
||||||
// Add optional deps.
|
|
||||||
for (dep_name, deps) in &graph.dep_name_map[&package_index] {
|
|
||||||
if deps.iter().any(|(_idx, is_optional)| *is_optional) {
|
|
||||||
to_add.push(*dep_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if requested_features.uses_default_features {
|
if cli_features.uses_default_features {
|
||||||
to_add.push(InternedString::new("default"));
|
to_add.insert(FeatureValue::Feature(InternedString::new("default")));
|
||||||
}
|
}
|
||||||
to_add.extend(requested_features.features.iter().copied());
|
to_add.extend(cli_features.features.iter().cloned());
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add each feature as a node, and mark as "from command-line" in graph.cli_features.
|
// Add each feature as a node, and mark as "from command-line" in graph.cli_features.
|
||||||
for name in to_add {
|
for fv in to_add {
|
||||||
if name.contains('/') {
|
match fv {
|
||||||
let mut parts = name.splitn(2, '/');
|
FeatureValue::Feature(feature) => {
|
||||||
let dep_name = InternedString::new(parts.next().unwrap());
|
let index = add_feature(graph, feature, None, package_index, EdgeKind::Feature);
|
||||||
let feat_name = InternedString::new(parts.next().unwrap());
|
|
||||||
for (dep_index, is_optional) in graph.dep_name_map[&package_index][&dep_name].clone() {
|
|
||||||
if is_optional {
|
|
||||||
// Activate the optional dep on self.
|
|
||||||
let index =
|
|
||||||
add_feature(graph, dep_name, None, package_index, EdgeKind::Feature);
|
|
||||||
graph.cli_features.insert(index);
|
|
||||||
}
|
|
||||||
let index = add_feature(graph, feat_name, None, dep_index, EdgeKind::Feature);
|
|
||||||
graph.cli_features.insert(index);
|
graph.cli_features.insert(index);
|
||||||
}
|
}
|
||||||
} else {
|
// This is enforced by CliFeatures.
|
||||||
let index = add_feature(graph, name, None, package_index, EdgeKind::Feature);
|
FeatureValue::Dep { .. } => panic!("unexpected cli dep feature {}", fv),
|
||||||
graph.cli_features.insert(index);
|
FeatureValue::DepFeature {
|
||||||
|
dep_name,
|
||||||
|
dep_feature,
|
||||||
|
dep_prefix: _,
|
||||||
|
weak,
|
||||||
|
} => {
|
||||||
|
let dep_connections = match graph.dep_name_map[&package_index].get(&dep_name) {
|
||||||
|
// Clone to deal with immutable borrow of `graph`. :(
|
||||||
|
Some(dep_connections) => dep_connections.clone(),
|
||||||
|
None => {
|
||||||
|
// --features bar?/feat where `bar` is not activated should be ignored.
|
||||||
|
// If this wasn't weak, then this is a bug.
|
||||||
|
if weak {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
panic!(
|
||||||
|
"missing dep graph connection for CLI feature `{}` for member {:?}\n\
|
||||||
|
Please file a bug report at https://github.com/rust-lang/cargo/issues",
|
||||||
|
fv,
|
||||||
|
graph.nodes.get(package_index)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (dep_index, is_optional) in dep_connections {
|
||||||
|
if is_optional {
|
||||||
|
// Activate the optional dep on self.
|
||||||
|
let index =
|
||||||
|
add_feature(graph, dep_name, None, package_index, EdgeKind::Feature);
|
||||||
|
graph.cli_features.insert(index);
|
||||||
|
}
|
||||||
|
let index = add_feature(graph, dep_feature, None, dep_index, EdgeKind::Feature);
|
||||||
|
graph.cli_features.insert(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -570,6 +588,10 @@ fn add_feature_rec(
|
|||||||
package_index,
|
package_index,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Dependencies are already shown in the graph as dep edges. I'm
|
||||||
|
// uncertain whether or not this might be confusing in some cases
|
||||||
|
// (like feature `"somefeat" = ["dep:somedep"]`), so maybe in the
|
||||||
|
// future consider explicitly showing this?
|
||||||
FeatureValue::Dep { .. } => {}
|
FeatureValue::Dep { .. } => {}
|
||||||
FeatureValue::DepFeature {
|
FeatureValue::DepFeature {
|
||||||
dep_name,
|
dep_name,
|
||||||
|
@ -3,9 +3,7 @@
|
|||||||
use self::format::Pattern;
|
use self::format::Pattern;
|
||||||
use crate::core::compiler::{CompileKind, RustcTargetData};
|
use crate::core::compiler::{CompileKind, RustcTargetData};
|
||||||
use crate::core::dependency::DepKind;
|
use crate::core::dependency::DepKind;
|
||||||
use crate::core::resolver::{
|
use crate::core::resolver::{features::CliFeatures, ForceAllTargets, HasDevUnits};
|
||||||
features::RequestedFeatures, ForceAllTargets, HasDevUnits, ResolveOpts,
|
|
||||||
};
|
|
||||||
use crate::core::{Package, PackageId, PackageIdSpec, Workspace};
|
use crate::core::{Package, PackageId, PackageIdSpec, Workspace};
|
||||||
use crate::ops::{self, Packages};
|
use crate::ops::{self, Packages};
|
||||||
use crate::util::{CargoResult, Config};
|
use crate::util::{CargoResult, Config};
|
||||||
@ -21,9 +19,7 @@ mod graph;
|
|||||||
pub use {graph::EdgeKind, graph::Node};
|
pub use {graph::EdgeKind, graph::Node};
|
||||||
|
|
||||||
pub struct TreeOptions {
|
pub struct TreeOptions {
|
||||||
pub features: Vec<String>,
|
pub cli_features: CliFeatures,
|
||||||
pub no_default_features: bool,
|
|
||||||
pub all_features: bool,
|
|
||||||
/// The packages to display the tree for.
|
/// The packages to display the tree for.
|
||||||
pub packages: Packages,
|
pub packages: Packages,
|
||||||
/// The platform to filter for.
|
/// The platform to filter for.
|
||||||
@ -138,12 +134,6 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
|
|||||||
let requested_kinds = CompileKind::from_requested_targets(ws.config(), &requested_targets)?;
|
let requested_kinds = CompileKind::from_requested_targets(ws.config(), &requested_targets)?;
|
||||||
let target_data = RustcTargetData::new(ws, &requested_kinds)?;
|
let target_data = RustcTargetData::new(ws, &requested_kinds)?;
|
||||||
let specs = opts.packages.to_package_id_specs(ws)?;
|
let specs = opts.packages.to_package_id_specs(ws)?;
|
||||||
let requested_features = RequestedFeatures::from_command_line(
|
|
||||||
&opts.features,
|
|
||||||
opts.all_features,
|
|
||||||
!opts.no_default_features,
|
|
||||||
);
|
|
||||||
let resolve_opts = ResolveOpts::new(/*dev_deps*/ true, requested_features);
|
|
||||||
let has_dev = if opts
|
let has_dev = if opts
|
||||||
.edge_kinds
|
.edge_kinds
|
||||||
.contains(&EdgeKind::Dep(DepKind::Development))
|
.contains(&EdgeKind::Dep(DepKind::Development))
|
||||||
@ -161,7 +151,7 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
|
|||||||
ws,
|
ws,
|
||||||
&target_data,
|
&target_data,
|
||||||
&requested_kinds,
|
&requested_kinds,
|
||||||
&resolve_opts,
|
&opts.cli_features,
|
||||||
&specs,
|
&specs,
|
||||||
has_dev,
|
has_dev,
|
||||||
force_all,
|
force_all,
|
||||||
@ -178,7 +168,7 @@ pub fn build_and_print(ws: &Workspace<'_>, opts: &TreeOptions) -> CargoResult<()
|
|||||||
&ws_resolve.targeted_resolve,
|
&ws_resolve.targeted_resolve,
|
||||||
&ws_resolve.resolved_features,
|
&ws_resolve.resolved_features,
|
||||||
&specs,
|
&specs,
|
||||||
&resolve_opts.features,
|
&opts.cli_features,
|
||||||
&target_data,
|
&target_data,
|
||||||
&requested_kinds,
|
&requested_kinds,
|
||||||
package_map,
|
package_map,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::core::compiler::{BuildConfig, MessageFormat};
|
use crate::core::compiler::{BuildConfig, MessageFormat};
|
||||||
|
use crate::core::resolver::CliFeatures;
|
||||||
use crate::core::{Edition, Workspace};
|
use crate::core::{Edition, Workspace};
|
||||||
use crate::ops::{CompileFilter, CompileOptions, NewOptions, Packages, VersionControl};
|
use crate::ops::{CompileFilter, CompileOptions, NewOptions, Packages, VersionControl};
|
||||||
use crate::sources::CRATES_IO_REGISTRY;
|
use crate::sources::CRATES_IO_REGISTRY;
|
||||||
@ -495,9 +496,7 @@ pub trait ArgMatchesExt {
|
|||||||
|
|
||||||
let opts = CompileOptions {
|
let opts = CompileOptions {
|
||||||
build_config,
|
build_config,
|
||||||
features: self._values_of("features"),
|
cli_features: self.cli_features()?,
|
||||||
all_features: self._is_present("all-features"),
|
|
||||||
no_default_features: self._is_present("no-default-features"),
|
|
||||||
spec,
|
spec,
|
||||||
filter: CompileFilter::from_raw_arguments(
|
filter: CompileFilter::from_raw_arguments(
|
||||||
self._is_present("lib"),
|
self._is_present("lib"),
|
||||||
@ -539,6 +538,14 @@ pub trait ArgMatchesExt {
|
|||||||
Ok(opts)
|
Ok(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cli_features(&self) -> CargoResult<CliFeatures> {
|
||||||
|
CliFeatures::from_command_line(
|
||||||
|
&self._values_of("features"),
|
||||||
|
self._is_present("all-features"),
|
||||||
|
!self._is_present("no-default-features"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn compile_options_for_single_package(
|
fn compile_options_for_single_package(
|
||||||
&self,
|
&self,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
|
@ -1773,6 +1773,35 @@ impl<P: ResolveToPath> DetailedTomlDependency<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Early detection of potentially misused feature syntax
|
||||||
|
// instead of generating a "feature not found" error.
|
||||||
|
if let Some(features) = &self.features {
|
||||||
|
for feature in features {
|
||||||
|
if feature.contains('/') {
|
||||||
|
bail!(
|
||||||
|
"feature `{}` in dependency `{}` is not allowed to contain slashes\n\
|
||||||
|
If you want to enable features of a transitive dependency, \
|
||||||
|
the direct dependency needs to re-export those features from \
|
||||||
|
the `[features]` table.",
|
||||||
|
feature,
|
||||||
|
name_in_toml
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if feature.starts_with("dep:") {
|
||||||
|
bail!(
|
||||||
|
"feature `{}` in dependency `{}` is not allowed to use explicit \
|
||||||
|
`dep:` syntax\n\
|
||||||
|
If you want to enable an optional dependency, specify the name \
|
||||||
|
of the optional dependency without the `dep:` prefix, or specify \
|
||||||
|
a feature from the dependency's `[features]` table that enables \
|
||||||
|
the optional dependency.",
|
||||||
|
feature,
|
||||||
|
name_in_toml
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let new_source_id = match (
|
let new_source_id = match (
|
||||||
self.git.as_ref(),
|
self.git.as_ref(),
|
||||||
self.path.as_ref(),
|
self.path.as_ref(),
|
||||||
|
@ -269,7 +269,15 @@ fn invalid8() {
|
|||||||
|
|
||||||
p.cargo("build --features foo")
|
p.cargo("build --features foo")
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr("[ERROR] feature names may not contain slashes: `foo/bar`")
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
error: failed to parse manifest at `[CWD]/Cargo.toml`
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
feature `foo/bar` in dependency `bar` is not allowed to contain slashes
|
||||||
|
If you want to enable features [..]
|
||||||
|
",
|
||||||
|
)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,7 +417,14 @@ fn no_transitive_dep_feature_requirement() {
|
|||||||
.build();
|
.build();
|
||||||
p.cargo("build")
|
p.cargo("build")
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr("[ERROR] feature names may not contain slashes: `bar/qux`")
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
error: failed to parse manifest at `[CWD]/Cargo.toml`
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
multiple slashes in feature `derived/bar/qux` (included by feature `default`) are not allowed
|
||||||
|
",
|
||||||
|
)
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1192,7 +1207,7 @@ fn dep_feature_in_cmd_line() {
|
|||||||
// Hierarchical feature specification should still be disallowed
|
// Hierarchical feature specification should still be disallowed
|
||||||
p.cargo("build --features derived/bar/some-feat")
|
p.cargo("build --features derived/bar/some-feat")
|
||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr("[ERROR] feature names may not contain slashes: `bar/some-feat`")
|
.with_stderr("[ERROR] multiple slashes in feature `derived/bar/some-feat` is not allowed")
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1906,7 +1921,7 @@ fn nonexistent_required_features() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
fn invalid_feature_names() {
|
fn invalid_feature_names_warning() {
|
||||||
// Warnings for more restricted feature syntax.
|
// Warnings for more restricted feature syntax.
|
||||||
let p = project()
|
let p = project()
|
||||||
.file(
|
.file(
|
||||||
@ -1929,7 +1944,6 @@ fn invalid_feature_names() {
|
|||||||
"+foo" = []
|
"+foo" = []
|
||||||
"-foo" = []
|
"-foo" = []
|
||||||
".foo" = []
|
".foo" = []
|
||||||
"foo/bar" = []
|
|
||||||
"foo:bar" = []
|
"foo:bar" = []
|
||||||
"foo?" = []
|
"foo?" = []
|
||||||
"?foo" = []
|
"?foo" = []
|
||||||
@ -1961,9 +1975,6 @@ For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues
|
|||||||
[WARNING] invalid character `¼` in feature `a¼` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
|
[WARNING] invalid character `¼` in feature `a¼` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
|
||||||
This was previously accepted but is being phased out; it will become a hard error in a future release.
|
This was previously accepted but is being phased out; it will become a hard error in a future release.
|
||||||
For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
|
For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
|
||||||
[WARNING] invalid character `/` in feature `foo/bar` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
|
|
||||||
This was previously accepted but is being phased out; it will become a hard error in a future release.
|
|
||||||
For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
|
|
||||||
[WARNING] invalid character `:` in feature `foo:bar` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
|
[WARNING] invalid character `:` in feature `foo:bar` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
|
||||||
This was previously accepted but is being phased out; it will become a hard error in a future release.
|
This was previously accepted but is being phased out; it will become a hard error in a future release.
|
||||||
For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
|
For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
|
||||||
@ -1994,9 +2005,6 @@ For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues
|
|||||||
[WARNING] invalid character `¼` in feature `a¼` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
|
[WARNING] invalid character `¼` in feature `a¼` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
|
||||||
This was previously accepted but is being phased out; it will become a hard error in a future release.
|
This was previously accepted but is being phased out; it will become a hard error in a future release.
|
||||||
For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
|
For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
|
||||||
[WARNING] invalid character `/` in feature `foo/bar` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
|
|
||||||
This was previously accepted but is being phased out; it will become a hard error in a future release.
|
|
||||||
For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
|
|
||||||
[WARNING] invalid character `:` in feature `foo:bar` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
|
[WARNING] invalid character `:` in feature `foo:bar` in package foo v0.1.0 ([ROOT]/foo), characters must be Unicode XID characters, `+`, or `.` (numbers, `+`, `-`, `_`, `.`, or most letters)
|
||||||
This was previously accepted but is being phased out; it will become a hard error in a future release.
|
This was previously accepted but is being phased out; it will become a hard error in a future release.
|
||||||
For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
|
For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues/8813>, and please leave a comment if this will be a problem for your project.
|
||||||
@ -2017,3 +2025,34 @@ For more information, see issue #8813 <https://github.com/rust-lang/cargo/issues
|
|||||||
")
|
")
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn invalid_feature_names_error() {
|
||||||
|
// Errors for more restricted feature syntax.
|
||||||
|
let p = project()
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
"foo/bar" = []
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/lib.rs", "")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
p.cargo("check")
|
||||||
|
.with_status(101)
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
error: failed to parse manifest at `[CWD]/Cargo.toml`
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
feature named `foo/bar` is not allowed to contain slashes
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
//! Tests for namespaced features.
|
//! Tests for namespaced features.
|
||||||
|
|
||||||
|
use super::features2::switch_to_resolver_2;
|
||||||
use cargo_test_support::registry::{Dependency, Package};
|
use cargo_test_support::registry::{Dependency, Package};
|
||||||
use cargo_test_support::{project, publish};
|
use cargo_test_support::{project, publish};
|
||||||
|
|
||||||
@ -633,8 +634,11 @@ fn crate_syntax_in_dep() {
|
|||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
error: failed to parse manifest at `[CWD]/Cargo.toml`
|
||||||
[ERROR] feature value `dep:baz` is not allowed to use explicit `dep:` syntax
|
|
||||||
|
Caused by:
|
||||||
|
feature `dep:baz` in dependency `bar` is not allowed to use explicit `dep:` syntax
|
||||||
|
If you want to enable [..]
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
@ -664,8 +668,18 @@ fn crate_syntax_cli() {
|
|||||||
.with_status(101)
|
.with_status(101)
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
"\
|
"\
|
||||||
[UPDATING] [..]
|
[ERROR] feature `dep:bar` is not allowed to use explicit `dep:` syntax
|
||||||
[ERROR] feature value `dep:bar` is not allowed to use explicit `dep:` syntax
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
switch_to_resolver_2(&p);
|
||||||
|
p.cargo("check -Z namespaced-features --features dep:bar")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_status(101)
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[ERROR] feature `dep:bar` is not allowed to use explicit `dep:` syntax
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
@ -998,6 +1012,57 @@ bar v1.0.0
|
|||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn tree_no_implicit() {
|
||||||
|
// tree without an implicit feature
|
||||||
|
Package::new("bar", "1.0.0").publish();
|
||||||
|
let p = project()
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bar = { version = "1.0", optional=true }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
a = ["dep:bar"]
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/lib.rs", "")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
p.cargo("tree -e features -Z namespaced-features")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_stdout("foo v0.1.0 ([ROOT]/foo)")
|
||||||
|
.run();
|
||||||
|
|
||||||
|
p.cargo("tree -e features --all-features -Z namespaced-features")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_stdout(
|
||||||
|
"\
|
||||||
|
foo v0.1.0 ([ROOT]/foo)
|
||||||
|
└── bar feature \"default\"
|
||||||
|
└── bar v1.0.0
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
p.cargo("tree -e features -i bar --all-features -Z namespaced-features")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_stdout(
|
||||||
|
"\
|
||||||
|
bar v1.0.0
|
||||||
|
└── bar feature \"default\"
|
||||||
|
└── foo v0.1.0 ([ROOT]/foo)
|
||||||
|
└── foo feature \"a\" (command-line)
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
fn publish_no_implicit() {
|
fn publish_no_implicit() {
|
||||||
// Does not include implicit features or dep: syntax on publish.
|
// Does not include implicit features or dep: syntax on publish.
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
//! Tests for feature selection on the command-line.
|
//! Tests for feature selection on the command-line.
|
||||||
|
|
||||||
use super::features2::switch_to_resolver_2;
|
use super::features2::switch_to_resolver_2;
|
||||||
use cargo_test_support::registry::Package;
|
use cargo_test_support::registry::{Dependency, Package};
|
||||||
use cargo_test_support::{basic_manifest, project};
|
use cargo_test_support::{basic_manifest, project};
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
fn virtual_no_default_features() {
|
fn virtual_no_default_features() {
|
||||||
@ -460,32 +461,162 @@ fn resolver1_member_features() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
fn resolver1_non_member_optional_feature() {
|
fn non_member_feature() {
|
||||||
// --features x/y for an optional dependency `x` with the v1 resolver.
|
// --features for a non-member
|
||||||
|
Package::new("jazz", "1.0.0").publish();
|
||||||
Package::new("bar", "1.0.0")
|
Package::new("bar", "1.0.0")
|
||||||
.feature("feat1", &[])
|
.add_dep(Dependency::new("jazz", "1.0").optional(true))
|
||||||
.file(
|
|
||||||
"src/lib.rs",
|
|
||||||
r#"
|
|
||||||
#[cfg(not(feature = "feat1"))]
|
|
||||||
compile_error!("feat1 should be activated");
|
|
||||||
"#,
|
|
||||||
)
|
|
||||||
.publish();
|
.publish();
|
||||||
let p = project()
|
let make_toml = |resolver, optional| {
|
||||||
.file(
|
let mut s = String::new();
|
||||||
"Cargo.toml",
|
write!(
|
||||||
|
s,
|
||||||
r#"
|
r#"
|
||||||
[package]
|
[package]
|
||||||
name = "foo"
|
name = "foo"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
resolver = "{}"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bar = { version="1.0", optional=true }
|
|
||||||
"#,
|
"#,
|
||||||
|
resolver
|
||||||
)
|
)
|
||||||
|
.unwrap();
|
||||||
|
if optional {
|
||||||
|
s.push_str(r#"bar = { version = "1.0", optional = true } "#);
|
||||||
|
} else {
|
||||||
|
s.push_str(r#"bar = "1.0""#)
|
||||||
|
}
|
||||||
|
s.push('\n');
|
||||||
|
s
|
||||||
|
};
|
||||||
|
let p = project()
|
||||||
|
.file("Cargo.toml", &make_toml("1", false))
|
||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
p.cargo("fetch").run();
|
||||||
|
///////////////////////// V1 non-optional
|
||||||
|
eprintln!("V1 non-optional");
|
||||||
|
p.cargo("check -p bar")
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[CHECKING] bar v1.0.0
|
||||||
|
[FINISHED] [..]
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
// TODO: This should not be allowed (future warning?)
|
||||||
|
p.cargo("check --features bar/jazz")
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[DOWNLOADING] crates ...
|
||||||
|
[DOWNLOADED] jazz v1.0.0 [..]
|
||||||
|
[CHECKING] jazz v1.0.0
|
||||||
|
[CHECKING] bar v1.0.0
|
||||||
|
[CHECKING] foo v0.1.0 [..]
|
||||||
|
[FINISHED] [..]
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
// TODO: This should not be allowed (future warning?)
|
||||||
|
p.cargo("check -p bar --features bar/jazz -v")
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[FRESH] jazz v1.0.0
|
||||||
|
[FRESH] bar v1.0.0
|
||||||
|
[FINISHED] [..]
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
p.cargo("check -p bar --features bar/feat1").run();
|
///////////////////////// V1 optional
|
||||||
|
eprintln!("V1 optional");
|
||||||
|
p.change_file("Cargo.toml", &make_toml("1", true));
|
||||||
|
|
||||||
|
// This error isn't great, but is probably unlikely to be common in
|
||||||
|
// practice, so I'm not going to put much effort into improving it.
|
||||||
|
p.cargo("check -p bar")
|
||||||
|
.with_status(101)
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
error: package ID specification `bar` did not match any packages
|
||||||
|
|
||||||
|
<tab>Did you mean `foo`?
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
p.cargo("check -p bar --features bar -v")
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[FRESH] bar v1.0.0
|
||||||
|
[FINISHED] [..]
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
// TODO: This should not be allowed (future warning?)
|
||||||
|
p.cargo("check -p bar --features bar/jazz -v")
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[FRESH] jazz v1.0.0
|
||||||
|
[FRESH] bar v1.0.0
|
||||||
|
[FINISHED] [..]
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
///////////////////////// V2 non-optional
|
||||||
|
eprintln!("V2 non-optional");
|
||||||
|
p.change_file("Cargo.toml", &make_toml("2", false));
|
||||||
|
// TODO: This should not be allowed (future warning?)
|
||||||
|
p.cargo("check --features bar/jazz -v")
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[FRESH] jazz v1.0.0
|
||||||
|
[FRESH] bar v1.0.0
|
||||||
|
[FRESH] foo v0.1.0 [..]
|
||||||
|
[FINISHED] [..]
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
p.cargo("check -p bar -v")
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[FRESH] bar v1.0.0
|
||||||
|
[FINISHED] [..]
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
p.cargo("check -p bar --features bar/jazz")
|
||||||
|
.with_status(101)
|
||||||
|
.with_stderr("error: cannot specify features for packages outside of workspace")
|
||||||
|
.run();
|
||||||
|
|
||||||
|
///////////////////////// V2 optional
|
||||||
|
eprintln!("V2 optional");
|
||||||
|
p.change_file("Cargo.toml", &make_toml("2", true));
|
||||||
|
p.cargo("check -p bar")
|
||||||
|
.with_status(101)
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
error: package ID specification `bar` did not match any packages
|
||||||
|
|
||||||
|
<tab>Did you mean `foo`?
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
// New --features behavior does not look at cwd.
|
||||||
|
p.cargo("check -p bar --features bar")
|
||||||
|
.with_status(101)
|
||||||
|
.with_stderr("error: cannot specify features for packages outside of workspace")
|
||||||
|
.run();
|
||||||
|
p.cargo("check -p bar --features bar/jazz")
|
||||||
|
.with_status(101)
|
||||||
|
.with_stderr("error: cannot specify features for packages outside of workspace")
|
||||||
|
.run();
|
||||||
|
p.cargo("check -p bar --features foo/bar")
|
||||||
|
.with_status(101)
|
||||||
|
.with_stderr("error: cannot specify features for packages outside of workspace")
|
||||||
|
.run();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
//! Tests for weak-dep-features.
|
//! Tests for weak-dep-features.
|
||||||
|
|
||||||
|
use super::features2::switch_to_resolver_2;
|
||||||
|
use cargo_test_support::paths::CargoPathExt;
|
||||||
use cargo_test_support::registry::{Dependency, Package};
|
use cargo_test_support::registry::{Dependency, Package};
|
||||||
use cargo_test_support::{project, publish};
|
use cargo_test_support::{project, publish};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
@ -272,6 +274,7 @@ fn optional_cli_syntax() {
|
|||||||
.file("src/lib.rs", "")
|
.file("src/lib.rs", "")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
// Does not build bar.
|
||||||
p.cargo("check --features bar?/feat -Z weak-dep-features")
|
p.cargo("check --features bar?/feat -Z weak-dep-features")
|
||||||
.masquerade_as_nightly_cargo()
|
.masquerade_as_nightly_cargo()
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
@ -285,6 +288,33 @@ fn optional_cli_syntax() {
|
|||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
|
|
||||||
|
// Builds bar.
|
||||||
|
p.cargo("check --features bar?/feat,bar -Z weak-dep-features")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[CHECKING] bar v1.0.0
|
||||||
|
[CHECKING] foo v0.1.0 [..]
|
||||||
|
[FINISHED] [..]
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
eprintln!("check V2 resolver");
|
||||||
|
switch_to_resolver_2(&p);
|
||||||
|
p.build_dir().rm_rf();
|
||||||
|
// Does not build bar.
|
||||||
|
p.cargo("check --features bar?/feat -Z weak-dep-features")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[CHECKING] foo v0.1.0 [..]
|
||||||
|
[FINISHED] [..]
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
// Builds bar.
|
||||||
p.cargo("check --features bar?/feat,bar -Z weak-dep-features")
|
p.cargo("check --features bar?/feat,bar -Z weak-dep-features")
|
||||||
.masquerade_as_nightly_cargo()
|
.masquerade_as_nightly_cargo()
|
||||||
.with_stderr(
|
.with_stderr(
|
||||||
@ -561,6 +591,32 @@ bar v1.0.0
|
|||||||
│ └── foo feature \"f1\" (command-line)
|
│ └── foo feature \"f1\" (command-line)
|
||||||
└── bar feature \"feat\"
|
└── bar feature \"feat\"
|
||||||
└── foo feature \"f1\" (command-line)
|
└── foo feature \"f1\" (command-line)
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
p.cargo("tree -Z weak-dep-features -e features --features bar?/feat")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_stdout("foo v0.1.0 ([ROOT]/foo)")
|
||||||
|
.run();
|
||||||
|
|
||||||
|
// This is a little strange in that it produces no output.
|
||||||
|
// Maybe `cargo tree` should print a note about why?
|
||||||
|
p.cargo("tree -Z weak-dep-features -e features -i bar --features bar?/feat")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_stdout("")
|
||||||
|
.run();
|
||||||
|
|
||||||
|
p.cargo("tree -Z weak-dep-features -e features -i bar --features bar?/feat,bar")
|
||||||
|
.masquerade_as_nightly_cargo()
|
||||||
|
.with_stdout(
|
||||||
|
"\
|
||||||
|
bar v1.0.0
|
||||||
|
├── bar feature \"default\"
|
||||||
|
│ └── foo v0.1.0 ([ROOT]/foo)
|
||||||
|
│ ├── foo feature \"bar\" (command-line)
|
||||||
|
│ └── foo feature \"default\" (command-line)
|
||||||
|
└── bar feature \"feat\" (command-line)
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user