diff options
Diffstat (limited to 'crates/asist-core/src/tools.rs')
| -rw-r--r-- | crates/asist-core/src/tools.rs | 48 |
1 files changed, 14 insertions, 34 deletions
diff --git a/crates/asist-core/src/tools.rs b/crates/asist-core/src/tools.rs index ac08141..3911985 100644 --- a/crates/asist-core/src/tools.rs +++ b/crates/asist-core/src/tools.rs @@ -177,7 +177,8 @@ impl ToolRegistry { pub mod builtin { use super::*; - use std::process::{Command, Stdio}; + use std::path::Path; + use std::process::Command; /// Fecha y hora locales. Existe porque el modelo no las sabe y las inventa /// con aplomo, y de paso sirve de ejemplo mínimo de herramienta. @@ -361,40 +362,14 @@ pub mod builtin { // Sin shell de por medio: los argumentos van al `execve` tal cual, // así que un «; rm -rf /» es un argumento literal, no otra orden. - let mut command = Command::new(program); - command - .args(&arguments) - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - if !self.working_dir.is_empty() { - command.current_dir(&self.working_dir); - } - - let mut child = command.spawn().map_err(|e| fail(e.to_string()))?; - let deadline = std::time::Instant::now() + self.timeout; - loop { - match child.try_wait().map_err(|e| fail(e.to_string()))? { - Some(_) => break, - None if std::time::Instant::now() >= deadline => { - let _ = child.kill(); - let _ = child.wait(); - return Err(fail(format!( - "«{}» superó el plazo de {} s y se detuvo", - rendered.trim(), - self.timeout.as_secs() - ))); - } - None => std::thread::sleep(Duration::from_millis(20)), - } - } + let working_dir = (!self.working_dir.is_empty()).then(|| Path::new(&self.working_dir)); + let output = crate::proc::run(program, &arguments, self.timeout, working_dir) + .map_err(|e| fail(e.to_string()))?; - let output = child.wait_with_output().map_err(|e| fail(e.to_string()))?; let stdout = String::from_utf8_lossy(&output.stdout); - let stderr = String::from_utf8_lossy(&output.stderr); let mut body = stdout.trim().to_string(); if body.is_empty() { - body = stderr.trim().to_string(); + body = output.stderr.trim().to_string(); } // La salida se va a leer en voz alta: pasado cierto punto sólo // sirve para aburrir a quien escucha. @@ -402,10 +377,10 @@ pub mod builtin { if body.chars().count() > MAX { body = body.chars().take(MAX).collect::<String>() + "… (salida recortada)"; } - if !output.status.success() { + if !output.success() { return Ok(format!( "la orden terminó con código {}: {body}", - output.status.code().unwrap_or(-1) + output.status.unwrap_or(-1) )); } Ok(if body.is_empty() { @@ -520,7 +495,12 @@ mod tests { let err = shell .call(&json!({ "programa": "sleep", "argumentos": ["30"] })) .unwrap_err(); - assert!(err.to_string().contains("plazo"), "{err}"); + let err = err.to_string(); + assert!(err.contains("tardó más de"), "{err}"); + assert!( + err.contains("sleep"), + "el error debe decir qué orden se colgó: {err}" + ); } #[test] |