refactor(sudo): add SudoExecuteOpts builder functions and preserve_env enum
This commit is contained in:
@@ -127,15 +127,7 @@ pub fn run_rubygems(ctx: &ExecutionContext) -> Result<()> {
|
||||
} else {
|
||||
let sudo = ctx.require_sudo()?;
|
||||
if !Path::new("/usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb").exists() {
|
||||
sudo.execute_opts(
|
||||
ctx,
|
||||
&gem,
|
||||
SudoExecuteOpts {
|
||||
preserve_env: Some(&[]),
|
||||
set_home: true,
|
||||
..Default::default()
|
||||
},
|
||||
)?
|
||||
sudo.execute_opts(ctx, &gem, SudoExecuteOpts::new().preserve_env().set_home())?
|
||||
.args(["update", "--system"])
|
||||
.status_checked()?;
|
||||
}
|
||||
|
||||
@@ -993,14 +993,7 @@ pub fn run_config_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
}
|
||||
|
||||
print_separator(t!("Configuration update"));
|
||||
sudo.execute_opts(
|
||||
ctx,
|
||||
&pacdiff,
|
||||
SudoExecuteOpts {
|
||||
preserve_env: Some(&["DIFFPROG"]),
|
||||
..Default::default()
|
||||
},
|
||||
)?
|
||||
sudo.execute_opts(ctx, &pacdiff, SudoExecuteOpts::new().preserve_env_list(&["DIFFPROG"]))?
|
||||
.status_checked()?;
|
||||
}
|
||||
|
||||
|
||||
@@ -330,15 +330,7 @@ pub fn run_brew_formula(ctx: &ExecutionContext, variant: BrewVariant) -> Result<
|
||||
print_separator(format!("{} ({})", variant.step_title(), sudo_as_user));
|
||||
|
||||
let sudo = ctx.require_sudo()?;
|
||||
sudo.execute_opts(
|
||||
ctx,
|
||||
&binary_name,
|
||||
SudoExecuteOpts {
|
||||
set_home: true,
|
||||
user: Some(&user.name),
|
||||
..Default::default()
|
||||
},
|
||||
)?
|
||||
sudo.execute_opts(ctx, &binary_name, SudoExecuteOpts::new().set_home().user(&user.name))?
|
||||
.current_dir("/tmp") // brew needs a writable current directory
|
||||
.arg("update")
|
||||
.status_checked()?;
|
||||
@@ -557,14 +549,7 @@ pub fn run_nix_self_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
||||
let nix_args = nix_args();
|
||||
if multi_user {
|
||||
let sudo = ctx.require_sudo()?;
|
||||
sudo.execute_opts(
|
||||
ctx,
|
||||
&nix,
|
||||
SudoExecuteOpts {
|
||||
interactive: true,
|
||||
..Default::default()
|
||||
},
|
||||
)?
|
||||
sudo.execute_opts(ctx, &nix, SudoExecuteOpts::new().interactive())?
|
||||
.args(nix_args)
|
||||
.arg("upgrade-nix")
|
||||
.status_checked()
|
||||
|
||||
86
src/sudo.rs
86
src/sudo.rs
@@ -23,20 +23,72 @@ pub struct Sudo {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
/// Generic sudo options, translated into flags to pass to `sudo`. Depending on the sudo kind, OS
|
||||
/// and system config, some options might be specified by default or unsupported.
|
||||
pub enum SudoPreserveEnv<'a> {
|
||||
/// Preserve all environment variables.
|
||||
All,
|
||||
/// Preserve only the specified environment variables.
|
||||
Some(&'a [&'a str]),
|
||||
/// Preserve no environment variables.
|
||||
#[default]
|
||||
None,
|
||||
}
|
||||
|
||||
/// Generic sudo options, translated into flags to pass to `sudo`.
|
||||
/// NOTE: Depending on the sudo kind, OS and system config, some options might be specified by
|
||||
/// default or unsupported.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct SudoExecuteOpts<'a> {
|
||||
/// Run the command "interactively", i.e. inside a login shell.
|
||||
pub interactive: bool,
|
||||
/// Preserve environment variables across the sudo call. If an empty list is given, preserves
|
||||
/// all existing environment variables.
|
||||
pub preserve_env: Option<&'a [&'a str]>,
|
||||
/// Preserve environment variables across the sudo call.
|
||||
pub preserve_env: SudoPreserveEnv<'a>,
|
||||
/// Set the HOME environment variable to the target user's home directory.
|
||||
pub set_home: bool,
|
||||
/// Run the command as a user other than the root user.
|
||||
pub user: Option<&'a str>,
|
||||
}
|
||||
|
||||
impl<'a> SudoExecuteOpts<'a> {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// Run the command "interactively", i.e. inside a login shell.
|
||||
#[allow(unused)]
|
||||
pub fn interactive(mut self) -> Self {
|
||||
self.interactive = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Preserve all environment variables across the sudo call.
|
||||
#[allow(unused)]
|
||||
pub fn preserve_env(mut self) -> Self {
|
||||
self.preserve_env = SudoPreserveEnv::All;
|
||||
self
|
||||
}
|
||||
|
||||
/// Preserve only the specified environment variables across the sudo call.
|
||||
#[allow(unused)]
|
||||
pub fn preserve_env_list(mut self, vars: &'a [&'a str]) -> Self {
|
||||
self.preserve_env = SudoPreserveEnv::Some(vars);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the HOME environment variable to the target user's home directory.
|
||||
#[allow(unused)]
|
||||
pub fn set_home(mut self) -> Self {
|
||||
self.set_home = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Run the command as a user other than the root user.
|
||||
#[allow(unused)]
|
||||
pub fn user(mut self, user: &'a str) -> Self {
|
||||
self.user = Some(user);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
const DETECT_ORDER: [SudoKind; 5] = [
|
||||
SudoKind::Doas,
|
||||
@@ -143,7 +195,7 @@ impl Sudo {
|
||||
|
||||
/// Execute a command with `sudo`.
|
||||
pub fn execute<S: AsRef<OsStr>>(&self, ctx: &ExecutionContext, command: S) -> Result<Executor> {
|
||||
self.execute_opts(ctx, command, SudoExecuteOpts::default())
|
||||
self.execute_opts(ctx, command, SudoExecuteOpts::new())
|
||||
}
|
||||
|
||||
/// Execute a command with `sudo`, with custom options.
|
||||
@@ -182,9 +234,8 @@ impl Sudo {
|
||||
cmd.arg("-d");
|
||||
}
|
||||
|
||||
if let Some(preserve_env) = opts.preserve_env {
|
||||
if preserve_env.is_empty() {
|
||||
match self.kind {
|
||||
match opts.preserve_env {
|
||||
SudoPreserveEnv::All => match self.kind {
|
||||
SudoKind::Sudo => {
|
||||
cmd.arg("-E");
|
||||
}
|
||||
@@ -198,30 +249,29 @@ impl Sudo {
|
||||
}
|
||||
.into());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match self.kind {
|
||||
},
|
||||
SudoPreserveEnv::Some(vars) => match self.kind {
|
||||
SudoKind::Sudo if cfg!(not(target_os = "windows")) => {
|
||||
cmd.arg(format!("--preserve_env={}", preserve_env.join(",")));
|
||||
cmd.arg(format!("--preserve_env={}", vars.join(",")));
|
||||
}
|
||||
SudoKind::Run0 => {
|
||||
for env in preserve_env {
|
||||
for env in vars {
|
||||
cmd.arg(format!("--setenv={}", env));
|
||||
}
|
||||
}
|
||||
SudoKind::Please => {
|
||||
cmd.arg("-a");
|
||||
cmd.arg(preserve_env.join(","));
|
||||
cmd.arg(vars.join(","));
|
||||
}
|
||||
SudoKind::Doas | SudoKind::Sudo | SudoKind::Gsudo | SudoKind::Pkexec => {
|
||||
return Err(UnsupportedSudo {
|
||||
sudo_kind: self.kind,
|
||||
option: "preserve_env list",
|
||||
option: "preserve_env_list",
|
||||
}
|
||||
.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
SudoPreserveEnv::None => {}
|
||||
}
|
||||
|
||||
if opts.set_home {
|
||||
|
||||
Reference in New Issue
Block a user