diff --git a/Cargo.lock b/Cargo.lock index baf65356a..e58d7bb90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3866,9 +3866,11 @@ dependencies = [ "chrono", "const_format", "daedalus", + "dirs 4.0.0", "fs_extra", "futures", "json5", + "lazy_static", "log", "once_cell", "path-clean", diff --git a/theseus/Cargo.toml b/theseus/Cargo.toml index 203053fca..c8b5413b3 100644 --- a/theseus/Cargo.toml +++ b/theseus/Cargo.toml @@ -24,6 +24,7 @@ zip-extensions = "0.6" sha1 = { version = "0.6.0", features = ["std"]} path-clean = "0.1.0" fs_extra = "1.2.0" +dirs = "4.0" regex = "1.5" @@ -35,6 +36,7 @@ sys-info = "0.9.0" log = "0.4.14" const_format = "0.2.22" once_cell = "1.9.0" +lazy_static = "1.4" [dev-dependencies] argh = "0.1.6" diff --git a/theseus/src/data/meta.rs b/theseus/src/data/meta.rs index bd253e205..3aa3f7252 100644 --- a/theseus/src/data/meta.rs +++ b/theseus/src/data/meta.rs @@ -1,5 +1,3 @@ -use std::path::Path; - use crate::{data::DataError, LAUNCHER_WORK_DIR}; use once_cell::sync; use serde::{Deserialize, Serialize}; @@ -19,12 +17,13 @@ pub struct Metadata { impl Metadata { pub async fn init() -> Result<(), DataError> { - let meta_path = Path::new(LAUNCHER_WORK_DIR).join(META_FILE); + let meta_path = LAUNCHER_WORK_DIR.join(META_FILE); if meta_path.exists() { - let meta_data = std::fs::read_to_string(meta_path) + let meta_data = tokio::fs::read_to_string(meta_path) + .await .ok() - .and_then(|x| serde_json::from_str::(&x).ok()); + .and_then(|it| serde_json::from_str::(&it).ok()); if let Some(metadata) = meta_data { METADATA.get_or_init(|| RwLock::new(metadata)); @@ -37,7 +36,7 @@ impl Metadata { let new = Self::fetch().await?; std::fs::write( - Path::new(LAUNCHER_WORK_DIR).join(META_FILE), + LAUNCHER_WORK_DIR.join(META_FILE), &serde_json::to_string(&new)?, )?; diff --git a/theseus/src/data/settings.rs b/theseus/src/data/settings.rs index ec0643b2b..1c33697b6 100644 --- a/theseus/src/data/settings.rs +++ b/theseus/src/data/settings.rs @@ -1,8 +1,5 @@ use super::profiles::*; -use std::{ - collections::HashSet, - path::{Path, PathBuf}, -}; +use std::{collections::HashSet, path::PathBuf}; use crate::{data::DataError, LAUNCHER_WORK_DIR}; use once_cell::sync; @@ -12,6 +9,7 @@ use tokio::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; const SETTINGS_FILE: &str = "settings.json"; const ICONS_PATH: &str = "icons"; const METADATA_DIR: &str = "meta"; +const SETTINGS_PATH_ENV: &str = "THESEUS_CONFIG_DIR"; static SETTINGS: sync::OnceCell> = sync::OnceCell::new(); pub const FORMAT_VERSION: u32 = 1; @@ -41,8 +39,8 @@ impl Default for Settings { java_8_path: None, java_17_path: None, hooks: ProfileHooks::default(), - icon_path: Path::new(LAUNCHER_WORK_DIR).join(ICONS_PATH), - metadata_dir: Path::new(LAUNCHER_WORK_DIR).join(METADATA_DIR), + icon_path: LAUNCHER_WORK_DIR.join(ICONS_PATH), + metadata_dir: LAUNCHER_WORK_DIR.join(METADATA_DIR), profiles: HashSet::new(), max_concurrent_downloads: 32, version: FORMAT_VERSION, @@ -52,10 +50,12 @@ impl Default for Settings { impl Settings { pub async fn init() -> Result<(), DataError> { - let settings_path = Path::new(LAUNCHER_WORK_DIR).join(SETTINGS_FILE); + let settings_path = std::env::var_os(SETTINGS_PATH_ENV) + .map_or(LAUNCHER_WORK_DIR.join(SETTINGS_FILE), PathBuf::from); if settings_path.exists() { - let settings_data = std::fs::read_to_string(settings_path) + let settings_data = tokio::fs::read_to_string(settings_path) + .await .map(|x| serde_json::from_str::(&x).ok()) .ok() .flatten(); @@ -68,11 +68,8 @@ impl Settings { if SETTINGS.get().is_none() { let new = Self::default(); - tokio::fs::rename(SETTINGS_FILE, format!("{SETTINGS_FILE}.bak")) - .await?; - tokio::fs::write( - Path::new(LAUNCHER_WORK_DIR).join(SETTINGS_FILE), + LAUNCHER_WORK_DIR.join(SETTINGS_FILE), &serde_json::to_string(&new)?, ) .await?; @@ -85,7 +82,7 @@ impl Settings { pub async fn load() -> Result<(), DataError> { let new = serde_json::from_str::(&std::fs::read_to_string( - Path::new(LAUNCHER_WORK_DIR).join(SETTINGS_FILE), + LAUNCHER_WORK_DIR.join(SETTINGS_FILE), )?)?; let mut write = SETTINGS @@ -103,7 +100,7 @@ impl Settings { let settings = Self::get().await?; std::fs::write( - Path::new(LAUNCHER_WORK_DIR).join(SETTINGS_FILE), + LAUNCHER_WORK_DIR.join(SETTINGS_FILE), &serde_json::to_string_pretty(&*settings)?, )?; diff --git a/theseus/src/lib.rs b/theseus/src/lib.rs index 5d0528c22..7b4265d5b 100644 --- a/theseus/src/lib.rs +++ b/theseus/src/lib.rs @@ -5,7 +5,10 @@ #![warn(unused_import_braces, missing_debug_implementations)] -static LAUNCHER_WORK_DIR: &'static str = "./launcher"; +// TODO: make non-hardcoded +lazy_static::lazy_static! { + static ref LAUNCHER_WORK_DIR: std::path::PathBuf = dirs::config_dir().expect("Could not find config dir").join("theseus"); +} pub mod data; pub mod launcher; @@ -25,7 +28,8 @@ pub enum Error { } pub async fn init() -> Result<(), Error> { - std::fs::create_dir_all(LAUNCHER_WORK_DIR) + tokio::fs::create_dir_all(LAUNCHER_WORK_DIR.as_path()) + .await .expect("Unable to create launcher root directory!"); use crate::data::*; diff --git a/theseus_cli/src/main.rs b/theseus_cli/src/main.rs index c98db7e7f..580631805 100644 --- a/theseus_cli/src/main.rs +++ b/theseus_cli/src/main.rs @@ -1,4 +1,5 @@ use eyre::Result; +use futures::TryFutureExt; use paris::*; mod subcommands; @@ -16,12 +17,8 @@ async fn main() -> Result<()> { let args = argh::from_env::(); theseus::init().await?; - let res = args.dispatch().await; - if res.is_err() { - error!("An error has occurred!\n"); - } else { - theseus::save().await?; - } - - res + args.dispatch() + .inspect_err(|_| error!("An error has occurred!\n")) + .and_then(|_| async { Ok(theseus::save().await?) }) + .await }