Skip to content

Commit 2976e2a

Browse files
committed
fix(install): Don't suggest --locked for MSRV when its root package
This will also report the error without having to download the `.crate` first. If installing multiple packages, this will also report it immediately, rather than waiting for the other packages to be installed first. This also offers us more flexibility in the error we report, like suggesting more appropriate fixes.
1 parent 699b30a commit 2976e2a

File tree

4 files changed

+57
-16
lines changed

4 files changed

+57
-16
lines changed

src/cargo/ops/cargo_install.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ impl<'cfg> InstallablePackage<'cfg> {
6868
force: bool,
6969
no_track: bool,
7070
needs_update_if_source_is_index: bool,
71+
current_rust_version: Option<&semver::Version>,
7172
) -> CargoResult<Option<Self>> {
7273
if let Some(name) = krate {
7374
if name == "." {
@@ -105,6 +106,7 @@ impl<'cfg> InstallablePackage<'cfg> {
105106
dep,
106107
|git: &mut GitSource<'_>| git.read_packages(),
107108
config,
109+
current_rust_version,
108110
)?
109111
} else if source_id.is_path() {
110112
let mut src = path_source(source_id, config)?;
@@ -142,6 +144,7 @@ impl<'cfg> InstallablePackage<'cfg> {
142144
dep,
143145
|path: &mut PathSource<'_>| path.read_packages(),
144146
config,
147+
current_rust_version,
145148
)?
146149
} else if let Some(dep) = dep {
147150
let mut source = map.load(source_id, &HashSet::new())?;
@@ -161,7 +164,13 @@ impl<'cfg> InstallablePackage<'cfg> {
161164
config.shell().status("Ignored", &msg)?;
162165
return Ok(None);
163166
}
164-
select_dep_pkg(&mut source, dep, config, needs_update_if_source_is_index)?
167+
select_dep_pkg(
168+
&mut source,
169+
dep,
170+
config,
171+
needs_update_if_source_is_index,
172+
current_rust_version,
173+
)?
165174
} else {
166175
bail!(
167176
"must specify a crate to install from \
@@ -616,14 +625,40 @@ pub fn install(
616625
let dst = root.join("bin").into_path_unlocked();
617626
let map = SourceConfigMap::new(config)?;
618627

628+
let current_rust_version = if opts.honor_rust_version {
629+
let rustc = config.load_global_rustc(None)?;
630+
631+
// Remove any pre-release identifiers for easier comparison
632+
let current_version = &rustc.version;
633+
let untagged_version = semver::Version::new(
634+
current_version.major,
635+
current_version.minor,
636+
current_version.patch,
637+
);
638+
Some(untagged_version)
639+
} else {
640+
None
641+
};
642+
619643
let (installed_anything, scheduled_error) = if krates.len() <= 1 {
620644
let (krate, vers) = krates
621645
.iter()
622646
.next()
623647
.map(|(k, v)| (Some(k.as_str()), v.as_ref()))
624648
.unwrap_or((None, None));
625649
let installable_pkg = InstallablePackage::new(
626-
config, root, map, krate, source_id, from_cwd, vers, opts, force, no_track, true,
650+
config,
651+
root,
652+
map,
653+
krate,
654+
source_id,
655+
from_cwd,
656+
vers,
657+
opts,
658+
force,
659+
no_track,
660+
true,
661+
current_rust_version.as_ref(),
627662
)?;
628663
let mut installed_anything = true;
629664
if let Some(installable_pkg) = installable_pkg {
@@ -654,6 +689,7 @@ pub fn install(
654689
force,
655690
no_track,
656691
!did_update,
692+
current_rust_version.as_ref(),
657693
) {
658694
Ok(Some(installable_pkg)) => {
659695
did_update = true;
@@ -773,7 +809,7 @@ where
773809
// expensive network call in the case that the package is already installed.
774810
// If this fails, the caller will possibly do an index update and try again, this is just a
775811
// best-effort check to see if we can avoid hitting the network.
776-
if let Ok(pkg) = select_dep_pkg(source, dep, config, false) {
812+
if let Ok(pkg) = select_dep_pkg(source, dep, config, false, None) {
777813
let (_ws, rustc, target) =
778814
make_ws_rustc_target(config, opts, &source.source_id(), pkg.clone())?;
779815
if let Ok(true) = is_installed(&pkg, config, opts, &rustc, &target, root, dst, force) {

src/cargo/ops/cargo_uninstall.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ fn uninstall_cwd(root: &Filesystem, bins: &[String], config: &Config) -> CargoRe
9090
None,
9191
|path: &mut PathSource<'_>| path.read_packages(),
9292
config,
93+
None,
9394
)?;
9495
let pkgid = pkg.package_id();
9596
uninstall_pkgid(root, tracker, pkgid, bins, config)

src/cargo/ops/common_for_install_and_uninstall.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,7 @@ pub fn select_dep_pkg<T>(
532532
dep: Dependency,
533533
config: &Config,
534534
needs_update: bool,
535+
current_rust_version: Option<&semver::Version>,
535536
) -> CargoResult<Package>
536537
where
537538
T: Source,
@@ -551,9 +552,19 @@ where
551552
Poll::Pending => source.block_until_ready()?,
552553
}
553554
};
554-
match deps.iter().map(|p| p.package_id()).max() {
555-
Some(pkgid) => {
556-
let pkg = Box::new(source).download_now(pkgid, config)?;
555+
match deps.iter().max_by_key(|p| p.package_id()) {
556+
Some(summary) => {
557+
if let (Some(current), Some(msrv)) = (current_rust_version, summary.rust_version()) {
558+
let msrv_req = msrv.caret_req();
559+
if !msrv_req.matches(current) {
560+
let name = summary.name();
561+
let ver = summary.version();
562+
bail!("\
563+
cannot install package `{name} {ver}`, it requires rustc {msrv} or newer, while the currently active rustc version is {current}"
564+
)
565+
}
566+
}
567+
let pkg = Box::new(source).download_now(summary.package_id(), config)?;
557568
Ok(pkg)
558569
}
559570
None => {
@@ -599,6 +610,7 @@ pub fn select_pkg<T, F>(
599610
dep: Option<Dependency>,
600611
mut list_all: F,
601612
config: &Config,
613+
current_rust_version: Option<&semver::Version>,
602614
) -> CargoResult<Package>
603615
where
604616
T: Source,
@@ -612,7 +624,7 @@ where
612624
source.invalidate_cache();
613625

614626
return if let Some(dep) = dep {
615-
select_dep_pkg(source, dep, config, false)
627+
select_dep_pkg(source, dep, config, false, current_rust_version)
616628
} else {
617629
let candidates = list_all(source)?;
618630
let binaries = candidates

tests/testsuite/install.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,15 +2478,7 @@ fn install_incompat_msrv() {
24782478
cargo_process("install foo")
24792479
.with_stderr("\
24802480
[UPDATING] `dummy-registry` index
2481-
[DOWNLOADING] crates ...
2482-
[DOWNLOADED] foo v0.2.0 (registry `[..]`)
2483-
[INSTALLING] foo v0.2.0
2484-
[ERROR] failed to compile `foo v0.2.0`, intermediate artifacts can be found at `[..]`.
2485-
To reuse those artifacts with a future compilation, set the environment variable `CARGO_TARGET_DIR` to that path.
2486-
2487-
Caused by:
2488-
package `foo v0.2.0` cannot be built because it requires rustc 1.9876.0 or newer, while the currently active rustc version is [..]
2489-
Try re-running cargo install with `--locked`
2481+
[ERROR] cannot install package `foo 0.2.0`, it requires rustc 1.9876.0 or newer, while the currently active rustc version is [..]
24902482
")
24912483
.with_status(101).run();
24922484
}

0 commit comments

Comments
 (0)