Skip to content

Commit c8e4f8e

Browse files
committed
Serialize cargo fix
1 parent 18f2598 commit c8e4f8e

File tree

2 files changed

+53
-4
lines changed

2 files changed

+53
-4
lines changed

src/cargo/ops/fix.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -420,10 +420,12 @@ fn rustfix_crate(
420420
// process at a time. If two invocations concurrently check a crate then
421421
// it's likely to corrupt it.
422422
//
423-
// We currently do this by assigning the name on our lock to the manifest
424-
// directory.
425-
let dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is missing?");
426-
let _lock = LockServerClient::lock(&lock_addr.parse()?, dir)?;
423+
// Historically this used per-source-file locking, then per-package
424+
// locking. It now uses a single, global lock as some users do things like
425+
// #[path] or include!() of shared files between packages. Serializing
426+
// makes it slower, but is the only safe way to prevent concurrent
427+
// modification.
428+
let _lock = LockServerClient::lock(&lock_addr.parse()?, "global")?;
427429

428430
// Next up, this is a bit suspicious, but we *iteratively* execute rustc and
429431
// collect suggestions to feed to rustfix. Once we hit our limit of times to

tests/testsuite/fix.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Tests for the `cargo fix` command.
22
33
use cargo::core::Edition;
4+
use cargo_test_support::compare::assert_match_exact;
45
use cargo_test_support::git;
56
use cargo_test_support::paths::CargoPathExt;
67
use cargo_test_support::registry::{Dependency, Package};
@@ -1553,3 +1554,49 @@ fn fix_edition_2021() {
15531554
.run();
15541555
assert!(p.read_file("src/lib.rs").contains(r#"0..=100 => true,"#));
15551556
}
1557+
1558+
#[cargo_test]
1559+
fn fix_shared_cross_workspace() {
1560+
// Fixing a file that is shared between multiple packages in the same workspace.
1561+
// Make sure two processes don't try to fix the same file at the same time.
1562+
let p = project()
1563+
.file(
1564+
"Cargo.toml",
1565+
r#"
1566+
[workspace]
1567+
members = ["foo", "bar"]
1568+
"#,
1569+
)
1570+
.file("foo/Cargo.toml", &basic_manifest("foo", "0.1.0"))
1571+
.file("foo/src/lib.rs", "pub mod shared;")
1572+
// This will fix both unused and bare trait.
1573+
.file("foo/src/shared.rs", "pub fn fixme(x: Box<&Fn() -> ()>) {}")
1574+
.file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
1575+
.file(
1576+
"bar/src/lib.rs",
1577+
r#"
1578+
#[path="../../foo/src/shared.rs"]
1579+
pub mod shared;
1580+
"#,
1581+
)
1582+
.build();
1583+
1584+
// The output here can be either of these two, depending on who runs first:
1585+
// [FIXED] bar/src/../../foo/src/shared.rs (2 fixes)
1586+
// [FIXED] foo/src/shared.rs (2 fixes)
1587+
p.cargo("fix --allow-no-vcs")
1588+
.with_stderr_unordered(
1589+
"\
1590+
[CHECKING] foo v0.1.0 [..]
1591+
[CHECKING] bar v0.1.0 [..]
1592+
[FIXED] [..]foo/src/shared.rs (2 fixes)
1593+
[FINISHED] [..]
1594+
",
1595+
)
1596+
.run();
1597+
1598+
assert_match_exact(
1599+
"pub fn fixme(_x: Box<&dyn Fn() -> ()>) {}",
1600+
&p.read_file("foo/src/shared.rs"),
1601+
);
1602+
}

0 commit comments

Comments
 (0)