Wrap commands with ShellCommand builder
Signed-off-by: Trivernis <trivernis@protonmail.com>i18n
parent
2266b10a7b
commit
b8507025f6
@ -1,105 +1,125 @@
|
|||||||
use crate::error::{AppError, AppResult};
|
use crate::internal::error::{AppError, AppResult};
|
||||||
use crate::internal::uwu_enabled;
|
|
||||||
use crate::uwu;
|
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::io::{BufRead, BufReader};
|
use std::process::{Child, Command, ExitStatus, Stdio};
|
||||||
use std::process::{ChildStderr, ChildStdout, Command, Stdio};
|
|
||||||
|
|
||||||
/// Executes a makepkg command
|
pub struct StringOutput {
|
||||||
#[inline]
|
pub stdout: String,
|
||||||
pub fn makepkg<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(args: I) -> AppResult<String> {
|
pub stderr: String,
|
||||||
run_command("makepkg", args)
|
pub status: ExitStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes a git command
|
/// A wrapper around [std::process::Command] with predefined
|
||||||
#[inline]
|
/// commands used in this project as well as elevated access.
|
||||||
pub fn git<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(args: I) -> AppResult<String> {
|
pub struct ShellCommand {
|
||||||
run_command("git", args)
|
command: String,
|
||||||
|
args: Vec<OsString>,
|
||||||
|
elevated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes a bash command
|
impl ShellCommand {
|
||||||
#[inline]
|
pub fn pacman() -> Self {
|
||||||
pub fn bash<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(args: I) -> AppResult<String> {
|
Self::new("pacman")
|
||||||
run_command("bash", args)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs pacman with sudo
|
pub fn makepkg() -> Self {
|
||||||
pub fn sudo_pacman<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(args: I) -> AppResult<String> {
|
Self::new("makepkg")
|
||||||
let mut pacman_args = args
|
}
|
||||||
.into_iter()
|
|
||||||
.map(|i: S| OsString::from(i.as_ref()))
|
|
||||||
.collect::<Vec<OsString>>();
|
|
||||||
let mut sudo_args = vec![OsString::from("pacman")];
|
|
||||||
sudo_args.append(&mut pacman_args);
|
|
||||||
sudo(sudo_args)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Executes a pacman command
|
pub fn git() -> Self {
|
||||||
#[inline]
|
Self::new("git")
|
||||||
pub fn pacman<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(args: I) -> AppResult<String> {
|
}
|
||||||
run_command("pacman", args)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
pub fn bash() -> Self {
|
||||||
pub fn sudo<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(args: I) -> AppResult<String> {
|
Self::new("bash")
|
||||||
run_command("sudo", args)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs a command and parses its output as string
|
fn new<S: ToString>(command: S) -> Self {
|
||||||
fn run_command<S1: AsRef<OsStr>, I: IntoIterator<Item = S2>, S2: AsRef<OsStr>>(
|
Self {
|
||||||
command: S1,
|
command: command.to_string(),
|
||||||
args: I,
|
args: Vec::new(),
|
||||||
) -> AppResult<String> {
|
elevated: false,
|
||||||
let mut child = Command::new(command)
|
}
|
||||||
.args(args)
|
|
||||||
.stdout(Stdio::piped())
|
|
||||||
.stderr(Stdio::piped())
|
|
||||||
.spawn()?;
|
|
||||||
let stdout = child.stdout.as_mut().unwrap();
|
|
||||||
let stderr = child.stderr.as_mut().unwrap();
|
|
||||||
let stdout_str = read_stdout(stdout)?;
|
|
||||||
let stderr_str = read_stderr(stderr)?;
|
|
||||||
|
|
||||||
let status = child.wait()?;
|
|
||||||
if status.success() {
|
|
||||||
Ok(stdout_str)
|
|
||||||
} else {
|
|
||||||
Err(AppError::from(stderr_str))
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn read_stdout(stdout: &mut ChildStdout) -> AppResult<String> {
|
/// Adds one argument
|
||||||
let mut stdout_str = String::new();
|
pub fn arg<S: AsRef<OsStr>>(mut self, arg: S) -> Self {
|
||||||
let stdout_reader = BufReader::new(stdout);
|
self.args.push(arg.as_ref().to_os_string());
|
||||||
|
|
||||||
for line in stdout_reader.lines() {
|
self
|
||||||
let line = line?;
|
|
||||||
if uwu_enabled() {
|
|
||||||
println!("{}", uwu!(&*line))
|
|
||||||
} else {
|
|
||||||
println!("{}", &line);
|
|
||||||
}
|
}
|
||||||
stdout_str.push_str(&line);
|
|
||||||
stdout_str.push_str("\n");
|
/// Adds a list of arguments
|
||||||
|
pub fn args<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(mut self, args: I) -> Self {
|
||||||
|
self.args.append(
|
||||||
|
&mut args
|
||||||
|
.into_iter()
|
||||||
|
.map(|a: S| a.as_ref().to_os_string())
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(stdout_str)
|
/// Runs the command with sudo
|
||||||
}
|
pub fn elevated(mut self) -> Self {
|
||||||
|
self.elevated = true;
|
||||||
|
|
||||||
fn read_stderr(stderr: &mut ChildStderr) -> AppResult<String> {
|
self
|
||||||
let mut stderr_str = String::new();
|
}
|
||||||
let stderr_reader = BufReader::new(stderr);
|
|
||||||
|
|
||||||
for line in stderr_reader.lines() {
|
/// Waits for the child to exit but returns an error when it exists with a non-zero status code
|
||||||
let line = line?;
|
pub fn wait_success(self) -> AppResult<()> {
|
||||||
if uwu_enabled() {
|
let status = self.wait()?;
|
||||||
eprintln!("{}", uwu!(&line))
|
if status.success() {
|
||||||
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
eprintln!("{}", &line);
|
Err(AppError::NonZeroExit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
stderr_str.push_str(&line);
|
|
||||||
stderr_str.push_str("\n");
|
/// Waits for the child to exit and returns the output status
|
||||||
|
pub fn wait(self) -> AppResult<ExitStatus> {
|
||||||
|
let mut child = self.spawn(false)?;
|
||||||
|
|
||||||
|
child.wait().map_err(AppError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(stderr_str)
|
/// Waits with output until the program completed and
|
||||||
|
/// returns the string output object
|
||||||
|
pub fn wait_with_output(self) -> AppResult<StringOutput> {
|
||||||
|
let child = self.spawn(true)?;
|
||||||
|
let output = child.wait_with_output()?;
|
||||||
|
let stdout = String::from_utf8(output.stdout).map_err(|e| AppError::from(e.to_string()))?;
|
||||||
|
let stderr = String::from_utf8(output.stderr).map_err(|e| AppError::from(e.to_string()))?;
|
||||||
|
|
||||||
|
Ok(StringOutput {
|
||||||
|
status: output.status,
|
||||||
|
stdout,
|
||||||
|
stderr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn(self, piped: bool) -> AppResult<Child> {
|
||||||
|
let (stdout, stderr) = if piped {
|
||||||
|
(Stdio::piped(), Stdio::piped())
|
||||||
|
} else {
|
||||||
|
(Stdio::inherit(), Stdio::inherit())
|
||||||
|
};
|
||||||
|
let child = if self.elevated {
|
||||||
|
Command::new("sudo")
|
||||||
|
.arg(self.command)
|
||||||
|
.args(self.args)
|
||||||
|
.stdout(stdout)
|
||||||
|
.stderr(stderr)
|
||||||
|
.spawn()?
|
||||||
|
} else {
|
||||||
|
Command::new(self.command)
|
||||||
|
.args(self.args)
|
||||||
|
.stdout(stdout)
|
||||||
|
.stderr(stderr)
|
||||||
|
.spawn()?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(child)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
pub enum AppExitCode {
|
||||||
|
RunAsRoot = 1,
|
||||||
|
FailedAddingPkg = 2,
|
||||||
|
FailedInitDb = 3,
|
||||||
|
FailedCreatingPaths = 4,
|
||||||
|
MissingDeps = 5,
|
||||||
|
UserCancellation = 6,
|
||||||
|
PacmanError = 7,
|
||||||
|
GitError = 8,
|
||||||
|
MakePkgError = 9,
|
||||||
|
Other = 102,
|
||||||
|
}
|
Loading…
Reference in New Issue