mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
Auto merge of #13776 - epage:msrv-resolver, r=weihanglo
feat(resolver): Add v3 resolver for MSRV-aware resolving ### What does this PR try to resolve? This is a part of #9930 and is important for changing the default with the new edition. ### How should we test and review this PR? ### Additional information
This commit is contained in:
commit
14b46ecc62
@ -196,7 +196,7 @@ impl FeatureOpts {
|
|||||||
}
|
}
|
||||||
match ws.resolve_behavior() {
|
match ws.resolve_behavior() {
|
||||||
ResolveBehavior::V1 => {}
|
ResolveBehavior::V1 => {}
|
||||||
ResolveBehavior::V2 => {
|
ResolveBehavior::V2 | ResolveBehavior::V3 => {
|
||||||
enable(&vec!["all".to_string()]).unwrap();
|
enable(&vec!["all".to_string()]).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -214,7 +214,7 @@ impl FeatureOpts {
|
|||||||
pub fn new_behavior(behavior: ResolveBehavior, has_dev_units: HasDevUnits) -> FeatureOpts {
|
pub fn new_behavior(behavior: ResolveBehavior, has_dev_units: HasDevUnits) -> FeatureOpts {
|
||||||
match behavior {
|
match behavior {
|
||||||
ResolveBehavior::V1 => FeatureOpts::default(),
|
ResolveBehavior::V1 => FeatureOpts::default(),
|
||||||
ResolveBehavior::V2 => FeatureOpts {
|
ResolveBehavior::V2 | ResolveBehavior::V3 => FeatureOpts {
|
||||||
decouple_host_deps: true,
|
decouple_host_deps: true,
|
||||||
decouple_dev_deps: has_dev_units == HasDevUnits::No,
|
decouple_dev_deps: has_dev_units == HasDevUnits::No,
|
||||||
ignore_inactive_targets: true,
|
ignore_inactive_targets: true,
|
||||||
|
@ -111,6 +111,8 @@ pub enum ResolveBehavior {
|
|||||||
V1,
|
V1,
|
||||||
/// V2 adds the new feature resolver.
|
/// V2 adds the new feature resolver.
|
||||||
V2,
|
V2,
|
||||||
|
/// V3 changes version preferences
|
||||||
|
V3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResolveBehavior {
|
impl ResolveBehavior {
|
||||||
@ -118,6 +120,7 @@ impl ResolveBehavior {
|
|||||||
match resolver {
|
match resolver {
|
||||||
"1" => Ok(ResolveBehavior::V1),
|
"1" => Ok(ResolveBehavior::V1),
|
||||||
"2" => Ok(ResolveBehavior::V2),
|
"2" => Ok(ResolveBehavior::V2),
|
||||||
|
"3" => Ok(ResolveBehavior::V3),
|
||||||
s => anyhow::bail!(
|
s => anyhow::bail!(
|
||||||
"`resolver` setting `{}` is not valid, valid options are \"1\" or \"2\"",
|
"`resolver` setting `{}` is not valid, valid options are \"1\" or \"2\"",
|
||||||
s
|
s
|
||||||
@ -129,6 +132,7 @@ impl ResolveBehavior {
|
|||||||
match self {
|
match self {
|
||||||
ResolveBehavior::V1 => "1",
|
ResolveBehavior::V1 => "1",
|
||||||
ResolveBehavior::V2 => "2",
|
ResolveBehavior::V2 => "2",
|
||||||
|
ResolveBehavior::V3 => "3",
|
||||||
}
|
}
|
||||||
.to_owned()
|
.to_owned()
|
||||||
}
|
}
|
||||||
|
@ -306,6 +306,17 @@ impl<'gctx> Workspace<'gctx> {
|
|||||||
MaybePackage::Virtual(vm) => vm.resolve_behavior().unwrap_or(ResolveBehavior::V1),
|
MaybePackage::Virtual(vm) => vm.resolve_behavior().unwrap_or(ResolveBehavior::V1),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
match self.resolve_behavior() {
|
||||||
|
ResolveBehavior::V1 | ResolveBehavior::V2 => {}
|
||||||
|
ResolveBehavior::V3 => {
|
||||||
|
if self.resolve_behavior == ResolveBehavior::V3 {
|
||||||
|
if !self.gctx().cli_unstable().msrv_policy {
|
||||||
|
anyhow::bail!("`resolver=\"3\"` requires `-Zmsrv-policy`");
|
||||||
|
}
|
||||||
|
self.resolve_honors_rust_version = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
match self.gctx().get::<CargoResolverConfig>("resolver") {
|
match self.gctx().get::<CargoResolverConfig>("resolver") {
|
||||||
Ok(CargoResolverConfig {
|
Ok(CargoResolverConfig {
|
||||||
something_like_precedence: Some(precedence),
|
something_like_precedence: Some(precedence),
|
||||||
@ -869,7 +880,7 @@ impl<'gctx> Workspace<'gctx> {
|
|||||||
self.is_virtual()
|
self.is_virtual()
|
||||||
|| match self.resolve_behavior() {
|
|| match self.resolve_behavior() {
|
||||||
ResolveBehavior::V1 => false,
|
ResolveBehavior::V1 => false,
|
||||||
ResolveBehavior::V2 => true,
|
ResolveBehavior::V2 | ResolveBehavior::V3 => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,6 +266,12 @@ fn resolve_toml(
|
|||||||
warnings: &mut Vec<String>,
|
warnings: &mut Vec<String>,
|
||||||
_errors: &mut Vec<String>,
|
_errors: &mut Vec<String>,
|
||||||
) -> CargoResult<manifest::TomlManifest> {
|
) -> CargoResult<manifest::TomlManifest> {
|
||||||
|
if let Some(workspace) = &original_toml.workspace {
|
||||||
|
if workspace.resolver.as_deref() == Some("3") {
|
||||||
|
features.require(Feature::edition2024())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut resolved_toml = manifest::TomlManifest {
|
let mut resolved_toml = manifest::TomlManifest {
|
||||||
cargo_features: original_toml.cargo_features.clone(),
|
cargo_features: original_toml.cargo_features.clone(),
|
||||||
package: None,
|
package: None,
|
||||||
@ -300,7 +306,8 @@ fn resolve_toml(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(original_package) = original_toml.package() {
|
if let Some(original_package) = original_toml.package() {
|
||||||
let resolved_package = resolve_package_toml(original_package, package_root, &inherit)?;
|
let resolved_package =
|
||||||
|
resolve_package_toml(original_package, features, package_root, &inherit)?;
|
||||||
let edition = resolved_package
|
let edition = resolved_package
|
||||||
.resolved_edition()
|
.resolved_edition()
|
||||||
.expect("previously resolved")
|
.expect("previously resolved")
|
||||||
@ -432,6 +439,7 @@ fn resolve_toml(
|
|||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
fn resolve_package_toml<'a>(
|
fn resolve_package_toml<'a>(
|
||||||
original_package: &manifest::TomlPackage,
|
original_package: &manifest::TomlPackage,
|
||||||
|
features: &Features,
|
||||||
package_root: &Path,
|
package_root: &Path,
|
||||||
inherit: &dyn Fn() -> CargoResult<&'a InheritableFields>,
|
inherit: &dyn Fn() -> CargoResult<&'a InheritableFields>,
|
||||||
) -> CargoResult<Box<manifest::TomlPackage>> {
|
) -> CargoResult<Box<manifest::TomlPackage>> {
|
||||||
@ -559,6 +567,11 @@ fn resolve_package_toml<'a>(
|
|||||||
metadata: original_package.metadata.clone(),
|
metadata: original_package.metadata.clone(),
|
||||||
_invalid_cargo_features: Default::default(),
|
_invalid_cargo_features: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if resolved_package.resolver.as_deref() == Some("3") {
|
||||||
|
features.require(Feature::edition2024())?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Box::new(resolved_package))
|
Ok(Box::new(resolved_package))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,6 +338,7 @@ This was stabilized in 1.79 in [#13608](https://github.com/rust-lang/cargo/pull/
|
|||||||
|
|
||||||
`-Zmsrv-policy` allows access to an MSRV-aware resolver which can be enabled with:
|
`-Zmsrv-policy` allows access to an MSRV-aware resolver which can be enabled with:
|
||||||
- `resolver.something-like-precedence` config field
|
- `resolver.something-like-precedence` config field
|
||||||
|
- `workspace.resolver = "3"` / `package.resolver = "3"`
|
||||||
|
|
||||||
The resolver will prefer dependencies with a `package.rust-version` that is the same or older than your project's MSRV.
|
The resolver will prefer dependencies with a `package.rust-version` that is the same or older than your project's MSRV.
|
||||||
Your project's MSRV is determined by taking the lowest `package.rust-version` set among your workspace members.
|
Your project's MSRV is determined by taking the lowest `package.rust-version` set among your workspace members.
|
||||||
|
@ -613,6 +613,133 @@ foo v0.0.1 ([CWD])
|
|||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cargo_test(nightly, reason = "edition2024 in rustc is unstable")]
|
||||||
|
fn resolve_v3() {
|
||||||
|
Package::new("only-newer", "1.6.0")
|
||||||
|
.rust_version("1.65.0")
|
||||||
|
.file("src/lib.rs", "fn other_stuff() {}")
|
||||||
|
.publish();
|
||||||
|
Package::new("newer-and-older", "1.5.0")
|
||||||
|
.rust_version("1.55.0")
|
||||||
|
.file("src/lib.rs", "fn other_stuff() {}")
|
||||||
|
.publish();
|
||||||
|
Package::new("newer-and-older", "1.6.0")
|
||||||
|
.rust_version("1.65.0")
|
||||||
|
.file("src/lib.rs", "fn other_stuff() {}")
|
||||||
|
.publish();
|
||||||
|
|
||||||
|
let p = project()
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
cargo-features = ["edition2024"]
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.0.1"
|
||||||
|
edition = "2015"
|
||||||
|
authors = []
|
||||||
|
rust-version = "1.60.0"
|
||||||
|
resolver = "3"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
only-newer = "1.0.0"
|
||||||
|
newer-and-older = "1.0.0"
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/main.rs", "fn main(){}")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// v3 should resolve for MSRV
|
||||||
|
p.cargo("generate-lockfile")
|
||||||
|
.arg("-Zmsrv-policy")
|
||||||
|
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[UPDATING] `dummy-registry` index
|
||||||
|
[LOCKING] 3 packages to latest Rust 1.60.0 compatible versions
|
||||||
|
[ADDING] newer-and-older v1.5.0 (latest: v1.6.0)
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
p.cargo("tree")
|
||||||
|
.arg("-Zmsrv-policy")
|
||||||
|
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
|
||||||
|
.with_stdout(
|
||||||
|
"\
|
||||||
|
foo v0.0.1 ([CWD])
|
||||||
|
├── newer-and-older v1.5.0
|
||||||
|
└── only-newer v1.6.0
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
// `--ignore-rust-version` has precedence over v3
|
||||||
|
p.cargo("generate-lockfile --ignore-rust-version")
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[UPDATING] `dummy-registry` index
|
||||||
|
[LOCKING] 3 packages to latest compatible versions
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.arg("-Zmsrv-policy")
|
||||||
|
.masquerade_as_nightly_cargo(&["msrv-policy"])
|
||||||
|
.run();
|
||||||
|
p.cargo("tree")
|
||||||
|
.arg("-Zmsrv-policy")
|
||||||
|
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
|
||||||
|
.with_stdout(
|
||||||
|
"\
|
||||||
|
foo v0.0.1 ([CWD])
|
||||||
|
├── newer-and-older v1.6.0
|
||||||
|
└── only-newer v1.6.0
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
// config has precedence over v3
|
||||||
|
p.cargo("generate-lockfile")
|
||||||
|
.env(
|
||||||
|
"CARGO_RESOLVER_SOMETHING_LIKE_PRECEDENCE",
|
||||||
|
"something-like-maximum",
|
||||||
|
)
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[UPDATING] `dummy-registry` index
|
||||||
|
[LOCKING] 3 packages to latest compatible versions
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.arg("-Zmsrv-policy")
|
||||||
|
.masquerade_as_nightly_cargo(&["msrv-policy"])
|
||||||
|
.run();
|
||||||
|
p.cargo("tree")
|
||||||
|
.arg("-Zmsrv-policy")
|
||||||
|
.masquerade_as_nightly_cargo(&["edition2024", "msrv-policy"])
|
||||||
|
.with_stdout(
|
||||||
|
"\
|
||||||
|
foo v0.0.1 ([CWD])
|
||||||
|
├── newer-and-older v1.6.0
|
||||||
|
└── only-newer v1.6.0
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
// unstable
|
||||||
|
p.cargo("generate-lockfile")
|
||||||
|
.with_status(101)
|
||||||
|
.with_stderr(
|
||||||
|
"\
|
||||||
|
[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
|
||||||
|
|
||||||
|
Caused by:
|
||||||
|
the cargo feature `edition2024` requires a nightly version of Cargo, but this is the `stable` channel
|
||||||
|
See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information about Rust release channels.
|
||||||
|
See https://doc.rust-lang.org/cargo/reference/unstable.html#edition-2024 for more information about using this feature.
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
#[cargo_test]
|
#[cargo_test]
|
||||||
fn generate_lockfile_ignore_rust_version_is_unstable() {
|
fn generate_lockfile_ignore_rust_version_is_unstable() {
|
||||||
Package::new("bar", "1.5.0")
|
Package::new("bar", "1.5.0")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user