Skip to content

feat: introduce Dirs for unified XDG-aware path resolution - #2346

Draft
forehalo wants to merge 1 commit into
voidzero-dev:mainfrom
forehalo:feat/dirs-path-resolution
Draft

feat: introduce Dirs for unified XDG-aware path resolution#2346
forehalo wants to merge 1 commit into
voidzero-dev:mainfrom
forehalo:feat/dirs-path-resolution

Conversation

@forehalo

@forehalo forehalo commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Groundwork for #827 (the env-var removal and installer cutover land in stacked follow-up PRs).

Summary

Introduces vp_shared::Dirs as the single owner of every on-disk placement decision. All priority chains are internal details; call sites ask for a category root or a named path. Dirs is the sole path source — get_vp_home(), home.rs, and per-crate wrapper helpers are gone.

This PR is behavior-preserving for every install flavorVP_HOME, the installers, and the generated env* scripts work exactly as before. Fresh installs still land in ~/.vite-plus; the split XDG layout only activates via explicit VP_*_DIR/XDG_* configuration until the follow-up stack flips installer defaults.

Layout selection happens once via an internal DirsInner enum (first match wins):

  1. VP_HOME set → legacy monolithic Home layout (highest priority, as today).

  2. Executable self-locationcurrent_exe is <root>/current/bin/vpHome(root). Covers IDE/trampoline launches without PATH context.

  3. Legacy PATH inference<root>/bin on PATH with the legacy layout → Home(root) (as today).

  4. ~/.vite-plus existsHome, grandfathered; nothing is moved.

  5. Custom (split XDG layout) — each category resolves independently:

    Category Chain
    bin VP_BIN_DIRXDG_BIN_HOMEXDG_DATA_HOME/../bin~/.local/bin (uv's chain)
    config XDG_CONFIG_HOME/vite-plus~/.config/vite-plus
    data (runtimes, package managers, versions, bins/*.json) VP_DATA_DIRXDG_DATA_HOME/vite-plus~/.local/share/vite-plus
    state XDG_STATE_HOME/vite-plus~/.local/state/vite-plus
    cache VP_CACHE_DIRXDG_CACHE_HOME/vite-plus~/.cache/vite-plus

    Only bin/data/cache get dedicated VP_*_DIR overrides (mirroring uv's UV_TOOL_BIN_DIR / UV_PYTHON_INSTALL_DIR / UV_CACHE_DIR); config and state rely on the standard XDG vars. Relative values are ignored per the spec. Windows defaults live under %LOCALAPPDATA%\vite-plus\... (config under %APPDATA%\vite-plus).

What changed

  • crates/vp_shared/src/dirs.rs (new, absorbs home.rs): Dirs + DirsInner, pure injectable resolution core (XDG/platform/PATH all injected — no env mutation or serial_test anywhere), 5 category accessors, 12 named helpers, is_legacy_layout(). Test helpers live in a #[cfg(test)] impl block; cross-crate tests sandbox via EnvConfig::for_test_with_home (temp home → fully isolated layout).
  • Env plumbing: VP_BIN_DIR/VP_DATA_DIR/VP_CACHE_DIR and the XDG_*_HOME names are constants in env_vars.rs; EnvConfig carries only vp_* path overrides — Dirs reads the XDG vars itself.
  • Call-site migration: all get_vp_home() uses and hand-rolled $VP_HOME/... constructions across vp_global_cli, vp_js_runtime, vp_pm_cli, vp_setup, vp_command, vp_installer now go through Dirs; wrapper helpers (get_js_runtime_dir, bins_dir, …) deleted; bins/*.json moves to the data category (identical on disk under Home).
  • TS parity: the global CLI injects the resolved VP_BIN_DIR/VP_DATA_DIR/VP_CACHE_DIR into JS child processes under the split layout only (never overriding user-set vars); org-tarball.ts prefers VP_CACHE_DIR; generated git hook scripts fall back through VP_BIN_DIRVP_HOME/bin~/.vite-plus/bin~/.local/bin.
  • Docs: installer-env-vars.md gains the new variables and a full layout-resolution section; env.md/install.md/implode.md/CONTRIBUTING.md/AGENTS.md updated; supersede note added to rfcs/env-command.md.

Stacked follow-ups (not in this PR)

  • Remove VP_HOME and switch installer defaults so fresh installs land in the split XDG layout (including generated env* script content).
  • vp implode removal of the split XDG dirs.

Validation

  • cargo check --workspace --all-targets, cargo clippy --workspace --all-targets: zero warnings
  • cargo test on all touched crates: ~1500 tests pass (full-workspace failures are pre-existing vendored-rolldown fixture issues, unrelated)
  • TS: 200 unit tests pass, including the shell end-to-end test for the modified git hook script; vp fmt --check / vp lint clean on changed files

@netlify

netlify Bot commented Aug 5, 2026

Copy link
Copy Markdown

Deploy Preview for viteplus-preview ready!

Name Link
🔨 Latest commit b8069a5
🔍 Latest deploy log https://app.netlify.com/projects/viteplus-preview/deploys/6a735cc1a033f30008e5c8c3
😎 Deploy Preview https://deploy-preview-2346--viteplus-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@forehalo
forehalo force-pushed the feat/dirs-path-resolution branch 2 times, most recently from f9b80b6 to 0df4587 Compare August 5, 2026 14:38
Add vp_shared::Dirs as the single owner of on-disk placement decisions.
An internal DirsInner enum selects the layout once per resolution (first
match wins):

- Home (legacy monolithic root): VP_HOME is set, the vp binary
  self-locates at <root>/current/bin/vp, a legacy layout is found on
  PATH, or ~/.vite-plus exists on disk. Existing installs keep working
  untouched, byte-identical paths.
- Custom (split XDG layout, fresh installs): each category resolves
  through its own VP_*_DIR override -> XDG_* -> platform-default chain
  (bin: VP_BIN_DIR -> XDG_BIN_HOME -> XDG_DATA_HOME/../bin -> ~/.local/bin,
  mirroring uv). Only VP_BIN_DIR/VP_DATA_DIR/VP_CACHE_DIR exist as
  dedicated overrides; config and state rely on XDG_CONFIG_HOME /
  XDG_STATE_HOME. Relative values are ignored per the spec.

XDG_* names are defined alongside vp's own variables in env_vars.rs, but
only vp_* path overrides live in EnvConfig; Dirs reads XDG vars itself
behind an injectable, parallel-safe resolution core (no env mutation or
serial_test anywhere in Dirs tests; test helpers live in a #[cfg(test)]
impl block, and cross-crate tests sandbox through
EnvConfig::for_test_with_home).

Migrate every Rust call site to Dirs category accessors and named
helpers, delete get_vp_home() and the home.rs module (folded into
dirs.rs), and drop per-crate wrapper helpers so Dirs is the sole path
source. bins/*.json metadata moves to the data category.

On the TS side, the global CLI injects the resolved VP_BIN_DIR /
VP_DATA_DIR / VP_CACHE_DIR into JS child processes under the split layout
only (never overriding user-set vars); org-tarball.ts prefers
VP_CACHE_DIR; generated git hook scripts fall back through VP_BIN_DIR,
VP_HOME/bin, ~/.vite-plus/bin, ~/.local/bin.

VP_HOME, the installers, and the generated env* shell scripts are
unchanged in behavior: fresh installs still land in ~/.vite-plus, so the
split layout is opt-in via VP_*_DIR/XDG until the follow-up stack removes
the legacy variables and switches installer defaults.

Groundwork for voidzero-dev#827.
@forehalo
forehalo force-pushed the feat/dirs-path-resolution branch from 0df4587 to b8069a5 Compare August 5, 2026 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant