summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs47
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(())
+ }
+}