teaql-tool-extra 0.1.1

Heavy-dependency extra utilities for the TeaQL Tool ecosystem.
Documentation
use teaql_tool_core::{Result, TeaQLToolError};
use std::process::Command;
use wait_timeout::ChildExt;
use std::time::Duration;

#[derive(Debug, Clone)]
pub struct CmdTool;

impl CmdTool {
    pub fn new() -> Self { Self }

    pub fn run_with_timeout(&self, cmd_line: &str, timeout_secs: u64) -> Result<(String, String, i32)> {
        let parts: Vec<&str> = cmd_line.split_whitespace().collect();
        if parts.is_empty() {
            return Err(TeaQLToolError::ExecutionError("Empty command".into()));
        }
        
        let mut cmd = Command::new(parts[0]);
        cmd.args(&parts[1..]);
        cmd.stdout(std::process::Stdio::piped());
        cmd.stderr(std::process::Stdio::piped());
        
        let mut child = cmd.spawn().map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
        let timeout = Duration::from_secs(timeout_secs);
        
        match child.wait_timeout(timeout).map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))? {
            Some(status) => {
                let out = child.wait_with_output().map_err(|e| TeaQLToolError::ExecutionError(e.to_string()))?;
                let stdout = String::from_utf8_lossy(&out.stdout).to_string();
                let stderr = String::from_utf8_lossy(&out.stderr).to_string();
                Ok((stdout, stderr, status.code().unwrap_or(-1)))
            }
            None => {
                let _ = child.kill();
                let _ = child.wait();
                Err(TeaQLToolError::ExecutionError("Command timed out".into()))
            }
        }
    }
}

impl Default for CmdTool {
    fn default() -> Self { Self::new() }
}