summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-03-03 22:07:46 +0000
committerbors <bors@rust-lang.org>2024-03-03 22:07:46 +0000
commit9e6288efe0bbccc53d95080070524e4640769339 (patch)
tree91eeae13743c4c8f102041a13ca58e8024c1ba8f
parent352d2f36430ce202a93e12f7bc5c77ef3e1747d2 (diff)
parent55d3d65434192b124876d161224a42872b65e10b (diff)
Auto merge of #13516 - epage:msrv-add, r=ehussHEADmasterauto-cargo
feat(add): Fallback to `rustc -v` when no MSRV is set ### What does this PR try to resolve? #10653 made version-requirement selection respect MSRV as part of #9930. This updates the implementation for the now-approved RFC specifies that we should respect `rustc -v` if there is no MSRV. The messages also get a little bit of polish. ### How should we test and review this PR? Tests are added in separate commits for easier viewing of behavior changes. ### Additional information
-rw-r--r--src/cargo/ops/cargo_add/mod.rs142
-rw-r--r--tests/testsuite/cargo_add/mod.rs4
-rw-r--r--tests/testsuite/cargo_add/rust_version_incompatible/stderr.term.svg10
-rw-r--r--tests/testsuite/cargo_add/rust_version_older/stderr.term.svg4
-rw-r--r--tests/testsuite/cargo_add/rustc_ignore/in/Cargo.toml6
-rw-r--r--tests/testsuite/cargo_add/rustc_ignore/in/src/lib.rs0
-rw-r--r--tests/testsuite/cargo_add/rustc_ignore/mod.rs38
-rw-r--r--tests/testsuite/cargo_add/rustc_ignore/out/Cargo.toml9
-rw-r--r--tests/testsuite/cargo_add/rustc_ignore/out/src/lib.rs0
-rw-r--r--tests/testsuite/cargo_add/rustc_ignore/stderr.term.svg29
-rw-r--r--tests/testsuite/cargo_add/rustc_incompatible/in/Cargo.toml6
-rw-r--r--tests/testsuite/cargo_add/rustc_incompatible/in/src/lib.rs0
-rw-r--r--tests/testsuite/cargo_add/rustc_incompatible/mod.rs31
-rw-r--r--tests/testsuite/cargo_add/rustc_incompatible/out/Cargo.toml6
-rw-r--r--tests/testsuite/cargo_add/rustc_incompatible/out/src/lib.rs0
-rw-r--r--tests/testsuite/cargo_add/rustc_incompatible/stderr.term.svg32
-rw-r--r--tests/testsuite/cargo_add/rustc_latest/in/Cargo.toml6
-rw-r--r--tests/testsuite/cargo_add/rustc_latest/in/src/lib.rs0
-rw-r--r--tests/testsuite/cargo_add/rustc_latest/mod.rs37
-rw-r--r--tests/testsuite/cargo_add/rustc_latest/out/Cargo.toml9
-rw-r--r--tests/testsuite/cargo_add/rustc_latest/out/src/lib.rs0
-rw-r--r--tests/testsuite/cargo_add/rustc_latest/stderr.term.svg32
-rw-r--r--tests/testsuite/cargo_add/rustc_older/in/Cargo.toml6
-rw-r--r--tests/testsuite/cargo_add/rustc_older/in/src/lib.rs0
-rw-r--r--tests/testsuite/cargo_add/rustc_older/mod.rs37
-rw-r--r--tests/testsuite/cargo_add/rustc_older/out/Cargo.toml9
-rw-r--r--tests/testsuite/cargo_add/rustc_older/out/src/lib.rs0
-rw-r--r--tests/testsuite/cargo_add/rustc_older/stderr.term.svg32
28 files changed, 413 insertions, 72 deletions
diff --git a/src/cargo/ops/cargo_add/mod.rs b/src/cargo/ops/cargo_add/mod.rs
index b36e4e729..eeebddaf8 100644
--- a/src/cargo/ops/cargo_add/mod.rs
+++ b/src/cargo/ops/cargo_add/mod.rs
@@ -11,6 +11,7 @@ use std::str::FromStr;
use anyhow::Context as _;
use cargo_util::paths;
+use cargo_util_schemas::core::PartialVersion;
use cargo_util_schemas::manifest::RustVersion;
use indexmap::IndexSet;
use itertools::Itertools;
@@ -615,52 +616,74 @@ fn get_latest_dependency(
})?;
if gctx.cli_unstable().msrv_policy && honor_rust_version {
- fn parse_msrv(comp: &RustVersion) -> (u64, u64, u64) {
- (comp.major, comp.minor.unwrap_or(0), comp.patch.unwrap_or(0))
- }
+ let (req_msrv, is_msrv) = spec
+ .rust_version()
+ .cloned()
+ .map(|msrv| CargoResult::Ok((msrv.clone(), true)))
+ .unwrap_or_else(|| {
+ let rustc = gctx.load_global_rustc(None)?;
+
+ // Remove any pre-release identifiers for easier comparison
+ let current_version = &rustc.version;
+ let untagged_version = RustVersion::try_from(PartialVersion {
+ major: current_version.major,
+ minor: Some(current_version.minor),
+ patch: Some(current_version.patch),
+ pre: None,
+ build: None,
+ })
+ .unwrap();
+ Ok((untagged_version, false))
+ })?;
- if let Some(req_msrv) = spec.rust_version().map(parse_msrv) {
- let msrvs = possibilities
- .iter()
- .map(|s| (s, s.rust_version().map(parse_msrv)))
- .collect::<Vec<_>>();
-
- // Find the latest version of the dep which has a compatible rust-version. To
- // determine whether or not one rust-version is compatible with another, we
- // compare the lowest possible versions they could represent, and treat
- // candidates without a rust-version as compatible by default.
- let (latest_msrv, _) = msrvs
- .iter()
- .filter(|(_, v)| v.map(|msrv| req_msrv >= msrv).unwrap_or(true))
- .last()
- .ok_or_else(|| {
- // Failing that, try to find the highest version with the lowest
- // rust-version to report to the user.
- let lowest_candidate = msrvs
- .iter()
- .min_set_by_key(|(_, v)| v)
- .iter()
- .map(|(s, _)| s)
- .max_by_key(|s| s.version());
- rust_version_incompat_error(
- &dependency.name,
- spec.rust_version().unwrap(),
- lowest_candidate.copied(),
+ let msrvs = possibilities
+ .iter()
+ .map(|s| (s, s.rust_version()))
+ .collect::<Vec<_>>();
+
+ // Find the latest version of the dep which has a compatible rust-version. To
+ // determine whether or not one rust-version is compatible with another, we
+ // compare the lowest possible versions they could represent, and treat
+ // candidates without a rust-version as compatible by default.
+ let latest_msrv = latest_compatible(&msrvs, &req_msrv).ok_or_else(|| {
+ let name = spec.name();
+ let dep_name = &dependency.name;
+ let latest_version = latest.version();
+ let latest_msrv = latest
+ .rust_version()
+ .expect("as `None` are compatible, we can't be here");
+ if is_msrv {
+ anyhow::format_err!(
+ "\
+no version of crate `{dep_name}` can maintain {name}'s rust-version of {req_msrv}
+help: pass `--ignore-rust-version` to select {dep_name}@{latest_version} which requires rustc {latest_msrv}"
)
- })?;
-
- if latest_msrv.version() < latest.version() {
+ } else {
+ anyhow::format_err!(
+ "\
+no version of crate `{dep_name}` is compatible with rustc {req_msrv}
+help: pass `--ignore-rust-version` to select {dep_name}@{latest_version} which requires rustc {latest_msrv}"
+ )
+ }
+ })?;
+
+ if latest_msrv.version() < latest.version() {
+ let latest_version = latest.version();
+ let latest_rust_version = latest.rust_version().unwrap();
+ let name = spec.name();
+ if is_msrv {
gctx.shell().warn(format_args!(
- "ignoring `{dependency}@{latest_version}` (which has a rust-version of \
- {latest_rust_version}) to satisfy this package's rust-version of \
- {rust_version} (use `--ignore-rust-version` to override)",
- latest_version = latest.version(),
- latest_rust_version = latest.rust_version().unwrap(),
- rust_version = spec.rust_version().unwrap(),
+ "\
+ignoring {dependency}@{latest_version} (which requires rustc {latest_rust_version}) to maintain {name}'s rust-version of {req_msrv}",
+ ))?;
+ } else {
+ gctx.shell().warn(format_args!(
+ "\
+ignoring {dependency}@{latest_version} (which requires rustc {latest_rust_version}) as it is incompatible with rustc {req_msrv}",
))?;
-
- latest = latest_msrv;
}
+
+ latest = latest_msrv;
}
}
@@ -673,29 +696,20 @@ fn get_latest_dependency(
}
}
-fn rust_version_incompat_error(
- dep: &str,
- rust_version: &RustVersion,
- lowest_rust_version: Option<&Summary>,
-) -> anyhow::Error {
- let mut error_msg = format!(
- "could not find version of crate `{dep}` that satisfies this package's rust-version of \
- {rust_version}\n\
- help: use `--ignore-rust-version` to override this behavior"
- );
-
- if let Some(lowest) = lowest_rust_version {
- // rust-version must be present for this candidate since it would have been selected as
- // compatible previously if it weren't.
- let version = lowest.version();
- let rust_version = lowest.rust_version().unwrap();
- error_msg.push_str(&format!(
- "\nnote: the lowest rust-version available for `{dep}` is {rust_version}, used in \
- version {version}"
- ));
- }
-
- anyhow::format_err!(error_msg)
+/// Of MSRV-compatible summaries, find the highest version
+///
+/// Assumptions:
+/// - `msrvs` is sorted by version
+fn latest_compatible<'s>(
+ msrvs: &[(&'s Summary, Option<&RustVersion>)],
+ req_msrv: &RustVersion,
+) -> Option<&'s Summary> {
+ msrvs
+ .iter()
+ .filter(|(_, v)| v.as_ref().map(|msrv| req_msrv >= *msrv).unwrap_or(true))
+ .map(|(s, _)| s)
+ .last()
+ .copied()
}
fn select_package(
diff --git a/tests/testsuite/cargo_add/mod.rs b/tests/testsuite/cargo_add/mod.rs
index bf52f6e7f..8800ac23c 100644
--- a/tests/testsuite/cargo_add/mod.rs
+++ b/tests/testsuite/cargo_add/mod.rs
@@ -123,6 +123,10 @@ mod rust_version_ignore;
mod rust_version_incompatible;
mod rust_version_latest;
mod rust_version_older;
+mod rustc_ignore;
+mod rustc_incompatible;
+mod rustc_latest;
+mod rustc_older;
mod sorted_table_with_dotted_item;
mod target;
mod target_cfg;
diff --git a/tests/testsuite/cargo_add/rust_version_incompatible/stderr.term.svg b/tests/testsuite/cargo_add/rust_version_incompatible/stderr.term.svg
index 916d611ad..8983eae2f 100644
--- a/tests/testsuite/cargo_add/rust_version_incompatible/stderr.term.svg
+++ b/tests/testsuite/cargo_add/rust_version_incompatible/stderr.term.svg
@@ -1,4 +1,4 @@
-<svg width="936px" height="110px" xmlns="http://www.w3.org/2000/svg">
+<svg width="911px" height="92px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
@@ -21,13 +21,11 @@
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-green bold"> Updating</tspan><tspan> `dummy-registry` index</tspan>
</tspan>
- <tspan x="10px" y="46px"><tspan class="fg-red bold">error</tspan><tspan class="bold">:</tspan><tspan> could not find version of crate `rust-version-user` that satisfies this package's rust-version of 1.56</tspan>
+ <tspan x="10px" y="46px"><tspan class="fg-red bold">error</tspan><tspan class="bold">:</tspan><tspan> no version of crate `rust-version-user` can maintain cargo-list-test-fixture's rust-version of 1.56</tspan>
</tspan>
- <tspan x="10px" y="64px"><tspan>help: use `--ignore-rust-version` to override this behavior</tspan>
+ <tspan x="10px" y="64px"><tspan>help: pass `--ignore-rust-version` to select rust-version-user@0.2.1 which requires rustc 1.72</tspan>
</tspan>
- <tspan x="10px" y="82px"><tspan>note: the lowest rust-version available for `rust-version-user` is 1.66, used in version 0.1.1</tspan>
-</tspan>
- <tspan x="10px" y="100px">
+ <tspan x="10px" y="82px">
</tspan>
</text>
diff --git a/tests/testsuite/cargo_add/rust_version_older/stderr.term.svg b/tests/testsuite/cargo_add/rust_version_older/stderr.term.svg
index 904b2013f..bccac4116 100644
--- a/tests/testsuite/cargo_add/rust_version_older/stderr.term.svg
+++ b/tests/testsuite/cargo_add/rust_version_older/stderr.term.svg
@@ -1,4 +1,4 @@
-<svg width="1423px" height="92px" xmlns="http://www.w3.org/2000/svg">
+<svg width="1096px" height="92px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
@@ -21,7 +21,7 @@
<text xml:space="preserve" class="container fg">
<tspan x="10px" y="28px"><tspan class="fg-green bold"> Updating</tspan><tspan> `dummy-registry` index</tspan>
</tspan>
- <tspan x="10px" y="46px"><tspan class="fg-yellow bold">warning</tspan><tspan class="bold">:</tspan><tspan> ignoring `rust-version-user@0.2.1` (which has a rust-version of 1.72) to satisfy this package's rust-version of 1.70 (use `--ignore-rust-version` to override)</tspan>
+ <tspan x="10px" y="46px"><tspan class="fg-yellow bold">warning</tspan><tspan class="bold">:</tspan><tspan> ignoring rust-version-user@0.2.1 (which requires rustc 1.72) to maintain cargo-list-test-fixture's rust-version of 1.70</tspan>
</tspan>
<tspan x="10px" y="64px"><tspan class="fg-green bold"> Adding</tspan><tspan> rust-version-user v0.1.0 to dependencies</tspan>
</tspan>
diff --git a/tests/testsuite/cargo_add/rustc_ignore/in/Cargo.toml b/tests/testsuite/cargo_add/rustc_ignore/in/Cargo.toml
new file mode 100644
index 000000000..946b7c86b
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_ignore/in/Cargo.toml
@@ -0,0 +1,6 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+edition = "2015"
diff --git a/tests/testsuite/cargo_add/rustc_ignore/in/src/lib.rs b/tests/testsuite/cargo_add/rustc_ignore/in/src/lib.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_ignore/in/src/lib.rs
diff --git a/tests/testsuite/cargo_add/rustc_ignore/mod.rs b/tests/testsuite/cargo_add/rustc_ignore/mod.rs
new file mode 100644
index 000000000..9d17037dd
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_ignore/mod.rs
@@ -0,0 +1,38 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::current_dir;
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+use cargo_test_support::str;
+use cargo_test_support::Project;
+
+#[cargo_test]
+fn case() {
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("rust-version-user", "0.1.0")
+ .rust_version("1.30")
+ .publish();
+ cargo_test_support::registry::Package::new("rust-version-user", "0.1.1")
+ .rust_version("1.30")
+ .publish();
+ cargo_test_support::registry::Package::new("rust-version-user", "0.2.1")
+ .rust_version("1.2345")
+ .publish();
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("-Zmsrv-policy")
+ .arg("add")
+ .arg("--ignore-rust-version")
+ .arg_line("rust-version-user")
+ .current_dir(cwd)
+ .masquerade_as_nightly_cargo(&["msrv-policy"])
+ .assert()
+ .code(0)
+ .stdout_matches(str![""])
+ .stderr_matches(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_add/rustc_ignore/out/Cargo.toml b/tests/testsuite/cargo_add/rustc_ignore/out/Cargo.toml
new file mode 100644
index 000000000..d9d31d176
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_ignore/out/Cargo.toml
@@ -0,0 +1,9 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+edition = "2015"
+
+[dependencies]
+rust-version-user = "0.2.1"
diff --git a/tests/testsuite/cargo_add/rustc_ignore/out/src/lib.rs b/tests/testsuite/cargo_add/rustc_ignore/out/src/lib.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_ignore/out/src/lib.rs
diff --git a/tests/testsuite/cargo_add/rustc_ignore/stderr.term.svg b/tests/testsuite/cargo_add/rustc_ignore/stderr.term.svg
new file mode 100644
index 000000000..b9eb4bded
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_ignore/stderr.term.svg
@@ -0,0 +1,29 @@
+<svg width="740px" height="74px" xmlns="http://www.w3.org/2000/svg">
+ <style>
+ .fg { fill: #AAAAAA }
+ .bg { background: #000000 }
+ .fg-green { fill: #00AA00 }
+ .container {
+ padding: 0 10px;
+ line-height: 18px;
+ }
+ .bold { font-weight: bold; }
+ tspan {
+ font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
+ white-space: pre;
+ line-height: 18px;
+ }
+ </style>
+
+ <rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
+
+ <text xml:space="preserve" class="container fg">
+ <tspan x="10px" y="28px"><tspan class="fg-green bold"> Updating</tspan><tspan> `dummy-registry` index</tspan>
+</tspan>
+ <tspan x="10px" y="46px"><tspan class="fg-green bold"> Adding</tspan><tspan> rust-version-user v0.2.1 to dependencies</tspan>
+</tspan>
+ <tspan x="10px" y="64px">
+</tspan>
+ </text>
+
+</svg>
diff --git a/tests/testsuite/cargo_add/rustc_incompatible/in/Cargo.toml b/tests/testsuite/cargo_add/rustc_incompatible/in/Cargo.toml
new file mode 100644
index 000000000..946b7c86b
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_incompatible/in/Cargo.toml
@@ -0,0 +1,6 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+edition = "2015"
diff --git a/tests/testsuite/cargo_add/rustc_incompatible/in/src/lib.rs b/tests/testsuite/cargo_add/rustc_incompatible/in/src/lib.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_incompatible/in/src/lib.rs
diff --git a/tests/testsuite/cargo_add/rustc_incompatible/mod.rs b/tests/testsuite/cargo_add/rustc_incompatible/mod.rs
new file mode 100644
index 000000000..3e38359c2
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_incompatible/mod.rs
@@ -0,0 +1,31 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::current_dir;
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+use cargo_test_support::str;
+use cargo_test_support::Project;
+
+#[cargo_test]
+fn case() {
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("rust-version-user", "0.2.1")
+ .rust_version("1.2345")
+ .publish();
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("-Zmsrv-policy")
+ .arg("add")
+ .arg_line("rust-version-user")
+ .current_dir(cwd)
+ .masquerade_as_nightly_cargo(&["msrv-policy"])
+ .assert()
+ .failure()
+ .stdout_matches(str![""])
+ .stderr_matches(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_add/rustc_incompatible/out/Cargo.toml b/tests/testsuite/cargo_add/rustc_incompatible/out/Cargo.toml
new file mode 100644
index 000000000..946b7c86b
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_incompatible/out/Cargo.toml
@@ -0,0 +1,6 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+edition = "2015"
diff --git a/tests/testsuite/cargo_add/rustc_incompatible/out/src/lib.rs b/tests/testsuite/cargo_add/rustc_incompatible/out/src/lib.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_incompatible/out/src/lib.rs
diff --git a/tests/testsuite/cargo_add/rustc_incompatible/stderr.term.svg b/tests/testsuite/cargo_add/rustc_incompatible/stderr.term.svg
new file mode 100644
index 000000000..ecf03af2d
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_incompatible/stderr.term.svg
@@ -0,0 +1,32 @@
+<svg width="827px" height="92px" xmlns="http://www.w3.org/2000/svg">
+ <style>
+ .fg { fill: #AAAAAA }
+ .bg { background: #000000 }
+ .fg-green { fill: #00AA00 }
+ .fg-red { fill: #AA0000 }
+ .container {
+ padding: 0 10px;
+ line-height: 18px;
+ }
+ .bold { font-weight: bold; }
+ tspan {
+ font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
+ white-space: pre;
+ line-height: 18px;
+ }
+ </style>
+
+ <rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
+
+ <text xml:space="preserve" class="container fg">
+ <tspan x="10px" y="28px"><tspan class="fg-green bold"> Updating</tspan><tspan> `dummy-registry` index</tspan>
+</tspan>
+ <tspan x="10px" y="46px"><tspan class="fg-red bold">error</tspan><tspan class="bold">:</tspan><tspan> no version of crate `rust-version-user` is compatible with rustc [..]</tspan>
+</tspan>
+ <tspan x="10px" y="64px"><tspan>help: pass `--ignore-rust-version` to select rust-version-user@0.2.1 which requires rustc 1.2345</tspan>
+</tspan>
+ <tspan x="10px" y="82px">
+</tspan>
+ </text>
+
+</svg>
diff --git a/tests/testsuite/cargo_add/rustc_latest/in/Cargo.toml b/tests/testsuite/cargo_add/rustc_latest/in/Cargo.toml
new file mode 100644
index 000000000..946b7c86b
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_latest/in/Cargo.toml
@@ -0,0 +1,6 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+edition = "2015"
diff --git a/tests/testsuite/cargo_add/rustc_latest/in/src/lib.rs b/tests/testsuite/cargo_add/rustc_latest/in/src/lib.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_latest/in/src/lib.rs
diff --git a/tests/testsuite/cargo_add/rustc_latest/mod.rs b/tests/testsuite/cargo_add/rustc_latest/mod.rs
new file mode 100644
index 000000000..e16841e3a
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_latest/mod.rs
@@ -0,0 +1,37 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::current_dir;
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+use cargo_test_support::str;
+use cargo_test_support::Project;
+
+#[cargo_test]
+fn case() {
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("rust-version-user", "0.1.0")
+ .rust_version("1.30")
+ .publish();
+ cargo_test_support::registry::Package::new("rust-version-user", "0.1.1")
+ .rust_version("1.30")
+ .publish();
+ cargo_test_support::registry::Package::new("rust-version-user", "0.2.1")
+ .rust_version("1.2345")
+ .publish();
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("-Zmsrv-policy")
+ .arg("add")
+ .arg_line("rust-version-user")
+ .current_dir(cwd)
+ .masquerade_as_nightly_cargo(&["msrv-policy"])
+ .assert()
+ .success()
+ .stdout_matches(str![""])
+ .stderr_matches(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_add/rustc_latest/out/Cargo.toml b/tests/testsuite/cargo_add/rustc_latest/out/Cargo.toml
new file mode 100644
index 000000000..392f7f49c
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_latest/out/Cargo.toml
@@ -0,0 +1,9 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+edition = "2015"
+
+[dependencies]
+rust-version-user = "0.1.1"
diff --git a/tests/testsuite/cargo_add/rustc_latest/out/src/lib.rs b/tests/testsuite/cargo_add/rustc_latest/out/src/lib.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_latest/out/src/lib.rs
diff --git a/tests/testsuite/cargo_add/rustc_latest/stderr.term.svg b/tests/testsuite/cargo_add/rustc_latest/stderr.term.svg
new file mode 100644
index 000000000..001f5ad2e
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_latest/stderr.term.svg
@@ -0,0 +1,32 @@
+<svg width="953px" height="92px" xmlns="http://www.w3.org/2000/svg">
+ <style>
+ .fg { fill: #AAAAAA }
+ .bg { background: #000000 }
+ .fg-green { fill: #00AA00 }
+ .fg-yellow { fill: #AA5500 }
+ .container {
+ padding: 0 10px;
+ line-height: 18px;
+ }
+ .bold { font-weight: bold; }
+ tspan {
+ font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
+ white-space: pre;
+ line-height: 18px;
+ }
+ </style>
+
+ <rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
+
+ <text xml:space="preserve" class="container fg">
+ <tspan x="10px" y="28px"><tspan class="fg-green bold"> Updating</tspan><tspan> `dummy-registry` index</tspan>
+</tspan>
+ <tspan x="10px" y="46px"><tspan class="fg-yellow bold">warning</tspan><tspan class="bold">:</tspan><tspan> ignoring rust-version-user@0.2.1 (which requires rustc 1.2345) as it is incompatible with rustc [..]</tspan>
+</tspan>
+ <tspan x="10px" y="64px"><tspan class="fg-green bold"> Adding</tspan><tspan> rust-version-user v0.1.1 to dependencies</tspan>
+</tspan>
+ <tspan x="10px" y="82px">
+</tspan>
+ </text>
+
+</svg>
diff --git a/tests/testsuite/cargo_add/rustc_older/in/Cargo.toml b/tests/testsuite/cargo_add/rustc_older/in/Cargo.toml
new file mode 100644
index 000000000..946b7c86b
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_older/in/Cargo.toml
@@ -0,0 +1,6 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+edition = "2015"
diff --git a/tests/testsuite/cargo_add/rustc_older/in/src/lib.rs b/tests/testsuite/cargo_add/rustc_older/in/src/lib.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_older/in/src/lib.rs
diff --git a/tests/testsuite/cargo_add/rustc_older/mod.rs b/tests/testsuite/cargo_add/rustc_older/mod.rs
new file mode 100644
index 000000000..e16841e3a
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_older/mod.rs
@@ -0,0 +1,37 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::current_dir;
+use cargo_test_support::file;
+use cargo_test_support::prelude::*;
+use cargo_test_support::str;
+use cargo_test_support::Project;
+
+#[cargo_test]
+fn case() {
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("rust-version-user", "0.1.0")
+ .rust_version("1.30")
+ .publish();
+ cargo_test_support::registry::Package::new("rust-version-user", "0.1.1")
+ .rust_version("1.30")
+ .publish();
+ cargo_test_support::registry::Package::new("rust-version-user", "0.2.1")
+ .rust_version("1.2345")
+ .publish();
+
+ let project = Project::from_template(current_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("-Zmsrv-policy")
+ .arg("add")
+ .arg_line("rust-version-user")
+ .current_dir(cwd)
+ .masquerade_as_nightly_cargo(&["msrv-policy"])
+ .assert()
+ .success()
+ .stdout_matches(str![""])
+ .stderr_matches(file!["stderr.term.svg"]);
+
+ assert_ui().subset_matches(current_dir!().join("out"), &project_root);
+}
diff --git a/tests/testsuite/cargo_add/rustc_older/out/Cargo.toml b/tests/testsuite/cargo_add/rustc_older/out/Cargo.toml
new file mode 100644
index 000000000..392f7f49c
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_older/out/Cargo.toml
@@ -0,0 +1,9 @@
+[workspace]
+
+[package]
+name = "cargo-list-test-fixture"
+version = "0.0.0"
+edition = "2015"
+
+[dependencies]
+rust-version-user = "0.1.1"
diff --git a/tests/testsuite/cargo_add/rustc_older/out/src/lib.rs b/tests/testsuite/cargo_add/rustc_older/out/src/lib.rs
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_older/out/src/lib.rs
diff --git a/tests/testsuite/cargo_add/rustc_older/stderr.term.svg b/tests/testsuite/cargo_add/rustc_older/stderr.term.svg
new file mode 100644
index 000000000..001f5ad2e
--- /dev/null
+++ b/tests/testsuite/cargo_add/rustc_older/stderr.term.svg
@@ -0,0 +1,32 @@
+<svg width="953px" height="92px" xmlns="http://www.w3.org/2000/svg">
+ <style>
+ .fg { fill: #AAAAAA }
+ .bg { background: #000000 }
+ .fg-green { fill: #00AA00 }
+ .fg-yellow { fill: #AA5500 }
+ .container {
+ padding: 0 10px;
+ line-height: 18px;
+ }
+ .bold { font-weight: bold; }
+ tspan {
+ font: 14px SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
+ white-space: pre;
+ line-height: 18px;
+ }
+ </style>
+
+ <rect width="100%" height="100%" y="0" rx="4.5" class="bg" />
+
+ <text xml:space="preserve" class="container fg">
+ <tspan x="10px" y="28px"><tspan class="fg-green bold"> Updating</tspan><tspan> `dummy-registry` index</tspan>
+</tspan>
+ <tspan x="10px" y="46px"><tspan class="fg-yellow bold">warning</tspan><tspan class="bold">:</tspan><tspan> ignoring rust-version-user@0.2.1 (which requires rustc 1.2345) as it is incompatible with rustc [..]</tspan>
+</tspan>
+ <tspan x="10px" y="64px"><tspan class="fg-green bold"> Adding</tspan><tspan> rust-version-user v0.1.1 to dependencies</tspan>
+</tspan>
+ <tspan x="10px" y="82px">
+</tspan>
+ </text>
+
+</svg>