aboutsummaryrefslogtreecommitdiffstats
path: root/crates/asist-core/src/tools.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/asist-core/src/tools.rs')
-rw-r--r--crates/asist-core/src/tools.rs48
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]