Credentials helper if config not present or unparseable

Fixes #1
This commit is contained in:
Michael Edwards
2019-03-27 22:35:31 +01:00
committed by Henrik Friedrichsen
parent 58f34b9288
commit d78e71871a
5 changed files with 248 additions and 26 deletions

View File

@@ -1,6 +1,6 @@
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use directories::ProjectDirs;
@@ -8,8 +8,6 @@ pub const CLIENT_ID: &str = "d420a117a32841c2b3474932e49fb54b";
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct Config {
pub username: String,
pub password: String,
pub keybindings: Option<HashMap<String, String>>,
pub theme: Option<ConfigTheme>,
pub use_nerdfont: Option<bool>,
@@ -42,7 +40,7 @@ pub fn config_path(file: &str) -> PathBuf {
let proj_dirs = proj_dirs();
let cfg_dir = proj_dirs.config_dir();
trace!("{:?}", cfg_dir);
if !cfg_dir.is_dir() {
if cfg_dir.exists() && !cfg_dir.is_dir() {
fs::remove_file(cfg_dir).expect("unable to remove old config file");
}
if !cfg_dir.exists() {
@@ -63,3 +61,54 @@ pub fn cache_path(file: &str) -> PathBuf {
pb.push(file);
pb
}
/// Configuration and credential file helper
/// Creates a default configuration if none exist, otherwise will optionally overwrite
/// the file if it fails to parse
pub fn load_or_generate_default<
P: AsRef<Path>,
T: serde::Serialize + serde::de::DeserializeOwned,
F: Fn(&Path) -> Result<T, String>,
>(
path: P,
default: F,
default_on_parse_failure: bool,
) -> Result<T, String> {
let path = path.as_ref();
// Nothing exists so just write the default and return it
if !path.exists() {
let value = default(&path)?;
return write_content_helper(&path, value);
}
// load the serialized content. Always report this failure
let contents = std::fs::read_to_string(&path)
.map_err(|e| format!("Unable to read {}: {}", path.to_string_lossy(), e))?;
// Deserialize the content, optionally fall back to default if it fails
let result = toml::from_str(&contents);
if default_on_parse_failure {
if let Err(_) = result {
let value = default(&path)?;
return write_content_helper(&path, value);
}
}
result.map_err(|e| format!("Unable to parse {}: {}", path.to_string_lossy(), e))
}
fn write_content_helper<P: AsRef<Path>, T: serde::Serialize>(
path: P,
value: T,
) -> Result<T, String> {
let content =
toml::to_string_pretty(&value).map_err(|e| format!("Failed serializing value: {}", e))?;
fs::write(path.as_ref(), content)
.map(|_| value)
.map_err(|e| {
format!(
"Failed writing content to {}: {}",
path.as_ref().display(),
e
)
})
}