use crate::errors::*;
use console::Emoji;
use indicatif::{ProgressBar, ProgressStyle};
use std::io::Write;
use std::path::Path;
use std::process::{Command, Stdio};
pub static SUCCESS: Emoji<'_, '_> = Emoji("✅", "success!");
pub static FAILURE: Emoji<'_, '_> = Emoji("❌", "failed!");
pub fn run_cmd(
cmd: String,
dir: &Path,
envs: Vec<(&str, &str)>,
pre_dump: impl Fn(),
) -> Result<(String, String, i32), ExecutionError> {
#[cfg(unix)]
let shell_exec = "sh";
#[cfg(windows)]
let shell_exec = "powershell";
#[cfg(unix)]
let shell_param = "-c";
#[cfg(windows)]
let shell_param = "-command";
let output = Command::new(shell_exec)
.args([shell_param, &cmd])
.envs(envs)
.current_dir(dir)
.output()
.map_err(|err| ExecutionError::CmdExecFailed { cmd, source: err })?;
let exit_code = match output.status.code() {
Some(exit_code) => exit_code, None if output.status.success() => 0,
None => 1,
};
if !output.stderr.is_empty() && exit_code != 0 {
pre_dump();
std::io::stderr().write_all(&output.stdout).unwrap();
std::io::stderr().write_all(&output.stderr).unwrap();
}
Ok((
String::from_utf8_lossy(&output.stdout).to_string(),
String::from_utf8_lossy(&output.stderr).to_string(),
exit_code,
))
}
pub fn cfg_spinner(spinner: ProgressBar, message: &str) -> ProgressBar {
spinner.set_style(ProgressStyle::default_spinner().tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ "));
spinner.set_message(format!("{}...", &message));
spinner.enable_steady_tick(50);
spinner
}
pub fn succeed_spinner(spinner: &ProgressBar, message: &str) {
spinner.finish_with_message(format!("{}...{}", message, SUCCESS));
}
pub fn fail_spinner(spinner: &ProgressBar, message: &str) {
spinner.finish_with_message(format!("{}...{}", message, FAILURE));
}
pub fn run_stage(
cmds: Vec<&str>,
target: &Path,
spinner: &ProgressBar,
message: &str,
envs: Vec<(&str, &str)>,
) -> Result<(String, String, i32), ExecutionError> {
let mut last_output = (String::new(), String::new());
for cmd in cmds {
let (stdout, stderr, exit_code) = run_cmd(cmd.to_string(), target, envs.to_vec(), || {
fail_spinner(spinner, message);
})?;
last_output = (stdout, stderr);
if exit_code != 0 {
return Ok((last_output.0, last_output.1, 1));
}
}
succeed_spinner(spinner, message);
Ok((last_output.0, last_output.1, 0))
}
pub fn run_cmd_directly(
cmd: String,
dir: &Path,
envs: Vec<(&str, &str)>,
) -> Result<i32, ExecutionError> {
#[cfg(unix)]
let shell_exec = "sh";
#[cfg(windows)]
let shell_exec = "powershell";
#[cfg(unix)]
let shell_param = "-c";
#[cfg(windows)]
let shell_param = "-command";
let output = Command::new(shell_exec)
.args([shell_param, &cmd])
.current_dir(dir)
.envs(envs)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()
.map_err(|err| ExecutionError::CmdExecFailed { cmd, source: err })?;
let exit_code = match output.status.code() {
Some(exit_code) => exit_code, None if output.status.success() => 0,
None => 1,
};
Ok(exit_code)
}