mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-25 11:14:46 +00:00
559 lines
14 KiB
Rust
559 lines
14 KiB
Rust
//! Tests for `lockfile-path` flag
|
|
|
|
use std::fs;
|
|
|
|
use snapbox::str;
|
|
|
|
use crate::prelude::*;
|
|
use crate::utils::cargo_process;
|
|
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::{
|
|
ProjectBuilder, basic_bin_manifest, cargo_test, paths, project, symlink_supported,
|
|
};
|
|
///////////////////////////////
|
|
//// Unstable feature tests start
|
|
///////////////////////////////
|
|
|
|
#[cargo_test]
|
|
fn must_have_unstable_options() {
|
|
let lockfile_path = "mylockfile/is/burried/Cargo.lock";
|
|
let p = make_project().build();
|
|
|
|
p.cargo("generate-lockfile")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.with_stderr_data(str![[
|
|
r#"[ERROR] the `--lockfile-path` flag is unstable, pass `-Z unstable-options` to enable it
|
|
See https://github.com/rust-lang/cargo/issues/14421 for more information about the `--lockfile-path` flag.
|
|
|
|
"#]])
|
|
.with_status(101)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn must_be_nightly() {
|
|
let lockfile_path = "mylockfile/is/burried/Cargo.lock";
|
|
let p = make_project().build();
|
|
|
|
p.cargo("generate-lockfile")
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.with_stderr_data(str![[
|
|
r#"[ERROR] the `-Z` flag is only accepted on the nightly channel of Cargo, but this is the `stable` channel
|
|
See https://doc.rust-lang.org/book/appendix-07-nightly-rust.html for more information about Rust release channels.
|
|
|
|
"#]])
|
|
.with_status(101)
|
|
.run();
|
|
}
|
|
|
|
///////////////////////////////
|
|
//// Unstable feature tests end
|
|
///////////////////////////////
|
|
|
|
#[cargo_test]
|
|
fn basic_lockfile_created() {
|
|
let lockfile_path = "mylockfile/is/burried/Cargo.lock";
|
|
let p = make_project().build();
|
|
|
|
p.cargo("generate-lockfile")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.run();
|
|
assert!(!p.root().join("Cargo.lock").exists());
|
|
assert!(p.root().join(lockfile_path).is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn basic_lockfile_read() {
|
|
let lockfile_path = "mylockfile/Cargo.lock";
|
|
let p = make_project().file(lockfile_path, VALID_LOCKFILE).build();
|
|
|
|
p.cargo("generate-lockfile")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.run();
|
|
|
|
assert!(!p.root().join("Cargo.lock").exists());
|
|
assert!(p.root().join(lockfile_path).is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn basic_lockfile_override() {
|
|
let lockfile_path = "mylockfile/Cargo.lock";
|
|
let p = make_project()
|
|
.file("Cargo.lock", "This is an invalid lock file!")
|
|
.build();
|
|
|
|
p.cargo("generate-lockfile")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.run();
|
|
|
|
assert!(p.root().join(lockfile_path).is_file());
|
|
}
|
|
|
|
//////////////////////
|
|
///// Symlink tests
|
|
//////////////////////
|
|
|
|
#[cargo_test]
|
|
fn symlink_in_path() {
|
|
if !symlink_supported() {
|
|
return;
|
|
}
|
|
|
|
let dst = "dst";
|
|
let src = "somedir/link";
|
|
let lockfile_path = format!("{src}/Cargo.lock");
|
|
|
|
let p = make_project().symlink_dir(dst, src).build();
|
|
|
|
fs::create_dir(p.root().join("dst")).unwrap();
|
|
assert!(p.root().join(src).is_dir());
|
|
|
|
p.cargo("generate-lockfile")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path.as_str())
|
|
.run();
|
|
|
|
assert!(p.root().join(lockfile_path).is_file());
|
|
assert!(p.root().join(dst).join("Cargo.lock").is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn symlink_lockfile() {
|
|
if !symlink_supported() {
|
|
return;
|
|
}
|
|
|
|
let lockfile_path = "dst/Cargo.lock";
|
|
let src = "somedir/link";
|
|
let lock_body = VALID_LOCKFILE;
|
|
|
|
let p = make_project()
|
|
.file(lockfile_path, lock_body)
|
|
.symlink(lockfile_path, src)
|
|
.build();
|
|
|
|
assert!(p.root().join(src).is_file());
|
|
|
|
p.cargo("generate-lockfile")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.run();
|
|
|
|
assert!(!p.root().join("Cargo.lock").exists());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn broken_symlink() {
|
|
if !symlink_supported() {
|
|
return;
|
|
}
|
|
|
|
let invalid_dst = "invalid_path";
|
|
let src = "somedir/link";
|
|
let lockfile_path = format!("{src}/Cargo.lock");
|
|
|
|
let p = make_project().symlink_dir(invalid_dst, src).build();
|
|
assert!(!p.root().join(src).is_dir());
|
|
|
|
p.cargo("generate-lockfile")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.with_status(101)
|
|
.with_stderr_data(str![[
|
|
r#"[ERROR] failed to create directory `[ROOT]/foo/somedir/link`
|
|
|
|
...
|
|
|
|
"#
|
|
]])
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn loop_symlink() {
|
|
if !symlink_supported() {
|
|
return;
|
|
}
|
|
|
|
let loop_link = "loop";
|
|
let src = "somedir/link";
|
|
let lockfile_path = format!("{src}/Cargo.lock");
|
|
|
|
let p = make_project()
|
|
.symlink_dir(loop_link, src)
|
|
.symlink_dir(src, loop_link)
|
|
.build();
|
|
assert!(!p.root().join(src).is_dir());
|
|
|
|
p.cargo("generate-lockfile")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.with_status(101)
|
|
.with_stderr_data(str![[
|
|
r#"[ERROR] failed to create directory `[ROOT]/foo/somedir/link`
|
|
|
|
...
|
|
|
|
"#
|
|
]])
|
|
.run();
|
|
}
|
|
|
|
/////////////////////////
|
|
//// Commands tests
|
|
/////////////////////////
|
|
|
|
#[cargo_test]
|
|
fn add_lockfile_override() {
|
|
let lockfile_path = "mylockfile/Cargo.lock";
|
|
project()
|
|
.at("bar")
|
|
.file("Cargo.toml", LIB_TOML)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.build();
|
|
let p = make_project()
|
|
.file("Cargo.lock", "This is an invalid lock file!")
|
|
.build();
|
|
p.cargo("add")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.arg("--path")
|
|
.arg("../bar")
|
|
.run();
|
|
|
|
assert!(p.root().join(lockfile_path).is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn clean_lockfile_override() {
|
|
let lockfile_path = "mylockfile/Cargo.lock";
|
|
let p = make_project()
|
|
.file("Cargo.lock", "This is an invalid lock file!")
|
|
.build();
|
|
p.cargo("clean")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.arg("--package")
|
|
.arg("test_foo")
|
|
.run();
|
|
|
|
assert!(p.root().join(lockfile_path).is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn fix_lockfile_override() {
|
|
let lockfile_path = "mylockfile/Cargo.lock";
|
|
let p = make_project()
|
|
.file("Cargo.lock", "This is an invalid lock file!")
|
|
.build();
|
|
p.cargo("fix")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.arg("--package")
|
|
.arg("test_foo")
|
|
.arg("--allow-no-vcs")
|
|
.run();
|
|
|
|
assert!(p.root().join(lockfile_path).is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn publish_lockfile_read() {
|
|
let lockfile_path = "mylockfile/Cargo.lock";
|
|
let p = make_project().file(lockfile_path, VALID_LOCKFILE).build();
|
|
let registry = RegistryBuilder::new().http_api().http_index().build();
|
|
|
|
p.cargo("publish")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.replace_crates_io(registry.index_url())
|
|
.run();
|
|
|
|
assert!(!p.root().join("Cargo.lock").exists());
|
|
assert!(p.root().join(lockfile_path).is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn remove_lockfile_override() {
|
|
let lockfile_path = "mylockfile/Cargo.lock";
|
|
let manifest = r#"
|
|
[package]
|
|
|
|
name = "foo"
|
|
version = "0.5.0"
|
|
authors = ["wycats@example.com"]
|
|
edition = "2015"
|
|
|
|
[[bin]]
|
|
|
|
name = "foo"
|
|
|
|
[dependencies]
|
|
test_bar = { version = "0.1.0", path = "../bar" }
|
|
"#;
|
|
|
|
project()
|
|
.at("bar")
|
|
.file("Cargo.toml", LIB_TOML)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.build();
|
|
|
|
let p = project()
|
|
.file("Cargo.toml", &manifest)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.file("Cargo.lock", "This is an invalid lock file!")
|
|
.build();
|
|
p.cargo("remove")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.arg("test_bar")
|
|
.run();
|
|
|
|
assert!(p.root().join(lockfile_path).is_file());
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn assert_respect_pinned_version_from_lockfile_path() {
|
|
let lockfile_path = "mylockfile/Cargo.lock";
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"#
|
|
[package]
|
|
|
|
name = "test_foo"
|
|
version = "0.5.0"
|
|
authors = ["wycats@example.com"]
|
|
edition = "2015"
|
|
|
|
[[bin]]
|
|
|
|
name = "test_foo"
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.build();
|
|
|
|
Package::new("bar", "0.1.0").publish();
|
|
p.cargo("generate-lockfile")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.run();
|
|
|
|
assert!(!p.root().join("Cargo.lock").exists());
|
|
assert!(p.root().join(lockfile_path).is_file());
|
|
|
|
let lockfile_original = fs::read_to_string(p.root().join(lockfile_path)).unwrap();
|
|
|
|
Package::new("bar", "0.1.1").publish();
|
|
p.cargo("package")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.run();
|
|
|
|
assert!(
|
|
p.root()
|
|
.join("target/package/test_foo-0.5.0/Cargo.lock")
|
|
.is_file()
|
|
);
|
|
|
|
let path = p.root().join("target/package/test_foo-0.5.0/Cargo.lock");
|
|
let contents = fs::read_to_string(path).unwrap();
|
|
|
|
assert_e2e().eq(contents, lockfile_original);
|
|
}
|
|
|
|
#[cargo_test]
|
|
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", "")
|
|
.file(
|
|
"src/main.rs",
|
|
"extern crate foo; extern crate bar; fn main() {}",
|
|
)
|
|
.file(
|
|
"Cargo.lock",
|
|
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"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
dependencies = [
|
|
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
]
|
|
"#,
|
|
)
|
|
.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 -Zunstable-options --lockfile-path lockfile_dir/Cargo.lock")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.with_stderr_data(str![[r#"
|
|
...
|
|
[ERROR] no Cargo.lock file found in the requested path [ROOT]/lockfile_dir/Cargo.lock
|
|
...
|
|
"#]])
|
|
.with_status(101)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test(nightly, reason = "-Zscript is unstable")]
|
|
fn run_embed() {
|
|
let lockfile_path = "mylockfile/Cargo.lock";
|
|
let invalid_lockfile = "Cargo.lock";
|
|
let p = project()
|
|
.file("src/main.rs", "fn main() {}")
|
|
.file("Cargo.lock", "This is an invalid lock file!")
|
|
.build();
|
|
|
|
p.cargo("run")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("-Zscript")
|
|
.arg("--lockfile-path")
|
|
.arg(lockfile_path)
|
|
.arg("--manifest-path")
|
|
.arg("src/main.rs")
|
|
.run();
|
|
|
|
assert!(p.root().join(lockfile_path).is_file());
|
|
|
|
p.cargo("run")
|
|
.masquerade_as_nightly_cargo(&["lockfile-path"])
|
|
.arg("-Zunstable-options")
|
|
.arg("-Zscript")
|
|
.arg("--lockfile-path")
|
|
.arg(invalid_lockfile)
|
|
.arg("--manifest-path")
|
|
.arg("src/main.rs")
|
|
.with_status(101)
|
|
.with_stderr_data(str![[
|
|
r#"[WARNING] `package.edition` is unspecified, defaulting to `2024`
|
|
[ERROR] failed to parse lock file at: [ROOT]/foo/Cargo.lock
|
|
|
|
...
|
|
"#
|
|
]])
|
|
.run();
|
|
}
|
|
|
|
const VALID_LOCKFILE: &str = r#"# Test lockfile
|
|
version = 4
|
|
|
|
[[package]]
|
|
name = "test_foo"
|
|
version = "0.5.0"
|
|
"#;
|
|
|
|
const LIB_TOML: &str = r#"
|
|
[package]
|
|
name = "test_bar"
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
"#;
|
|
|
|
fn make_project() -> ProjectBuilder {
|
|
project()
|
|
.file("Cargo.toml", &basic_bin_manifest("test_foo"))
|
|
.file("src/main.rs", "fn main() {}")
|
|
}
|