Skip to content

Commit 2ea444b

Browse files
committed
Fix stale Pipfile.lock blocking sibling redirects
Only add packages to refused_pipenv_uuids when there's an actual conflict (version mismatch, already exists, or not a registry package) rather than for all plan() failures. This prevents stale/leftover Pipfile.lock files with missing entries or unsupported specs from blocking redirects in requirements.txt and uv.lock.
1 parent fa6b27f commit 2ea444b

42 files changed

Lines changed: 779 additions & 379 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎crates/socket-patch-core/src/crawlers/go_crawler.rs‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,8 +1196,7 @@ mod tests {
11961196
// FIRST GOPATH entry is skipped in favor of the next non-empty one
11971197
// (GOPATH is an OS-separator-delimited list; Go uses the first
11981198
// usable entry for the module cache).
1199-
let gopath_list =
1200-
std::env::join_paths(["".as_ref(), gopath_a.path().as_os_str()]).unwrap();
1199+
let gopath_list = std::env::join_paths(["".as_ref(), gopath_a.path().as_os_str()]).unwrap();
12011200
let _gomodcache = EnvGuard::set("GOMODCACHE", "");
12021201
let _gopath = EnvGuard::set("GOPATH", gopath_list.to_str().unwrap());
12031202
let _home = EnvGuard::set("HOME", "/nonexistent-home-unused");

‎crates/socket-patch-core/src/crawlers/nuget_crawler.rs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,9 @@ mod tests {
748748
async fn test_scan_package_dir_dedups_same_package_across_two_scans() {
749749
let dir = tempfile::tempdir().unwrap();
750750
let pkg_dir = dir.path().join("newtonsoft.json").join("13.0.3");
751-
tokio::fs::create_dir_all(pkg_dir.join("lib")).await.unwrap();
751+
tokio::fs::create_dir_all(pkg_dir.join("lib"))
752+
.await
753+
.unwrap();
752754

753755
let crawler = NuGetCrawler::new();
754756
let mut seen = HashSet::new();

‎crates/socket-patch-core/src/package_json/find.rs‎

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -846,10 +846,7 @@ mod tests {
846846
// below); if the team decides such values should degrade to
847847
// WorkspaceType::None (npm semantics), update detect_workspaces and
848848
// flip these assertions together.
849-
for spelling in [
850-
r#"{"workspaces": "packages/*"}"#,
851-
r#"{"workspaces": null}"#,
852-
] {
849+
for spelling in [r#"{"workspaces": "packages/*"}"#, r#"{"workspaces": null}"#] {
853850
let dir = tempfile::tempdir().unwrap();
854851
let pkg = dir.path().join("package.json");
855852
fs::write(&pkg, spelling).await.unwrap();

‎crates/socket-patch-core/src/package_json/update.rs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,9 @@ mod tests {
787787
);
788788
assert!(result.new_script.is_none());
789789
assert!(
790-
result.old_dependencies_script.contains("socket-patch apply"),
790+
result
791+
.old_dependencies_script
792+
.contains("socket-patch apply"),
791793
"old_dependencies_script must reflect the configured script, got {:?}",
792794
result.old_dependencies_script
793795
);

‎crates/socket-patch-core/src/patch/apply.rs‎

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2763,7 +2763,9 @@ mod tests {
27632763
assert!(result.success, "expected success: {:?}", result.error);
27642764
assert_eq!(result.files_patched, vec!["new.js".to_string()]);
27652765
assert_eq!(result.applied_via.get("new.js"), Some(&AppliedVia::Blob));
2766-
let written = tokio::fs::read(pkg_dir.path().join("new.js")).await.unwrap();
2766+
let written = tokio::fs::read(pkg_dir.path().join("new.js"))
2767+
.await
2768+
.unwrap();
27672769
assert_eq!(written, fresh, "divergent existing content is overwritten");
27682770
}
27692771

@@ -2811,7 +2813,9 @@ mod tests {
28112813

28122814
assert!(result.success, "strict still overwrites at a new-file path");
28132815
assert_eq!(result.files_patched, vec!["new.js".to_string()]);
2814-
let written = tokio::fs::read(pkg_dir.path().join("new.js")).await.unwrap();
2816+
let written = tokio::fs::read(pkg_dir.path().join("new.js"))
2817+
.await
2818+
.unwrap();
28152819
assert_eq!(written, fresh);
28162820
}
28172821

@@ -2961,7 +2965,9 @@ mod tests {
29612965
let evil = b"pwned";
29622966
let evil_hash = compute_git_sha256_from_bytes(evil);
29632967

2964-
tokio::fs::write(pkg.join("index.js"), original).await.unwrap();
2968+
tokio::fs::write(pkg.join("index.js"), original)
2969+
.await
2970+
.unwrap();
29652971
tokio::fs::write(blobs_dir.path().join(&after_hash), patched)
29662972
.await
29672973
.unwrap();
@@ -3005,7 +3011,10 @@ mod tests {
30053011
assert!(result.files_patched.is_empty());
30063012
// The safe file was never written — the whole apply aborted
30073013
// before the write phase.
3008-
assert_eq!(tokio::fs::read(pkg.join("index.js")).await.unwrap(), original);
3014+
assert_eq!(
3015+
tokio::fs::read(pkg.join("index.js")).await.unwrap(),
3016+
original
3017+
);
30093018
assert!(!root.path().join("escape.js").exists());
30103019
}
30113020

@@ -3028,9 +3037,15 @@ mod tests {
30283037
after_hash: compute_git_sha256_from_bytes(b"x"),
30293038
};
30303039

3031-
let applied =
3032-
try_apply_from_diff(Some(&entries), "new.js", dir.path(), "new.js", &info, Some("anything"))
3033-
.await;
3040+
let applied = try_apply_from_diff(
3041+
Some(&entries),
3042+
"new.js",
3043+
dir.path(),
3044+
"new.js",
3045+
&info,
3046+
Some("anything"),
3047+
)
3048+
.await;
30343049
assert!(!applied, "new-file entries must never apply via diff");
30353050
assert!(!dir.path().join("new.js").exists(), "nothing written");
30363051
}

‎crates/socket-patch-core/src/patch/apply_lock.rs‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -496,9 +496,9 @@ mod tests {
496496
fs2::lock_contended_error().raw_os_error()
497497
);
498498
}
499-
LockError::Held => panic!(
500-
"a genuine flock fault must not be mislabelled as contention"
501-
),
499+
LockError::Held => {
500+
panic!("a genuine flock fault must not be mislabelled as contention")
501+
}
502502
}
503503
// The fault arm returns without ever entering the retry/backoff
504504
// path: nowhere near the 5 s budget (the old funnel-everything-
@@ -530,9 +530,9 @@ mod tests {
530530
fs2::lock_contended_error().raw_os_error()
531531
);
532532
}
533-
LockError::Held => panic!(
534-
"try-once mode must not mislabel a genuine flock fault as Held"
535-
),
533+
LockError::Held => {
534+
panic!("try-once mode must not mislabel a genuine flock fault as Held")
535+
}
536536
}
537537
}
538538

‎crates/socket-patch-core/src/patch/redirect/golang_local.rs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2177,7 +2177,10 @@ mod tests {
21772177

21782178
// Parity: the real run removes exactly what the dry run reported.
21792179
let removed_wet = reconcile_go_redirects(root, &HashSet::new(), false).await;
2180-
assert_eq!(removed_wet, removed, "dry-run report must match the real run");
2180+
assert_eq!(
2181+
removed_wet, removed,
2182+
"dry-run report must match the real run"
2183+
);
21812184
assert!(!copy_dir.exists(), "real run prunes the copy");
21822185
assert!(read_replace_entries(root).await.is_empty());
21832186
}

‎crates/socket-patch-core/src/patch/redirect/pipenv.rs‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,12 @@ pub(super) fn rewrite(
178178
result.edits.extend(edits);
179179
}
180180
Err(detail) => {
181-
result.refused_pipenv_uuids.insert(dep.patch_uuid.clone());
181+
let is_conflict = detail.contains("already exists")
182+
|| detail.contains("does not match")
183+
|| detail.contains("is not a registry package");
184+
if is_conflict {
185+
result.refused_pipenv_uuids.insert(dep.patch_uuid.clone());
186+
}
182187
result.warnings.push(RewriteWarning {
183188
code: "redirect_pipenv_refused".into(),
184189
detail,

‎crates/socket-patch-core/src/patch/redirect/replay.rs‎

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -656,9 +656,7 @@ pub async fn revert_remaining_redirect_edits(
656656
}
657657
}
658658
}
659-
outcome
660-
.reverted_files
661-
.extend(staged.keys().cloned());
659+
outcome.reverted_files.extend(staged.keys().cloned());
662660
pending_warnings.extend(group_warnings);
663661
drop_indices.extend(group_drops);
664662
}
@@ -725,9 +723,9 @@ mod tests {
725723
let mut state = RedirectState::new();
726724
state.edits = edits;
727725
for p in record_purls {
728-
state
729-
.records
730-
.insert((*p).to_string(), crate::manifest::schema::PatchRecord {
726+
state.records.insert(
727+
(*p).to_string(),
728+
crate::manifest::schema::PatchRecord {
731729
uuid: "u".into(),
732730
exported_at: "now".into(),
733731
files: Default::default(),
@@ -776,7 +774,10 @@ mod tests {
776774
);
777775
let out = revert_remaining_redirect_edits(dir.path(), &mut state, false).await;
778776
assert!(out.fully_reverted(), "{:?}", out.refusals);
779-
assert_eq!(read(dir.path(), "requirements.txt").await, "left-pad==1.3.0\n");
777+
assert_eq!(
778+
read(dir.path(), "requirements.txt").await,
779+
"left-pad==1.3.0\n"
780+
);
780781
assert!(state.edits.is_empty());
781782
assert!(state.records.is_empty());
782783
assert_eq!(out.dropped_records, vec!["pkg:pypi/[email protected]"]);
@@ -804,7 +805,10 @@ mod tests {
804805
);
805806
let out = revert_remaining_redirect_edits(dir.path(), &mut state, false).await;
806807
assert!(out.fully_reverted(), "{:?}", out.refusals);
807-
assert_eq!(read(dir.path(), "pom.xml").await, "<version>2.17.1</version>\n");
808+
assert_eq!(
809+
read(dir.path(), "pom.xml").await,
810+
"<version>2.17.1</version>\n"
811+
);
808812
}
809813

810814
#[tokio::test]
@@ -1248,7 +1252,9 @@ mod tests {
12481252
// The npm group refused; the bun group replayed.
12491253
assert_eq!(out.refusals.len(), 1);
12501254
assert_eq!(out.refusals[0].group, "npm");
1251-
assert!(read(dir.path(), "bun.lock").await.contains("upstream.example"));
1255+
assert!(read(dir.path(), "bun.lock")
1256+
.await
1257+
.contains("upstream.example"));
12521258
// npm-family records are held while ANY npm-family group refused.
12531259
assert!(state.records.contains_key("pkg:npm/a@1"));
12541260
assert_eq!(state.edits.len(), 1, "only the refused npm edit remains");
@@ -1428,7 +1434,9 @@ mod tests {
14281434
assert_eq!(out.dropped_records, vec!["pkg:pypi/[email protected]"]);
14291435
assert!(out.reverted_files.contains("requirements.txt"));
14301436
// Disk and ledger untouched.
1431-
assert!(read(dir.path(), "requirements.txt").await.contains("patch.example"));
1437+
assert!(read(dir.path(), "requirements.txt")
1438+
.await
1439+
.contains("patch.example"));
14321440
assert_eq!(state.edits.len(), 1);
14331441
assert_eq!(state.records.len(), 1);
14341442
}
@@ -1645,7 +1653,9 @@ mod tests {
16451653
);
16461654
let out = revert_remaining_redirect_edits(dir.path(), &mut state, false).await;
16471655
assert_eq!(out.refusals.len(), 1, "{out:?}");
1648-
assert!(out.refusals[0].reason.contains("missing its recorded lines"));
1656+
assert!(out.refusals[0]
1657+
.reason
1658+
.contains("missing its recorded lines"));
16491659
assert_eq!(state.edits.len(), 1);
16501660
assert_eq!(read(dir.path(), "go.sum").await, "x v1 h1:a\n");
16511661
}
@@ -1690,10 +1700,16 @@ mod tests {
16901700
];
16911701
for (path, kind, action, original, new) in cases {
16921702
let dir = TempDir::new().unwrap();
1693-
tokio::fs::create_dir_all(dir.path().join(path)).await.unwrap();
1703+
tokio::fs::create_dir_all(dir.path().join(path))
1704+
.await
1705+
.unwrap();
16941706
let mut state = state_with(vec![edit(path, kind, action, original, new)], &[]);
16951707
let out = revert_remaining_redirect_edits(dir.path(), &mut state, false).await;
1696-
assert_eq!(out.refusals.len(), 1, "{kind}/{action} must refuse: {out:?}");
1708+
assert_eq!(
1709+
out.refusals.len(),
1710+
1,
1711+
"{kind}/{action} must refuse: {out:?}"
1712+
);
16971713
assert!(
16981714
out.refusals[0].reason.starts_with(&format!("read {path}:")),
16991715
"{kind}/{action}: {}",
@@ -1958,7 +1974,10 @@ mod tests {
19581974
);
19591975
let out = revert_remaining_redirect_edits(dir.path(), &mut state, false).await;
19601976
assert_eq!(out.refusals.len(), 1, "{out:?}");
1961-
assert_eq!(out.refusals[0].reason, "composer.lock is not a regular file");
1977+
assert_eq!(
1978+
out.refusals[0].reason,
1979+
"composer.lock is not a regular file"
1980+
);
19621981
assert_eq!(
19631982
read(dir.path(), "real.lock").await,
19641983
"https://patch.example/a\n",

‎crates/socket-patch-core/src/patch/redirect/takeover.rs‎

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,7 +1082,10 @@ mod tests {
10821082
// previews — the whole-ledger replay running after per-purl
10831083
// reverts — must see the post-claim state); the caller owns the
10841084
// clone and never persists it on a dry run.
1085-
assert!(state.records.len() < records_before, "record claimed in memory");
1085+
assert!(
1086+
state.records.len() < records_before,
1087+
"record claimed in memory"
1088+
);
10861089
assert!(state.edits.len() < edits_before, "edits claimed in memory");
10871090

10881091
// The preview names exactly the files a wet run then reverts —
@@ -1901,7 +1904,9 @@ mod tests {
19011904
.and_then(Value::as_object_mut)
19021905
.unwrap();
19031906
entry.remove("name").expect("fixture name field present");
1904-
entry.remove("version").expect("fixture version field present");
1907+
entry
1908+
.remove("version")
1909+
.expect("fixture version field present");
19051910
tokio::fs::write(
19061911
root.join("package-lock.json"),
19071912
serde_json::to_string_pretty(&on_disk).unwrap(),
@@ -2038,9 +2043,7 @@ mod tests {
20382043
.await;
20392044
let root = tmp.path();
20402045
assert_eq!(state.edits.len(), 2, "{:?}", state.edits);
2041-
let scoped_url = npm_dep_for("@scope/left-pad", "1.3.0")
2042-
.artifact_url
2043-
.clone();
2046+
let scoped_url = npm_dep_for("@scope/left-pad", "1.3.0").artifact_url.clone();
20442047
// Hand edit / merge artifact: strip the alias entry's name+version.
20452048
let mut on_disk: Value = serde_json::from_str(
20462049
&tokio::fs::read_to_string(root.join("package-lock.json"))
@@ -2054,7 +2057,9 @@ mod tests {
20542057
.and_then(Value::as_object_mut)
20552058
.unwrap();
20562059
entry.remove("name").expect("fixture name field present");
2057-
entry.remove("version").expect("fixture version field present");
2060+
entry
2061+
.remove("version")
2062+
.expect("fixture version field present");
20582063
tokio::fs::write(
20592064
root.join("package-lock.json"),
20602065
serde_json::to_string_pretty(&on_disk).unwrap(),
@@ -2361,7 +2366,9 @@ mod tests {
23612366
let cfg_before = tokio::fs::read_to_string(root.join(".cargo/config.toml"))
23622367
.await
23632368
.unwrap();
2364-
tokio::fs::remove_file(root.join("Cargo.lock")).await.unwrap();
2369+
tokio::fs::remove_file(root.join("Cargo.lock"))
2370+
.await
2371+
.unwrap();
23652372
let records_before = state.records.len();
23662373
let edits_before = state.edits.len();
23672374

@@ -2515,9 +2522,12 @@ mod tests {
25152522
let wired_toml = tokio::fs::read_to_string(root.join("Cargo.toml"))
25162523
.await
25172524
.unwrap();
2518-
tokio::fs::write(root.join("Cargo.toml"), format!("{wired_toml}{pinned_line}"))
2519-
.await
2520-
.unwrap();
2525+
tokio::fs::write(
2526+
root.join("Cargo.toml"),
2527+
format!("{wired_toml}{pinned_line}"),
2528+
)
2529+
.await
2530+
.unwrap();
25212531

25222532
let out = revert_cargo_redirect_purl(root, &mut state, PURL, false)
25232533
.await
@@ -2627,7 +2637,9 @@ mod tests {
26272637
async fn npm_missing_text_lock_refuses_and_keeps_the_ledger() {
26282638
let (tmp, mut state) = npm_redirected_fixture("yarn.lock", &classic_pristine()).await;
26292639
let root = tmp.path();
2630-
tokio::fs::remove_file(root.join("yarn.lock")).await.unwrap();
2640+
tokio::fs::remove_file(root.join("yarn.lock"))
2641+
.await
2642+
.unwrap();
26312643
let records_before = state.records.len();
26322644
let edits_before = state.edits.len();
26332645

@@ -2821,7 +2833,10 @@ mod tests {
28212833
let err = revert_npm_redirect_purl(root, &mut state, NPM_PURL, false)
28222834
.await
28232835
.expect_err("vanished v2 tree must refuse");
2824-
assert!(err.contains("no longer holds a `dependencies` tree"), "{err}");
2836+
assert!(
2837+
err.contains("no longer holds a `dependencies` tree"),
2838+
"{err}"
2839+
);
28252840
let after = tokio::fs::read_to_string(root.join("package-lock.json"))
28262841
.await
28272842
.unwrap();

0 commit comments

Comments
 (0)