mirror of
https://github.com/rust-lang/cargo
synced 2024-10-05 23:39:47 +00:00
Auto merge of #10269 - ehuss:stabilized-new-features, r=alexcrichton
Stabilize namespaced and weak dependency features. This stabilizes the namespaced and weak dependency features. Support is now enabled on crates.io, so this should be ready to go. As a part of this change, the new feature resolver is now enabled all of the time. This is fairly risky, since there are likely edge cases that haven't been exercised. NOTE: Projects using `resolver="1"` *should* continue to have the same behavior, the old resolver behavior is emulated. Closes #8813 Closes #8832
This commit is contained in:
commit
e77c0719fd
|
@ -20,7 +20,7 @@ atty = "0.2"
|
|||
bytesize = "1.0"
|
||||
cargo-platform = { path = "crates/cargo-platform", version = "0.1.2" }
|
||||
cargo-util = { path = "crates/cargo-util", version = "0.1.2" }
|
||||
crates-io = { path = "crates/crates-io", version = "0.33.1" }
|
||||
crates-io = { path = "crates/crates-io", version = "0.34.0" }
|
||||
crossbeam-utils = "0.8"
|
||||
curl = { version = "0.4.41", features = ["http2"] }
|
||||
curl-sys = "0.4.50"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "crates-io"
|
||||
version = "0.33.1"
|
||||
version = "0.34.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/rust-lang/cargo"
|
||||
|
|
|
@ -55,8 +55,6 @@ pub struct NewCrate {
|
|||
pub repository: Option<String>,
|
||||
pub badges: BTreeMap<String, BTreeMap<String, String>>,
|
||||
pub links: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub v: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
|
|
@ -15,8 +15,6 @@ Deprecated, use `cargo metadata --no-deps` instead.\
|
|||
|
||||
pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
|
||||
let ws = args.workspace(config)?;
|
||||
config
|
||||
.shell()
|
||||
.print_json(&ws.current()?.serialized(config))?;
|
||||
config.shell().print_json(&ws.current()?.serialized())?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -645,7 +645,6 @@ unstable_cli_options!(
|
|||
minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum"),
|
||||
mtime_on_use: bool = ("Configure Cargo to update the mtime of used files"),
|
||||
multitarget: bool = ("Allow passing multiple `--target` flags to the cargo subcommand selected"),
|
||||
namespaced_features: bool = ("Allow features with `dep:` prefix"),
|
||||
no_index_update: bool = ("Do not update the registry index even if the cache is outdated"),
|
||||
panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"),
|
||||
host_config: bool = ("Enable the [host] section in the .cargo/config.toml file"),
|
||||
|
@ -655,7 +654,6 @@ unstable_cli_options!(
|
|||
terminal_width: Option<Option<usize>> = ("Provide a terminal width to rustc for error truncation"),
|
||||
timings: Option<Vec<String>> = ("Display concurrency information"),
|
||||
unstable_options: bool = ("Allow the usage of unstable options"),
|
||||
weak_dep_features: bool = ("Allow `dep_name?/feature` feature syntax"),
|
||||
// TODO(wcrichto): move scrape example configuration into Cargo.toml before stabilization
|
||||
// See: https://github.com/rust-lang/cargo/pull/9525#discussion_r728470927
|
||||
rustdoc_scrape_examples: Option<String> = ("Allow rustdoc to scrape examples from reverse-dependencies for documentation"),
|
||||
|
@ -710,6 +708,10 @@ const STABILIZED_NAMED_PROFILES: &str = "The named-profiles feature is now alway
|
|||
const STABILIZED_FUTURE_INCOMPAT_REPORT: &str =
|
||||
"The future-incompat-report feature is now always enabled.";
|
||||
|
||||
const STABILIZED_WEAK_DEP_FEATURES: &str = "Weak dependency features are now always available.";
|
||||
|
||||
const STABILISED_NAMESPACED_FEATURES: &str = "Namespaced features are now always available.";
|
||||
|
||||
fn deserialize_build_std<'de, D>(deserializer: D) -> Result<Option<Vec<String>>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
|
@ -876,8 +878,8 @@ impl CliUnstable {
|
|||
"multitarget" => self.multitarget = parse_empty(k, v)?,
|
||||
"rustdoc-map" => self.rustdoc_map = parse_empty(k, v)?,
|
||||
"terminal-width" => self.terminal_width = Some(parse_usize_opt(v)?),
|
||||
"namespaced-features" => self.namespaced_features = parse_empty(k, v)?,
|
||||
"weak-dep-features" => self.weak_dep_features = parse_empty(k, v)?,
|
||||
"namespaced-features" => stabilized_warn(k, "1.60", STABILISED_NAMESPACED_FEATURES),
|
||||
"weak-dep-features" => stabilized_warn(k, "1.60", STABILIZED_WEAK_DEP_FEATURES),
|
||||
"credential-process" => self.credential_process = parse_empty(k, v)?,
|
||||
"rustdoc-scrape-examples" => {
|
||||
if let Some(s) = v {
|
||||
|
|
|
@ -208,7 +208,7 @@ impl Package {
|
|||
self.targets().iter().any(|t| t.is_example() || t.is_bin())
|
||||
}
|
||||
|
||||
pub fn serialized(&self, config: &Config) -> SerializedPackage {
|
||||
pub fn serialized(&self) -> SerializedPackage {
|
||||
let summary = self.manifest().summary();
|
||||
let package_id = summary.package_id();
|
||||
let manmeta = self.manifest().metadata();
|
||||
|
@ -222,27 +222,19 @@ impl Package {
|
|||
.filter(|t| t.src_path().is_path())
|
||||
.cloned()
|
||||
.collect();
|
||||
let features = if config.cli_unstable().namespaced_features {
|
||||
// Convert Vec<FeatureValue> to Vec<InternedString>
|
||||
summary
|
||||
.features()
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
(
|
||||
*k,
|
||||
v.iter()
|
||||
.map(|fv| InternedString::new(&fv.to_string()))
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
self.manifest()
|
||||
.original()
|
||||
.features()
|
||||
.cloned()
|
||||
.unwrap_or_default()
|
||||
};
|
||||
// Convert Vec<FeatureValue> to Vec<InternedString>
|
||||
let features = summary
|
||||
.features()
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
(
|
||||
*k,
|
||||
v.iter()
|
||||
.map(|fv| InternedString::new(&fv.to_string()))
|
||||
.collect(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
SerializedPackage {
|
||||
name: package_id.name(),
|
||||
|
|
|
@ -1,19 +1,14 @@
|
|||
//! Feature resolver.
|
||||
//!
|
||||
//! This is a new feature resolver that runs independently of the main
|
||||
//! dependency resolver. It is enabled when the user specifies `resolver =
|
||||
//! "2"` in `Cargo.toml`.
|
||||
//! dependency resolver. It has several options which can enable new feature
|
||||
//! resolution behavior.
|
||||
//!
|
||||
//! One of its key characteristics is that it can avoid unifying features for
|
||||
//! shared dependencies in some situations. See `FeatureOpts` for the
|
||||
//! different behaviors that can be enabled. If no extra options are enabled,
|
||||
//! then it should behave exactly the same as the dependency resolver's
|
||||
//! feature resolution. This can be verified by setting the
|
||||
//! `__CARGO_FORCE_NEW_FEATURES=compare` environment variable and running
|
||||
//! Cargo's test suite (or building other projects), and checking if it
|
||||
//! panics. Note: the `features2` tests will fail because they intentionally
|
||||
//! compare the old vs new behavior, so forcing the old behavior will
|
||||
//! naturally fail the tests.
|
||||
//! feature resolution.
|
||||
//!
|
||||
//! The preferred way to engage this new resolver is via
|
||||
//! `resolve_ws_with_opts`.
|
||||
|
@ -59,22 +54,12 @@ pub struct ResolvedFeatures {
|
|||
///
|
||||
/// The value is the `name_in_toml` of the dependencies.
|
||||
activated_dependencies: ActivateMap,
|
||||
/// This is only here for legacy support when the new resolver is not enabled.
|
||||
///
|
||||
/// This is the set of features enabled for each package.
|
||||
legacy_features: Option<HashMap<PackageId, Vec<InternedString>>>,
|
||||
/// This is only here for legacy support when the new resolver is not enabled.
|
||||
///
|
||||
/// This is the set of optional dependencies enabled for each package.
|
||||
legacy_dependencies: Option<HashMap<PackageId, HashSet<InternedString>>>,
|
||||
opts: FeatureOpts,
|
||||
}
|
||||
|
||||
/// Options for how the feature resolver works.
|
||||
#[derive(Default)]
|
||||
pub struct FeatureOpts {
|
||||
/// Use the new resolver instead of the old one.
|
||||
new_resolver: bool,
|
||||
/// Build deps and proc-macros will not share share features with other dep kinds.
|
||||
decouple_host_deps: bool,
|
||||
/// Dev dep features will not be activated unless needed.
|
||||
|
@ -132,7 +117,6 @@ impl FeatureOpts {
|
|||
let mut opts = FeatureOpts::default();
|
||||
let unstable_flags = ws.config().cli_unstable();
|
||||
let mut enable = |feat_opts: &Vec<String>| {
|
||||
opts.new_resolver = true;
|
||||
for opt in feat_opts {
|
||||
match opt.as_ref() {
|
||||
"build_dep" | "host_dep" => opts.decouple_host_deps = true,
|
||||
|
@ -159,15 +143,6 @@ impl FeatureOpts {
|
|||
enable(&vec!["all".to_string()]).unwrap();
|
||||
}
|
||||
}
|
||||
// This env var is intended for testing only.
|
||||
if let Ok(env_opts) = std::env::var("__CARGO_FORCE_NEW_FEATURES") {
|
||||
if env_opts == "1" {
|
||||
opts.new_resolver = true;
|
||||
} else {
|
||||
let env_opts = env_opts.split(',').map(|s| s.to_string()).collect();
|
||||
enable(&env_opts)?;
|
||||
}
|
||||
}
|
||||
if let HasDevUnits::Yes = has_dev_units {
|
||||
// Dev deps cannot be decoupled when they are in use.
|
||||
opts.decouple_dev_deps = false;
|
||||
|
@ -175,10 +150,6 @@ impl FeatureOpts {
|
|||
if let ForceAllTargets::Yes = force_all_targets {
|
||||
opts.ignore_inactive_targets = false;
|
||||
}
|
||||
if unstable_flags.weak_dep_features {
|
||||
// Force this ON because it only works with the new resolver.
|
||||
opts.new_resolver = true;
|
||||
}
|
||||
Ok(opts)
|
||||
}
|
||||
|
||||
|
@ -187,7 +158,6 @@ impl FeatureOpts {
|
|||
match behavior {
|
||||
ResolveBehavior::V1 => FeatureOpts::default(),
|
||||
ResolveBehavior::V2 => FeatureOpts {
|
||||
new_resolver: true,
|
||||
decouple_host_deps: true,
|
||||
decouple_dev_deps: has_dev_units == HasDevUnits::No,
|
||||
ignore_inactive_targets: true,
|
||||
|
@ -306,18 +276,11 @@ impl ResolvedFeatures {
|
|||
features_for: FeaturesFor,
|
||||
dep_name: InternedString,
|
||||
) -> bool {
|
||||
if let Some(legacy) = &self.legacy_dependencies {
|
||||
legacy
|
||||
.get(&pkg_id)
|
||||
.map(|deps| deps.contains(&dep_name))
|
||||
.unwrap_or(false)
|
||||
} else {
|
||||
let is_build = self.opts.decouple_host_deps && features_for == FeaturesFor::HostDep;
|
||||
self.activated_dependencies
|
||||
.get(&(pkg_id, is_build))
|
||||
.map(|deps| deps.contains(&dep_name))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
let is_build = self.opts.decouple_host_deps && features_for == FeaturesFor::HostDep;
|
||||
self.activated_dependencies
|
||||
.get(&(pkg_id, is_build))
|
||||
.map(|deps| deps.contains(&dep_name))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Variant of `activated_features` that returns `None` if this is
|
||||
|
@ -336,15 +299,11 @@ impl ResolvedFeatures {
|
|||
pkg_id: PackageId,
|
||||
features_for: FeaturesFor,
|
||||
) -> CargoResult<Vec<InternedString>> {
|
||||
if let Some(legacy) = &self.legacy_features {
|
||||
Ok(legacy.get(&pkg_id).map_or_else(Vec::new, |v| v.clone()))
|
||||
let is_build = self.opts.decouple_host_deps && features_for == FeaturesFor::HostDep;
|
||||
if let Some(fs) = self.activated_features.get(&(pkg_id, is_build)) {
|
||||
Ok(fs.iter().cloned().collect())
|
||||
} else {
|
||||
let is_build = self.opts.decouple_host_deps && features_for == FeaturesFor::HostDep;
|
||||
if let Some(fs) = self.activated_features.get(&(pkg_id, is_build)) {
|
||||
Ok(fs.iter().cloned().collect())
|
||||
} else {
|
||||
bail!("features did not find {:?} {:?}", pkg_id, is_build)
|
||||
}
|
||||
bail!("features did not find {:?} {:?}", pkg_id, is_build)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -352,14 +311,16 @@ impl ResolvedFeatures {
|
|||
///
|
||||
/// Used by `cargo fix --edition` to display any differences.
|
||||
pub fn compare_legacy(&self, legacy: &ResolvedFeatures) -> DiffMap {
|
||||
let legacy_features = legacy.legacy_features.as_ref().unwrap();
|
||||
self.activated_features
|
||||
.iter()
|
||||
.filter_map(|((pkg_id, for_host), new_features)| {
|
||||
let old_features = match legacy_features.get(pkg_id) {
|
||||
Some(feats) => feats.iter().cloned().collect(),
|
||||
None => BTreeSet::new(),
|
||||
};
|
||||
let old_features = legacy
|
||||
.activated_features
|
||||
.get(&(*pkg_id, *for_host))
|
||||
// The new features may have for_host entries where the old one does not.
|
||||
.or_else(|| legacy.activated_features.get(&(*pkg_id, false)))
|
||||
.map(|feats| feats.iter().cloned().collect())
|
||||
.unwrap_or_else(|| BTreeSet::new());
|
||||
// The new resolver should never add features.
|
||||
assert_eq!(new_features.difference(&old_features).next(), None);
|
||||
let removed_features: BTreeSet<_> =
|
||||
|
@ -427,17 +388,6 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
|||
) -> CargoResult<ResolvedFeatures> {
|
||||
use crate::util::profile;
|
||||
let _p = profile::start("resolve features");
|
||||
|
||||
if !opts.new_resolver {
|
||||
// Legacy mode.
|
||||
return Ok(ResolvedFeatures {
|
||||
activated_features: HashMap::new(),
|
||||
activated_dependencies: HashMap::new(),
|
||||
legacy_features: Some(resolve.features_clone()),
|
||||
legacy_dependencies: Some(compute_legacy_deps(resolve)),
|
||||
opts,
|
||||
});
|
||||
}
|
||||
let track_for_host = opts.decouple_host_deps || opts.ignore_inactive_targets;
|
||||
let mut r = FeatureResolver {
|
||||
ws,
|
||||
|
@ -460,8 +410,6 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
|||
Ok(ResolvedFeatures {
|
||||
activated_features: r.activated_features,
|
||||
activated_dependencies: r.activated_dependencies,
|
||||
legacy_features: None,
|
||||
legacy_dependencies: None,
|
||||
opts: r.opts,
|
||||
})
|
||||
}
|
||||
|
@ -826,19 +774,3 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
|
|||
.proc_macro()
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes a map of PackageId to the set of optional dependencies that are
|
||||
/// enabled for that dep (when the new resolver is not enabled).
|
||||
fn compute_legacy_deps(resolve: &Resolve) -> HashMap<PackageId, HashSet<InternedString>> {
|
||||
let mut result: HashMap<PackageId, HashSet<InternedString>> = HashMap::new();
|
||||
for pkg_id in resolve.iter() {
|
||||
for (_dep_id, deps) in resolve.deps(pkg_id) {
|
||||
for dep in deps {
|
||||
if dep.is_optional() {
|
||||
result.entry(pkg_id).or_default().insert(dep.name_in_toml());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
|
|
@ -23,8 +23,6 @@ struct Inner {
|
|||
package_id: PackageId,
|
||||
dependencies: Vec<Dependency>,
|
||||
features: Rc<FeatureMap>,
|
||||
has_namespaced_features: bool,
|
||||
has_overlapping_features: Option<InternedString>,
|
||||
checksum: Option<String>,
|
||||
links: Option<InternedString>,
|
||||
}
|
||||
|
@ -37,15 +35,11 @@ impl Summary {
|
|||
features: &BTreeMap<InternedString, Vec<InternedString>>,
|
||||
links: Option<impl Into<InternedString>>,
|
||||
) -> CargoResult<Summary> {
|
||||
// ****CAUTION**** If you change anything here than may raise a new
|
||||
// ****CAUTION**** If you change anything here that may raise a new
|
||||
// error, be sure to coordinate that change with either the index
|
||||
// schema field or the SummariesCache version.
|
||||
let mut has_overlapping_features = None;
|
||||
for dep in dependencies.iter() {
|
||||
let dep_name = dep.name_in_toml();
|
||||
if features.contains_key(&dep_name) {
|
||||
has_overlapping_features = Some(dep_name);
|
||||
}
|
||||
if dep.is_optional() && !dep.is_transitive() {
|
||||
bail!(
|
||||
"dev-dependencies are not allowed to be optional: `{}`",
|
||||
|
@ -53,8 +47,7 @@ impl Summary {
|
|||
)
|
||||
}
|
||||
}
|
||||
let (feature_map, has_namespaced_features) =
|
||||
build_feature_map(config, pkg_id, features, &dependencies)?;
|
||||
let feature_map = build_feature_map(config, pkg_id, features, &dependencies)?;
|
||||
Ok(Summary {
|
||||
inner: Rc::new(Inner {
|
||||
package_id: pkg_id,
|
||||
|
@ -62,8 +55,6 @@ impl Summary {
|
|||
features: Rc::new(feature_map),
|
||||
checksum: None,
|
||||
links: links.map(|l| l.into()),
|
||||
has_namespaced_features,
|
||||
has_overlapping_features,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
@ -87,46 +78,6 @@ impl Summary {
|
|||
&self.inner.features
|
||||
}
|
||||
|
||||
/// Returns an error if this Summary is using an unstable feature that is
|
||||
/// not enabled.
|
||||
pub fn unstable_gate(
|
||||
&self,
|
||||
namespaced_features: bool,
|
||||
weak_dep_features: bool,
|
||||
) -> CargoResult<()> {
|
||||
if !namespaced_features {
|
||||
if self.inner.has_namespaced_features {
|
||||
bail!(
|
||||
"namespaced features with the `dep:` prefix are only allowed on \
|
||||
the nightly channel and requires the `-Z namespaced-features` flag on the command-line"
|
||||
);
|
||||
}
|
||||
if let Some(dep_name) = self.inner.has_overlapping_features {
|
||||
bail!(
|
||||
"features and dependencies cannot have the same name: `{}`",
|
||||
dep_name
|
||||
)
|
||||
}
|
||||
}
|
||||
if !weak_dep_features {
|
||||
for (feat_name, features) in self.features() {
|
||||
for fv in features {
|
||||
if matches!(fv, FeatureValue::DepFeature { weak: true, .. }) {
|
||||
bail!(
|
||||
"optional dependency features with `?` syntax are only \
|
||||
allowed on the nightly channel and requires the \
|
||||
`-Z weak-dep-features` flag on the command line\n\
|
||||
Feature `{}` had feature value `{}`.",
|
||||
feat_name,
|
||||
fv
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn checksum(&self) -> Option<&str> {
|
||||
self.inner.checksum.as_deref()
|
||||
}
|
||||
|
@ -181,16 +132,12 @@ impl Hash for Summary {
|
|||
|
||||
/// Checks features for errors, bailing out a CargoResult:Err if invalid,
|
||||
/// and creates FeatureValues for each feature.
|
||||
///
|
||||
/// The returned `bool` indicates whether or not the `[features]` table
|
||||
/// included a `dep:` prefixed namespaced feature (used for gating on
|
||||
/// nightly).
|
||||
fn build_feature_map(
|
||||
config: &Config,
|
||||
pkg_id: PackageId,
|
||||
features: &BTreeMap<InternedString, Vec<InternedString>>,
|
||||
dependencies: &[Dependency],
|
||||
) -> CargoResult<(FeatureMap, bool)> {
|
||||
) -> CargoResult<FeatureMap> {
|
||||
use self::FeatureValue::*;
|
||||
let mut dep_map = HashMap::new();
|
||||
for dep in dependencies.iter() {
|
||||
|
@ -210,7 +157,6 @@ fn build_feature_map(
|
|||
(*feature, fvs)
|
||||
})
|
||||
.collect();
|
||||
let has_namespaced_features = map.values().flatten().any(|fv| fv.has_dep_prefix());
|
||||
|
||||
// Add implicit features for optional dependencies if they weren't
|
||||
// explicitly listed anywhere.
|
||||
|
@ -372,7 +318,7 @@ fn build_feature_map(
|
|||
);
|
||||
}
|
||||
|
||||
Ok((map, has_namespaced_features))
|
||||
Ok(map)
|
||||
}
|
||||
|
||||
/// FeatureValue represents the types of dependencies a feature can have.
|
||||
|
|
|
@ -31,9 +31,8 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo
|
|||
VERSION
|
||||
);
|
||||
}
|
||||
let config = ws.config();
|
||||
let (packages, resolve) = if opt.no_deps {
|
||||
let packages = ws.members().map(|pkg| pkg.serialized(config)).collect();
|
||||
let packages = ws.members().map(|pkg| pkg.serialized()).collect();
|
||||
(packages, None)
|
||||
} else {
|
||||
let (packages, resolve) = build_resolve_graph(ws, opt)?;
|
||||
|
@ -152,11 +151,10 @@ fn build_resolve_graph(
|
|||
);
|
||||
}
|
||||
// Get a Vec of Packages.
|
||||
let config = ws.config();
|
||||
let actual_packages = package_map
|
||||
.into_iter()
|
||||
.filter_map(|(pkg_id, pkg)| node_map.get(&pkg_id).map(|_| pkg))
|
||||
.map(|pkg| pkg.serialized(config))
|
||||
.map(|pkg| pkg.serialized())
|
||||
.collect();
|
||||
|
||||
let mr = MetadataResolve {
|
||||
|
|
|
@ -287,7 +287,6 @@ fn transmit(
|
|||
license_file: license_file.clone(),
|
||||
badges: badges.clone(),
|
||||
links: links.clone(),
|
||||
v: None,
|
||||
},
|
||||
tarball,
|
||||
)
|
||||
|
|
|
@ -293,8 +293,6 @@ impl<'cfg> RegistryIndex<'cfg> {
|
|||
{
|
||||
let source_id = self.source_id;
|
||||
let config = self.config;
|
||||
let namespaced_features = self.config.cli_unstable().namespaced_features;
|
||||
let weak_dep_features = self.config.cli_unstable().weak_dep_features;
|
||||
|
||||
// First up actually parse what summaries we have available. If Cargo
|
||||
// has run previously this will parse a Cargo-specific cache file rather
|
||||
|
@ -309,11 +307,6 @@ impl<'cfg> RegistryIndex<'cfg> {
|
|||
// minimize the amount of work being done here and parse as little as
|
||||
// necessary.
|
||||
let raw_data = &summaries.raw_data;
|
||||
let max_version = if namespaced_features || weak_dep_features {
|
||||
INDEX_V_MAX
|
||||
} else {
|
||||
1
|
||||
};
|
||||
Ok(summaries
|
||||
.versions
|
||||
.iter_mut()
|
||||
|
@ -328,7 +321,7 @@ impl<'cfg> RegistryIndex<'cfg> {
|
|||
},
|
||||
)
|
||||
.filter(move |is| {
|
||||
if is.v > max_version {
|
||||
if is.v > INDEX_V_MAX {
|
||||
debug!(
|
||||
"unsupported schema version {} ({} {})",
|
||||
is.v,
|
||||
|
@ -339,11 +332,6 @@ impl<'cfg> RegistryIndex<'cfg> {
|
|||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.filter(move |is| {
|
||||
is.summary
|
||||
.unstable_gate(namespaced_features, weak_dep_features)
|
||||
.is_ok()
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
|
@ -1309,8 +1309,6 @@ impl TomlManifest {
|
|||
me.features.as_ref().unwrap_or(&empty_features),
|
||||
project.links.as_deref(),
|
||||
)?;
|
||||
let unstable = config.cli_unstable();
|
||||
summary.unstable_gate(unstable.namespaced_features, unstable.weak_dep_features)?;
|
||||
|
||||
let metadata = ManifestMetadata {
|
||||
description: project.description.clone(),
|
||||
|
|
|
@ -116,21 +116,33 @@ an external package to handle GIF images. This can be expressed like this:
|
|||
gif = { version = "0.11.1", optional = true }
|
||||
```
|
||||
|
||||
Optional dependencies implicitly define a feature of the same name as the
|
||||
dependency. This means that the same `cfg(feature = "gif")` syntax can be used
|
||||
in the code, and the dependency can be enabled just like a feature such as
|
||||
`--features gif` (see [Command-line feature
|
||||
options](#command-line-feature-options) below).
|
||||
By default, this optional dependency implicitly defines a feature that looks
|
||||
like this:
|
||||
|
||||
> **Note**: A feature in the `[feature]` table cannot use the same name as a
|
||||
> dependency. Experimental support for enabling this and other extensions is
|
||||
> available on the nightly channel via [namespaced
|
||||
> features](unstable.md#namespaced-features).
|
||||
```toml
|
||||
[features]
|
||||
gif = ["dep:gif"]
|
||||
```
|
||||
|
||||
Explicitly defined features can enable optional dependencies, too. Just
|
||||
include the name of the optional dependency in the feature list. For example,
|
||||
let's say in order to support the AVIF image format, our library needs two
|
||||
other dependencies to be enabled:
|
||||
This means that this dependency will only be included if the `gif`
|
||||
feature is enabled.
|
||||
The same `cfg(feature = "gif")` syntax can be used in the code, and the
|
||||
dependency can be enabled just like any feature such as `--features gif` (see
|
||||
[Command-line feature options](#command-line-feature-options) below).
|
||||
|
||||
In some cases, you may not want to expose a feature that has the same name
|
||||
as the optional dependency.
|
||||
For example, perhaps the optional dependency is an internal detail, or you
|
||||
want to group multiple optional dependencies together, or you just want to use
|
||||
a better name.
|
||||
If you specify the optional dependency with the `dep:` prefix anywhere
|
||||
in the `[features]` table, that disables the implicit feature.
|
||||
|
||||
> **Note**: The `dep:` syntax is only available starting with Rust 1.60.
|
||||
> Previous versions can only use the implicit feature name.
|
||||
|
||||
For example, let's say in order to support the AVIF image format, our library
|
||||
needs two other dependencies to be enabled:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
|
@ -138,10 +150,13 @@ ravif = { version = "0.6.3", optional = true }
|
|||
rgb = { version = "0.8.25", optional = true }
|
||||
|
||||
[features]
|
||||
avif = ["ravif", "rgb"]
|
||||
avif = ["dep:ravif", "dep:rgb"]
|
||||
```
|
||||
|
||||
In this example, the `avif` feature will enable the two listed dependencies.
|
||||
This also avoids creating the implicit `ravif` and `rgb` features, since we
|
||||
don't want users to enable those individually as they are internal details to
|
||||
our crate.
|
||||
|
||||
> **Note**: Another way to optionally include a dependency is to use
|
||||
> [platform-specific dependencies]. Instead of using features, these are
|
||||
|
@ -185,10 +200,31 @@ jpeg-decoder = { version = "0.1.20", default-features = false }
|
|||
parallel = ["jpeg-decoder/rayon"]
|
||||
```
|
||||
|
||||
> **Note**: The `"package-name/feature-name"` syntax will also enable
|
||||
> `package-name` if it is an optional dependency. Experimental support for
|
||||
> disabling that behavior is available on the nightly channel via [weak
|
||||
> dependency features](unstable.md#weak-dependency-features).
|
||||
The `"package-name/feature-name"` syntax will also enable `package-name`
|
||||
if it is an optional dependency. Often this is not what you want.
|
||||
You can add a `?` as in `"package-name?/feature-name"` which will only enable
|
||||
the given feature if something else enables the optional dependency.
|
||||
|
||||
> **Note**: The `?` syntax is only available starting with Rust 1.60.
|
||||
|
||||
For example, let's say we have added some serialization support to our
|
||||
library, and it requires enabling a corresponding feature in some optional
|
||||
dependencies.
|
||||
That can be done like this:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
serde = { version = "1.0.133", optional = true }
|
||||
rgb = { version = "0.8.25", optional = true }
|
||||
|
||||
[features]
|
||||
serde = ["dep:serde", "rgb?/serde"]
|
||||
```
|
||||
|
||||
In this example, enabling the `serde` feature will enable the serde
|
||||
dependency.
|
||||
It will also enable the `serde` feature for the `rgb` dependency, but only if
|
||||
something else has enabled the `rgb` dependency.
|
||||
|
||||
### Command-line feature options
|
||||
|
||||
|
|
|
@ -263,7 +263,45 @@ explaining the format of the entry.
|
|||
"yanked": false,
|
||||
// The `links` string value from the package's manifest, or null if not
|
||||
// specified. This field is optional and defaults to null.
|
||||
"links": null
|
||||
"links": null,
|
||||
// An unsigned 32-bit integer value indicating the schema version of this
|
||||
// entry.
|
||||
//
|
||||
// If this not specified, it should be interpreted as the default of 1.
|
||||
//
|
||||
// Cargo (starting with version 1.51) will ignore versions it does not
|
||||
// recognize. This provides a method to safely introduce changes to index
|
||||
// entries and allow older versions of cargo to ignore newer entries it
|
||||
// doesn't understand. Versions older than 1.51 ignore this field, and
|
||||
// thus may misinterpret the meaning of the index entry.
|
||||
//
|
||||
// The current values are:
|
||||
//
|
||||
// * 1: The schema as documented here, not including newer additions.
|
||||
// This is honored in Rust version 1.51 and newer.
|
||||
// * 2: The addition of the `features2` field.
|
||||
// This is honored in Rust version 1.60 and newer.
|
||||
"v": 2,
|
||||
// This optional field contains features with new, extended syntax.
|
||||
// Specifically, namespaced features (`dep:`) and weak dependencies
|
||||
// (`pkg?/feat`).
|
||||
//
|
||||
// This is separated from `features` because versions older than 1.19
|
||||
// will fail to load due to not being able to parse the new syntax, even
|
||||
// with a `Cargo.lock` file.
|
||||
//
|
||||
// Cargo will merge any values listed here with the "features" field.
|
||||
//
|
||||
// If this field is included, the "v" field should be set to at least 2.
|
||||
//
|
||||
// Registries are not required to use this field for extended feature
|
||||
// syntax, they are allowed to include those in the "features" field.
|
||||
// Using this is only necessary if the registry wants to support cargo
|
||||
// versions older than 1.19, which in practice is only crates.io since
|
||||
// those older versions do not support other registries.
|
||||
"features2": {
|
||||
"serde": ["dep:serde", "chrono?/serde"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -69,8 +69,6 @@ Each new feature described below should explain how to use it.
|
|||
* [avoid-dev-deps](#avoid-dev-deps) — Prevents the resolver from including dev-dependencies during resolution.
|
||||
* [minimal-versions](#minimal-versions) — Forces the resolver to use the lowest compatible version instead of the highest.
|
||||
* [public-dependency](#public-dependency) — Allows dependencies to be classified as either public or private.
|
||||
* [Namespaced features](#namespaced-features) — Separates optional dependencies into a separate namespace from regular features, and allows feature names to be the same as some dependency name.
|
||||
* [Weak dependency features](#weak-dependency-features) — Allows setting features for dependencies without enabling optional dependencies.
|
||||
* Output behavior
|
||||
* [out-dir](#out-dir) — Adds a directory where artifacts are copied to.
|
||||
* [terminal-width](#terminal-width) — Tells rustc the width of the terminal so that long diagnostic messages can be truncated to be more readable.
|
||||
|
@ -253,68 +251,6 @@ dir-name = "lto" # Emits to target/lto instead of target/release-lto
|
|||
lto = true
|
||||
```
|
||||
|
||||
|
||||
### Namespaced features
|
||||
* Original issue: [#1286](https://github.com/rust-lang/cargo/issues/1286)
|
||||
* Tracking Issue: [#5565](https://github.com/rust-lang/cargo/issues/5565)
|
||||
|
||||
The `namespaced-features` option makes two changes to how features can be
|
||||
specified:
|
||||
|
||||
* Features may now be defined with the same name as a dependency.
|
||||
* Optional dependencies can be explicitly enabled in the `[features]` table
|
||||
with the `dep:` prefix, which enables the dependency without enabling a
|
||||
feature of the same name.
|
||||
|
||||
By default, an optional dependency `foo` will define a feature `foo =
|
||||
["dep:foo"]` *unless* `dep:foo` is mentioned in any other feature, or the
|
||||
`foo` feature is already defined. This helps prevent unnecessary boilerplate
|
||||
of listing every optional dependency, but still allows you to override the
|
||||
implicit feature.
|
||||
|
||||
This allows two use cases that were previously not possible:
|
||||
|
||||
* You can "hide" an optional dependency, so that external users cannot
|
||||
explicitly enable that optional dependency.
|
||||
* There is no longer a need to create "funky" feature names to work around the
|
||||
restriction that features cannot shadow dependency names.
|
||||
|
||||
To enable namespaced-features, use the `-Z namespaced-features` command-line
|
||||
flag.
|
||||
|
||||
An example of hiding an optional dependency:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
regex = { version = "1.4.1", optional = true }
|
||||
lazy_static = { version = "1.4.0", optional = true }
|
||||
|
||||
[features]
|
||||
regex = ["dep:regex", "dep:lazy_static"]
|
||||
```
|
||||
|
||||
In this example, the "regex" feature enables both `regex` and `lazy_static`.
|
||||
The `lazy_static` feature does not exist, and a user cannot explicitly enable
|
||||
it. This helps hide internal details of how your package is implemented.
|
||||
|
||||
An example of avoiding "funky" names:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
bigdecimal = "0.1"
|
||||
chrono = "0.4"
|
||||
num-bigint = "0.2"
|
||||
serde = {version = "1.0", optional = true }
|
||||
|
||||
[features]
|
||||
serde = ["dep:serde", "bigdecimal/serde", "chrono/serde", "num-bigint/serde"]
|
||||
```
|
||||
|
||||
In this case, `serde` is a natural name to use for a feature, because it is
|
||||
relevant to your exported API. However, previously you would need to use a
|
||||
name like `serde1` to work around the naming limitation if you wanted to also
|
||||
enable other features.
|
||||
|
||||
### Build-plan
|
||||
* Tracking Issue: [#5579](https://github.com/rust-lang/cargo/issues/5579)
|
||||
|
||||
|
@ -917,29 +853,6 @@ error[E0308]: mismatched types
|
|||
error: aborting due to previous error
|
||||
```
|
||||
|
||||
### Weak dependency features
|
||||
* Tracking Issue: [#8832](https://github.com/rust-lang/cargo/issues/8832)
|
||||
|
||||
The `-Z weak-dep-features` command-line options enables the ability to use
|
||||
`dep_name?/feat_name` syntax in the `[features]` table. The `?` indicates that
|
||||
the optional dependency `dep_name` will not be automatically enabled. The
|
||||
feature `feat_name` will only be added if something else enables the
|
||||
`dep_name` dependency.
|
||||
|
||||
Example:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
serde = { version = "1.0.117", optional = true, default-features = false }
|
||||
|
||||
[features]
|
||||
std = ["serde?/std"]
|
||||
```
|
||||
|
||||
In this example, the `std` feature enables the `std` feature on the `serde`
|
||||
dependency. However, unlike the normal `serde/std` syntax, it will not enable
|
||||
the optional dependency `serde` unless something else has included it.
|
||||
|
||||
### per-package-target
|
||||
* Tracking Issue: [#9406](https://github.com/rust-lang/cargo/pull/9406)
|
||||
* Original Pull Request: [#9030](https://github.com/rust-lang/cargo/pull/9030)
|
||||
|
@ -1394,3 +1307,13 @@ The profile `strip` option has been stabilized in the 1.59 release. See the
|
|||
Support for generating a future-incompat report has been stabilized
|
||||
in the 1.59 release. See the [future incompat report chapter](future-incompat-report.md)
|
||||
for more information.
|
||||
|
||||
### Namespaced features
|
||||
|
||||
Namespaced features has been stabilized in the 1.60 release.
|
||||
See the [Features chapter](features.md#optional-dependencies) for more information.
|
||||
|
||||
### Weak dependency features
|
||||
|
||||
Weak dependency features has been stabilized in the 1.60 release.
|
||||
See the [Features chapter](features.md#dependency-features) for more information.
|
||||
|
|
|
@ -36,7 +36,8 @@ Caused by:
|
|||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn invalid2() {
|
||||
fn same_name() {
|
||||
// Feature with the same name as a dependency.
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
|
@ -59,14 +60,24 @@ fn invalid2() {
|
|||
.file("bar/src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("build")
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
p.cargo("tree -f")
|
||||
.arg("{p} [{f}]")
|
||||
.with_stderr("")
|
||||
.with_stdout(
|
||||
"\
|
||||
[ERROR] failed to parse manifest at `[..]`
|
||||
foo v0.0.1 ([..]) []
|
||||
└── bar v1.0.0 ([..]) []
|
||||
",
|
||||
)
|
||||
.run();
|
||||
|
||||
Caused by:
|
||||
features and dependencies cannot have the same name: `bar`
|
||||
p.cargo("tree --features bar -f")
|
||||
.arg("{p} [{f}]")
|
||||
.with_stderr("")
|
||||
.with_stdout(
|
||||
"\
|
||||
foo v0.0.1 ([..]) [bar,baz]
|
||||
└── bar v1.0.0 ([..]) []
|
||||
",
|
||||
)
|
||||
.run();
|
||||
|
|
|
@ -4,99 +4,6 @@ use super::features2::switch_to_resolver_2;
|
|||
use cargo_test_support::registry::{Dependency, Package};
|
||||
use cargo_test_support::{project, publish};
|
||||
|
||||
#[cargo_test]
|
||||
fn gated() {
|
||||
// Need namespaced-features to use `dep:` syntax.
|
||||
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]
|
||||
foo = ["dep:bar"]
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check")
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
[ERROR] failed to parse manifest at `[..]/foo/Cargo.toml`
|
||||
|
||||
Caused by:
|
||||
namespaced features with the `dep:` prefix are only allowed on the nightly channel \
|
||||
and requires the `-Z namespaced-features` flag on the command-line
|
||||
",
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn dependency_gate_ignored() {
|
||||
// Dependencies with `dep:` features are ignored in the registry if not on nightly.
|
||||
Package::new("baz", "1.0.0").publish();
|
||||
Package::new("bar", "1.0.0")
|
||||
.add_dep(Dependency::new("baz", "1.0").optional(true))
|
||||
.feature("feat", &["dep:baz"])
|
||||
.publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bar = "1.0"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
[ERROR] no matching package named `bar` found
|
||||
location searched: registry `crates-io`
|
||||
required by package `foo v0.1.0 ([..]/foo)`
|
||||
",
|
||||
)
|
||||
.run();
|
||||
|
||||
// Publish a version without namespaced features, it should ignore 1.0.0
|
||||
// and use this instead.
|
||||
Package::new("bar", "1.0.1")
|
||||
.add_dep(Dependency::new("baz", "1.0").optional(true))
|
||||
.feature("feat", &["baz"])
|
||||
.publish();
|
||||
p.cargo("check")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
[DOWNLOADING] crates ...
|
||||
[DOWNLOADED] bar [..]
|
||||
[CHECKING] bar v1.0.1
|
||||
[CHECKING] foo v0.1.0 [..]
|
||||
[FINISHED] [..]
|
||||
",
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn dependency_with_crate_syntax() {
|
||||
// Registry dependency uses dep: syntax.
|
||||
|
@ -120,8 +27,7 @@ fn dependency_with_crate_syntax() {
|
|||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check")
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
|
@ -156,8 +62,7 @@ fn namespaced_invalid_feature() {
|
|||
.file("src/main.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("build -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("build")
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
|
@ -188,8 +93,7 @@ fn namespaced_invalid_dependency() {
|
|||
.file("src/main.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("build -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("build")
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
|
@ -223,8 +127,8 @@ fn namespaced_non_optional_dependency() {
|
|||
.file("src/main.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("build -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("build")
|
||||
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
|
@ -261,8 +165,7 @@ fn namespaced_implicit_feature() {
|
|||
.file("src/main.rs", "fn main() {}")
|
||||
.build();
|
||||
|
||||
p.cargo("check -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check")
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
|
@ -271,8 +174,7 @@ fn namespaced_implicit_feature() {
|
|||
",
|
||||
)
|
||||
.run();
|
||||
p.cargo("check -Z namespaced-features --features baz")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check --features baz")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DOWNLOADING] crates ...
|
||||
|
@ -307,8 +209,7 @@ fn namespaced_shadowed_dep() {
|
|||
.file("src/main.rs", "fn main() {}")
|
||||
.build();
|
||||
|
||||
p.cargo("build -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("build")
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
|
@ -344,9 +245,7 @@ fn namespaced_shadowed_non_optional() {
|
|||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.run();
|
||||
p.cargo("check").run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
|
@ -370,7 +269,7 @@ fn namespaced_implicit_non_optional() {
|
|||
.file("src/main.rs", "fn main() {}")
|
||||
.build();
|
||||
|
||||
p.cargo("build -Z namespaced-features").masquerade_as_nightly_cargo().with_status(101).with_stderr(
|
||||
p.cargo("build").with_status(101).with_stderr(
|
||||
"\
|
||||
[ERROR] failed to parse manifest at `[..]`
|
||||
|
||||
|
@ -411,8 +310,7 @@ fn namespaced_same_name() {
|
|||
)
|
||||
.build();
|
||||
|
||||
p.cargo("run -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("run")
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
|
@ -424,8 +322,7 @@ fn namespaced_same_name() {
|
|||
.with_stdout("")
|
||||
.run();
|
||||
|
||||
p.cargo("run -Z namespaced-features --features baz")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("run --features baz")
|
||||
.with_stderr(
|
||||
"\
|
||||
[DOWNLOADING] crates ...
|
||||
|
@ -473,8 +370,7 @@ fn no_implicit_feature() {
|
|||
)
|
||||
.build();
|
||||
|
||||
p.cargo("run -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("run")
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
|
@ -486,8 +382,7 @@ fn no_implicit_feature() {
|
|||
.with_stdout("")
|
||||
.run();
|
||||
|
||||
p.cargo("run -Z namespaced-features --features regex")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("run --features regex")
|
||||
.with_stderr_unordered(
|
||||
"\
|
||||
[DOWNLOADING] crates ...
|
||||
|
@ -503,8 +398,7 @@ fn no_implicit_feature() {
|
|||
.with_stdout("regex")
|
||||
.run();
|
||||
|
||||
p.cargo("run -Z namespaced-features --features lazy_static")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("run --features lazy_static")
|
||||
.with_stderr(
|
||||
"\
|
||||
[ERROR] Package `foo v0.1.0 [..]` does not have feature `lazy_static`. \
|
||||
|
@ -538,8 +432,7 @@ fn crate_syntax_bad_name() {
|
|||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check -Z namespaced-features --features dep:bar")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check --features dep:bar")
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
|
@ -574,8 +467,7 @@ fn crate_syntax_in_dep() {
|
|||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check")
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
|
@ -608,8 +500,7 @@ fn crate_syntax_cli() {
|
|||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check -Z namespaced-features --features dep:bar")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check --features dep:bar")
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
|
@ -619,8 +510,7 @@ fn crate_syntax_cli() {
|
|||
.run();
|
||||
|
||||
switch_to_resolver_2(&p);
|
||||
p.cargo("check -Z namespaced-features --features dep:bar")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check --features dep:bar")
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
|
@ -653,8 +543,7 @@ fn crate_required_features() {
|
|||
.file("src/main.rs", "fn main() {}")
|
||||
.build();
|
||||
|
||||
p.cargo("check -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check")
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
|
@ -685,8 +574,7 @@ fn json_exposed() {
|
|||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("metadata -Z namespaced-features --no-deps")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("metadata --no-deps")
|
||||
.with_json(
|
||||
r#"
|
||||
{
|
||||
|
@ -775,8 +663,7 @@ fn crate_feature_with_explicit() {
|
|||
)
|
||||
.build();
|
||||
|
||||
p.cargo("check -Z namespaced-features --features f1")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check --features f1")
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
|
@ -814,8 +701,7 @@ fn optional_explicit_without_crate() {
|
|||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("build -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("build")
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
|
@ -856,13 +742,11 @@ fn tree() {
|
|||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("tree -e features -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree -e features")
|
||||
.with_stdout("foo v0.1.0 ([ROOT]/foo)")
|
||||
.run();
|
||||
|
||||
p.cargo("tree -e features --features a -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree -e features --features a")
|
||||
.with_stdout(
|
||||
"\
|
||||
foo v0.1.0 ([ROOT]/foo)
|
||||
|
@ -876,8 +760,7 @@ foo v0.1.0 ([ROOT]/foo)
|
|||
)
|
||||
.run();
|
||||
|
||||
p.cargo("tree -e features --features a -i bar -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree -e features --features a -i bar")
|
||||
.with_stdout(
|
||||
"\
|
||||
bar v1.0.0
|
||||
|
@ -895,8 +778,7 @@ bar v1.0.0
|
|||
)
|
||||
.run();
|
||||
|
||||
p.cargo("tree -e features --features bar -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree -e features --features bar")
|
||||
.with_stdout(
|
||||
"\
|
||||
foo v0.1.0 ([ROOT]/foo)
|
||||
|
@ -910,8 +792,7 @@ foo v0.1.0 ([ROOT]/foo)
|
|||
)
|
||||
.run();
|
||||
|
||||
p.cargo("tree -e features --features bar -i bar -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree -e features --features bar -i bar")
|
||||
.with_stdout(
|
||||
"\
|
||||
bar v1.0.0
|
||||
|
@ -948,13 +829,11 @@ fn tree_no_implicit() {
|
|||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("tree -e features -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree -e features")
|
||||
.with_stdout("foo v0.1.0 ([ROOT]/foo)")
|
||||
.run();
|
||||
|
||||
p.cargo("tree -e features --all-features -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree -e features --all-features")
|
||||
.with_stdout(
|
||||
"\
|
||||
foo v0.1.0 ([ROOT]/foo)
|
||||
|
@ -964,8 +843,7 @@ foo v0.1.0 ([ROOT]/foo)
|
|||
)
|
||||
.run();
|
||||
|
||||
p.cargo("tree -e features -i bar --all-features -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree -e features -i bar --all-features")
|
||||
.with_stdout(
|
||||
"\
|
||||
bar v1.0.0
|
||||
|
@ -1116,8 +994,7 @@ fn publish() {
|
|||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("publish --token sekrit -Z namespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("publish --token sekrit")
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
|
|
|
@ -558,8 +558,7 @@ fn index_cache_rebuild() {
|
|||
fs::remove_file(p.root().join("Cargo.lock")).unwrap();
|
||||
|
||||
// This should rebuild the cache and use 1.0.1.
|
||||
p.cargo("check -Znamespaced-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check")
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
|
|
|
@ -20,100 +20,6 @@ fn require(enabled_features: &[&str], disabled_features: &[&str]) -> String {
|
|||
s
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn gated() {
|
||||
// Need -Z weak-dep-features to enable.
|
||||
Package::new("bar", "1.0.0").feature("feat", &[]).publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bar = { version = "1.0", optional = true }
|
||||
|
||||
[features]
|
||||
f1 = ["bar?/feat"]
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
p.cargo("check")
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
|
||||
|
||||
Caused by:
|
||||
optional dependency features with `?` syntax are only allowed on the nightly \
|
||||
channel and requires the `-Z weak-dep-features` flag on the command line
|
||||
Feature `f1` had feature value `bar?/feat`.
|
||||
",
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn dependency_gate_ignored() {
|
||||
// Dependencies with ? features in the registry are ignored in the
|
||||
// registry if not on nightly.
|
||||
Package::new("baz", "1.0.0").feature("feat", &[]).publish();
|
||||
Package::new("bar", "1.0.0")
|
||||
.add_dep(Dependency::new("baz", "1.0").optional(true))
|
||||
.feature("feat", &["baz?/feat"])
|
||||
.publish();
|
||||
let p = project()
|
||||
.file(
|
||||
"Cargo.toml",
|
||||
r#"
|
||||
[package]
|
||||
name = "foo"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
bar = "1.0"
|
||||
"#,
|
||||
)
|
||||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
[ERROR] no matching package named `bar` found
|
||||
location searched: registry `crates-io`
|
||||
required by package `foo v0.1.0 ([..]/foo)`
|
||||
",
|
||||
)
|
||||
.run();
|
||||
|
||||
// Publish a version without the ? feature, it should ignore 1.0.0
|
||||
// and use this instead.
|
||||
Package::new("bar", "1.0.1")
|
||||
.add_dep(Dependency::new("baz", "1.0").optional(true))
|
||||
.feature("feat", &["baz"])
|
||||
.publish();
|
||||
p.cargo("check")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
[DOWNLOADING] crates ...
|
||||
[DOWNLOADED] bar [..]
|
||||
[CHECKING] bar v1.0.1
|
||||
[CHECKING] foo v0.1.0 [..]
|
||||
[FINISHED] [..]
|
||||
",
|
||||
)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[cargo_test]
|
||||
fn simple() {
|
||||
Package::new("bar", "1.0.0")
|
||||
|
@ -140,8 +46,7 @@ fn simple() {
|
|||
|
||||
// It's a bit unfortunate that this has to download `bar`, but avoiding
|
||||
// that is extremely difficult.
|
||||
p.cargo("check -Z weak-dep-features --features f1")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check --features f1")
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
|
@ -153,8 +58,7 @@ fn simple() {
|
|||
)
|
||||
.run();
|
||||
|
||||
p.cargo("check -Z weak-dep-features --features f1,bar")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check --features f1,bar")
|
||||
.with_stderr(
|
||||
"\
|
||||
[CHECKING] bar v1.0.0
|
||||
|
@ -196,8 +100,7 @@ fn deferred() {
|
|||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check -Z weak-dep-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check")
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
|
@ -238,8 +141,7 @@ fn not_optional_dep() {
|
|||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("check -Z weak-dep-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check")
|
||||
.with_status(101)
|
||||
.with_stderr("\
|
||||
error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
|
||||
|
@ -275,8 +177,7 @@ fn optional_cli_syntax() {
|
|||
.build();
|
||||
|
||||
// Does not build bar.
|
||||
p.cargo("check --features bar?/feat -Z weak-dep-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check --features bar?/feat")
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
|
@ -289,8 +190,7 @@ fn optional_cli_syntax() {
|
|||
.run();
|
||||
|
||||
// Builds bar.
|
||||
p.cargo("check --features bar?/feat,bar -Z weak-dep-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check --features bar?/feat,bar")
|
||||
.with_stderr(
|
||||
"\
|
||||
[CHECKING] bar v1.0.0
|
||||
|
@ -304,8 +204,7 @@ fn optional_cli_syntax() {
|
|||
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()
|
||||
p.cargo("check --features bar?/feat")
|
||||
.with_stderr(
|
||||
"\
|
||||
[CHECKING] foo v0.1.0 [..]
|
||||
|
@ -315,8 +214,7 @@ fn optional_cli_syntax() {
|
|||
.run();
|
||||
|
||||
// Builds bar.
|
||||
p.cargo("check --features bar?/feat,bar -Z weak-dep-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check --features bar?/feat,bar")
|
||||
.with_stderr(
|
||||
"\
|
||||
[CHECKING] bar v1.0.0
|
||||
|
@ -351,8 +249,7 @@ fn required_features() {
|
|||
.file("src/main.rs", "fn main() {}")
|
||||
.build();
|
||||
|
||||
p.cargo("check -Z weak-dep-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check")
|
||||
.with_status(101)
|
||||
.with_stderr(
|
||||
"\
|
||||
|
@ -366,7 +263,7 @@ optional dependency with `?` is not allowed in required-features
|
|||
|
||||
#[cargo_test]
|
||||
fn weak_with_host_decouple() {
|
||||
// -Z weak-opt-features with new resolver
|
||||
// weak-dep-features with new resolver
|
||||
//
|
||||
// foo v0.1.0
|
||||
// └── common v1.0.0
|
||||
|
@ -447,8 +344,7 @@ fn weak_with_host_decouple() {
|
|||
)
|
||||
.build();
|
||||
|
||||
p.cargo("run -Z weak-dep-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("run")
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
|
@ -493,8 +389,7 @@ fn weak_namespaced() {
|
|||
.file("src/lib.rs", &require(&["f1"], &["f2", "bar"]))
|
||||
.build();
|
||||
|
||||
p.cargo("check -Z weak-dep-features -Z namespaced-features --features f1")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check --features f1")
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
|
@ -506,21 +401,18 @@ fn weak_namespaced() {
|
|||
)
|
||||
.run();
|
||||
|
||||
p.cargo("tree -Z weak-dep-features -Z namespaced-features -f")
|
||||
p.cargo("tree -f")
|
||||
.arg("{p} feats:{f}")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stdout("foo v0.1.0 ([ROOT]/foo) feats:")
|
||||
.run();
|
||||
|
||||
p.cargo("tree -Z weak-dep-features -Z namespaced-features --features f1 -f")
|
||||
p.cargo("tree --features f1 -f")
|
||||
.arg("{p} feats:{f}")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stdout("foo v0.1.0 ([ROOT]/foo) feats:f1")
|
||||
.run();
|
||||
|
||||
p.cargo("tree -Z weak-dep-features -Z namespaced-features --features f1,f2 -f")
|
||||
p.cargo("tree --features f1,f2 -f")
|
||||
.arg("{p} feats:{f}")
|
||||
.masquerade_as_nightly_cargo()
|
||||
.with_stdout(
|
||||
"\
|
||||
foo v0.1.0 ([ROOT]/foo) feats:f1,f2
|
||||
|
@ -532,8 +424,7 @@ foo v0.1.0 ([ROOT]/foo) feats:f1,f2
|
|||
// "bar" remains not-a-feature
|
||||
p.change_file("src/lib.rs", &require(&["f1", "f2"], &["bar"]));
|
||||
|
||||
p.cargo("check -Z weak-dep-features -Z namespaced-features --features f1,f2")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("check --features f1,f2")
|
||||
.with_stderr(
|
||||
"\
|
||||
[CHECKING] bar v1.0.0
|
||||
|
@ -568,13 +459,11 @@ fn tree() {
|
|||
.file("src/lib.rs", &require(&["f1"], &[]))
|
||||
.build();
|
||||
|
||||
p.cargo("tree -Z weak-dep-features --features f1")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree --features f1")
|
||||
.with_stdout("foo v0.1.0 ([ROOT]/foo)")
|
||||
.run();
|
||||
|
||||
p.cargo("tree -Z weak-dep-features --features f1,bar")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree --features f1,bar")
|
||||
.with_stdout(
|
||||
"\
|
||||
foo v0.1.0 ([ROOT]/foo)
|
||||
|
@ -583,8 +472,7 @@ foo v0.1.0 ([ROOT]/foo)
|
|||
)
|
||||
.run();
|
||||
|
||||
p.cargo("tree -Z weak-dep-features --features f1,bar -e features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree --features f1,bar -e features")
|
||||
.with_stdout(
|
||||
"\
|
||||
foo v0.1.0 ([ROOT]/foo)
|
||||
|
@ -594,8 +482,7 @@ foo v0.1.0 ([ROOT]/foo)
|
|||
)
|
||||
.run();
|
||||
|
||||
p.cargo("tree -Z weak-dep-features --features f1,bar -e features -i bar")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree --features f1,bar -e features -i bar")
|
||||
.with_stdout(
|
||||
"\
|
||||
bar v1.0.0
|
||||
|
@ -610,20 +497,17 @@ bar v1.0.0
|
|||
)
|
||||
.run();
|
||||
|
||||
p.cargo("tree -Z weak-dep-features -e features --features bar?/feat")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree -e features --features bar?/feat")
|
||||
.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()
|
||||
p.cargo("tree -e features -i bar --features bar?/feat")
|
||||
.with_stdout("")
|
||||
.run();
|
||||
|
||||
p.cargo("tree -Z weak-dep-features -e features -i bar --features bar?/feat,bar")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("tree -e features -i bar --features bar?/feat,bar")
|
||||
.with_stdout(
|
||||
"\
|
||||
bar v1.0.0
|
||||
|
@ -663,8 +547,7 @@ fn publish() {
|
|||
.file("src/lib.rs", "")
|
||||
.build();
|
||||
|
||||
p.cargo("publish --token sekrit -Z weak-dep-features")
|
||||
.masquerade_as_nightly_cargo()
|
||||
p.cargo("publish --token sekrit")
|
||||
.with_stderr(
|
||||
"\
|
||||
[UPDATING] [..]
|
||||
|
|
Loading…
Reference in a new issue