Stuff!
This commit is contained in:
@ -1,11 +1,11 @@
|
||||
use crate::{ColorMode, Opt};
|
||||
use crate::{ColorMode, Config};
|
||||
use async_recursion::async_recursion;
|
||||
use futures::future::join_all;
|
||||
use handlebars::{Context, Handlebars};
|
||||
use serde::Serialize;
|
||||
use std::ffi::OsStr;
|
||||
use std::io::{self, ErrorKind};
|
||||
use std::path::PathBuf;
|
||||
use templar::{Context, InnerData, StandardContext, Templar};
|
||||
use tokio::fs::{copy, create_dir, read_dir, read_to_string, write};
|
||||
use tokio::try_join;
|
||||
|
||||
@ -16,27 +16,36 @@ struct TemplateContext<'a> {
|
||||
darkmode: bool,
|
||||
}
|
||||
|
||||
pub async fn build_tree(opt: &Opt) -> io::Result<()> {
|
||||
const TEMPLATE_EXTENSION: &str = "tpl";
|
||||
|
||||
pub async fn build_tree(cfg: &Config) -> io::Result<()> {
|
||||
let tpl = Templar::global();
|
||||
|
||||
let hostname = read_to_string("/etc/hostname").await?;
|
||||
let darkmode = cfg.color == ColorMode::Dark;
|
||||
let ctx = StandardContext::new();
|
||||
ctx.set(
|
||||
InnerData::new(TemplateContext {
|
||||
hostname: hostname.trim(),
|
||||
darkmode,
|
||||
lightmode: !darkmode,
|
||||
})
|
||||
.expect("serialize template context"),
|
||||
)
|
||||
.expect("set template context");
|
||||
|
||||
let darkmode = opt.color.map(|m| m == ColorMode::Dark).unwrap_or(true);
|
||||
|
||||
let hbs = Handlebars::new();
|
||||
|
||||
let ctx = Context::wraps(TemplateContext {
|
||||
hostname: hostname.trim(),
|
||||
darkmode,
|
||||
lightmode: !darkmode,
|
||||
})
|
||||
.expect("template context");
|
||||
|
||||
dir(opt, &ctx, &hbs, PathBuf::new()).await
|
||||
dir(cfg, &ctx, &tpl, PathBuf::new()).await
|
||||
}
|
||||
|
||||
#[async_recursion]
|
||||
async fn dir(opt: &Opt, ctx: &Context, hbs: &Handlebars<'_>, relative: PathBuf) -> io::Result<()> {
|
||||
let template_path = opt.template_dir.join(&relative);
|
||||
let build_path = opt.build_dir.join(&relative);
|
||||
async fn dir(
|
||||
cfg: &Config,
|
||||
ctx: &StandardContext,
|
||||
tpl: &Templar,
|
||||
relative: PathBuf,
|
||||
) -> io::Result<()> {
|
||||
let template_path = cfg.template_dir.join(&relative);
|
||||
let build_path = cfg.build_dir.join(&relative);
|
||||
|
||||
info!("traversing {:?}", template_path);
|
||||
|
||||
@ -56,9 +65,9 @@ async fn dir(opt: &Opt, ctx: &Context, hbs: &Handlebars<'_>, relative: PathBuf)
|
||||
let new_relative = relative.join(entry.file_name());
|
||||
|
||||
if meta.is_dir() {
|
||||
dir_tasks.push(dir(opt, ctx, hbs, new_relative));
|
||||
dir_tasks.push(dir(cfg, ctx, tpl, new_relative));
|
||||
} else if meta.is_file() {
|
||||
file_tasks.push(file(opt, ctx, hbs, new_relative));
|
||||
file_tasks.push(file(cfg, ctx, tpl, new_relative));
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,22 +90,28 @@ async fn dir(opt: &Opt, ctx: &Context, hbs: &Handlebars<'_>, relative: PathBuf)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn file(opt: &Opt, ctx: &Context, hbs: &Handlebars<'_>, relative: PathBuf) -> io::Result<()> {
|
||||
let template_path = opt.template_dir.join(&relative);
|
||||
let mut new_path = opt.build_dir.join(&relative);
|
||||
async fn file(
|
||||
cfg: &Config,
|
||||
ctx: &StandardContext,
|
||||
tpl: &Templar,
|
||||
relative: PathBuf,
|
||||
) -> io::Result<()> {
|
||||
let template_path = cfg.template_dir.join(&relative);
|
||||
let mut new_path = cfg.build_dir.join(&relative);
|
||||
|
||||
// if it is a handlebars file
|
||||
if template_path.extension() == Some(OsStr::new("hbs")) {
|
||||
info!("rendering {:?}", template_path);
|
||||
let file_data = read_to_string(&template_path).await?;
|
||||
info!("rendering {:?}", template_path);
|
||||
let file_data = read_to_string(&template_path).await?;
|
||||
|
||||
if template_path.extension() == Some(OsStr::new(TEMPLATE_EXTENSION)) {
|
||||
// perform templating
|
||||
// TODO: error handling
|
||||
let rendered = hbs
|
||||
.render_template_with_context(&file_data, &ctx)
|
||||
.expect("template error");
|
||||
let rendered = tpl
|
||||
.parse_template(&file_data)
|
||||
.expect("failed to parse template")
|
||||
.render(ctx)
|
||||
.expect("failed to render template");
|
||||
|
||||
// remove .hbs
|
||||
// remove template file extension
|
||||
new_path.set_extension("");
|
||||
|
||||
// write the rendered file
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::Opt;
|
||||
use crate::Config;
|
||||
use async_recursion::async_recursion;
|
||||
use futures::future::join_all;
|
||||
use std::io::{self, ErrorKind};
|
||||
@ -6,14 +6,14 @@ use std::path::PathBuf;
|
||||
use tokio::fs::{create_dir, read_dir, remove_file, symlink};
|
||||
use tokio::try_join;
|
||||
|
||||
pub async fn link_tree(opt: &Opt) -> io::Result<()> {
|
||||
dir(opt, PathBuf::new()).await
|
||||
pub async fn link_tree(cfg: &Config) -> io::Result<()> {
|
||||
dir(cfg, PathBuf::new()).await
|
||||
}
|
||||
|
||||
#[async_recursion]
|
||||
async fn dir(opt: &Opt, relative: PathBuf) -> io::Result<()> {
|
||||
let build_path = opt.build_dir.join(&relative);
|
||||
let link_path = opt.link_dir.join(&relative);
|
||||
async fn dir(cfg: &Config, relative: PathBuf) -> io::Result<()> {
|
||||
let build_path = cfg.build_dir.join(&relative);
|
||||
let link_path = cfg.link_dir.join(&relative);
|
||||
|
||||
info!("traversing {:?}", build_path);
|
||||
|
||||
@ -33,9 +33,9 @@ async fn dir(opt: &Opt, relative: PathBuf) -> io::Result<()> {
|
||||
let new_relative = relative.join(entry.file_name());
|
||||
|
||||
if meta.is_dir() {
|
||||
dir_tasks.push(dir(opt, new_relative));
|
||||
dir_tasks.push(dir(cfg, new_relative));
|
||||
} else if meta.is_file() {
|
||||
file_tasks.push(file(opt, new_relative));
|
||||
file_tasks.push(file(cfg, new_relative));
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,9 +58,9 @@ async fn dir(opt: &Opt, relative: PathBuf) -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn file(opt: &Opt, relative: PathBuf) -> io::Result<()> {
|
||||
let build_path = opt.build_dir.join(&relative);
|
||||
let link_path = opt.link_dir.join(&relative);
|
||||
async fn file(cfg: &Config, relative: PathBuf) -> io::Result<()> {
|
||||
let build_path = cfg.build_dir.join(&relative);
|
||||
let link_path = cfg.link_dir.join(&relative);
|
||||
|
||||
match remove_file(&link_path).await {
|
||||
Ok(_) => {
|
||||
|
||||
@ -6,21 +6,39 @@ mod linker;
|
||||
|
||||
use builder::build_tree;
|
||||
use linker::link_tree;
|
||||
use log::LevelFilter;
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use structopt::StructOpt;
|
||||
use tokio::io;
|
||||
|
||||
#[derive(StructOpt)]
|
||||
pub struct Opt {
|
||||
template_dir: PathBuf,
|
||||
build_dir: PathBuf,
|
||||
link_dir: PathBuf,
|
||||
struct Opt {
|
||||
#[structopt(short, long)]
|
||||
template_dir: Option<PathBuf>,
|
||||
|
||||
#[structopt(short, long)]
|
||||
build_dir: Option<PathBuf>,
|
||||
|
||||
#[structopt(short, long)]
|
||||
link_dir: Option<PathBuf>,
|
||||
|
||||
#[structopt(subcommand)]
|
||||
color: Option<ColorMode>,
|
||||
|
||||
#[structopt(short, parse(from_occurrences))]
|
||||
verbosity: u8,
|
||||
}
|
||||
|
||||
#[derive(StructOpt, PartialEq, Eq, Clone, Copy)]
|
||||
#[derive(Debug)]
|
||||
pub struct Config {
|
||||
template_dir: PathBuf,
|
||||
build_dir: PathBuf,
|
||||
link_dir: PathBuf,
|
||||
color: ColorMode,
|
||||
}
|
||||
|
||||
#[derive(StructOpt, PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub enum ColorMode {
|
||||
Dark,
|
||||
Light,
|
||||
@ -28,15 +46,39 @@ pub enum ColorMode {
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> io::Result<()> {
|
||||
pretty_env_logger::init();
|
||||
|
||||
let opt = Opt::from_args();
|
||||
|
||||
let filter_level = match opt.verbosity {
|
||||
0 => LevelFilter::Warn,
|
||||
1 => LevelFilter::Info,
|
||||
2 => LevelFilter::Debug,
|
||||
_ => LevelFilter::Trace,
|
||||
};
|
||||
|
||||
pretty_env_logger::formatted_builder()
|
||||
.filter_level(filter_level)
|
||||
.init();
|
||||
|
||||
let xdg_dirs = xdg::BaseDirectories::with_prefix("dotfiles").unwrap();
|
||||
|
||||
let cfg = Config {
|
||||
template_dir: opt
|
||||
.template_dir
|
||||
.unwrap_or_else(|| xdg_dirs.create_config_directory("tree").expect("xdg")),
|
||||
build_dir: opt
|
||||
.build_dir
|
||||
.unwrap_or_else(|| xdg_dirs.create_cache_directory("").expect("xdg")),
|
||||
link_dir: opt
|
||||
.link_dir
|
||||
.unwrap_or_else(|| env::var("HOME").expect("$HOME").into()),
|
||||
color: opt.color.unwrap_or(ColorMode::Dark),
|
||||
};
|
||||
|
||||
info!("building tree");
|
||||
build_tree(&opt).await?;
|
||||
build_tree(&cfg).await?;
|
||||
|
||||
info!("linking tree");
|
||||
link_tree(&opt).await?;
|
||||
link_tree(&cfg).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user