mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-28 11:20:36 +00:00

This commit makes lockfile version 4 the default version when Cargo tries to write to a lockfile. The lockfile version 4 has been stabilized since 1.78.0, and will become default in 1.83.0. the length of transition period is pretty similar as before. One caveat is that in other output from Cargo, e.g., `cargo metatada`, status messages, `SourceID` will display in the v4 URL encoded format. This shouldn't affect the majority of Rust users, as `SourceId` representation should be opaque to them, unless comparing `SourceId` across different version of toolchains.
1312 lines
31 KiB
Rust
1312 lines
31 KiB
Rust
//! Tests for supporting older versions of the Cargo.lock file format.
|
|
|
|
use cargo_test_support::compare::assert_e2e;
|
|
use cargo_test_support::git;
|
|
use cargo_test_support::prelude::*;
|
|
use cargo_test_support::registry::Package;
|
|
use cargo_test_support::str;
|
|
use cargo_test_support::{basic_lib_manifest, basic_manifest, project};
|
|
|
|
#[cargo_test]
|
|
fn oldest_lockfile_still_works() {
|
|
let cargo_commands = vec!["build", "update"];
|
|
for cargo_command in cargo_commands {
|
|
oldest_lockfile_still_works_with_command(cargo_command);
|
|
}
|
|
}
|
|
|
|
fn oldest_lockfile_still_works_with_command(cargo_command: &str) {
|
|
Package::new("bar", "0.1.0").publish();
|
|
|
|
let expected_lockfile = str![[r##"
|
|
# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
version = 4
|
|
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "[..]"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar",
|
|
]
|
|
|
|
"##]];
|
|
|
|
let old_lockfile = r#"
|
|
[root]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
]
|
|
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
"#;
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("Cargo.lock", old_lockfile)
|
|
.build();
|
|
|
|
p.cargo(cargo_command).run();
|
|
|
|
let lock = p.read_lockfile();
|
|
assert_e2e().eq(&lock, expected_lockfile);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn frozen_flag_preserves_old_lockfile() {
|
|
let cksum = Package::new("bar", "0.1.0").publish();
|
|
|
|
let old_lockfile = format!(
|
|
r#"[root]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
]
|
|
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
|
[metadata]
|
|
"checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "{}"
|
|
"#,
|
|
cksum,
|
|
);
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("Cargo.lock", &old_lockfile)
|
|
.build();
|
|
|
|
p.cargo("check --locked").run();
|
|
|
|
let lock = p.read_lockfile();
|
|
assert_e2e().eq(&lock, &old_lockfile);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn totally_wild_checksums_works() {
|
|
Package::new("bar", "0.1.0").publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"Cargo.lock",
|
|
r#"
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
]
|
|
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
|
[metadata]
|
|
"checksum baz 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "checksum"
|
|
"checksum bar 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "checksum"
|
|
"#,
|
|
);
|
|
|
|
let p = p.build();
|
|
|
|
p.cargo("check").run();
|
|
|
|
let lock = p.read_lockfile();
|
|
assert_e2e().eq(
|
|
&lock,
|
|
str![[r##"
|
|
# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
version = 4
|
|
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "[..]"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar",
|
|
]
|
|
|
|
"##]],
|
|
);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn wrong_checksum_is_an_error() {
|
|
Package::new("bar", "0.1.0").publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"Cargo.lock",
|
|
r#"
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
]
|
|
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
|
[metadata]
|
|
"checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "checksum"
|
|
"#,
|
|
);
|
|
|
|
let p = p.build();
|
|
|
|
p.cargo("check")
|
|
.with_status(101)
|
|
.with_stderr_data(str![[r#"
|
|
[UPDATING] `dummy-registry` index
|
|
[ERROR] checksum for `bar v0.1.0` changed between lock files
|
|
|
|
this could be indicative of a few possible errors:
|
|
|
|
* the lock file is corrupt
|
|
* a replacement source in use (e.g., a mirror) returned a different checksum
|
|
* the source itself may be corrupt in one way or another
|
|
|
|
unable to verify that `bar v0.1.0` is the same as when the lockfile was generated
|
|
|
|
|
|
"#]])
|
|
.run();
|
|
}
|
|
|
|
// If the checksum is unlisted in the lock file (e.g., <none>) yet we can
|
|
// calculate it (e.g., it's a registry dep), then we should in theory just fill
|
|
// it in.
|
|
#[cargo_test]
|
|
fn unlisted_checksum_is_bad_if_we_calculate() {
|
|
Package::new("bar", "0.1.0").publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"Cargo.lock",
|
|
r#"
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
]
|
|
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
|
[metadata]
|
|
"checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "<none>"
|
|
"#,
|
|
);
|
|
let p = p.build();
|
|
|
|
p.cargo("fetch").with_status(101).with_stderr_data(str![[r#"
|
|
[UPDATING] `dummy-registry` index
|
|
[ERROR] checksum for `bar v0.1.0` was not previously calculated, but a checksum could now be calculated
|
|
|
|
this could be indicative of a few possible situations:
|
|
|
|
* the source `registry `crates-io`` did not previously support checksums,
|
|
but was replaced with one that does
|
|
* newer Cargo implementations know how to checksum this source, but this
|
|
older implementation does not
|
|
* the lock file is corrupt
|
|
|
|
|
|
"#]]).run();
|
|
}
|
|
|
|
// If the checksum is listed in the lock file yet we cannot calculate it (e.g.,
|
|
// Git dependencies as of today), then make sure we choke.
|
|
#[cargo_test]
|
|
fn listed_checksum_bad_if_we_cannot_compute() {
|
|
let git = git::new("bar", |p| {
|
|
p.file("Cargo.toml", &basic_manifest("bar", "0.1.0"))
|
|
.file("src/lib.rs", "")
|
|
});
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = {{ git = '{}' }}
|
|
"#,
|
|
git.url()
|
|
),
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"Cargo.lock",
|
|
&format!(
|
|
r#"
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar 0.1.0 (git+{0})"
|
|
]
|
|
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "git+{0}"
|
|
|
|
[metadata]
|
|
"checksum bar 0.1.0 (git+{0})" = "checksum"
|
|
"#,
|
|
git.url()
|
|
),
|
|
);
|
|
|
|
let p = p.build();
|
|
|
|
p.cargo("fetch").with_status(101).with_stderr_data(str![[r#"
|
|
[UPDATING] git repository `[ROOTURL]/bar`
|
|
[ERROR] checksum for `bar v0.1.0 ([ROOTURL]/bar)` could not be calculated, but a checksum is listed in the existing lock file
|
|
|
|
this could be indicative of a few possible situations:
|
|
|
|
* the source `[ROOTURL]/bar` supports checksums,
|
|
but was replaced with one that doesn't
|
|
* the lock file is corrupt
|
|
|
|
unable to verify that `bar v0.1.0 ([ROOTURL]/bar)` is the same as when the lockfile was generated
|
|
|
|
|
|
"#]]).run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn current_lockfile_format() {
|
|
Package::new("bar", "0.1.0").publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "");
|
|
let p = p.build();
|
|
|
|
p.cargo("check").run();
|
|
|
|
let actual = p.read_lockfile();
|
|
|
|
let expected = str![[r##"
|
|
# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
version = 4
|
|
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "[..]"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar",
|
|
]
|
|
|
|
"##]];
|
|
assert_e2e().eq(&actual, expected);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn lockfile_without_root() {
|
|
Package::new("bar", "0.1.0").publish();
|
|
|
|
let lockfile = r#"
|
|
# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar",
|
|
]
|
|
"#;
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("Cargo.lock", lockfile);
|
|
|
|
let p = p.build();
|
|
|
|
p.cargo("check").run();
|
|
|
|
let lock = p.read_lockfile();
|
|
assert_e2e().eq(
|
|
&lock,
|
|
str![[r##"
|
|
# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
version = 4
|
|
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "[..]"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar",
|
|
]
|
|
|
|
"##]],
|
|
);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn locked_correct_error() {
|
|
Package::new("bar", "0.1.0").publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "");
|
|
let p = p.build();
|
|
|
|
p.cargo("check --locked")
|
|
.with_status(101)
|
|
.with_stderr_data(str![[r#"
|
|
[UPDATING] `dummy-registry` index
|
|
[ERROR] the lock file [ROOT]/foo/Cargo.lock needs to be updated but --locked was passed to prevent this
|
|
If you want to try to generate the lock file without accessing the network, remove the --locked flag and use --offline instead.
|
|
|
|
"#]])
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn v2_format_preserved() {
|
|
let cksum = Package::new("bar", "0.1.0").publish();
|
|
|
|
let lockfile = format!(
|
|
r#"# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "{}"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar",
|
|
]
|
|
"#,
|
|
cksum
|
|
);
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("Cargo.lock", &lockfile)
|
|
.build();
|
|
|
|
p.cargo("fetch").run();
|
|
|
|
let lock = p.read_lockfile();
|
|
assert_e2e().eq(&lock, &lockfile);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn v2_path_and_crates_io() {
|
|
let cksum010 = Package::new("a", "0.1.0").publish();
|
|
let cksum020 = Package::new("a", "0.2.0").publish();
|
|
|
|
let lockfile = format!(
|
|
r#"# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
[[package]]
|
|
name = "a"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "{}"
|
|
|
|
[[package]]
|
|
name = "a"
|
|
version = "0.2.0"
|
|
|
|
[[package]]
|
|
name = "a"
|
|
version = "0.2.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "{}"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"a 0.1.0",
|
|
"a 0.2.0",
|
|
"a 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
]
|
|
"#,
|
|
cksum010, cksum020,
|
|
);
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
a = { path = 'a' }
|
|
b = { version = "0.1", package = 'a' }
|
|
c = { version = "0.2", package = 'a' }
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file(
|
|
"a/Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "a"
|
|
version = "0.2.0"
|
|
edition = "2015"
|
|
"#,
|
|
)
|
|
.file("a/src/lib.rs", "")
|
|
.file("Cargo.lock", &lockfile)
|
|
.build();
|
|
|
|
p.cargo("fetch").run();
|
|
p.cargo("fetch").run();
|
|
|
|
let lock = p.read_lockfile();
|
|
assert_e2e().eq(&lock, &lockfile);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn v3_and_git() {
|
|
let (git_project, repo) = git::new_repo("dep1", |project| {
|
|
project
|
|
.file("Cargo.toml", &basic_lib_manifest("dep1"))
|
|
.file("src/lib.rs", "")
|
|
});
|
|
let head_id = repo.head().unwrap().target().unwrap();
|
|
|
|
let lockfile = format!(
|
|
r#"# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
version = 3
|
|
|
|
[[package]]
|
|
name = "dep1"
|
|
version = "0.5.0"
|
|
source = "git+[ROOTURL]/dep1?branch=master#{}"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"dep1",
|
|
]
|
|
"#,
|
|
head_id,
|
|
);
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
rust-version = "1.81" # ensure it stays in lockfile v3
|
|
|
|
[dependencies]
|
|
dep1 = {{ git = '{}', branch = 'master' }}
|
|
"#,
|
|
git_project.url(),
|
|
),
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("Cargo.lock", "version = 3")
|
|
.build();
|
|
|
|
p.cargo("fetch").run();
|
|
|
|
let lock = p.read_lockfile();
|
|
assert_e2e().eq(&lock, &lockfile);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn lock_from_the_future() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
authors = []
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("Cargo.lock", "version = 10000000")
|
|
.build();
|
|
|
|
p.cargo("fetch").with_stderr_data(str![[r#"
|
|
[ERROR] failed to parse lock file at: [ROOT]/foo/Cargo.lock
|
|
|
|
Caused by:
|
|
lock file version `10000000` was found, but this version of Cargo does not understand this lock file, perhaps Cargo needs to be updated?
|
|
|
|
"#]]).with_status(101).run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn preserve_old_format_if_no_update_needed() {
|
|
let cksum = Package::new("bar", "0.1.0").publish();
|
|
let lockfile = format!(
|
|
r#"# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
]
|
|
|
|
[metadata]
|
|
"checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "{}"
|
|
"#,
|
|
cksum
|
|
);
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
authors = []
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("Cargo.lock", &lockfile)
|
|
.build();
|
|
|
|
p.cargo("check --locked").run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn same_name_version_different_sources() {
|
|
let cksum = Package::new("foo", "0.1.0").publish();
|
|
let (git_project, repo) = git::new_repo("dep1", |project| {
|
|
project
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
edition = "2015"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
});
|
|
let head_id = repo.head().unwrap().target().unwrap();
|
|
|
|
// Lockfile was generated with Rust 1.51
|
|
let lockfile = format!(
|
|
r#"# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
version = 3
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
dependencies = [
|
|
"foo 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
"foo 0.1.0 (git+{url})",
|
|
]
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "{cksum}"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
source = "git+{url}#{sha}"
|
|
"#,
|
|
sha = head_id,
|
|
url = git_project.url(),
|
|
cksum = cksum
|
|
);
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.1.0"
|
|
edition = "2015"
|
|
|
|
[dependencies]
|
|
foo = "0.1.0"
|
|
foo2 = {{ git = '{}', package = 'foo' }}
|
|
"#,
|
|
git_project.url(),
|
|
),
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("Cargo.lock", &lockfile)
|
|
.build();
|
|
|
|
p.cargo("check").run();
|
|
|
|
assert_eq!(p.read_file("Cargo.lock"), lockfile);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn bad_data_in_lockfile_error_meg() {
|
|
Package::new("bar", "0.0.1").publish();
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "test"
|
|
version = "0.0.0"
|
|
edition = "2015"
|
|
|
|
[dependencies]
|
|
bar = "*"
|
|
"#,
|
|
)
|
|
.file("src/main.rs", "fn main() {}")
|
|
.file(
|
|
"Cargo.lock",
|
|
r#"# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
version = 3
|
|
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "8e1b9346248cf3391ead604c4407258d327c28e37209f6d56127598165165dda"
|
|
|
|
[[package]]
|
|
name = "test"
|
|
version = "0.0.0"
|
|
dependencies = [
|
|
"bar",
|
|
]"#,
|
|
)
|
|
.build();
|
|
p.cargo("check")
|
|
.with_status(101)
|
|
.with_stderr_data(str![[r#"
|
|
[UPDATING] `dummy-registry` index
|
|
[ERROR] failed to select a version for the requirement `bar = "*"` (locked to 0.1.0)
|
|
candidate versions found which didn't match: 0.0.1
|
|
location searched: `dummy-registry` index (which is replacing registry `crates-io`)
|
|
required by package `test v0.0.0 ([ROOT]/foo)`
|
|
perhaps a crate was updated and forgotten to be re-vendored?
|
|
|
|
"#]])
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn next_version_is_always_unstable() {
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
"#,
|
|
),
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("Cargo.lock", "version = 5")
|
|
.build();
|
|
|
|
p.cargo("fetch").with_status(101).with_stderr_data(str![[r#"
|
|
[ERROR] failed to parse lock file at: [ROOT]/foo/Cargo.lock
|
|
|
|
Caused by:
|
|
lock file version `5` was found, but this version of Cargo does not understand this lock file, perhaps Cargo needs to be updated?
|
|
|
|
"#]]).run();
|
|
|
|
// On nightly, let the user know about the `-Z` flag.
|
|
p.cargo("fetch")
|
|
.masquerade_as_nightly_cargo(&["-Znext-lockfile-bump"])
|
|
.with_status(101)
|
|
.with_stderr_data(str![[r#"
|
|
[ERROR] failed to parse lock file at: [ROOT]/foo/Cargo.lock
|
|
|
|
Caused by:
|
|
lock file version `5` requires `-Znext-lockfile-bump`
|
|
|
|
"#]])
|
|
.run();
|
|
}
|
|
|
|
fn create_branch(repo: &git2::Repository, branch: &str, head_id: git2::Oid) {
|
|
repo.branch(branch, &repo.find_commit(head_id).unwrap(), true)
|
|
.unwrap();
|
|
}
|
|
|
|
fn create_tag(repo: &git2::Repository, tag: &str, head_id: git2::Oid) {
|
|
repo.tag(
|
|
tag,
|
|
&repo.find_object(head_id, None).unwrap(),
|
|
&repo.signature().unwrap(),
|
|
"make a new tag",
|
|
false,
|
|
)
|
|
.unwrap();
|
|
}
|
|
|
|
fn v3_and_git_url_encoded(ref_kind: &str, f: impl FnOnce(&git2::Repository, &str, git2::Oid)) {
|
|
let (git_project, repo) = git::new_repo("dep1", |project| {
|
|
project
|
|
.file("Cargo.toml", &basic_lib_manifest("dep1"))
|
|
.file("src/lib.rs", "")
|
|
});
|
|
let url = git_project.url();
|
|
let head_id = repo.head().unwrap().target().unwrap();
|
|
// Ref name with special characters
|
|
let git_ref = "a-_+#$)";
|
|
let encoded_ref = "a-_%2B%23%24%29";
|
|
f(&repo, git_ref, head_id);
|
|
|
|
let lockfile = format!(
|
|
r#"# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
version = 3
|
|
|
|
[[package]]
|
|
name = "dep1"
|
|
version = "0.5.0"
|
|
source = "git+[ROOTURL]/dep1?{ref_kind}={git_ref}#{head_id}"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"dep1",
|
|
]
|
|
"#,
|
|
);
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
rust-version = "1.81" # ensure it stays in lockfile v3
|
|
|
|
[dependencies]
|
|
dep1 = {{ git = '{url}', {ref_kind} = '{git_ref}' }}
|
|
"#,
|
|
),
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("Cargo.lock", "version = 3")
|
|
.build();
|
|
|
|
p.cargo("check")
|
|
.with_stderr_data(format!(
|
|
"\
|
|
[UPDATING] git repository `[ROOTURL]/dep1`
|
|
[LOCKING] 1 package to latest compatible version
|
|
[ADDING] dep1 v0.5.0 ([ROOTURL]/dep1?{ref_kind}={encoded_ref}#[..])
|
|
[CHECKING] dep1 v0.5.0 ([ROOTURL]/dep1?{ref_kind}={encoded_ref}#[..])
|
|
[CHECKING] foo v0.0.1 ([ROOT]/foo)
|
|
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
|
|
"
|
|
))
|
|
.run();
|
|
|
|
let lock = p.read_lockfile();
|
|
assert_e2e().eq(&lock, &lockfile);
|
|
|
|
// v3 doesn't URL-encode URL parameters, but `url` crate does decode as it
|
|
// was URL-encoded. Therefore Cargo thinks they are from different source
|
|
// and clones the repository again.
|
|
p.cargo("check")
|
|
.with_stderr_data(format!(
|
|
"\
|
|
[UPDATING] git repository `[ROOTURL]/dep1`
|
|
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
|
|
"
|
|
))
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn v3_and_git_url_encoded_branch() {
|
|
v3_and_git_url_encoded("branch", create_branch);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn v3_and_git_url_encoded_tag() {
|
|
v3_and_git_url_encoded("tag", create_tag);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn v3_and_git_url_encoded_rev() {
|
|
v3_and_git_url_encoded("rev", create_tag);
|
|
}
|
|
|
|
fn v4_and_git_url_encoded(ref_kind: &str, f: impl FnOnce(&git2::Repository, &str, git2::Oid)) {
|
|
let (git_project, repo) = git::new_repo("dep1", |project| {
|
|
project
|
|
.file("Cargo.toml", &basic_lib_manifest("dep1"))
|
|
.file("src/lib.rs", "")
|
|
});
|
|
let url = git_project.url();
|
|
let head_id = repo.head().unwrap().target().unwrap();
|
|
// Ref name with special characters
|
|
let git_ref = "a-_+#$)";
|
|
let encoded_ref = "a-_%2B%23%24%29";
|
|
f(&repo, git_ref, head_id);
|
|
|
|
let lockfile = format!(
|
|
r#"# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
version = 4
|
|
|
|
[[package]]
|
|
name = "dep1"
|
|
version = "0.5.0"
|
|
source = "git+[ROOTURL]/dep1?{ref_kind}={encoded_ref}#{head_id}"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"dep1",
|
|
]
|
|
"#,
|
|
);
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
|
|
[dependencies]
|
|
dep1 = {{ git = '{url}', {ref_kind} = '{git_ref}' }}
|
|
"#,
|
|
),
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.file("Cargo.lock", "version = 4")
|
|
.build();
|
|
|
|
p.cargo("check")
|
|
.with_stderr_data(format!(
|
|
"\
|
|
[UPDATING] git repository `[ROOTURL]/dep1`
|
|
[LOCKING] 1 package to latest compatible version
|
|
[ADDING] dep1 v0.5.0 ([ROOTURL]/dep1?{ref_kind}={encoded_ref}#[..])
|
|
[CHECKING] dep1 v0.5.0 ([ROOTURL]/dep1?{ref_kind}={encoded_ref}#[..])
|
|
[CHECKING] foo v0.0.1 ([ROOT]/foo)
|
|
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
|
|
"
|
|
))
|
|
.run();
|
|
|
|
let lock = p.read_lockfile();
|
|
assert_e2e().eq(&lock, &lockfile);
|
|
|
|
// Unlike v3_and_git_url_encoded, v4 encodes URL parameters so no git
|
|
// repository re-clone happen.
|
|
p.cargo("check")
|
|
.with_stderr_data(
|
|
"\
|
|
[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s
|
|
",
|
|
)
|
|
.run();
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn v4_and_git_url_encoded_branch() {
|
|
v4_and_git_url_encoded("branch", create_branch);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn v4_and_git_url_encoded_tag() {
|
|
v4_and_git_url_encoded("tag", create_tag);
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn v4_and_git_url_encoded_rev() {
|
|
v4_and_git_url_encoded("rev", create_tag)
|
|
}
|
|
|
|
#[cargo_test]
|
|
fn with_msrv() {
|
|
let cksum = Package::new("bar", "0.1.0").publish();
|
|
|
|
let v3_lockfile = format!(
|
|
r#"# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
version = 3
|
|
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "{cksum}"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar",
|
|
]
|
|
"#
|
|
);
|
|
let v2_lockfile = format!(
|
|
r#"# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
checksum = "{cksum}"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar",
|
|
]
|
|
"#
|
|
);
|
|
|
|
let v1_lockfile = format!(
|
|
r#"# This file is automatically @generated by Cargo.
|
|
# It is not intended for manual editing.
|
|
[[package]]
|
|
name = "bar"
|
|
version = "0.1.0"
|
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
|
[[package]]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
dependencies = [
|
|
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
]
|
|
|
|
[metadata]
|
|
"checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "{cksum}"
|
|
"#
|
|
);
|
|
|
|
let p = project()
|
|
.file(
|
|
"Cargo.toml",
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
)
|
|
.file("src/lib.rs", "")
|
|
.build();
|
|
|
|
let cases = [
|
|
// v1 is the default
|
|
("1.37", None, 1),
|
|
("1.37", Some(1), 1),
|
|
("1.37", Some(2), 2),
|
|
("1.37", Some(3), 3),
|
|
("1.37", Some(4), 4),
|
|
// v2 introduced
|
|
("1.38", None, 1),
|
|
// last version of v1 as the default
|
|
("1.40", None, 1),
|
|
// v2 is the default
|
|
("1.41", None, 2),
|
|
("1.41", Some(1), 1),
|
|
("1.41", Some(2), 2),
|
|
("1.41", Some(3), 3),
|
|
("1.41", Some(4), 4),
|
|
// v3 introduced
|
|
("1.47", None, 2),
|
|
// last version of v2 as the default
|
|
("1.48", None, 2),
|
|
// v3 is the default
|
|
("1.53", None, 3),
|
|
("1.53", Some(1), 1),
|
|
("1.53", Some(2), 2),
|
|
("1.53", Some(3), 3),
|
|
("1.53", Some(4), 4),
|
|
// v4 introduced
|
|
("1.78", None, 3),
|
|
// last version of v3 as the default
|
|
("1.82", None, 3),
|
|
// v4 is the default
|
|
("1.83", None, 4),
|
|
("1.83", Some(1), 1),
|
|
("1.83", Some(2), 2),
|
|
("1.83", Some(3), 3),
|
|
("1.83", Some(4), 4),
|
|
];
|
|
|
|
for (msrv, existing_lockfile, expected_version) in cases {
|
|
// Clean previous lockfile.
|
|
_ = std::fs::remove_file(p.root().join("Cargo.lock"));
|
|
|
|
p.change_file(
|
|
"Cargo.toml",
|
|
&format!(
|
|
r#"
|
|
[package]
|
|
name = "foo"
|
|
version = "0.0.1"
|
|
edition = "2015"
|
|
rust-version = "{msrv}"
|
|
|
|
[dependencies]
|
|
bar = "0.1.0"
|
|
"#,
|
|
),
|
|
);
|
|
|
|
if let Some(existing_lockfile) = existing_lockfile {
|
|
let existing_lockfile = match existing_lockfile {
|
|
1 => v1_lockfile.as_str().into(),
|
|
2 => v2_lockfile.as_str().into(),
|
|
3 => v3_lockfile.as_str().into(),
|
|
v => std::borrow::Cow::from(format!("version = {v}")),
|
|
};
|
|
p.change_file("Cargo.lock", &existing_lockfile);
|
|
}
|
|
|
|
p.cargo("fetch").run();
|
|
|
|
let lock = p.read_lockfile();
|
|
let toml = lock.parse::<toml::Table>().unwrap();
|
|
// get `version = <n>` from Cargo.lock
|
|
let version_field = toml.get("version").and_then(|v| v.as_integer());
|
|
|
|
let actual_version = if let Some(ver) = version_field {
|
|
ver
|
|
} else if lock.find("\nchecksum = ").is_some() {
|
|
2
|
|
} else {
|
|
1
|
|
};
|
|
|
|
assert_eq!(
|
|
expected_version, actual_version,
|
|
"msrv: {msrv}, existing lockfile: {existing_lockfile:?}"
|
|
);
|
|
}
|
|
}
|