aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/export_fun.rs (renamed from src/unix.rs)68
-rw-r--r--src/main.rs10
-rw-r--r--src/run/mod.rs17
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(())
}