use crate::config::Config;
use anyhow::{Context, Result};
use std::fs;
use std::path::Path;
use walkdir::WalkDir;
pub fn run(config: &Config) -> Result<()> {
for root in config.static_roots() {
copy_tree(&root, &config.output_dir)?;
}
Ok(())
}
fn copy_tree(root: &Path, output_dir: &Path) -> Result<()> {
if !root.exists() {
return Ok(());
}
for entry in WalkDir::new(root) {
let entry = entry.with_context(|| format!("walking {}", root.display()))?;
if !entry.file_type().is_file() {
continue;
}
let rel = entry
.path()
.strip_prefix(root)
.expect("walkdir entry is always under the root we passed in");
let dest = output_dir.join(rel);
if let Some(parent) = dest.parent() {
fs::create_dir_all(parent).with_context(|| format!("creating {}", parent.display()))?;
}
fs::copy(entry.path(), &dest)
.with_context(|| format!("copying {} -> {}", entry.path().display(), dest.display()))?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_util::{cleanup, tempdir};
fn write(path: &Path, body: &str) {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).unwrap();
}
fs::write(path, body).unwrap();
}
#[test]
fn site_static_overlays_theme_static() {
let base = tempdir("static");
let theme = base.join("theme");
let site_static = base.join("static");
let out = base.join("public");
write(&theme.join("static/shared.css"), "theme");
write(&theme.join("static/only-theme.css"), "t");
write(&site_static.join("shared.css"), "site");
write(&site_static.join("only-site.css"), "s");
let config = Config {
static_dir: site_static,
theme: Some(theme),
output_dir: out.clone(),
..Config::default()
};
run(&config).unwrap();
assert_eq!(fs::read_to_string(out.join("shared.css")).unwrap(), "site");
assert_eq!(fs::read_to_string(out.join("only-theme.css")).unwrap(), "t");
assert_eq!(fs::read_to_string(out.join("only-site.css")).unwrap(), "s");
cleanup(&base);
}
#[test]
fn missing_roots_are_noops() {
let base = tempdir("static");
let config = Config {
static_dir: base.join("nope"),
theme: Some(base.join("also-nope")),
output_dir: base.join("public"),
..Config::default()
};
run(&config).unwrap();
cleanup(&base);
}
}