Skip to content

Commit cc2d88c

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 cc2d88c

File tree

5 files changed

+59
-16
lines changed

5 files changed

+59
-16
lines changed

src/bin/cargo/commands/install.rs

+1
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
203203
&compile_opts,
204204
args.flag("force"),
205205
args.flag("no-track"),
206+
!args.flag("ignore-rust-version"),
206207
)?;
207208
}
208209
Ok(())

src/cargo/ops/cargo_install.rs

+40-3
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 \
@@ -611,19 +620,46 @@ pub fn install(
611620
opts: &ops::CompileOptions,
612621
force: bool,
613622
no_track: bool,
623+
honor_rust_version: bool,
614624
) -> CargoResult<()> {
615625
let root = resolve_root(root, config)?;
616626
let dst = root.join("bin").into_path_unlocked();
617627
let map = SourceConfigMap::new(config)?;
618628

629+
let current_rust_version = if honor_rust_version {
630+
let rustc = config.load_global_rustc(None)?;
631+
632+
// Remove any pre-release identifiers for easier comparison
633+
let current_version = &rustc.version;
634+
let untagged_version = semver::Version::new(
635+
current_version.major,
636+
current_version.minor,
637+
current_version.patch,
638+
);
639+
Some(untagged_version)
640+
} else {
641+
None
642+
};
643+
619644
let (installed_anything, scheduled_error) = if krates.len() <= 1 {
620645
let (krate, vers) = krates
621646
.iter()
622647
.next()
623648
.map(|(k, v)| (Some(k.as_str()), v.as_ref()))
624649
.unwrap_or((None, None));
625650
let installable_pkg = InstallablePackage::new(
626-
config, root, map, krate, source_id, from_cwd, vers, opts, force, no_track, true,
651+
config,
652+
root,
653+
map,
654+
krate,
655+
source_id,
656+
from_cwd,
657+
vers,
658+
opts,
659+
force,
660+
no_track,
661+
true,
662+
current_rust_version.as_ref(),
627663
)?;
628664
let mut installed_anything = true;
629665
if let Some(installable_pkg) = installable_pkg {
@@ -654,6 +690,7 @@ pub fn install(
654690
force,
655691
no_track,
656692
!did_update,
693+
current_rust_version.as_ref(),
657694
) {
658695
Ok(Some(installable_pkg)) => {
659696
did_update = true;
@@ -773,7 +810,7 @@ where
773810
// expensive network call in the case that the package is already installed.
774811
// If this fails, the caller will possibly do an index update and try again, this is just a
775812
// best-effort check to see if we can avoid hitting the network.
776-
if let Ok(pkg) = select_dep_pkg(source, dep, config, false) {
813+
if let Ok(pkg) = select_dep_pkg(source, dep, config, false, None) {
777814
let (_ws, rustc, target) =
778815
make_ws_rustc_target(config, opts, &source.source_id(), pkg.clone())?;
779816
if let Ok(true) = is_installed(&pkg, config, opts, &rustc, &target, root, dst, force) {

src/cargo/ops/cargo_uninstall.rs

+1
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

+16-4
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

+1-9
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)