From d52851124953e052670c94ace8acc6c8ab6fc8ea Mon Sep 17 00:00:00 2001 From: Wojciech Kozlowski Date: Thu, 11 Jan 2024 23:27:01 +0100 Subject: [PATCH] Make it possible to launch main binary without database and/or library (#88) Closes #87 Reviewed-on: https://git.thenineworlds.net/wojtek/musichoard/pulls/88 --- src/bin/musichoard-edit.rs | 2 +- src/lib.rs | 61 ++++++++++------------------- src/main.rs | 79 +++++++++++++++++++++++--------------- 3 files changed, 69 insertions(+), 73 deletions(-) diff --git a/src/bin/musichoard-edit.rs b/src/bin/musichoard-edit.rs index 5d20230..9173ff7 100644 --- a/src/bin/musichoard-edit.rs +++ b/src/bin/musichoard-edit.rs @@ -16,7 +16,7 @@ type MH = MusicHoard>; struct Opt { #[structopt( long = "database", - name = "database file path", + help = "Database file path", default_value = "database.json" )] database_file_path: PathBuf, diff --git a/src/lib.rs b/src/lib.rs index 0c6d87c..47c152c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -788,45 +788,34 @@ impl MusicHoard { } pub fn rescan_library(&mut self) -> Result<(), Error> { - match self.library { - Some(ref mut library) => { - let items = library.list(&Query::new())?; - let mut library_collection = Self::items_to_artists(items); - Self::sort(&mut library_collection); + if let Some(ref mut library) = self.library { + let items = library.list(&Query::new())?; + let mut library_collection = Self::items_to_artists(items); + Self::sort(&mut library_collection); - let collection = mem::take(&mut self.collection); - self.collection = Self::merge(library_collection, collection); - - Ok(()) - } - None => Err(Error::LibraryError(String::from("library not provided"))), + let collection = mem::take(&mut self.collection); + self.collection = Self::merge(library_collection, collection); } + Ok(()) } pub fn load_from_database(&mut self) -> Result<(), Error> { - match self.database { - Some(ref mut database) => { - let mut database_collection: Collection = vec![]; - database.load(&mut database_collection)?; - Self::sort(&mut database_collection); + if let Some(ref mut database) = self.database { + let mut database_collection: Collection = vec![]; + database.load(&mut database_collection)?; + Self::sort(&mut database_collection); - let collection = mem::take(&mut self.collection); - self.collection = Self::merge(collection, database_collection); - - Ok(()) - } - None => Err(Error::DatabaseError(String::from("database not provided"))), + let collection = mem::take(&mut self.collection); + self.collection = Self::merge(collection, database_collection); } + Ok(()) } pub fn save_to_database(&mut self) -> Result<(), Error> { - match self.database { - Some(ref mut database) => { - database.save(&self.collection)?; - Ok(()) - } - None => Err(Error::DatabaseError(String::from("database not provided"))), + if let Some(ref mut database) = self.database { + database.save(&self.collection)?; } + Ok(()) } pub fn add_artist>(&mut self, artist_id: ID) { @@ -1963,10 +1952,7 @@ mod tests { let database = Some(MockIDatabase::new()); let mut music_hoard = MusicHoard::new(library, database); - let actual_err = music_hoard.rescan_library().unwrap_err(); - let expected_err = Error::LibraryError(String::from("library not provided")); - - assert_eq!(actual_err, expected_err); + assert!(music_hoard.rescan_library().is_ok()); } #[test] @@ -1997,15 +1983,8 @@ mod tests { let database: Option = None; let mut music_hoard = MusicHoard::new(library, database); - let expected_err = Error::DatabaseError(String::from("database not provided")); - - let actual_err = music_hoard.load_from_database().unwrap_err(); - assert_eq!(actual_err, expected_err); - assert_eq!(actual_err.to_string(), expected_err.to_string()); - - let actual_err = music_hoard.save_to_database().unwrap_err(); - assert_eq!(actual_err, expected_err); - assert_eq!(actual_err.to_string(), expected_err.to_string()); + assert!(music_hoard.load_from_database().is_ok()); + assert!(music_hoard.save_to_database().is_ok()); } #[test] diff --git a/src/main.rs b/src/main.rs index ac7ecd4..48cd409 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,8 @@ use std::fs::OpenOptions; use std::path::PathBuf; use std::{ffi::OsString, io}; +use musichoard::database::NoDatabase; +use musichoard::library::NoLibrary; use musichoard::Collection; use ratatui::{backend::CrosstermBackend, Terminal}; use structopt::StructOpt; @@ -27,22 +29,28 @@ use tui::{event::EventChannel, handler::EventHandler, listener::EventListener, T #[derive(StructOpt)] struct Opt { - #[structopt(long = "ssh", name = "beets SSH URI")] + #[structopt(long = "ssh", help = "Beets SSH URI")] beets_ssh_uri: Option, - #[structopt(long = "beets", name = "beets config file path")] + #[structopt(long = "beets", help = "Beets config file path")] beets_config_file_path: Option, + #[structopt(long = "no-library", help = "Do not connect to the library")] + no_library: bool, + #[structopt( long = "database", - name = "database file path", + help = "Database file path", default_value = "database.json" )] database_file_path: PathBuf, + + #[structopt(long = "no-database", help = "Do not read from/write to the database")] + no_database: bool, } -fn with(lib: LIB, db: DB) { - let music_hoard = MusicHoard::new(Some(lib), Some(db)); +fn with(lib: Option, db: Option) { + let music_hoard = MusicHoard::new(lib, db); // Initialize the terminal user interface. let backend = CrosstermBackend::new(io::stdout()); @@ -58,30 +66,10 @@ fn with(lib: LIB, db: DB) { Tui::run(terminal, ui, handler, listener).expect("failed to run tui"); } -fn main() { - let opt = Opt::from_args(); - - // Create an empty database file if it does not exist. - match OpenOptions::new() - .write(true) - .create_new(true) - .open(&opt.database_file_path) - { - Ok(f) => { - drop(f); - JsonDatabase::new(JsonDatabaseFileBackend::new(&opt.database_file_path)) - .save::(&vec![]) - .expect("failed to create empty database"); - } - Err(e) => match e.kind() { - io::ErrorKind::AlreadyExists => {} - _ => panic!("failed to access database file"), - }, - } - - // Create the application. - let db_exec = JsonDatabaseFileBackend::new(&opt.database_file_path); - if let Some(uri) = opt.beets_ssh_uri { +fn with_database(opt: Opt, db: Option) { + if opt.no_library { + with(None::, db); + } else if let Some(uri) = opt.beets_ssh_uri { let uri = uri.into_string().expect("invalid SSH URI"); let beets_config_file_path = opt .beets_config_file_path @@ -91,13 +79,42 @@ fn main() { let lib_exec = BeetsLibrarySshExecutor::new(uri) .expect("failed to initialise beets") .config(beets_config_file_path); - with(BeetsLibrary::new(lib_exec), JsonDatabase::new(db_exec)); + with(Some(BeetsLibrary::new(lib_exec)), db); } else { let lib_exec = BeetsLibraryProcessExecutor::default().config(opt.beets_config_file_path); - with(BeetsLibrary::new(lib_exec), JsonDatabase::new(db_exec)); + with(Some(BeetsLibrary::new(lib_exec)), db); } } +fn main() { + let opt = Opt::from_args(); + + if opt.no_database { + with_database(opt, None::); + } else { + // Create an empty database file if it does not exist. + match OpenOptions::new() + .write(true) + .create_new(true) + .open(&opt.database_file_path) + { + Ok(f) => { + drop(f); + JsonDatabase::new(JsonDatabaseFileBackend::new(&opt.database_file_path)) + .save::(&vec![]) + .expect("failed to create empty database"); + } + Err(e) => match e.kind() { + io::ErrorKind::AlreadyExists => {} + _ => panic!("failed to access database file"), + }, + } + + let db_exec = JsonDatabaseFileBackend::new(&opt.database_file_path); + with_database(opt, Some(JsonDatabase::new(db_exec))); + }; +} + #[cfg(test)] #[macro_use] mod testlib;