limonite 0.1.0

small blog generator
Documentation
use std::path::{Path,PathBuf};
use std::fs::{self, File};
use std::io::prelude::*;
use yaml_rust::YamlLoader;
use std::collections::HashMap;
use layout_store::LayoutStore;
use util;
use post::Post;

#[derive(Debug)]
pub struct Site {
    src_path: PathBuf,
    base_url: String,
    layout_store: LayoutStore,
    posts: Vec<Post>,
    files_to_copy: Vec<String>,
    files_to_render: Vec<String>
}

impl Site {
   pub fn new(src_path: &Path) -> Site {
        let config_path = src_path.join("_limonite.yml");
        let mut config_content = String::new();
        let mut f = File::open(config_path).unwrap();
        let _ = f.read_to_string(&mut config_content);
        let docs = YamlLoader::load_from_str(&config_content).unwrap();
        let doc = &docs[0];
        let base_url = doc["base_url"].as_str().unwrap().to_owned();

        let layout_store = LayoutStore::new(&src_path.join("_layouts"));

        let posts_dir = src_path.join("_posts");
        let mut posts = Vec::new();
        for entry in fs::read_dir(&posts_dir).unwrap() {
            let post_path = entry.unwrap().path();
            let fname = post_path.file_name().unwrap().to_str().unwrap();
            if !fname.starts_with(".") && fname.ends_with("markdown") {
                posts.push(Post::new(&post_path));
            }
        }

        let mut files_to_render = Vec::new();
        let mut files_to_copy = Vec::new();
        for entry in fs::read_dir(&src_path).unwrap() {
            let file_path = entry.unwrap().path();
            let metadata = fs::metadata(&file_path).unwrap();
            if (!metadata.is_dir()) {
                let fname = file_path.file_name().unwrap().to_str().unwrap();
                if !fname.starts_with("_") {
                    let relative_file_path = util::relative_from(&file_path, &src_path).unwrap();
                    match util::parse_front_matter_and_content(&file_path) {
                        Ok(_) => {
                            files_to_render.push(relative_file_path.to_str().unwrap().to_owned());
                        },
                        Err(_) => {
                            files_to_copy.push(relative_file_path.to_str().unwrap().to_owned());
                        }
                    }
                }
            } else {
            }
        }
        println!("{}", src_path.display());

        Site {
            src_path: src_path.to_path_buf(),
            base_url: base_url,
            layout_store: layout_store,
            posts: posts,
            files_to_render: files_to_render,
            files_to_copy: files_to_copy
        }
    }

    pub fn generate(&self, output_path: &Path) {
        for post in self.posts.iter() {
            let dir = output_path.join(post.slug());
            let _ = fs::create_dir_all(&dir);
            let mut f = File::create(&dir.join("index.html")).unwrap();
            let output = self.layout_store.render(&post.layout().unwrap(), post.render(HashMap::new()), HashMap::new());
            let _ = f.write_all(output.as_bytes());
        }

        for file in self.files_to_copy.iter() {
            let src = self.src_path.join(file);
            let target = output_path.join(file);
            match fs::copy(&src, &target) {
                Ok(_) => {
                    println!("{:?}=>{:?}", src, target);
                },
                Err(_) => {
                    println!("failed {:?}=>{:?}", src, target);
                }
            }
        }

        for file in self.files_to_render.iter() {
            let target = output_path.join(file);
            match util::parse_front_matter_and_content(&self.src_path.join(file)) {
                Ok((front_matter, content)) => {
                    let mut data = HashMap::new();
                    let result = util::render_liquid(&content, data).expect("couldn't render");
                    let mut f = File::create(target).ok().expect("file not found");
                    let _ = f.write_all(result.as_bytes());
                },
                Err(why) => {
                    println!("ooo {}", why);
                }
            }
        }
    }
}

#[cfg(test)]
pub mod tests {
    use std::env;
    use std::fs;
    use std::path::{Path, PathBuf};
    use uuid::Uuid;
    use diff::compare_paths;

    fn get_temp_output_path() -> PathBuf {
        let mut outdir = env::temp_dir();
        outdir.push("limonite");
        outdir.push(Uuid::new_v4().to_simple_string());
        fs::create_dir_all(&outdir);
        outdir
    }

    #[test]
    fn copies_files_without_front_matter() {
        let site = super::Site::new(Path::new("fixtures/007"));
        let outdir = get_temp_output_path();
        site.generate(&outdir);
        assert!(compare_paths(Path::new("fixtures/007/index.html"), &outdir.join("index.html")));
    }

    #[test]
    fn renders_files_with_front_matter() {
        let site = super::Site::new(Path::new("fixtures/010"));
        let outdir = get_temp_output_path();
        site.generate(&outdir);
        assert!(compare_paths(Path::new("fixtures/010-output/index.html"), &outdir.join("index.html")));
    }

    #[test]
    fn renders_files_with_front_matter2() {
        let site = super::Site::new(Path::new("fixtures/011"));
        let outdir = get_temp_output_path();
        site.generate(&outdir);
        assert!(compare_paths(Path::new("fixtures/011-output/main.html"), &outdir.join("main.html")));
    }
}