2023-01-25 01:30:47 +00:00
|
|
|
use std::{env, process::Stdio, sync::Weak};
|
2023-01-19 01:47:14 +00:00
|
|
|
|
2023-01-23 02:31:55 +00:00
|
|
|
use mlua::prelude::*;
|
2023-01-20 20:21:20 +00:00
|
|
|
use os_str_bytes::RawOsString;
|
2023-01-25 01:30:47 +00:00
|
|
|
use smol::{channel::Sender, process::Command};
|
2023-01-19 01:47:14 +00:00
|
|
|
|
2023-01-23 23:52:31 +00:00
|
|
|
use crate::{utils::table::TableBuilder, LuneMessage};
|
2023-01-21 20:48:56 +00:00
|
|
|
|
2023-01-23 07:38:32 +00:00
|
|
|
pub fn create(lua: &Lua, args_vec: Vec<String>) -> LuaResult<()> {
|
2023-01-21 20:30:22 +00:00
|
|
|
// Create readonly args array
|
2023-01-23 01:18:09 +00:00
|
|
|
let args_tab = TableBuilder::new(lua)?
|
|
|
|
.with_sequential_values(args_vec)?
|
|
|
|
.build_readonly()?;
|
|
|
|
// Create proxied table for env that gets & sets real env vars
|
|
|
|
let env_tab = TableBuilder::new(lua)?
|
|
|
|
.with_metatable(
|
|
|
|
TableBuilder::new(lua)?
|
2023-01-23 02:31:55 +00:00
|
|
|
.with_function(LuaMetaMethod::Index.name(), process_env_get)?
|
|
|
|
.with_function(LuaMetaMethod::NewIndex.name(), process_env_set)?
|
|
|
|
.with_function(LuaMetaMethod::Iter.name(), process_env_iter)?
|
2023-01-23 01:18:09 +00:00
|
|
|
.build_readonly()?,
|
|
|
|
)?
|
|
|
|
.build_readonly()?;
|
2023-01-21 20:30:22 +00:00
|
|
|
// Create the full process table
|
2023-01-22 20:23:56 +00:00
|
|
|
lua.globals().raw_set(
|
|
|
|
"process",
|
2023-01-23 01:18:09 +00:00
|
|
|
TableBuilder::new(lua)?
|
|
|
|
.with_value("args", args_tab)?
|
|
|
|
.with_value("env", env_tab)?
|
2023-01-23 18:51:32 +00:00
|
|
|
.with_async_function("exit", process_exit)?
|
2023-01-22 20:23:56 +00:00
|
|
|
.with_async_function("spawn", process_spawn)?
|
2023-01-23 01:18:09 +00:00
|
|
|
.build_readonly()?,
|
2023-01-22 21:26:45 +00:00
|
|
|
)
|
2023-01-19 01:47:14 +00:00
|
|
|
}
|
|
|
|
|
2023-01-23 02:31:55 +00:00
|
|
|
fn process_env_get<'lua>(
|
|
|
|
lua: &'lua Lua,
|
|
|
|
(_, key): (LuaValue<'lua>, String),
|
|
|
|
) -> LuaResult<LuaValue<'lua>> {
|
2023-01-20 20:21:20 +00:00
|
|
|
match env::var_os(key) {
|
|
|
|
Some(value) => {
|
|
|
|
let raw_value = RawOsString::new(value);
|
2023-01-23 02:31:55 +00:00
|
|
|
Ok(LuaValue::String(
|
|
|
|
lua.create_string(raw_value.as_raw_bytes())?,
|
|
|
|
))
|
2023-01-20 20:21:20 +00:00
|
|
|
}
|
2023-01-23 02:31:55 +00:00
|
|
|
None => Ok(LuaValue::Nil),
|
2023-01-19 01:47:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-23 02:31:55 +00:00
|
|
|
fn process_env_set(_: &Lua, (_, key, value): (LuaValue, String, Option<String>)) -> LuaResult<()> {
|
2023-01-20 20:21:20 +00:00
|
|
|
// Make sure key is valid, otherwise set_var will panic
|
|
|
|
if key.is_empty() {
|
2023-01-23 02:31:55 +00:00
|
|
|
Err(LuaError::RuntimeError("Key must not be empty".to_string()))
|
2023-01-20 20:21:20 +00:00
|
|
|
} else if key.contains('=') {
|
2023-01-23 02:31:55 +00:00
|
|
|
Err(LuaError::RuntimeError(
|
2023-01-20 20:21:20 +00:00
|
|
|
"Key must not contain the equals character '='".to_string(),
|
2023-01-23 02:21:11 +00:00
|
|
|
))
|
2023-01-20 20:21:20 +00:00
|
|
|
} else if key.contains('\0') {
|
2023-01-23 02:31:55 +00:00
|
|
|
Err(LuaError::RuntimeError(
|
2023-01-20 20:21:20 +00:00
|
|
|
"Key must not contain the NUL character".to_string(),
|
2023-01-23 02:21:11 +00:00
|
|
|
))
|
|
|
|
} else {
|
|
|
|
match value {
|
|
|
|
Some(value) => {
|
|
|
|
// Make sure value is valid, otherwise set_var will panic
|
|
|
|
if value.contains('\0') {
|
2023-01-23 02:31:55 +00:00
|
|
|
Err(LuaError::RuntimeError(
|
2023-01-23 02:21:11 +00:00
|
|
|
"Value must not contain the NUL character".to_string(),
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
env::set_var(&key, &value);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
env::remove_var(&key);
|
|
|
|
Ok(())
|
2023-01-21 04:40:31 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-20 20:21:20 +00:00
|
|
|
}
|
2023-01-19 01:47:14 +00:00
|
|
|
}
|
|
|
|
|
2023-01-23 02:31:55 +00:00
|
|
|
fn process_env_iter<'lua>(
|
|
|
|
lua: &'lua Lua,
|
|
|
|
(_, _): (LuaValue<'lua>, ()),
|
|
|
|
) -> LuaResult<LuaFunction<'lua>> {
|
2023-01-20 20:21:20 +00:00
|
|
|
let mut vars = env::vars_os();
|
|
|
|
lua.create_function_mut(move |lua, _: ()| match vars.next() {
|
|
|
|
Some((key, value)) => {
|
|
|
|
let raw_key = RawOsString::new(key);
|
|
|
|
let raw_value = RawOsString::new(value);
|
|
|
|
Ok((
|
2023-01-23 02:31:55 +00:00
|
|
|
LuaValue::String(lua.create_string(raw_key.as_raw_bytes())?),
|
|
|
|
LuaValue::String(lua.create_string(raw_value.as_raw_bytes())?),
|
2023-01-20 20:21:20 +00:00
|
|
|
))
|
|
|
|
}
|
2023-01-23 02:31:55 +00:00
|
|
|
None => Ok((LuaValue::Nil, LuaValue::Nil)),
|
2023-01-20 20:21:20 +00:00
|
|
|
})
|
2023-01-19 01:47:14 +00:00
|
|
|
}
|
|
|
|
|
2023-01-23 18:51:32 +00:00
|
|
|
async fn process_exit(lua: &Lua, exit_code: Option<u8>) -> LuaResult<()> {
|
|
|
|
let sender = lua
|
|
|
|
.app_data_ref::<Weak<Sender<LuneMessage>>>()
|
|
|
|
.unwrap()
|
|
|
|
.upgrade()
|
|
|
|
.unwrap();
|
|
|
|
sender
|
|
|
|
.send(LuneMessage::Exit(exit_code.unwrap_or(0)))
|
|
|
|
.await
|
|
|
|
.map_err(LuaError::external)?;
|
|
|
|
Ok(())
|
2023-01-19 01:47:14 +00:00
|
|
|
}
|
|
|
|
|
2023-01-23 02:31:55 +00:00
|
|
|
async fn process_spawn(
|
|
|
|
lua: &Lua,
|
|
|
|
(program, args): (String, Option<Vec<String>>),
|
|
|
|
) -> LuaResult<LuaTable> {
|
2023-01-25 01:30:47 +00:00
|
|
|
// Create and spawn our child process
|
2023-01-24 20:36:09 +00:00
|
|
|
let pwd = env::current_dir()?;
|
2023-01-25 01:30:47 +00:00
|
|
|
let mut cmd = Command::new(program);
|
|
|
|
if let Some(args) = args {
|
|
|
|
cmd.args(args);
|
|
|
|
}
|
|
|
|
let output = cmd
|
|
|
|
.current_dir(pwd)
|
|
|
|
.stdin(Stdio::null())
|
|
|
|
.stdout(Stdio::piped())
|
|
|
|
.stderr(Stdio::piped())
|
|
|
|
.output()
|
|
|
|
.await?;
|
2023-01-21 02:09:08 +00:00
|
|
|
// NOTE: If an exit code was not given by the child process,
|
|
|
|
// we default to 1 if it yielded any error output, otherwise 0
|
2023-01-19 01:47:14 +00:00
|
|
|
let code = output
|
|
|
|
.status
|
|
|
|
.code()
|
2023-01-21 02:09:08 +00:00
|
|
|
.unwrap_or(match output.stderr.is_empty() {
|
|
|
|
true => 0,
|
|
|
|
false => 1,
|
|
|
|
});
|
2023-01-19 01:47:14 +00:00
|
|
|
// Construct and return a readonly lua table with results
|
2023-01-23 01:18:09 +00:00
|
|
|
TableBuilder::new(lua)?
|
|
|
|
.with_value("ok", code == 0)?
|
|
|
|
.with_value("code", code)?
|
|
|
|
.with_value("stdout", lua.create_string(&output.stdout)?)?
|
|
|
|
.with_value("stderr", lua.create_string(&output.stderr)?)?
|
|
|
|
.build_readonly()
|
2023-01-19 01:47:14 +00:00
|
|
|
}
|