diff options
| -rw-r--r-- | src/export_fun.rs (renamed from src/unix.rs) | 68 | ||||
| -rw-r--r-- | src/main.rs | 10 | ||||
| -rw-r--r-- | src/run/mod.rs | 17 |
3 files changed, 71 insertions, 24 deletions
diff --git a/src/unix.rs b/src/export_fun.rs index 967c4fe..934b81c 100644 --- a/src/unix.rs +++ b/src/export_fun.rs @@ -1,25 +1,29 @@ //! allow sub-programs to invoke arbitrary user-defined functions via a unix socket +use crate::Session; +use std::env::current_exe; use std::ffi::OsStr; use std::fs; use std::io; use std::io::Write; use std::os::unix::ffi::OsStrExt; +use std::os::unix::fs::symlink; use std::os::unix::net::SocketAncillary; use std::os::unix::net::UnixListener; use std::os::unix::net::UnixStream; +use std::path::Path; use std::path::PathBuf; use std::process::exit; use std::sync::Arc; use std::sync::Mutex; use std::thread; -use crate::Session; fn handle_server(session: Arc<Mutex<Session>>, stream: UnixStream) -> io::Result<()> { todo!() } fn handle_client(stream: UnixStream) -> io::Result<()> { + println!("uhh hi"); todo!() } @@ -73,20 +77,22 @@ fn unique_string() -> String { hex[..12.min(hex.len())].to_string() } -fn unique_socket_path() -> PathBuf { - let mut socket_name = b"pish-cmd-".to_vec(); - socket_name.extend_from_slice(&unique_string().as_bytes()); - socket_name.extend_from_slice(b".sock"); - let socket_path = crate::basedir::data_dir().join(OsStr::from_bytes(&socket_name)); - socket_path -} - pub struct SocketRunning { + bin_dir: PathBuf, path: PathBuf, } +impl SocketRunning { + pub fn socket_path(&self) -> &Path { + &self.path + } + pub fn path(&self) -> &Path { + &self.bin_dir + } +} + #[must_use] -pub struct SocketDropper { +struct SocketDropper { session: Arc<Mutex<Session>>, } @@ -106,25 +112,33 @@ impl Drop for SocketDropper { } } -pub fn listen(session: Arc<Mutex<Session>>) -> SocketDropper { - let path = unique_socket_path(); +#[must_use] +pub fn listen(session: Arc<Mutex<Session>>) -> impl Drop { + let session_id = unique_string(); + let session_dir = crate::basedir::data_dir().join("session").join(session_id); + let bin_dir = session_dir.join("bin"); + std::fs::create_dir_all(&bin_dir).unwrap(); + let socket_path = session_dir.join("cmd.sock"); { let mut se = session.lock().unwrap(); assert!(se.socket_running.is_none()); - se.socket_running = Some(SocketRunning { path: path.clone() }); + se.socket_running = Some(SocketRunning { + bin_dir, + path: socket_path.clone(), + }); } let se = session.clone(); thread::spawn(move || { - struct SocketRemover(PathBuf); - impl Drop for SocketRemover { + struct SessionRemover(PathBuf); + impl Drop for SessionRemover { fn drop(&mut self) { - let _ = fs::remove_file(&self.0); + let _ = fs::remove_dir_all(&self.0); } } - let _socket_remover = SocketRemover(path.clone()); - let listener = UnixListener::bind(path).unwrap(); + let _session_remover = SessionRemover(session_dir); + let listener = UnixListener::bind(socket_path).unwrap(); let mut it = listener.incoming(); while let Some(stream) = it.next() { match se.lock() { @@ -141,3 +155,21 @@ pub fn listen(session: Arc<Mutex<Session>>) -> SocketDropper { SocketDropper { session } } + +fn create_function_hook_res( + session: Arc<Mutex<Session>>, + fun_name: &[u8], +) -> Result<(), Box<dyn std::error::Error>> { + let session = session.lock().map_err(|e| format!("{e:?}"))?; + let sock_run = session.socket_running.as_ref().ok_or("no socket running")?; + let exe_path = current_exe()?; + let symlink_path = sock_run.bin_dir.join(OsStr::from_bytes(fun_name)); + symlink(exe_path, symlink_path)?; + Ok(()) +} + +pub fn create_function_hook(session: Arc<Mutex<Session>>, fun_name: &[u8]) { + if let Err(e) = create_function_hook_res(session, fun_name) { + println!("failed to create function hook: {e:?}"); + } +} diff --git a/src/main.rs b/src/main.rs index 5d2643f..7196f58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use std::io::{self, IsTerminal, Read, Write}; use std::os::unix::ffi::OsStrExt; use std::os::unix::io::AsRawFd; use std::path::Path; -use std::process::{Command, Stdio, exit}; +use std::process::{Command, Stdio}; use std::sync::{Arc, Mutex}; use std::thread::sleep; use std::time::Duration; @@ -16,6 +16,7 @@ pub mod basedir; pub mod completion; pub mod cursor; pub mod date; +pub mod export_fun; pub mod history; pub mod linebuf; pub mod panic; @@ -23,7 +24,6 @@ pub mod parse; pub mod raw; pub mod reload; pub mod run; -pub mod unix; use linebuf::LineBuf; use raw::*; @@ -70,7 +70,7 @@ pub struct Session { builtins: HashMap<BString, &'static dyn run::Builtin>, vars: HashMap<BString, BString>, funs: HashMap<BString, Ast<PreExpansion>>, - socket_running: Option<unix::SocketRunning>, + socket_running: Option<export_fun::SocketRunning>, /// n before end of history.len() /// 0 == not checking history @@ -272,7 +272,7 @@ fn event_loop() { print!("{}", se.prompt()); let session = Arc::new(Mutex::new(se)); - let _sock_dropper = unix::listen(session.clone()); + let _sock_dropper = export_fun::listen(session.clone()); loop { let mut buf = [0u8; 1]; @@ -489,7 +489,7 @@ fn event_loop() { } fn main() { - unix::maybe_run_defined_function(); + export_fun::maybe_run_defined_function(); if !io::stdin().is_terminal() { println!("need to run in a tty"); return; diff --git a/src/run/mod.rs b/src/run/mod.rs index 8c36f91..da62778 100644 --- a/src/run/mod.rs +++ b/src/run/mod.rs @@ -62,6 +62,15 @@ impl Executor { command.stdout(Stdio::from(stdout)); } + if let Some(sr) = self.se.lock().unwrap().socket_running.as_ref() { + let my_path = std::env::var_os("PATH").expect("no PATH - seriously?"); + let mut new_path = sr.path().as_os_str().as_bytes().to_vec(); + new_path.push(b':'); + new_path.extend_from_slice(my_path.as_bytes()); + command.env("PATH", OsStr::from_bytes(&new_path)); + command.env("PISH_SOCKET", sr.socket_path().as_os_str()); + } + let child = match command.spawn() { Ok(c) => c, Err(e) => { @@ -185,7 +194,13 @@ impl Executor { } fn execute_fun_decl(&mut self, fd: parse::FunDecl<PostExpansion>) -> Result<(), ExecError> { - self.se.lock().unwrap().funs.insert(fd.name, *fd.body.body); + self.se + .lock() + .unwrap() + .funs + .insert(fd.name.clone(), *fd.body.body); + crate::export_fun::create_function_hook(self.se.clone(), &fd.name); + // TODO: very ugly to ad-hoc keep export stuff & session data in sync here Ok(()) } |
