diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 762a1f1b07..1d6a2e623c 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -445,36 +445,20 @@ but will not be added automatically." }; } -#[cfg(not(windows))] -macro_rules! post_install_msg_unix_source_env { - () => { - r#"To configure your current shell, you need to source -the corresponding `env` file under {cargo_home}. - -This is usually done by running one of the following (note the leading DOT): - . "{cargo_home}/env" # For sh/bash/zsh/ash/dash/pdksh - source "{cargo_home}/env.fish" # For fish - source "{cargo_home_nushell}/env.nu" # For nushell - source "{cargo_home}/env.tcsh" # For tcsh - . "{cargo_home}/env.ps1" # For pwsh - source "{cargo_home}/env.xsh" # For xonsh -"# - }; -} - #[cfg(not(windows))] macro_rules! post_install_msg_unix { () => { - concat!( - r"# Rust is installed now. Great! + r"# Rust is installed now. Great! To get started you may need to restart your current shell. This would reload your `PATH` environment variable to include Cargo's bin directory ({cargo_home}/bin). -", - post_install_msg_unix_source_env!(), - ) +To configure your current shell, you need to source +the corresponding `env` file under {cargo_home}. + +This is usually done by running one of the following (note the leading DOT): +{source_env_lines}" }; } @@ -494,15 +478,16 @@ Cargo's bin directory ({cargo_home}\\bin). #[cfg(not(windows))] macro_rules! post_install_msg_unix_no_modify_path { () => { - concat!( - r"# Rust is installed now. Great! + r"# Rust is installed now. Great! To get started you need Cargo's bin directory ({cargo_home}/bin) in your `PATH` environment variable. This has not been done automatically. -", - post_install_msg_unix_source_env!(), - ) +To configure your current shell, you need to source +the corresponding `env` file under {cargo_home}. + +This is usually done by running one of the following (note the leading DOT): +{source_env_lines}" }; } @@ -661,19 +646,19 @@ pub(crate) async fn install( format!(post_install_msg_win!(), cargo_home = cargo_home) }; #[cfg(not(windows))] - let cargo_home_nushell = Nu.cargo_home_str(cfg.process)?; + let source_env_lines = shell::build_source_env_lines(cfg.process); #[cfg(not(windows))] let msg = if no_modify_path { format!( post_install_msg_unix_no_modify_path!(), cargo_home = cargo_home, - cargo_home_nushell = cargo_home_nushell, + source_env_lines = source_env_lines, ) } else { format!( post_install_msg_unix!(), cargo_home = cargo_home, - cargo_home_nushell = cargo_home_nushell, + source_env_lines = source_env_lines, ) }; md(&mut term, msg); diff --git a/src/cli/self_update/shell.rs b/src/cli/self_update/shell.rs index 04396f5b60..79acd1f23c 100644 --- a/src/cli/self_update/shell.rs +++ b/src/cli/self_update/shell.rs @@ -73,6 +73,30 @@ fn enumerate_shells() -> Vec { ] } +/// Builds the shell source lines for the post-install message, showing only +/// shells that are available on the current system. Shells sharing the same +/// env file are grouped onto one line (e.g. sh/bash/zsh all use `env`). +pub(crate) fn build_source_env_lines(process: &Process) -> String { + let mut groups = Vec::<(String, Vec<&'static str>)>::new(); + for shell in get_available_shells(process) { + let Ok(src) = shell.source_string(process) else { + continue; + }; + if let Some(names) = groups + .iter_mut() + .find_map(|(s, names)| (*s == src).then_some(names)) + { + names.push(shell.name()); + } else { + groups.push((src, vec![shell.name()])); + } + } + groups + .into_iter() + .map(|(src, names)| format!(" {} # For {}\n", src, names.join("/"))) + .collect() +} + pub(crate) fn get_available_shells(process: &Process) -> impl Iterator + '_ { enumerate_shells() .into_iter() @@ -84,6 +108,9 @@ pub(crate) trait UnixShell { // heuristic should be used, assuming shells exist if any traces do. fn does_exist(&self, process: &Process) -> bool; + // Returns the display name of the shell, used in post-install messages. + fn name(&self) -> &'static str; + // Gives all rcfiles of a given shell that Rustup is concerned with. // Used primarily in checking rcfiles for cleanup. fn rcfiles(&self, process: &Process) -> Vec; @@ -128,6 +155,10 @@ impl UnixShell for Posix { true } + fn name(&self) -> &'static str { + "sh/ash/dash/pdksh" + } + fn rcfiles(&self, process: &Process) -> Vec { match process.home_dir() { Some(dir) => vec![dir.join(".profile")], @@ -149,6 +180,10 @@ impl UnixShell for Bash { !self.update_rcs(process).is_empty() } + fn name(&self) -> &'static str { + "bash" + } + fn rcfiles(&self, process: &Process) -> Vec { // Bash also may read .profile, however Rustup already includes handling // .profile as part of POSIX and always does setup for POSIX shells. @@ -197,6 +232,10 @@ impl UnixShell for Zsh { || utils::find_cmd(&["zsh"], process).is_some() } + fn name(&self) -> &'static str { + "zsh" + } + fn rcfiles(&self, process: &Process) -> Vec { [Zsh::zdotdir(process).ok(), process.home_dir()] .iter() @@ -229,6 +268,10 @@ impl UnixShell for Fish { || utils::find_cmd(&["fish"], process).is_some() } + fn name(&self) -> &'static str { + "fish" + } + // > "$XDG_CONFIG_HOME/fish/conf.d" (or "~/.config/fish/conf.d" if that variable is unset) for the user // from fn rcfiles(&self, process: &Process) -> Vec { @@ -278,6 +321,10 @@ impl UnixShell for Nu { || utils::find_cmd(&["nu"], process).is_some() } + fn name(&self) -> &'static str { + "nushell" + } + fn rcfiles(&self, process: &Process) -> Vec { let mut paths = vec![]; @@ -329,6 +376,10 @@ impl UnixShell for Tcsh { || utils::find_cmd(&["tcsh"], process).is_some() } + fn name(&self) -> &'static str { + "tcsh" + } + fn rcfiles(&self, process: &Process) -> Vec { let mut paths = vec![]; @@ -378,6 +429,10 @@ impl UnixShell for Pwsh { || utils::find_cmd(&["pwsh"], process).is_some() } + fn name(&self) -> &'static str { + "pwsh" + } + fn rcfiles(&self, process: &Process) -> Vec { let mut paths = vec![]; @@ -453,6 +508,10 @@ impl UnixShell for Xonsh { process.var("XONSHRC").is_ok() || utils::find_cmd(&["xonsh"], process).is_some() } + fn name(&self) -> &'static str { + "xonsh" + } + fn rcfiles(&self, process: &Process) -> Vec { let mut paths = vec![];