diff --git a/.gitignore b/.gitignore index 4b89477..7e592e2 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ src/target/ .DS_Store *txt +.gitignore diff --git a/Cargo.lock b/Cargo.lock index c3a9af6..4464847 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1204,7 +1204,7 @@ dependencies = [ [[package]] name = "ostiary" -version = "1.1.6" +version = "1.1.7" dependencies = [ "anyhow", "base64", diff --git a/Cargo.toml b/Cargo.toml index 62375da..2a8e8b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ostiary" -version = "1.1.6" +version = "1.1.7" edition = "2024" [dependencies] diff --git a/src/executor/structured.rs b/src/executor/structured.rs index 6f9ef76..7198da1 100644 --- a/src/executor/structured.rs +++ b/src/executor/structured.rs @@ -2,6 +2,7 @@ use crate::error::{AppError, Result}; use serde_json::Value; #[cfg(unix)] use libc; +use std::io::Write; use std::process::Stdio; use tokio::{ io::{AsyncBufReadExt, AsyncWriteExt, BufReader}, @@ -89,13 +90,20 @@ pub fn spawn( UnboundedSender, tokio::sync::oneshot::Sender<()>, // kill signal )> { + let random: u32 = rand::random(); + let script_path = std::env::temp_dir().join(format!("ostiary_{}_{}.sh", std::process::id(), random)); + { + let mut f = std::fs::File::create(&script_path)?; + f.write_all(script.as_bytes())?; + } + let mut child = Command::new("bash") - .arg("-c") - .arg(script) + .arg(&script_path) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) - .spawn()?; + .spawn() + .inspect_err(|_| { let _ = std::fs::remove_file(&script_path); })?; // Capture the PID before moving child into tasks (needed for kill). let pid = child.id(); @@ -159,6 +167,7 @@ pub fn spawn( tokio::spawn(async move { let status = child.wait().await; let code = status.map(|s| s.code().unwrap_or(1)).unwrap_or(1); + let _ = std::fs::remove_file(&script_path); let _ = finished_tx.send(code); }); diff --git a/src/main.rs b/src/main.rs index b790a77..7ef0722 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,6 +29,8 @@ async fn main() -> Result<()> { config::Config::create_with_endpoint(&url, &name)? }; + cleanup_stale_temp_scripts(); + enable_raw_mode()?; let mut stdout = io::stdout(); execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; @@ -168,6 +170,19 @@ async fn run_exec( Ok(()) } +fn cleanup_stale_temp_scripts() { + let tmp = std::env::temp_dir(); + if let Ok(entries) = std::fs::read_dir(&tmp) { + for entry in entries.flatten() { + let name = entry.file_name(); + let name = name.to_string_lossy(); + if name.starts_with("ostiary_") && name.ends_with(".sh") { + let _ = std::fs::remove_file(entry.path()); + } + } + } +} + /// Runs before ratatui starts. Prompts for endpoint URL and name on first launch. fn prompt_first_endpoint() -> Result<(String, String)> { use std::io::{BufRead, BufReader, Write};