mirror of
https://github.com/lune-org/lune.git
synced 2025-04-10 21:40:54 +01:00
feat: correct non blocking test for process.create
This commit is contained in:
parent
aa10e88495
commit
bd71b5e4b8
3 changed files with 40 additions and 72 deletions
|
@ -79,7 +79,7 @@ pub fn module(lua: &Lua) -> LuaResult<LuaTable> {
|
||||||
.with_value("env", env_tab)?
|
.with_value("env", env_tab)?
|
||||||
.with_value("exit", process_exit)?
|
.with_value("exit", process_exit)?
|
||||||
.with_async_function("exec", process_exec)?
|
.with_async_function("exec", process_exec)?
|
||||||
.with_async_function("create", process_spawn)?
|
.with_function("create", process_spawn)?
|
||||||
.build_readonly()
|
.build_readonly()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ async fn process_exec(
|
||||||
) -> LuaResult<LuaTable> {
|
) -> LuaResult<LuaTable> {
|
||||||
let res = lua
|
let res = lua
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
let cmd = spawn_command(program, args, options.clone()).await?;
|
let cmd = spawn_command_with_stdin(program, args, options.clone()).await?;
|
||||||
wait_for_child(cmd, options.stdio.stdout, options.stdio.stderr).await
|
wait_for_child(cmd, options.stdio.stdout, options.stdio.stderr).await
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -180,7 +180,7 @@ async fn process_exec(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::await_holding_refcell_ref)]
|
#[allow(clippy::await_holding_refcell_ref)]
|
||||||
async fn process_spawn(
|
fn process_spawn(
|
||||||
lua: &Lua,
|
lua: &Lua,
|
||||||
(program, args, options): (String, Option<Vec<String>>, ProcessSpawnOptions),
|
(program, args, options): (String, Option<Vec<String>>, ProcessSpawnOptions),
|
||||||
) -> LuaResult<LuaTable> {
|
) -> LuaResult<LuaTable> {
|
||||||
|
@ -189,26 +189,15 @@ async fn process_spawn(
|
||||||
let mut spawn_options = options.clone();
|
let mut spawn_options = options.clone();
|
||||||
spawn_options.stdio = ProcessSpawnOptionsStdio::default();
|
spawn_options.stdio = ProcessSpawnOptionsStdio::default();
|
||||||
|
|
||||||
let (stdin_tx, stdin_rx) = tokio::sync::oneshot::channel();
|
|
||||||
let (stdout_tx, stdout_rx) = tokio::sync::oneshot::channel();
|
|
||||||
let (stderr_tx, stderr_rx) = tokio::sync::oneshot::channel();
|
|
||||||
let (code_tx, code_rx) = tokio::sync::broadcast::channel(4);
|
let (code_tx, code_rx) = tokio::sync::broadcast::channel(4);
|
||||||
let code_rx_rc = Rc::new(RefCell::new(code_rx));
|
let code_rx_rc = Rc::new(RefCell::new(code_rx));
|
||||||
|
|
||||||
tokio::spawn(async move {
|
let mut child = spawn_command(program, args, spawn_options)?;
|
||||||
let mut child = spawn_command(program, args, spawn_options)
|
let stdin = child.stdin.take().unwrap();
|
||||||
.await
|
let stdout = child.stdout.take().unwrap();
|
||||||
.expect("Could not spawn child process");
|
let stderr = child.stderr.take().unwrap();
|
||||||
stdin_tx
|
|
||||||
.send(child.stdin.take())
|
|
||||||
.expect("Stdin receiver was unexpectedly dropped");
|
|
||||||
stdout_tx
|
|
||||||
.send(child.stdout.take())
|
|
||||||
.expect("Stdout receiver was unexpectedly dropped");
|
|
||||||
stderr_tx
|
|
||||||
.send(child.stderr.take())
|
|
||||||
.expect("Stderr receiver was unexpectedly dropped");
|
|
||||||
|
|
||||||
|
tokio::spawn(async move {
|
||||||
let res = child
|
let res = child
|
||||||
.wait_with_output()
|
.wait_with_output()
|
||||||
.await
|
.await
|
||||||
|
@ -225,33 +214,9 @@ async fn process_spawn(
|
||||||
});
|
});
|
||||||
|
|
||||||
TableBuilder::new(lua)?
|
TableBuilder::new(lua)?
|
||||||
.with_value(
|
.with_value("stdout", ChildProcessReader(stdout))?
|
||||||
"stdout",
|
.with_value("stderr", ChildProcessReader(stderr))?
|
||||||
ChildProcessReader(
|
.with_value("stdin", ChildProcessWriter(stdin))?
|
||||||
stdout_rx
|
|
||||||
.await
|
|
||||||
.expect("Stdout sender unexpectedly dropped")
|
|
||||||
.unwrap(),
|
|
||||||
),
|
|
||||||
)?
|
|
||||||
.with_value(
|
|
||||||
"stderr",
|
|
||||||
ChildProcessReader(
|
|
||||||
stderr_rx
|
|
||||||
.await
|
|
||||||
.expect("Stderr sender unexpectedly dropped")
|
|
||||||
.unwrap(),
|
|
||||||
),
|
|
||||||
)?
|
|
||||||
.with_value(
|
|
||||||
"stdin",
|
|
||||||
ChildProcessWriter(
|
|
||||||
stdin_rx
|
|
||||||
.await
|
|
||||||
.expect("Stdin sender unexpectedly dropped")
|
|
||||||
.unwrap(),
|
|
||||||
),
|
|
||||||
)?
|
|
||||||
.with_async_function("status", move |lua, ()| {
|
.with_async_function("status", move |lua, ()| {
|
||||||
let code_rx_rc_clone = Rc::clone(&code_rx_rc);
|
let code_rx_rc_clone = Rc::clone(&code_rx_rc);
|
||||||
async move {
|
async move {
|
||||||
|
@ -270,21 +235,14 @@ async fn process_spawn(
|
||||||
.build_readonly()
|
.build_readonly()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn spawn_command(
|
async fn spawn_command_with_stdin(
|
||||||
program: String,
|
program: String,
|
||||||
args: Option<Vec<String>>,
|
args: Option<Vec<String>>,
|
||||||
mut options: ProcessSpawnOptions,
|
mut options: ProcessSpawnOptions,
|
||||||
) -> LuaResult<Child> {
|
) -> LuaResult<Child> {
|
||||||
let stdout = options.stdio.stdout;
|
|
||||||
let stderr = options.stdio.stderr;
|
|
||||||
let stdin = options.stdio.stdin.take();
|
let stdin = options.stdio.stdin.take();
|
||||||
|
|
||||||
let mut child = options
|
let mut child = spawn_command(program, args, options)?;
|
||||||
.into_command(program, args)
|
|
||||||
.stdin(Stdio::piped())
|
|
||||||
.stdout(stdout.as_stdio())
|
|
||||||
.stderr(stderr.as_stdio())
|
|
||||||
.spawn()?;
|
|
||||||
|
|
||||||
if let Some(stdin) = stdin {
|
if let Some(stdin) = stdin {
|
||||||
let mut child_stdin = child.stdin.take().unwrap();
|
let mut child_stdin = child.stdin.take().unwrap();
|
||||||
|
@ -293,3 +251,21 @@ async fn spawn_command(
|
||||||
|
|
||||||
Ok(child)
|
Ok(child)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn spawn_command(
|
||||||
|
program: String,
|
||||||
|
args: Option<Vec<String>>,
|
||||||
|
options: ProcessSpawnOptions,
|
||||||
|
) -> LuaResult<Child> {
|
||||||
|
let stdout = options.stdio.stdout;
|
||||||
|
let stderr = options.stdio.stderr;
|
||||||
|
|
||||||
|
let child = options
|
||||||
|
.into_command(program, args)
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(stdout.as_stdio())
|
||||||
|
.stderr(stderr.as_stdio())
|
||||||
|
.spawn()?;
|
||||||
|
|
||||||
|
Ok(child)
|
||||||
|
}
|
||||||
|
|
|
@ -1,18 +1,13 @@
|
||||||
local process = require("@lune/process")
|
local process = require("@lune/process")
|
||||||
|
|
||||||
-- Spawning a child process should not block the main thread
|
-- Spawning a child process should not block the thread
|
||||||
|
|
||||||
local SAMPLES = 400
|
local childThread = coroutine.create(process.create)
|
||||||
|
|
||||||
for _ = 1, SAMPLES do
|
local ok, err = coroutine.resume(childThread, "echo", { "hello, world" })
|
||||||
local start = os.time()
|
assert(ok, err)
|
||||||
local child = process.create("echo", { "hello, world" })
|
|
||||||
|
|
||||||
assert(child ~= nil, "Failed to spawn child process")
|
assert(
|
||||||
|
coroutine.status(childThread) == "dead",
|
||||||
local delta = os.time() - start
|
"Child process should not block the thread it is running on"
|
||||||
assert(
|
)
|
||||||
delta <= 1,
|
|
||||||
`Spawning a child process should not block the main thread, process.spawn took {delta}s to return when it should return immediately`
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
|
@ -15,7 +15,4 @@ local echoChild = if process.os == "windows"
|
||||||
then process.create("/c", { "echo", msg, "1>&2" }, { shell = "cmd" })
|
then process.create("/c", { "echo", msg, "1>&2" }, { shell = "cmd" })
|
||||||
else process.create("echo", { msg, ">>/dev/stderr" }, { shell = true })
|
else process.create("echo", { msg, ">>/dev/stderr" }, { shell = true })
|
||||||
|
|
||||||
assert(
|
assert(msg == echoChild.stderr:read(#msg), "Failed to read from stderr of child process")
|
||||||
msg == echoChild.stderr:read(#msg),
|
|
||||||
"Failed to read from stderr of child process"
|
|
||||||
)
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue