use std::fs;
use std::collections::BTreeMap;
use std::ffi::OsStr;
use std::path::{Path, PathBuf};
use config::Config;
use document;
use error::{Error, Result};
use template;
use util;
pub fn build(config: &Config) -> Result<()> {
const DEFAULT_SOURCE_PATH: &'static str = "./";
const DEFAULT_DEST_PATH: &'static str = "./_site/";
let source = config.source_directory.as_ref()
.map(Path::new)
.map_or_else(|| PathBuf::from(DEFAULT_SOURCE_PATH), Path::to_path_buf);
if !source.exists() {
return Err(Error::path_not_found(&source))
}
let dest = config.dest_directory.as_ref()
.map(Path::new)
.map_or_else(|| PathBuf::from(DEFAULT_DEST_PATH), Path::to_path_buf);
debug!("Cleaning destination directory");
if !dest.exists() {
println!("Destination directory \"{}\" does not exist, creating.", dest.display());
fs::create_dir(&dest)?;
} else {
println!("Cleaning destination directory \"{}\".", dest.display());
remove_dir_contents(&dest)?;
}
debug!("Loading templates");
let templates = match template::load_templates_from_disk(&source.join("_templates"), |path| {
!util::is_hidden(&path) &&
path.extension().and_then(OsStr::to_str) == Some("tpl")
}) {
Ok(v) => v,
Err(e) => {
println!("Failed to read templates: {}", e);
return Err(e);
}
};
debug!("Copying static files");
if source != dest {
let is_static_file = |path: &Path| {
!util::is_hidden(&path) &&
path != dest &&
!path.to_str().map_or(false, |path| path.contains("_posts")) &&
!path.to_str().map_or(false, |path| path.contains("_templates"))
};
try!(util::copy_recursively(&source, &dest, is_static_file))
}
debug!("Loading documents from disk");
let documents: BTreeMap<PathBuf, document::Document> = document::load_documents_from_disk(&source.join("_posts"), |path| {
!util::is_hidden(&path)
})?;
debug!("Rendering documents");
let dest = dest.join("www");
for (key, document) in documents.into_iter() {
let new_dest = dest.join(&key);
try!(document.render_to_file(&new_dest, &templates));
}
Ok(())
}
fn remove_dir_contents(path: &Path) -> Result<()> {
if path.is_dir() {
for entry in fs::read_dir(path)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
fs::remove_dir_all(path)?;
} else {
fs::remove_file(path)?;
}
}
} else {
warn!("Attempted to remove dir contents for a file path");
}
Ok(())
}