Zoltan Kochan 6018359e4c feat(package-manager): BuildModules under hoisted node-linker (#438 slice 7) (#520)
Re-enables `BuildModules` for `nodeLinker: hoisted` installs. Slice 6
landed the hoisted install pipeline but skipped the build phase
entirely because `BuildModules` walked virtual-store slot directories
that don't exist under hoisted. Slice 7 routes the build phase
through the slice 4 walker's per-node `dir` so postinstall scripts
can run against the on-disk hoisted tree.

Changes:
- `BuildModules` gains two fields: `pkg_root_by_key:
  Option<&HashMap<PackageKey, PathBuf>>` overrides the per-snapshot
  pkg_root lookup with the slice 4 walker's
  `DependenciesGraphNode::dir` values; `gather_ancestor_bin_paths:
  bool` switches `extra_bin_paths` to the new
  `bin_dirs_in_all_parent_dirs` helper, a port of upstream's
  `binDirsInAllParentDirs` at
  https://github.com/pnpm/pnpm/blob/94240bc046/building/after-install/src/index.ts#L476-L487.
- `pkg_root_for_key` helper: routes between the layout-based slot
  computation (isolated) and the override map (hoisted). Hoisted
  snapshots absent from the map (walker-dropped) take the same exit
  as the isolated `!pkg_dir.exists()` skip.
- `InstallFrozenLockfile::run` now builds a snapshot-key →
  first-recorded-dir map from `walker_result.graph.values()` and
  threads it (plus `gather_ancestor_bin_paths: true`) into
  `BuildModules` instead of skipping the phase. Multiple graph
  nodes with the same dep_path collapse to the first entry,
  matching upstream's `pkgRoots[0]` pick at
  https://github.com/pnpm/pnpm/blob/94240bc046/building/after-install/src/index.ts#L348.
- New private `HoistedLinkerOutput` struct bundles `hoisted_locations`
  and `pkg_root_by_key` so the hoisted-branch return doesn't trip
  `clippy::type_complexity`.

Side-effects-cache key shape is unchanged — it's keyed by
`pkg_id_with_patch_hash` + dep-graph hash, both layout-independent
(`crates/graph-hasher/src/dep_state.rs`).

`MISSING_HOISTED_LOCATIONS` is intentionally deferred — pacquet has
no `rebuild` command, so the install path always re-runs the walker
and never reads `.modules.yaml.hoisted_locations`. Tracked as a
follow-up for when `pacquet rebuild` lands.

Workspace-aware hoisting (slice 9) and `hoistingLimits` /
`externalDependencies` (slice 10) remain.

Tests:
- Three new helper tests pin `bin_dirs_in_all_parent_dirs` against
  top-level, conflict-nested, and scoped-package shapes.
- Three new helper tests pin `pkg_root_for_key` for the isolated
  pass-through, the hoisted override hit, and the hoisted-missing
  short-circuit.
2026-05-14 09:15:12 +02:00
Description
No description provided
MIT 280 MiB
Languages
Rust 56.5%
TypeScript 43%
JavaScript 0.4%