From 1618d3d7508ba9e84ee7d0382d7627c17234e6ab Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Sun, 29 Sep 2024 23:13:02 +0300 Subject: [PATCH 1/7] chore(deps): Depend on snafu for more robust error handling --- Cargo.lock | 22 ++++++++++++++++++++++ Cargo.toml | 3 +++ 2 files changed, 25 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 374394d4f..0554a37b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1774,6 +1774,7 @@ dependencies = [ "mlua", "rust-embed", "semver", + "snafu", "vergen-gix", ] @@ -1783,6 +1784,27 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "snafu" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" +dependencies = [ + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" diff --git a/Cargo.toml b/Cargo.toml index c4cc9f0c7..60a443b7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,6 +78,9 @@ version = "0.15.7" [dependencies.anyhow] version = "1.0" +[dependencies.snafu] +version = "0.8" + [dependencies.clap] version = "4.4" optional = true From fb451604befa196f5e591f8de251455d9af96b08 Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Sun, 29 Sep 2024 23:13:02 +0300 Subject: [PATCH 2/7] feat(cli): Output runtime errors pretty-printed for readability --- src/bin/sile.rs | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/bin/sile.rs b/src/bin/sile.rs index d1e7c66e0..3cbb14186 100644 --- a/src/bin/sile.rs +++ b/src/bin/sile.rs @@ -1,18 +1,42 @@ +use sile::cli::Cli; + +use snafu::prelude::*; + use clap::{CommandFactory, FromArgMatches}; -use sile::cli::Cli; -use sile::Result; +#[derive(Snafu)] +enum Error { + #[snafu(display("{}", source))] + Args { source: clap::error::Error }, + + #[snafu(display("{}", source))] + Runtime { source: anyhow::Error }, + + #[snafu(display("{}", source))] + Version { source: anyhow::Error }, +} + +// Deeper error types are reported using the Debug trait, but we handle them via Snafu and the Display trait. +// So we delegate. c.f. https://github.com/shepmaster/snafu/issues/110 +impl std::fmt::Debug for Error { + fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { + std::fmt::Display::fmt(self, fmt) + } +} + +type Result = std::result::Result; fn main() -> Result<()> { let version = option_env!("VERGEN_GIT_DESCRIBE").unwrap_or_else(|| env!("CARGO_PKG_VERSION")); let version = version.replacen('-', ".r", 1); - let long_version = sile::version()? + let long_version = sile::version() + .context(VersionSnafu)? .strip_prefix("SILE ") .unwrap_or("") .to_string(); let app = Cli::command().version(version).long_version(long_version); let matches = app.get_matches(); - let args = Cli::from_arg_matches(&matches).expect("Unable to parse arguments"); + let args = Cli::from_arg_matches(&matches).context(ArgsSnafu)?; sile::run( args.input, args.backend, @@ -29,6 +53,7 @@ fn main() -> Result<()> { args.r#use, args.quiet, args.traceback, - )?; + ) + .context(RuntimeSnafu)?; Ok(()) } From bfd24b583af0d81a7397dabcf46aa2e3bd06867c Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Sun, 29 Sep 2024 23:13:02 +0300 Subject: [PATCH 3/7] refactor(cli): Bubble-up more error conditions --- src/embed.rs.in | 3 ++- src/lib.rs | 55 +++++++++++++++++++++++++++---------------------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/embed.rs.in b/src/embed.rs.in index b4a86d61b..7d028157f 100644 --- a/src/embed.rs.in +++ b/src/embed.rs.in @@ -56,7 +56,7 @@ extern "C-unwind" { /// Register a Lua function in the loaders/searchers table to return C modules linked into the CLI /// binary and another to return embedded Lua resources as Lua modules. See discussion in mlua: /// https://github.com/khvzak/mlua/discussions/322 -pub fn inject_embedded_loaders(lua: &Lua) { +pub fn inject_embedded_loaders(lua: Lua) -> crate::Result { let package: LuaTable = lua.globals().get("package").unwrap(); let loaders: LuaTable = match package.get("loaders").unwrap() { LuaValue::Table(loaders) => loaders, @@ -164,4 +164,5 @@ pub fn inject_embedded_loaders(lua: &Lua) { }) .unwrap(); loaders.push(embedded_ftl_loader).unwrap(); + Ok(lua) } diff --git a/src/lib.rs b/src/lib.rs index d3a6e8638..00cf621be 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,13 @@ // rust-embed include attributes have issues with lots of matches... #![recursion_limit = "2048"] +use mlua::prelude::*; + #[cfg(not(feature = "static"))] use mlua::chunk; -use mlua::prelude::*; -use std::{env, path::PathBuf}; +use std::env; +use std::path::PathBuf; + #[cfg(feature = "cli")] pub mod cli; @@ -16,21 +19,22 @@ pub mod types; pub type Result = anyhow::Result; pub fn start_luavm() -> crate::Result { - let lua = unsafe { Lua::unsafe_new() }; + let mut lua = unsafe { Lua::unsafe_new() }; #[cfg(feature = "static")] - crate::embed::inject_embedded_loaders(&lua); - inject_paths(&lua); - load_sile(&lua); - inject_version(&lua); + { + lua = embed::inject_embedded_loaders(lua)?; + } + lua = inject_paths(lua)?; + lua = load_sile(lua)?; + lua = inject_version(lua)?; Ok(lua) } -pub fn inject_paths(lua: &Lua) { +pub fn inject_paths(lua: Lua) -> crate::Result { #[cfg(feature = "static")] lua.load(r#"require("core.pathsetup")"#) .set_name("relative pathsetup loader") - .exec() - .unwrap(); + .exec()?; #[cfg(not(feature = "static"))] { let datadir = env!("CONFIGURE_DATADIR").to_string(); @@ -38,7 +42,7 @@ pub fn inject_paths(lua: &Lua) { Ok(val) => format!("{datadir};{val}"), Err(_) => datadir, }; - let sile_path: LuaString = lua.create_string(&sile_path).unwrap(); + let sile_path: LuaString = lua.create_string(&sile_path)?; lua.load(chunk! { local status for path in string.gmatch($sile_path, "[^;]+") do @@ -50,9 +54,9 @@ pub fn inject_paths(lua: &Lua) { end }) .set_name("hard coded pathsetup loader") - .exec() - .unwrap(); + .exec()?; } + Ok(lua) } pub fn get_rusile_exports(lua: &Lua) -> LuaResult { @@ -62,28 +66,29 @@ pub fn get_rusile_exports(lua: &Lua) -> LuaResult { Ok(exports) } -fn setenv(key: String, value: String) -> LuaResult<()> { +fn setenv(key: String, value: String) { env::set_var(key, value); - Ok(()) } -pub fn inject_version(lua: &Lua) { - let sile: LuaTable = lua.globals().get("SILE").unwrap(); - let mut full_version: String = sile.get("full_version").unwrap(); +pub fn inject_version(lua: Lua) -> crate::Result { + let sile: LuaTable = lua.globals().get("SILE")?; + let mut full_version: String = sile.get("full_version")?; full_version.push_str(" [Rust]"); - sile.set("full_version", full_version).unwrap(); + sile.set("full_version", full_version)?; + Ok(lua) } -pub fn load_sile(lua: &Lua) { - let entry: LuaString = lua.create_string("core.sile").unwrap(); - let require: LuaFunction = lua.globals().get("require").unwrap(); - require.call::(entry).unwrap(); +pub fn load_sile(lua: Lua) -> crate::Result { + let entry: LuaString = lua.create_string("core.sile")?; + let require: LuaFunction = lua.globals().get("require")?; + require.call::(entry)?; + Ok(lua) } pub fn version() -> crate::Result { let lua = start_luavm()?; - let sile: LuaTable = lua.globals().get("SILE").unwrap(); - let full_version: String = sile.get("full_version").unwrap(); + let sile: LuaTable = lua.globals().get("SILE")?; + let full_version: String = sile.get("full_version")?; Ok(full_version) } From d38ff03f134062a4ab8237da67f9a68bfb6c7fcc Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Thu, 5 Dec 2024 14:39:45 +0300 Subject: [PATCH 4/7] fix(outputters): Don't attempt to create output if we error before processing even starts --- core/utilities/init.lua | 2 +- outputters/libtexpdf.lua | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/core/utilities/init.lua b/core/utilities/init.lua index e56b26265..a7b0805d8 100644 --- a/core/utilities/init.lua +++ b/core/utilities/init.lua @@ -332,7 +332,7 @@ function utilities.error (message, isbug) utilities.warn(message, isbug) _skip_traceback_levels = 2 io.stderr:flush() - SILE.outputter:finish() -- Only really useful from the REPL but no harm in trying + SILE.outputter:finish() SILE.scratch.caughterror = true error("", 2) end diff --git a/outputters/libtexpdf.lua b/outputters/libtexpdf.lua index c7f7d42bf..878cf8ab7 100644 --- a/outputters/libtexpdf.lua +++ b/outputters/libtexpdf.lua @@ -68,12 +68,13 @@ end function outputter._endHook (_) end function outputter:finish () - self:_ensureInit() - pdf.endpage() - self:runHooks("prefinish") - pdf.finish() - started = false - lastkey = nil + if started then + pdf.endpage() + self:runHooks("prefinish") + pdf.finish() + started = false + lastkey = nil + end end function outputter.getCursor (_) From d83e63cdbfdcfd8439212b9261f2dc5fbd24620a Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Thu, 5 Dec 2024 14:46:59 +0300 Subject: [PATCH 5/7] fix(core): Avoid internal error when also erroring due to user provided content errors --- core/sile.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/sile.lua b/core/sile.lua index 9954b8ba3..1192baf6a 100644 --- a/core/sile.lua +++ b/core/sile.lua @@ -181,10 +181,10 @@ local function runEvals (evals, arg) for _, snippet in ipairs(evals) do local pId = SILE.traceStack:pushText(snippet) local status, func = pcall(load, snippet) - if status then + if status and type(func) == "function" then func() else - SU.error(("Error parsing code provided in --%s snippet: %s"):format(arg, func)) + SU.error(("Error parsing code provided in --%s snippet: %s"):format(arg, snippet)) end SILE.traceStack:pop(pId) end From 31593afc559934d6b269d9bba56db1ed0ac0c1a4 Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Thu, 5 Dec 2024 14:52:34 +0300 Subject: [PATCH 6/7] chore(tooling): Drop now obsolete lint exception for non-standard globals --- .luacheckrc | 2 -- 1 file changed, 2 deletions(-) diff --git a/.luacheckrc b/.luacheckrc index 9e91ba5d2..00aa11e43 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -27,8 +27,6 @@ globals = { "luautf8", "pl", "fluent", - "executablePath", - "extendSilePath", } max_line_length = false ignore = { From 6dc7e6d83d2322899ab641c11863f3fdff88ffda Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Thu, 5 Dec 2024 14:54:50 +0300 Subject: [PATCH 7/7] style(tooling): Restyle Lua code with stylua --- rusile.rockspec.in | 1 - 1 file changed, 1 deletion(-) diff --git a/rusile.rockspec.in b/rusile.rockspec.in index 95c75f9b1..0d1bf12f4 100644 --- a/rusile.rockspec.in +++ b/rusile.rockspec.in @@ -29,4 +29,3 @@ build = { "ru@PACKAGE_NAME@", }, } -