| //! 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:?}" |
| ); |
| } |
| } |