diff --git a/locales/app.yml b/locales/app.yml index 402d683c..87b6e22b 100644 --- a/locales/app.yml +++ b/locales/app.yml @@ -414,6 +414,14 @@ _version: 2 zh_CN: "在 $PATH 中找不到 %{binary_name} 二进制" zh_TW: "在 $PATH 中找不到 %{binary_name} 執行檔" de: "Kann %{binary_name} nicht im PATH finden" +"Cannot find any of {binary_names} in PATH": + en: "Cannot find any of %{binary_names} in PATH" + lt: "Nepavyksta rasti jokių %{binary_names} PATH sąraše" + es: "No se puede encontrar ninguno de %{binary_names} en PATH" + fr: "Impossible de trouver %{binary_names} dans PATH" + zh_CH: "在 PATH 中找不到 %{binary_names}" + zh_TW: "在 PATH 中找不到 %{binary_names}" + de: "Kann keines von %{binary_names} im PATH finden" "Failed to get a UTF-8 encoded hostname": en: "Failed to get a UTF-8 encoded hostname" lt: "Nepavyko gauti UTF-8 koduoto kompiuterio pavadinimo" diff --git a/src/steps/generic.rs b/src/steps/generic.rs index 25d788ec..1d8420c0 100644 --- a/src/steps/generic.rs +++ b/src/steps/generic.rs @@ -18,7 +18,9 @@ use crate::command::{CommandExt, Utf8Output}; use crate::execution_context::ExecutionContext; use crate::executor::ExecutorOutput; use crate::terminal::{print_separator, shell}; -use crate::utils::{check_is_python_2_or_shim, get_require_sudo_string, require, require_option, which, PathExt}; +use crate::utils::{ + check_is_python_2_or_shim, get_require_sudo_string, require, require_one, require_option, which, PathExt, +}; use crate::HOME_DIR; use crate::{ error::{SkipStep, StepFailed, TopgradeError}, @@ -1302,7 +1304,7 @@ pub fn run_poetry(ctx: &ExecutionContext) -> Result<()> { debug!("poetry interpreter: {:?}, args: {:?}", interp, interp_args); let check_official_install_script = - "import sys; from os import path; print('Y') if path.isfile(path.join(sys.prefix, 'poetry_env')) else print('N')"; + "import sys; from os import path; print('Y') if path.isfile(path.join(sys.prefix, 'poetry_env')) else print('N')"; let mut command = Command::new(&interp); if let Some(args) = interp_args { command.arg(args); @@ -1594,7 +1596,16 @@ fn run_jetbrains_ide(ctx: &ExecutionContext, bin: PathBuf, name: &str) -> Result pub fn run_android_studio(ctx: &ExecutionContext) -> Result<()> { // We don't use `run_jetbrains_ide` here because that would print "JetBrains Android Studio", // which is incorrect as Android Studio is made by Google. Just "Android Studio" is fine. - run_jetbrains_ide_generic::(ctx, require("studio")?, "Android Studio") + run_jetbrains_ide_generic::( + ctx, + require_one([ + "studio", + "android-studio", + "android-studio-beta", + "android-studio-canary", + ])?, + "Android Studio", + ) } pub fn run_jetbrains_aqua(ctx: &ExecutionContext) -> Result<()> { @@ -1602,31 +1613,43 @@ pub fn run_jetbrains_aqua(ctx: &ExecutionContext) -> Result<()> { } pub fn run_jetbrains_clion(ctx: &ExecutionContext) -> Result<()> { - run_jetbrains_ide(ctx, require("clion")?, "CLion") + run_jetbrains_ide(ctx, require_one(["clion", "clion-eap"])?, "CLion") } pub fn run_jetbrains_datagrip(ctx: &ExecutionContext) -> Result<()> { - run_jetbrains_ide(ctx, require("datagrip")?, "DataGrip") + run_jetbrains_ide(ctx, require_one(["datagrip", "datagrip-eap"])?, "DataGrip") } pub fn run_jetbrains_dataspell(ctx: &ExecutionContext) -> Result<()> { - run_jetbrains_ide(ctx, require("dataspell")?, "DataSpell") + run_jetbrains_ide(ctx, require_one(["dataspell", "dataspell-eap"])?, "DataSpell") } pub fn run_jetbrains_gateway(ctx: &ExecutionContext) -> Result<()> { - run_jetbrains_ide(ctx, require("gateway")?, "Gateway") + run_jetbrains_ide( + ctx, + require_one(["gateway", "jetbrains-gateway", "jetbrains-gateway-eap"])?, + "Gateway", + ) } pub fn run_jetbrains_goland(ctx: &ExecutionContext) -> Result<()> { - run_jetbrains_ide(ctx, require("goland")?, "Goland") + run_jetbrains_ide(ctx, require_one(["goland", "goland-eap"])?, "Goland") } pub fn run_jetbrains_idea(ctx: &ExecutionContext) -> Result<()> { - run_jetbrains_ide(ctx, require("idea")?, "IntelliJ IDEA") + run_jetbrains_ide( + ctx, + require_one([ + "idea", + "intellij-idea-ultimate-edition", + "intellij-idea-community-edition", + ])?, + "IntelliJ IDEA", + ) } pub fn run_jetbrains_mps(ctx: &ExecutionContext) -> Result<()> { - run_jetbrains_ide(ctx, require("mps")?, "MPS") + run_jetbrains_ide(ctx, require_one(["mps", "jetbrains-mps"])?, "MPS") } pub fn run_jetbrains_phpstorm(ctx: &ExecutionContext) -> Result<()> { @@ -1634,23 +1657,31 @@ pub fn run_jetbrains_phpstorm(ctx: &ExecutionContext) -> Result<()> { } pub fn run_jetbrains_pycharm(ctx: &ExecutionContext) -> Result<()> { - run_jetbrains_ide(ctx, require("pycharm")?, "PyCharm") + run_jetbrains_ide( + ctx, + require_one(["pycharm", "pycharm-professional", "pycharm-eap"])?, + "PyCharm", + ) } pub fn run_jetbrains_rider(ctx: &ExecutionContext) -> Result<()> { - run_jetbrains_ide(ctx, require("rider")?, "Rider") + run_jetbrains_ide(ctx, require_one(["rider", "rider-eap"])?, "Rider") } pub fn run_jetbrains_rubymine(ctx: &ExecutionContext) -> Result<()> { - run_jetbrains_ide(ctx, require("rubymine")?, "RubyMine") + run_jetbrains_ide( + ctx, + require_one(["rubymine", "jetbrains-rubymine", "rubymine-eap"])?, + "RubyMine", + ) } pub fn run_jetbrains_rustrover(ctx: &ExecutionContext) -> Result<()> { - run_jetbrains_ide(ctx, require("rustrover")?, "RustRover") + run_jetbrains_ide(ctx, require_one(["rustrover", "rustrover-eap"])?, "RustRover") } pub fn run_jetbrains_webstorm(ctx: &ExecutionContext) -> Result<()> { - run_jetbrains_ide(ctx, require("webstorm")?, "WebStorm") + run_jetbrains_ide(ctx, require_one(["webstorm", "webstorm-eap"])?, "WebStorm") } pub fn run_yazi(ctx: &ExecutionContext) -> Result<()> { diff --git a/src/utils.rs b/src/utils.rs index b20e6072..6f3afac0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -112,6 +112,29 @@ pub fn require + Debug>(binary_name: T) -> Result { } } +pub fn require_one + Debug>(binary_names: impl IntoIterator) -> Result { + let mut failed_bins = Vec::new(); + for bin in binary_names { + match require(&bin) { + Ok(path) => return Ok(path), + Err(_) => failed_bins.push(bin), + } + } + + Err(SkipStep(format!( + "{}", + t!( + "Cannot find any of {binary_names} in PATH", + binary_names = failed_bins + .iter() + .map(|bin| format!("{:?}", bin)) + .collect::>() + .join(", ") + ) + )) + .into()) +} + #[allow(dead_code)] pub fn require_option(option: Option, cause: String) -> Result { if let Some(value) = option {