Skip to content

fix(doctor): stop removing other dtvem installs' shims from PATH - #298

Merged
CalvinAllen merged 1 commit into
mainfrom
fix/doctor/stale-shims-other-roots
Oct 23, 2026
Merged

CalvinAllen merged 1 commit into
mainfrom
fix/doctor/stale-shims-other-roots

Conversation

@CalvinAllen

Copy link
Copy Markdown
Contributor

Description

dtvem doctor's stale-shims-path check treated every PATH entry that looked like a dtvem shims directory, other than the current root's, as stale, without checking whether it was. With a second install, or DTVEM_ROOT pointing away from the default install, the default install's real shims directory was:

  • reported as an error;
  • removed by dtvem doctor --fix (also under --yes): from the User PATH on Windows, and from the shell config on Unix;
  • dropped silently by dtvem init on Windows.

A non-current shims entry is now stale only when its directory no longer exists. One that still exists belongs to another dtvem root, which may still be in use. It is kept everywhere and only reported.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring (no functional changes)
  • Performance improvement
  • Test coverage improvement
  • CI/CD or build process change

Related Issues

Resolves #297

Changes Made

  • One rule for everything: new path.ClassifyShimsEntries sorts PATH entries into kept, stale (missing directory) and other roots (existing directory). PartitionStaleShimsEntries and FindStaleShimsEntries now wrap it, so every place that decides what's stale follows the same rule:
    • the doctor check;
    • the Windows registry fix (RemoveStaleShimsFromUserPath);
    • the Unix shell-config fix (removeDtvemMarkerBlocks);
    • dtvem init on Windows (prependShimsDir).
  • Environment references are expanded before judging an entry: %VAR% on Windows (registry.ExpandString), $VAR elsewhere (os.ExpandEnv). This also fixes a latent bug: a registry spelling of the current shims directory, such as %USERPROFILE%\.dtvem\shims, compared unequal to the expanded current directory, so the stale-shims fix removed it. It's now recognized as current.
  • Doctor report:
    • other roots' shims are a warning with manual instructions and no fix;
    • stale entries remain a fixable error, as before;
    • when both appear, the fix removes only the stale ones and the resolution says the others are left in place;
    • a directory listed in both the System and User PATH is reported once.
  • dtvem init on Windows keeps other roots' entries and warns: Left another dtvem install's shims on your User PATH: …. Unix init already only warned, and now warns only about missing directories.

Testing

Test Environment

  • OS: Windows 11 (plus golangci-lint with GOOS=linux and GOOS=darwin)
  • Go Version: 1.25.4 (module targets 1.23)

Test Steps

  1. ./rnr check: gofmt, golangci-lint (0 issues), all 27 packages pass. Lint also reports 0 issues with GOOS=linux and GOOS=darwin.
  2. internal/path, all platforms:
    • ClassifyShimsEntries: kept, stale and other roots, against real existing and missing directories.
    • An environment-variable spelling of the current directory counts as current; a spelling of an existing other root counts as another root.
    • FindStaleShimsEntries and FindOtherRootShimsEntries.
    • The shell-config fix keeps an existing other root's # Added by dtvem block and removes a missing one's. This test is Unix-only, since that parser splits "<dir>:$PATH" on :.
  3. internal/path, Windows:
    • prependShimsDir keeps and reports an existing other root, and doesn't duplicate a %USERPROFILE% spelling of the shims directory.
    • removeStaleShims keeps both of those and removes only the missing directory.
  4. internal/doctor: other root only (warning, not fixable, no "Found"), stale plus other root (fixable error, both listed, "left in place"), a repeated entry reported once. The existing tests are unchanged and pass.
  5. The issue's scenario on a real machine, read-only (--no-fix): DTVEM_ROOT set to a temp root, with the real install's shims on PATH.

Test Results

Before, the real install's shims directory was a fixable ✗ Stale dtvem shims entry in PATH. Now:

⚠ Another dtvem install's shims directory is in PATH  [manual]
  Expected:       C:\Users\<user>\AppData\Local\Temp\root297\shims
  Other install:  C:\Users\<user>\.dtvem\shims
  These shims belong to a different dtvem root than the one this dtvem uses ("Expected").
  If you use more than one dtvem root on purpose, nothing needs to change.
  If that install is no longer used, remove its entry from your PATH (…), then restart your terminal.

Checklist

  • My code follows the Google Go Style Guide
  • I have run golangci-lint run and fixed all issues (includes gofmt, govet, and 40+ linters)
  • I have run go mod tidy to clean up dependencies (no dependency changes in this PR)
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes (go test ./...)
  • I have commented my code, particularly in hard-to-understand areas
  • I have updated the documentation (README.md, CONTRIBUTING.md, etc.) if needed (no user docs describe this check)
  • My changes generate no new warnings or errors
  • I have checked my code works on multiple platforms (Windows, macOS, Linux) if applicable (Windows tested; Linux and macOS linted locally; CI runs the tests)
  • I have added appropriate error handling
  • I have followed conventional commit format in my commit messages

Breaking Changes

None. One behaviour change to know about: a leftover shims directory that still exists on disk is no longer removed automatically, for example a pre-XDG ~/.dtvem/shims that was never deleted. Doctor reports it as another install and says how to remove its PATH entry once the user confirms it's unused.

Additional Notes

The Unix-only shell-config test is skipped on Windows and runs on CI's Linux and macOS jobs.

Every PATH entry that looked like a dtvem shims directory (…/dtvem/shims
or …/.dtvem/shims) but wasn't the current root's was treated as stale,
without checking whether it was. With a second install, or DTVEM_ROOT
pointing away from the default install, the default install's real
shims directory was reported as an error and removed by
`dtvem doctor --fix` (also under --yes): from the User PATH on Windows,
and from the shell config on Unix. `dtvem init` on Windows dropped it
silently too.

A non-current shims entry is now stale only when its directory no longer
exists. A directory that still exists belongs to another dtvem root,
which may still be in use: it is kept everywhere and only reported.

- path.ClassifyShimsEntries sorts entries into kept, stale and other
  roots. PartitionStaleShimsEntries and FindStaleShimsEntries wrap it, so
  the doctor check, the Windows registry fix, the Unix shell-config fix
  and dtvem init all follow the same rule.
- Entries are judged with environment references expanded (%VAR% on
  Windows, $VAR elsewhere). A registry spelling of the current shims
  directory, such as %USERPROFILE%\.dtvem\shims, used to compare unequal
  to the expanded current directory and was removed as stale; it is now
  recognized as current.
- doctor reports other roots' shims as a warning with manual
  instructions and no fix; stale entries stay a fixable error. A
  directory listed in both the System and User PATH is reported once.
- dtvem init on Windows keeps other roots' entries and warns about them.
@CalvinAllen
CalvinAllen merged commit fea13ec into main Oct 23, 2026
14 checks passed
@CalvinAllen
CalvinAllen deleted the fix/doctor/stale-shims-other-roots branch October 23, 2026 14:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

fix(doctor): stop removing other dtvem installs' shims from PATH

1 participant