use std::path::PathBuf; use std::{ffi::OsString, io}; use ratatui::{backend::CrosstermBackend, Terminal}; use structopt::StructOpt; use musichoard::{ collection::MhCollectionManager, database::{ json::{backend::JsonDatabaseFileBackend, JsonDatabase}, Database, }, library::{ beets::{ executor::{ssh::BeetsLibrarySshExecutor, BeetsLibraryProcessExecutor}, BeetsLibrary, }, Library, }, }; mod tui; use tui::ui::MhUi; use tui::{event::EventChannel, handler::TuiEventHandler, listener::TuiEventListener, Tui}; #[derive(StructOpt)] struct Opt { #[structopt(long = "ssh", name = "beets SSH URI")] beets_ssh_uri: Option, #[structopt(long = "beets", name = "beets config file path")] beets_config_file_path: Option, #[structopt( long = "database", name = "database file path", default_value = "database.json" )] database_file_path: PathBuf, } fn with(lib: LIB, db: DB) { let collection_manager = MhCollectionManager::new(lib, db); // Initialize the terminal user interface. let backend = CrosstermBackend::new(io::stdout()); let terminal = Terminal::new(backend).expect("failed to initialise terminal"); let channel = EventChannel::new(); let listener = TuiEventListener::new(channel.sender()); let handler = TuiEventHandler::new(channel.receiver()); let ui = MhUi::new(collection_manager).expect("failed to initialise ui"); // Run the TUI application. Tui::run(terminal, ui, handler, listener).expect("failed to run tui"); } fn main() { // Create the application. let opt = Opt::from_args(); 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); let db_exec = JsonDatabaseFileBackend::new(&opt.database_file_path); with(BeetsLibrary::new(lib_exec), JsonDatabase::new(db_exec)); } else { let lib_exec = BeetsLibraryProcessExecutor::default().config(opt.beets_config_file_path); let db_exec = JsonDatabaseFileBackend::new(&opt.database_file_path); with(BeetsLibrary::new(lib_exec), JsonDatabase::new(db_exec)); } } #[cfg(test)] #[macro_use] mod testlib; #[cfg(test)] mod tests { use mockall::mock; use once_cell::sync::Lazy; use musichoard::collection::{self, Collection, CollectionManager}; use musichoard::*; pub static COLLECTION: Lazy> = Lazy::new(|| collection!()); mock! { pub CollectionManager {} impl CollectionManager for CollectionManager { fn rescan_library(&mut self) -> Result<(), collection::Error>; fn save_to_database(&mut self) -> Result<(), collection::Error>; fn get_collection(&self) -> &Collection; } } }