Repository navigation
fix(path): preserve the registry value type when rewriting PATH - #296
Merged
Merged
Conversation
Windows stores the User and System PATH as REG_EXPAND_SZ, and only expands %VAR% entries such as %SystemRoot%\system32 in a value of that type. Every place dtvem rewrote PATH wrote REG_SZ instead, leaving those entries literal and their directories off PATH for new processes: - dtvem init (modifyUserPath, modifySystemPath) and the doctor stale-shims fix (RemoveStaleShimsFromUserPath) read PATH with GetStringValue, dropped the type it returned, and wrote it back with SetStringValue. For the System PATH that would drop %SystemRoot%\ system32 itself. - install.ps1 read the User PATH with GetEnvironmentVariable, which expands %VAR% entries, and wrote it with SetEnvironmentVariable, which writes REG_SZ, freezing those entries and changing the type. PATH is now written through writePathValue, which keeps REG_EXPAND_SZ when the value had it or when it holds a %VAR% reference (the rule Windows' own environment editor uses), so a converted value is repaired on the next write. The three call sites share prependShimsDir and removeStaleShims, which take a small key interface so tests run against a fake rather than the real environment; modifyUserPath and modifySystemPath, which were duplicates, now share modifyPath. install.ps1 edits HKCU\Environment directly: it reads the raw value, checks for the install directory against the expanded entries, writes REG_EXPAND_SZ, and sends the WM_SETTINGCHANGE broadcast that SetEnvironmentVariable used to. A new dtvem doctor check, path-registry-type, flags a User or System PATH stored as REG_SZ that holds %VAR% references. --fix rewrites the User PATH as REG_EXPAND_SZ; the System PATH needs an elevated terminal, so doctor shows the PowerShell command for it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Windows stores the User and System
PATHasREG_EXPAND_SZ, and expands%VAR%entries such as%SystemRoot%\system32only in a value of that type. Every place dtvem rewrotePATHwroteREG_SZinstead, so those entries stayed literal and their directories dropped offPATHfor new processes. For the SystemPATH, written bydtvem initon a system install, that includes%SystemRoot%\system32itself.Type of Change
Related Issues
Resolves #295
Changes Made
One type-preserving writer.
writePathValue(internal/path/registry_windows.go) writesREG_EXPAND_SZwhen the value had that type, or when the new value holds a%VAR%reference. That's the rule Windows' own environment editor uses, so an already converted value is repaired on its next write. A missingPATHis created asREG_EXPAND_SZ.All three Go call sites use it:
dtvem inituser install (modifyUserPath);dtvem initsystem install (modifySystemPath);RemoveStaleShimsFromUserPath).Their logic moved into
prependShimsDirandremoveStaleShims, which take a small key interface so tests run against a fake.modifyUserPathandmodifySystemPathwere near-duplicates and now sharemodifyPath; their messages are unchanged.install.ps1, a fourth writer the issue didn't list. It read the UserPATHwith[Environment]::GetEnvironmentVariable, which expands%VAR%entries, then wrote it withSetEnvironmentVariable, which writesREG_SZ. That froze entries like%USERPROFILE%\.dotnet\toolsinto fixed paths and changed the type. The newAdd-ToUserPatheditsHKCU\Environmentdirectly: it reads the raw value, checks for the install folder against the expanded entries (so a%USERPROFILE%form counts as present), and writesREG_EXPAND_SZ.Send-EnvironmentChangesends theWM_SETTINGCHANGEbroadcast thatSetEnvironmentVariableused to.New
dtvem doctorcheck,path-registry-type. It flags a User or SystemPATHstored asREG_SZthat holds%VAR%references, since anyone who randtvem initor the stale-shims fix may already have one.--fixrewrites the UserPATHasREG_EXPAND_SZwith its entries unchanged.PATHneeds an elevated terminal, so the resolution shows the PowerShell command for it.CLAUDE.md: a note to write
PATHonly throughwritePathValue.Testing
Test Environment
GOOS=linuxvet andGOOS=darwinbuild)Test Steps
./rnr check: gofmt, golangci-lint (0 issues), all 27 packages pass.internal/path/registry_windows_test.go(Windows only):writePathValue: keepsREG_EXPAND_SZ, keepsREG_SZwithout references, upgradesREG_SZthat has references, and doesn't treat a lone%as a reference.readPathValue: a missing value reads as emptyREG_EXPAND_SZ.prependShimsDir: ordering, stale-entry removal and type kept, upgraded or created; it doesn't write after a read error.removeStaleShims: keeps the type, and doesn't rewrite when nothing is stale.repairPathType.HKCU\Softwarethat the test deletes, never the real environment.internal/doctor/check_path_registry_type_test.go: the not-Windows, fine, user-only, system-only and both cases; the fix wiring; a read error; registration.install.ps1'sAdd-ToUserPath, loaded into a harness pointed at a scratchHKCU\Softwarekey, under Windows PowerShell 5.1 and PowerShell 7.dtvem doctor --no-fixon the real machine.Test Results
Add-ToUserPath, identical in Windows PowerShell 5.1 and PowerShell 7:PathC:\tools;%USERPROFILE%\.dotnet\tools(REG_EXPAND_SZ)ExpandStringExpandString%USERPROFILE%\.dotnet\toolsExpandStringC:\tools(REG_SZ)ExpandStringPathvalueExpandStringThe real-machine
dtvem doctor --no-fixreported✓ PATH registry values expand their %VAR% entries.Checklist
golangci-lint runand fixed all issues (includes gofmt, govet, and 40+ linters)go mod tidyto clean up dependencies (no dependency changes in this PR)go test ./...)Breaking Changes
None. Writing
REG_EXPAND_SZmatches what Windows itself uses forPATH.Additional Notes
stale-shims-pathtreats any.dtvem\shimsentry that doesn't match the currentDTVEM_ROOTas stale. That's a design question about multiple roots and can be its own issue.