use std::process::Command as StdCommand;
use std::result::Result as StdResult;
use log::trace;
use minijinja::{Error as MinijinjaError, ErrorKind as MinijinjaErrorKind, Value};
pub fn function(command: String) -> StdResult<Value, MinijinjaError> {
trace!("pipe lookup - executing command: '{command}'");
let output = StdCommand::new("/bin/sh")
.arg("-c")
.arg(&command)
.output()
.map_err(|e| {
MinijinjaError::new(
MinijinjaErrorKind::InvalidOperation,
format!("Failed to execute command '{command}': {e}"),
)
})?;
trace!("pipe lookup - command output: {output:?}");
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(MinijinjaError::new(
MinijinjaErrorKind::InvalidOperation,
format!(
"Command '{}' failed with exit code {:?}: {}",
command,
output.status.code(),
stderr
),
));
}
let stdout = String::from_utf8_lossy(&output.stdout);
let result = stdout.trim_end().to_string();
trace!("pipe lookup - returning: '{result}'");
Ok(Value::from(result))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pipe_simple_command() {
let result = function("echo 'hello world'".to_string());
assert!(result.is_ok());
let value = result.unwrap();
assert_eq!(value.as_str().unwrap(), "hello world");
}
#[test]
fn test_pipe_command_with_newlines() {
let result = function("printf 'line1\\nline2\\n'".to_string());
assert!(result.is_ok());
let value = result.unwrap();
assert_eq!(value.as_str().unwrap(), "line1\nline2");
}
#[test]
fn test_pipe_pwd() {
let result = function("pwd".to_string());
assert!(result.is_ok());
let value = result.unwrap();
assert!(value.as_str().unwrap().starts_with('/'));
}
#[test]
fn test_pipe_failed_command() {
let result = function("exit 1".to_string());
assert!(result.is_err());
let error = result.unwrap_err();
assert!(error.to_string().contains("failed with exit code"));
}
#[test]
fn test_pipe_nonexistent_command() {
let result = function("nonexistent_command_12345".to_string());
assert!(result.is_err());
let error = result.unwrap_err();
assert!(error.to_string().contains("failed with exit code"));
}
#[test]
fn test_pipe_empty_output() {
let result = function("true".to_string());
assert!(result.is_ok());
let value = result.unwrap();
assert_eq!(value.as_str().unwrap(), "");
}
}