refactor: move cli argument parsing to main

Command line arguments are part of the OS process and should be under
main.
This commit is contained in:
Thomas Frans
2023-05-24 00:02:43 +02:00
committed by Henrik Friedrichsen
parent ae090b6073
commit abffb3c2a9
4 changed files with 39 additions and 23 deletions

View File

@@ -1,7 +1,6 @@
use crate::{command, ipc, mpris, queue, spotify}; use crate::{command, ipc, mpris, queue, spotify};
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr;
use std::sync::Arc; use std::sync::Arc;
use cursive::event::EventTrigger; use cursive::event::EventTrigger;
@@ -11,7 +10,6 @@ use librespot_core::authentication::Credentials;
use librespot_core::cache::Cache; use librespot_core::cache::Cache;
use log::{error, info, trace}; use log::{error, info, trace};
use ncspot::program_arguments;
#[cfg(unix)] #[cfg(unix)]
use signal_hook::{consts::SIGHUP, consts::SIGTERM, iterator::Signals}; use signal_hook::{consts::SIGHUP, consts::SIGTERM, iterator::Signals};
@@ -90,27 +88,33 @@ pub struct Application {
} }
impl Application { impl Application {
pub fn new() -> Result<Self, String> { /// Create a new ncspot application.
let matches = program_arguments().get_matches(); ///
/// # Arguments
if let Some(filename) = matches.get_one::<String>("debug") { ///
setup_logging(filename).expect("can't setup logging"); /// * `debug_log_path` - Path where an optional debug log should be written to
/// * `configuration_base_path` - Path to the configuration directory
/// * `configuration_file_path` - Relative path to the configuration file inside the base path
pub fn new(
debug_log_path: Option<PathBuf>,
configuration_base_path: Option<PathBuf>,
configuration_file_path: Option<PathBuf>,
) -> Result<Self, String> {
if let Some(filename) = debug_log_path {
setup_logging(&filename.to_string_lossy()).expect("can't setup logging");
} }
if let Some(basepath) = matches.get_one::<String>("basepath") { if let Some(basepath) = configuration_base_path {
let path = PathBuf::from_str(basepath).expect("invalid path"); if !basepath.exists() {
if !path.exists() { fs::create_dir_all(&basepath).expect("could not create basepath directory");
fs::create_dir_all(&path).expect("could not create basepath directory");
} }
*config::BASE_PATH.write().unwrap() = Some(path); *config::BASE_PATH.write().unwrap() = Some(basepath);
} }
// Things here may cause the process to abort; we must do them before creating curses windows // Things here may cause the process to abort; we must do them before creating curses windows
// otherwise the error message will not be seen by a user // otherwise the error message will not be seen by a user
let config: Arc<crate::config::Config> = Arc::new(Config::new( let config: Arc<crate::config::Config> = Arc::new(Config::new(
matches configuration_file_path.unwrap_or("config.toml".into()),
.get_one::<String>("config")
.unwrap_or(&"config.toml".to_string()),
)); ));
let mut credentials = { let mut credentials = {
let cache = Cache::new(Some(config::cache_path("librespot")), None, None, None) let cache = Cache::new(Some(config::cache_path("librespot")), None, None, None)

View File

@@ -169,14 +169,14 @@ lazy_static! {
} }
pub struct Config { pub struct Config {
filename: String, filename: PathBuf,
values: RwLock<ConfigValues>, values: RwLock<ConfigValues>,
state: RwLock<UserState>, state: RwLock<UserState>,
} }
impl Config { impl Config {
pub fn new(filename: &str) -> Self { pub fn new(filename: PathBuf) -> Self {
let values = load(filename).unwrap_or_else(|e| { let values = load(&filename.to_string_lossy()).unwrap_or_else(|e| {
eprintln!("could not load config: {e}"); eprintln!("could not load config: {e}");
process::exit(1); process::exit(1);
}); });
@@ -200,7 +200,7 @@ impl Config {
} }
Self { Self {
filename: filename.to_string(), filename,
values: RwLock::new(values), values: RwLock::new(values),
state: RwLock::new(userstate), state: RwLock::new(userstate),
} }
@@ -239,7 +239,7 @@ impl Config {
} }
pub fn reload(&self) { pub fn reload(&self) {
let cfg = load(&self.filename).expect("could not reload config"); let cfg = load(&self.filename.to_string_lossy()).expect("could not reload config");
*self.values.write().expect("can't writelock config values") = cfg *self.values.write().expect("can't writelock config values") = cfg
} }
} }

View File

@@ -1,3 +1,4 @@
use clap::builder::PathBufValueParser;
use librespot_playback::audio_backend; use librespot_playback::audio_backend;
pub const AUTHOR: &str = "Henrik Friedrichsen <henrik@affekt.org> and contributors"; pub const AUTHOR: &str = "Henrik Friedrichsen <henrik@affekt.org> and contributors";
@@ -22,6 +23,7 @@ pub fn program_arguments() -> clap::Command {
.short('d') .short('d')
.long("debug") .long("debug")
.value_name("FILE") .value_name("FILE")
.value_parser(PathBufValueParser::new())
.help("Enable debug logging to the specified file"), .help("Enable debug logging to the specified file"),
) )
.arg( .arg(
@@ -29,6 +31,7 @@ pub fn program_arguments() -> clap::Command {
.short('b') .short('b')
.long("basepath") .long("basepath")
.value_name("PATH") .value_name("PATH")
.value_parser(PathBufValueParser::new())
.help("custom basepath to config/cache files"), .help("custom basepath to config/cache files"),
) )
.arg( .arg(
@@ -36,6 +39,7 @@ pub fn program_arguments() -> clap::Command {
.short('c') .short('c')
.long("config") .long("config")
.value_name("FILE") .value_name("FILE")
.value_parser(PathBufValueParser::new())
.help("Filename of config file in basepath") .help("Filename of config file in basepath")
.default_value("config.toml"), .default_value("config.toml"),
) )

View File

@@ -8,6 +8,10 @@ extern crate serde;
use std::backtrace; use std::backtrace;
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use std::path::PathBuf;
use application::Application;
use ncspot::program_arguments;
mod application; mod application;
mod authentication; mod authentication;
@@ -36,8 +40,6 @@ mod ipc;
#[cfg(feature = "mpris")] #[cfg(feature = "mpris")]
mod mpris; mod mpris;
use crate::application::Application;
/// Register a custom panic handler to write the backtrace to a file since stdout is in use by the /// Register a custom panic handler to write the backtrace to a file since stdout is in use by the
/// Cursive TUI library during most of the application. /// Cursive TUI library during most of the application.
fn register_backtrace_panic_handler() { fn register_backtrace_panic_handler() {
@@ -64,7 +66,13 @@ fn register_backtrace_panic_handler() {
fn main() -> Result<(), String> { fn main() -> Result<(), String> {
register_backtrace_panic_handler(); register_backtrace_panic_handler();
let mut application = Application::new()?; let matches = program_arguments().get_matches();
let mut application = Application::new(
matches.get_one::<PathBuf>("debug").cloned(),
matches.get_one::<PathBuf>("basepath").cloned(),
matches.get_one::<PathBuf>("config").cloned(),
)?;
application.run() application.run()
} }