175 lines
4.2 KiB
Rust
175 lines
4.2 KiB
Rust
use anyhow::{Context, Result};
|
|
use serde::Deserialize;
|
|
use std::io::Write;
|
|
use std::{collections::HashMap, path::Path};
|
|
use tracing::{debug, error, trace, warn};
|
|
|
|
use crate::manifest::types::PickConfig;
|
|
|
|
use super::{PickTool, TaskContext};
|
|
|
|
#[derive(Debug, Deserialize, Clone)]
|
|
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) => {
|
|
debug!("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) => {
|
|
debug!("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(());
|
|
}
|
|
}
|