diff --git a/Cargo.lock b/Cargo.lock index d259d83..8f950fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,15 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" version = "0.6.5" @@ -222,6 +231,19 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "env_logger" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "equivalent" version = "1.0.1" @@ -331,6 +353,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "idna" version = "0.5.0" @@ -608,6 +636,16 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" +[[package]] +name = "pretty_env_logger" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "865724d4dbe39d9f3dd3b52b88d859d66bcb2d6a0acfd5ea68a65fb66d4bdc1c" +dependencies = [ + "env_logger", + "log", +] + [[package]] name = "proc-macro2" version = "1.0.76" @@ -646,6 +684,35 @@ dependencies = [ "thiserror", ] +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -732,7 +799,9 @@ dependencies = [ "handlebars", "handlebars_switch", "lazy_static", + "log", "miette", + "pretty_env_logger", "serde", "serde_json", "sys-info", @@ -800,6 +869,15 @@ dependencies = [ "libc", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "terminal_size" version = "0.1.17" @@ -986,6 +1064,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 451dc53..9d49fb3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,9 @@ git2 = "0.18.1" handlebars = "5.0.0" handlebars_switch = "0.6.0" lazy_static = "1.4.0" +log = "0.4.20" miette = { version = "5.10.0", features = ["serde", "fancy"] } +pretty_env_logger = "0.5.0" serde = { version = "1.0.195", features = ["derive"] } serde_json = "1.0.111" sys-info = "0.9.1" diff --git a/src/args.rs b/src/args.rs index 5a434b3..a1e347c 100644 --- a/src/args.rs +++ b/src/args.rs @@ -4,6 +4,9 @@ use clap::{Parser, Subcommand}; #[derive(Clone, Debug, Parser)] pub struct Args { + #[arg(short, long)] + pub verbose: bool, + #[arg(short, long, default_value = ".")] pub repo: PathBuf, /// The silo command to execute diff --git a/src/main.rs b/src/main.rs index b0a1caa..c98973b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,8 @@ mod templating; fn main() -> Result<()> { let args: Args = Args::parse(); + init_logging(args.verbose); + match &args.command { args::Command::Init => init(&args)?, args::Command::Apply => apply(&args)?, @@ -19,9 +21,22 @@ fn main() -> Result<()> { Ok(()) } +fn init_logging(verbose: bool) { + let mut builder = pretty_env_logger::formatted_builder(); + let builder = if verbose { + builder.filter_level(log::LevelFilter::Debug) + } else { + builder.filter_level(log::LevelFilter::Info) + }; + builder + .filter_module("handlebars", log::LevelFilter::Off) + .init(); +} + fn apply(args: &Args) -> Result<()> { let repo = SiloRepo::open(&args.repo)?; repo.apply()?; + log::info!("Applied all configurations in {:?}", args.repo); Ok(()) } @@ -35,5 +50,7 @@ fn init(args: &Args) -> Result<()> { let _gitrepo = git2::Repository::init(&args.repo) .into_diagnostic() .with_context(|| format!("initializing repository at {:?}", args.repo))?; + log::info!("Repo initialized at {:?}", args.repo); + Ok(()) } diff --git a/src/repo.rs b/src/repo.rs index 8505ecb..45a87be 100644 --- a/src/repo.rs +++ b/src/repo.rs @@ -1,7 +1,5 @@ -use handlebars::Handlebars; use miette::{bail, Context, IntoDiagnostic, Result}; use serde::Deserialize; -use serde_json::json; use std::{ env, fs::{self}, @@ -39,11 +37,19 @@ pub enum DirEntry { File(FileEntry), Dir(PathBuf, Vec), Root(PathBuf, RootDirData, Vec), + Ignored(PathBuf), } impl DirEntry { fn parse(path: PathBuf) -> Result { if path.is_dir() { + log::debug!("Parsing directory {path:?}"); + + if path.file_name().unwrap() == ".git" { + log::debug!("Ignoring .git directory"); + return Ok(Self::Ignored(path)); + } + let mut children = Vec::new(); for read_entry in fs::read_dir(&path).into_diagnostic()? { @@ -53,16 +59,23 @@ impl DirEntry { let meta_file = path.join("dir.toml"); let meta_tmpl = path.join("dir.toml.tmpl"); + if meta_file.exists() { + log::debug!("Found metadata file"); let metadata = RootDirData::read(&meta_file)?; + Ok(Self::Root(path, metadata, children)) } else if meta_tmpl.exists() { + log::debug!("Found metadata template"); let metadata = RootDirData::read_template(&meta_tmpl)?; + Ok(Self::Root(path, metadata, children)) } else { + log::debug!("Directory is child"); Ok(Self::Dir(path, children)) } } else { + log::debug!("Parsing file {path:?}"); Ok(Self::File(FileEntry::parse(path)?)) } } @@ -71,8 +84,9 @@ impl DirEntry { match self { DirEntry::File(file) => file.apply(cwd), DirEntry::Dir(p, children) => { - let cwd = cwd.join(p.iter().last().unwrap()); + let cwd = cwd.join(p.file_name().unwrap()); if !cwd.exists() { + log::info!("Creating {cwd:?}"); fs::create_dir_all(&cwd) .into_diagnostic() .with_context(|| format!("Creating directory {cwd:?}"))?; @@ -92,6 +106,7 @@ impl DirEntry { let cwd = PathBuf::from(rendered_path); if !cwd.exists() { + log::info!("Creating {cwd:?}"); fs::create_dir_all(&cwd) .into_diagnostic() .with_context(|| format!("Creating directory {cwd:?}"))?; @@ -101,6 +116,10 @@ impl DirEntry { } Ok(()) } + DirEntry::Ignored(p) => { + log::debug!("Ignoring {p:?}"); + Ok(()) + } } } } @@ -109,7 +128,7 @@ impl DirEntry { pub enum FileEntry { Template(PathBuf), Plain(PathBuf), - Metadata, + Ignored(PathBuf), } impl FileEntry { @@ -117,10 +136,13 @@ impl FileEntry { let file_name = path.file_name().unwrap(); if file_name == "dir.toml" || file_name == "dir.toml.tmpl" { - Ok(Self::Metadata) + log::debug!("File is metadata"); + Ok(Self::Ignored(path)) } else if let Some(true) = path.extension().map(|e| e == "tmpl") { + log::debug!("File is template"); Ok(Self::Template(path)) } else { + log::debug!("File is plain"); Ok(Self::Plain(path)) } } @@ -128,6 +150,7 @@ impl FileEntry { fn apply(&self, cwd: &Path) -> Result<()> { match self { FileEntry::Template(path) => { + log::debug!("Processing template {path:?}"); let contents = fs::read_to_string(path).into_diagnostic()?; let rendered = templating::engine() @@ -135,9 +158,11 @@ impl FileEntry { .into_diagnostic() .with_context(|| format!("rendering template {path:?}"))?; - let path = path.with_extension(""); - let filename = path.file_name().unwrap(); + let new_path = path.with_extension(""); + let filename = new_path.file_name().unwrap(); let dest = cwd.join(filename); + log::info!("Writing {path:?} -> {dest:?}"); + fs::write(&dest, rendered) .into_diagnostic() .with_context(|| format!("write to destination {dest:?}"))?; @@ -145,11 +170,15 @@ impl FileEntry { FileEntry::Plain(path) => { let filename = path.file_name().unwrap(); let dest = cwd.join(filename); + log::info!("Copying {path:?} -> {dest:?}"); + fs::copy(path, &dest) .into_diagnostic() .with_context(|| format!("copy {path:?} to {dest:?}"))?; } - FileEntry::Metadata => {} + FileEntry::Ignored(p) => { + log::debug!("Ignoring {p:?}") + } } Ok(())