From a95dd1e0374a9469218b4273ac23521e1455ad7b Mon Sep 17 00:00:00 2001 From: Andre Toerien Date: Wed, 25 Jun 2025 15:59:02 +0200 Subject: [PATCH] refactor: route sudo usage through Sudo::execute* --- locales/app.yml | 8 -- src/execution_context.rs | 26 ++-- src/main.rs | 3 +- src/steps/generic.rs | 59 ++++----- src/steps/node.rs | 13 +- src/steps/os/archlinux.rs | 29 ++-- src/steps/os/dragonfly.rs | 34 ++--- src/steps/os/freebsd.rs | 24 ++-- src/steps/os/linux.rs | 270 +++++++++++++++++++++----------------- src/steps/os/macos.rs | 13 +- src/steps/os/openbsd.rs | 29 ++-- src/steps/os/unix.rs | 68 ++++++---- src/steps/os/windows.rs | 16 +-- src/steps/powershell.rs | 10 +- src/sudo.rs | 16 ++- src/utils.rs | 6 - 16 files changed, 303 insertions(+), 321 deletions(-) diff --git a/locales/app.yml b/locales/app.yml index a5a9817d..53f41c8e 100644 --- a/locales/app.yml +++ b/locales/app.yml @@ -214,14 +214,6 @@ _version: 2 zh_CN: "正在跳过" zh_TW: "正在略過" de: "Überspringe" -"Aura(<0.4.6) requires sudo installed to work with AUR packages": - en: "Aura(<0.4.6) requires sudo installed to work with AUR packages" - lt: "Aura (<0.4.6) reikalauja sudo įdiegimo, kad galėtų naudoti AUR paketus" - es: "Aura(<0.4.6) requiere tener sudo instalado para funcionar con paquetes AUR" - fr: "Aura(<0.4.6) nécessite sudo pour fonctionner avec les paquets AUR" - zh_CN: "Aura(<0.4.6) 依赖 sudo 安装 AUR 软件包。" - zh_TW: "Aura(<0.4.6)依賴 sudo 安裝 AUR 套件" - de: "Aura(<0.4.6) benötigt sudo zur Verwendung von AUR-Paketen" "Pacman backup configuration files found:": en: "Pacman backup configuration files found:" lt: "Rasti Pacman atsarginės konfigūracijos failai:" diff --git a/src/execution_context.rs b/src/execution_context.rs index b60d050a..c5cd15c2 100644 --- a/src/execution_context.rs +++ b/src/execution_context.rs @@ -3,7 +3,6 @@ use color_eyre::eyre::Result; use rust_i18n::t; use std::env::var; use std::ffi::OsStr; -use std::path::Path; use std::process::Command; use std::sync::{LazyLock, Mutex}; @@ -11,8 +10,8 @@ use crate::executor::DryCommand; use crate::powershell::Powershell; #[cfg(target_os = "linux")] use crate::steps::linux::Distribution; -use crate::sudo::{Sudo, SudoExecuteOpts}; -use crate::utils::{get_require_sudo_string, require_option}; +use crate::sudo::Sudo; +use crate::utils::require_option; use crate::{config::Config, executor::Executor}; /// An enum telling whether Topgrade should perform dry runs or actually perform the steps. @@ -87,20 +86,6 @@ impl<'a> ExecutionContext<'a> { } } - /// Create an instance of `Executor` that should run `program`, - /// using sudo to elevate privileges. - pub fn execute_elevated(&self, command: &Path, interactive: bool) -> Result { - let sudo = require_option(self.sudo.as_ref(), get_require_sudo_string())?; - sudo.execute_opts( - self, - command, - SudoExecuteOpts { - interactive, - ..Default::default() - }, - ) - } - pub fn run_type(&self) -> RunType { self.run_type } @@ -109,6 +94,13 @@ impl<'a> ExecutionContext<'a> { &self.sudo } + pub fn require_sudo(&self) -> Result<&Sudo> { + require_option( + self.sudo.as_ref(), + t!("Require sudo or counterpart but not found, skip").to_string(), + ) + } + pub fn config(&self) -> &Config { self.config } diff --git a/src/main.rs b/src/main.rs index 696f0e33..73355fec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -232,7 +232,8 @@ fn run() -> Result<()> { run_shell().context("Failed to execute shell")?; } Ok(Key::Char('r' | 'R')) => { - reboot().context("Failed to reboot")?; + println!("{}", t!("Rebooting...")); + reboot(&ctx).context("Failed to reboot")?; } Ok(Key::Char('q' | 'Q')) => (), _ => { diff --git a/src/steps/generic.rs b/src/steps/generic.rs index 74004a2f..e3f9a155 100644 --- a/src/steps/generic.rs +++ b/src/steps/generic.rs @@ -20,10 +20,9 @@ use crate::execution_context::ExecutionContext; use crate::executor::ExecutorOutput; use crate::output_changed_message; use crate::step::Step; +use crate::sudo::SudoExecuteOpts; 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, -}; +use crate::utils::{check_is_python_2_or_shim, require, require_one, require_option, which, PathExt}; use crate::HOME_DIR; use crate::{ error::{SkipStep, StepFailed, TopgradeError}, @@ -126,13 +125,19 @@ pub fn run_rubygems(ctx: &ExecutionContext) -> Result<()> { { ctx.execute(gem).args(["update", "--system"]).status_checked()?; } else { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; if !Path::new("/usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb").exists() { - ctx.execute(sudo) - .arg("-EH") - .arg(gem) - .args(["update", "--system"]) - .status_checked()?; + sudo.execute_opts( + ctx, + &gem, + SudoExecuteOpts { + preserve_env: Some(&[]), + set_home: true, + ..Default::default() + }, + )? + .args(["update", "--system"]) + .status_checked()?; } } @@ -154,10 +159,8 @@ pub fn run_haxelib_update(ctx: &ExecutionContext) -> Result<()> { let mut command = if directory_writable { ctx.execute(&haxelib) } else { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - let mut c = ctx.execute(sudo); - c.arg(&haxelib); - c + let sudo = ctx.require_sudo()?; + sudo.execute(ctx, &haxelib)? }; command.arg("update").status_checked() @@ -439,10 +442,8 @@ pub fn run_vcpkg_update(ctx: &ExecutionContext) -> Result<()> { let mut command = if is_root_install { ctx.execute(&vcpkg) } else { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - let mut c = ctx.execute(sudo); - c.arg(&vcpkg); - c + let sudo = ctx.require_sudo()?; + sudo.execute(ctx, &vcpkg)? }; command.args(["upgrade", "--no-dry-run"]).status_checked() @@ -850,10 +851,8 @@ pub fn run_tlmgr_update(ctx: &ExecutionContext) -> Result<()> { let mut command = if directory_writable { ctx.execute(&tlmgr) } else { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - let mut c = ctx.execute(sudo); - c.arg(&tlmgr); - c + let sudo = ctx.require_sudo()?; + sudo.execute(ctx, &tlmgr)? }; command.args(["update", "--self", "--all"]); @@ -932,9 +931,8 @@ pub fn run_composer_update(ctx: &ExecutionContext) -> Result<()> { }; if has_update { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - ctx.execute(sudo) - .arg(&composer) + let sudo = ctx.require_sudo()?; + sudo.execute(ctx, &composer)? .arg("self-update") .status_checked()?; } @@ -1173,16 +1171,12 @@ pub fn run_bob(ctx: &ExecutionContext) -> Result<()> { } pub fn run_certbot(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; let certbot = require("certbot")?; print_separator("Certbot"); - let mut cmd = ctx.execute(sudo); - cmd.arg(certbot); - cmd.arg("renew"); - - cmd.status_checked() + sudo.execute(ctx, &certbot)?.arg("renew").status_checked() } /// Run `$ freshclam` to update ClamAV signature database @@ -1223,10 +1217,9 @@ pub fn run_lensfun_update_data(ctx: &ExecutionContext) -> Result<()> { const EXIT_CODE_WHEN_NO_UPDATE: i32 = 1; if ctx.config().lensfun_use_sudo() { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; print_separator(SEPARATOR); - ctx.execute(sudo) - .arg(lensfun_update_data) + sudo.execute(ctx, &lensfun_update_data)? // `lensfun-update-data` returns 1 when there is no update available // which should be considered success .status_checked_with_codes(&[EXIT_CODE_WHEN_NO_UPDATE]) diff --git a/src/steps/node.rs b/src/steps/node.rs index e26b57be..9d89bf2d 100644 --- a/src/steps/node.rs +++ b/src/steps/node.rs @@ -4,7 +4,6 @@ use std::os::unix::fs::MetadataExt; use std::path::PathBuf; use std::process::Command; -use crate::utils::{get_require_sudo_string, require_option}; use crate::HOME_DIR; use color_eyre::eyre::Result; #[cfg(target_os = "linux")] @@ -93,8 +92,8 @@ impl NPM { fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> { let args = ["update", self.global_location_arg()]; if use_sudo { - let sudo = require_option(ctx.sudo().clone(), get_require_sudo_string())?; - ctx.execute(sudo).arg(&self.command).args(args).status_checked()?; + let sudo = ctx.require_sudo()?; + sudo.execute(ctx, &self.command)?.args(args).status_checked()?; } else { ctx.execute(&self.command).args(args).status_checked()?; } @@ -153,11 +152,9 @@ impl Yarn { let args = ["global", "upgrade"]; if use_sudo { - let sudo = require_option(ctx.sudo().clone(), get_require_sudo_string())?; - ctx.execute(sudo) - .arg(self.yarn.as_ref().unwrap_or(&self.command)) - .args(args) - .status_checked()?; + let sudo = ctx.require_sudo()?; + let command = self.yarn.as_ref().unwrap_or(&self.command); + sudo.execute(ctx, command)?.args(args).status_checked()?; } else { ctx.execute(&self.command).args(args).status_checked()?; } diff --git a/src/steps/os/archlinux.rs b/src/steps/os/archlinux.rs index 71d109da..e6f00de4 100644 --- a/src/steps/os/archlinux.rs +++ b/src/steps/os/archlinux.rs @@ -11,7 +11,6 @@ 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}; @@ -150,20 +149,17 @@ pub struct Pacman { impl ArchPackageManager for Pacman { fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), "sudo is required to run pacman".into())?; - let mut command = ctx.execute(sudo); - command - .arg(&self.executable) - .arg("-Syu") - .env("PATH", get_execution_path()); + let sudo = ctx.require_sudo()?; + let mut command = sudo.execute(ctx, &self.executable)?; + command.arg("-Syu").env("PATH", get_execution_path()); if ctx.config().yes(Step::System) { command.arg("--noconfirm"); } command.status_checked()?; if ctx.config().cleanup() { - let mut command = ctx.execute(sudo); - command.arg(&self.executable).arg("-Scc"); + let mut command = sudo.execute(ctx, &self.executable)?; + command.arg("-Scc"); if ctx.config().yes(Step::System) { command.arg("--noconfirm"); } @@ -306,23 +302,18 @@ impl ArchPackageManager for Aura { } cmd.status_checked()?; } else { - let sudo = crate::utils::require_option( - ctx.sudo().as_ref(), - t!("Aura(<0.4.6) requires sudo installed to work with AUR packages").to_string(), - )?; + let sudo = ctx.require_sudo()?; - let mut cmd = ctx.execute(sudo); - cmd.arg(&self.executable) - .arg("-Au") + let mut cmd = sudo.execute(ctx, &self.executable)?; + cmd.arg("-Au") .args(ctx.config().aura_aur_arguments().split_whitespace()); if ctx.config().yes(Step::System) { cmd.arg("--noconfirm"); } cmd.status_checked()?; - let mut cmd = ctx.execute(sudo); - cmd.arg(&self.executable) - .arg("-Syu") + let mut cmd = sudo.execute(ctx, &self.executable)?; + cmd.arg("-Syu") .args(ctx.config().aura_pacman_arguments().split_whitespace()); if ctx.config().yes(Step::System) { cmd.arg("--noconfirm"); diff --git a/src/steps/os/dragonfly.rs b/src/steps/os/dragonfly.rs index e88794da..cf5ef4e9 100644 --- a/src/steps/os/dragonfly.rs +++ b/src/steps/os/dragonfly.rs @@ -2,15 +2,15 @@ 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 color_eyre::eyre::Result; -use std::process::Command; +use rust_i18n::t; pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; print_separator(t!("DragonFly BSD Packages")); - let mut cmd = ctx.execute(sudo); - cmd.args(["/usr/local/sbin/pkg", "upgrade"]); + + let mut cmd = sudo.execute(ctx, "/usr/local/sbin/pkg")?; + cmd.arg("upgrade"); if ctx.config().yes(Step::System) { cmd.arg("-y"); } @@ -18,19 +18,19 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> { } pub fn audit_packages(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; print_separator(t!("DragonFly BSD Audit")); - #[allow(clippy::disallowed_methods)] - if !Command::new(sudo) - .args(["/usr/local/sbin/pkg", "audit", "-Fr"]) - .status()? - .success() - { - println!(t!( - "The package audit was successful, but vulnerable packages still remain on the system" - )); - } - Ok(()) + sudo.execute(ctx, "/usr/local/sbin/pkg")? + .args(["audit", "-Fr"]) + .status_checked_with(|status| { + if !status.success() { + println!( + "{}", + t!("The package audit was successful, but vulnerable packages still remain on the system") + ); + } + Ok(()) + }) } diff --git a/src/steps/os/freebsd.rs b/src/steps/os/freebsd.rs index abb84a59..abb8ea38 100644 --- a/src/steps/os/freebsd.rs +++ b/src/steps/os/freebsd.rs @@ -2,26 +2,23 @@ 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 color_eyre::Result; use rust_i18n::t; -use std::process::Command; pub fn upgrade_freebsd(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; print_separator(t!("FreeBSD Update")); - ctx.execute(sudo) - .args(["/usr/sbin/freebsd-update", "fetch", "install"]) + sudo.execute(ctx, "/usr/sbin/freebsd-update")? + .args(["fetch", "install"]) .status_checked() } pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; print_separator(t!("FreeBSD Packages")); - let mut command = ctx.execute(sudo); - - command.args(["/usr/sbin/pkg", "upgrade"]); + let mut command = sudo.execute(ctx, "/usr/sbin/pkg")?; + command.arg("upgrade"); if ctx.config().yes(Step::System) { command.arg("-y"); } @@ -29,12 +26,11 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> { } pub fn audit_packages(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; print_separator(t!("FreeBSD Audit")); - Command::new(sudo) - .args(["/usr/sbin/pkg", "audit", "-Fr"]) - .status_checked()?; - Ok(()) + sudo.execute(ctx, "/usr/sbin/pkg")? + .args(["audit", "-Fr"]) + .status_checked() } diff --git a/src/steps/os/linux.rs b/src/steps/os/linux.rs index d7e6c3bb..cbcaef47 100644 --- a/src/steps/os/linux.rs +++ b/src/steps/os/linux.rs @@ -12,8 +12,9 @@ use crate::execution_context::ExecutionContext; use crate::step::Step; use crate::steps::generic::is_wsl; use crate::steps::os::archlinux; +use crate::sudo::SudoExecuteOpts; use crate::terminal::{print_separator, prompt_yesno}; -use crate::utils::{get_require_sudo_string, require, require_option, which, PathExt}; +use crate::utils::{require, require_one, which, PathExt}; use crate::HOME_DIR; static OS_RELEASE_PATH: &str = "/etc/os-release"; @@ -175,11 +176,9 @@ impl Distribution { } fn update_bedrock(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let brl = require("brl")?; - ctx.execute(sudo).args(["brl", "update"]); - - let output = Command::new("brl").arg("list").output_checked_utf8()?; + let output = Command::new(&brl).arg("list").output_checked_utf8()?; debug!("brl list: {:?} {:?}", output.stdout, output.stderr); for distribution in output.stdout.trim().lines() { @@ -199,34 +198,34 @@ fn update_bedrock(ctx: &ExecutionContext) -> Result<()> { } fn upgrade_alpine_linux(ctx: &ExecutionContext) -> Result<()> { + let sudo = ctx.require_sudo()?; let apk = require("apk")?; - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - ctx.execute(sudo).arg(&apk).arg("update").status_checked()?; - ctx.execute(sudo).arg(&apk).arg("upgrade").status_checked() + sudo.execute(ctx, &apk)?.arg("update").status_checked()?; + sudo.execute(ctx, &apk)?.arg("upgrade").status_checked() } fn upgrade_chimera_linux(ctx: &ExecutionContext) -> Result<()> { + let sudo = ctx.require_sudo()?; let apk = require("apk")?; - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - ctx.execute(sudo).arg(&apk).arg("update").status_checked()?; - ctx.execute(sudo).arg(&apk).arg("upgrade").status_checked() + sudo.execute(ctx, &apk)?.arg("update").status_checked()?; + sudo.execute(ctx, &apk)?.arg("upgrade").status_checked() } fn upgrade_wolfi_linux(ctx: &ExecutionContext) -> Result<()> { + let sudo = ctx.require_sudo()?; let apk = require("apk")?; - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - ctx.execute(sudo).arg(&apk).arg("update").status_checked()?; - ctx.execute(sudo).arg(&apk).arg("upgrade").status_checked() + sudo.execute(ctx, &apk)?.arg("update").status_checked()?; + sudo.execute(ctx, &apk)?.arg("upgrade").status_checked() } fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> { if let Some(bootc) = which("bootc") { if ctx.config().bootc() { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - return ctx.execute(sudo).arg(&bootc).arg("upgrade").status_checked(); + let sudo = ctx.require_sudo()?; + return sudo.execute(ctx, &bootc)?.arg("upgrade").status_checked(); } } @@ -238,15 +237,15 @@ fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> { } }; - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - let mut command = ctx.execute(sudo); - command - .arg(which("dnf").unwrap_or_else(|| Path::new("yum").to_path_buf())) - .arg(if ctx.config().redhat_distro_sync() { - "distro-sync" - } else { - "upgrade" - }); + let sudo = ctx.require_sudo()?; + let dnf = require_one(["dnf", "yum"])?; + + let mut command = sudo.execute(ctx, &dnf)?; + command.arg(if ctx.config().redhat_distro_sync() { + "distro-sync" + } else { + "upgrade" + }); if let Some(args) = ctx.config().dnf_arguments() { command.args(args.split_whitespace()); @@ -261,11 +260,10 @@ fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> { } fn upgrade_nobara(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - let pkg_manager = require("dnf")?; + let sudo = ctx.require_sudo()?; + let dnf = require("dnf")?; - let mut update_command = ctx.execute(sudo); - update_command.arg(&pkg_manager); + let mut update_command = sudo.execute(ctx, &dnf)?; if ctx.config().yes(Step::System) { update_command.arg("-y"); @@ -281,8 +279,7 @@ fn upgrade_nobara(ctx: &ExecutionContext) -> Result<()> { ]); update_command.arg("--refresh").status_checked()?; - let mut upgrade_command = ctx.execute(sudo); - upgrade_command.arg(&pkg_manager); + let mut upgrade_command = sudo.execute(ctx, &dnf)?; if ctx.config().yes(Step::System) { upgrade_command.arg("-y"); @@ -295,18 +292,18 @@ fn upgrade_nobara(ctx: &ExecutionContext) -> Result<()> { } fn upgrade_nilrt(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; let opkg = require("opkg")?; - ctx.execute(sudo).arg(&opkg).arg("update").status_checked()?; - ctx.execute(sudo).arg(&opkg).arg("upgrade").status_checked() + sudo.execute(ctx, &opkg)?.arg("update").status_checked()?; + sudo.execute(ctx, &opkg)?.arg("upgrade").status_checked() } fn upgrade_fedora_immutable(ctx: &ExecutionContext) -> Result<()> { if let Some(bootc) = which("bootc") { if ctx.config().bootc() { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - return ctx.execute(sudo).arg(&bootc).arg("upgrade").status_checked(); + let sudo = ctx.require_sudo()?; + return sudo.execute(ctx, &bootc)?.arg("upgrade").status_checked(); } } @@ -318,18 +315,21 @@ fn upgrade_fedora_immutable(ctx: &ExecutionContext) -> Result<()> { } fn upgrade_bedrock_strata(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - ctx.execute(sudo).args(["brl", "update"]).status_checked()?; + let sudo = ctx.require_sudo()?; + let brl = require("brl")?; + + sudo.execute(ctx, &brl)?.arg("update").status_checked()?; Ok(()) } fn upgrade_suse(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - ctx.execute(sudo).args(["zypper", "refresh"]).status_checked()?; + let sudo = ctx.require_sudo()?; + let zypper = require("zypper")?; - let mut cmd = ctx.execute(sudo); - cmd.arg("zypper"); + sudo.execute(ctx, &zypper)?.arg("refresh").status_checked()?; + + let mut cmd = sudo.execute(ctx, &zypper)?; cmd.arg(if ctx.config().suse_dup() { "dist-upgrade" } else { @@ -345,11 +345,13 @@ fn upgrade_suse(ctx: &ExecutionContext) -> Result<()> { } fn upgrade_opensuse_tumbleweed(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - ctx.execute(sudo).args(["zypper", "refresh"]).status_checked()?; + let sudo = ctx.require_sudo()?; + let zypper = require("zypper")?; - let mut cmd = ctx.execute(sudo); - cmd.args(["zypper", "dist-upgrade"]); + sudo.execute(ctx, &zypper)?.arg("refresh").status_checked()?; + + let mut cmd = sudo.execute(ctx, &zypper)?; + cmd.arg("dist-upgrade"); if ctx.config().yes(Step::System) { cmd.arg("-y"); } @@ -360,9 +362,10 @@ fn upgrade_opensuse_tumbleweed(ctx: &ExecutionContext) -> Result<()> { } fn upgrade_suse_micro(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - let mut cmd = ctx.execute(sudo); - cmd.arg("transactional-update"); + let sudo = ctx.require_sudo()?; + let upd = require("transactional-update")?; + + let mut cmd = sudo.execute(ctx, &upd)?; if ctx.config().yes(Step::System) { cmd.arg("-n"); } @@ -373,10 +376,12 @@ fn upgrade_suse_micro(ctx: &ExecutionContext) -> Result<()> { } fn upgrade_openmandriva(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - let mut command = ctx.execute(sudo); + let sudo = ctx.require_sudo()?; + let dnf = require("dnf")?; - command.arg(which("dnf").unwrap()).arg("upgrade"); + let mut command = sudo.execute(ctx, &dnf)?; + + command.arg("upgrade"); if let Some(args) = ctx.config().dnf_arguments() { command.args(args.split_whitespace()); @@ -392,10 +397,12 @@ fn upgrade_openmandriva(ctx: &ExecutionContext) -> Result<()> { } fn upgrade_pclinuxos(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - let mut command_update = ctx.execute(sudo); + let sudo = ctx.require_sudo()?; + let apt_get = require("apt-get")?; - command_update.arg(which("apt-get").unwrap()).arg("update"); + let mut command_update = sudo.execute(ctx, &apt_get)?; + + command_update.arg("update"); if let Some(args) = ctx.config().dnf_arguments() { command_update.args(args.split_whitespace()); @@ -407,8 +414,7 @@ fn upgrade_pclinuxos(ctx: &ExecutionContext) -> Result<()> { command_update.status_checked()?; - let mut cmd = ctx.execute(sudo); - cmd.arg(which("apt-get").unwrap()); + let mut cmd = sudo.execute(ctx, &apt_get)?; cmd.arg("dist-upgrade"); if ctx.config().yes(Step::System) { cmd.arg("-y"); @@ -439,16 +445,18 @@ fn upgrade_vanilla(ctx: &ExecutionContext) -> Result<()> { } fn upgrade_void(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - let mut command = ctx.execute(sudo); - command.args(["xbps-install", "-Su", "xbps"]); + let sudo = ctx.require_sudo()?; + let xbps = require("xbps-install")?; + + let mut command = sudo.execute(ctx, &xbps)?; + command.args(["-Su", "xbps"]); if ctx.config().yes(Step::System) { command.arg("-y"); } command.status_checked()?; - let mut command = ctx.execute(sudo); - command.args(["xbps-install", "-u"]); + let mut command = sudo.execute(ctx, &xbps)?; + command.arg("-u"); if ctx.config().yes(Step::System) { command.arg("-y"); } @@ -458,18 +466,20 @@ fn upgrade_void(ctx: &ExecutionContext) -> Result<()> { } fn upgrade_gentoo(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; + let emerge = require("emerge")?; + if let Some(layman) = which("layman") { - ctx.execute(sudo).arg(layman).args(["-s", "ALL"]).status_checked()?; + sudo.execute(ctx, &layman)?.args(["-s", "ALL"]).status_checked()?; } println!("{}", t!("Syncing portage")); if let Some(ego) = which("ego") { // The Funtoo team doesn't reccomend running both ego sync and emerge --sync - ctx.execute(sudo).arg(ego).arg("sync").status_checked()?; + sudo.execute(ctx, &ego)?.arg("sync").status_checked()?; } else { - ctx.execute(sudo) - .args(["emerge", "--sync"]) + sudo.execute(ctx, &emerge)? + .arg("--sync") .args( ctx.config() .emerge_sync_flags() @@ -480,11 +490,10 @@ fn upgrade_gentoo(ctx: &ExecutionContext) -> Result<()> { } if let Some(eix_update) = which("eix-update") { - ctx.execute(sudo).arg(eix_update).status_checked()?; + sudo.execute(ctx, &eix_update)?.status_checked()?; } - ctx.execute(sudo) - .arg("emerge") + sudo.execute(ctx, &emerge)? .args( ctx.config() .emerge_update_flags() @@ -527,16 +536,14 @@ fn upgrade_debian(ctx: &ExecutionContext) -> Result<()> { return Ok(()); } - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; if !is_nala { - ctx.execute(sudo) - .arg(&apt) + sudo.execute(ctx, &apt)? .arg("update") .status_checked_with_codes(&[0, 100])?; } - let mut command = ctx.execute(sudo); - command.arg(&apt); + let mut command = sudo.execute(ctx, &apt)?; if is_nala { command.arg("upgrade"); } else { @@ -551,10 +558,10 @@ fn upgrade_debian(ctx: &ExecutionContext) -> Result<()> { command.status_checked()?; if ctx.config().cleanup() { - ctx.execute(sudo).arg(&apt).arg("clean").status_checked()?; + sudo.execute(ctx, &apt)?.arg("clean").status_checked()?; - let mut command = ctx.execute(sudo); - command.arg(&apt).arg("autoremove"); + let mut command = sudo.execute(ctx, &apt)?; + command.arg("autoremove"); if ctx.config().yes(Step::System) { command.arg("-y"); } @@ -584,9 +591,10 @@ pub fn run_deb_get(ctx: &ExecutionContext) -> Result<()> { } fn upgrade_solus(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - let mut cmd = ctx.execute(sudo); - cmd.arg("eopkg"); + let sudo = ctx.require_sudo()?; + let eopkg = require("eopkg")?; + + let mut cmd = sudo.execute(ctx, &eopkg)?; if ctx.config().yes(Step::System) { cmd.arg("-y"); } @@ -689,9 +697,11 @@ pub fn run_packer_nu(ctx: &ExecutionContext) -> Result<()> { } fn upgrade_clearlinux(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - let mut cmd = ctx.execute(sudo); - cmd.args(["swupd", "update"]); + let sudo = ctx.require_sudo()?; + let swupd = require("swupd")?; + + let mut cmd = sudo.execute(ctx, &swupd)?; + cmd.arg("update"); if ctx.config().yes(Step::System) { cmd.arg("--assume=yes"); } @@ -701,32 +711,36 @@ fn upgrade_clearlinux(ctx: &ExecutionContext) -> Result<()> { } fn upgrade_exherbo(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - ctx.execute(sudo).args(["cave", "sync"]).status_checked()?; + let sudo = ctx.require_sudo()?; + let cave = require("cave")?; + let eclectic = require("eclectic")?; - ctx.execute(sudo) - .args(["cave", "resolve", "world", "-c1", "-Cs", "-km", "-Km", "-x"]) + sudo.execute(ctx, &cave)?.arg("sync").status_checked()?; + + sudo.execute(ctx, &cave)? + .args(["resolve", "world", "-c1", "-Cs", "-km", "-Km", "-x"]) .status_checked()?; if ctx.config().cleanup() { - ctx.execute(sudo).args(["cave", "purge", "-x"]).status_checked()?; + sudo.execute(ctx, &cave)?.args(["purge", "-x"]).status_checked()?; } - ctx.execute(sudo) - .args(["cave", "fix-linkage", "-x", "--", "-Cs"]) + sudo.execute(ctx, &cave)? + .args(["fix-linkage", "-x", "--", "-Cs"]) .status_checked()?; - ctx.execute(sudo) - .args(["eclectic", "config", "interactive"]) + sudo.execute(ctx, &eclectic)? + .args(["config", "interactive"]) .status_checked()?; Ok(()) } fn upgrade_nixos(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - let mut command = ctx.execute(sudo); - command.args(["/run/current-system/sw/bin/nixos-rebuild", "switch", "--upgrade"]); + let sudo = ctx.require_sudo()?; + + let mut command = sudo.execute(ctx, "/run/current-system/sw/bin/nixos-rebuild")?; + command.args(["switch", "--upgrade"]); if let Some(args) = ctx.config().nix_arguments() { command.args(args.split_whitespace()); @@ -734,8 +748,8 @@ fn upgrade_nixos(ctx: &ExecutionContext) -> Result<()> { command.status_checked()?; if ctx.config().cleanup() { - ctx.execute(sudo) - .args(["/run/current-system/sw/bin/nix-collect-garbage", "-d"]) + sudo.execute(ctx, "/run/current-system/sw/bin/nix-collect-garbage")? + .arg("-d") .status_checked()?; } @@ -749,12 +763,14 @@ fn upgrade_neon(ctx: &ExecutionContext) -> Result<()> { // seems rare // if that comes up we need to create a Distribution::PackageKit or some such - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; - let pkcon = which("pkcon").unwrap(); + let sudo = ctx.require_sudo()?; + let pkcon = require("pkcon")?; + // pkcon ignores update with update and refresh provided together - ctx.execute(sudo).arg(&pkcon).arg("refresh").status_checked()?; - let mut exe = ctx.execute(sudo); - let cmd = exe.arg(&pkcon).arg("update"); + sudo.execute(ctx, &pkcon)?.arg("refresh").status_checked()?; + + let mut exe = sudo.execute(ctx, &pkcon)?; + let cmd = exe.arg("update"); if ctx.config().yes(Step::System) { cmd.arg("-y"); } @@ -809,14 +825,14 @@ fn should_skip_needrestart() -> Result<()> { } pub fn run_needrestart(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; let needrestart = require("needrestart")?; should_skip_needrestart()?; print_separator(t!("Check for needed restarts")); - ctx.execute(sudo).arg(needrestart).status_checked()?; + sudo.execute(ctx, &needrestart)?.status_checked()?; Ok(()) } @@ -846,8 +862,9 @@ pub fn run_fwupdmgr(ctx: &ExecutionContext) -> Result<()> { } pub fn run_flatpak(ctx: &ExecutionContext) -> Result<()> { + let sudo = ctx.require_sudo()?; let flatpak = require("flatpak")?; - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let cleanup = ctx.config().cleanup(); let yes = ctx.config().yes(Step::Flatpak); print_separator("Flatpak User Packages"); @@ -872,13 +889,13 @@ pub fn run_flatpak(ctx: &ExecutionContext) -> Result<()> { if yes { update_args.push("-y"); } - ctx.execute(sudo).arg(&flatpak).args(&update_args).status_checked()?; + sudo.execute(ctx, &flatpak)?.args(&update_args).status_checked()?; if cleanup { let mut cleanup_args = vec!["uninstall", "--system", "--unused"]; if yes { cleanup_args.push("-y"); } - ctx.execute(sudo).arg(flatpak).args(&cleanup_args).status_checked()?; + sudo.execute(ctx, &flatpak)?.args(&cleanup_args).status_checked()?; } } else { let mut update_args = vec!["update", "--system"]; @@ -899,7 +916,7 @@ pub fn run_flatpak(ctx: &ExecutionContext) -> Result<()> { } pub fn run_snap(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; let snap = require("snap")?; if !PathBuf::from("/var/snapd.socket").exists() && !PathBuf::from("/run/snapd.socket").exists() { @@ -907,17 +924,17 @@ pub fn run_snap(ctx: &ExecutionContext) -> Result<()> { } print_separator("snap"); - ctx.execute(sudo).arg(snap).arg("refresh").status_checked() + sudo.execute(ctx, &snap)?.arg("refresh").status_checked() } pub fn run_pihole_update(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; let pihole = require("pihole")?; Path::new("/opt/pihole/update.sh").require()?; print_separator("pihole"); - ctx.execute(sudo).arg(pihole).arg("-up").status_checked() + sudo.execute(ctx, &pihole)?.arg("-up").status_checked() } pub fn run_protonup_update(ctx: &ExecutionContext) -> Result<()> { @@ -960,36 +977,44 @@ pub fn run_distrobox_update(ctx: &ExecutionContext) -> Result<()> { } pub fn run_dkp_pacman_update(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; let dkp_pacman = require("dkp-pacman")?; print_separator("Devkitpro pacman"); - ctx.execute(sudo).arg(&dkp_pacman).arg("-Syu").status_checked()?; + sudo.execute(ctx, &dkp_pacman)?.arg("-Syu").status_checked()?; if ctx.config().cleanup() { - ctx.execute(sudo).arg(&dkp_pacman).arg("-Scc").status_checked()?; + sudo.execute(ctx, &dkp_pacman)?.arg("-Scc").status_checked()?; } Ok(()) } pub fn run_config_update(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; if ctx.config().yes(Step::ConfigUpdate) { return Err(SkipStep(t!("Skipped in --yes").to_string()).into()); } if let Ok(etc_update) = require("etc-update") { print_separator(t!("Configuration update")); - ctx.execute(sudo).arg(etc_update).status_checked()?; + sudo.execute(ctx, etc_update)?.status_checked()?; } else if let Ok(pacdiff) = require("pacdiff") { if std::env::var("DIFFPROG").is_err() { require("vim")?; } print_separator(t!("Configuration update")); - ctx.execute_elevated(&pacdiff, false)?.status_checked()?; + sudo.execute_opts( + ctx, + &pacdiff, + SudoExecuteOpts { + preserve_env: Some(&["DIFFPROG"]), + ..Default::default() + }, + )? + .status_checked()?; } Ok(()) @@ -1012,8 +1037,9 @@ pub fn run_lure_update(ctx: &ExecutionContext) -> Result<()> { } pub fn run_waydroid(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; let waydroid = require("waydroid")?; + let status = ctx.execute(&waydroid).arg("status").output_checked_utf8()?; // example output of `waydroid status`: // @@ -1052,16 +1078,16 @@ pub fn run_waydroid(ctx: &ExecutionContext) -> Result<()> { ); } } - ctx.execute(sudo).arg(&waydroid).arg("upgrade").status_checked() + sudo.execute(ctx, &waydroid)?.arg("upgrade").status_checked() } pub fn run_auto_cpufreq(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; let auto_cpu_freq = require("auto-cpufreq")?; print_separator("auto-cpufreq"); - ctx.execute(sudo).arg(auto_cpu_freq).arg("--update").status_checked() + sudo.execute(ctx, &auto_cpu_freq)?.arg("--update").status_checked() } pub fn run_cinnamon_spices_updater(ctx: &ExecutionContext) -> Result<()> { diff --git a/src/steps/os/macos.rs b/src/steps/os/macos.rs index 85323782..73231d48 100644 --- a/src/steps/os/macos.rs +++ b/src/steps/os/macos.rs @@ -3,7 +3,6 @@ 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 color_eyre::eyre::Result; use rust_i18n::t; use std::collections::HashSet; @@ -12,16 +11,16 @@ use std::process::Command; use tracing::debug; pub fn run_macports(ctx: &ExecutionContext) -> Result<()> { - require("port")?; - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; + let port = require("port")?; print_separator("MacPorts"); - ctx.execute(sudo).args(["port", "selfupdate"]).status_checked()?; - ctx.execute(sudo) - .args(["port", "-u", "upgrade", "outdated"]) + sudo.execute(ctx, &port)?.arg("selfupdate").status_checked()?; + sudo.execute(ctx, &port)? + .args(["-u", "upgrade", "outdated"]) .status_checked()?; if ctx.config().cleanup() { - ctx.execute(sudo).args(["port", "-N", "reclaim"]).status_checked()?; + sudo.execute(ctx, &port)?.args(["-N", "reclaim"]).status_checked()?; } Ok(()) diff --git a/src/steps/os/openbsd.rs b/src/steps/os/openbsd.rs index 35a49c17..cf3a839c 100644 --- a/src/steps/os/openbsd.rs +++ b/src/steps/os/openbsd.rs @@ -1,7 +1,6 @@ use crate::command::CommandExt; use crate::execution_context::ExecutionContext; use crate::terminal::print_separator; -use crate::utils::{get_require_sudo_string, require_option}; use color_eyre::eyre::Result; use rust_i18n::t; use std::fs; @@ -18,7 +17,7 @@ fn is_openbsd_current(ctx: &ExecutionContext) -> Result { } pub fn upgrade_openbsd(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; print_separator(t!("OpenBSD Update")); let is_current = is_openbsd_current(ctx)?; @@ -28,17 +27,15 @@ pub fn upgrade_openbsd(ctx: &ExecutionContext) -> Result<()> { return Ok(()); } - let args = if is_current { - vec!["/usr/sbin/sysupgrade", "-sn"] + if is_current { + sudo.execute(ctx, "/usr/sbin/sysupgrade")?.arg("-sn").status_checked() } else { - vec!["/usr/sbin/syspatch"] - }; - - ctx.execute(sudo).args(&args).status_checked() + sudo.execute(ctx, "/usr/sbin/syspatch")?.status_checked() + } } pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> { - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; + let sudo = ctx.require_sudo()?; print_separator(t!("OpenBSD Packages")); let is_current = is_openbsd_current(ctx)?; @@ -49,17 +46,13 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> { } if ctx.config().cleanup() { - ctx.execute(sudo) - .args(["/usr/sbin/pkg_delete", "-ac"]) - .status_checked()?; + sudo.execute(ctx, "/usr/sbin/pkg_delete")?.arg("-ac").status_checked()?; } - let mut args = vec!["/usr/sbin/pkg_add", "-u"]; + let mut command = sudo.execute(ctx, "/usr/sbin/pkg_add")?; + command.arg("-u"); if is_current { - args.push("-Dsnap"); + command.arg("-Dsnap"); } - - ctx.execute(sudo).args(&args).status_checked()?; - - Ok(()) + command.status_checked() } diff --git a/src/steps/os/unix.rs b/src/steps/os/unix.rs index f1fa3b86..5f3a6a22 100644 --- a/src/steps/os/unix.rs +++ b/src/steps/os/unix.rs @@ -1,5 +1,3 @@ -use crate::command::CommandExt; -use crate::{output_changed_message, HOME_DIR}; use color_eyre::eyre::eyre; use color_eyre::eyre::Context; use color_eyre::eyre::Result; @@ -20,6 +18,10 @@ use std::sync::LazyLock; use std::{env::var, path::Path}; use tracing::{debug, warn}; +use crate::command::CommandExt; +use crate::sudo::SudoExecuteOpts; +use crate::{output_changed_message, HOME_DIR}; + #[cfg(target_os = "linux")] use super::linux::Distribution; use crate::error::SkipStep; @@ -28,7 +30,7 @@ use crate::execution_context::ExecutionContext; use crate::executor::Executor; use crate::step::Step; use crate::terminal::print_separator; -use crate::utils::{get_require_sudo_string, require, require_option, PathExt}; +use crate::utils::{require, PathExt}; #[cfg(any(target_os = "linux", target_os = "macos"))] const INTEL_BREW: &str = "/usr/local/bin/brew"; @@ -197,20 +199,20 @@ pub fn run_oh_my_fish(ctx: &ExecutionContext) -> Result<()> { } pub fn run_pkgin(ctx: &ExecutionContext) -> Result<()> { + let sudo = ctx.require_sudo()?; let pkgin = require("pkgin")?; - let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?; print_separator("Pkgin"); - let mut command = ctx.execute(sudo); - command.arg(&pkgin).arg("update"); + let mut command = sudo.execute(ctx, &pkgin)?; + command.arg("update"); if ctx.config().yes(Step::Pkgin) { command.arg("-y"); } command.status_checked()?; - let mut command = ctx.execute(sudo); - command.arg(&pkgin).arg("upgrade"); + let mut command = sudo.execute(ctx, &pkgin)?; + command.arg("upgrade"); if ctx.config().yes(Step::Pkgin) { command.arg("-y"); } @@ -247,7 +249,7 @@ pub fn run_fundle(ctx: &ExecutionContext) -> Result<()> { #[cfg(not(any(target_os = "android", target_os = "macos")))] pub fn upgrade_gnome_extensions(ctx: &ExecutionContext) -> Result<()> { let gdbus = require("gdbus")?; - require_option( + crate::utils::require_option( var("XDG_CURRENT_DESKTOP").ok().filter(|p| p.contains("GNOME")), t!("Desktop does not appear to be GNOME").to_string(), )?; @@ -327,16 +329,19 @@ pub fn run_brew_formula(ctx: &ExecutionContext, variant: BrewVariant) -> Result< let sudo_as_user = t!("sudo as user '{user}'", user = user.name); print_separator(format!("{} ({})", variant.step_title(), sudo_as_user)); - let sudo = crate::utils::require_option(ctx.sudo().as_ref(), crate::utils::get_require_sudo_string())?; - ctx.execute(sudo) - .current_dir("/tmp") // brew needs a writable current directory - .args([ - "--set-home", - &format!("--user={}", user.name), - &format!("{}", binary_name.to_string_lossy()), - "update", - ]) - .status_checked()?; + let sudo = ctx.require_sudo()?; + sudo.execute_opts( + ctx, + &binary_name, + SudoExecuteOpts { + set_home: true, + user: Some(&user.name), + ..Default::default() + }, + )? + .current_dir("/tmp") // brew needs a writable current directory + .arg("update") + .status_checked()?; return Ok(()); } } @@ -551,10 +556,18 @@ pub fn run_nix_self_upgrade(ctx: &ExecutionContext) -> Result<()> { let nix_args = nix_args(); if multi_user { - ctx.execute_elevated(&nix, true)? - .args(nix_args) - .arg("upgrade-nix") - .status_checked() + let sudo = ctx.require_sudo()?; + sudo.execute_opts( + ctx, + &nix, + SudoExecuteOpts { + interactive: true, + ..Default::default() + }, + )? + .args(nix_args) + .arg("upgrade-nix") + .status_checked() } else { ctx.execute(&nix).args(nix_args).arg("upgrade-nix").status_checked() } @@ -897,8 +910,9 @@ pub fn run_maza(ctx: &ExecutionContext) -> Result<()> { ctx.execute(maza).arg("update").status_checked() } -pub fn reboot() -> Result<()> { - print!("{}", t!("Rebooting...")); - - Command::new("sudo").arg("reboot").status_checked() +pub fn reboot(ctx: &ExecutionContext) -> Result<()> { + match ctx.sudo() { + Some(sudo) => sudo.execute(ctx, "reboot")?.status_checked(), + None => ctx.execute("reboot").status_checked(), + } } diff --git a/src/steps/os/windows.rs b/src/steps/os/windows.rs index 198252b2..f4544491 100644 --- a/src/steps/os/windows.rs +++ b/src/steps/os/windows.rs @@ -20,11 +20,7 @@ pub fn run_chocolatey(ctx: &ExecutionContext) -> Result<()> { print_separator("Chocolatey"); let mut command = match ctx.sudo() { - Some(sudo) => { - let mut command = ctx.execute(sudo); - command.arg(choco); - command - } + Some(sudo) => sudo.execute(ctx, &choco)?, None => ctx.execute(choco), }; @@ -46,11 +42,7 @@ pub fn run_winget(ctx: &ExecutionContext) -> Result<()> { let mut command = if ctx.config().winget_use_sudo() { match ctx.sudo() { - Some(sudo) => { - let mut command = ctx.execute(sudo); - command.arg(winget); - command - } + Some(sudo) => sudo.execute(ctx, &winget)?, None => ctx.execute(winget), } } else { @@ -242,10 +234,10 @@ pub fn microsoft_store(ctx: &ExecutionContext) -> Result<()> { powershell.microsoft_store(ctx) } -pub fn reboot() -> Result<()> { +pub fn reboot(ctx: &ExecutionContext) -> Result<()> { // If this works, it won't return, but if it doesn't work, it may return a useful error // message. - Command::new("shutdown").args(["/R", "/T", "0"]).status_checked() + ctx.execute("shutdown.exe").args(["/R", "/T", "0"]).status_checked() } pub fn insert_startup_scripts(git_repos: &mut RepoStep) -> Result<()> { diff --git a/src/steps/powershell.rs b/src/steps/powershell.rs index 6182403a..eb6d5e19 100644 --- a/src/steps/powershell.rs +++ b/src/steps/powershell.rs @@ -75,12 +75,10 @@ impl Powershell { /// Builds a "primary" powershell command (uses dry-run if required): /// {powershell} -NoProfile -Command {cmd} fn build_command<'a>(&self, ctx: &'a ExecutionContext, cmd: &str, use_sudo: bool) -> Result { - let mut command = if use_sudo && ctx.sudo().is_some() { - let mut cmd = ctx.execute(ctx.sudo().as_ref().unwrap()); - cmd.arg(&self.path); - cmd - } else { - ctx.execute(&self.path) + // if use_sudo and sudo is available, use it, otherwise run directly + let mut command = match ctx.sudo() { + Some(sudo) if use_sudo => sudo.execute(ctx, &self.path)?, + _ => ctx.execute(&self.path), }; #[cfg(windows)] diff --git a/src/sudo.rs b/src/sudo.rs index 3de601a4..8d57c1b2 100644 --- a/src/sudo.rs +++ b/src/sudo.rs @@ -1,4 +1,5 @@ use std::ffi::OsStr; +use std::path::Path; use std::path::PathBuf; use color_eyre::eyre::Context; @@ -69,6 +70,15 @@ impl Sudo { which(kind.as_ref()).map(|path| Self { path, kind }) } + /// Gets the path to the `sudo` binary. Do not use this to execute `sudo` directly - either use + /// [`Sudo::elevate`], or if you need to specify arguments to `sudo`, use [`Sudo::elevate_opts`]. + /// This way, sudo options can be specified generically and the actual arguments customized + /// depending on the sudo kind. + #[allow(unused)] + pub fn path(&self) -> &Path { + self.path.as_ref() + } + /// Elevate permissions with `sudo`. /// /// This helps prevent blocking `sudo` prompts from stopping the run in the middle of a @@ -278,9 +288,3 @@ pub enum SudoKind { Run0, Please, } - -impl AsRef for Sudo { - fn as_ref(&self) -> &OsStr { - self.path.as_ref() - } -} diff --git a/src/utils.rs b/src/utils.rs index 6f3afac0..c9f0ff22 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -222,12 +222,6 @@ pub mod merge_strategies { } } -// Skip causes -// TODO: Put them in a better place when we have more of them -pub fn get_require_sudo_string() -> String { - t!("Require sudo or counterpart but not found, skip").to_string() -} - /// Return `Err(SkipStep)` if `python` is a Python 2 or shim. /// /// # Shim