GeezerVison is showing github.com — Fix: Preserve stage on swap failure to prevent destroying live vendor… · SocketDev/socket-patch@fc2d1f9
File treeExpand file treeCollapse file tree Open diff view settings socket-patch-core/src/vendor
Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: crates/socket-patch-cli/src/commands/get.rs +5-5Lines changed: 5 additions & 5 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -1232,10 +1232,7 @@ pub async fn download_and_apply_patches( | 1232 | 1232 | // status/exit code degrade and it is never auto-applied. | 1233 | 1233 | if files.is_empty() { | 1234 | 1234 | if !params.json && !params.silent { | 1235 | | - eprintln!( | 1236 | | - " [fail] {} (patch has no applicable files)", | 1237 | | - patch.purl | 1238 | | - ); | | 1235 | + eprintln!(" [fail] {} (patch has no applicable files)", patch.purl); | 1239 | 1236 | } | 1240 | 1237 | downloaded_patches.push(serde_json::json!({ | 1241 | 1238 | "purl": patch.purl, | @@ -3106,7 +3103,10 @@ mod tests { | 3106 | 3103 | // record — the guardrail-triggering condition the download/apply | 3107 | 3104 | // flows now count as failed rather than applied. | 3108 | 3105 | let mut broken = HashMap::new(); | 3109 | | - broken.insert("src/lib.rs".to_string(), file_resp(Some(&"e".repeat(64)), None)); | | 3106 | + broken.insert( | | 3107 | + "src/lib.rs".to_string(), | | 3108 | + file_resp(Some(&"e".repeat(64)), None), | | 3109 | + ); | 3110 | 3110 | let broken_patch = patch_with_files(broken); | 3111 | 3111 | assert!( | 3112 | 3112 | files_for_manifest(&broken_patch).is_empty(), | |
Collapse file Copy file name to clipboardExpand all lines: crates/socket-patch-cli/src/commands/scan/hosted.rs +3-1Lines changed: 3 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -529,7 +529,9 @@ pub(super) async fn run_redirect( | 529 | 529 | // deleting the other mode's ledger; reconciliation is deferred (see PR Scope). | 530 | 530 | // Read after the ledger write above so a non-dry-run reflects this run. | 531 | 531 | let mut takeover_warnings: Vec<serde_json::Value> = Vec::new(); | 532 | | - let superseded = super::classify_overlap_takeover(&args.common.cwd).await.redirect; | | 532 | + let superseded = super::classify_overlap_takeover(&args.common.cwd) | | 533 | + .await | | 534 | + .redirect; | 533 | 535 | if !superseded.is_empty() { | 534 | 536 | takeover_warnings.push(serde_json::json!({ | 535 | 537 | "code": super::REDIRECT_SUPERSEDES_VENDORED, | |
Collapse file Copy file name to clipboardExpand all lines: crates/socket-patch-cli/src/commands/scan/mod.rs +15-5Lines changed: 15 additions & 5 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -520,11 +520,15 @@ pub(super) async fn classify_overlap_takeover(cwd: &Path) -> OverlapTakeover { | 520 | 520 | return out; | 521 | 521 | }; | 522 | 522 | let canon = |p: &str| normalize_purl(strip_purl_qualifiers(p)).into_owned(); | 523 | | - let mut vendor_by_purl: std::collections::HashMap<String, &socket_patch_core::vendor::VendorEntry> = | 524 | | - std::collections::HashMap::new(); | | 523 | + let mut vendor_by_purl: std::collections::HashMap< | | 524 | + String, | | 525 | + &socket_patch_core::vendor::VendorEntry, | | 526 | + > = std::collections::HashMap::new(); | 525 | 527 | for (key, entry) in &vendor.entries { | 526 | 528 | vendor_by_purl.entry(canon(key)).or_insert(entry); | 527 | | - vendor_by_purl.entry(canon(&entry.base_purl)).or_insert(entry); | | 529 | + vendor_by_purl | | 530 | + .entry(canon(&entry.base_purl)) | | 531 | + .or_insert(entry); | 528 | 532 | } | 529 | 533 | // The scan inventory keeps only http(s) `resolved` URLs and DROPS our own | 530 | 534 | // `file:.socket/vendor/…` specs (see `lock_inventory`), so a | @@ -2095,7 +2099,10 @@ mod tests { | 2095 | 2099 | "hosted flow must not warn when the lock is vendored: {takeover:?}" | 2096 | 2100 | ); | 2097 | 2101 | // Truthful direction: vendored won ⇒ the redirect ledger is the stale one. | 2098 | | - | | 2102 | + assert_eq!( | | 2103 | + takeover.vendored, | | 2104 | + | | 2105 | + ); | 2099 | 2106 | // Pre-fix the hosted flow keyed off the raw overlap, which is non-empty | 2100 | 2107 | // — it WOULD have wrongly told the user to delete the live ledger. | 2101 | 2108 | assert!(!overlapping_ledger_purls(root).await.is_empty()); | @@ -2119,7 +2126,10 @@ mod tests { | 2119 | 2126 | "vendored flow must not warn when the lock is hosted: {takeover:?}" | 2120 | 2127 | ); | 2121 | 2128 | // Truthful direction: hosted won ⇒ the vendored ledger is the stale one. | 2122 | | - | | 2129 | + assert_eq!( | | 2130 | + takeover.redirect, | | 2131 | + | | 2132 | + ); | 2123 | 2133 | } | 2124 | 2134 |
| 2125 | 2135 | #[tokio::test] | |
Collapse file Copy file name to clipboardExpand all lines: crates/socket-patch-cli/src/update_notifier.rs +8-2Lines changed: 8 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -445,9 +445,15 @@ mod tests { | 445 | 445 | // ceiling — the override never silently changes shipped behavior. | 446 | 446 | assert_eq!(grace_budget_from(None), Duration::from_millis(500)); | 447 | 447 | assert_eq!(grace_budget_from(Some("")), Duration::from_millis(500)); | 448 | | - assert_eq!(grace_budget_from(Some("not-a-number")), Duration::from_millis(500)); | | 448 | + assert_eq!( | | 449 | + grace_budget_from(Some("not-a-number")), | | 450 | + Duration::from_millis(500) | | 451 | + ); | 449 | 452 | // A valid value lifts the ceiling (the e2e suite's escape hatch). | 450 | | - assert_eq!(grace_budget_from(Some("30000")), Duration::from_millis(30_000)); | | 453 | + assert_eq!( | | 454 | + grace_budget_from(Some("30000")), | | 455 | + Duration::from_millis(30_000) | | 456 | + ); | 451 | 457 | assert_eq!(grace_budget_from(Some("0")), Duration::from_millis(0)); | 452 | 458 | } | 453 | 459 |
| |
Collapse file Copy file name to clipboardExpand all lines: crates/socket-patch-cli/tests/e2e_vendored_production.rs +47-14Lines changed: 47 additions & 14 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -316,7 +316,9 @@ fn scan_vendored(cwd: &Path, extra: &[&str]) -> serde_json::Value { | 316 | 316 | "scan --mode vendored failed (exit {code}).\nstdout:\n{stdout}\nstderr:\n{stderr}" | 317 | 317 | ); | 318 | 318 | let env: serde_json::Value = serde_json::from_str(stdout.trim()).unwrap_or_else(|e| { | 319 | | - panic!("scan --mode vendored did not emit JSON ({e}).\nstdout:\n{stdout}\nstderr:\n{stderr}") | | 319 | + panic!( | | 320 | + "scan --mode vendored did not emit JSON ({e}).\nstdout:\n{stdout}\nstderr:\n{stderr}" | | 321 | + ) | 320 | 322 | }); | 321 | 323 | assert_eq!( | 322 | 324 | env["status"].as_str(), | @@ -385,8 +387,16 @@ fn assert_download_uuid(env: &serde_json::Value, uuids: &[&str], leg: &str) { | 385 | 387 | /// `vendor --revert --json` in `cwd`, asserting success and returning the | 386 | 388 | /// number of reverted entries. | 387 | 389 | fn vendor_revert(cwd: &Path, leg: &str) -> u64 { | 388 | | - let (code, stdout, stderr) = | 389 | | - run_socket(cwd, &["vendor", "--revert", "--json", "--cwd", cwd.to_str().unwrap()]); | | 390 | + let (code, stdout, stderr) = run_socket( | | 391 | + cwd, | | 392 | + &[ | | 393 | + "vendor", | | 394 | + "--revert", | | 395 | + "--json", | | 396 | + "--cwd", | | 397 | + cwd.to_str().unwrap(), | | 398 | + ], | | 399 | + ); | 390 | 400 | assert_eq!( | 391 | 401 | code, 0, | 392 | 402 | "{leg}: vendor --revert failed (exit {code}).\nstdout:\n{stdout}\nstderr:\n{stderr}" | @@ -730,7 +740,11 @@ fn npm_package_lock_vendored_install_proof() { | 730 | 740 | let fresh = tmp.path().join("fresh"); | 731 | 741 | std::fs::create_dir_all(&fresh).unwrap(); | 732 | 742 | std::fs::copy(proj.join("package.json"), fresh.join("package.json")).unwrap(); | 733 | | - std::fs::copy(proj.join("package-lock.json"), fresh.join("package-lock.json")).unwrap(); | | 743 | + std::fs::copy( | | 744 | + proj.join("package-lock.json"), | | 745 | + fresh.join("package-lock.json"), | | 746 | + ) | | 747 | + .unwrap(); | 734 | 748 | copy_dir_recursive(&proj.join(".socket"), &fresh.join(".socket")); | 735 | 749 |
| 736 | 750 | let fresh_cache = tmp.path().join("fresh-npm-cache").display().to_string(); | @@ -1327,7 +1341,11 @@ fn pypi_requirements_txt_vendored_install_proof() { | 1327 | 1341 | // from the project root (bare relative paths resolve against the CWD). | 1328 | 1342 | let fresh = tmp.path().join("fresh"); | 1329 | 1343 | std::fs::create_dir_all(&fresh).unwrap(); | 1330 | | - std::fs::copy(proj.join("requirements.txt"), fresh.join("requirements.txt")).unwrap(); | | 1344 | + std::fs::copy( | | 1345 | + proj.join("requirements.txt"), | | 1346 | + fresh.join("requirements.txt"), | | 1347 | + ) | | 1348 | + .unwrap(); | 1331 | 1349 | copy_dir_recursive(&proj.join(".socket"), &fresh.join(".socket")); | 1332 | 1350 | let fresh_venv = fresh.join(".venv"); | 1333 | 1351 | assert!( | @@ -1415,7 +1433,11 @@ fn pypi_uv_lock_vendored_install_proof() { | 1415 | 1433 | } | 1416 | 1434 | let venv = proj.join(".venv"); | 1417 | 1435 | let Some(site) = site_packages(&venv) else { | 1418 | | - soft_skip!(LEG, "could not locate site-packages under {}", venv.display()); | | 1436 | + soft_skip!( | | 1437 | + LEG, | | 1438 | + "could not locate site-packages under {}", | | 1439 | + venv.display() | | 1440 | + ); | 1419 | 1441 | }; | 1420 | 1442 | assert!( | 1421 | 1443 | !urllib3_patched(&site), | @@ -1551,7 +1573,9 @@ fn cargo_vendored_install_proof() { | 1551 | 1573 |
| 1552 | 1574 | // Vendored directory carries the patch; the registry source stays pristine. | 1553 | 1575 | let vendored_lib = proj | 1554 | | - .join(format!(".socket/vendor/cargo/{CARGO_UUID}/{CARGO_NAME}-{CARGO_VERSION}")) | | 1576 | + .join(format!( | | 1577 | + ".socket/vendor/cargo/{CARGO_UUID}/{CARGO_NAME}-{CARGO_VERSION}" | | 1578 | + )) | 1555 | 1579 | .join("src/lib.rs"); | 1556 | 1580 | assert_patched(&vendored_lib, CARGO_MARKER, LEG); | 1557 | 1581 | if let Some(ref lib) = registry_lib { | @@ -1745,7 +1769,9 @@ fn gem_bundler_vendored_known_platform_defect() { | 1745 | 1769 | .map(|v| v == "1" || v.eq_ignore_ascii_case("true")) | 1746 | 1770 | .unwrap_or(false); | 1747 | 1771 |
| 1748 | | - let applied = env_json["vendor"]["summary"]["applied"].as_u64().unwrap_or(0); | | 1772 | + let applied = env_json["vendor"]["summary"]["applied"] | | 1773 | + .as_u64() | | 1774 | + .unwrap_or(0); | 1749 | 1775 | if code == 0 && applied >= 1 { | 1750 | 1776 | // The CLI now vendors platform gems. Say so loudly — this leg should be | 1751 | 1777 | // promoted to a full delivery proof (bundle install frozen) and this | @@ -1759,10 +1785,13 @@ fn gem_bundler_vendored_known_platform_defect() { | 1759 | 1785 | } | 1760 | 1786 |
| 1761 | 1787 | // Otherwise: it must be exactly the known `platform_gem_unsupported` failure. | 1762 | | - let events = env_json["vendor"]["events"].as_array().cloned().unwrap_or_default(); | 1763 | | - let is_known = events.iter().any(|e| { | 1764 | | - e["action"] == "failed" && e["errorCode"] == "platform_gem_unsupported" | 1765 | | - }); | | 1788 | + let events = env_json["vendor"]["events"] | | 1789 | + .as_array() | | 1790 | + .cloned() | | 1791 | + .unwrap_or_default(); | | 1792 | + let is_known = events | | 1793 | + .iter() | | 1794 | + .any(|e| e["action"] == "failed" && e["errorCode"] == "platform_gem_unsupported"); | 1766 | 1795 | assert!( | 1767 | 1796 | !gem_strict, | 1768 | 1797 | "{LEG}: SOCKET_PATCH_VENDORED_E2E_GEM_STRICT=1 and vendoring {GEM_PURL} did not succeed \ | @@ -1809,7 +1838,9 @@ fn golang_vendored_finds_no_free_patches() { | 1809 | 1838 | .expect("write go.mod"); | 1810 | 1839 |
| 1811 | 1840 | let env_json = scan_vendored(&proj, &["--ecosystems", "golang"]); | 1812 | | - let applied = env_json["vendor"]["summary"]["applied"].as_u64().unwrap_or(0); | | 1841 | + let applied = env_json["vendor"]["summary"]["applied"] | | 1842 | + .as_u64() | | 1843 | + .unwrap_or(0); | 1813 | 1844 | assert_eq!( | 1814 | 1845 | applied, 0, | 1815 | 1846 | "{LEG}: golang vendored something, but production publishes no free golang patches. \ | @@ -1849,7 +1880,9 @@ fn deno_vendored_is_unsupported() { | 1849 | 1880 | .expect("write deno.json"); | 1850 | 1881 |
| 1851 | 1882 | let env_json = scan_vendored(&proj, &["--ecosystems", "deno"]); | 1852 | | - let applied = env_json["vendor"]["summary"]["applied"].as_u64().unwrap_or(0); | | 1883 | + let applied = env_json["vendor"]["summary"]["applied"] | | 1884 | + .as_u64() | | 1885 | + .unwrap_or(0); | 1853 | 1886 | assert_eq!( | 1854 | 1887 | applied, 0, | 1855 | 1888 | "{LEG}: deno vendored something, but vendored mode is not supported for deno:\n{env_json:#}" | |
Collapse file Copy file name to clipboardExpand all lines: crates/socket-patch-cli/tests/ecosystem_dispatch_e2e.rs +1-4Lines changed: 1 addition & 4 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -788,10 +788,7 @@ fn rollback_dispatch_branch_maven() { | 788 | 788 | let fixture = RollbackFixture { | 789 | 789 | purl: purl.to_string(), | 790 | 790 | verify_file, | 791 | | - envs: vec![( | 792 | | - "MAVEN_REPO_LOCAL".to_string(), | 793 | | - repo.display().to_string(), | 794 | | - )], | | 791 | + envs: vec![("MAVEN_REPO_LOCAL".to_string(), repo.display().to_string())], | 795 | 792 | global: false, | 796 | 793 | }; | 797 | 794 | assert_rollback_restored(root, "maven", &fixture); | |
Collapse file Copy file name to clipboardExpand all lines: crates/socket-patch-cli/tests/update_notifier_e2e.rs +25-10Lines changed: 25 additions & 10 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -132,8 +132,11 @@ async fn first_eligible_run_checks_and_notices() { | 132 | 132 | .mount() | 133 | 133 | .await; | 134 | 134 |
| 135 | | - let (code, stdout, stderr) = | 136 | | - run_installed(&install, &["apply"], &eligible_kit_await_fetch(&release.base_url)); | | 135 | + let (code, stdout, stderr) = run_installed( | | 136 | + &install, | | 137 | + &["apply"], | | 138 | + &eligible_kit_await_fetch(&release.base_url), | | 139 | + ); | 137 | 140 | assert_eq!(code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); | 138 | 141 | assert!( | 139 | 142 | stderr.contains("Update available") && stderr.contains("9.9.9"), | @@ -196,8 +199,11 @@ async fn stale_state_rechecks() { | 196 | 199 | .await; | 197 | 200 | write_state(&install.state_dir, STALE, Some(CURRENT), None); | 198 | 201 |
| 199 | | - let (code, stdout, stderr) = | 200 | | - run_installed(&install, &["apply"], &eligible_kit_await_fetch(&release.base_url)); | | 202 | + let (code, stdout, stderr) = run_installed( | | 203 | + &install, | | 204 | + &["apply"], | | 205 | + &eligible_kit_await_fetch(&release.base_url), | | 206 | + ); | 201 | 207 | assert_eq!(code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); | 202 | 208 |
| 203 | 209 | let state = read_state(&install.state_dir); | @@ -225,8 +231,11 @@ async fn up_to_date_prints_nothing() { | 225 | 231 | .await; | 226 | 232 | write_state(&install.state_dir, STALE, Some(CURRENT), None); | 227 | 233 |
| 228 | | - let (code, _, stderr) = | 229 | | - run_installed(&install, &["apply"], &eligible_kit_await_fetch(&release.base_url)); | | 234 | + let (code, _, stderr) = run_installed( | | 235 | + &install, | | 236 | + &["apply"], | | 237 | + &eligible_kit_await_fetch(&release.base_url), | | 238 | + ); | 230 | 239 | assert_eq!(code, 0); | 231 | 240 | assert!( | 232 | 241 | !stderr.contains("Update available"), | @@ -288,8 +297,11 @@ async fn corrupt_state_recovers() { | 288 | 297 | ) | 289 | 298 | .unwrap(); | 290 | 299 |
| 291 | | - let (code, stdout, stderr) = | 292 | | - run_installed(&install, &["apply"], &eligible_kit_await_fetch(&release.base_url)); | | 300 | + let (code, stdout, stderr) = run_installed( | | 301 | + &install, | | 302 | + &["apply"], | | 303 | + &eligible_kit_await_fetch(&release.base_url), | | 304 | + ); | 293 | 305 | assert_eq!(code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); | 294 | 306 | assert!( | 295 | 307 | !stderr.contains("panicked"), | @@ -316,8 +328,11 @@ async fn future_timestamp_tolerated() { | 316 | 328 | .await; | 317 | 329 | write_state(&install.state_dir, -48 * HOUR, Some("9.9.9"), None); | 318 | 330 |
| 319 | | - let (code, stdout, stderr) = | 320 | | - run_installed(&install, &["apply"], &eligible_kit_await_fetch(&release.base_url)); | | 331 | + let (code, stdout, stderr) = run_installed( | | 332 | + &install, | | 333 | + &["apply"], | | 334 | + &eligible_kit_await_fetch(&release.base_url), | | 335 | + ); | 321 | 336 | assert_eq!(code, 0, "stdout:\n{stdout}\nstderr:\n{stderr}"); | 322 | 337 | assert_install_pristine(&install); | 323 | 338 | } | |
Collapse file Copy file name to clipboardExpand all lines: crates/socket-patch-core/src/vendor/cargo.rs +21-11Lines changed: 21 additions & 11 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -98,13 +98,19 @@ fn stage_dir_for(copy_dir: &Path) -> std::path::PathBuf { | 98 | 98 | } | 99 | 99 | } | 100 | 100 |
| 101 | | -/// Swap a fully-built stage into place: remove the old copy (if any), then | 102 | | -/// rename the stage over it. The rename is same-directory and only happens | 103 | | -/// after the stage passed every check, so the destroy-then-replace window is | 104 | | -/// as small as the filesystem allows. | | 101 | +/// Swap a fully-built stage into place: rename the stage over the old copy. | | 102 | +/// The rename is same-directory and only happens after the stage passed every | | 103 | +/// check. Try the rename first (may succeed atomically on Unix); if that fails, | | 104 | +/// remove the old copy and retry. If the retry fails, the stage is left intact | | 105 | +/// so a valid replacement exists for recovery. | 105 | 106 | async fn swap_stage_into_place(stage: &Path, copy_dir: &Path) -> std::io::Result<()> { | 106 | | - remove_tree(copy_dir).await?; | 107 | | - tokio::fs::rename(stage, copy_dir).await | | 107 | + match tokio::fs::rename(stage, copy_dir).await { | | 108 | + Ok(()) => Ok(()), | | 109 | + Err(_) => { | | 110 | + remove_tree(copy_dir).await?; | | 111 | + tokio::fs::rename(stage, copy_dir).await | | 112 | + } | | 113 | + } | 108 | 114 | } | 109 | 115 |
| 110 | 116 | /// Best-effort removal of an EMPTY `<uuid>/` dir plus the empty | @@ -224,7 +230,6 @@ async fn cargo_service_copy( | 224 | 230 | ); | 225 | 231 | } | 226 | 232 | if let Err(e) = swap_stage_into_place(&stage, copy_dir).await { | 227 | | - cleanup_failed_stage(&stage, uuid_dir, false).await; | 228 | 233 | return hard( | 229 | 234 | "vendor_prebuilt_write_failed", | 230 | 235 | format!("cannot move the extracted crate into place: {e}"), | @@ -322,7 +327,6 @@ async fn copy_and_patch( | 322 | 327 | } | 323 | 328 | let _ = tokio::fs::remove_file(stage.join(".cargo-checksum.json")).await; | 324 | 329 | if let Err(e) = swap_stage_into_place(&stage, copy_dir).await { | 325 | | - cleanup_failed_stage(&stage, uuid_dir, unwind_uuid_dir).await; | 326 | 330 | result.success = false; | 327 | 331 | result.error = Some(format!("failed to move the rebuilt copy into place: {e}")); | 328 | 332 | return Err(result); | @@ -1305,7 +1309,9 @@ mod tests { | 1305 | 1309 | "marker must survive" | 1306 | 1310 | ); | 1307 | 1311 | assert_eq!( | 1308 | | - tokio::fs::read(root.join(".cargo/config.toml")).await.unwrap(), | | 1312 | + tokio::fs::read(root.join(".cargo/config.toml")) | | 1313 | + .await | | 1314 | + .unwrap(), | 1309 | 1315 | cfg1, | 1310 | 1316 | "config untouched" | 1311 | 1317 | ); | @@ -1372,7 +1378,9 @@ mod tests { | 1372 | 1378 | [[package]]\nname = \"cfg-if\"\nversion = \"1.0.4\"\nsource = \"{SOURCE}\"\nchecksum = \"{CHECKSUM}\"\n\n\ | 1373 | 1379 | [[package]]\nname = \"cfg-if\"\nversion = \"1.0.4\"\nsource = \"git+https://example.com/fork/cfg-if#abcdef\"\n" | 1374 | 1380 | ); | 1375 | | - tokio::fs::write(root.join("Cargo.lock"), &lock).await.unwrap(); | | 1381 | + tokio::fs::write(root.join("Cargo.lock"), &lock) | | 1382 | + .await | | 1383 | + .unwrap(); | 1376 | 1384 |
| 1377 | 1385 | let detail = expect_refused( | 1378 | 1386 | run_vendor(PURL, root, &blobs, &pristine, &record, false).await, | @@ -1399,7 +1407,9 @@ mod tests { | 1399 | 1407 | async fn test_refuses_user_entry_through_foreign_socket_dir() { | 1400 | 1408 | let (dir, blobs, pristine, record) = fixture().await; | 1401 | 1409 | let root = dir.path(); | 1402 | | - tokio::fs::create_dir_all(root.join(".cargo")).await.unwrap(); | | 1410 | + tokio::fs::create_dir_all(root.join(".cargo")) | | 1411 | + .await | | 1412 | + .unwrap(); | 1403 | 1413 | let user_cfg = format!( | 1404 | 1414 | "[patch.crates-io]\ncfg-if = {{ path = \"../shared-fork/.socket/vendor/cargo/{UUID2}/cfg-if-1.0.4\" }}\n" | 1405 | 1415 | ); | |
|