diff --git a/src/bin/cargo/commands/install.rs b/src/bin/cargo/commands/install.rs index dabdc79c353..2b0a77feac9 100644 --- a/src/bin/cargo/commands/install.rs +++ b/src/bin/cargo/commands/install.rs @@ -98,6 +98,7 @@ pub fn cli() -> Command { .arg_target_triple("Build for the target triple") .arg_target_dir() .arg_timings() + .arg_lockfile_path() .after_help(color_print::cstr!( "Run `cargo help install` for more detailed information.\n" )) @@ -204,6 +205,13 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { if args.dry_run() { gctx.cli_unstable().fail_if_stable_opt("--dry-run", 11123)?; } + + let requested_lockfile_path = args.lockfile_path(gctx)?; + // 14421: lockfile path should imply --locked on running `install` + if requested_lockfile_path.is_some() { + gctx.set_locked(true); + } + if args.flag("list") { ops::install_list(root, gctx)?; } else { @@ -217,6 +225,7 @@ pub fn exec(gctx: &mut GlobalContext, args: &ArgMatches) -> CliResult { args.flag("force"), args.flag("no-track"), args.dry_run(), + requested_lockfile_path.as_deref(), )?; } Ok(()) diff --git a/src/cargo/core/workspace.rs b/src/cargo/core/workspace.rs index 44066ec7a08..d4871fef203 100644 --- a/src/cargo/core/workspace.rs +++ b/src/cargo/core/workspace.rs @@ -662,6 +662,10 @@ impl<'gctx> Workspace<'gctx> { self.requested_lockfile_path = path; } + pub fn requested_lockfile_path(&self) -> Option<&Path> { + self.requested_lockfile_path.as_deref() + } + /// Get the lowest-common denominator `package.rust-version` within the workspace, if specified /// anywhere pub fn lowest_rust_version(&self) -> Option<&RustVersion> { diff --git a/src/cargo/ops/cargo_install.rs b/src/cargo/ops/cargo_install.rs index 2c20d29c23d..74583deebcb 100644 --- a/src/cargo/ops/cargo_install.rs +++ b/src/cargo/ops/cargo_install.rs @@ -46,7 +46,6 @@ struct InstallablePackage<'gctx> { vers: Option, force: bool, no_track: bool, - pkg: Package, ws: Workspace<'gctx>, rustc: Rustc, @@ -68,6 +67,7 @@ impl<'gctx> InstallablePackage<'gctx> { no_track: bool, needs_update_if_source_is_index: bool, current_rust_version: Option<&PartialVersion>, + lockfile_path: Option<&Path>, ) -> CargoResult> { if let Some(name) = krate { if name == "." { @@ -155,6 +155,7 @@ impl<'gctx> InstallablePackage<'gctx> { &root, &dst, force, + lockfile_path, ) { let msg = format!( "package `{}` is already installed, use --force to override", @@ -179,15 +180,32 @@ impl<'gctx> InstallablePackage<'gctx> { } }; - let (ws, rustc, target) = - make_ws_rustc_target(gctx, &original_opts, &source_id, pkg.clone())?; - // If we're installing in --locked mode and there's no `Cargo.lock` published - // ie. the bin was published before https://github.com/rust-lang/cargo/pull/7026 - if gctx.locked() && !ws.root().join("Cargo.lock").exists() { - gctx.shell().warn(format!( - "no Cargo.lock file published in {}", - pkg.to_string() - ))?; + let (ws, rustc, target) = make_ws_rustc_target( + gctx, + &original_opts, + &source_id, + pkg.clone(), + lockfile_path.clone(), + )?; + + if gctx.locked() { + // When --lockfile-path is set, check that passed lock file exists + // (unlike the usual flag behavior, lockfile won't be created as we imply --locked) + if let Some(requested_lockfile_path) = ws.requested_lockfile_path() { + if !requested_lockfile_path.is_file() { + bail!( + "no Cargo.lock file found in the requested path {}", + requested_lockfile_path.display() + ); + } + // If we're installing in --locked mode and there's no `Cargo.lock` published + // ie. the bin was published before https://github.com/rust-lang/cargo/pull/7026 + } else if !ws.root().join("Cargo.lock").exists() { + gctx.shell().warn(format!( + "no Cargo.lock file published in {}", + pkg.to_string() + ))?; + } } let pkg = if source_id.is_git() { // Don't use ws.current() in order to keep the package source as a git source so that @@ -246,7 +264,6 @@ impl<'gctx> InstallablePackage<'gctx> { vers: vers.cloned(), force, no_track, - pkg, ws, rustc, @@ -636,6 +653,7 @@ pub fn install( force: bool, no_track: bool, dry_run: bool, + lockfile_path: Option<&Path>, ) -> CargoResult<()> { let root = resolve_root(root, gctx)?; let dst = root.join("bin").into_path_unlocked(); @@ -667,6 +685,7 @@ pub fn install( no_track, true, current_rust_version.as_ref(), + lockfile_path, )?; let mut installed_anything = true; if let Some(installable_pkg) = installable_pkg { @@ -698,6 +717,7 @@ pub fn install( no_track, !did_update, current_rust_version.as_ref(), + lockfile_path, ) { Ok(Some(installable_pkg)) => { did_update = true; @@ -804,6 +824,7 @@ fn installed_exact_package( root: &Filesystem, dst: &Path, force: bool, + lockfile_path: Option<&Path>, ) -> CargoResult> where T: Source, @@ -819,7 +840,7 @@ where // best-effort check to see if we can avoid hitting the network. if let Ok(pkg) = select_dep_pkg(source, dep, gctx, false, None) { let (_ws, rustc, target) = - make_ws_rustc_target(gctx, opts, &source.source_id(), pkg.clone())?; + make_ws_rustc_target(gctx, opts, &source.source_id(), pkg.clone(), lockfile_path)?; if let Ok(true) = is_installed(&pkg, gctx, opts, &rustc, &target, root, dst, force) { return Ok(Some(pkg)); } @@ -832,6 +853,7 @@ fn make_ws_rustc_target<'gctx>( opts: &ops::CompileOptions, source_id: &SourceId, pkg: Package, + lockfile_path: Option<&Path>, ) -> CargoResult<(Workspace<'gctx>, Rustc, String)> { let mut ws = if source_id.is_git() || source_id.is_path() { Workspace::new(pkg.manifest_path(), gctx)? @@ -841,6 +863,11 @@ fn make_ws_rustc_target<'gctx>( ws }; ws.set_ignore_lock(gctx.lock_update_allowed()); + ws.set_requested_lockfile_path(lockfile_path.map(|p| p.to_path_buf())); + // if --lockfile-path is set, imply --locked + if ws.requested_lockfile_path().is_some() { + ws.set_ignore_lock(false); + } ws.set_require_optional_deps(false); let rustc = gctx.load_global_rustc(Some(&ws))?; diff --git a/src/cargo/util/context/mod.rs b/src/cargo/util/context/mod.rs index ab283aa2481..c38fd6fd55a 100644 --- a/src/cargo/util/context/mod.rs +++ b/src/cargo/util/context/mod.rs @@ -1142,6 +1142,10 @@ impl GlobalContext { self.locked } + pub fn set_locked(&mut self, locked: bool) { + self.locked = locked; + } + pub fn lock_update_allowed(&self) -> bool { !self.frozen && !self.locked } diff --git a/tests/testsuite/cargo_install/help/stdout.term.svg b/tests/testsuite/cargo_install/help/stdout.term.svg index 38ef23809e7..23375b98513 100644 --- a/tests/testsuite/cargo_install/help/stdout.term.svg +++ b/tests/testsuite/cargo_install/help/stdout.term.svg @@ -1,4 +1,4 @@ - +