GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix(cargo): fully migrate hosted<->vendored modes (C1-C7) (#196) · SocketDev/socket-patch@3f44056

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • crates
    • socket-patch-cli
      • src/commands
        • scan
          • hosted.rs
          • mod.rs
          • vendor_flow.rs
        • vendor.rs
      • tests
        • mode_migration_cargo.rs
    • socket-patch-core/src
      • patch/redirect
        • mod.rs
        • state.rs
        • takeover.rs
      • vendor
        • cargo.rs
        • cargo_config.rs
        • cargo_lock.rs
        • mod.rs
        • state.rs
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎crates/socket-patch-cli/src/commands/scan/hosted.rs‎

Copy file name to clipboardExpand all lines: crates/socket-patch-cli/src/commands/scan/hosted.rs
+173-9Lines changed: 173 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -247,15 +247,15 @@ pub(super) async fn run_redirect(
247247
}
248248
}
249249

250-
// Load the existing redirect ledger BEFORE any file is written — bun
251-
// migration included. The ledger is the only store of the pre-redirect
252-
// originals a future revert needs, so a malformed (torn/hand-mangled)
253-
// ledger must abort the run while the project is still untouched: the old
254-
// tolerant load treated it as "no ledger" and the merge below would have
255-
// started fresh, silently overwriting that revert data. The malformed
256-
// file is moved aside to redirect-state.json.corrupt (never clobbered)
257-
// so recovery stays possible; a dry-run reports the same hard error but
258-
// moves nothing.
250+
// Load the existing redirect ledger BEFORE any file is written — the
251+
// cargo takeover reverts and the bun migration included. The ledger is
252+
// the only store of the pre-redirect originals a future revert needs, so
253+
// a malformed (torn/hand-mangled) ledger must abort the run while the
254+
// project is still untouched: the old tolerant load treated it as "no
255+
// ledger" and the merge below would have started fresh, silently
256+
// overwriting that revert data. The malformed file is moved aside to
257+
// redirect-state.json.corrupt (never clobbered) so recovery stays
258+
// possible; a dry-run reports the same hard error but moves nothing.
259259
let existing_ledger =
260260
match socket_patch_core::patch::redirect::load_redirect_state(&args.common.cwd).await {
261261
Ok(state) => state,
@@ -272,6 +272,166 @@ pub(super) async fn run_redirect(
272272
}
273273
};
274274

275+
// Cross-mode takeover (cargo): a purl this run is about to redirect may
276+
// still be VENDORED — a committed `[patch.crates-io]` path entry, a
277+
// detached Cargo.lock entry, a committed copy, and a vendored ledger
278+
// entry. The hosted rewriters know nothing about that wiring, so
279+
// redirecting on top of it would leave BOTH wirings in place and cargo
280+
// then refuses every `--locked` build over the now-unused `[patch]`
281+
// entry while this run reports success. A takeover must leave the
282+
// project FULLY hosted: revert each such purl's vendored state first
283+
// (the exact per-purl machinery `vendor --revert` runs — restore the
284+
// lock originals from the ledger, drop the `[patch]` entry, remove the
285+
// committed tree and the ledger entry), and only then redirect. This
286+
// ordering also hands the redirect the PRISTINE crates.io lock fragment
287+
// to record as its own revert original, keeping the originals chain
288+
// intact across repeated mode migrations. A purl whose vendored state
289+
// cannot be cleanly reverted (revert failure, or vendored wiring with a
290+
// missing/corrupt ledger) is REFUSED — skipped with an actionable
291+
// error — never half-migrated.
292+
let mut takeover_pre_warnings: Vec<serde_json::Value> = Vec::new();
293+
if !candidates.iter().any(|(p, ..)| p.starts_with("pkg:cargo/")) {
294+
// No cargo candidates — nothing to reconcile.
295+
} else {
296+
use socket_patch_core::utils::purl::{normalize_purl, strip_purl_qualifiers};
297+
let canon = |p: &str| normalize_purl(strip_purl_qualifiers(p)).into_owned();
298+
let vendor_state = socket_patch_core::vendor::load_state(&args.common.cwd).await;
299+
let patch_entries =
300+
socket_patch_core::vendor::cargo_config::read_patch_entries(&args.common.cwd).await;
301+
let mut refused: Vec<String> = Vec::new();
302+
for (purl, _uuid, ..) in &candidates {
303+
if !purl.starts_with("pkg:cargo/") {
304+
continue;
305+
}
306+
let stripped = strip_purl_qualifiers(purl);
307+
let ledger_entry = vendor_state
308+
.as_ref()
309+
.ok()
310+
.and_then(|s| socket_patch_core::vendor::lookup_entry(&s.entries, stripped))
311+
.cloned();
312+
if let Some(entry) = ledger_entry {
313+
if args.common.dry_run {
314+
takeover_pre_warnings.push(serde_json::json!({
315+
"code": "redirect_would_revert_vendored",
316+
"detail": format!(
317+
"{purl} is currently vendored; the hosted redirect will \
318+
revert its vendored wiring, ledger entry, and committed \
319+
artifact first, then redirect (mode takeover)"
320+
),
321+
}));
322+
continue;
323+
}
324+
let outcome =
325+
crate::commands::vendor::dispatch_revert_one(&entry, &args.common.cwd, false)
326+
.await;
327+
if !outcome.success {
328+
refused.push(purl.clone());
329+
takeover_pre_warnings.push(serde_json::json!({
330+
"code": "redirect_vendored_revert_failed",
331+
"detail": format!(
332+
"{purl} is vendored and its vendored state could not be \
333+
reverted ({}); NOT redirected — run `socket-patch vendor \
334+
--revert` to clean up, then re-run `scan --mode hosted`",
335+
outcome.error.as_deref().unwrap_or("unknown error")
336+
),
337+
}));
338+
continue;
339+
}
340+
// Drop the reverted entry and persist per purl so a crash
341+
// mid-run leaves a ledger matching the on-disk wiring.
342+
// Re-loaded fresh each iteration (each iteration saves): the
343+
// saved file is the truth.
344+
let mut state = match socket_patch_core::vendor::load_state(&args.common.cwd).await
345+
{
346+
Ok(s) => s,
347+
Err(e) => {
348+
refused.push(purl.clone());
349+
takeover_pre_warnings.push(serde_json::json!({
350+
"code": "redirect_vendored_revert_failed",
351+
"detail": format!(
352+
"{purl}: vendored wiring reverted but the vendored \
353+
ledger could not be re-read ({e}); NOT redirected — \
354+
fix .socket/vendor/state.json and re-run"
355+
),
356+
}));
357+
continue;
358+
}
359+
};
360+
state
361+
.entries
362+
.retain(|k, e| canon(k) != canon(purl) && canon(&e.base_purl) != canon(purl));
363+
if let Err(e) =
364+
socket_patch_core::vendor::save_state(&args.common.cwd, &state).await
365+
{
366+
// The wiring is reverted but the ledger still claims it;
367+
// redirecting now would leave a ledger asserting wiring
368+
// that is gone. Fail closed for this purl.
369+
refused.push(purl.clone());
370+
takeover_pre_warnings.push(serde_json::json!({
371+
"code": "redirect_vendored_revert_failed",
372+
"detail": format!(
373+
"{purl}: vendored wiring reverted but the vendored ledger \
374+
could not be updated ({e}); NOT redirected — fix \
375+
.socket/vendor/state.json and re-run"
376+
),
377+
}));
378+
continue;
379+
}
380+
takeover_pre_warnings.push(serde_json::json!({
381+
"code": "redirect_takeover_reverted_vendored",
382+
"detail": format!(
383+
"{purl} was vendored; reverted its vendored wiring, ledger \
384+
entry, and committed artifact before redirecting (mode \
385+
takeover: the project is now fully hosted for this package)"
386+
),
387+
}));
388+
} else {
389+
// No usable ledger entry. If socket-owned vendored wiring for
390+
// this crate is nevertheless present, the ledger is missing or
391+
// corrupt — the originals needed to revert are unrecoverable,
392+
// so redirecting on top would wedge the project. Refuse.
393+
let name = parse_purl_simple(purl).map(|(_, name, _)| name);
394+
let wired = name
395+
.as_deref()
396+
.is_some_and(|n| patch_entries.get(n).is_some_and(|i| i.socket_owned));
397+
if wired {
398+
refused.push(purl.clone());
399+
takeover_pre_warnings.push(serde_json::json!({
400+
"code": "redirect_vendored_revert_failed",
401+
"detail": format!(
402+
"{purl} has socket-owned vendored wiring in \
403+
.cargo/config.toml but no usable vendored ledger entry \
404+
(.socket/vendor/state.json is missing or corrupt); NOT \
405+
redirected — restore the ledger or remove the vendored \
406+
wiring manually, then re-run"
407+
),
408+
}));
409+
}
410+
}
411+
}
412+
if !refused.is_empty() {
413+
for purl in &refused {
414+
if let Some((_, uuid, ..)) = candidates.iter().find(|(p, ..)| p == purl) {
415+
skipped.push(serde_json::json!({
416+
"purl": purl, "uuid": uuid, "reason": "vendored_revert_failed",
417+
}));
418+
}
419+
}
420+
let refused_names: std::collections::HashSet<(String, String)> = candidates
421+
.iter()
422+
.filter(|(p, ..)| refused.contains(p))
423+
.filter_map(|(p, ..)| {
424+
parse_purl_simple(p).map(|(_, name, version)| (name, version))
425+
})
426+
.collect();
427+
candidates.retain(|(p, ..)| !refused.contains(p));
428+
overrides.retain(|o| {
429+
o.ecosystem != "cargo"
430+
|| !refused_names.contains(&(o.name.clone(), o.version.clone()))
431+
});
432+
}
433+
}
434+
275435
// bun.lockb auto-migration: the redirect rewriter only edits the TEXT
276436
// lockfile, so a project locked to a binary `bun.lockb` must be re-locked
277437
// to `bun.lock` first. `bun install --save-text-lockfile --frozen-lockfile
@@ -700,6 +860,7 @@ pub(super) async fn run_redirect(
700860
warnings.extend(migration_warnings.iter().cloned());
701861
warnings.extend(rush_warnings.iter().cloned());
702862
warnings.extend(pnpm_warnings.iter().cloned());
863+
warnings.extend(takeover_pre_warnings.iter().cloned());
703864
warnings.extend(takeover_warnings.iter().cloned());
704865
warnings.extend(prune_warnings.iter().cloned());
705866
// Nest the redirect result under `redirect` inside the classic scan
@@ -772,6 +933,9 @@ pub(super) async fn run_redirect(
772933
for w in &pnpm_warnings {
773934
eprintln!(" warning: {}", w["detail"].as_str().unwrap_or_default());
774935
}
936+
for w in &takeover_pre_warnings {
937+
eprintln!(" warning: {}", w["detail"].as_str().unwrap_or_default());
938+
}
775939
for w in &takeover_warnings {
776940
eprintln!(" warning: {}", w["detail"].as_str().unwrap_or_default());
777941
}

0 commit comments

Comments
0 (0)
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.