first commit
This commit is contained in:
commit
2eb8aac027
91 files changed
+20139
No files matched your search
@@ -0,0 +1,51 @@
|
||||
use std::{collections::HashMap, process::Stdio, time::Duration};
|
||||
|
||||
use tokio::{io::AsyncWriteExt, process::Command, time::timeout};
|
||||
|
||||
use crate::error::{AppError, AppResult};
|
||||
|
||||
pub async fn run(command: &[String], vars: &[(&str, &str)], stdin: Option<&[u8]>) -> AppResult<()> {
|
||||
if command.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let vars: HashMap<&str, &str> = vars.iter().copied().collect();
|
||||
let expand = |value: &str| {
|
||||
let mut out = value.to_string();
|
||||
for (key, replacement) in &vars {
|
||||
out = out.replace(&format!("{{{key}}}"), replacement);
|
||||
}
|
||||
out
|
||||
};
|
||||
let program = expand(&command[0]);
|
||||
if program.is_empty() {
|
||||
return Err(AppError::config("hook program cannot be empty"));
|
||||
}
|
||||
let mut cmd = Command::new(program);
|
||||
for arg in command.iter().skip(1) {
|
||||
cmd.arg(expand(arg));
|
||||
}
|
||||
cmd.kill_on_drop(true)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped());
|
||||
if stdin.is_some() {
|
||||
cmd.stdin(Stdio::piped());
|
||||
} else {
|
||||
cmd.stdin(Stdio::null());
|
||||
}
|
||||
let mut child = cmd.spawn()?;
|
||||
if let (Some(data), Some(mut pipe)) = (stdin, child.stdin.take()) {
|
||||
pipe.write_all(data).await?;
|
||||
}
|
||||
let output = timeout(Duration::from_secs(30), child.wait_with_output())
|
||||
.await
|
||||
.map_err(|_| AppError::config("hook timed out after 30 seconds"))??;
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
return Err(AppError::config(format!(
|
||||
"hook failed with {}: {}",
|
||||
output.status,
|
||||
stderr.trim()
|
||||
)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in new issue
Block a user