Add Sudo type (#221)
* Create `Sudo` type and `SudoKind` enum * Fix build * reformat * Fix choco on windows * Fix linux * Fix linux more * more fix stuff hehe hoho hahaha * more fix stuff hehe hoho hahaha Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>
This commit is contained in:
@@ -1,16 +1,17 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use crate::executor::RunType;
|
use crate::executor::RunType;
|
||||||
use crate::git::Git;
|
use crate::git::Git;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::utils::require_option;
|
use crate::utils::require_option;
|
||||||
use crate::{config::Config, executor::Executor};
|
use crate::{config::Config, executor::Executor};
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use directories::BaseDirs;
|
use directories::BaseDirs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::Path;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
pub struct ExecutionContext<'a> {
|
pub struct ExecutionContext<'a> {
|
||||||
run_type: RunType,
|
run_type: RunType,
|
||||||
sudo: &'a Option<PathBuf>,
|
sudo: Option<Sudo>,
|
||||||
git: &'a Git,
|
git: &'a Git,
|
||||||
config: &'a Config,
|
config: &'a Config,
|
||||||
base_dirs: &'a BaseDirs,
|
base_dirs: &'a BaseDirs,
|
||||||
@@ -23,7 +24,7 @@ pub struct ExecutionContext<'a> {
|
|||||||
impl<'a> ExecutionContext<'a> {
|
impl<'a> ExecutionContext<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
run_type: RunType,
|
run_type: RunType,
|
||||||
sudo: &'a Option<PathBuf>,
|
sudo: Option<Sudo>,
|
||||||
git: &'a Git,
|
git: &'a Git,
|
||||||
config: &'a Config,
|
config: &'a Config,
|
||||||
base_dirs: &'a BaseDirs,
|
base_dirs: &'a BaseDirs,
|
||||||
@@ -40,18 +41,7 @@ impl<'a> ExecutionContext<'a> {
|
|||||||
|
|
||||||
pub fn execute_elevated(&self, command: &Path, interactive: bool) -> Result<Executor> {
|
pub fn execute_elevated(&self, command: &Path, interactive: bool) -> Result<Executor> {
|
||||||
let sudo = require_option(self.sudo.clone(), "Sudo is required for this operation".into())?;
|
let sudo = require_option(self.sudo.clone(), "Sudo is required for this operation".into())?;
|
||||||
let mut cmd = self.run_type.execute(&sudo);
|
Ok(sudo.execute_elevated(self, command, interactive))
|
||||||
|
|
||||||
if sudo.ends_with("sudo") {
|
|
||||||
cmd.arg("--preserve-env=DIFFPROG");
|
|
||||||
}
|
|
||||||
|
|
||||||
if interactive {
|
|
||||||
cmd.arg("-i");
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.arg(command);
|
|
||||||
Ok(cmd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_type(&self) -> RunType {
|
pub fn run_type(&self) -> RunType {
|
||||||
@@ -62,8 +52,8 @@ impl<'a> ExecutionContext<'a> {
|
|||||||
self.git
|
self.git
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sudo(&self) -> &Option<PathBuf> {
|
pub fn sudo(&self) -> &Option<Sudo> {
|
||||||
self.sudo
|
&self.sudo
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn config(&self) -> &Config {
|
pub fn config(&self) -> &Config {
|
||||||
|
|||||||
28
src/main.rs
28
src/main.rs
@@ -83,10 +83,10 @@ fn run() -> Result<()> {
|
|||||||
let git = git::Git::new();
|
let git = git::Git::new();
|
||||||
let mut git_repos = git::Repositories::new(&git);
|
let mut git_repos = git::Repositories::new(&git);
|
||||||
|
|
||||||
let sudo = sudo::path();
|
let sudo = sudo::Sudo::detect();
|
||||||
let run_type = executor::RunType::new(config.dry_run());
|
let run_type = executor::RunType::new(config.dry_run());
|
||||||
|
|
||||||
let ctx = execution_context::ExecutionContext::new(run_type, &sudo, &git, &config, &base_dirs);
|
let ctx = execution_context::ExecutionContext::new(run_type, sudo, &git, &config, &base_dirs);
|
||||||
|
|
||||||
let mut runner = runner::Runner::new(&ctx);
|
let mut runner = runner::Runner::new(&ctx);
|
||||||
|
|
||||||
@@ -121,7 +121,9 @@ fn run() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if config.pre_sudo() {
|
if config.pre_sudo() {
|
||||||
sudo::elevate(&ctx, sudo.as_ref())?;
|
if let Some(sudo) = ctx.sudo() {
|
||||||
|
sudo.elevate(&ctx)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let powershell = powershell::Powershell::new();
|
let powershell = powershell::Powershell::new();
|
||||||
@@ -202,17 +204,17 @@ fn run() -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "dragonfly")]
|
#[cfg(target_os = "dragonfly")]
|
||||||
runner.execute(Step::Pkg, "DragonFly BSD Packages", || {
|
runner.execute(Step::Pkg, "DragonFly BSD Packages", || {
|
||||||
dragonfly::upgrade_packages(sudo.as_ref(), run_type)
|
dragonfly::upgrade_packages(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
runner.execute(Step::Pkg, "FreeBSD Packages", || {
|
runner.execute(Step::Pkg, "FreeBSD Packages", || {
|
||||||
freebsd::upgrade_packages(&ctx, sudo.as_ref(), run_type)
|
freebsd::upgrade_packages(&ctx, ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(target_os = "openbsd")]
|
#[cfg(target_os = "openbsd")]
|
||||||
runner.execute(Step::Pkg, "OpenBSD Packages", || {
|
runner.execute(Step::Pkg, "OpenBSD Packages", || {
|
||||||
openbsd::upgrade_packages(sudo.as_ref(), run_type)
|
openbsd::upgrade_packages(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
@@ -383,7 +385,7 @@ fn run() -> Result<()> {
|
|||||||
runner.execute(Step::DebGet, "deb-get", || linux::run_deb_get(&ctx))?;
|
runner.execute(Step::DebGet, "deb-get", || linux::run_deb_get(&ctx))?;
|
||||||
runner.execute(Step::Toolbx, "toolbx", || toolbx::run_toolbx(&ctx))?;
|
runner.execute(Step::Toolbx, "toolbx", || toolbx::run_toolbx(&ctx))?;
|
||||||
runner.execute(Step::Flatpak, "Flatpak", || linux::flatpak_update(&ctx))?;
|
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::Snap, "snap", || linux::run_snap(ctx.sudo().as_ref(), run_type))?;
|
||||||
runner.execute(Step::Pacstall, "pacstall", || linux::run_pacstall(&ctx))?;
|
runner.execute(Step::Pacstall, "pacstall", || linux::run_pacstall(&ctx))?;
|
||||||
runner.execute(Step::Pacdef, "pacdef", || linux::run_pacdef(&ctx))?;
|
runner.execute(Step::Pacdef, "pacdef", || linux::run_pacdef(&ctx))?;
|
||||||
runner.execute(Step::Protonup, "protonup", || linux::run_protonup_update(&ctx))?;
|
runner.execute(Step::Protonup, "protonup", || linux::run_protonup_update(&ctx))?;
|
||||||
@@ -403,11 +405,11 @@ fn run() -> Result<()> {
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
runner.execute(Step::System, "pihole", || {
|
runner.execute(Step::System, "pihole", || {
|
||||||
linux::run_pihole_update(sudo.as_ref(), run_type)
|
linux::run_pihole_update(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
runner.execute(Step::Firmware, "Firmware upgrades", || linux::run_fwupdmgr(&ctx))?;
|
runner.execute(Step::Firmware, "Firmware upgrades", || linux::run_fwupdmgr(&ctx))?;
|
||||||
runner.execute(Step::Restarts, "Restarts", || {
|
runner.execute(Step::Restarts, "Restarts", || {
|
||||||
linux::run_needrestart(sudo.as_ref(), run_type)
|
linux::run_needrestart(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,12 +422,12 @@ fn run() -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
runner.execute(Step::System, "FreeBSD Upgrade", || {
|
runner.execute(Step::System, "FreeBSD Upgrade", || {
|
||||||
freebsd::upgrade_freebsd(sudo.as_ref(), run_type)
|
freebsd::upgrade_freebsd(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(target_os = "openbsd")]
|
#[cfg(target_os = "openbsd")]
|
||||||
runner.execute(Step::System, "OpenBSD Upgrade", || {
|
runner.execute(Step::System, "OpenBSD Upgrade", || {
|
||||||
openbsd::upgrade_openbsd(sudo.as_ref(), run_type)
|
openbsd::upgrade_openbsd(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@@ -457,10 +459,10 @@ fn run() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
freebsd::audit_packages(&sudo).ok();
|
freebsd::audit_packages(ctx.sudo().as_ref()).ok();
|
||||||
|
|
||||||
#[cfg(target_os = "dragonfly")]
|
#[cfg(target_os = "dragonfly")]
|
||||||
dragonfly::audit_packages(&sudo).ok();
|
dragonfly::audit_packages(ctx.sudo().as_ref()).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut post_command_failed = false;
|
let mut post_command_failed = false;
|
||||||
|
|||||||
@@ -202,7 +202,6 @@ pub fn run_juliaup(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
run_type.execute(&juliaup).arg("update").status_checked()
|
run_type.execute(&juliaup).arg("update").status_checked()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_choosenim(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_choosenim(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use std::os::unix::fs::MetadataExt;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use crate::sudo;
|
|
||||||
use crate::utils::require_option;
|
use crate::utils::require_option;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
@@ -13,9 +12,7 @@ use semver::Version;
|
|||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::executor::RunType;
|
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::sudo;
|
|
||||||
use crate::utils::{require, PathExt};
|
use crate::utils::{require, PathExt};
|
||||||
use crate::{error::SkipStep, execution_context::ExecutionContext};
|
use crate::{error::SkipStep, execution_context::ExecutionContext};
|
||||||
|
|
||||||
@@ -91,14 +88,17 @@ impl NPM {
|
|||||||
Version::parse(&version_str?).map_err(|err| err.into())
|
Version::parse(&version_str?).map_err(|err| err.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
|
||||||
let args = ["update", self.global_location_arg()];
|
let args = ["update", self.global_location_arg()];
|
||||||
if use_sudo {
|
if use_sudo {
|
||||||
let sudo_option = sudo::path();
|
let sudo = require_option(ctx.sudo().clone(), String::from("sudo is not installed"))?;
|
||||||
let sudo = require_option(sudo_option, String::from("sudo is not installed"))?;
|
ctx.run_type()
|
||||||
run_type.execute(sudo).arg(&self.command).args(args).status_checked()?;
|
.execute(sudo)
|
||||||
|
.arg(&self.command)
|
||||||
|
.args(args)
|
||||||
|
.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
run_type.execute(&self.command).args(args).status_checked()?;
|
ctx.run_type().execute(&self.command).args(args).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -151,17 +151,18 @@ impl Yarn {
|
|||||||
.map(|s| PathBuf::from(s.stdout.trim()))
|
.map(|s| PathBuf::from(s.stdout.trim()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
|
||||||
let args = ["global", "upgrade"];
|
let args = ["global", "upgrade"];
|
||||||
|
|
||||||
if use_sudo {
|
if use_sudo {
|
||||||
run_type
|
let sudo = require_option(ctx.sudo().clone(), String::from("sudo is not installed"))?;
|
||||||
.execute("sudo")
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
.arg(self.yarn.as_ref().unwrap_or(&self.command))
|
.arg(self.yarn.as_ref().unwrap_or(&self.command))
|
||||||
.args(args)
|
.args(args)
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
run_type.execute(&self.command).args(args).status_checked()?;
|
ctx.run_type().execute(&self.command).args(args).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -216,12 +217,12 @@ pub fn run_npm_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
npm.upgrade(ctx.run_type(), should_use_sudo(&npm, ctx)?)
|
npm.upgrade(ctx, should_use_sudo(&npm, ctx)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
npm.upgrade(ctx.run_type(), false)
|
npm.upgrade(ctx, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,12 +233,12 @@ pub fn run_pnpm_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
pnpm.upgrade(ctx.run_type(), should_use_sudo(&pnpm, ctx)?)
|
pnpm.upgrade(ctx, should_use_sudo(&pnpm, ctx)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
pnpm.upgrade(ctx.run_type(), false)
|
pnpm.upgrade(ctx, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,12 +254,12 @@ pub fn run_yarn_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
yarn.upgrade(ctx.run_type(), should_use_sudo_yarn(&yarn, ctx)?)
|
yarn.upgrade(ctx, should_use_sudo_yarn(&yarn, ctx)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
yarn.upgrade(ctx.run_type(), false)
|
yarn.upgrade(ctx, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use walkdir::WalkDir;
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::error::TopgradeError;
|
use crate::error::TopgradeError;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::utils::which;
|
use crate::utils::which;
|
||||||
use crate::{config, Step};
|
use crate::{config, Step};
|
||||||
|
|
||||||
@@ -110,7 +111,7 @@ impl Trizen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Pacman {
|
pub struct Pacman {
|
||||||
sudo: PathBuf,
|
sudo: Sudo,
|
||||||
executable: PathBuf,
|
executable: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +230,7 @@ impl ArchPackageManager for Pamac {
|
|||||||
|
|
||||||
pub struct Aura {
|
pub struct Aura {
|
||||||
executable: PathBuf,
|
executable: PathBuf,
|
||||||
sudo: PathBuf,
|
sudo: Sudo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Aura {
|
impl Aura {
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::executor::RunType;
|
use crate::executor::RunType;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::require_option;
|
use crate::utils::require_option;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn upgrade_packages(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
||||||
print_separator("DragonFly BSD Packages");
|
print_separator("DragonFly BSD Packages");
|
||||||
run_type
|
run_type
|
||||||
@@ -15,7 +16,7 @@ pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()>
|
|||||||
.status_checked()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<()> {
|
pub fn audit_packages(sudo: Option<&Sudo>) -> Result<()> {
|
||||||
if let Some(sudo) = sudo {
|
if let Some(sudo) = sudo {
|
||||||
println!();
|
println!();
|
||||||
Command::new(sudo)
|
Command::new(sudo)
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::RunType;
|
use crate::executor::RunType;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::require_option;
|
use crate::utils::require_option;
|
||||||
use crate::Step;
|
use crate::Step;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
pub fn upgrade_freebsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn upgrade_freebsd(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
||||||
print_separator("FreeBSD Update");
|
print_separator("FreeBSD Update");
|
||||||
run_type
|
run_type
|
||||||
@@ -17,7 +17,7 @@ pub fn upgrade_freebsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()>
|
|||||||
.status_checked()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upgrade_packages(ctx: &ExecutionContext, sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn upgrade_packages(ctx: &ExecutionContext, sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
||||||
print_separator("FreeBSD Packages");
|
print_separator("FreeBSD Packages");
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ pub fn upgrade_packages(ctx: &ExecutionContext, sudo: Option<&PathBuf>, run_type
|
|||||||
command.status_checked()
|
command.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<()> {
|
pub fn audit_packages(sudo: Option<&Sudo>) -> Result<()> {
|
||||||
if let Some(sudo) = sudo {
|
if let Some(sudo) = sudo {
|
||||||
println!();
|
println!();
|
||||||
Command::new(sudo)
|
Command::new(sudo)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use crate::error::{SkipStep, TopgradeError};
|
|||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::RunType;
|
use crate::executor::RunType;
|
||||||
use crate::steps::os::archlinux;
|
use crate::steps::os::archlinux;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::terminal::{print_separator, print_warning};
|
use crate::terminal::{print_separator, print_warning};
|
||||||
use crate::utils::{require, require_option, which, PathExt};
|
use crate::utils::{require, require_option, which, PathExt};
|
||||||
use crate::Step;
|
use crate::Step;
|
||||||
@@ -498,7 +499,7 @@ fn upgrade_neon(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_needrestart(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn run_needrestart(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
||||||
let needrestart = require("needrestart")?;
|
let needrestart = require("needrestart")?;
|
||||||
let distribution = Distribution::detect()?;
|
let distribution = Distribution::detect()?;
|
||||||
@@ -603,7 +604,7 @@ pub fn flatpak_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_snap(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn run_snap(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
||||||
let snap = require("snap")?;
|
let snap = require("snap")?;
|
||||||
|
|
||||||
@@ -615,7 +616,7 @@ pub fn run_snap(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
|||||||
run_type.execute(sudo).arg(snap).arg("refresh").status_checked()
|
run_type.execute(sudo).arg(snap).arg("refresh").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pihole_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn run_pihole_update(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
||||||
let pihole = require("pihole")?;
|
let pihole = require("pihole")?;
|
||||||
Path::new("/opt/pihole/update.sh").require()?;
|
Path::new("/opt/pihole/update.sh").require()?;
|
||||||
|
|||||||
@@ -19,17 +19,16 @@ pub fn run_chocolatey(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Chocolatey");
|
print_separator("Chocolatey");
|
||||||
|
|
||||||
let mut cmd = &choco;
|
let mut command = match ctx.sudo() {
|
||||||
let mut args = vec!["upgrade", "all"];
|
Some(sudo) => {
|
||||||
|
let mut command = ctx.run_type().execute(sudo);
|
||||||
|
command.arg(choco);
|
||||||
|
command
|
||||||
|
}
|
||||||
|
None => ctx.run_type().execute(choco),
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(sudo) = ctx.sudo() {
|
command.args(["upgrade", "all"]);
|
||||||
cmd = sudo;
|
|
||||||
args.insert(0, "choco");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(cmd);
|
|
||||||
|
|
||||||
command.args(&args);
|
|
||||||
|
|
||||||
if yes {
|
if yes {
|
||||||
command.arg("--yes");
|
command.arg("--yes");
|
||||||
|
|||||||
112
src/sudo.rs
112
src/sudo.rs
@@ -1,3 +1,5 @@
|
|||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
@@ -5,30 +7,102 @@ use color_eyre::eyre::Result;
|
|||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::executor::Executor;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::which;
|
use crate::utils::which;
|
||||||
|
|
||||||
/// Get the path of the `sudo` utility.
|
#[derive(Clone, Debug)]
|
||||||
///
|
pub struct Sudo {
|
||||||
/// Detects `doas`, `sudo`, `gsudo`, or `pkexec`.
|
/// The path to the `sudo` binary.
|
||||||
pub fn path() -> Option<PathBuf> {
|
path: PathBuf,
|
||||||
which("doas")
|
/// The type of program being used as `sudo`.
|
||||||
.or_else(|| which("sudo"))
|
kind: SudoKind,
|
||||||
.or_else(|| which("gsudo"))
|
|
||||||
.or_else(|| which("pkexec"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Elevate permissions with `sudo`.
|
impl Sudo {
|
||||||
pub fn elevate(ctx: &ExecutionContext, sudo: Option<&PathBuf>) -> Result<()> {
|
/// Get the `sudo` binary for this platform.
|
||||||
if let Some(sudo) = sudo {
|
pub fn detect() -> Option<Self> {
|
||||||
print_separator("Sudo");
|
which("doas")
|
||||||
ctx.run_type()
|
.map(|p| (p, SudoKind::Doas))
|
||||||
.execute(sudo)
|
.or_else(|| which("sudo").map(|p| (p, SudoKind::Sudo)))
|
||||||
// TODO: Does this work with `doas`, `pkexec`, `gsudo`, GNU `sudo`...?
|
.or_else(|| which("gsudo").map(|p| (p, SudoKind::Gsudo)))
|
||||||
.arg("-v")
|
.or_else(|| which("pkexec").map(|p| (p, SudoKind::Pkexec)))
|
||||||
.status_checked()
|
.map(|(path, kind)| Self { path, kind })
|
||||||
.wrap_err("Failed to elevate permissions")?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
/// Elevate permissions with `sudo`.
|
||||||
|
///
|
||||||
|
/// This helps prevent blocking `sudo` prompts from stopping the run in the middle of a
|
||||||
|
/// step.
|
||||||
|
///
|
||||||
|
/// See: https://github.com/topgrade-rs/topgrade/issues/205
|
||||||
|
pub fn elevate(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
print_separator("Sudo");
|
||||||
|
let mut cmd = ctx.run_type().execute(self);
|
||||||
|
match self.kind {
|
||||||
|
SudoKind::Doas => {
|
||||||
|
// `doas` doesn't have anything like `sudo -v` to cache credentials,
|
||||||
|
// so we just execute a dummy `echo` command so we have something
|
||||||
|
// unobtrusive to run.
|
||||||
|
// See: https://man.openbsd.org/doas
|
||||||
|
cmd.arg("echo");
|
||||||
|
}
|
||||||
|
SudoKind::Sudo => {
|
||||||
|
// From `man sudo` on macOS:
|
||||||
|
// -v, --validate
|
||||||
|
// Update the user's cached credentials, authenticating the user
|
||||||
|
// if necessary. For the sudoers plugin, this extends the sudo
|
||||||
|
// timeout for another 5 minutes by default, but does not run a
|
||||||
|
// command. Not all security policies support cached credentials.
|
||||||
|
cmd.arg("-v");
|
||||||
|
}
|
||||||
|
SudoKind::Gsudo => {
|
||||||
|
// Shows current user, cache and console status.
|
||||||
|
// See: https://gerardog.github.io/gsudo/docs/usage
|
||||||
|
cmd.arg("status");
|
||||||
|
}
|
||||||
|
SudoKind::Pkexec => {
|
||||||
|
// I don't think this does anything; `pkexec` usually asks for
|
||||||
|
// authentication every time, although it can be configured
|
||||||
|
// differently.
|
||||||
|
//
|
||||||
|
// See the note for `doas` above.
|
||||||
|
//
|
||||||
|
// See: https://linux.die.net/man/1/pkexec
|
||||||
|
cmd.arg("echo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.status_checked().wrap_err("Failed to elevate permissions")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute a command with `sudo`.
|
||||||
|
pub fn execute_elevated(&self, ctx: &ExecutionContext, command: &Path, interactive: bool) -> Executor {
|
||||||
|
let mut cmd = ctx.run_type().execute(self);
|
||||||
|
|
||||||
|
if let SudoKind::Sudo = self.kind {
|
||||||
|
cmd.arg("--preserve-env=DIFFPROG");
|
||||||
|
}
|
||||||
|
|
||||||
|
if interactive {
|
||||||
|
cmd.arg("-i");
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.arg(command);
|
||||||
|
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum SudoKind {
|
||||||
|
Doas,
|
||||||
|
Sudo,
|
||||||
|
Gsudo,
|
||||||
|
Pkexec,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<OsStr> for Sudo {
|
||||||
|
fn as_ref(&self) -> &OsStr {
|
||||||
|
self.path.as_ref()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user