|
|
@ -1,7 +1,5 @@
|
|
|
|
use handlebars::Handlebars;
|
|
|
|
|
|
|
|
use miette::{bail, Context, IntoDiagnostic, Result};
|
|
|
|
use miette::{bail, Context, IntoDiagnostic, Result};
|
|
|
|
use serde::Deserialize;
|
|
|
|
use serde::Deserialize;
|
|
|
|
use serde_json::json;
|
|
|
|
|
|
|
|
use std::{
|
|
|
|
use std::{
|
|
|
|
env,
|
|
|
|
env,
|
|
|
|
fs::{self},
|
|
|
|
fs::{self},
|
|
|
@ -39,11 +37,19 @@ pub enum DirEntry {
|
|
|
|
File(FileEntry),
|
|
|
|
File(FileEntry),
|
|
|
|
Dir(PathBuf, Vec<DirEntry>),
|
|
|
|
Dir(PathBuf, Vec<DirEntry>),
|
|
|
|
Root(PathBuf, RootDirData, Vec<DirEntry>),
|
|
|
|
Root(PathBuf, RootDirData, Vec<DirEntry>),
|
|
|
|
|
|
|
|
Ignored(PathBuf),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl DirEntry {
|
|
|
|
impl DirEntry {
|
|
|
|
fn parse(path: PathBuf) -> Result<Self> {
|
|
|
|
fn parse(path: PathBuf) -> Result<Self> {
|
|
|
|
if path.is_dir() {
|
|
|
|
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();
|
|
|
|
let mut children = Vec::new();
|
|
|
|
|
|
|
|
|
|
|
|
for read_entry in fs::read_dir(&path).into_diagnostic()? {
|
|
|
|
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_file = path.join("dir.toml");
|
|
|
|
let meta_tmpl = path.join("dir.toml.tmpl");
|
|
|
|
let meta_tmpl = path.join("dir.toml.tmpl");
|
|
|
|
|
|
|
|
|
|
|
|
if meta_file.exists() {
|
|
|
|
if meta_file.exists() {
|
|
|
|
|
|
|
|
log::debug!("Found metadata file");
|
|
|
|
let metadata = RootDirData::read(&meta_file)?;
|
|
|
|
let metadata = RootDirData::read(&meta_file)?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(Self::Root(path, metadata, children))
|
|
|
|
Ok(Self::Root(path, metadata, children))
|
|
|
|
} else if meta_tmpl.exists() {
|
|
|
|
} else if meta_tmpl.exists() {
|
|
|
|
|
|
|
|
log::debug!("Found metadata template");
|
|
|
|
let metadata = RootDirData::read_template(&meta_tmpl)?;
|
|
|
|
let metadata = RootDirData::read_template(&meta_tmpl)?;
|
|
|
|
|
|
|
|
|
|
|
|
Ok(Self::Root(path, metadata, children))
|
|
|
|
Ok(Self::Root(path, metadata, children))
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log::debug!("Directory is child");
|
|
|
|
Ok(Self::Dir(path, children))
|
|
|
|
Ok(Self::Dir(path, children))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log::debug!("Parsing file {path:?}");
|
|
|
|
Ok(Self::File(FileEntry::parse(path)?))
|
|
|
|
Ok(Self::File(FileEntry::parse(path)?))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -71,8 +84,9 @@ impl DirEntry {
|
|
|
|
match self {
|
|
|
|
match self {
|
|
|
|
DirEntry::File(file) => file.apply(cwd),
|
|
|
|
DirEntry::File(file) => file.apply(cwd),
|
|
|
|
DirEntry::Dir(p, children) => {
|
|
|
|
DirEntry::Dir(p, children) => {
|
|
|
|
let cwd = cwd.join(p.iter().last().unwrap());
|
|
|
|
let cwd = cwd.join(p.file_name().unwrap());
|
|
|
|
if !cwd.exists() {
|
|
|
|
if !cwd.exists() {
|
|
|
|
|
|
|
|
log::info!("Creating {cwd:?}");
|
|
|
|
fs::create_dir_all(&cwd)
|
|
|
|
fs::create_dir_all(&cwd)
|
|
|
|
.into_diagnostic()
|
|
|
|
.into_diagnostic()
|
|
|
|
.with_context(|| format!("Creating directory {cwd:?}"))?;
|
|
|
|
.with_context(|| format!("Creating directory {cwd:?}"))?;
|
|
|
@ -92,6 +106,7 @@ impl DirEntry {
|
|
|
|
let cwd = PathBuf::from(rendered_path);
|
|
|
|
let cwd = PathBuf::from(rendered_path);
|
|
|
|
|
|
|
|
|
|
|
|
if !cwd.exists() {
|
|
|
|
if !cwd.exists() {
|
|
|
|
|
|
|
|
log::info!("Creating {cwd:?}");
|
|
|
|
fs::create_dir_all(&cwd)
|
|
|
|
fs::create_dir_all(&cwd)
|
|
|
|
.into_diagnostic()
|
|
|
|
.into_diagnostic()
|
|
|
|
.with_context(|| format!("Creating directory {cwd:?}"))?;
|
|
|
|
.with_context(|| format!("Creating directory {cwd:?}"))?;
|
|
|
@ -101,6 +116,10 @@ impl DirEntry {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DirEntry::Ignored(p) => {
|
|
|
|
|
|
|
|
log::debug!("Ignoring {p:?}");
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -109,7 +128,7 @@ impl DirEntry {
|
|
|
|
pub enum FileEntry {
|
|
|
|
pub enum FileEntry {
|
|
|
|
Template(PathBuf),
|
|
|
|
Template(PathBuf),
|
|
|
|
Plain(PathBuf),
|
|
|
|
Plain(PathBuf),
|
|
|
|
Metadata,
|
|
|
|
Ignored(PathBuf),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl FileEntry {
|
|
|
|
impl FileEntry {
|
|
|
@ -117,10 +136,13 @@ impl FileEntry {
|
|
|
|
let file_name = path.file_name().unwrap();
|
|
|
|
let file_name = path.file_name().unwrap();
|
|
|
|
|
|
|
|
|
|
|
|
if file_name == "dir.toml" || file_name == "dir.toml.tmpl" {
|
|
|
|
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") {
|
|
|
|
} else if let Some(true) = path.extension().map(|e| e == "tmpl") {
|
|
|
|
|
|
|
|
log::debug!("File is template");
|
|
|
|
Ok(Self::Template(path))
|
|
|
|
Ok(Self::Template(path))
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
|
|
|
|
log::debug!("File is plain");
|
|
|
|
Ok(Self::Plain(path))
|
|
|
|
Ok(Self::Plain(path))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -128,6 +150,7 @@ impl FileEntry {
|
|
|
|
fn apply(&self, cwd: &Path) -> Result<()> {
|
|
|
|
fn apply(&self, cwd: &Path) -> Result<()> {
|
|
|
|
match self {
|
|
|
|
match self {
|
|
|
|
FileEntry::Template(path) => {
|
|
|
|
FileEntry::Template(path) => {
|
|
|
|
|
|
|
|
log::debug!("Processing template {path:?}");
|
|
|
|
let contents = fs::read_to_string(path).into_diagnostic()?;
|
|
|
|
let contents = fs::read_to_string(path).into_diagnostic()?;
|
|
|
|
|
|
|
|
|
|
|
|
let rendered = templating::engine()
|
|
|
|
let rendered = templating::engine()
|
|
|
@ -135,9 +158,11 @@ impl FileEntry {
|
|
|
|
.into_diagnostic()
|
|
|
|
.into_diagnostic()
|
|
|
|
.with_context(|| format!("rendering template {path:?}"))?;
|
|
|
|
.with_context(|| format!("rendering template {path:?}"))?;
|
|
|
|
|
|
|
|
|
|
|
|
let path = path.with_extension("");
|
|
|
|
let new_path = path.with_extension("");
|
|
|
|
let filename = path.file_name().unwrap();
|
|
|
|
let filename = new_path.file_name().unwrap();
|
|
|
|
let dest = cwd.join(filename);
|
|
|
|
let dest = cwd.join(filename);
|
|
|
|
|
|
|
|
log::info!("Writing {path:?} -> {dest:?}");
|
|
|
|
|
|
|
|
|
|
|
|
fs::write(&dest, rendered)
|
|
|
|
fs::write(&dest, rendered)
|
|
|
|
.into_diagnostic()
|
|
|
|
.into_diagnostic()
|
|
|
|
.with_context(|| format!("write to destination {dest:?}"))?;
|
|
|
|
.with_context(|| format!("write to destination {dest:?}"))?;
|
|
|
@ -145,11 +170,15 @@ impl FileEntry {
|
|
|
|
FileEntry::Plain(path) => {
|
|
|
|
FileEntry::Plain(path) => {
|
|
|
|
let filename = path.file_name().unwrap();
|
|
|
|
let filename = path.file_name().unwrap();
|
|
|
|
let dest = cwd.join(filename);
|
|
|
|
let dest = cwd.join(filename);
|
|
|
|
|
|
|
|
log::info!("Copying {path:?} -> {dest:?}");
|
|
|
|
|
|
|
|
|
|
|
|
fs::copy(path, &dest)
|
|
|
|
fs::copy(path, &dest)
|
|
|
|
.into_diagnostic()
|
|
|
|
.into_diagnostic()
|
|
|
|
.with_context(|| format!("copy {path:?} to {dest:?}"))?;
|
|
|
|
.with_context(|| format!("copy {path:?} to {dest:?}"))?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FileEntry::Metadata => {}
|
|
|
|
FileEntry::Ignored(p) => {
|
|
|
|
|
|
|
|
log::debug!("Ignoring {p:?}")
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|