feat: --lockfile-path add install support

This commit is contained in:
Ifropc 2024-09-26 01:19:40 -04:00
parent 284b380e08
commit bf37cf7f32
6 changed files with 141 additions and 47 deletions

View file

@ -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 `<cyan,bold>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(())

View file

@ -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 rust_version(&self) -> Option<&RustVersion> {

View file

@ -46,7 +46,6 @@ struct InstallablePackage<'gctx> {
vers: Option<VersionReq>,
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<Option<Self>> {
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<T>(
root: &Filesystem,
dst: &Path,
force: bool,
lockfile_path: Option<&Path>,
) -> CargoResult<Option<Package>>
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))?;

View file

@ -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
}

View file

@ -1,4 +1,4 @@
<svg width="844px" height="1064px" xmlns="http://www.w3.org/2000/svg">
<svg width="844px" height="1082px" xmlns="http://www.w3.org/2000/svg">
<style>
.fg { fill: #AAAAAA }
.bg { background: #000000 }
@ -83,57 +83,59 @@
</tspan>
<tspan x="10px" y="586px"><tspan class="fg-green bold">Manifest Options:</tspan>
</tspan>
<tspan x="10px" y="604px"><tspan> </tspan><tspan class="fg-cyan bold">--ignore-rust-version</tspan><tspan> Ignore `rust-version` specification in packages</tspan>
<tspan x="10px" y="604px"><tspan> </tspan><tspan class="fg-cyan bold">--ignore-rust-version</tspan><tspan> Ignore `rust-version` specification in packages</tspan>
</tspan>
<tspan x="10px" y="622px"><tspan> </tspan><tspan class="fg-cyan bold">--locked</tspan><tspan> Assert that `Cargo.lock` will remain unchanged</tspan>
<tspan x="10px" y="622px"><tspan> </tspan><tspan class="fg-cyan bold">--lockfile-path</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;PATH&gt;</tspan><tspan> Path to Cargo.lock (unstable)</tspan>
</tspan>
<tspan x="10px" y="640px"><tspan> </tspan><tspan class="fg-cyan bold">--offline</tspan><tspan> Run without accessing the network</tspan>
<tspan x="10px" y="640px"><tspan> </tspan><tspan class="fg-cyan bold">--locked</tspan><tspan> Assert that `Cargo.lock` will remain unchanged</tspan>
</tspan>
<tspan x="10px" y="658px"><tspan> </tspan><tspan class="fg-cyan bold">--frozen</tspan><tspan> Equivalent to specifying both --locked and --offline</tspan>
<tspan x="10px" y="658px"><tspan> </tspan><tspan class="fg-cyan bold">--offline</tspan><tspan> Run without accessing the network</tspan>
</tspan>
<tspan x="10px" y="676px">
<tspan x="10px" y="676px"><tspan> </tspan><tspan class="fg-cyan bold">--frozen</tspan><tspan> Equivalent to specifying both --locked and --offline</tspan>
</tspan>
<tspan x="10px" y="694px"><tspan class="fg-green bold">Target Selection:</tspan>
<tspan x="10px" y="694px">
</tspan>
<tspan x="10px" y="712px"><tspan> </tspan><tspan class="fg-cyan bold">--bin</tspan><tspan class="fg-cyan"> [</tspan><tspan class="fg-cyan">&lt;NAME&gt;</tspan><tspan class="fg-cyan">]</tspan><tspan> Install only the specified binary</tspan>
<tspan x="10px" y="712px"><tspan class="fg-green bold">Target Selection:</tspan>
</tspan>
<tspan x="10px" y="730px"><tspan> </tspan><tspan class="fg-cyan bold">--bins</tspan><tspan> Install all binaries</tspan>
<tspan x="10px" y="730px"><tspan> </tspan><tspan class="fg-cyan bold">--bin</tspan><tspan class="fg-cyan"> [</tspan><tspan class="fg-cyan">&lt;NAME&gt;</tspan><tspan class="fg-cyan">]</tspan><tspan> Install only the specified binary</tspan>
</tspan>
<tspan x="10px" y="748px"><tspan> </tspan><tspan class="fg-cyan bold">--example</tspan><tspan class="fg-cyan"> [</tspan><tspan class="fg-cyan">&lt;NAME&gt;</tspan><tspan class="fg-cyan">]</tspan><tspan> Install only the specified example</tspan>
<tspan x="10px" y="748px"><tspan> </tspan><tspan class="fg-cyan bold">--bins</tspan><tspan> Install all binaries</tspan>
</tspan>
<tspan x="10px" y="766px"><tspan> </tspan><tspan class="fg-cyan bold">--examples</tspan><tspan> Install all examples</tspan>
<tspan x="10px" y="766px"><tspan> </tspan><tspan class="fg-cyan bold">--example</tspan><tspan class="fg-cyan"> [</tspan><tspan class="fg-cyan">&lt;NAME&gt;</tspan><tspan class="fg-cyan">]</tspan><tspan> Install only the specified example</tspan>
</tspan>
<tspan x="10px" y="784px">
<tspan x="10px" y="784px"><tspan> </tspan><tspan class="fg-cyan bold">--examples</tspan><tspan> Install all examples</tspan>
</tspan>
<tspan x="10px" y="802px"><tspan class="fg-green bold">Feature Selection:</tspan>
<tspan x="10px" y="802px">
</tspan>
<tspan x="10px" y="820px"><tspan> </tspan><tspan class="fg-cyan bold">-F</tspan><tspan>, </tspan><tspan class="fg-cyan bold">--features</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;FEATURES&gt;</tspan><tspan> Space or comma separated list of features to activate</tspan>
<tspan x="10px" y="820px"><tspan class="fg-green bold">Feature Selection:</tspan>
</tspan>
<tspan x="10px" y="838px"><tspan> </tspan><tspan class="fg-cyan bold">--all-features</tspan><tspan> Activate all available features</tspan>
<tspan x="10px" y="838px"><tspan> </tspan><tspan class="fg-cyan bold">-F</tspan><tspan>, </tspan><tspan class="fg-cyan bold">--features</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;FEATURES&gt;</tspan><tspan> Space or comma separated list of features to activate</tspan>
</tspan>
<tspan x="10px" y="856px"><tspan> </tspan><tspan class="fg-cyan bold">--no-default-features</tspan><tspan> Do not activate the `default` feature</tspan>
<tspan x="10px" y="856px"><tspan> </tspan><tspan class="fg-cyan bold">--all-features</tspan><tspan> Activate all available features</tspan>
</tspan>
<tspan x="10px" y="874px">
<tspan x="10px" y="874px"><tspan> </tspan><tspan class="fg-cyan bold">--no-default-features</tspan><tspan> Do not activate the `default` feature</tspan>
</tspan>
<tspan x="10px" y="892px"><tspan class="fg-green bold">Compilation Options:</tspan>
<tspan x="10px" y="892px">
</tspan>
<tspan x="10px" y="910px"><tspan> </tspan><tspan class="fg-cyan bold">-j</tspan><tspan>, </tspan><tspan class="fg-cyan bold">--jobs</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;N&gt;</tspan><tspan> Number of parallel jobs, defaults to # of CPUs.</tspan>
<tspan x="10px" y="910px"><tspan class="fg-green bold">Compilation Options:</tspan>
</tspan>
<tspan x="10px" y="928px"><tspan> </tspan><tspan class="fg-cyan bold">--keep-going</tspan><tspan> Do not abort the build as soon as there is an error</tspan>
<tspan x="10px" y="928px"><tspan> </tspan><tspan class="fg-cyan bold">-j</tspan><tspan>, </tspan><tspan class="fg-cyan bold">--jobs</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;N&gt;</tspan><tspan> Number of parallel jobs, defaults to # of CPUs.</tspan>
</tspan>
<tspan x="10px" y="946px"><tspan> </tspan><tspan class="fg-cyan bold">--profile</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;PROFILE-NAME&gt;</tspan><tspan> Install artifacts with the specified profile</tspan>
<tspan x="10px" y="946px"><tspan> </tspan><tspan class="fg-cyan bold">--keep-going</tspan><tspan> Do not abort the build as soon as there is an error</tspan>
</tspan>
<tspan x="10px" y="964px"><tspan> </tspan><tspan class="fg-cyan bold">--target</tspan><tspan class="fg-cyan"> [</tspan><tspan class="fg-cyan">&lt;TRIPLE&gt;</tspan><tspan class="fg-cyan">]</tspan><tspan> Build for the target triple</tspan>
<tspan x="10px" y="964px"><tspan> </tspan><tspan class="fg-cyan bold">--profile</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;PROFILE-NAME&gt;</tspan><tspan> Install artifacts with the specified profile</tspan>
</tspan>
<tspan x="10px" y="982px"><tspan> </tspan><tspan class="fg-cyan bold">--target-dir</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;DIRECTORY&gt;</tspan><tspan> Directory for all generated artifacts</tspan>
<tspan x="10px" y="982px"><tspan> </tspan><tspan class="fg-cyan bold">--target</tspan><tspan class="fg-cyan"> [</tspan><tspan class="fg-cyan">&lt;TRIPLE&gt;</tspan><tspan class="fg-cyan">]</tspan><tspan> Build for the target triple</tspan>
</tspan>
<tspan x="10px" y="1000px"><tspan> </tspan><tspan class="fg-cyan bold">--timings</tspan><tspan class="fg-cyan">[=</tspan><tspan class="fg-cyan">&lt;FMTS&gt;</tspan><tspan class="fg-cyan">]</tspan><tspan> Timing output formats (unstable) (comma separated): html, json</tspan>
<tspan x="10px" y="1000px"><tspan> </tspan><tspan class="fg-cyan bold">--target-dir</tspan><tspan class="fg-cyan"> </tspan><tspan class="fg-cyan">&lt;DIRECTORY&gt;</tspan><tspan> Directory for all generated artifacts</tspan>
</tspan>
<tspan x="10px" y="1018px">
<tspan x="10px" y="1018px"><tspan> </tspan><tspan class="fg-cyan bold">--timings</tspan><tspan class="fg-cyan">[=</tspan><tspan class="fg-cyan">&lt;FMTS&gt;</tspan><tspan class="fg-cyan">]</tspan><tspan> Timing output formats (unstable) (comma separated): html, json</tspan>
</tspan>
<tspan x="10px" y="1036px"><tspan>Run `</tspan><tspan class="fg-cyan bold">cargo help install</tspan><tspan class="bold">` for more detailed information.</tspan>
<tspan x="10px" y="1036px">
</tspan>
<tspan x="10px" y="1054px">
<tspan x="10px" y="1054px"><tspan>Run `</tspan><tspan class="fg-cyan bold">cargo help install</tspan><tspan class="bold">` for more detailed information.</tspan>
</tspan>
<tspan x="10px" y="1072px">
</tspan>
</text>

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -5,12 +5,12 @@ use std::fs;
use snapbox::str;
use cargo_test_support::compare::assert_e2e;
use cargo_test_support::install::assert_has_installed_exe;
use cargo_test_support::registry::{Package, RegistryBuilder};
use cargo_test_support::{
basic_bin_manifest, cargo_process, cargo_test, paths, project, symlink_supported,
ProjectBuilder,
};
///////////////////////////////
//// Unstable feature tests start
///////////////////////////////
@ -402,11 +402,13 @@ bar = "0.1.0"
}
#[cargo_test]
fn install_without_lockfile_path() {
fn install_respects_lock_file_path() {
// `cargo install` will imply --locked when lockfile path is provided
Package::new("bar", "0.1.0").publish();
Package::new("bar", "0.1.1")
.file("src/lib.rs", "not rust")
.publish();
// Publish with lockfile containing bad version of `bar` (0.1.1)
Package::new("foo", "0.1.0")
.dep("bar", "0.1")
.file("src/lib.rs", "")
@ -419,6 +421,35 @@ fn install_without_lockfile_path() {
r#"
[[package]]
name = "bar"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "foo"
version = "0.1.0"
dependencies = [
"bar 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
"#,
)
.publish();
cargo_process("install foo --locked")
.with_stderr_data(str![[r#"
...
[..]not rust[..]
...
"#]])
.with_status(101)
.run();
// Create lockfile with the good `bar` version (0.1.0) and use it for install
project()
.file(
"Cargo.lock",
r#"
[[package]]
name = "bar"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@ -430,20 +461,37 @@ dependencies = [
]
"#,
)
.build();
cargo_process("install foo -Zunstable-options --lockfile-path foo/Cargo.lock")
.masquerade_as_nightly_cargo(&["lockfile-path"])
.run();
assert!(paths::root().join("foo/Cargo.lock").is_file());
assert_has_installed_exe(paths::cargo_home(), "foo");
}
#[cargo_test]
fn install_lock_file_path_must_present() {
// `cargo install` will imply --locked when lockfile path is provided
Package::new("bar", "0.1.0").publish();
Package::new("foo", "0.1.0")
.dep("bar", "0.1")
.file("src/lib.rs", "")
.file(
"src/main.rs",
"extern crate foo; extern crate bar; fn main() {}",
)
.publish();
cargo_process("install foo")
cargo_process("install foo -Zunstable-options --lockfile-path lockfile_dir/Cargo.lock")
.masquerade_as_nightly_cargo(&["lockfile-path"])
.with_stderr_data(str![[r#"
...
[..]not rust[..]
[ERROR] no Cargo.lock file found in the requested path [ROOT]/lockfile_dir/Cargo.lock
...
"#]])
.with_status(101)
.run();
cargo_process("install foo --locked").run();
assert!(paths::root()
.join("home/.cargo/registry/src/-ec6bec4300fe98b6/foo-0.1.0/Cargo.lock")
.is_file());
}
#[cargo_test]