@@ -1743,7 +1743,11 @@ type LockRefusals = HashMap<String, (&'static str, String)>;
17431743/// refusal and the ledger's idempotency skip, which take precedence in the
17441744/// fetch loop. A purl the lockfiles pin hosted is left to the vendor loop:
17451745/// its takeover restores the upstream lock entry first, and the restore
1746- /// rewrites the very text the gates read.
1746+ /// rewrites the very text the gates read. The one exception is a hosted
1747+ /// gem the takeover would refuse ([`gem_takeover_refusals_for`]), which
1748+ /// is refused here with the takeover's code instead of after its fetch.
1749+ ///
1750+ /// [`gem_takeover_refusals_for`]: crate::commands::vendor::gem_takeover_refusals_for
17471751///
17481752/// Only a package the vendor loop would hand to its backend is refused
17491753/// here (see [`crate::commands::vendor::lock_refusals_reaching_backend`]):
@@ -1760,44 +1764,65 @@ async fn lock_text_refusals_for(
17601764 prior : Option < & crate :: ecosystem_dispatch:: NpmCrawlSnapshot > ,
17611765) -> LockRefusals {
17621766 let cwd = params. cwd . as_path ( ) ;
1763- let claimed: Vec < String > = socket_patch_core:: patch:: redirect:: upstream:: HostedPin :: all (
1767+ let origins: Vec < String > = params
1768+ . patch_server_url
1769+ . iter ( )
1770+ . filter ( |url| !url. trim ( ) . is_empty ( ) )
1771+ . cloned ( )
1772+ . collect ( ) ;
1773+ let pins = socket_patch_core:: patch:: redirect:: upstream:: HostedPin :: all (
17641774 & socket_patch_core:: vex:: discover_patched_refs_with (
17651775 cwd,
17661776 & socket_patch_core:: vex:: DiscoverOptions {
1767- patch_server_origins : params
1768- . patch_server_url
1769- . iter ( )
1770- . filter ( |url| !url. trim ( ) . is_empty ( ) )
1771- . cloned ( )
1772- . collect ( ) ,
1777+ patch_server_origins : origins. clone ( ) ,
17731778 } ,
17741779 )
17751780 . await ,
1776- )
1777- . into_iter ( )
1778- . map ( |pin| canonical_purl ( & pin. purl ) )
1779- . collect ( ) ;
1780- let candidates: Vec < ( & str , & str ) > = selected
1781+ ) ;
1782+ let claimed: Vec < String > = pins. iter ( ) . map ( |pin| canonical_purl ( & pin. purl ) ) . collect ( ) ;
1783+ let fetchable: Vec < & PatchSearchResult > = selected
17811784 . iter ( )
17821785 . filter ( |sr| bun_refusal. filter ( |r| r. applies_to ( & sr. purl ) ) . is_none ( ) )
17831786 . filter ( |sr| {
17841787 detached_ledger_record ( RecordStore :: Ledger ( & ledger. entries ) , & sr. purl , & sr. uuid )
17851788 . is_none ( )
17861789 } )
1790+ . collect ( ) ;
1791+ let candidates: Vec < ( & str , & str ) > = fetchable
1792+ . iter ( )
17871793 . filter ( |sr| !claimed. contains ( & canonical_purl ( & sr. purl ) ) )
17881794 . map ( |sr| ( sr. purl . as_str ( ) , sr. uuid . as_str ( ) ) )
17891795 . collect ( ) ;
17901796 let refused = socket_patch_core:: vendor:: lock_text_refusals ( cwd, & candidates) . await ;
17911797 let options = params. crawler_options ( ) ;
1792- crate :: commands:: vendor:: lock_refusals_reaching_backend (
1793- cwd,
1794- refused,
1795- & ledger. entries ,
1796- |purls| async move {
1797- crate :: commands:: vendor:: installed_purls ( & options, & purls, prior) . await
1798- } ,
1799- )
1800- . await
1798+ let mut refusals =
1799+ crate :: commands:: vendor:: lock_refusals_reaching_backend (
1800+ cwd,
1801+ refused,
1802+ & ledger. entries ,
1803+ |purls| async move {
1804+ crate :: commands:: vendor:: installed_purls ( & options, & purls, prior) . await
1805+ } ,
1806+ )
1807+ . await ;
1808+ // A hosted gem the takeover will refuse (#775) is refused here too, so
1809+ // its view is never fetched for a package the run cannot vendor. The
1810+ // download phase only runs online (`--offline` refuses `get` and `scan`
1811+ // before it), so the dry-run restore may resolve the registry entry.
1812+ refusals. extend (
1813+ crate :: commands:: vendor:: gem_takeover_refusals_for (
1814+ cwd,
1815+ fetchable
1816+ . iter ( )
1817+ . filter ( |sr| claimed. contains ( & canonical_purl ( & sr. purl ) ) )
1818+ . map ( |sr| sr. purl . as_str ( ) ) ,
1819+ & pins,
1820+ false ,
1821+ origins,
1822+ )
1823+ . await ,
1824+ ) ;
1825+ refusals
18011826}
18021827
18031828/// The record a detached ledger entry already carries for `purl` at
@@ -3759,7 +3784,12 @@ async fn run_get_vendored(
37593784 // Dry run: ledger-classification preview only (scan's posture) — no
37603785 // download, no vendor step, no writes.
37613786 if args. common . dry_run {
3762- let preview = super :: scan:: preview_vendor_json ( & args. common . cwd , selected) . await ;
3787+ let takeover = super :: vendor:: gem_takeover_preview_refusals (
3788+ & args. common ,
3789+ selected. iter ( ) . map ( |p| p. purl . as_str ( ) ) ,
3790+ )
3791+ . await ;
3792+ let preview = super :: scan:: preview_vendor_json ( & args. common . cwd , selected, & takeover) . await ;
37633793 if args. common . json {
37643794 let mut result = serde_json:: json!( {
37653795 "status" : "success" ,
0 commit comments