use std::collections::HashMap;
use anyhow::bail;
use log::debug;
use serde_derive::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct Global {
pub author: libpijul::change::Author,
pub unrecord_changes: Option<usize>,
}
const CONFIG_DIR: &str = "pijul";
impl Global {
pub fn load() -> Result<Global, anyhow::Error> {
if let Some(mut dir) = dirs_next::config_dir() {
dir.push(CONFIG_DIR);
dir.push("config.toml");
let s = std::fs::read(&dir)
.or_else(|e| {
if let Some(mut dir) = dirs_next::home_dir() {
dir.push(".config");
dir.push(CONFIG_DIR);
dir.push("config.toml");
std::fs::read(&dir)
} else {
Err(e.into())
}
})
.or_else(|e| {
if let Some(mut dir) = dirs_next::home_dir() {
dir.push(".pijulconfig");
std::fs::read(&dir)
} else {
Err(e.into())
}
})?;
debug!("s = {:?}", s);
if let Ok(t) = toml::from_slice(&s) {
Ok(t)
} else {
bail!("Could not read configuration file at {:?}", dir)
}
} else {
bail!("Global configuration file missing")
}
}
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct Config {
pub current_channel: Option<String>,
pub default_remote: Option<String>,
#[serde(default)]
pub remotes: HashMap<String, String>,
#[serde(default)]
pub hooks: Hooks,
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct Hooks {
#[serde(default)]
pub record: Vec<String>,
}
impl Config {
pub fn get_current_channel<'a>(&'a self, alt: Option<&'a String>) -> &'a str {
if let Some(channel) = alt {
channel.as_ref()
} else if let Some(ref channel) = self.current_channel {
channel.as_str()
} else {
crate::DEFAULT_CHANNEL
}
}
pub fn current_channel(&self) -> Option<&str> {
if let Some(ref channel) = self.current_channel {
Some(channel.as_str())
} else {
None
}
}
}
#[derive(Debug, Serialize, Deserialize)]
struct Remote_ {
ssh: Option<SshRemote>,
local: Option<String>,
url: Option<String>,
}
#[derive(Debug)]
pub enum Remote {
Ssh(SshRemote),
Local { local: String },
Http { url: String },
None,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SshRemote {
pub addr: String,
}
impl<'de> serde::Deserialize<'de> for Remote {
fn deserialize<D>(deserializer: D) -> Result<Remote, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let r = Remote_::deserialize(deserializer)?;
if let Some(ssh) = r.ssh {
Ok(Remote::Ssh(ssh))
} else if let Some(local) = r.local {
Ok(Remote::Local { local })
} else if let Some(url) = r.url {
Ok(Remote::Http { url })
} else {
Ok(Remote::None)
}
}
}
impl serde::Serialize for Remote {
fn serialize<D>(&self, serializer: D) -> Result<D::Ok, D::Error>
where
D: serde::ser::Serializer,
{
let r = match *self {
Remote::Ssh(ref ssh) => Remote_ {
ssh: Some(ssh.clone()),
local: None,
url: None,
},
Remote::Local { ref local } => Remote_ {
local: Some(local.to_string()),
ssh: None,
url: None,
},
Remote::Http { ref url } => Remote_ {
local: None,
ssh: None,
url: Some(url.to_string()),
},
Remote::None => Remote_ {
local: None,
ssh: None,
url: None,
},
};
r.serialize(serializer)
}
}