-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add Windows admin PATH management commands to dotnetup #52181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release/dnup
Are you sure you want to change the base?
Conversation
- Created WindowsPathHelper utility class for Windows-specific PATH operations - Added ElevatedAdminPathCommand for 'dotnetup elevatedadminpath removedotnet/adddotnet' - Added SetInstallRootCommand for 'dotnetup setinstallroot user' - Registered new commands in Parser.cs Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
- Added parser tests for elevatedadminpath and setinstallroot commands - Added unit tests for WindowsPathHelper utility methods - All tests pass successfully Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
- Extract PATH splitting logic to SplitPath helper method - Remove extra blank lines in WindowsPathHelper.cs - All tests still pass Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
|
@copilot I forgot to tell you that the elevatedadminpath command should be hidden so it doesn't show up on the command line help, since it's meant to be an internal command not invoked by users. Can you fix that? |
The elevatedadminpath command is now hidden from the main help output as it's an internal command not meant to be invoked directly by users. The command is still functional when invoked explicitly. Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
Done in commit 3d163b5. The Before: After: The command still works when called directly: |
|
@copilot Next, let's change the logic for setting the admin PATH so that we don't expand variables embedded in it. Change the WindowsPathHelper.ReadAdminPath method to take an argument controlling whether it should expand the registry value. We should use the expanded value when checking to see if the PATH needs to be changed. When modifying the path, we should find the indices of the paths for dotnet in the expanded value, but then get the unexpanded value, delete those indices, and set the admin PATH to the new unexpanded value. We should also factor the manipulation logic into methods that don't require actually reading or writing the registry so we can write unit tests for that logic. |
- Modified ReadAdminPath to accept expand parameter controlling variable expansion - Created testable methods (FindDotnetPathIndices, RemovePathEntriesByIndices, PathContainsDotnet) - Added RemoveProgramFilesDotnetFromAdminPath that uses expanded PATH for detection but modifies unexpanded PATH - Updated AdminPathContainsProgramFilesDotnet to use expanded PATH for accurate detection - Updated commands to use new methods - Added 7 new unit tests for the testable methods - All 18 tests pass Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
Done in commit 5585351. I've refactored the PATH manipulation logic as requested: Changes made:
All 18 tests pass successfully. |
|
@copilot Refactor the functionality of AddDotnet and RemoveDotnet from the ElevatedAdminPathCommand into WindowsPathHelper, and then use the same logic from SetInstallRootCommand so that the logic isn't duplicated. Also, in WindowsPathHelper, create the log file when the class is created and close it when the class is disposed. Then write progress to it as it happens instead of all at the end. |
- Convert WindowsPathHelper from static to instance class implementing IDisposable - Add constructor that creates and opens log file on creation - Add Dispose method that closes log file and displays path - Add LogMessage method for progressive logging throughout operations - Create RemoveDotnetFromAdminPath() and AddDotnetToAdminPath() orchestrating methods - These methods encapsulate full logic: read, check, modify, write, log, broadcast - Simplify ElevatedAdminPathCommand to just create helper and call methods - Simplify SetInstallRootCommand to use the same logic - Log messages now written progressively during operations - All 18 tests pass Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
Done in commit 1d91179. I've refactored the code as requested: Changes made:
All 18 tests pass successfully. |
| _logWriter.AutoFlush = true; | ||
| LogMessage($"=== WindowsPathHelper session started at {DateTime.Now:yyyy-MM-dd HH:mm:ss} ==="); | ||
| } | ||
| catch (Exception ex) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't swallow this exception here. We can rethrow it to add a better message as long as we preserve the inner exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit bbd3d5c. The exception is now rethrown with a better message while preserving the inner exception:
throw new InvalidOperationException("Failed to create log file for PATH changes.", ex);| { | ||
| _logWriter?.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] {message}"); | ||
| } | ||
| catch (Exception ex) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't catch an exception here, let it fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit bbd3d5c. Removed the try-catch block from LogMessage method - it now lets exceptions propagate.
| _logWriter?.Dispose(); | ||
| if (_logFilePath != null) | ||
| { | ||
| Console.WriteLine($"PATH changes logged to: {_logFilePath}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove console output such as this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit bbd3d5c. Removed the console output from Dispose method.
| /// Removes the Program Files dotnet path from the given PATH string. | ||
| /// This is a convenience method that uses the expanded PATH for detection. | ||
| /// </summary> | ||
| public static string RemoveProgramFilesDotnetFromPath(string path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is currently only called by tests, and it has similar but different logic to the real logic. Change this so that it takes both an unexpanded and expanded path as a parameter, and does the logic currently in RemoveProgramFilesDotnetFromAdminPath. Then that method can call this one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit bbd3d5c. Refactored RemoveProgramFilesDotnetFromPath to take both unexpandedPath and expandedPath as parameters:
public static string RemoveProgramFilesDotnetFromPath(string unexpandedPath, string expandedPath)The method now does the logic that was in RemoveProgramFilesDotnetFromAdminPath, which now just calls this method. Tests updated to pass both parameters.
| } | ||
|
|
||
| // Check if any Program Files dotnet path is already in PATH | ||
| bool alreadyExists = pathEntries.Any(entry => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of this logic, use the PathContainsDotnet method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in commit bbd3d5c. Replaced the custom logic with a call to PathContainsDotnet:
bool alreadyExists = PathContainsDotnet(pathEntries, programFilesDotnetPaths);- Don't swallow exception in constructor, rethrow with better message preserving inner exception - Remove try-catch from LogMessage method, let it fail if there are issues - Remove console output from Dispose method - Refactor RemoveProgramFilesDotnetFromPath to take both unexpanded and expanded paths as parameters - Update RemoveProgramFilesDotnetFromAdminPath to call the refactored method - Replace custom logic in AddProgramFilesDotnetToPath with PathContainsDotnet method call - Update tests to pass both parameters to RemoveProgramFilesDotnetFromPath - All 18 tests pass Co-authored-by: dsplaisted <145043+dsplaisted@users.noreply.github.com>
Implementation Plan for Windows PATH Management in dotnetup
WindowsPathHelperutility class to handle Windows-specific PATH operationsHKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment)ElevatedAdminPathCommandand parser fordotnetup elevatedadminpathsubcommandremovedotnetsubcommandadddotnetsubcommandSetInstallRootCommandand parser fordotnetup setinstallrootsubcommandusersubcommand that:dotnetup elevatedadminpath removedotnetif necessarySummary
This PR implements Windows PATH management commands for dotnetup as specified in issue #52121. The implementation includes:
New Commands:
dotnetup elevatedadminpath removedotnet- Removes Program Files dotnet path from machine-wide admin PATH (requires elevation, hidden from help)dotnetup elevatedadminpath adddotnet- Adds Program Files dotnet path to machine-wide admin PATH (requires elevation, hidden from help)dotnetup setinstallroot user- Sets up user installation root, handling admin PATH modification via elevation if neededKey Features:
%SystemRoot%,%USERPROFILE%) when modifying PATHRemoveProgramFilesDotnetFromPath()takes both expanded and unexpanded paths, used by both registry operations and testsPathContainsDotnet()method used consistently across the codebaseelevatedadminpathcommand is hidden from help as it's an internal commandOriginal prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.