diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 00000000..f520b42e --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,24 @@ +name: Cargo Build & Test + +on: + push: + pull_request: + +env: + CARGO_TERM_COLOR: always + +jobs: + build_and_test: + name: Rust project - latest + runs-on: ubuntu-latest + strategy: + matrix: + toolchain: + - stable + - beta + - nightly + steps: + - uses: actions/checkout@v3 + - run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} + - run: cargo build --verbose + - run: cargo test --verbose diff --git a/.github/workflows/rust-ubuntu.yml b/.github/workflows/rust-ubuntu.yml new file mode 100644 index 00000000..18bcd0ae --- /dev/null +++ b/.github/workflows/rust-ubuntu.yml @@ -0,0 +1,24 @@ +name: Rust + +on: + push: + branches: [ "master", "dev" ] + pull_request: + branches: [ "master", "dev" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Build + run: cargo build --verbose + - name: Fmt + run: cargo fmt --check --all + - name: Run tests + run: cargo test --verbose diff --git a/Cargo.toml b/Cargo.toml index 1b9e0a7d..903cd551 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,54 +1,54 @@ [package] name = "topgrade-rs" -description = "Upgrade all the things" +description = "Upgrade all the things, successor of topgrade" categories = ["os"] keywords = ["upgrade", "update"] license-file = "LICENSE" repository = "https://github.com/topgrade-rs/topgrade" -version = "9.0.1" -authors = ["Thomas Schönauer"] +version = "9.1.0" +authors = ["Roey Darwish Dror ", "Thomas Schönauer "] exclude = ["doc/screenshot.gif"] edition = "2018" readme = "README.md" [dependencies] -directories = "4.0.1" -serde = { version = "1.0.125", features = ["derive"] } -toml = "0.5.8" -which_crate = { version = "4.1.0", package = "which" } -shellexpand = "2.1.0" +directories = "4.0" +serde = { version = "1.0", features = ["derive"] } +toml = "0.5" +which_crate = { version = "4.1", package = "which" } +shellexpand = "2.1" clap = { version = "3.1", features = ["cargo", "derive"] } -log = "0.4.14" -walkdir = "2.3.2" -console = "0.15.0" -lazy_static = "1.4.0" -chrono = "0.4.19" -pretty_env_logger = "0.4.0" -glob = "0.3.0" -strum = { version = "0.24.0", features = ["derive"] } -thiserror = "1.0.24" -anyhow = "1.0.40" -tempfile = "3.2.0" -cfg-if = "1.0.0" -tokio = { version = "1.5.0", features = ["process", "rt-multi-thread"] } -futures = "0.3.14" -regex = "1.5.3" +log = "0.4" +walkdir = "2.3" +console = "0.15" +lazy_static = "1.4" +chrono = "0.4" +pretty_env_logger = "0.4" +glob = "0.3" +strum = { version = "0.24", features = ["derive"] } +thiserror = "1.0" +anyhow = "1.0" +tempfile = "3.2" +cfg-if = "1.0" +tokio = { version = "1.5", features = ["process", "rt-multi-thread"] } +futures = "0.3" +regex = "1.5" sys-info = "0.9" semver = "1.0" [target.'cfg(target_os = "macos")'.dependencies] -notify-rust = "4.5.0" +notify-rust = "4.5" [target.'cfg(unix)'.dependencies] -nix = "0.24.1" -rust-ini = "0.18.0" -self_update_crate = { version = "0.30.0", default-features = false, optional = true, package = "self_update", features = ["archive-tar", "compression-flate2", "rustls"] } +nix = "0.24" +rust-ini = "0.18" +self_update_crate = { version = "0.30", default-features = false, optional = true, package = "self_update", features = ["archive-tar", "compression-flate2", "rustls"] } [target.'cfg(windows)'.dependencies] -self_update_crate = { version = "0.30.0", default-features = false, optional = true, package = "self_update", features = ["archive-zip", "compression-zip-deflate", "rustls"] } -winapi = "0.3.9" -parselnk = "0.1.0" +self_update_crate = { version = "0.30", default-features = false, optional = true, package = "self_update", features = ["archive-zip", "compression-zip-deflate", "rustls"] } +winapi = "0.3" +parselnk = "0.1" [profile.release] lto = true diff --git a/README.md b/README.md index f339f966..24cb375b 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,17 @@ ![Topgrade](doc/topgrade.png) - -[![Travis](https://api.travis-ci.org/r-darwish/topgrade.svg?branch=master)](https://travis-ci.org/r-darwish/topgrade) -[![AppVeyor](https://ci.appveyor.com/api/projects/status/github/r-darwish/topgrade?svg=true)](https://ci.appveyor.com/project/r-darwish/topgrade) + +---> ![Demo](doc/screenshot.gif) +## Fork +This is a fork of [topgrade by r-darwish](https://github.com/r-darwish/topgrade) to keep it maintained. + + Keeping your system up to date usually involves invoking multiple package managers. This results in big, non-portable shell one-liners saved in your shell. To remedy this, _topgrade_ detects which tools you use and runs the appropriate commands to update them. @@ -23,6 +26,9 @@ The compiled binaries contain a self-upgrading feature. Topgrade requires Rust 1.51 or above. +## Documentation[WIP] +You can visit the documentation at [topgrade-rs.github.io](https://topgrade-rs.github.io/) . + ## Usage Just run `topgrade`. See [the wiki](https://github.com/r-darwish/topgrade/wiki/Step-list) for the list of things Topgrade supports. diff --git a/config.example.toml b/config.example.toml index 231a6e60..df506e86 100644 --- a/config.example.toml +++ b/config.example.toml @@ -37,6 +37,9 @@ # Cleanup temporary or old files #cleanup = true +# Skip sending a notification at the end of a run +#skip_notify = true + [git] #max_concurrency = 5 # Additional git repositories to pull @@ -64,6 +67,7 @@ [brew] #greedy_cask = true +#autoremove = true [linux] # Arch Package Manager to use. Allowed values: autodetect, trizen, paru, yay, pikaur, pacman, pamac. @@ -87,7 +91,7 @@ # Causes Topgrade to rename itself during the run to allow package managers # to upgrade it. Use this only if you installed Topgrade by using a package -# manager such as Scoop to Cargo +# manager such as Scoop or Cargo #self_rename = true [npm] diff --git a/src/config.rs b/src/config.rs index 2acade8c..b5b50822 100644 --- a/src/config.rs +++ b/src/config.rs @@ -62,7 +62,7 @@ macro_rules! get_deprecated { type Commands = BTreeMap; -#[derive(ArgEnum, EnumString, EnumVariantNames, Debug, Clone, PartialEq, Deserialize, EnumIter, Copy)] +#[derive(ArgEnum, EnumString, EnumVariantNames, Debug, Clone, PartialEq, Eq, Deserialize, EnumIter, Copy)] #[clap(rename_all = "snake_case")] #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] @@ -71,6 +71,7 @@ pub enum Step { Atom, BrewCask, BrewFormula, + Bun, Bin, Cargo, Chezmoi, @@ -94,10 +95,12 @@ pub enum Step { GithubCliExtensions, GitRepos, Go, + Guix, Haxelib, GnomeShellExtensions, HomeManager, Jetpack, + Julia, Kakoune, Krew, Macports, @@ -107,6 +110,7 @@ pub enum Step { Nix, Node, Opam, + Pacdef, Pacstall, Pearl, Pipx, @@ -114,6 +118,7 @@ pub enum Step { Pkg, Pkgin, Powershell, + Protonup, Raco, Remotes, Restarts, @@ -166,6 +171,13 @@ pub struct Windows { enable_winget: Option, } +#[derive(Deserialize, Default, Debug)] +#[serde(deny_unknown_fields)] +#[allow(clippy::upper_case_acronyms)] +pub struct Yarn { + use_sudo: Option, +} + #[derive(Deserialize, Default, Debug)] #[serde(deny_unknown_fields)] #[allow(clippy::upper_case_acronyms)] @@ -191,6 +203,7 @@ pub struct Flatpak { #[serde(deny_unknown_fields)] pub struct Brew { greedy_cask: Option, + autoremove: Option, } #[derive(Debug, Deserialize, Clone, Copy)] @@ -260,6 +273,7 @@ pub struct ConfigFile { cleanup: Option, notify_each_step: Option, accept_all_windows_updates: Option, + skip_notify: Option, bashit_branch: Option, only: Option>, composer: Option, @@ -268,6 +282,7 @@ pub struct ConfigFile { git: Option, windows: Option, npm: Option, + yarn: Option, vim: Option, firmware: Option, vagrant: Option, @@ -415,6 +430,10 @@ pub struct CommandLineArgs { #[clap(short = 'k', long = "keep")] keep_at_end: bool, + /// Skip sending a notification at the end of a run + #[clap(long = "skip-notify")] + skip_notify: bool, + /// Say yes to package manager's prompt #[clap(short = 'y', long = "yes", arg_enum, multiple_values = true, min_values = 0)] yes: Option>, @@ -600,6 +619,15 @@ impl Config { self.opt.keep_at_end || env::var("TOPGRADE_KEEP_END").is_ok() } + /// Skip sending a notification at the end of a run + pub fn skip_notify(&self) -> bool { + if let Some(yes) = self.config_file.skip_notify { + return yes; + } + + self.opt.skip_notify + } + /// Whether to set the terminal title pub fn set_title(&self) -> bool { self.config_file.set_title.unwrap_or(true) @@ -656,6 +684,15 @@ impl Config { .unwrap_or(false) } + /// Whether Brew should autoremove + pub fn brew_autoremove(&self) -> bool { + self.config_file + .brew + .as_ref() + .and_then(|c| c.autoremove) + .unwrap_or(false) + } + /// Whether Composer should update itself pub fn composer_self_update(&self) -> bool { self.config_file @@ -839,6 +876,14 @@ impl Config { .and_then(|npm| npm.use_sudo) .unwrap_or(false) } + #[cfg(target_os = "linux")] + pub fn yarn_use_sudo(&self) -> bool { + self.config_file + .yarn + .as_ref() + .and_then(|yarn| yarn.use_sudo) + .unwrap_or(false) + } #[cfg(target_os = "linux")] pub fn firmware_upgrade(&self) -> bool { diff --git a/src/error.rs b/src/error.rs index 34605806..5ec6ce75 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,7 +2,7 @@ use std::process::ExitStatus; use thiserror::Error; -#[derive(Error, Debug, PartialEq)] +#[derive(Error, Debug, PartialEq, Eq)] pub enum TopgradeError { #[error("{0}")] ProcessFailed(ExitStatus), diff --git a/src/main.rs b/src/main.rs index 88d0f605..cdcfe9e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -191,9 +191,12 @@ fn run() -> Result<()> { { runner.execute(Step::Yadm, "yadm", || unix::run_yadm(&ctx))?; runner.execute(Step::Nix, "nix", || unix::run_nix(&ctx))?; + runner.execute(Step::Guix, "guix", || unix::run_guix(&ctx))?; + runner.execute(Step::HomeManager, "home-manager", || unix::run_home_manager(run_type))?; runner.execute(Step::Asdf, "asdf", || unix::run_asdf(run_type))?; runner.execute(Step::Pkgin, "pkgin", || unix::run_pkgin(&ctx))?; + runner.execute(Step::Bun, "bun", || unix::run_bun(&ctx))?; } #[cfg(target_os = "dragonfly")] @@ -315,7 +318,7 @@ fn run() -> Result<()> { runner.execute(Step::Flutter, "Flutter", || generic::run_flutter_upgrade(run_type))?; runner.execute(Step::Go, "Go", || generic::run_go(run_type))?; runner.execute(Step::Emacs, "Emacs", || emacs.upgrade(&ctx))?; - runner.execute(Step::Opam, "opam", || generic::run_opam_update(run_type))?; + runner.execute(Step::Opam, "opam", || generic::run_opam_update(&ctx))?; runner.execute(Step::Vcpkg, "vcpkg", || generic::run_vcpkg_update(run_type))?; runner.execute(Step::Pipx, "pipx", || generic::run_pipx_update(run_type))?; runner.execute(Step::Conda, "conda", || generic::run_conda_update(&ctx))?; @@ -335,11 +338,13 @@ fn run() -> Result<()> { runner.execute(Step::Vim, "voom", || vim::run_voom(&base_dirs, run_type))?; runner.execute(Step::Kakoune, "Kakoune", || kakoune::upgrade_kak_plug(&ctx))?; runner.execute(Step::Node, "npm", || node::run_npm_upgrade(&ctx))?; + runner.execute(Step::Node, "yarn", || node::run_yarn_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(run_type))?; runner.execute(Step::Gem, "gem", || generic::run_gem(&base_dirs, run_type))?; + 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::Rtcl, "rtcl", || generic::run_rtcl(&ctx))?; @@ -361,6 +366,8 @@ fn run() -> Result<()> { runner.execute(Step::Flatpak, "Flatpak", || linux::flatpak_update(&ctx))?; runner.execute(Step::Snap, "snap", || linux::run_snap(sudo.as_ref(), run_type))?; 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))?; } if let Some(commands) = config.commands() { @@ -460,13 +467,17 @@ fn run() -> Result<()> { } let failed = post_command_failed || runner.report().data().iter().any(|(_, result)| result.failed()); - terminal::notify_desktop( - format!( - "Topgrade finished {}", - if failed { "with errors" } else { "successfully" } - ), - None, - ); + + if !config.skip_notify() { + terminal::notify_desktop( + format!( + "Topgrade finished {}", + if failed { "with errors" } else { "successfully" } + ), + None, + ); + } + if failed { Err(StepFailed.into()) } else { diff --git a/src/steps/bun.rs b/src/steps/bun.rs new file mode 100644 index 00000000..e69de29b diff --git a/src/steps/emacs.rs b/src/steps/emacs.rs index 862ff16d..75ab817b 100644 --- a/src/steps/emacs.rs +++ b/src/steps/emacs.rs @@ -67,25 +67,24 @@ impl Emacs { print_separator("Doom Emacs"); let mut command = ctx.run_type().execute(doom); - command.args(&["-y", "upgrade"]); - if ctx.config().yes(Step::Emacs) { command.arg("--force"); } + command.args(&["upgrade"]); + command.check_run() } pub fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> { let emacs = require("emacs")?; + if let Some(doom) = &self.doom { + Emacs::update_doom(doom, ctx)?; + } let init_file = require_option(self.directory.as_ref(), String::from("Emacs directory does not exist"))? .join("init.el") .require()?; - if let Some(doom) = &self.doom { - return Emacs::update_doom(doom, ctx); - } - print_separator("Emacs"); let mut command = ctx.run_type().execute(&emacs); diff --git a/src/steps/generic.rs b/src/steps/generic.rs index 698f10d8..9f7dae43 100644 --- a/src/steps/generic.rs +++ b/src/steps/generic.rs @@ -220,13 +220,19 @@ pub fn run_rtcl(ctx: &ExecutionContext) -> Result<()> { ctx.run_type().execute(&rupdate).check_run() } -pub fn run_opam_update(run_type: RunType) -> Result<()> { +pub fn run_opam_update(ctx: &ExecutionContext) -> Result<()> { let opam = utils::require("opam")?; print_separator("OCaml Package Manager"); - run_type.execute(&opam).arg("update").check_run()?; - run_type.execute(&opam).arg("upgrade").check_run() + ctx.run_type().execute(&opam).arg("update").check_run()?; + ctx.run_type().execute(&opam).arg("upgrade").check_run()?; + + if ctx.config().cleanup() { + ctx.run_type().execute(&opam).arg("clean").check_run()?; + } + + Ok(()) } pub fn run_vcpkg_update(run_type: RunType) -> Result<()> { @@ -496,3 +502,14 @@ pub fn run_ghcli_extensions_upgrade(ctx: &ExecutionContext) -> Result<()> { .args(&["extension", "upgrade", "--all"]) .check_run() } + +pub fn update_julia_packages(ctx: &ExecutionContext) -> Result<()> { + let julia = utils::require("julia")?; + + print_separator("Julia Packages"); + + ctx.run_type() + .execute(&julia) + .args(&["-e", "using Pkg; Pkg.update()"]) + .check_run() +} diff --git a/src/steps/node.rs b/src/steps/node.rs index 2541e7cd..6d22d07e 100644 --- a/src/steps/node.rs +++ b/src/steps/node.rs @@ -20,15 +20,11 @@ use crate::{error::SkipStep, execution_context::ExecutionContext}; #[allow(clippy::upper_case_acronyms)] struct NPM { command: PathBuf, - pnpm: Option, } impl NPM { fn new(command: PathBuf) -> Self { - Self { - command, - pnpm: require("pnpm").ok(), - } + Self { command } } #[cfg(target_os = "linux")] @@ -56,17 +52,13 @@ impl NPM { fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> { print_separator("Node Package Manager"); let version = self.version()?; - let args = if version < Version::new(8, 11, 0) || self.pnpm.is_some() { + let args = if version < Version::new(8, 11, 0) { ["update", "-g"] } else { ["update", "--location=global"] }; if use_sudo { - run_type - .execute("sudo") - .arg(self.pnpm.as_ref().unwrap_or(&self.command)) - .args(args) - .check_run()?; + run_type.execute("sudo").args(args).check_run()?; } else { run_type.execute(&self.command).args(args).check_run()?; } @@ -88,6 +80,59 @@ impl NPM { } } +struct Yarn { + command: PathBuf, + yarn: Option, +} + +impl Yarn { + fn new(command: PathBuf) -> Self { + Self { + command, + yarn: require("yarn").ok(), + } + } + + #[cfg(target_os = "linux")] + fn root(&self) -> Result { + let args = ["global", "dir"]; + Command::new(&self.command) + .args(args) + .check_output() + .map(|s| PathBuf::from(s.trim())) + } + + fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> { + print_separator("Yarn Package Manager"); + let args = ["global", "upgrade"]; + + if use_sudo { + run_type + .execute("sudo") + .arg(self.yarn.as_ref().unwrap_or(&self.command)) + .args(args) + .check_run()?; + } else { + run_type.execute(&self.command).args(args).check_run()?; + } + + Ok(()) + } + + #[cfg(target_os = "linux")] + pub fn should_use_sudo(&self) -> Result { + let yarn_root = self.root()?; + if !yarn_root.exists() { + return Err(SkipStep(format!("NPM root at {} doesn't exist", yarn_root.display(),)).into()); + } + + let metadata = std::fs::metadata(&yarn_root)?; + let uid = Uid::effective(); + + Ok(metadata.uid() != uid.as_raw() && metadata.uid() == 0) + } +} + #[cfg(target_os = "linux")] fn should_use_sudo(npm: &NPM, ctx: &ExecutionContext) -> Result { if npm.should_use_sudo()? { @@ -102,8 +147,22 @@ fn should_use_sudo(npm: &NPM, ctx: &ExecutionContext) -> Result { } } +#[cfg(target_os = "linux")] +fn should_use_sudo_yarn(yarn: &Yarn, ctx: &ExecutionContext) -> Result { + if yarn.should_use_sudo()? { + if ctx.config().yarn_use_sudo() { + Ok(true) + } else { + Err(SkipStep("NPM root is owned by another user which is not the current user. Set use_sudo = true under the NPM section in your configuration to run NPM as sudo".to_string()) + .into()) + } + } else { + Ok(false) + } +} + pub fn run_npm_upgrade(ctx: &ExecutionContext) -> Result<()> { - let npm = require("npm").map(NPM::new)?; + let npm = require("pnpm").or_else(|_| require("npm")).map(NPM::new)?; #[cfg(target_os = "linux")] { @@ -116,6 +175,20 @@ pub fn run_npm_upgrade(ctx: &ExecutionContext) -> Result<()> { } } +pub fn run_yarn_upgrade(ctx: &ExecutionContext) -> Result<()> { + let yarn = require("yarn").map(Yarn::new)?; + + #[cfg(target_os = "linux")] + { + yarn.upgrade(ctx.run_type(), should_use_sudo_yarn(&yarn, ctx)?) + } + + #[cfg(not(target_os = "linux"))] + { + yarn.upgrade(ctx.run_type(), false) + } +} + pub fn deno_upgrade(ctx: &ExecutionContext) -> Result<()> { let deno = require("deno")?; let deno_dir = ctx.base_dirs().home_dir().join(".deno"); diff --git a/src/steps/os/linux.rs b/src/steps/os/linux.rs index bca05509..96a35452 100644 --- a/src/steps/os/linux.rs +++ b/src/steps/os/linux.rs @@ -26,6 +26,7 @@ pub enum Distribution { Fedora, Debian, Gentoo, + OpenMandriva, Suse, Void, Solus, @@ -44,7 +45,7 @@ impl Distribution { Some("alpine") => Distribution::Alpine, Some("centos") | Some("rhel") | Some("ol") => Distribution::CentOS, Some("clear-linux-os") => Distribution::ClearLinux, - Some("fedora") => Distribution::Fedora, + Some("fedora") | Some("nobara") => Distribution::Fedora, Some("void") => Distribution::Void, Some("debian") | Some("pureos") => Distribution::Debian, Some("arch") | Some("anarchy") | Some("manjaro-arm") | Some("garuda") | Some("artix") => Distribution::Arch, @@ -53,6 +54,7 @@ impl Distribution { Some("exherbo") => Distribution::Exherbo, Some("nixos") => Distribution::NixOS, Some("neon") => Distribution::KDENeon, + Some("openmandriva") => Distribution::OpenMandriva, _ => { if let Some(id_like) = id_like { if id_like.contains(&"debian") || id_like.contains(&"ubuntu") { @@ -105,6 +107,7 @@ impl Distribution { Distribution::NixOS => upgrade_nixos(ctx), Distribution::KDENeon => upgrade_neon(ctx), Distribution::Bedrock => update_bedrock(ctx), + Distribution::OpenMandriva => upgrade_openmandriva(ctx), } } @@ -218,6 +221,28 @@ fn upgrade_suse(ctx: &ExecutionContext) -> Result<()> { Ok(()) } +fn upgrade_openmandriva(ctx: &ExecutionContext) -> Result<()> { + if let Some(sudo) = &ctx.sudo() { + let mut command = ctx.run_type().execute(&sudo); + + command.arg(which("dnf").unwrap().to_path_buf()).arg("upgrade"); + + if let Some(args) = ctx.config().dnf_arguments() { + command.args(args.split_whitespace()); + } + + if ctx.config().yes(Step::System) { + command.arg("-y"); + } + + command.check_run()?; + } else { + print_warning("No sudo detected. Skipping system upgrade"); + } + + Ok(()) +} + fn upgrade_void(ctx: &ExecutionContext) -> Result<()> { if let Some(sudo) = ctx.sudo() { let mut command = ctx.run_type().execute(&sudo); @@ -349,6 +374,17 @@ fn upgrade_solus(ctx: &ExecutionContext) -> Result<()> { Ok(()) } +pub fn run_pacdef(ctx: &ExecutionContext) -> Result<()> { + let pacdef = require("pacdef")?; + + print_separator("pacdef"); + + ctx.run_type().execute(&pacdef).arg("sync").check_run()?; + + println!(); + ctx.run_type().execute(&pacdef).arg("review").check_run() +} + pub fn run_pacstall(ctx: &ExecutionContext) -> Result<()> { let pacstall = require("pacstall")?; @@ -492,44 +528,50 @@ pub fn flatpak_update(ctx: &ExecutionContext) -> Result<()> { let flatpak = require("flatpak")?; let sudo = require_option(ctx.sudo().as_ref(), String::from("sudo is not installed"))?; let cleanup = ctx.config().cleanup(); + let yes = ctx.config().yes(Step::Flatpak); let run_type = ctx.run_type(); print_separator("Flatpak User Packages"); - run_type - .execute(&flatpak) - .args(&["update", "--user", "-y"]) - .check_run()?; + let mut update_args = vec!["update", "--user"]; + if yes { + update_args.push("-y"); + } + run_type.execute(&flatpak).args(&update_args).check_run()?; + if cleanup { - run_type - .execute(&flatpak) - .args(&["uninstall", "--user", "--unused"]) - .check_run()?; + let mut cleanup_args = vec!["uninstall", "--user", "--unused"]; + if yes { + cleanup_args.push("-y"); + } + run_type.execute(&flatpak).args(&cleanup_args).check_run()?; } print_separator("Flatpak System Packages"); if ctx.config().flatpak_use_sudo() || std::env::var("SSH_CLIENT").is_ok() { - run_type - .execute(&sudo) - .arg(&flatpak) - .args(&["update", "--system", "-y"]) - .check_run()?; + let mut update_args = vec!["update", "--system"]; + if yes { + update_args.push("-y"); + } + run_type.execute(&sudo).arg(&flatpak).args(&update_args).check_run()?; if cleanup { - run_type - .execute(sudo) - .arg(flatpak) - .args(&["uninstall", "--system", "--unused"]) - .check_run()?; + let mut cleanup_args = vec!["uninstall", "--system", "--unused"]; + if yes { + cleanup_args.push("-y"); + } + run_type.execute(sudo).arg(flatpak).args(&cleanup_args).check_run()?; } } else { - run_type - .execute(&flatpak) - .args(&["update", "--system", "-y"]) - .check_run()?; + let mut update_args = vec!["update", "--system"]; + if yes { + update_args.push("-y"); + } + run_type.execute(&flatpak).args(&update_args).check_run()?; if cleanup { - run_type - .execute(flatpak) - .args(&["uninstall", "--system", "--unused"]) - .check_run()?; + let mut cleanup_args = vec!["uninstall", "--system", "--unused"]; + if yes { + cleanup_args.push("-y"); + } + run_type.execute(flatpak).args(&cleanup_args).check_run()?; } } @@ -558,6 +600,15 @@ pub fn run_pihole_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<() run_type.execute(sudo).arg(pihole).arg("-up").check_run() } +pub fn run_protonup_update(ctx: &ExecutionContext) -> Result<()> { + let protonup = require("protonup")?; + + print_separator("protonup"); + + ctx.run_type().execute(protonup).check_run()?; + Ok(()) +} + pub fn run_config_update(ctx: &ExecutionContext) -> Result<()> { let sudo = require_option(ctx.sudo().as_ref(), String::from("sudo is not installed"))?; if ctx.config().yes(Step::ConfigUpdate) { diff --git a/src/steps/os/unix.rs b/src/steps/os/unix.rs index dd90b2d0..cdbc9ad3 100644 --- a/src/steps/os/unix.rs +++ b/src/steps/os/unix.rs @@ -210,6 +210,10 @@ pub fn run_brew_formula(ctx: &ExecutionContext, variant: BrewVariant) -> Result< variant.execute(run_type).arg("cleanup").check_run()?; } + if ctx.config().brew_autoremove() { + variant.execute(run_type).arg("autoremove").check_run()?; + } + Ok(()) } @@ -251,6 +255,24 @@ pub fn run_brew_cask(ctx: &ExecutionContext, variant: BrewVariant) -> Result<()> Ok(()) } +pub fn run_guix(ctx: &ExecutionContext) -> Result<()> { + let guix = require("guix")?; + + let run_type = ctx.run_type(); + + let output = Command::new(&guix).arg("pull").check_output(); + debug!("guix pull output: {:?}", output); + let should_upgrade = output.is_ok(); + debug!("Can Upgrade Guix: {:?}", should_upgrade); + + print_separator("Guix"); + + if should_upgrade { + return run_type.execute(&guix).args(&["package", "-u"]).check_run(); + } + Err(SkipStep(String::from("Guix Pull Failed, Skipping")).into()) +} + pub fn run_nix(ctx: &ExecutionContext) -> Result<()> { let nix = require("nix")?; let nix_channel = require("nix-channel")?; @@ -274,6 +296,16 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> { } } + #[cfg(target_os = "macos")] + { + if let Ok(..) = require("darwin-rebuild") { + return Err(SkipStep(String::from( + "Nix-darwin on macOS must be upgraded via darwin-rebuild switch", + )) + .into()); + } + } + let run_type = ctx.run_type(); if should_self_upgrade { @@ -391,6 +423,14 @@ pub fn run_sdkman(base_dirs: &BaseDirs, cleanup: bool, run_type: RunType) -> Res Ok(()) } +pub fn run_bun(ctx: &ExecutionContext) -> Result<()> { + let bun = require("bun")?; + + print_separator("Bun"); + + ctx.run_type().execute(&bun).arg("upgrade").check_run() +} + pub fn reboot() { print!("Rebooting..."); Command::new("sudo").arg("reboot").spawn().unwrap().wait().unwrap();