config: Make YAML/JSON modular and optional (#21)

This commit is contained in:
Sergey Smirnykh
2019-10-02 16:21:39 +02:00
committed by Kenny Levinsen
parent c02937d8b6
commit c695288d1e
4 changed files with 119 additions and 35 deletions
+8 -4
View File
@@ -8,12 +8,15 @@ edition = "2018"
lto = "fat"
[features]
default = ["alsa-widget", "pulseaudio-widget"]
default = ["alsa-widget", "pulseaudio-widget", "yaml-cfg", "json-cfg"]
damage_debug = []
yaml-cfg = ["serde_yaml"]
json-cfg = ["serde_json"]
alsa-widget = ["alsa"]
pulseaudio-widget = ["libpulse-binding"]
[dependencies]
smithay-client-toolkit = "0.6.4"
byteorder = "1.3"
@@ -30,9 +33,10 @@ lazy_static = "1.4"
rcalc_lib = { version = "0.9" }
rust-ini = "0.13"
shlex = "0.1"
serde_json = "1.0"
serde_yaml = "0.8"
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", optional = true }
serde_yaml = { version = "0.8", optional = true }
libpulse-binding = { version = "2.11", optional = true }
alsa = { version = "0.3.0", optional = true }
+61
View File
@@ -0,0 +1,61 @@
use serde::{de::DeserializeOwned, Serialize};
use std::io::BufRead;
pub enum ConfigFmt {
#[cfg(feature = "yaml-cfg")]
Yaml,
#[cfg(feature = "json-cfg")]
Json,
}
pub const CONFIG_NAMES: &'static [&'static str] = &[
#[cfg(feature = "yaml-cfg")]
"config.yaml",
#[cfg(feature = "json-cfg")]
"config.json",
];
impl ConfigFmt {
#[inline]
pub fn new(ext: &str) -> Option<Self> {
match ext {
#[cfg(feature = "yaml-cfg")]
"yaml" => Some(ConfigFmt::Yaml),
#[cfg(feature = "json-cfg")]
"json" => Some(ConfigFmt::Json),
_ => None,
}
}
#[inline]
pub fn from_reader<B: BufRead, T: DeserializeOwned>(&self, r: B) -> T {
match self {
#[cfg(feature = "yaml-cfg")]
ConfigFmt::Yaml => serde_yaml::from_reader(r).unwrap(),
#[cfg(feature = "json-cfg")]
ConfigFmt::Json => serde_json::from_reader(r).unwrap(),
}
}
#[inline]
pub fn to_string<T: Serialize + ?Sized>(&self, src: &T) -> String {
match self {
#[cfg(feature = "yaml-cfg")]
ConfigFmt::Yaml => serde_yaml::to_string(&src).unwrap(),
#[cfg(feature = "json-cfg")]
ConfigFmt::Json => serde_json::to_string_pretty(&src).unwrap(),
}
}
}
impl Default for ConfigFmt {
fn default() -> Self {
// attributes require curly braces to work
#[cfg(feature = "yaml-cfg")]
{
ConfigFmt::Yaml
}
#[cfg(all(feature = "json-cfg", not(feature = "yaml-cfg")))]
{
ConfigFmt::Json
}
}
}
+44 -25
View File
@@ -1,4 +1,3 @@
use std::default::Default;
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader, Read, Write};
@@ -14,6 +13,7 @@ mod buffer;
mod cmd;
mod color;
mod config;
mod configfmt;
mod desktop;
mod doublemempool;
mod draw;
@@ -22,13 +22,15 @@ mod widgets;
use app::{App, OutputMode};
use cmd::Cmd;
use config::Config;
use configfmt::ConfigFmt;
enum Mode {
Start,
Daemonize,
StartOrKill,
ToggleVisible,
PrintConfig(bool),
PrintConfig(ConfigFmt),
}
fn main() {
@@ -44,40 +46,61 @@ fn main() {
},
};
let (is_yaml, config): (bool, config::Config) = match File::open(config_home.clone() + "/config.yaml") {
Ok(f) => {
let reader = BufReader::new(f);
(true, serde_yaml::from_reader(reader).unwrap())
// From all existing files take the first readable one and write it's extension to `ext`
let mut ext = [0x0; 8];
let file = configfmt::CONFIG_NAMES
.iter()
.map(|name| std::path::Path::new(&config_home).join(name))
.filter_map(|path| {
match File::open(&path) {
Ok(file) => {
let e = path.extension().and_then(|e| e.to_str())?;
let len = e.len();
let from = len.saturating_sub(8); // the longest possible extension
ext[0..len - from].copy_from_slice(&e.as_bytes()[from..]);
Some(file)
}
Err(_) => match File::open(config_home + "/config.json") {
Ok(f) => {
let reader = BufReader::new(f);
(false, serde_json::from_reader(reader).unwrap())
Err(_) => None,
}
Err(_) => (true, Default::default()),
}
};
})
.next();
let fmt = std::str::from_utf8(&ext)
.ok()
.and_then(ConfigFmt::new)
.unwrap_or_default();
let config: Config = file
.map(|f| fmt.from_reader(BufReader::new(f)))
.unwrap_or_default();
let scale = config.scale;
let mut args = env::args();
let _ = args.next();
let mode = match args.next() {
Some(arg) => {
match arg.as_str() {
Some(arg) => match arg.as_str() {
"start" => Mode::Daemonize,
"start-or-kill" => Mode::StartOrKill,
"toggle-visible" => Mode::ToggleVisible,
"print-config" => Mode::PrintConfig(!is_yaml),
"print-config-json" => Mode::PrintConfig(true),
"print-config-yaml" => Mode::PrintConfig(false),
"print-config" => Mode::PrintConfig(fmt),
s => {
let p = "print-config-";
let l = p.len();
let fmt = if s.starts_with(p) {
ConfigFmt::new(&s[l..])
} else {
None
};
if let Some(fmt) = fmt {
Mode::PrintConfig(fmt)
} else {
eprintln!("unsupported sub-command {}", s);
std::process::exit(1);
}
}
},
None => Mode::Start
None => Mode::Start,
};
if let Some(_) = args.next() {
// total = args.count + 2 (the two we skipped + the rest)
@@ -115,12 +138,8 @@ fn main() {
};
daemon = true;
}
Mode::PrintConfig(json) => {
if json {
println!("{}", serde_json::to_string_pretty(&config).unwrap());
} else {
println!("{}", serde_yaml::to_string(&config).unwrap());
}
Mode::PrintConfig(fmt) => {
println!("{}", fmt.to_string(&config));
std::process::exit(0);
}
}
+1 -1
View File
@@ -6,5 +6,5 @@ pub mod clock;
pub mod date;
pub mod launcher;
#[allow(dead_code)]
#[cfg(any(feature="alsa-widget", feature="pulseaudio-widget"))]
pub mod audio;