Bash tool
This commit is contained in:
174
src/tool/bash.rs
Normal file
174
src/tool/bash.rs
Normal file
@ -0,0 +1,174 @@
|
||||
use anyhow::{Context, Result};
|
||||
use serde::Deserialize;
|
||||
use std::io::Write;
|
||||
use std::{collections::HashMap, path::Path};
|
||||
use tracing::{error, trace, warn};
|
||||
|
||||
use crate::manifest::PickConfig;
|
||||
|
||||
use super::{PickTool, TaskContext};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ToolBash {
|
||||
#[serde(default)]
|
||||
pub before: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub after: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub env: HashMap<String, String>,
|
||||
|
||||
#[serde(default)]
|
||||
pub script: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl PickTool for ToolBash {
|
||||
fn before(&self, manifest_path: &Path, cfg: &PickConfig) -> Result<()> {
|
||||
let script = match &self.before {
|
||||
None => {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Some(script) => {
|
||||
trace!("Running `before` script");
|
||||
let mut temp_file =
|
||||
tempfile::NamedTempFile::new().context("while creating temporary script")?;
|
||||
writeln!(temp_file, "{}", script).context("while creating temporary script")?;
|
||||
temp_file
|
||||
}
|
||||
};
|
||||
|
||||
let mut cmd = std::process::Command::new("bash");
|
||||
cmd.arg(script.path());
|
||||
cmd.current_dir(&cfg.work_dir(manifest_path)?);
|
||||
|
||||
for (key, value) in &self.env {
|
||||
cmd.env(key, value);
|
||||
}
|
||||
|
||||
let output = match cmd.output() {
|
||||
Ok(output) => output,
|
||||
Err(error) => {
|
||||
error!("Failed to execute `before` script: {error}");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
error!(
|
||||
"`before` script failed with status {}: {stderr}",
|
||||
output.status.code().unwrap_or(-1)
|
||||
);
|
||||
} else {
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
#[expect(clippy::print_stdout)]
|
||||
if !stdout.is_empty() {
|
||||
println!("{}", stdout.trim());
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn after(&self, manifest_path: &Path, cfg: &PickConfig) -> Result<()> {
|
||||
let script = match &self.after {
|
||||
None => {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Some(script) => {
|
||||
trace!("Running `after` script");
|
||||
let mut temp_file =
|
||||
tempfile::NamedTempFile::new().context("while creating temporary script")?;
|
||||
writeln!(temp_file, "{}", script).context("while creating temporary script")?;
|
||||
temp_file
|
||||
}
|
||||
};
|
||||
|
||||
let mut cmd = std::process::Command::new("bash");
|
||||
cmd.arg(script.path());
|
||||
cmd.current_dir(&cfg.work_dir(manifest_path)?);
|
||||
|
||||
for (key, value) in &self.env {
|
||||
cmd.env(key, value);
|
||||
}
|
||||
|
||||
let output = match cmd.output() {
|
||||
Ok(output) => output,
|
||||
Err(error) => {
|
||||
error!("Failed to execute `after` script: {error}");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
error!(
|
||||
"`after` script failed with status {}: {stderr}",
|
||||
output.status.code().unwrap_or(-1)
|
||||
);
|
||||
} else {
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
#[expect(clippy::print_stdout)]
|
||||
if !stdout.is_empty() {
|
||||
println!("{}", stdout.trim());
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn run(&self, manifest_path: &Path, cfg: &PickConfig, ctx: TaskContext) -> Result<()> {
|
||||
let script = match self.script.get(&ctx.task) {
|
||||
None => {
|
||||
warn!("No script named \"{}\"", ctx.task);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
Some(script) => {
|
||||
trace!("Running script for {}: {}", ctx.path_rel_str, ctx.task);
|
||||
let mut temp_file =
|
||||
tempfile::NamedTempFile::new().context("while creating temporary script")?;
|
||||
writeln!(temp_file, "{}", script).context("while creating temporary script")?;
|
||||
temp_file
|
||||
}
|
||||
};
|
||||
|
||||
let mut cmd = std::process::Command::new("bash");
|
||||
cmd.arg(script.path());
|
||||
cmd.current_dir(&cfg.work_dir(manifest_path)?);
|
||||
|
||||
cmd.env("PICK_FILE", &ctx.path_abs_str);
|
||||
cmd.env("PICK_RELATIVE", &ctx.path_rel_str);
|
||||
for (key, value) in &self.env {
|
||||
cmd.env(key, value);
|
||||
}
|
||||
|
||||
let output = match cmd.output() {
|
||||
Ok(output) => output,
|
||||
Err(error) => {
|
||||
error!("Failed to execute script for {}: {error}", ctx.path_rel_str);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
error!(
|
||||
"Script for {} failed with status {}: {stderr}",
|
||||
ctx.path_rel_str,
|
||||
output.status.code().unwrap_or(-1)
|
||||
);
|
||||
} else {
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
#[expect(clippy::print_stdout)]
|
||||
if !stdout.is_empty() {
|
||||
println!("{}", stdout.trim());
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user