1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
//! Initializes a directory for a new site
//!
//! Initializes a directory for a new site containing the bare
//! minimum files. Fails if the directory isn't empty.

mod consts;
mod user_prompts;

use std::fs::{self, create_dir};
use std::path::Path;

use clap::crate_name;
use relative_path::RelativePath;

use crate::debug_print::dprintln;
use user_prompts::*;

/// Checks if folder is empty
///
/// Ignores hidden files and the crate executable
fn is_dir_empty(path: &Path) -> Result<bool, &Path> {
    if path.is_dir() {
        let mut files = match path.read_dir() {
            Ok(files) => files,
            Err(e) => panic!(
                "Could not read {} because of error: {}",
                path.to_string_lossy().to_string(),
                e
            ),
        };
        // if any filename is not hidden (starts with dot) --> false
        if files.any(|x| match x {
            Ok(file) => {
                let filename = file.file_name();
                let filename = filename.to_str().expect("Unable to convert filename to &str");
                !(filename.starts_with('.') || filename.starts_with(crate_name!()))
            }
            Err(_) => true,
        }) {
            return Ok(false);
        }
        return Ok(true);
    }
    return Err(path);
}

/// Initialize directory
pub(crate) fn init(root_dir: &str) {
    // prepare variables to be inserted into the config
    let base_url: String;
    let katex: bool;
    let highlight: bool;
    let git: bool;

    // fail if root_dir empty
    match is_dir_empty(Path::new(root_dir)) {
        Ok(true) => (),
        Ok(false) => {
            println!("Specified root directory: \"{}\" is not empty, empty it, or choose a different one", root_dir);
            return;
        }
        Err(e) => {
            eprintln!("Provided path: {} is not a directory", e.to_string_lossy().to_string());
            return;
        }
    }

    // populate config variables
    base_url = inquire_url("What is the URL of your site");
    katex = inquire_yn("Do you wish to enable katex precompilation");
    highlight = inquire_yn("Do you wish to enable syntax highlighting");
    git = inquire_yn("Do you wish to enable git support");

    // prepare config file
    let config = consts::CONFIG
        .trim_start()
        .replace("{% BASE_URL %}", &base_url)
        .replace("{% KATEX_YN %}", &katex.to_string())
        .replace("{% HIGHLIGHT_CODE %}", &highlight.to_string())
        .replace("{% GIT_ENABLE %}", &git.to_string());

    println!("Initializing directory...");
    // create folders in root_dir
    for relative_dir in ["content", "assets", "templates"] {
        let dir_to_create = RelativePath::new(relative_dir).to_logical_path(root_dir);
        create_dir(&dir_to_create).unwrap();
        dprintln!("Created folder: {}", dir_to_create.to_str().unwrap())
    }
    // create config file
    if let Ok(_) =
        fs::write(RelativePath::new("config.toml").to_logical_path(root_dir), config.as_bytes())
    {
        dprintln!("Succesfully generated config file");
    } else {
        eprintln!("Unable to create 'config.toml' in the output directory");
        return;
    }
}

#[test]
fn test_logical_path() {
    let root_dir = ".";
    let relative_dir = "assets";
    assert_eq!(
        ".\\assets",
        RelativePath::new(relative_dir).to_logical_path(root_dir).to_str().unwrap()
    );
}