From cef350fca211f5a16a25455d6ea5122e871b1436 Mon Sep 17 00:00:00 2001 From: Thomas Heck Date: Sun, 8 Nov 2020 16:21:27 +0100 Subject: [PATCH] improve configurability --- Cargo.toml | 5 ++- src/config.rs | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 7 ++-- 3 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 src/config.rs diff --git a/Cargo.toml b/Cargo.toml index 95c0c25..004ffdd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,7 @@ futures = "0.3" num_cpus = "1" walkdir = "2" libc = "0.2" -anyhow = "1" \ No newline at end of file +anyhow = "1" +clap = "2" +serde = { version = "1.0", features = ["derive"] } +serde_yaml = "0.8" diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..6a5ae2c --- /dev/null +++ b/src/config.rs @@ -0,0 +1,103 @@ +use anyhow::{Context, Error, Result}; +use serde::{Deserialize, Serialize}; +use std::path::{Path, PathBuf}; + +#[derive(Debug)] +pub struct Config { + pub from: PathBuf, + pub to: PathBuf, +} + +#[derive(Debug, Default, Serialize, Deserialize)] +struct ConfigFile { + pub from: Option, + pub to: Option, +} + +pub fn config() -> Result { + use clap::Arg; + + let matches = clap::App::new("audio-conv") + .version(clap::crate_version!()) + .about("Converts audio files") + .arg( + Arg::with_name("config") + .short("c") + .long("config") + .required(false) + .takes_value(true) + .help("path to an audio-conv config file, defaults to \"audio-conv.yaml\""), + ) + .arg( + Arg::with_name("from") + .short("f") + .long("from") + .required(false) + .takes_value(true) + .help("from directory path"), + ) + .arg( + Arg::with_name("to") + .short("t") + .long("to") + .required(false) + .takes_value(true) + .help("to directory path"), + ) + .get_matches(); + + let current_dir = std::env::current_dir().context("could not get current directory")?; + + let config_path = matches.value_of_os("config"); + let force_load = config_path.is_some(); + let config_path = config_path + .map(AsRef::::as_ref) + .unwrap_or_else(|| AsRef::::as_ref("audio-conv.yaml")); + let config_path = current_dir.join(config_path); + + let config_file = load_config_file(&config_path) + .with_context(|| format!("failed loading config file \"{}\"", config_path.display()))?; + + if force_load && config_file.is_none() { + return Err(Error::msg(format!( + "could not find config file \"{}\"", + config_path.display() + ))); + } + + Ok(Config { + from: matches + .value_of_os("from") + .map(AsRef::::as_ref) + .or_else(|| { + config_file + .as_ref() + .map(|c| c.from.as_ref().map(AsRef::as_ref)) + .flatten() + }) + .map(|p| current_dir.join(p)) + .ok_or_else(|| Error::msg("\"from\" not configured"))?, + to: matches + .value_of_os("to") + .map(AsRef::::as_ref) + .or_else(|| { + config_file + .as_ref() + .map(|c| c.to.as_ref().map(AsRef::as_ref)) + .flatten() + }) + .map(|p| current_dir.join(p)) + .ok_or_else(|| Error::msg("\"to\" not configured"))?, + }) +} + +fn load_config_file(path: &Path) -> Result> { + let mut file = match std::fs::File::open(path) { + Ok(file) => file, + Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None), + Err(err) => return Err(Error::new(err)), + }; + let config: ConfigFile = + serde_yaml::from_reader(&mut file).context("could not read config file")?; + Ok(Some(config)) +} diff --git a/src/main.rs b/src/main.rs index 46010bd..fd45da5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +mod config; + use anyhow::{Context, Result}; use futures::{channel::mpsc, prelude::*}; use glib::GString; @@ -54,14 +56,13 @@ fn get_path_pairs(input: PathBuf, output: PathBuf) -> impl Iterator Result<()> { gstreamer::init()?; - let input = std::env::args().nth(1).context("missing input")?; - let output = std::env::args().nth(2).context("missing output")?; + let config = config::config().context("could not get the config")?; let (pair_tx, pair_rx) = mpsc::channel(16); // move blocking directory reading to an external thread let pair_producer = std::thread::spawn(|| { - let produce_pairs = futures::stream::iter(get_path_pairs(input.into(), output.into())) + let produce_pairs = futures::stream::iter(get_path_pairs(config.from, config.to)) .map(Ok) .forward(pair_tx) .map(|res| res.context("sending path pairs failed"));