From 56e04be35cf6e91d6b3a13694f92f18a7f7a3960 Mon Sep 17 00:00:00 2001 From: Truman Kilen Date: Fri, 21 Jul 2023 14:05:26 -0500 Subject: [PATCH] More verbose error handling --- Cargo.lock | 61 ++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 2 +- src/gui/mod.rs | 25 ++++++++++++++---- src/integrate.rs | 7 ++--- src/lib.rs | 21 +++++++++++++-- src/main.rs | 17 +++++++++++- src/providers/mod.rs | 3 ++- src/state/config.rs | 4 ++- 8 files changed, 124 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6da74bf4..3085635e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,6 +87,15 @@ dependencies = [ "winit", ] +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + [[package]] name = "adler" version = "1.0.2" @@ -232,6 +241,9 @@ name = "anyhow" version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +dependencies = [ + "backtrace", +] [[package]] name = "arboard" @@ -406,6 +418,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide 0.6.2", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.13.1" @@ -1264,7 +1291,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.7.1", ] [[package]] @@ -1479,6 +1506,12 @@ dependencies = [ "syn 2.0.18", ] +[[package]] +name = "gimli" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" + [[package]] name = "gio-sys" version = "0.16.3" @@ -2077,6 +2110,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + [[package]] name = "miniz_oxide" version = "0.7.1" @@ -2334,6 +2376,15 @@ dependencies = [ "objc", ] +[[package]] +name = "object" +version = "0.30.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" version = "1.17.2" @@ -2569,7 +2620,7 @@ dependencies = [ "crc32fast", "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.7.1", ] [[package]] @@ -2829,6 +2880,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + [[package]] name = "rustc-hash" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index f0834865..c14f51c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" repository = "https://github.com/trumank/drg-mod-integration" [dependencies] -anyhow = "1.0.71" +anyhow = { version = "1.0.71", features = ["backtrace"] } async-trait = "0.1.68" clap = { version = "4.3.0", features = ["derive"] } dialoguer = "0.10.4" diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 73b5ed73..b221344a 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -28,7 +28,7 @@ use crate::{ use request_counter::{RequestCounter, RequestID}; -pub fn gui() -> Result<()> { +pub fn gui(args: Option>) -> Result<()> { let options = eframe::NativeOptions { initial_window_size: Some(egui::vec2(320.0, 240.0)), ..Default::default() @@ -36,13 +36,14 @@ pub fn gui() -> Result<()> { eframe::run_native( "DRG Mod Integration", options, - Box::new(|_cc| Box::new(App::new().unwrap())), + Box::new(|_cc| Box::new(App::new(args).unwrap())), ) .map_err(|e| anyhow!("{e}"))?; Ok(()) } struct App { + args: Option>, tx: Sender, rx: Receiver, state: State, @@ -65,11 +66,12 @@ struct App { } impl App { - fn new() -> Result { + fn new(args: Option>) -> Result { let (tx, rx) = mpsc::channel(10); let state = State::new()?; Ok(Self { + args, tx, rx, request_counter: Default::default(), @@ -575,7 +577,7 @@ impl eframe::App for App { ); } Err(e) => { - self.log.println(format!("{:#?}", e)); + self.log.println(format!("{:#?}\n{}", e, e.backtrace())); } }, } @@ -602,7 +604,7 @@ impl eframe::App for App { ); } Err(e) => { - self.log.println(format!("{:#?}", e)); + self.log.println(format!("{:#?}\n{}", e, e.backtrace())); } }, } @@ -645,6 +647,19 @@ impl eframe::App for App { && self.update_rid.is_none() && self.state.config.drg_pak_path.is_some(), |ui| { + if let Some(args) = &self.args { + if ui.button("launch game").on_hover_ui(|ui| for arg in args { + ui.label(arg); + }).clicked() { + let args = args.clone(); + tokio::task::spawn_blocking(move || { + let mut iter = args.iter(); + std::process::Command::new( + iter.next().unwrap(), + ).args(iter).spawn().unwrap(); + }); + } + } ui.add_enabled_ui(self.state.config.drg_pak_path.is_some(), |ui| { let mut button = ui.button("install mods"); if self.state.config.drg_pak_path.is_none() { diff --git a/src/integrate.rs b/src/integrate.rs index 8e1f3704..b812720a 100644 --- a/src/integrate.rs +++ b/src/integrate.rs @@ -1,5 +1,5 @@ use std::collections::{HashMap, HashSet}; -use std::fs::{File, OpenOptions}; +use std::fs::OpenOptions; use std::io::{self, BufReader, BufWriter, Cursor, Read, Seek}; use std::path::{Path, PathBuf}; @@ -8,6 +8,7 @@ use unreal_asset::properties::object_property::TopLevelAssetPath; use unreal_asset::types::vector::Vector; use unreal_asset::unversioned::ancestry::Ancestry; +use crate::open_file; use crate::providers::{ModInfo, ReadSeek}; use unreal_asset::{ @@ -38,7 +39,7 @@ pub fn integrate>(path_pak: P, mods: Vec<(ModInfo, PathBuf)>) -> let path_pak = Path::join(path_paks, "FSD-WindowsNoEditor.pak"); let path_mod_pak = Path::join(path_paks, "mods_P.pak"); - let mut fsd_pak_reader = BufReader::new(File::open(path_pak)?); + let mut fsd_pak_reader = BufReader::new(open_file(path_pak)?); let fsd_pak = repak::PakReader::new_any(&mut fsd_pak_reader, None)?; let pcb_path = ( @@ -83,7 +84,7 @@ pub fn integrate>(path_pak: P, mods: Vec<(ModInfo, PathBuf)>) -> let mods = mods .into_iter() .map(|(m, path)| { - let mut buf = get_pak_from_data(Box::new(BufReader::new(File::open(path)?)))?; + let mut buf = get_pak_from_data(Box::new(BufReader::new(open_file(path)?)))?; let pak = repak::PakReader::new_any(&mut buf, None)?; let mount = Path::new(pak.mount_point()); diff --git a/src/lib.rs b/src/lib.rs index 89d23338..04450b92 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ use std::{ path::{Path, PathBuf}, }; -use anyhow::Result; +use anyhow::{Context, Result}; use error::IntegrationError; use providers::{ModSpecification, ProviderFactory}; @@ -23,8 +23,25 @@ pub fn find_drg_pak() -> Option { }) } +/// File::open with the file path included in any error messages +pub fn open_file>(path: P) -> Result { + std::fs::File::open(&path) + .with_context(|| format!("Could not open file {}", path.as_ref().display())) +} + +/// fs::read with the file path included in any error messages +pub fn read_file>(path: P) -> Result> { + std::fs::read(&path).with_context(|| format!("Could not read file {}", path.as_ref().display())) +} + +/// fs::write with the file path included in any error messages +pub fn write_file, C: AsRef<[u8]>>(path: P, data: C) -> Result<()> { + std::fs::write(&path, data) + .with_context(|| format!("Could not write to file {}", path.as_ref().display())) +} + pub fn is_drg_pak>(path: P) -> Result<()> { - let mut reader = std::io::BufReader::new(std::fs::File::open(path)?); + let mut reader = std::io::BufReader::new(open_file(path)?); let pak = repak::PakReader::new_any(&mut reader, None)?; pak.get("FSD/FSD.uproject", &mut reader)?; Ok(()) diff --git a/src/main.rs b/src/main.rs index b644ea77..a2380e77 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,10 +52,17 @@ struct ActionIntegrateProfile { profile: String, } +/// Launch via steam +#[derive(Parser, Debug)] +struct ActionLaunch { + args: Vec, +} + #[derive(Subcommand, Debug)] enum Action { Integrate(ActionIntegrate), Profile(ActionIntegrateProfile), + Launch(ActionLaunch), } #[derive(Parser, Debug)] @@ -66,6 +73,7 @@ struct Args { } fn main() -> Result<()> { + std::env::set_var("RUST_BACKTRACE", "1"); let rt = tokio::runtime::Runtime::new().expect("Unable to create Runtime"); let _enter = rt.enter(); @@ -80,11 +88,18 @@ fn main() -> Result<()> { action_integrate_profile(action).await?; Ok(()) }), + Some(Action::Launch(action)) => { + std::thread::spawn(move || { + rt.block_on(std::future::pending::<()>()); + }); + gui(Some(action.args))?; + Ok(()) + } None => { std::thread::spawn(move || { rt.block_on(std::future::pending::<()>()); }); - gui()?; + gui(None)?; Ok(()) } } diff --git a/src/providers/mod.rs b/src/providers/mod.rs index cedd285d..80b482e0 100644 --- a/src/providers/mod.rs +++ b/src/providers/mod.rs @@ -4,6 +4,7 @@ pub mod modio; use crate::error::IntegrationError; use crate::state::config::ConfigWrapper; +use crate::write_file; use anyhow::{Context, Result}; @@ -380,7 +381,7 @@ impl BlobCache { let hash = hex::encode(hasher.finalize()); let tmp = self.path.join(format!(".{hash}")); - std::fs::write(&tmp, blob)?; + write_file(&tmp, blob)?; std::fs::rename(tmp, self.path.join(&hash))?; Ok(BlobRef(hash)) diff --git a/src/state/config.rs b/src/state/config.rs index c7d207cc..0dd71c35 100644 --- a/src/state/config.rs +++ b/src/state/config.rs @@ -4,6 +4,8 @@ use anyhow::Result; use serde::{de::DeserializeOwned, Serialize}; +use crate::write_file; + /// Wrapper around an object that is read from a file on init and written on drop pub struct ConfigWrapper { path: PathBuf, @@ -20,7 +22,7 @@ impl ConfigWrapper { } } pub fn save(&self) -> Result<()> { - std::fs::write(&self.path, serde_json::to_vec_pretty(&self.config)?)?; + write_file(&self.path, serde_json::to_vec_pretty(&self.config)?)?; Ok(()) } }