Make it possible to launch main binary without database and/or library (#88)
Closes #87 Reviewed-on: #88
This commit is contained in:
parent
0c48673032
commit
d528511249
@ -16,7 +16,7 @@ type MH = MusicHoard<NoLibrary, JsonDatabase<JsonDatabaseFileBackend>>;
|
|||||||
struct Opt {
|
struct Opt {
|
||||||
#[structopt(
|
#[structopt(
|
||||||
long = "database",
|
long = "database",
|
||||||
name = "database file path",
|
help = "Database file path",
|
||||||
default_value = "database.json"
|
default_value = "database.json"
|
||||||
)]
|
)]
|
||||||
database_file_path: PathBuf,
|
database_file_path: PathBuf,
|
||||||
|
39
src/lib.rs
39
src/lib.rs
@ -788,46 +788,35 @@ impl<LIB: ILibrary, DB: IDatabase> MusicHoard<LIB, DB> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn rescan_library(&mut self) -> Result<(), Error> {
|
pub fn rescan_library(&mut self) -> Result<(), Error> {
|
||||||
match self.library {
|
if let Some(ref mut library) = self.library {
|
||||||
Some(ref mut library) => {
|
|
||||||
let items = library.list(&Query::new())?;
|
let items = library.list(&Query::new())?;
|
||||||
let mut library_collection = Self::items_to_artists(items);
|
let mut library_collection = Self::items_to_artists(items);
|
||||||
Self::sort(&mut library_collection);
|
Self::sort(&mut library_collection);
|
||||||
|
|
||||||
let collection = mem::take(&mut self.collection);
|
let collection = mem::take(&mut self.collection);
|
||||||
self.collection = Self::merge(library_collection, collection);
|
self.collection = Self::merge(library_collection, collection);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
None => Err(Error::LibraryError(String::from("library not provided"))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load_from_database(&mut self) -> Result<(), Error> {
|
pub fn load_from_database(&mut self) -> Result<(), Error> {
|
||||||
match self.database {
|
if let Some(ref mut database) = self.database {
|
||||||
Some(ref mut database) => {
|
|
||||||
let mut database_collection: Collection = vec![];
|
let mut database_collection: Collection = vec![];
|
||||||
database.load(&mut database_collection)?;
|
database.load(&mut database_collection)?;
|
||||||
Self::sort(&mut database_collection);
|
Self::sort(&mut database_collection);
|
||||||
|
|
||||||
let collection = mem::take(&mut self.collection);
|
let collection = mem::take(&mut self.collection);
|
||||||
self.collection = Self::merge(collection, database_collection);
|
self.collection = Self::merge(collection, database_collection);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
None => Err(Error::DatabaseError(String::from("database not provided"))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn save_to_database(&mut self) -> Result<(), Error> {
|
pub fn save_to_database(&mut self) -> Result<(), Error> {
|
||||||
match self.database {
|
if let Some(ref mut database) = self.database {
|
||||||
Some(ref mut database) => {
|
|
||||||
database.save(&self.collection)?;
|
database.save(&self.collection)?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
None => Err(Error::DatabaseError(String::from("database not provided"))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_artist<ID: Into<ArtistId>>(&mut self, artist_id: ID) {
|
pub fn add_artist<ID: Into<ArtistId>>(&mut self, artist_id: ID) {
|
||||||
let artist_id: ArtistId = artist_id.into();
|
let artist_id: ArtistId = artist_id.into();
|
||||||
@ -1963,10 +1952,7 @@ mod tests {
|
|||||||
let database = Some(MockIDatabase::new());
|
let database = Some(MockIDatabase::new());
|
||||||
let mut music_hoard = MusicHoard::new(library, database);
|
let mut music_hoard = MusicHoard::new(library, database);
|
||||||
|
|
||||||
let actual_err = music_hoard.rescan_library().unwrap_err();
|
assert!(music_hoard.rescan_library().is_ok());
|
||||||
let expected_err = Error::LibraryError(String::from("library not provided"));
|
|
||||||
|
|
||||||
assert_eq!(actual_err, expected_err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1997,15 +1983,8 @@ mod tests {
|
|||||||
let database: Option<NoDatabase> = None;
|
let database: Option<NoDatabase> = None;
|
||||||
let mut music_hoard = MusicHoard::new(library, database);
|
let mut music_hoard = MusicHoard::new(library, database);
|
||||||
|
|
||||||
let expected_err = Error::DatabaseError(String::from("database not provided"));
|
assert!(music_hoard.load_from_database().is_ok());
|
||||||
|
assert!(music_hoard.save_to_database().is_ok());
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
59
src/main.rs
59
src/main.rs
@ -2,6 +2,8 @@ use std::fs::OpenOptions;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::{ffi::OsString, io};
|
use std::{ffi::OsString, io};
|
||||||
|
|
||||||
|
use musichoard::database::NoDatabase;
|
||||||
|
use musichoard::library::NoLibrary;
|
||||||
use musichoard::Collection;
|
use musichoard::Collection;
|
||||||
use ratatui::{backend::CrosstermBackend, Terminal};
|
use ratatui::{backend::CrosstermBackend, Terminal};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
@ -27,22 +29,28 @@ use tui::{event::EventChannel, handler::EventHandler, listener::EventListener, T
|
|||||||
|
|
||||||
#[derive(StructOpt)]
|
#[derive(StructOpt)]
|
||||||
struct Opt {
|
struct Opt {
|
||||||
#[structopt(long = "ssh", name = "beets SSH URI")]
|
#[structopt(long = "ssh", help = "Beets SSH URI")]
|
||||||
beets_ssh_uri: Option<OsString>,
|
beets_ssh_uri: Option<OsString>,
|
||||||
|
|
||||||
#[structopt(long = "beets", name = "beets config file path")]
|
#[structopt(long = "beets", help = "Beets config file path")]
|
||||||
beets_config_file_path: Option<OsString>,
|
beets_config_file_path: Option<OsString>,
|
||||||
|
|
||||||
|
#[structopt(long = "no-library", help = "Do not connect to the library")]
|
||||||
|
no_library: bool,
|
||||||
|
|
||||||
#[structopt(
|
#[structopt(
|
||||||
long = "database",
|
long = "database",
|
||||||
name = "database file path",
|
help = "Database file path",
|
||||||
default_value = "database.json"
|
default_value = "database.json"
|
||||||
)]
|
)]
|
||||||
database_file_path: PathBuf,
|
database_file_path: PathBuf,
|
||||||
|
|
||||||
|
#[structopt(long = "no-database", help = "Do not read from/write to the database")]
|
||||||
|
no_database: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with<LIB: ILibrary, DB: IDatabase>(lib: LIB, db: DB) {
|
fn with<LIB: ILibrary, DB: IDatabase>(lib: Option<LIB>, db: Option<DB>) {
|
||||||
let music_hoard = MusicHoard::new(Some(lib), Some(db));
|
let music_hoard = MusicHoard::new(lib, db);
|
||||||
|
|
||||||
// Initialize the terminal user interface.
|
// Initialize the terminal user interface.
|
||||||
let backend = CrosstermBackend::new(io::stdout());
|
let backend = CrosstermBackend::new(io::stdout());
|
||||||
@ -58,9 +66,32 @@ fn with<LIB: ILibrary, DB: IDatabase>(lib: LIB, db: DB) {
|
|||||||
Tui::run(terminal, ui, handler, listener).expect("failed to run tui");
|
Tui::run(terminal, ui, handler, listener).expect("failed to run tui");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn with_database<DB: IDatabase>(opt: Opt, db: Option<DB>) {
|
||||||
|
if opt.no_library {
|
||||||
|
with(None::<NoLibrary>, 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
|
||||||
|
.map(|s| s.into_string())
|
||||||
|
.transpose()
|
||||||
|
.expect("failed to extract beets config file path");
|
||||||
|
let lib_exec = BeetsLibrarySshExecutor::new(uri)
|
||||||
|
.expect("failed to initialise beets")
|
||||||
|
.config(beets_config_file_path);
|
||||||
|
with(Some(BeetsLibrary::new(lib_exec)), db);
|
||||||
|
} else {
|
||||||
|
let lib_exec = BeetsLibraryProcessExecutor::default().config(opt.beets_config_file_path);
|
||||||
|
with(Some(BeetsLibrary::new(lib_exec)), db);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let opt = Opt::from_args();
|
let opt = Opt::from_args();
|
||||||
|
|
||||||
|
if opt.no_database {
|
||||||
|
with_database(opt, None::<NoDatabase>);
|
||||||
|
} else {
|
||||||
// Create an empty database file if it does not exist.
|
// Create an empty database file if it does not exist.
|
||||||
match OpenOptions::new()
|
match OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
@ -79,23 +110,9 @@ fn main() {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the application.
|
|
||||||
let db_exec = JsonDatabaseFileBackend::new(&opt.database_file_path);
|
let db_exec = JsonDatabaseFileBackend::new(&opt.database_file_path);
|
||||||
if let Some(uri) = opt.beets_ssh_uri {
|
with_database(opt, Some(JsonDatabase::new(db_exec)));
|
||||||
let uri = uri.into_string().expect("invalid SSH URI");
|
};
|
||||||
let beets_config_file_path = opt
|
|
||||||
.beets_config_file_path
|
|
||||||
.map(|s| s.into_string())
|
|
||||||
.transpose()
|
|
||||||
.expect("failed to extract beets config file path");
|
|
||||||
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));
|
|
||||||
} else {
|
|
||||||
let lib_exec = BeetsLibraryProcessExecutor::default().config(opt.beets_config_file_path);
|
|
||||||
with(BeetsLibrary::new(lib_exec), JsonDatabase::new(db_exec));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
Loading…
Reference in New Issue
Block a user