mirror of
https://github.com/CompeyDev/lune-packaging.git
synced 2025-01-09 12:19:09 +00:00
Improve process error code handling
This commit is contained in:
parent
c2ee188ad5
commit
fd8a41759c
2 changed files with 85 additions and 43 deletions
|
@ -1,14 +1,10 @@
|
||||||
use std::{
|
use std::{env, process::Stdio, sync::Weak};
|
||||||
env,
|
|
||||||
process::{exit, Stdio},
|
|
||||||
sync::Weak,
|
|
||||||
};
|
|
||||||
|
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
use os_str_bytes::RawOsString;
|
use os_str_bytes::RawOsString;
|
||||||
use smol::{process::Command, LocalExecutor};
|
use smol::{channel::Sender, process::Command, LocalExecutor};
|
||||||
|
|
||||||
use crate::utils::table_builder::TableBuilder;
|
use crate::{utils::table_builder::TableBuilder, LuneMessage};
|
||||||
|
|
||||||
pub fn create(lua: &Lua, args_vec: Vec<String>) -> LuaResult<()> {
|
pub fn create(lua: &Lua, args_vec: Vec<String>) -> LuaResult<()> {
|
||||||
// Create readonly args array
|
// Create readonly args array
|
||||||
|
@ -31,7 +27,7 @@ pub fn create(lua: &Lua, args_vec: Vec<String>) -> LuaResult<()> {
|
||||||
TableBuilder::new(lua)?
|
TableBuilder::new(lua)?
|
||||||
.with_value("args", args_tab)?
|
.with_value("args", args_tab)?
|
||||||
.with_value("env", env_tab)?
|
.with_value("env", env_tab)?
|
||||||
.with_function("exit", process_exit)?
|
.with_async_function("exit", process_exit)?
|
||||||
.with_async_function("spawn", process_spawn)?
|
.with_async_function("spawn", process_spawn)?
|
||||||
.build_readonly()?,
|
.build_readonly()?,
|
||||||
)
|
)
|
||||||
|
@ -103,14 +99,17 @@ fn process_env_iter<'lua>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_exit(_: &Lua, exit_code: Option<i32>) -> LuaResult<()> {
|
async fn process_exit(lua: &Lua, exit_code: Option<u8>) -> LuaResult<()> {
|
||||||
// TODO: Exit gracefully to the root with an Ok
|
let sender = lua
|
||||||
// result instead of completely exiting the process
|
.app_data_ref::<Weak<Sender<LuneMessage>>>()
|
||||||
if let Some(code) = exit_code {
|
.unwrap()
|
||||||
exit(code);
|
.upgrade()
|
||||||
} else {
|
.unwrap();
|
||||||
exit(0)
|
sender
|
||||||
}
|
.send(LuneMessage::Exit(exit_code.unwrap_or(0)))
|
||||||
|
.await
|
||||||
|
.map_err(LuaError::external)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_spawn(
|
async fn process_spawn(
|
||||||
|
|
|
@ -1,10 +1,4 @@
|
||||||
use std::{
|
use std::{collections::HashSet, sync::Arc};
|
||||||
collections::HashSet,
|
|
||||||
sync::{
|
|
||||||
atomic::{AtomicU32, Ordering},
|
|
||||||
Arc,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, Result};
|
use anyhow::{anyhow, bail, Result};
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
|
@ -42,7 +36,9 @@ impl LuneGlobal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub(crate) enum LuneMessage {
|
pub(crate) enum LuneMessage {
|
||||||
|
Exit(u8),
|
||||||
Spawned,
|
Spawned,
|
||||||
Finished,
|
Finished,
|
||||||
Error(anyhow::Error),
|
Error(anyhow::Error),
|
||||||
|
@ -77,7 +73,7 @@ impl Lune {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(&self, name: &str, chunk: &str) -> Result<()> {
|
pub async fn run(&self, name: &str, chunk: &str) -> Result<u8> {
|
||||||
let (s, r) = smol::channel::unbounded::<LuneMessage>();
|
let (s, r) = smol::channel::unbounded::<LuneMessage>();
|
||||||
let lua = Arc::new(mlua::Lua::new());
|
let lua = Arc::new(mlua::Lua::new());
|
||||||
let exec = Arc::new(LocalExecutor::new());
|
let exec = Arc::new(LocalExecutor::new());
|
||||||
|
@ -122,33 +118,72 @@ impl Lune {
|
||||||
sender.send(message).await
|
sender.send(message).await
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
// Run the executor until there are no tasks left
|
// Run the executor until there are no tasks left,
|
||||||
let task_count = AtomicU32::new(0);
|
// taking care to not exit right away for errors
|
||||||
smol::block_on(exec.run(async {
|
let (got_code, got_error, exit_code) = smol::block_on(exec.run(async {
|
||||||
|
let mut task_count = 0;
|
||||||
|
let mut got_error = false;
|
||||||
|
let mut got_code = false;
|
||||||
|
let mut exit_code = 0;
|
||||||
while let Ok(message) = receiver.recv().await {
|
while let Ok(message) = receiver.recv().await {
|
||||||
let value = match message {
|
// Make sure our task-count-modifying messages are sent correctly, one
|
||||||
LuneMessage::Spawned => task_count.fetch_add(1, Ordering::Relaxed),
|
// task spawned must always correspond to one task finished / errored
|
||||||
LuneMessage::Finished => task_count.fetch_sub(1, Ordering::Relaxed),
|
match &message {
|
||||||
|
LuneMessage::Exit(_) => {}
|
||||||
|
LuneMessage::Spawned => {}
|
||||||
|
message => {
|
||||||
|
if task_count == 0 {
|
||||||
|
bail!(
|
||||||
|
"Got message while task count was 0!\nMessage: {:#?}",
|
||||||
|
message
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Handle whatever message we got
|
||||||
|
match message {
|
||||||
|
LuneMessage::Exit(code) => {
|
||||||
|
exit_code = code;
|
||||||
|
got_code = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
LuneMessage::Spawned => task_count += 1,
|
||||||
|
LuneMessage::Finished => task_count -= 1,
|
||||||
LuneMessage::Error(e) => {
|
LuneMessage::Error(e) => {
|
||||||
task_count.fetch_sub(1, Ordering::Relaxed);
|
eprintln!("{}", e);
|
||||||
bail!("{}", e)
|
got_error = true;
|
||||||
|
task_count += 1;
|
||||||
}
|
}
|
||||||
LuneMessage::LuaError(e) => {
|
LuneMessage::LuaError(e) => {
|
||||||
task_count.fetch_sub(1, Ordering::Relaxed);
|
eprintln!("{}", e);
|
||||||
bail!("{}", e)
|
got_error = true;
|
||||||
|
task_count += 1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
println!("Running tasks: {value}");
|
// If there are no tasks left running, it is now
|
||||||
|
// safe to close the receiver and end execution
|
||||||
|
if task_count == 0 {
|
||||||
|
receiver.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok((got_code, got_error, exit_code))
|
||||||
}))
|
}))?;
|
||||||
|
// If we got an error, we will default to exiting
|
||||||
|
// with code 1, unless a code was manually given
|
||||||
|
if got_code {
|
||||||
|
Ok(exit_code)
|
||||||
|
} else if got_error {
|
||||||
|
Ok(1)
|
||||||
|
} else {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::Lune;
|
use crate::Lune;
|
||||||
use anyhow::Result;
|
use anyhow::{bail, Result};
|
||||||
use smol::fs::read_to_string;
|
use smol::fs::read_to_string;
|
||||||
use std::env::current_dir;
|
use std::env::current_dir;
|
||||||
|
|
||||||
|
@ -167,9 +202,19 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let lune = Lune::new()
|
let lune = Lune::new()
|
||||||
.with_args(ARGS.clone().iter().map(ToString::to_string).collect())
|
.with_args(
|
||||||
|
ARGS
|
||||||
|
.clone()
|
||||||
|
.iter()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.collect()
|
||||||
|
)
|
||||||
.with_all_globals();
|
.with_all_globals();
|
||||||
lune.run($value, &script).await
|
let exit_code = lune.run($value, &script).await?;
|
||||||
|
if exit_code != 0 {
|
||||||
|
bail!("Test exited with failure code {}", exit_code);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
@ -184,9 +229,7 @@ mod tests {
|
||||||
fs_dirs: "fs/dirs",
|
fs_dirs: "fs/dirs",
|
||||||
process_args: "process/args",
|
process_args: "process/args",
|
||||||
process_env: "process/env",
|
process_env: "process/env",
|
||||||
// NOTE: This test does not currently work, it will exit the entire
|
process_exit: "process/exit",
|
||||||
// process, meaning it will also exit our test runner and skip testing
|
|
||||||
// process_exit: "process/exit",
|
|
||||||
process_spawn: "process/spawn",
|
process_spawn: "process/spawn",
|
||||||
net_request_codes: "net/request/codes",
|
net_request_codes: "net/request/codes",
|
||||||
net_request_methods: "net/request/methods",
|
net_request_methods: "net/request/methods",
|
||||||
|
|
Loading…
Reference in a new issue