diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05de5533..0b16c150 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,15 +35,29 @@ jobs: - name: Check if `Step` enum is sorted run: | ENUM_NAME="Step" - FILE="src/config.rs" + FILE="src/step.rs" awk "/enum $ENUM_NAME/,/}/" "$FILE" | \ grep -E '^\s*[A-Za-z_][A-Za-z0-9_]*\s*,?$' | \ sed 's/[, ]//g' > original.txt sort original.txt > sorted.txt diff original.txt sorted.txt + step-match-sorted: + name: Step match sorted + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Check if `Step::run()`'s match is sorted + run: | + FILE="src/step.rs" + awk '/[[:alpha:]] =>/{print $1}' $FILE > original.txt + sort original.txt > sorted.txt + diff original.txt sorted.txt + main: - needs: [fmt, step-enum-sorted] + needs: [ fmt, step-enum-sorted, step-match-sorted ] name: ${{ matrix.target_name }} (check, clippy) runs-on: ${{ matrix.os }} strategy: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e2fd5d9a..8a3de544 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ In `topgrade`'s term, package manager is called `step`. To add a new `step` to `topgrade`: 1. Add a new variant to - [`enum Step`](https://github.com/topgrade-rs/topgrade/blob/cb7adc8ced8a77addf2cb051d18bba9f202ab866/src/config.rs#L100) + [`enum Step`](https://github.com/topgrade-rs/topgrade/blob/main/src/step.rs) ```rust pub enum Step { @@ -32,9 +32,9 @@ To add a new `step` to `topgrade`: 2. Implement the update function You need to find the appropriate location where this update function goes, it should be - a file under [`src/steps`](https://github.com/topgrade-rs/topgrade/tree/master/src/steps), + a file under [`src/steps`](https://github.com/topgrade-rs/topgrade/tree/main/src/steps), the file names are self-explanatory, for example, `step`s related to `zsh` are - placed in [`steps/zsh.rs`](https://github.com/topgrade-rs/topgrade/blob/master/src/steps/zsh.rs). + placed in [`steps/zsh.rs`](https://github.com/topgrade-rs/topgrade/blob/main/src/steps/zsh.rs). Then you implement the update function, and put it in the file where it belongs. @@ -61,17 +61,17 @@ To add a new `step` to `topgrade`: [here](https://github.com/topgrade-rs/topgrade/blob/7e48c5dedcfd5d0124bb9f39079a03e27ed23886/src/main.rs#L201-L219)). Update function would usually do 3 things: - 1. Check if the step is installed - 2. Output the Separator - 3. Invoke the step + 1. Check if the step is installed + 2. Output the Separator + 3. Invoke the step Still, this is sufficient for most tools, but you may need some extra stuff with complicated `step`. -3. Finally, invoke that update function in `main.rs` +3. Add a match arm to `Step::run()` ```rust - runner.execute(Step::Xxx, "xxx", || ItsModule::run_xxx(&ctx))?; + Xxx => runner.execute(*self, "xxx", || ItsModule::run_xxx(ctx))? ``` We use [conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html) @@ -86,19 +86,25 @@ To add a new `step` to `topgrade`: } ``` +4. Finally, add the step to `default_steps()` in `step.rs` + ```rust + steps.push(Xxx) + ``` + Try to keep the conditional compilation the same as in the above step 3. + Congrats, you just added a new `step` :) ## Modification to the configuration entries If your PR has the configuration options -(in [`src/config.rs`](https://github.com/topgrade-rs/topgrade/blob/master/src/config.rs)) +(in [`src/config.rs`](https://github.com/topgrade-rs/topgrade/blob/main/src/config.rs)) modified: 1. Adding new options 2. Changing the existing options Be sure to apply your changes to -[`config.example.toml`](https://github.com/topgrade-rs/topgrade/blob/master/config.example.toml), +[`config.example.toml`](https://github.com/topgrade-rs/topgrade/blob/main/config.example.toml), and have some basic documentations guiding user how to use these options. ## Breaking changes @@ -138,7 +144,7 @@ without arguments (e.g., "hello world"), we can simply translate them according arguments, e.g., "hello ", please follow this convention: ```yml -"hello {name}": # key +"hello {name}": # key en: "hello %{name}" # translation ``` diff --git a/src/config.rs b/src/config.rs index 9e9a0ff1..d46c904b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -17,11 +17,12 @@ use regex::Regex; use regex_split::RegexSplit; use rust_i18n::t; use serde::Deserialize; -use strum::{EnumIter, EnumString, IntoEnumIterator, VariantNames}; +use strum::IntoEnumIterator; use which_crate::which; use super::utils::editor; use crate::command::CommandExt; +use crate::step::Step; use crate::sudo::SudoKind; use crate::utils::string_prepend_str; use tracing::{debug, error}; @@ -46,157 +47,6 @@ macro_rules! str_value { pub type Commands = IndexMap; -#[derive(ValueEnum, EnumString, VariantNames, Debug, Clone, PartialEq, Eq, Deserialize, EnumIter, Copy)] -#[clap(rename_all = "snake_case")] -#[serde(rename_all = "snake_case")] -#[strum(serialize_all = "snake_case")] -pub enum Step { - AM, - AndroidStudio, - AppMan, - Aqua, - Asdf, - Atom, - Audit, - AutoCpufreq, - Bin, - Bob, - BrewCask, - BrewFormula, - Bun, - BunPackages, - Cargo, - Certbot, - Chezmoi, - Chocolatey, - Choosenim, - CinnamonSpices, - ClamAvDb, - Composer, - Conda, - ConfigUpdate, - Containers, - CustomCommands, - DebGet, - Deno, - Distrobox, - DkpPacman, - Dotnet, - Elan, - Emacs, - Firmware, - Flatpak, - Flutter, - Fossil, - Gcloud, - Gem, - Ghcup, - GitRepos, - GithubCliExtensions, - GnomeShellExtensions, - Go, - Guix, - Haxelib, - Helix, - Helm, - HomeManager, - // These names are miscapitalized on purpose, so the CLI name is - // `jetbrains_pycharm` instead of `jet_brains_py_charm`. - JetbrainsAqua, - JetbrainsClion, - JetbrainsDatagrip, - JetbrainsDataspell, - JetbrainsGateway, - JetbrainsGoland, - JetbrainsIdea, - JetbrainsMps, - JetbrainsPhpstorm, - JetbrainsPycharm, - JetbrainsRider, - JetbrainsRubymine, - JetbrainsRustrover, - JetbrainsToolbox, - JetbrainsWebstorm, - Jetpack, - Julia, - Juliaup, - Kakoune, - Krew, - Lensfun, - Lure, - Macports, - Mamba, - Mas, - Maza, - Micro, - MicrosoftStore, - Miktex, - Mise, - Myrepos, - Nix, - NixHelper, - Node, - Opam, - Pacdef, - Pacstall, - Pearl, - Pip3, - PipReview, - PipReviewLocal, - Pipupgrade, - Pipx, - Pipxu, - Pixi, - Pkg, - Pkgin, - PlatformioCore, - Pnpm, - Poetry, - Powershell, - Protonup, - Pyenv, - Raco, - Rcm, - Remotes, - Restarts, - Rtcl, - RubyGems, - Rustup, - Rye, - Scoop, - Sdkman, - SelfUpdate, - Sheldon, - Shell, - Snap, - Sparkle, - Spicetify, - Stack, - Stew, - System, - Tldr, - Tlmgr, - Tmux, - Toolbx, - Uv, - Vagrant, - Vcpkg, - Vim, - VoltaPackages, - Vscode, - Vscodium, - Waydroid, - Winget, - Wsl, - WslUpdate, - Xcodes, - Yadm, - Yarn, - Yazi, - Zigup, - Zvm, -} - #[derive(Deserialize, Default, Debug, Merge)] #[serde(deny_unknown_fields)] pub struct Include { diff --git a/src/execution_context.rs b/src/execution_context.rs index a4cc8684..86a08b14 100644 --- a/src/execution_context.rs +++ b/src/execution_context.rs @@ -1,5 +1,7 @@ #![allow(dead_code)] use crate::executor::RunType; +#[cfg(target_os = "linux")] +use crate::steps::linux::Distribution; use crate::sudo::Sudo; use crate::utils::{get_require_sudo_string, require_option}; use crate::{config::Config, executor::Executor}; @@ -18,10 +20,17 @@ pub struct ExecutionContext<'a> { tmux_session: Mutex>, /// True if topgrade is running under ssh. under_ssh: bool, + #[cfg(target_os = "linux")] + distribution: &'a Result, } impl<'a> ExecutionContext<'a> { - pub fn new(run_type: RunType, sudo: Option, config: &'a Config) -> Self { + pub fn new( + run_type: RunType, + sudo: Option, + config: &'a Config, + #[cfg(target_os = "linux")] distribution: &'a Result, + ) -> Self { let under_ssh = var("SSH_CLIENT").is_ok() || var("SSH_TTY").is_ok(); Self { run_type, @@ -29,6 +38,8 @@ impl<'a> ExecutionContext<'a> { config, tmux_session: Mutex::new(None), under_ssh, + #[cfg(target_os = "linux")] + distribution, } } @@ -60,4 +71,9 @@ impl<'a> ExecutionContext<'a> { pub fn get_tmux_session(&self) -> Option { self.tmux_session.lock().unwrap().clone() } + + #[cfg(target_os = "linux")] + pub fn distribution(&self) -> &Result { + self.distribution + } } diff --git a/src/main.rs b/src/main.rs index 5737931f..a83ba732 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,7 +21,7 @@ use once_cell::sync::Lazy; use rust_i18n::{i18n, t}; use tracing::debug; -use self::config::{CommandLineArgs, Config, Step}; +use self::config::{CommandLineArgs, Config}; use self::error::StepFailed; #[cfg(all(windows, feature = "self-update"))] use self::error::Upgraded; @@ -29,8 +29,7 @@ use self::error::Upgraded; use self::steps::{remote::*, *}; #[allow(clippy::wildcard_imports)] use self::terminal::*; - -use self::utils::{hostname, install_color_eyre, install_tracing, update_tracing}; +use self::utils::{install_color_eyre, install_tracing, update_tracing}; mod breaking_changes; mod command; @@ -45,6 +44,7 @@ mod runner; mod self_renamer; #[cfg(feature = "self-update")] mod self_update; +mod step; mod steps; mod sudo; mod terminal; @@ -122,7 +122,7 @@ fn run() -> Result<()> { debug!("Version: {}", crate_version!()); debug!("OS: {}", env!("TARGET")); - debug!("{:?}", std::env::args()); + debug!("{:?}", env::args()); debug!("Binary path: {:?}", std::env::current_exe()); debug!("self-update Feature Enabled: {:?}", cfg!(feature = "self-update")); debug!("Configuration: {:?}", config); @@ -135,15 +135,18 @@ fn run() -> Result<()> { } } - let powershell = powershell::Powershell::new(); - let should_run_powershell = powershell.profile().is_some() && config.should_run(Step::Powershell); - let emacs = emacs::Emacs::new(); #[cfg(target_os = "linux")] let distribution = linux::Distribution::detect(); let sudo = config.sudo_command().map_or_else(sudo::Sudo::detect, sudo::Sudo::new); let run_type = executor::RunType::new(config.dry_run()); - let ctx = execution_context::ExecutionContext::new(run_type, sudo, &config); + let ctx = execution_context::ExecutionContext::new( + run_type, + sudo, + &config, + #[cfg(target_os = "linux")] + &distribution, + ); let mut runner = runner::Runner::new(&ctx); // If @@ -170,7 +173,7 @@ fn run() -> Result<()> { let should_self_update = env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() && !config.no_self_update(); if should_self_update { - runner.execute(Step::SelfUpdate, "Self Update", || self_update::self_update(&ctx))?; + runner.execute(step::Step::SelfUpdate, "Self Update", || self_update::self_update(&ctx))?; } } @@ -193,345 +196,10 @@ fn run() -> Result<()> { } } - if let Some(topgrades) = config.remote_topgrades() { - for remote_topgrade in topgrades.iter().filter(|t| config.should_execute_remote(hostname(), t)) { - runner.execute(Step::Remotes, format!("Remote ({remote_topgrade})"), || { - ssh::ssh_step(&ctx, remote_topgrade) - })?; - } + for step in step::default_steps() { + step.run(&mut runner, &ctx)? } - #[cfg(windows)] - { - runner.execute(Step::Wsl, "WSL", || windows::run_wsl_topgrade(&ctx))?; - runner.execute(Step::WslUpdate, "WSL", || windows::update_wsl(&ctx))?; - runner.execute(Step::Chocolatey, "Chocolatey", || windows::run_chocolatey(&ctx))?; - runner.execute(Step::Scoop, "Scoop", || windows::run_scoop(&ctx))?; - runner.execute(Step::Winget, "Winget", || windows::run_winget(&ctx))?; - runner.execute(Step::System, "Windows update", || windows::windows_update(&ctx))?; - runner.execute(Step::MicrosoftStore, "Microsoft Store", || { - windows::microsoft_store(&ctx) - })?; - } - - #[cfg(target_os = "linux")] - { - // NOTE: Due to breaking `nu` updates, `packer.nu` needs to be updated before `nu` get updated - // by other package managers. - runner.execute(Step::Shell, "packer.nu", || linux::run_packer_nu(&ctx))?; - - match &distribution { - Ok(distribution) => { - runner.execute(Step::System, "System update", || distribution.upgrade(&ctx))?; - } - Err(e) => { - println!("{}", t!("Error detecting current distribution: {error}", error = e)); - } - } - runner.execute(Step::ConfigUpdate, "config-update", || linux::run_config_update(&ctx))?; - - runner.execute(Step::AM, "am", || linux::run_am(&ctx))?; - runner.execute(Step::AppMan, "appman", || linux::run_appman(&ctx))?; - runner.execute(Step::DebGet, "deb-get", || linux::run_deb_get(&ctx))?; - runner.execute(Step::Toolbx, "toolbx", || toolbx::run_toolbx(&ctx))?; - runner.execute(Step::Snap, "snap", || linux::run_snap(&ctx))?; - runner.execute(Step::Pacstall, "pacstall", || linux::run_pacstall(&ctx))?; - runner.execute(Step::Pacdef, "pacdef", || linux::run_pacdef(&ctx))?; - runner.execute(Step::Protonup, "protonup", || linux::run_protonup_update(&ctx))?; - runner.execute(Step::Distrobox, "distrobox", || linux::run_distrobox_update(&ctx))?; - runner.execute(Step::DkpPacman, "dkp-pacman", || linux::run_dkp_pacman_update(&ctx))?; - runner.execute(Step::System, "pihole", || linux::run_pihole_update(&ctx))?; - runner.execute(Step::Firmware, "Firmware upgrades", || linux::run_fwupdmgr(&ctx))?; - runner.execute(Step::Restarts, "Restarts", || linux::run_needrestart(&ctx))?; - - runner.execute(Step::Flatpak, "Flatpak", || linux::run_flatpak(&ctx))?; - runner.execute(Step::BrewFormula, "Brew", || { - unix::run_brew_formula(&ctx, unix::BrewVariant::Path) - })?; - runner.execute(Step::Lure, "LURE", || linux::run_lure_update(&ctx))?; - runner.execute(Step::Waydroid, "Waydroid", || linux::run_waydroid(&ctx))?; - runner.execute(Step::AutoCpufreq, "auto-cpufreq", || linux::run_auto_cpufreq(&ctx))?; - runner.execute(Step::CinnamonSpices, "Cinnamon spices", || { - linux::run_cinnamon_spices_updater(&ctx) - })?; - } - - #[cfg(target_os = "macos")] - { - runner.execute(Step::BrewFormula, "Brew (ARM)", || { - unix::run_brew_formula(&ctx, unix::BrewVariant::MacArm) - })?; - runner.execute(Step::BrewFormula, "Brew (Intel)", || { - unix::run_brew_formula(&ctx, unix::BrewVariant::MacIntel) - })?; - runner.execute(Step::BrewFormula, "Brew", || { - unix::run_brew_formula(&ctx, unix::BrewVariant::Path) - })?; - runner.execute(Step::BrewCask, "Brew Cask (ARM)", || { - unix::run_brew_cask(&ctx, unix::BrewVariant::MacArm) - })?; - runner.execute(Step::BrewCask, "Brew Cask (Intel)", || { - unix::run_brew_cask(&ctx, unix::BrewVariant::MacIntel) - })?; - runner.execute(Step::BrewCask, "Brew Cask", || { - unix::run_brew_cask(&ctx, unix::BrewVariant::Path) - })?; - runner.execute(Step::Macports, "MacPorts", || macos::run_macports(&ctx))?; - runner.execute(Step::Xcodes, "Xcodes", || macos::update_xcodes(&ctx))?; - runner.execute(Step::Sparkle, "Sparkle", || macos::run_sparkle(&ctx))?; - runner.execute(Step::Mas, "App Store", || macos::run_mas(&ctx))?; - runner.execute(Step::System, "System upgrade", || macos::upgrade_macos(&ctx))?; - } - - #[cfg(target_os = "dragonfly")] - { - runner.execute(Step::Pkg, "DragonFly BSD Packages", || { - dragonfly::upgrade_packages(&ctx) - })?; - runner.execute(Step::Audit, "DragonFly Audit", || dragonfly::audit_packages(&ctx))?; - } - - #[cfg(target_os = "freebsd")] - { - runner.execute(Step::Pkg, "FreeBSD Packages", || freebsd::upgrade_packages(&ctx))?; - runner.execute(Step::System, "FreeBSD Upgrade", || freebsd::upgrade_freebsd(&ctx))?; - runner.execute(Step::Audit, "FreeBSD Audit", || freebsd::audit_packages(&ctx))?; - } - - #[cfg(target_os = "openbsd")] - { - runner.execute(Step::Pkg, "OpenBSD Packages", || openbsd::upgrade_packages(&ctx))?; - runner.execute(Step::System, "OpenBSD Upgrade", || openbsd::upgrade_openbsd(&ctx))?; - } - - #[cfg(target_os = "android")] - { - runner.execute(Step::Pkg, "Termux Packages", || android::upgrade_packages(&ctx))?; - } - - #[cfg(unix)] - { - runner.execute(Step::Yadm, "yadm", || unix::run_yadm(&ctx))?; - runner.execute(Step::Nix, "nix", || unix::run_nix(&ctx))?; - runner.execute(Step::Nix, "nix upgrade-nix", || unix::run_nix_self_upgrade(&ctx))?; - runner.execute(Step::NixHelper, "nh", || unix::run_nix_helper(&ctx))?; - runner.execute(Step::Guix, "guix", || unix::run_guix(&ctx))?; - runner.execute(Step::HomeManager, "home-manager", || unix::run_home_manager(&ctx))?; - runner.execute(Step::Asdf, "asdf", || unix::run_asdf(&ctx))?; - runner.execute(Step::Mise, "mise", || unix::run_mise(&ctx))?; - runner.execute(Step::Pkgin, "pkgin", || unix::run_pkgin(&ctx))?; - runner.execute(Step::BunPackages, "bun-packages", || unix::run_bun_packages(&ctx))?; - runner.execute(Step::Shell, "zr", || zsh::run_zr(&ctx))?; - runner.execute(Step::Shell, "antibody", || zsh::run_antibody(&ctx))?; - runner.execute(Step::Shell, "antidote", || zsh::run_antidote(&ctx))?; - runner.execute(Step::Shell, "antigen", || zsh::run_antigen(&ctx))?; - runner.execute(Step::Shell, "zgenom", || zsh::run_zgenom(&ctx))?; - runner.execute(Step::Shell, "zplug", || zsh::run_zplug(&ctx))?; - runner.execute(Step::Shell, "zinit", || zsh::run_zinit(&ctx))?; - runner.execute(Step::Shell, "zi", || zsh::run_zi(&ctx))?; - runner.execute(Step::Shell, "zim", || zsh::run_zim(&ctx))?; - runner.execute(Step::Shell, "oh-my-zsh", || zsh::run_oh_my_zsh(&ctx))?; - runner.execute(Step::Shell, "oh-my-bash", || unix::run_oh_my_bash(&ctx))?; - runner.execute(Step::Shell, "fisher", || unix::run_fisher(&ctx))?; - runner.execute(Step::Shell, "bash-it", || unix::run_bashit(&ctx))?; - runner.execute(Step::Shell, "oh-my-fish", || unix::run_oh_my_fish(&ctx))?; - runner.execute(Step::Shell, "fish-plug", || unix::run_fish_plug(&ctx))?; - runner.execute(Step::Shell, "fundle", || unix::run_fundle(&ctx))?; - runner.execute(Step::Tmux, "tmux", || tmux::run_tpm(&ctx))?; - runner.execute(Step::Tldr, "TLDR", || unix::run_tldr(&ctx))?; - runner.execute(Step::Pearl, "pearl", || unix::run_pearl(&ctx))?; - #[cfg(not(any(target_os = "macos", target_os = "android")))] - runner.execute(Step::GnomeShellExtensions, "Gnome Shell Extensions", || { - unix::upgrade_gnome_extensions(&ctx) - })?; - runner.execute(Step::Pyenv, "pyenv", || unix::run_pyenv(&ctx))?; - runner.execute(Step::Sdkman, "SDKMAN!", || unix::run_sdkman(&ctx))?; - runner.execute(Step::Rcm, "rcm", || unix::run_rcm(&ctx))?; - runner.execute(Step::Maza, "maza", || unix::run_maza(&ctx))?; - } - - #[cfg(not(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly" - )))] - { - runner.execute(Step::Atom, "apm", || generic::run_apm(&ctx))?; - } - - // The following update function should be executed on all OSes. - runner.execute(Step::Fossil, "fossil", || generic::run_fossil(&ctx))?; - runner.execute(Step::Elan, "elan", || generic::run_elan(&ctx))?; - runner.execute(Step::Rye, "rye", || generic::run_rye(&ctx))?; - runner.execute(Step::Rustup, "rustup", || generic::run_rustup(&ctx))?; - runner.execute(Step::Juliaup, "juliaup", || generic::run_juliaup(&ctx))?; - runner.execute(Step::Dotnet, ".NET", || generic::run_dotnet_upgrade(&ctx))?; - runner.execute(Step::Choosenim, "choosenim", || generic::run_choosenim(&ctx))?; - runner.execute(Step::Cargo, "cargo", || generic::run_cargo_update(&ctx))?; - runner.execute(Step::Flutter, "Flutter", || generic::run_flutter_upgrade(&ctx))?; - runner.execute(Step::Go, "go-global-update", || go::run_go_global_update(&ctx))?; - runner.execute(Step::Go, "gup", || go::run_go_gup(&ctx))?; - runner.execute(Step::Emacs, "Emacs", || emacs.upgrade(&ctx))?; - runner.execute(Step::Opam, "opam", || generic::run_opam_update(&ctx))?; - runner.execute(Step::Vcpkg, "vcpkg", || generic::run_vcpkg_update(&ctx))?; - runner.execute(Step::Pipx, "pipx", || generic::run_pipx_update(&ctx))?; - runner.execute(Step::Pipxu, "pipxu", || generic::run_pipxu_update(&ctx))?; - runner.execute(Step::Vscode, "Visual Studio Code extensions", || { - generic::run_vscode_extensions_update(&ctx) - })?; - runner.execute(Step::Vscodium, "VSCodium extensions", || { - generic::run_vscodium_extensions_update(&ctx) - })?; - runner.execute(Step::Conda, "conda", || generic::run_conda_update(&ctx))?; - runner.execute(Step::Mamba, "mamba", || generic::run_mamba_update(&ctx))?; - runner.execute(Step::Pixi, "pixi", || generic::run_pixi_update(&ctx))?; - runner.execute(Step::Miktex, "miktex", || generic::run_miktex_packages_update(&ctx))?; - runner.execute(Step::Pip3, "pip3", || generic::run_pip3_update(&ctx))?; - runner.execute(Step::PipReview, "pip-review", || generic::run_pip_review_update(&ctx))?; - runner.execute(Step::PipReviewLocal, "pip-review (local)", || { - generic::run_pip_review_local_update(&ctx) - })?; - runner.execute(Step::Pipupgrade, "pipupgrade", || generic::run_pipupgrade_update(&ctx))?; - runner.execute(Step::Ghcup, "ghcup", || generic::run_ghcup_update(&ctx))?; - runner.execute(Step::Stack, "stack", || generic::run_stack_update(&ctx))?; - runner.execute(Step::Tlmgr, "tlmgr", || generic::run_tlmgr_update(&ctx))?; - runner.execute(Step::Myrepos, "myrepos", || generic::run_myrepos_update(&ctx))?; - runner.execute(Step::Chezmoi, "chezmoi", || generic::run_chezmoi_update(&ctx))?; - runner.execute(Step::Jetpack, "jetpack", || generic::run_jetpack(&ctx))?; - runner.execute(Step::Vim, "vim", || vim::upgrade_vim(&ctx))?; - runner.execute(Step::Vim, "Neovim", || vim::upgrade_neovim(&ctx))?; - runner.execute(Step::Vim, "The Ultimate vimrc", || vim::upgrade_ultimate_vimrc(&ctx))?; - runner.execute(Step::Vim, "voom", || vim::run_voom(&ctx))?; - runner.execute(Step::Kakoune, "Kakoune", || kakoune::upgrade_kak_plug(&ctx))?; - runner.execute(Step::Helix, "helix", || generic::run_helix_grammars(&ctx))?; - runner.execute(Step::Node, "npm", || node::run_npm_upgrade(&ctx))?; - runner.execute(Step::Yarn, "yarn", || node::run_yarn_upgrade(&ctx))?; - runner.execute(Step::Pnpm, "pnpm", || node::run_pnpm_upgrade(&ctx))?; - runner.execute(Step::VoltaPackages, "volta packages", || { - node::run_volta_packages_upgrade(&ctx) - })?; - runner.execute(Step::Containers, "Containers", || containers::run_containers(&ctx))?; - runner.execute(Step::Deno, "deno", || node::deno_upgrade(&ctx))?; - runner.execute(Step::Composer, "composer", || generic::run_composer_update(&ctx))?; - runner.execute(Step::Krew, "krew", || generic::run_krew_upgrade(&ctx))?; - runner.execute(Step::Helm, "helm", || generic::run_helm_repo_update(&ctx))?; - runner.execute(Step::Gem, "gem", || generic::run_gem(&ctx))?; - runner.execute(Step::RubyGems, "rubygems", || generic::run_rubygems(&ctx))?; - runner.execute(Step::Julia, "julia", || generic::update_julia_packages(&ctx))?; - runner.execute(Step::Haxelib, "haxelib", || generic::run_haxelib_update(&ctx))?; - runner.execute(Step::Sheldon, "sheldon", || generic::run_sheldon(&ctx))?; - runner.execute(Step::Stew, "stew", || generic::run_stew(&ctx))?; - runner.execute(Step::Rtcl, "rtcl", || generic::run_rtcl(&ctx))?; - runner.execute(Step::Bin, "bin", || generic::bin_update(&ctx))?; - runner.execute(Step::Gcloud, "gcloud", || generic::run_gcloud_components_update(&ctx))?; - runner.execute(Step::Micro, "micro", || generic::run_micro(&ctx))?; - runner.execute(Step::Raco, "raco", || generic::run_raco_update(&ctx))?; - runner.execute(Step::Spicetify, "spicetify", || generic::spicetify_upgrade(&ctx))?; - runner.execute(Step::GithubCliExtensions, "GitHub CLI Extensions", || { - generic::run_ghcli_extensions_upgrade(&ctx) - })?; - runner.execute(Step::Bob, "Bob", || generic::run_bob(&ctx))?; - runner.execute(Step::Certbot, "Certbot", || generic::run_certbot(&ctx))?; - runner.execute(Step::GitRepos, "Git Repositories", || git::run_git_pull(&ctx))?; - runner.execute(Step::ClamAvDb, "ClamAV Databases", || generic::run_freshclam(&ctx))?; - runner.execute(Step::PlatformioCore, "PlatformIO Core", || { - generic::run_platform_io(&ctx) - })?; - runner.execute(Step::Lensfun, "Lensfun's database update", || { - generic::run_lensfun_update_data(&ctx) - })?; - runner.execute(Step::Poetry, "Poetry", || generic::run_poetry(&ctx))?; - runner.execute(Step::Uv, "uv", || generic::run_uv(&ctx))?; - runner.execute(Step::Zvm, "ZVM", || generic::run_zvm(&ctx))?; - runner.execute(Step::Aqua, "aqua", || generic::run_aqua(&ctx))?; - runner.execute(Step::Bun, "bun", || generic::run_bun(&ctx))?; - runner.execute(Step::Zigup, "zigup", || generic::run_zigup(&ctx))?; - runner.execute(Step::JetbrainsToolbox, "JetBrains Toolbox", || { - generic::run_jetbrains_toolbox(&ctx) - })?; - runner.execute(Step::AndroidStudio, "Android Studio plugins", || { - generic::run_android_studio(&ctx) - })?; - runner.execute(Step::JetbrainsAqua, "JetBrains Aqua plugins", || { - generic::run_jetbrains_aqua(&ctx) - })?; - runner.execute(Step::JetbrainsClion, "JetBrains CLion plugins", || { - generic::run_jetbrains_clion(&ctx) - })?; - runner.execute(Step::JetbrainsDatagrip, "JetBrains DataGrip plugins", || { - generic::run_jetbrains_datagrip(&ctx) - })?; - runner.execute(Step::JetbrainsDataspell, "JetBrains DataSpell plugins", || { - generic::run_jetbrains_dataspell(&ctx) - })?; - // JetBrains dotCover has no CLI - // JetBrains dotMemory has no CLI - // JetBrains dotPeek has no CLI - // JetBrains dotTrace has no CLI - // JetBrains Fleet has a different CLI without a `fleet update` command. - runner.execute(Step::JetbrainsGateway, "JetBrains Gateway plugins", || { - generic::run_jetbrains_gateway(&ctx) - })?; - runner.execute(Step::JetbrainsGoland, "JetBrains GoLand plugins", || { - generic::run_jetbrains_goland(&ctx) - })?; - runner.execute(Step::JetbrainsIdea, "JetBrains IntelliJ IDEA plugins", || { - generic::run_jetbrains_idea(&ctx) - })?; - runner.execute(Step::JetbrainsMps, "JetBrains MPS plugins", || { - generic::run_jetbrains_mps(&ctx) - })?; - runner.execute(Step::JetbrainsPhpstorm, "JetBrains PhpStorm plugins", || { - generic::run_jetbrains_phpstorm(&ctx) - })?; - runner.execute(Step::JetbrainsPycharm, "JetBrains PyCharm plugins", || { - generic::run_jetbrains_pycharm(&ctx) - })?; - // JetBrains ReSharper has no CLI (it's a VSCode extension) - // JetBrains ReSharper C++ has no CLI (it's a VSCode extension) - runner.execute(Step::JetbrainsRider, "JetBrains Rider plugins", || { - generic::run_jetbrains_rider(&ctx) - })?; - runner.execute(Step::JetbrainsRubymine, "JetBrains RubyMine plugins", || { - generic::run_jetbrains_rubymine(&ctx) - })?; - runner.execute(Step::JetbrainsRustrover, "JetBrains RustRover plugins", || { - generic::run_jetbrains_rustrover(&ctx) - })?; - // JetBrains Space Desktop does not have a CLI - runner.execute(Step::JetbrainsWebstorm, "JetBrains WebStorm plugins", || { - generic::run_jetbrains_webstorm(&ctx) - })?; - runner.execute(Step::Yazi, "Yazi packages", || generic::run_yazi(&ctx))?; - - if should_run_powershell { - runner.execute(Step::Powershell, "Powershell Modules Update", || { - powershell.update_modules(&ctx) - })?; - } - - if let Some(commands) = config.commands() { - for (name, command) in commands { - if config.should_run_custom_command(name) { - runner.execute(Step::CustomCommands, name, || { - generic::run_custom_command(name, command, &ctx) - })?; - } - } - } - - if config.should_run(Step::Vagrant) { - if let Ok(boxes) = vagrant::collect_boxes(&ctx) { - for vagrant_box in boxes { - runner.execute(Step::Vagrant, format!("Vagrant ({})", vagrant_box.smart_name()), || { - vagrant::topgrade_vagrant_box(&ctx, &vagrant_box) - })?; - } - } - } - runner.execute(Step::Vagrant, "Vagrant boxes", || vagrant::upgrade_vagrant_boxes(&ctx))?; - if !runner.report().data().is_empty() { print_separator(t!("Summary")); diff --git a/src/runner.rs b/src/runner.rs index af26c725..730b62dd 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -2,8 +2,9 @@ use crate::ctrlc; use crate::error::{DryRun, SkipStep}; use crate::execution_context::ExecutionContext; use crate::report::{Report, StepResult}; +use crate::step::Step; use crate::terminal::print_error; -use crate::{config::Step, terminal::should_retry}; +use crate::terminal::should_retry; use color_eyre::eyre::Result; use std::borrow::Cow; use std::fmt::Debug; diff --git a/src/self_update.rs b/src/self_update.rs index f18cca16..6a237905 100644 --- a/src/self_update.rs +++ b/src/self_update.rs @@ -3,7 +3,7 @@ use std::env; use std::os::unix::process::CommandExt as _; use std::process::Command; -use crate::config::Step; +use crate::step::Step; use color_eyre::eyre::{bail, Result}; use rust_i18n::t; use self_update_crate::backends::github::Update; diff --git a/src/step.rs b/src/step.rs new file mode 100644 index 00000000..866b80ef --- /dev/null +++ b/src/step.rs @@ -0,0 +1,859 @@ +use crate::execution_context::ExecutionContext; +use crate::runner::Runner; +use clap::ValueEnum; +use color_eyre::Result; +#[cfg(target_os = "linux")] +use rust_i18n::t; +use serde::Deserialize; +use strum::{EnumCount, EnumIter, EnumString, VariantNames}; + +#[cfg(feature = "self-update")] +use crate::self_update; +use crate::steps::remote::vagrant; +#[allow(clippy::wildcard_imports)] +use crate::steps::*; +use crate::utils::hostname; + +#[derive(ValueEnum, EnumString, VariantNames, Debug, Clone, PartialEq, Eq, Deserialize, EnumIter, Copy, EnumCount)] +#[clap(rename_all = "snake_case")] +#[serde(rename_all = "snake_case")] +#[strum(serialize_all = "snake_case")] +pub enum Step { + AM, + AndroidStudio, + AppMan, + Aqua, + Asdf, + Atom, + Audit, + AutoCpufreq, + Bin, + Bob, + BrewCask, + BrewFormula, + Bun, + BunPackages, + Cargo, + Certbot, + Chezmoi, + Chocolatey, + Choosenim, + CinnamonSpices, + ClamAvDb, + Composer, + Conda, + ConfigUpdate, + Containers, + CustomCommands, + DebGet, + Deno, + Distrobox, + DkpPacman, + Dotnet, + Elan, + Emacs, + Firmware, + Flatpak, + Flutter, + Fossil, + Gcloud, + Gem, + Ghcup, + GitRepos, + GithubCliExtensions, + GnomeShellExtensions, + Go, + Guix, + Haxelib, + Helix, + Helm, + HomeManager, + // These names are miscapitalized on purpose, so the CLI name is + // `jetbrains_pycharm` instead of `jet_brains_py_charm`. + JetbrainsAqua, + JetbrainsClion, + JetbrainsDatagrip, + JetbrainsDataspell, + JetbrainsGateway, + JetbrainsGoland, + JetbrainsIdea, + JetbrainsMps, + JetbrainsPhpstorm, + JetbrainsPycharm, + JetbrainsRider, + JetbrainsRubymine, + JetbrainsRustrover, + JetbrainsToolbox, + JetbrainsWebstorm, + Jetpack, + Julia, + Juliaup, + Kakoune, + Krew, + Lensfun, + Lure, + Macports, + Mamba, + Mas, + Maza, + Micro, + MicrosoftStore, + Miktex, + Mise, + Myrepos, + Nix, + NixHelper, + Node, + Opam, + Pacdef, + Pacstall, + Pearl, + Pip3, + PipReview, + PipReviewLocal, + Pipupgrade, + Pipx, + Pipxu, + Pixi, + Pkg, + Pkgin, + PlatformioCore, + Pnpm, + Poetry, + Powershell, + Protonup, + Pyenv, + Raco, + Rcm, + Remotes, + Restarts, + Rtcl, + RubyGems, + Rustup, + Rye, + Scoop, + Sdkman, + SelfUpdate, + Sheldon, + Shell, + Snap, + Sparkle, + Spicetify, + Stack, + Stew, + System, + Tldr, + Tlmgr, + Tmux, + Toolbx, + Uv, + Vagrant, + Vcpkg, + Vim, + VoltaPackages, + Vscode, + Vscodium, + Waydroid, + Winget, + Wsl, + WslUpdate, + Xcodes, + Yadm, + Yarn, + Yazi, + Zigup, + Zvm, +} + +impl Step { + #[allow(clippy::too_many_lines)] + pub fn run(&self, runner: &mut Runner, ctx: &ExecutionContext) -> Result<()> { + use Step::*; + + match *self { + AM => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "am", || linux::run_am(ctx))? + } + AndroidStudio => runner.execute(*self, "Android Studio Plugins", || generic::run_android_studio(ctx))?, + AppMan => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "appman", || linux::run_appman(ctx))? + } + Aqua => runner.execute(*self, "aqua", || generic::run_aqua(ctx))?, + Asdf => + { + #[cfg(unix)] + runner.execute(*self, "asdf", || unix::run_asdf(ctx))? + } + Atom => + { + #[cfg(not(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + )))] + runner.execute(*self, "apm", || generic::run_apm(ctx))? + } + Audit => { + #[cfg(target_os = "dragonfly")] + runner.execute(*self, "DragonFly Audit", || dragonfly::audit_packages(ctx))?; + #[cfg(target_os = "freebsd")] + runner.execute(*self, "FreeBSD Audit", || freebsd::audit_packages(ctx))? + } + AutoCpufreq => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "auto-cpufreq", || linux::run_auto_cpufreq(ctx))? + } + Bin => runner.execute(*self, "bin", || generic::bin_update(ctx))?, + Bob => runner.execute(*self, "Bob", || generic::run_bob(ctx))?, + BrewCask => { + #[cfg(target_os = "macos")] + runner.execute(*self, "Brew Cask", || unix::run_brew_cask(ctx, unix::BrewVariant::Path))?; + #[cfg(target_os = "macos")] + runner.execute(*self, "Brew Cask (Intel)", || { + unix::run_brew_cask(ctx, unix::BrewVariant::MacIntel) + })?; + #[cfg(target_os = "macos")] + runner.execute(*self, "Brew Cask (ARM)", || { + unix::run_brew_cask(ctx, unix::BrewVariant::MacArm) + })? + } + BrewFormula => { + #[cfg(target_os = "linux")] + runner.execute(*self, "Brew", || unix::run_brew_formula(ctx, unix::BrewVariant::Path))?; + #[cfg(target_os = "macos")] + runner.execute(*self, "Brew (ARM)", || { + unix::run_brew_formula(ctx, unix::BrewVariant::MacArm) + })?; + #[cfg(target_os = "macos")] + runner.execute(*self, "Brew (Intel)", || { + unix::run_brew_formula(ctx, unix::BrewVariant::MacIntel) + })? + } + Bun => runner.execute(*self, "bun", || generic::run_bun(ctx))?, + BunPackages => + { + #[cfg(unix)] + runner.execute(*self, "bun-packages", || unix::run_bun_packages(ctx))? + } + Cargo => runner.execute(*self, "cargo", || generic::run_cargo_update(ctx))?, + Certbot => runner.execute(*self, "Certbot", || generic::run_certbot(ctx))?, + Chezmoi => runner.execute(*self, "chezmoi", || generic::run_chezmoi_update(ctx))?, + Chocolatey => + { + #[cfg(windows)] + runner.execute(*self, "Chocolatey", || windows::run_chocolatey(ctx))? + } + Choosenim => runner.execute(*self, "choosenim", || generic::run_choosenim(ctx))?, + CinnamonSpices => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "Cinnamon spices", || linux::run_cinnamon_spices_updater(ctx))? + } + ClamAvDb => runner.execute(*self, "ClamAV Databases", || generic::run_freshclam(ctx))?, + Composer => runner.execute(*self, "composer", || generic::run_composer_update(ctx))?, + Conda => runner.execute(*self, "conda", || generic::run_conda_update(ctx))?, + ConfigUpdate => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "config-update", || linux::run_config_update(ctx))? + } + Containers => runner.execute(*self, "Containers", || containers::run_containers(ctx))?, + CustomCommands => { + if let Some(commands) = ctx.config().pre_commands() { + for (name, command) in commands { + generic::run_custom_command(name, command, ctx)?; + } + } + } + DebGet => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "deb-get", || linux::run_deb_get(ctx))? + } + Deno => runner.execute(*self, "deno", || node::deno_upgrade(ctx))?, + Distrobox => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "distrobox", || linux::run_distrobox_update(ctx))? + } + DkpPacman => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "dkp-pacman", || linux::run_dkp_pacman_update(ctx))? + } + Dotnet => runner.execute(*self, ".NET", || generic::run_dotnet_upgrade(ctx))?, + Elan => runner.execute(*self, "elan", || generic::run_elan(ctx))?, + Emacs => runner.execute(*self, "Emacs", || emacs::Emacs::new().upgrade(ctx))?, + Firmware => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "Firmware", || linux::run_fwupdmgr(ctx))? + } + Flatpak => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "Flatpak", || linux::run_flatpak(ctx))? + } + Flutter => runner.execute(*self, "Flutter", || generic::run_flutter_upgrade(ctx))?, + Fossil => runner.execute(*self, "fossil", || generic::run_fossil(ctx))?, + Gcloud => runner.execute(*self, "gcloud", || generic::run_gcloud_components_update(ctx))?, + Gem => runner.execute(*self, "gem", || generic::run_gem(ctx))?, + Ghcup => runner.execute(*self, "ghcup", || generic::run_ghcup_update(ctx))?, + GitRepos => runner.execute(*self, "Git Repositories", || git::run_git_pull(ctx))?, + GithubCliExtensions => runner.execute(*self, "GitHub CLI Extenstions", || { + generic::run_ghcli_extensions_upgrade(ctx) + })?, + GnomeShellExtensions => + { + #[cfg(all(unix, not(any(target_os = "macos", target_os = "android"))))] + runner.execute(*self, "Gnome Shell Extensions", || unix::upgrade_gnome_extensions(ctx))? + } + Go => { + runner.execute(*self, "go-global-update", || go::run_go_global_update(ctx))?; + runner.execute(*self, "gup", || go::run_go_gup(ctx))? + } + Guix => + { + #[cfg(unix)] + runner.execute(*self, "guix", || unix::run_guix(ctx))? + } + Haxelib => runner.execute(*self, "haxelib", || generic::run_haxelib_update(ctx))?, + Helix => runner.execute(*self, "helix", || generic::run_helix_grammars(ctx))?, + Helm => runner.execute(*self, "helm", || generic::run_helm_repo_update(ctx))?, + HomeManager => + { + #[cfg(unix)] + runner.execute(*self, "home-manager", || unix::run_home_manager(ctx))? + } + JetbrainsAqua => runner.execute(*self, "JetBrains Aqua Plugins", || generic::run_jetbrains_aqua(ctx))?, + JetbrainsClion => runner.execute(*self, "JetBrains CL", || generic::run_jetbrains_clion(ctx))?, + JetbrainsDatagrip => { + runner.execute(*self, "JetBrains DataGrip", || generic::run_jetbrains_datagrip(ctx))? + } + JetbrainsDataspell => runner.execute(*self, "JetBrains DataSpell Plugins", || { + generic::run_jetbrains_dataspell(ctx) + })?, + JetbrainsGateway => runner.execute(*self, "JetBrains Gateway Plugins", || { + generic::run_jetbrains_gateway(ctx) + })?, + JetbrainsGoland => { + runner.execute(*self, "JetBrains GoLand Plugins", || generic::run_jetbrains_goland(ctx))? + } + JetbrainsIdea => runner.execute(*self, "JetBrains IntelliJ IDEA Plugins", || { + generic::run_jetbrains_idea(ctx) + })?, + JetbrainsMps => runner.execute(*self, "JetBrains MPS Plugins", || generic::run_jetbrains_mps(ctx))?, + JetbrainsPhpstorm => runner.execute(*self, "JetBrains PhpStorm Plugins", || { + generic::run_jetbrains_phpstorm(ctx) + })?, + JetbrainsPycharm => runner.execute(*self, "JetBrains PyCharm Plugins", || { + generic::run_jetbrains_pycharm(ctx) + })?, + JetbrainsRider => runner.execute(*self, "JetBrains Rider Plugins", || generic::run_jetbrains_rider(ctx))?, + JetbrainsRubymine => runner.execute(*self, "JetBrains RubyMine Plugins", || { + generic::run_jetbrains_rubymine(ctx) + })?, + JetbrainsRustrover => runner.execute(*self, "JetBrains RustRover Plugins", || { + generic::run_jetbrains_rustrover(ctx) + })?, + JetbrainsToolbox => runner.execute(*self, "JetBrains Toolbox", || generic::run_jetbrains_toolbox(ctx))?, + JetbrainsWebstorm => runner.execute(*self, "JetBrains WebStorm Plugins", || { + generic::run_jetbrains_webstorm(ctx) + })?, + Jetpack => runner.execute(*self, "jetpack", || generic::run_jetpack(ctx))?, + Julia => runner.execute(*self, "julia", || generic::update_julia_packages(ctx))?, + Juliaup => runner.execute(*self, "juliaup", || generic::run_juliaup(ctx))?, + Kakoune => runner.execute(*self, "Kakoune", || kakoune::upgrade_kak_plug(ctx))?, + Krew => runner.execute(*self, "krew", || generic::run_krew_upgrade(ctx))?, + Lensfun => runner.execute(*self, "Lensfun's database update", || { + generic::run_lensfun_update_data(ctx) + })?, + Lure => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "LURE", || linux::run_lure_update(ctx))? + } + Macports => + { + #[cfg(target_os = "macos")] + runner.execute(*self, "MacPorts", || macos::run_macports(ctx))? + } + Mamba => runner.execute(*self, "mamba", || generic::run_mamba_update(ctx))?, + Mas => + { + #[cfg(target_os = "macos")] + runner.execute(*self, "App Store", || macos::run_mas(ctx))? + } + Maza => + { + #[cfg(unix)] + runner.execute(*self, "maza", || unix::run_maza(ctx))? + } + Micro => runner.execute(*self, "micro", || generic::run_micro(ctx))?, + MicrosoftStore => + { + #[cfg(windows)] + runner.execute(*self, "Microsoft Store", || windows::microsoft_store(ctx))? + } + Miktex => runner.execute(*self, "miktex", || generic::run_miktex_packages_update(ctx))?, + Mise => + { + #[cfg(unix)] + runner.execute(*self, "mise", || unix::run_mise(ctx))? + } + Myrepos => runner.execute(*self, "myrepos", || generic::run_myrepos_update(ctx))?, + Nix => { + #[cfg(unix)] + runner.execute(*self, "nix", || unix::run_nix(ctx))?; + #[cfg(unix)] + runner.execute(*self, "nix upgrade-nix", || unix::run_nix_self_upgrade(ctx))? + } + NixHelper => + { + #[cfg(unix)] + runner.execute(*self, "nh", || unix::run_nix_helper(ctx))? + } + Node => runner.execute(*self, "npm", || node::run_npm_upgrade(ctx))?, + Opam => runner.execute(*self, "opam", || generic::run_opam_update(ctx))?, + Pacdef => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "pacdef", || linux::run_pacdef(ctx))? + } + Pacstall => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "pacstall", || linux::run_pacstall(ctx))? + } + Pearl => + { + #[cfg(unix)] + runner.execute(*self, "pearl", || unix::run_pearl(ctx))? + } + Pip3 => runner.execute(*self, "pip3", || generic::run_pip3_update(ctx))?, + PipReview => runner.execute(*self, "pip-review", || generic::run_pip_review_update(ctx))?, + PipReviewLocal => runner.execute(*self, "pip-review (local)", || { + generic::run_pip_review_local_update(ctx) + })?, + Pipupgrade => runner.execute(*self, "pipupgrade", || generic::run_pipupgrade_update(ctx))?, + Pipx => runner.execute(*self, "pipx", || generic::run_pipx_update(ctx))?, + Pipxu => runner.execute(*self, "pipxu", || generic::run_pipxu_update(ctx))?, + Pixi => runner.execute(*self, "pixi", || generic::run_pixi_update(ctx))?, + Pkg => { + #[cfg(target_os = "dragonfly")] + runner.execute(*self, "Dragonfly BSD Packages", || dragonfly::upgrade_packages(ctx))?; + #[cfg(target_os = "freebsd")] + runner.execute(*self, "FreeBSD Packages", || freebsd::upgrade_packages(ctx))?; + #[cfg(target_os = "openbsd")] + runner.execute(*self, "OpenBSD Packages", || openbsd::upgrade_packages(ctx))?; + #[cfg(target_os = "android")] + runner.execute(*self, "Termux Packages", || android::upgrade_packages(ctx))? + } + Pkgin => + { + #[cfg(unix)] + runner.execute(*self, "pkgin", || unix::run_pkgin(ctx))? + } + PlatformioCore => runner.execute(*self, "PlatformIO Core", || generic::run_platform_io(ctx))?, + Pnpm => runner.execute(*self, "pnpm", || node::run_pnpm_upgrade(ctx))?, + Poetry => runner.execute(*self, "Poetry", || generic::run_poetry(ctx))?, + Powershell => { + let powershell = powershell::Powershell::new(); + if powershell.profile().is_some() { + runner.execute(Powershell, "Powershell Modules Update", || { + powershell.update_modules(ctx) + })?; + } + } + Protonup => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "protonup", || linux::run_protonup_update(ctx))? + } + Pyenv => + { + #[cfg(unix)] + runner.execute(*self, "pyenv", || unix::run_pyenv(ctx))? + } + Raco => runner.execute(*self, "raco", || generic::run_raco_update(ctx))?, + Rcm => + { + #[cfg(unix)] + runner.execute(*self, "rcm", || unix::run_rcm(ctx))? + } + Remotes => { + if let Some(topgrades) = ctx.config().remote_topgrades() { + for remote_topgrade in topgrades + .iter() + .filter(|t| ctx.config().should_execute_remote(hostname(), t)) + { + runner.execute(Remotes, format!("Remote ({remote_topgrade})"), || { + crate::ssh::ssh_step(ctx, remote_topgrade) + })?; + } + } + } + Restarts => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "Restarts", || linux::run_needrestart(ctx))? + } + Rtcl => runner.execute(*self, "rtcl", || generic::run_rtcl(ctx))?, + RubyGems => runner.execute(*self, "rubygems", || generic::run_rubygems(ctx))?, + Rustup => runner.execute(*self, "rustup", || generic::run_rustup(ctx))?, + Rye => runner.execute(*self, "rye", || generic::run_rye(ctx))?, + Scoop => + { + #[cfg(windows)] + runner.execute(*self, "Scoop", || windows::run_scoop(ctx))? + } + Sdkman => + { + #[cfg(unix)] + runner.execute(*self, "SDKMAN!", || unix::run_sdkman(ctx))? + } + SelfUpdate => { + #[cfg(feature = "self-update")] + { + if std::env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() && !ctx.config().no_self_update() { + runner.execute(*self, "Self Update", || self_update::self_update(ctx))?; + } + } + } + Sheldon => runner.execute(*self, "sheldon", || generic::run_sheldon(ctx))?, + Shell => { + #[cfg(unix)] + { + runner.execute(*self, "zr", || zsh::run_zr(ctx))?; + runner.execute(*self, "antibody", || zsh::run_antibody(ctx))?; + runner.execute(*self, "antidote", || zsh::run_antidote(ctx))?; + runner.execute(*self, "antigen", || zsh::run_antigen(ctx))?; + runner.execute(*self, "zgenom", || zsh::run_zgenom(ctx))?; + runner.execute(*self, "zplug", || zsh::run_zplug(ctx))?; + runner.execute(*self, "zinit", || zsh::run_zinit(ctx))?; + runner.execute(*self, "zi", || zsh::run_zi(ctx))?; + runner.execute(*self, "zim", || zsh::run_zim(ctx))?; + runner.execute(*self, "oh-my-zsh", || zsh::run_oh_my_zsh(ctx))?; + runner.execute(*self, "oh-my-bash", || unix::run_oh_my_bash(ctx))?; + runner.execute(*self, "fisher", || unix::run_fisher(ctx))?; + runner.execute(*self, "bash-it", || unix::run_bashit(ctx))?; + runner.execute(*self, "oh-my-fish", || unix::run_oh_my_fish(ctx))?; + runner.execute(*self, "fish-plug", || unix::run_fish_plug(ctx))?; + runner.execute(*self, "fundle", || unix::run_fundle(ctx))? + } + } + Snap => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "snap", || linux::run_snap(ctx))? + } + Sparkle => + { + #[cfg(target_os = "macos")] + runner.execute(*self, "Sparkle", || macos::run_sparkle(ctx))? + } + Spicetify => runner.execute(*self, "spicetify", || generic::spicetify_upgrade(ctx))?, + Stack => runner.execute(*self, "stack", || generic::run_stack_update(ctx))?, + Stew => runner.execute(*self, "stew", || generic::run_stew(ctx))?, + System => { + #[cfg(target_os = "linux")] + { + // NOTE: Due to breaking `nu` updates, `packer.nu` needs to be updated before `nu` get updated + // by other package managers. + runner.execute(Shell, "packer.nu", || linux::run_packer_nu(ctx))?; + + match ctx.distribution() { + Ok(distribution) => { + runner.execute(System, "System update", || distribution.upgrade(ctx))?; + } + Err(e) => { + println!("{}", t!("Error detecting current distribution: {error}", error = e)); + } + } + runner.execute(*self, "pihole", || linux::run_pihole_update(ctx))?; + } + #[cfg(windows)] + runner.execute(*self, "Windows update", || windows::windows_update(ctx))?; + #[cfg(target_os = "macos")] + runner.execute(*self, "System update", || macos::upgrade_macos(ctx))?; + #[cfg(target_os = "freebsd")] + runner.execute(*self, "FreeBSD Upgrade", || freebsd::upgrade_freebsd(ctx))?; + #[cfg(target_os = "openbsd")] + runner.execute(*self, "OpenBSD Upgrade", || openbsd::upgrade_openbsd(ctx))? + } + Tldr => + { + #[cfg(unix)] + runner.execute(*self, "TLDR", || unix::run_tldr(ctx))? + } + Tlmgr => runner.execute(*self, "tlmgr", || generic::run_tlmgr_update(ctx))?, + Tmux => + { + #[cfg(unix)] + runner.execute(*self, "tmux", || tmux::run_tpm(ctx))? + } + Toolbx => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "toolbx", || toolbx::run_toolbx(ctx))? + } + Uv => runner.execute(*self, "uv", || generic::run_uv(ctx))?, + Vagrant => { + if ctx.config().should_run(Vagrant) { + if let Ok(boxes) = vagrant::collect_boxes(ctx) { + for vagrant_box in boxes { + runner.execute(Vagrant, format!("Vagrant ({})", vagrant_box.smart_name()), || { + vagrant::topgrade_vagrant_box(ctx, &vagrant_box) + })?; + } + } + } + runner.execute(Vagrant, "Vagrant boxes", || vagrant::upgrade_vagrant_boxes(ctx))?; + } + Vcpkg => runner.execute(*self, "vcpkg", || generic::run_vcpkg_update(ctx))?, + Vim => { + runner.execute(*self, "vim", || vim::upgrade_vim(ctx))?; + runner.execute(*self, "Neovim", || vim::upgrade_neovim(ctx))?; + runner.execute(*self, "The Ultimate vimrc", || vim::upgrade_ultimate_vimrc(ctx))?; + runner.execute(*self, "voom", || vim::run_voom(ctx))? + } + VoltaPackages => runner.execute(*self, "volta packages", || node::run_volta_packages_upgrade(ctx))?, + Vscode => runner.execute(*self, "Visual Studio Code extensions", || { + generic::run_vscode_extensions_update(ctx) + })?, + Vscodium => runner.execute(*self, "VSCodium extensions", || { + generic::run_vscodium_extensions_update(ctx) + })?, + Waydroid => + { + #[cfg(target_os = "linux")] + runner.execute(*self, "Waydroid", || linux::run_waydroid(ctx))? + } + Winget => + { + #[cfg(windows)] + runner.execute(*self, "Winget", || windows::run_winget(ctx))? + } + Wsl => + { + #[cfg(windows)] + runner.execute(*self, "WSL", || windows::run_wsl_topgrade(ctx))? + } + WslUpdate => + { + #[cfg(windows)] + runner.execute(*self, "WSL", || windows::update_wsl(ctx))? + } + Xcodes => + { + #[cfg(target_os = "macos")] + runner.execute(*self, "Xcodes", || macos::update_xcodes(ctx))? + } + Yadm => + { + #[cfg(unix)] + runner.execute(*self, "yadm", || unix::run_yadm(ctx))? + } + Yarn => runner.execute(*self, "yarn", || node::run_yarn_upgrade(ctx))?, + Yazi => runner.execute(*self, "Yazi packages", || generic::run_yazi(ctx))?, + Zigup => runner.execute(*self, "zigup", || generic::run_zigup(ctx))?, + Zvm => runner.execute(*self, "ZVM", || generic::run_zvm(ctx))?, + } + + Ok(()) + } +} + +#[allow(clippy::too_many_lines)] +pub(crate) fn default_steps() -> Vec { + // For now, SelfRenamer and SelfUpdate isn't included as they're ran before the other non-steps (pre-commands, sudo, etc) + + use Step::*; + // Could probably have a smaller starting capacity, but this at least ensures only 2 allocations: + // initial and shrink + let mut steps = Vec::with_capacity(Step::COUNT); + + #[cfg(windows)] + steps.extend_from_slice(&[Wsl, WslUpdate, Chocolatey, Scoop, Winget]); + + #[cfg(target_os = "macos")] + steps.extend_from_slice(&[BrewFormula, BrewCask, Macports, Xcodes, Sparkle, Mas]); + + #[cfg(target_os = "dragonfly")] + steps.extend_from_slice(&[Pkg, Audit]); + + #[cfg(any(target_os = "freebsd", target_os = "openbsd"))] + steps.push(Pkg); + + #[cfg(not(any(target_os = "dragonfly", target_os = "android")))] + steps.push(System); + + #[cfg(windows)] + steps.push(MicrosoftStore); + + #[cfg(target_os = "linux")] + steps.extend_from_slice(&[ + ConfigUpdate, + AM, + AppMan, + DebGet, + Toolbx, + Snap, + Pacstall, + Pacdef, + Protonup, + Distrobox, + DkpPacman, + Firmware, + Restarts, + Flatpak, + BrewFormula, + Lure, + Waydroid, + AutoCpufreq, + CinnamonSpices, + ]); + + #[cfg(target_os = "freebsd")] + steps.push(Audit); + + #[cfg(unix)] + steps.extend_from_slice(&[ + Yadm, + Nix, + Guix, + HomeManager, + Asdf, + Mise, + Pkgin, + BunPackages, + Shell, + Tmux, + Tldr, + Pearl, + #[cfg(not(any(target_os = "macos", target_os = "android")))] + GnomeShellExtensions, + Pyenv, + Sdkman, + Rcm, + Maza, + ]); + + #[cfg(not(any( + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + target_os = "dragonfly" + )))] + steps.push(Atom); + + // The following update function should be executed on all OSes. + steps.extend_from_slice(&[ + Fossil, + Elan, + Rye, + Rustup, + Juliaup, + Dotnet, + Choosenim, + Cargo, + Flutter, + Go, + Emacs, + Opam, + Vcpkg, + Pipx, + Pipxu, + Vscode, + Vscodium, + Conda, + Mamba, + Pixi, + Miktex, + Pip3, + PipReview, + PipReviewLocal, + Pipupgrade, + Ghcup, + Stack, + Tlmgr, + Myrepos, + Chezmoi, + Jetpack, + Vim, + Kakoune, + Helix, + Node, + Yarn, + Pnpm, + VoltaPackages, + Containers, + Deno, + Composer, + Krew, + Helm, + Gem, + RubyGems, + Julia, + Haxelib, + Sheldon, + Stew, + Rtcl, + Bin, + Gcloud, + Micro, + Raco, + Spicetify, + GithubCliExtensions, + Bob, + Certbot, + GitRepos, + ClamAvDb, + PlatformioCore, + Lensfun, + Poetry, + Uv, + Zvm, + Aqua, + Bun, + Zigup, + JetbrainsToolbox, + AndroidStudio, + JetbrainsAqua, + JetbrainsClion, + JetbrainsDatagrip, + JetbrainsDataspell, + // JetBrains dotCover has no CLI + // JetBrains dotMemory has no CLI + // JetBrains dotPeek has no CLI + // JetBrains dotTrace has no CLI + // JetBrains Fleet has a different CLI without a `fleet update` command. + JetbrainsGateway, + JetbrainsGoland, + JetbrainsIdea, + JetbrainsMps, + JetbrainsPhpstorm, + JetbrainsPycharm, + // JetBrains ReSharper has no CLI (it's a VSCode extension) + // JetBrains ReSharper C++ has no CLI (it's a VSCode extension) + JetbrainsRider, + JetbrainsRubymine, + JetbrainsRustrover, + // JetBrains Space Desktop does not have a CLI + JetbrainsWebstorm, + Yazi, + Powershell, + CustomCommands, + Vagrant, + ]); + + steps.shrink_to_fit(); + + steps +} diff --git a/src/steps/emacs.rs b/src/steps/emacs.rs index 2567dc0e..57c61095 100644 --- a/src/steps/emacs.rs +++ b/src/steps/emacs.rs @@ -8,9 +8,9 @@ use rust_i18n::t; use crate::command::CommandExt; use crate::execution_context::ExecutionContext; +use crate::step::Step; use crate::terminal::print_separator; use crate::utils::{require, require_option, PathExt}; -use crate::Step; const EMACS_UPGRADE: &str = include_str!("emacs.el"); #[cfg(windows)] diff --git a/src/steps/generic.rs b/src/steps/generic.rs index e4dccecb..a4fe9140 100644 --- a/src/steps/generic.rs +++ b/src/steps/generic.rs @@ -18,6 +18,8 @@ use tracing::{debug, error, warn}; use crate::command::{CommandExt, Utf8Output}; use crate::execution_context::ExecutionContext; use crate::executor::ExecutorOutput; +use crate::output_changed_message; +use crate::step::Step; use crate::terminal::{print_separator, shell}; use crate::utils::{ check_is_python_2_or_shim, get_require_sudo_string, require, require_one, require_option, which, PathExt, @@ -27,7 +29,6 @@ use crate::{ error::{SkipStep, StepFailed, TopgradeError}, terminal::print_warning, }; -use crate::{output_changed_message, Step}; #[cfg(target_os = "linux")] pub fn is_wsl() -> Result { diff --git a/src/steps/git.rs b/src/steps/git.rs index 0e5ba609..0e6dc970 100644 --- a/src/steps/git.rs +++ b/src/steps/git.rs @@ -13,8 +13,8 @@ use tokio::runtime; use tracing::{debug, error}; use crate::command::CommandExt; -use crate::config::Step; use crate::execution_context::ExecutionContext; +use crate::step::Step; use crate::steps::emacs::Emacs; use crate::terminal::print_separator; use crate::utils::{require, PathExt}; diff --git a/src/steps/os/android.rs b/src/steps/os/android.rs index 54581923..dcb82f98 100644 --- a/src/steps/os/android.rs +++ b/src/steps/os/android.rs @@ -1,10 +1,10 @@ use crate::command::CommandExt; use crate::execution_context::ExecutionContext; +use crate::step::Step; use crate::terminal::print_separator; use crate::utils::require; use crate::utils::which; -use crate::Step; -use color_eyre::eyre::Result; +use color_eyre::Result; pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> { //let pkg = require("pkg")?; diff --git a/src/steps/os/archlinux.rs b/src/steps/os/archlinux.rs index 2a62de82..1d2775e1 100644 --- a/src/steps/os/archlinux.rs +++ b/src/steps/os/archlinux.rs @@ -10,9 +10,10 @@ use walkdir::WalkDir; use crate::command::CommandExt; use crate::error::TopgradeError; use crate::execution_context::ExecutionContext; +use crate::step::Step; use crate::utils::require_option; use crate::utils::which; -use crate::{config, output_changed_message, Step}; +use crate::{config, output_changed_message}; fn get_execution_path() -> OsString { let mut path = OsString::from("/usr/bin:"); diff --git a/src/steps/os/dragonfly.rs b/src/steps/os/dragonfly.rs index 895ab254..61ecd4df 100644 --- a/src/steps/os/dragonfly.rs +++ b/src/steps/os/dragonfly.rs @@ -1,8 +1,8 @@ use crate::command::CommandExt; use crate::execution_context::ExecutionContext; +use crate::step::Step; use crate::terminal::print_separator; use crate::utils::{get_require_sudo_string, require_option}; -use crate::Step; use color_eyre::eyre::Result; use std::process::Command; diff --git a/src/steps/os/freebsd.rs b/src/steps/os/freebsd.rs index 57982711..9fe64c8f 100644 --- a/src/steps/os/freebsd.rs +++ b/src/steps/os/freebsd.rs @@ -1,9 +1,9 @@ use crate::command::CommandExt; use crate::execution_context::ExecutionContext; +use crate::step::Step; use crate::terminal::print_separator; use crate::utils::{get_require_sudo_string, require_option}; -use crate::Step; -use color_eyre::eyre::Result; +use color_eyre::Result; use rust_i18n::t; use std::process::Command; diff --git a/src/steps/os/linux.rs b/src/steps/os/linux.rs index 6babeb34..6753ddcf 100644 --- a/src/steps/os/linux.rs +++ b/src/steps/os/linux.rs @@ -9,11 +9,12 @@ use tracing::{debug, warn}; use crate::command::CommandExt; use crate::error::{SkipStep, TopgradeError}; use crate::execution_context::ExecutionContext; +use crate::step::Step; use crate::steps::generic::is_wsl; use crate::steps::os::archlinux; use crate::terminal::{print_separator, prompt_yesno}; use crate::utils::{get_require_sudo_string, require, require_option, which, PathExt}; -use crate::{Step, HOME_DIR}; +use crate::HOME_DIR; static OS_RELEASE_PATH: &str = "/etc/os-release"; diff --git a/src/steps/os/macos.rs b/src/steps/os/macos.rs index 105d15f1..e89554c4 100644 --- a/src/steps/os/macos.rs +++ b/src/steps/os/macos.rs @@ -1,8 +1,9 @@ use crate::command::CommandExt; use crate::execution_context::ExecutionContext; +use crate::step::Step; use crate::terminal::{print_separator, prompt_yesno}; +use crate::utils::require; use crate::utils::{get_require_sudo_string, require_option}; -use crate::{utils::require, Step}; use color_eyre::eyre::Result; use rust_i18n::t; use std::collections::HashSet; diff --git a/src/steps/os/unix.rs b/src/steps/os/unix.rs index 60dd0d96..f04ee1c0 100644 --- a/src/steps/os/unix.rs +++ b/src/steps/os/unix.rs @@ -1,5 +1,5 @@ use crate::command::CommandExt; -use crate::{output_changed_message, Step, HOME_DIR}; +use crate::{output_changed_message, HOME_DIR}; use color_eyre::eyre::eyre; use color_eyre::eyre::Context; use color_eyre::eyre::Result; @@ -28,6 +28,7 @@ use crate::execution_context::ExecutionContext; use crate::executor::Executor; #[cfg(any(target_os = "linux", target_os = "macos"))] use crate::executor::RunType; +use crate::step::Step; use crate::terminal::print_separator; use crate::utils::{get_require_sudo_string, require, require_option, PathExt}; diff --git a/src/steps/os/windows.rs b/src/steps/os/windows.rs index c84beac9..048234b4 100644 --- a/src/steps/os/windows.rs +++ b/src/steps/os/windows.rs @@ -7,10 +7,11 @@ use tracing::debug; use crate::command::CommandExt; use crate::execution_context::ExecutionContext; +use crate::powershell; +use crate::step::Step; use crate::terminal::{print_separator, print_warning}; use crate::utils::{require, which}; use crate::{error::SkipStep, steps::git::RepoStep}; -use crate::{powershell, Step}; use rust_i18n::t; pub fn run_chocolatey(ctx: &ExecutionContext) -> Result<()> { diff --git a/src/steps/powershell.rs b/src/steps/powershell.rs index cf5d930f..7cb64c0a 100644 --- a/src/steps/powershell.rs +++ b/src/steps/powershell.rs @@ -6,9 +6,9 @@ use rust_i18n::t; use crate::command::CommandExt; use crate::execution_context::ExecutionContext; +use crate::step::Step; use crate::terminal::{is_dumb, print_separator}; use crate::utils::{require_option, which}; -use crate::Step; pub struct Powershell { path: Option, diff --git a/src/steps/remote/vagrant.rs b/src/steps/remote/vagrant.rs index fc8ff470..26354815 100644 --- a/src/steps/remote/vagrant.rs +++ b/src/steps/remote/vagrant.rs @@ -10,8 +10,9 @@ use tracing::{debug, error}; use crate::command::CommandExt; use crate::execution_context::ExecutionContext; +use crate::step::Step; use crate::terminal::print_separator; -use crate::{error::SkipStep, utils, Step}; +use crate::{error::SkipStep, utils}; #[derive(Debug, Copy, Clone, EnumString)] #[strum(serialize_all = "lowercase")] diff --git a/src/steps/toolbx.rs b/src/steps/toolbx.rs index d6e5b022..7d716513 100644 --- a/src/steps/toolbx.rs +++ b/src/steps/toolbx.rs @@ -1,7 +1,7 @@ use color_eyre::eyre::Result; use crate::command::CommandExt; -use crate::config::Step; +use crate::step::Step; use crate::terminal::print_separator; use crate::{execution_context::ExecutionContext, utils::require}; use std::path::Path;