Dotnetup: Shell profile modification for PATH and DOTNET_ROOT#53447
Dotnetup: Shell profile modification for PATH and DOTNET_ROOT#53447dsplaisted merged 54 commits intodotnet:release/dnupfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds Unix shell profile modification support to dotnetup so PATH/DOTNET_ROOT configuration can be persisted via .bashrc, .zshrc, etc., and consolidates shell detection/providers into a shared Microsoft.DotNet.Tools.Bootstrapper.Shell namespace.
Changes:
- Introduces
ShellProfileManager+ShellDetectionand new bash/zsh/pwshIEnvShellProviderimplementations under...Bootstrapper.Shell. - Updates install/defaultinstall flows to write shell-profile entries on Unix (and prints an activation command for the current terminal).
- Adds/updates tests and rewrites Unix environment setup documentation accordingly.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| test/dotnetup.Tests/ShellProfileManagerTests.cs | New tests for add/remove/backup/idempotency and provider entry formatting. |
| test/dotnetup.Tests/EnvShellProviderTests.cs | Updates tests to new provider namespace and validates dotnetup-dir PATH behavior. |
| src/Installer/dotnetup/Shell/IEnvShellProvider.cs | New shared shell provider interface (env script + profile integration). |
| src/Installer/dotnetup/Shell/BashEnvShellProvider.cs | Bash env script/profile/activation implementation; profile paths selection logic. |
| src/Installer/dotnetup/Shell/ZshEnvShellProvider.cs | Zsh env script/profile/activation implementation. |
| src/Installer/dotnetup/Shell/PowerShellEnvShellProvider.cs | PowerShell env script/profile/activation implementation. |
| src/Installer/dotnetup/Shell/ShellDetection.cs | Centralized supported shell list + current-shell detection. |
| src/Installer/dotnetup/Shell/ShellProfileManager.cs | New profile file mutation logic (append/replace/remove + backups). |
| src/Installer/dotnetup/DotnetInstallManager.cs | Switches Unix “default install” persistence from env vars to shell profiles. |
| src/Installer/dotnetup/Commands/Shared/InstallWalkthrough.cs | Skips the default-install prompt when shell is unsupported on Unix. |
| src/Installer/dotnetup/Commands/Shared/InstallExecutor.cs | Prints a post-install activation command on Unix. |
| src/Installer/dotnetup/Commands/PrintEnvScript/PrintEnvScriptCommandParser.cs | Uses ShellDetection, adds --dotnetup-only, updates validation/completions. |
| src/Installer/dotnetup/Commands/PrintEnvScript/PrintEnvScriptCommand.cs | Adds dotnetup-dir PATH injection + dotnetup-only behavior when generating scripts. |
| src/Installer/dotnetup/Commands/DefaultInstall/DefaultInstallCommand.cs | Implements Unix defaultinstall user/admin using profile entries. |
| src/Installer/dotnetup/Commands/PrintEnvScript/BashEnvShellProvider.cs | Removes old provider type (moved to ...Shell). |
| src/Installer/dotnetup/Commands/PrintEnvScript/ZshEnvShellProvider.cs | Removes old provider type (moved to ...Shell). |
| src/Installer/dotnetup/Commands/PrintEnvScript/PowerShellEnvShellProvider.cs | Removes old provider type (moved to ...Shell). |
| src/Installer/dotnetup/Commands/PrintEnvScript/IEnvShellProvider.cs | Removes old interface (replaced by shared interface). |
| documentation/general/dotnetup/unix-environment-setup.md | Rewrites doc around user workflows and new profile management behavior. |
You can also share your feedback on Copilot code review. Take the survey.
Extend IEnvShellProvider with GetProfilePaths(), GenerateProfileEntry(), and GenerateActivationCommand() methods. Implement in all three providers: - Bash: ~/.bashrc + login profile (~/.bash_profile or ~/.profile) - Zsh: ~/.zshrc - PowerShell: ~/.config/powershell/Microsoft.PowerShell_profile.ps1 Add ShellProfileManager for coordinating file I/O (add/remove entries, backup, idempotency) and ShellDetection for resolving the current shell. Hook profile modification into DotnetInstallManager.ConfigureInstallType() on non-Windows so that 'sdk install --interactive' persists to profiles. Implement DefaultInstallCommand.SetUserInstallRoot() for non-Windows, replacing the 'not yet supported' error. Print activation command after install so users can immediately use .NET in their current terminal. Closes dotnet#51582 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> # Conflicts: # src/Installer/dotnetup/Commands/Shared/InstallExecutor.cs # src/Installer/dotnetup/DotnetInstallManager.cs
GenerateEnvScript now accepts an optional dotnetupDir parameter. When provided, the dotnetup binary's directory is prepended to PATH alongside the dotnet install path, so both dotnet and dotnetup are available after sourcing the script. The print-env-script command passes Path.GetDirectoryName(Environment.ProcessPath) automatically. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When switching to admin install on Unix, shell profile entries are replaced with dotnetup-only versions that add dotnetup to PATH but do not set DOTNET_ROOT or add the dotnet install path (since the admin/system install manages dotnet). Add --dotnetup-only flag to print-env-script command. When set, the generated script only adds the dotnetup directory to PATH. Add ShellProfileManager.ReplaceProfileEntries() for switching between user and admin profile entries. Add includeDotnet parameter to GenerateEnvScript and dotnetupOnly parameter to GenerateProfileEntry/GenerateActivationCommand on IEnvShellProvider. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> # Conflicts: # src/Installer/dotnetup/Commands/DefaultInstall/DefaultInstallCommand.cs # src/Installer/dotnetup/Commands/PrintEnvScript/PrintEnvScriptCommand.cs # src/Installer/dotnetup/DotnetInstallManager.cs
Restructure the document so that install and defaultinstall are presented as the primary ways environment setup happens, with print-env-script described as the underlying building block and standalone utility. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
EnvironmentVariableTarget.User has no persistent store on Unix in .NET, so the SetEnvironmentVariable calls for DOTNET_ROOT and PATH were effectively process-scoped and had no lasting effect. Shell profile entries are the sole persistence mechanism on Unix. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> # Conflicts: # src/Installer/dotnetup/DotnetInstallManager.cs
The shell providers generate eval-based commands, so the documentation examples should match. Also use dot-source (.) instead of source for POSIX compatibility. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ripts The output of print-env-script is consumed via eval, not sourced as a file. The 'source this script' instructions were misleading. Removed from all three shell providers and the documentation examples. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The generated scripts add both the dotnetup binary directory and the dotnet install path to PATH. The documentation examples were missing the dotnetup directory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The command works on Unix by replacing profile entries with dotnetup-only entries. The remaining gap is system-wide /etc/profile.d/ configuration, so reword the item to reflect that. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
On non-Windows, configuring the default install requires modifying shell profile files. If the current shell cannot be detected or is not supported, the profile modification would silently do nothing. Instead, detect this up-front and skip the prompt with a warning message, so the user knows why the default install setup was skipped. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> # Conflicts: # src/Installer/dotnetup/Commands/Shared/InstallWalkthrough.cs
Move the supported shells array and shell map from PrintEnvScriptCommandParser into ShellDetection, eliminating the duplicate dictionary and the duplicate LookupShellFromEnvironment method. All callers now go through ShellDetection for shell lookup. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> # Conflicts: # src/Installer/dotnetup/Commands/Shared/InstallWalkthrough.cs
AddProfileEntries now replaces existing entries in-place when found, preserving the user's ordering in their profile file. This eliminates the need for a separate ReplaceProfileEntries method and fixes the case where AddProfileEntries would silently skip stale entries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> # Conflicts: # src/Installer/dotnetup/DotnetInstallManager.cs
Remove duplicate '# dotnetup' constants from BashEnvShellProvider, ZshEnvShellProvider, and PowerShellEnvShellProvider. All three now reference ShellProfileManager.MarkerComment, ensuring the marker used to generate entries always matches the one used to find them. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add 'hash -d dotnet' (bash) and 'rehash' (zsh) to the generated scripts so a stale cached dotnet path is cleared when the environment is configured. This replaces the misleading comments that claimed dotnetup would handle it automatically. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the validator and completion source setup from the static constructor into the ShellOption object initializer using collection initializer syntax. Remove the now-unnecessary helper methods. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move IEnvShellProvider, BashEnvShellProvider, ZshEnvShellProvider, PowerShellEnvShellProvider, ShellDetection, and ShellProfileManager into a new Shell/ directory and namespace. These types are used across multiple commands and don't belong in the PrintEnvScript namespace. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> # Conflicts: # src/Installer/dotnetup/Commands/Shared/InstallExecutor.cs # src/Installer/dotnetup/Commands/Shared/InstallWalkthrough.cs # src/Installer/dotnetup/DotnetInstallManager.cs
The test was checking that the first PATH entry containing 'dotnet' was the install path. Now that the dotnetup directory is also added to PATH, the dotnetup binary path (which contains 'dotnet' as a substring) can appear first. Changed to simply verify the install path is contained in PATH entries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
b3afd4e to
b2176bf
Compare
Thread the selected install root through generated shell profile entries and activation commands, and align the Unix environment docs with the current API behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
a1eb785 to
2e20591
Compare
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Suppress the explicit install-path argument when the effective path is the environment default, and keep the helper naming aligned with its return value. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Thanks for responding to all of my feedback 🥳
I will look at the tests in a bit and do a final pass, but these are the remaining nits/thoughts I had. I don't consider any of the comments here blocking except I'm double checking on the security focused issue(s)
| { | ||
| if (File.Exists(tempPath)) | ||
| { | ||
| File.Delete(tempPath); |
There was a problem hiding this comment.
nit: the exists check here and in the restoreoriginal file are redundant - delete should not fail to my knowledge here. The one around move however is necessary.
There was a problem hiding this comment.
This has been rewritten now, I'm not 100% sure whether this specific concern has been addressed.
| return | ||
| $""" | ||
| #!/usr/bin/env bash | ||
| # This script configures the environment for .NET installed at {dotnetInstallPath} |
There was a problem hiding this comment.
Asking for a 2nd opinion on this to make sure there's nothing we didn't think of
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
nagilson
left a comment
There was a problem hiding this comment.
Finished looking at the tests, the remaining feedback is about polish on the PR but a few I think are more important, such as the interop change. Let me know what you think!
| [Fact] | ||
| public void ResolveCurrentInstallRootPath_UsesRealDirectoryWhenParentDirectoryIsSymlinked() | ||
| { | ||
| if (OperatingSystem.IsWindows()) |
There was a problem hiding this comment.
if we use the native method interop replacement API I think we can remove this condition.
There was a problem hiding this comment.
I think we should probably stick to realpath and I don't think we are concerned with this behavior on Windows.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
nagilson
left a comment
There was a problem hiding this comment.
Thank you for adding those tests, the follow ups, and remaining improvements!
|
/ba-g .NET SDK tests failing in dotnetup branch |
Unix shell profile integration for dotnetup
When dotnetup installs .NET on Unix, it needs to configure the user's shell so that
dotnetis available on the command line by default. This PR adds and improves the shell profile modification support that makes that work — adding entries to.bashrc,.zshrc, etc. that setDOTNET_ROOTand updatePATHon shell startup.Shell profile management
defaultinstall adminon Unix with dotnetup-only profile entrieshash -d dotnet/dotnetupfor bash,rehashfor zsh) in generated scripts so stale cached paths don't shadow the new installationCode cleanup
SetEnvironmentVariablecalls on Unix (EnvironmentVariableTarget.Userhas no persistent store on Unix in .NET)ShellDetectionas single source of truth for supported shellsMicrosoft.DotNet.Tools.Bootstrapper.Shellnamespace — these types are used across multiple commands and don't belong inPrintEnvScriptDocumentation
unix-environment-setup.mdto lead with user-facing workflows (install,defaultinstall) instead of theprint-env-scriptimplementation detaildefaultinstall adminis now implemented