use anyhow::{Context, Result};
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
pub struct ProcessRunner {
working_dir: Option<PathBuf>,
log_dir: Option<PathBuf>,
binary: Option<PathBuf>,
}
impl ProcessRunner {
#[must_use]
pub fn new() -> Self {
Self {
working_dir: None,
log_dir: None,
binary: None,
}
}
#[must_use]
pub fn with_binary<P: AsRef<Path>>(mut self, binary: P) -> Self {
self.binary = Some(binary.as_ref().to_path_buf());
self
}
fn make_command(&self) -> Command {
if let Some(binary) = &self.binary {
Command::new(binary)
} else {
let mut cmd = Command::new("cargo");
cmd.args(["run", "--"]);
cmd
}
}
#[must_use]
pub fn working_dir<P: AsRef<Path>>(mut self, dir: P) -> Self {
self.working_dir = Some(dir.as_ref().to_path_buf());
self
}
#[must_use]
pub fn log_dir<P: AsRef<Path>>(mut self, dir: P) -> Self {
self.log_dir = Some(dir.as_ref().to_path_buf());
self
}
pub fn run_create_command(&self, config_file: &str) -> Result<ProcessResult> {
let mut cmd = self.make_command();
if let Some(working_dir) = &self.working_dir {
let absolute_config = if config_file.starts_with("./") {
working_dir.join(config_file.trim_start_matches("./"))
} else {
working_dir.join(config_file)
};
cmd.args([
"create",
"environment",
"--env-file",
absolute_config.to_str().unwrap(),
"--working-dir",
working_dir.to_str().unwrap(),
]);
} else {
cmd.args(["create", "environment", "--env-file", config_file]);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd.output().context("Failed to execute create command")?;
Ok(ProcessResult::new(output))
}
pub fn run_provision_command(&self, environment_name: &str) -> Result<ProcessResult> {
let mut cmd = self.make_command();
if let Some(working_dir) = &self.working_dir {
cmd.args([
"provision",
environment_name,
"--working-dir",
working_dir.to_str().unwrap(),
]);
} else {
cmd.args(["provision", environment_name]);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd
.output()
.context("Failed to execute provision command")?;
Ok(ProcessResult::new(output))
}
pub fn run_destroy_command(&self, environment_name: &str) -> Result<ProcessResult> {
let mut cmd = self.make_command();
if let Some(working_dir) = &self.working_dir {
cmd.args([
"destroy",
environment_name,
"--working-dir",
working_dir.to_str().unwrap(),
]);
} else {
cmd.args(["destroy", environment_name]);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd.output().context("Failed to execute destroy command")?;
Ok(ProcessResult::new(output))
}
pub fn run_register_command(
&self,
environment_name: &str,
instance_ip: &str,
ssh_port: Option<u16>,
) -> Result<ProcessResult> {
let mut cmd = self.make_command();
cmd.args(["register", environment_name, "--instance-ip", instance_ip]);
if let Some(port) = ssh_port {
cmd.args(["--ssh-port", &port.to_string()]);
}
if let Some(working_dir) = &self.working_dir {
cmd.args(["--working-dir", working_dir.to_str().unwrap()]);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd.output().context("Failed to execute register command")?;
Ok(ProcessResult::new(output))
}
pub fn run_configure_command(&self, environment_name: &str) -> Result<ProcessResult> {
let mut cmd = self.make_command();
if let Some(working_dir) = &self.working_dir {
cmd.args([
"configure",
environment_name,
"--working-dir",
working_dir.to_str().unwrap(),
]);
} else {
cmd.args(["configure", environment_name]);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd
.output()
.context("Failed to execute configure command")?;
Ok(ProcessResult::new(output))
}
pub fn run_test_command(&self, environment_name: &str) -> Result<ProcessResult> {
let mut cmd = self.make_command();
if let Some(working_dir) = &self.working_dir {
cmd.args([
"test",
environment_name,
"--working-dir",
working_dir.to_str().unwrap(),
]);
} else {
cmd.args(["test", environment_name]);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd.output().context("Failed to execute test command")?;
Ok(ProcessResult::new(output))
}
pub fn run_release_command(&self, environment_name: &str) -> Result<ProcessResult> {
let mut cmd = self.make_command();
if let Some(working_dir) = &self.working_dir {
cmd.args([
"release",
environment_name,
"--working-dir",
working_dir.to_str().unwrap(),
]);
} else {
cmd.args(["release", environment_name]);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd.output().context("Failed to execute release command")?;
Ok(ProcessResult::new(output))
}
pub fn run_run_command(&self, environment_name: &str) -> Result<ProcessResult> {
let mut cmd = self.make_command();
if let Some(working_dir) = &self.working_dir {
cmd.args([
"run",
environment_name,
"--working-dir",
working_dir.to_str().unwrap(),
]);
} else {
cmd.args(["run", environment_name]);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd.output().context("Failed to execute run command")?;
Ok(ProcessResult::new(output))
}
pub fn run_list_command(&self) -> Result<ProcessResult> {
let mut cmd = self.make_command();
if let Some(working_dir) = &self.working_dir {
cmd.args(["list", "--working-dir", working_dir.to_str().unwrap()]);
} else {
cmd.arg("list");
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd.output().context("Failed to execute list command")?;
Ok(ProcessResult::new(output))
}
pub fn run_exists_command(&self, environment_name: &str) -> Result<ProcessResult> {
let mut cmd = self.make_command();
if let Some(working_dir) = &self.working_dir {
cmd.args([
"exists",
environment_name,
"--working-dir",
working_dir.to_str().unwrap(),
]);
} else {
cmd.args(["exists", environment_name]);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd.output().context("Failed to execute exists command")?;
Ok(ProcessResult::new(output))
}
pub fn run_show_command(&self, environment_name: &str) -> Result<ProcessResult> {
let mut cmd = self.make_command();
if let Some(working_dir) = &self.working_dir {
cmd.args([
"show",
environment_name,
"--working-dir",
working_dir.to_str().unwrap(),
]);
} else {
cmd.args(["show", environment_name]);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd.output().context("Failed to execute show command")?;
Ok(ProcessResult::new(output))
}
pub fn run_validate_command(&self, config_file: &str) -> Result<ProcessResult> {
let mut cmd = self.make_command();
cmd.args(["validate", "-f", config_file]);
if let Some(working_dir) = &self.working_dir {
cmd.arg("--working-dir");
cmd.arg(working_dir);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd.output().context("Failed to execute validate command")?;
Ok(ProcessResult::new(output))
}
pub fn run_render_command_with_env_name(
&self,
environment_name: &str,
instance_ip: &str,
output_dir: &str,
) -> Result<ProcessResult> {
let mut cmd = self.make_command();
cmd.args([
"render",
"--env-name",
environment_name,
"--instance-ip",
instance_ip,
"--output-dir",
output_dir,
]);
if let Some(working_dir) = &self.working_dir {
cmd.args(["--working-dir", working_dir.to_str().unwrap()]);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd
.output()
.context("Failed to execute render command with env-name")?;
Ok(ProcessResult::new(output))
}
pub fn run_render_command_with_config_file(
&self,
config_file: &str,
instance_ip: &str,
output_dir: &str,
) -> Result<ProcessResult> {
let mut cmd = self.make_command();
cmd.args([
"render",
"--env-file",
config_file,
"--instance-ip",
instance_ip,
"--output-dir",
output_dir,
]);
if let Some(working_dir) = &self.working_dir {
cmd.arg("--working-dir");
cmd.arg(working_dir);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd
.output()
.context("Failed to execute render command with env-file")?;
Ok(ProcessResult::new(output))
}
pub fn run_purge_command(&self, environment_name: &str) -> Result<ProcessResult> {
let mut cmd = self.make_command();
if let Some(working_dir) = &self.working_dir {
cmd.args([
"purge",
environment_name,
"--force",
"--working-dir",
working_dir.to_str().unwrap(),
]);
} else {
cmd.args(["purge", environment_name, "--force"]);
}
if let Some(log_dir) = &self.log_dir {
cmd.arg("--log-dir");
cmd.arg(log_dir);
}
let output = cmd.output().context("Failed to execute purge command")?;
Ok(ProcessResult::new(output))
}
}
impl Default for ProcessRunner {
fn default() -> Self {
Self::new()
}
}
pub struct ProcessResult {
output: Output,
}
impl ProcessResult {
fn new(output: Output) -> Self {
Self { output }
}
#[must_use]
pub fn success(&self) -> bool {
self.output.status.success()
}
#[must_use]
pub fn stdout(&self) -> String {
String::from_utf8_lossy(&self.output.stdout).to_string()
}
#[must_use]
pub fn stderr(&self) -> String {
String::from_utf8_lossy(&self.output.stderr).to_string()
}
#[must_use]
pub fn exit_code(&self) -> Option<i32> {
self.output.status.code()
}
}