diff --git a/CHANGELOG.md b/CHANGELOG.md index 707f17a..7135076 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased Changes * **Breaking**: Moved script execution to `remodel run` to make room for new subcommands. * If you previously used `remodel foo.lua`, use `remodel run foo.lua` now. +* Added `--verbose` and `-v` flags for setting verbosity. * Added `json.fromString` and `json.toString` for encoding/decoding JSON * Added `remodel.isFile` and `remodel.isDir`. * Added support for reading the auth cookie through the `REMODEL_AUTH` environment variable. @@ -10,6 +11,7 @@ * `remodel run foo` will now run `.remodel/foo.lua` if it exists. * Added (experimental) support for building Rojo projects through `rojo.buildProject`. * This is behind the `unstable_rojo_api` Cargo feature and is not enabled by default. +* Improved logging and error reporting across the board. ## 0.6.1 (2019-12-11) * Upgraded reflection database and dependencies. diff --git a/Cargo.lock b/Cargo.lock index 3e21d97..388486b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,11 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "anyhow" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "atty" version = "0.2.13" @@ -37,10 +42,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.40" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -48,7 +53,7 @@ dependencies = [ [[package]] name = "backtrace-sys" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", @@ -326,7 +331,7 @@ name = "error-chain" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -335,7 +340,7 @@ name = "failure" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1255,6 +1260,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "remodel" version = "0.6.1" dependencies = [ + "anyhow 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rbx_binary 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2020,10 +2027,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum anyhow 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "013a6e0a2cbe3d20f9c60b65458f7a7f7a5e636c5d0f45a5a6aee5d4b1f01785" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" -"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" -"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" +"checksum backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8" +"checksum backtrace-sys 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "ca797db0057bae1a7aa2eef3283a874695455cecf08a43bfb8507ee0ebc1ed69" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" diff --git a/Cargo.toml b/Cargo.toml index 9d34ccc..c08c248 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,17 +16,26 @@ default = [] # Enables the unstable Rojo API for Remodel unstable_rojo_api = ["rojo"] +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" + [dependencies] +anyhow = "1.0.27" +backtrace = "0.3.45" log = "0.4.8" rbx_binary = "0.4.1" rbx_dom_weak = "1.10.0" -rbx_xml = "0.11.2" rbx_reflection = "3.2.399" +rbx_xml = "0.11.2" reqwest = "0.9.20" rlua = "0.17.0" -structopt = "0.3.11" serde = "1.0.104" serde_json = "1.0.44" +structopt = "0.3.11" + rojo = { git = "https://github.com/rojo-rbx/rojo.git", rev = "build-api", optional = true } [target.'cfg(windows)'.dependencies] diff --git a/src/main.rs b/src/main.rs index 909e551..cef3737 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,12 +8,14 @@ mod value; mod rojo_api; use std::{ - error::Error, - fs, + env, fs, io::{self, Read}, + panic, path::{Path, PathBuf}, + process, }; +use backtrace::Backtrace; use rlua::{Lua, MultiValue, ToLua}; use structopt::StructOpt; @@ -27,22 +29,23 @@ use crate::{ about = env!("CARGO_PKG_DESCRIPTION"), author = env!("CARGO_PKG_AUTHORS"), )] -pub struct Options { +struct Options { #[structopt(subcommand)] subcommand: Subcommand, + /// Enables more verbose logging. + /// + /// Can be specified up to 3 times to increase verbosity. + #[structopt(long("verbose"), short, global(true), parse(from_occurrences))] + verbosity: u8, + /// The .ROBLOSECURITY cookie to use for authenticating to the Roblox API. /// /// Remodel will attempt to use an existing session from Roblox Studio on /// Windows if it is installed and you are logged in. /// /// Can also be passed via the REMODEL_AUTH environment variable. - #[structopt( - long = "auth", - env = "REMODEL_AUTH", - hide_env_values = true, - global = true - )] + #[structopt(long("auth"), env("REMODEL_AUTH"), hide_env_values(true), global(true))] auth_cookie: Option, } @@ -62,13 +65,21 @@ enum Subcommand { }, } -fn start() -> Result<(), Box> { - env_logger::from_env(env_logger::Env::default().default_filter_or("warn")).init(); +fn main() { + let options = Options::from_args(); + initialize_logger(options.verbosity); + install_panic_hook(); - let opt = Options::from_args(); - let auth_cookie = opt.auth_cookie.or_else(get_auth_cookie); + if let Err(err) = run(options) { + log::error!("{:?}", err); + process::exit(1); + } +} + +fn run(options: Options) -> Result<(), anyhow::Error> { + let auth_cookie = options.auth_cookie.or_else(get_auth_cookie); - match opt.subcommand { + match options.subcommand { Subcommand::Run { script, args } => { let (contents, chunk_name) = load_script(&script)?; let lua = Lua::new(); @@ -160,12 +171,65 @@ fn load_script(script: &str) -> io::Result<(String, String)> { } } -fn main() { - match start() { - Ok(_) => {} - Err(e) => { - eprintln!("{}", e); - std::process::exit(1); +fn initialize_logger(verbosity: u8) { + let log_filter = match verbosity { + 0 => "info", + 1 => "info,remodel=debug", + 2 => "info,remodel=trace", + _ => "trace", + }; + + let log_env = env_logger::Env::default().default_filter_or(log_filter); + + env_logger::Builder::from_env(log_env) + .format_module_path(false) + .format_timestamp(None) + // Indent following lines equal to the log level label, like `[ERROR] ` + .format_indent(Some(8)) + .init(); +} + +fn install_panic_hook() { + panic::set_hook(Box::new(|panic_info| { + // PanicInfo's payload is usually a &'static str or String. + // See: https://doc.rust-lang.org/beta/std/panic/struct.PanicInfo.html#method.payload + let message = match panic_info.payload().downcast_ref::<&str>() { + Some(message) => message.to_string(), + None => match panic_info.payload().downcast_ref::() { + Some(message) => message.clone(), + None => "".to_string(), + }, + }; + + log::error!("Remodel crashed!"); + log::error!("This may be a Remodel bug."); + log::error!(""); + log::error!( + "Please consider filing an issue: {}/issues", + env!("CARGO_PKG_REPOSITORY") + ); + log::error!(""); + log::error!("Details: {}", message); + + if let Some(location) = panic_info.location() { + log::error!("in file {} on line {}", location.file(), location.line()); } - } + + // When using the backtrace crate, we need to check the RUST_BACKTRACE + // environment variable ourselves. Once we switch to the (currently + // unstable) std::backtrace module, we won't need to do this anymore. + let should_backtrace = env::var("RUST_BACKTRACE") + .map(|var| var == "1") + .unwrap_or(false); + + if should_backtrace { + eprintln!("{:?}", Backtrace::new()); + } else { + eprintln!( + "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace." + ); + } + + process::exit(1); + })); }