diff options
Diffstat (limited to 'src/main.rs')
-rw-r--r-- | src/main.rs | 47 |
1 files changed, 46 insertions, 1 deletions
diff --git a/src/main.rs b/src/main.rs index 2d847dd..8ea2a45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::path::{Path, PathBuf}; use structopt::StructOpt; +use tempfile::NamedTempFile; const APP: &str = "clab"; @@ -27,6 +28,7 @@ fn main() -> anyhow::Result<()> { Cmd::Search(x) => x.run(&opt, &book)?, Cmd::Tagged(x) => x.run(&opt, &book)?, Cmd::MuttQuery(x) => x.run(&opt, &book), + Cmd::Reformat(x) => x.run(&opt, &book)?, } Ok(()) } @@ -35,14 +37,23 @@ fn main() -> anyhow::Result<()> { #[serde(deny_unknown_fields)] struct Entry { name: String, + #[serde(skip_serializing_if = "Option::is_none")] org: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] url: Option<Vec<String>>, + #[serde(skip_serializing_if = "Option::is_none")] notes: Option<String>, + #[serde(skip_serializing_if = "Option::is_none")] aliases: Option<Vec<String>>, + #[serde(skip_serializing_if = "Option::is_none")] email: Option<HashMap<String, String>>, + #[serde(skip_serializing_if = "Option::is_none")] phone: Option<HashMap<String, String>>, + #[serde(skip_serializing_if = "Option::is_none")] irc: Option<HashMap<String, String>>, + #[serde(skip_serializing_if = "Option::is_none")] address: Option<HashMap<String, String>>, + #[serde(skip_serializing_if = "Option::is_none")] tags: Option<Vec<String>>, last_checked: String, } @@ -77,16 +88,24 @@ fn contains(haystack: &str, needle: &str) -> bool { #[derive(std::default::Default)] struct AddressBook { + filename: PathBuf, entries: Vec<Entry>, } impl AddressBook { fn load(db: &Path) -> anyhow::Result<Self> { - let mut book = Self::default(); + let mut book = Self { + filename: db.to_path_buf(), + entries: vec![], + }; book.add_from(db)?; Ok(book) } + fn filename(&self) -> &Path { + &self.filename + } + fn add_from(&mut self, filename: &Path) -> anyhow::Result<()> { let text = std::fs::read(&filename)?; let mut entries: Vec<Entry> = serde_yaml::from_slice(&text)?; @@ -120,6 +139,7 @@ enum Cmd { Search(SearchCommand), Tagged(TaggedCommand), MuttQuery(MuttCommand), + Reformat(Reformat), } #[derive(Debug, StructOpt)] @@ -226,3 +246,28 @@ impl MuttCommand { entry.is_match(&self.word) } } + +#[derive(Debug, StructOpt)] +struct Reformat { + #[structopt(short, long)] + stdout: bool, +} + +impl Reformat { + fn run(&self, _opt: &Opt, book: &AddressBook) -> anyhow::Result<()> { + if self.stdout { + serde_yaml::to_writer(std::io::stdout(), book.entries())?; + } else { + let filename = book.filename(); + let dirname = match filename.parent() { + None => Path::new("/"), + Some(x) if x.display().to_string().is_empty() => Path::new("."), + Some(x) => x, + }; + let temp = NamedTempFile::new_in(dirname)?; + serde_yaml::to_writer(&temp, book.entries())?; + std::fs::rename(temp.path(), filename)?; + } + Ok(()) + } +} |