panres/src/main.rs

106 lines
3.3 KiB
Rust

#![forbid(unsafe_code)]
#[macro_use]
extern crate clap;
extern crate notify;
extern crate serde;
extern crate serde_json;
extern crate tera;
use clap::{App, AppSettings, Arg, Values};
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use serde_json::{from_str, Value};
use std::{
env,
error::Error,
fs::{create_dir_all, read_dir, read_to_string, write},
sync::mpsc::channel,
time::Duration,
};
use tera::{Context, Tera};
const DEFAULT_TEMPLATE_DIR: &'static str = "templates";
const DEFAULT_OUTPUT_DIR: &'static str = "output";
fn main() -> Result<(), Box<Error>> {
let config: Value = from_str(&read_to_string("config.json")?)?;
let template_dir =
&env::var("PANRES_TEMPLATE_DIR").unwrap_or_else(|_| String::from(DEFAULT_TEMPLATE_DIR));
let matches = App::new("panres")
.version(crate_version!())
.author(crate_authors!())
.about("Universal resume formatter")
.arg(Arg::with_name("watch").short("w").help("Watch for changes"))
.arg(
Arg::with_name("output-format")
.help("Specifies which output format you want")
.required(true)
.multiple(true),
)
.settings(&[AppSettings::ArgRequiredElseHelp])
.get_matches();
let tera = &mut Tera::new(&format!("{}/**/*", template_dir))?;
let context = &mut Context::new();
context.insert("config", &config);
let outputs = matches.values_of("output-format").unwrap_or_default();
if matches.is_present("watch") {
let (tx, rx) = channel();
let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
watcher.watch(template_dir, RecursiveMode::Recursive)?;
loop {
match rx.recv() {
Err(e) => println!("{}", e),
Ok(notify::DebouncedEvent::NoticeWrite(msg))
| Ok(notify::DebouncedEvent::NoticeRemove(msg))
| Ok(notify::DebouncedEvent::Chmod(msg))
| Ok(notify::DebouncedEvent::Remove(msg))
| Ok(notify::DebouncedEvent::Rename(_, msg)) => {
println!("Reloading: {:?}", msg);
tera.full_reload()?;
output(tera, context, outputs.clone(), template_dir)?;
},
Ok(notify::DebouncedEvent::Rescan) => {
println!("notify emitted rescan event!");
},
_ => (),
}
}
}
output(tera, context, outputs, template_dir)?;
Ok(())
}
fn output<'a>(
engine: &Tera,
context: &Context,
outputs: Values,
template_dir: &'a str,
) -> Result<(), Box<Error>> {
if outputs.clone().any(|e| e == "all") {
for output in read_dir(template_dir)? {
generate_output(engine, context, &output?.file_name().to_str().unwrap())?;
}
} else {
for output in outputs {
generate_output(engine, context, &output)?;
}
}
Ok(())
}
fn generate_output(engine: &Tera, context: &Context, format: &str) -> Result<(), Box<Error>> {
create_dir_all(DEFAULT_OUTPUT_DIR).expect("Could not create output dir");
write(
format!("{}/{}", DEFAULT_OUTPUT_DIR, format),
engine.render(format, context.clone())?,
)
.expect("to be able to write to output folder");
Ok(())
}