diff --git a/Cargo.lock b/Cargo.lock index f909fa3..f70a03c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,6 +109,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "anyhow" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + [[package]] name = "arrayref" version = "0.3.7" @@ -320,7 +326,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.89", ] [[package]] @@ -636,7 +642,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.89", ] [[package]] @@ -818,7 +824,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.89", ] [[package]] @@ -926,7 +932,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.89", ] [[package]] @@ -974,13 +980,19 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "hashlink" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown", + "hashbrown 0.14.5", ] [[package]] @@ -1078,12 +1090,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", ] [[package]] @@ -1477,9 +1489,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.84" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1627,7 +1639,7 @@ checksum = "0774e846889823aa5766f5b62cface3189a5b36280e65b2faaa6df0319da1726" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.89", ] [[package]] @@ -1719,22 +1731,22 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.203" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.89", ] [[package]] @@ -1750,9 +1762,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -1783,6 +1795,7 @@ dependencies = [ name = "sheet-organizer" version = "0.1.1" dependencies = [ + "anyhow", "blake3", "chrono", "clap", @@ -1794,11 +1807,14 @@ dependencies = [ "relm4", "relm4-components", "relm4-icons", + "serde", "sqlx", "strum", "strum_macros", "tokio", + "toml", "walkdir", + "xdg", ] [[package]] @@ -2113,7 +2129,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.66", + "syn 2.0.89", ] [[package]] @@ -2135,9 +2151,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" dependencies = [ "proc-macro2", "quote", @@ -2192,7 +2208,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.89", ] [[package]] @@ -2237,7 +2253,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.89", ] [[package]] @@ -2253,21 +2269,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.13" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.13", + "toml_edit 0.22.22", ] [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] @@ -2296,15 +2312,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.13" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.8", + "winnow 0.6.20", ] [[package]] @@ -2327,7 +2343,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.89", ] [[package]] @@ -2356,7 +2372,7 @@ checksum = "ca029746fbe0efda3298205de77bf759d7fef23ac97902641e0b49a623b0455f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.89", ] [[package]] @@ -2488,7 +2504,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.89", "wasm-bindgen-shared", ] @@ -2510,7 +2526,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.89", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2721,13 +2737,19 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] +[[package]] +name = "xdg" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" + [[package]] name = "zerocopy" version = "0.7.34" @@ -2745,7 +2767,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.89", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fc5df31..ed0a1dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,10 @@ chrono = "0.4.38" strum = "0.26" strum_macros = "0.26" rand = "0.8.5" +xdg = "2.5.2" +toml = "0.8.19" +serde = { version = "1.0", features = ["derive"] } +anyhow = "1.0.93" # strum = { version = "0.26", features = ["derive"] } [profile.dev.package.sqlx-macros] diff --git a/Readme.md b/Readme.md index 3153634..2c64af9 100644 --- a/Readme.md +++ b/Readme.md @@ -1,2 +1,9 @@ # Sheet Organizer A simple tool for organizing and opening digital sheet music on a touch display as part of a digital music stand. + +## Configuration +You can configure sheet-organizer using an file `config.toml` inside one of your `$XDG_CONFIG_DIRECTORIES` (e.g. `~/.config/sheet-organizer/config.toml`). + +```toml +working_directory = "~/my-sheets" +``` diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..0aa4664 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,39 @@ +use anyhow::{anyhow, Context, Result}; +use serde::Deserialize; +use std::fs; +use std::path::PathBuf; +use xdg::BaseDirectories; + +#[derive(Debug, Deserialize)] +pub struct Config { + pub working_directory: Option, +} + +impl Config { + pub fn default() -> Config { + Config { + working_directory: None, + } + } +} + +pub fn load_config(app_name: &str, file_name: &str) -> Result { + // Create an XDG base directories instance + let xdg_dirs = + BaseDirectories::with_prefix(app_name).context("Failed to initialize XDG directories")?; + + let config_path = xdg_dirs + .place_config_file(file_name) + .context("Failed to determine configuration file path")?; + + if !config_path.exists() { + return Err(anyhow!("No configuration file at {:?}", config_path)); + } + + let contents = fs::read_to_string(&config_path) + .with_context(|| format!("Failed to read configuration file at {:?}", config_path))?; + + let config: Config = toml::from_str(&contents) + .with_context(|| format!("Failed to parse TOML configuration at {:?}", config_path))?; + Ok(config) +} diff --git a/src/main.rs b/src/main.rs index 0b8bb76..222442a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +mod config; mod database; mod sheet; mod sheet_dao; @@ -7,9 +8,10 @@ mod ui; use std::{path::PathBuf, process}; use clap::Parser; +use config::Config; use database::Database; use env_logger::Env; -use log::error; +use log::{error, warn}; use relm4::RelmApp; use crate::ui::app::{AppInitData, AppModel}; @@ -17,28 +19,49 @@ use crate::ui::app::{AppInitData, AppModel}; #[derive(Parser)] #[command(author, version, about)] struct Cli { - directory: PathBuf, + working_directory: Option, } #[tokio::main] async fn main() { env_logger::Builder::from_env(Env::default().default_filter_or("debug")).init(); + + let mut config = match config::load_config("sheet-organizer", "config.toml") { + Ok(config) => config, + Err(err) => { + warn!("Could not get configuration: {:#}", err); + Config::default() + } + }; + let cli = Cli::parse(); - if !cli.directory.is_dir() { - error!("Sheet folder path is no dir or does not exist"); + // Overwrite config by cli options if specified + if cli.working_directory.is_some() { + config.working_directory = cli.working_directory; + } + + let working_directory = config.working_directory.unwrap_or_else(|| { + error!("No working directory specified, neither in config nor in cli. Exiting..."); + process::exit(1); + }); + if !working_directory.is_dir() { + error!( + "Working directory '{}' does not exist", + working_directory.to_string_lossy() + ); process::exit(1); } - let database = Database::setup(cli.directory.join("database.sqlite")) + let database = Database::setup(working_directory.join("database.sqlite")) .await .unwrap(); - let sheets = sheet_validation::load_and_validate_sheets(&database, &cli.directory).await; + let sheets = sheet_validation::load_and_validate_sheets(&database, &working_directory).await; let app_init_data = AppInitData { sheets, database, - directory: cli.directory, + directory: working_directory, }; let app = RelmApp::new("de.frajul.sheet-organizer"); // Pass empty command line args to allow my own parsing