zola/src/cmd/init.rs

228 lines
7.6 KiB
Rust
Raw Normal View History

2018-10-31 07:18:57 +00:00
use std::fs::{canonicalize, create_dir};
2016-12-06 05:51:33 +00:00
use std::path::Path;
2019-12-21 21:52:39 +00:00
use errors::{bail, Result};
2017-07-01 07:47:41 +00:00
use utils::fs::create_file;
2016-12-06 05:51:33 +00:00
2019-12-21 21:52:39 +00:00
use crate::console;
use crate::prompt::{ask_bool, ask_url};
2016-12-06 05:51:33 +00:00
2018-09-30 19:15:09 +00:00
const CONFIG: &str = r#"
2017-07-27 09:24:43 +00:00
# The URL the site will be built for
base_url = "%BASE_URL%"
# Whether to automatically compile all Sass files in the sass directory
compile_sass = %COMPILE_SASS%
# Whether to do syntax highlighting
# Theme can be customised by setting the `highlight_theme` variable to a theme supported by Zola
2017-07-27 09:24:43 +00:00
highlight_code = %HIGHLIGHT%
2017-02-23 08:34:57 +00:00
2018-03-12 19:11:03 +00:00
# Whether to build a search index to be used later on by a JavaScript library
build_search_index = %SEARCH%
2017-02-23 08:34:57 +00:00
[extra]
# Put all your custom variables here
2016-12-06 05:51:33 +00:00
"#;
// Given a path, return true if it is a directory and it doesn't have any
// non-hidden files, otherwise return false (path is assumed to exist)
pub fn is_directory_quasi_empty(path: &Path) -> Result<bool> {
if path.is_dir() {
let mut entries = match path.read_dir() {
Ok(entries) => entries,
2019-08-13 18:01:17 +00:00
Err(e) => {
bail!(
"Could not read `{}` because of error: {}",
path.to_string_lossy().to_string(),
e
);
}
};
// If any entry raises an error or isn't hidden (i.e. starts with `.`), we raise an error
if entries.any(|x| match x {
2019-08-13 18:01:17 +00:00
Ok(file) => !file
.file_name()
.to_str()
.expect("Could not convert filename to &str")
.starts_with('.'),
Err(_) => true,
}) {
2019-08-13 18:01:17 +00:00
return Ok(false);
}
2019-08-13 18:01:17 +00:00
return Ok(true);
}
2019-08-13 18:01:17 +00:00
Ok(false)
}
pub fn create_new_project(name: &str) -> Result<()> {
let path = Path::new(name);
2016-12-06 05:51:33 +00:00
// Better error message than the rust default
2019-08-24 20:23:08 +00:00
if path.exists() && !is_directory_quasi_empty(&path)? {
if name == "." {
bail!("The current directory is not an empty folder (hidden files are ignored).");
} else {
bail!(
"`{}` is not an empty folder (hidden files are ignored).",
path.to_string_lossy().to_string()
)
}
2016-12-06 05:51:33 +00:00
}
console::info("Welcome to Zola!");
console::info("Please answer a few questions to get started quickly.");
console::info("Any choices made can be changed by modifying the `config.toml` file later.");
2016-12-06 05:51:33 +00:00
2017-07-27 09:24:43 +00:00
let base_url = ask_url("> What is the URL of your site?", "https://example.com")?;
let compile_sass = ask_bool("> Do you want to enable Sass compilation?", true)?;
let highlight = ask_bool("> Do you want to enable syntax highlighting?", false)?;
2018-03-12 19:11:03 +00:00
let search = ask_bool("> Do you want to build a search index of the content?", false)?;
2016-12-06 05:51:33 +00:00
2017-07-27 09:24:43 +00:00
let config = CONFIG
.trim_start()
2017-07-27 09:24:43 +00:00
.replace("%BASE_URL%", &base_url)
.replace("%COMPILE_SASS%", &format!("{}", compile_sass))
2018-03-12 19:11:03 +00:00
.replace("%SEARCH%", &format!("{}", search))
2017-07-27 09:24:43 +00:00
.replace("%HIGHLIGHT%", &format!("{}", highlight));
populate(&path, compile_sass, &config)?;
2016-12-06 05:51:33 +00:00
println!();
console::success(&format!("Done! Your site was created in {:?}", canonicalize(path).unwrap()));
println!();
console::info(
"Get started by moving into the directory and using the built-in server: `zola serve`",
);
println!("Visit https://www.getzola.org for the full documentation.");
Ok(())
}
fn populate(path: &Path, compile_sass: bool, config: &str) -> Result<()> {
if !path.exists() {
create_dir(path)?;
}
create_file(&path.join("config.toml"), &config)?;
2017-07-27 09:24:43 +00:00
create_dir(path.join("content"))?;
create_dir(path.join("templates"))?;
2016-12-06 05:51:33 +00:00
create_dir(path.join("static"))?;
2017-08-24 23:43:54 +00:00
create_dir(path.join("themes"))?;
2017-07-27 09:24:43 +00:00
if compile_sass {
create_dir(path.join("sass"))?;
}
2016-12-06 05:51:33 +00:00
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
2019-08-13 18:01:17 +00:00
use std::env::temp_dir;
use std::fs::{create_dir, remove_dir, remove_dir_all};
#[test]
fn init_empty_directory() {
let mut dir = temp_dir();
dir.push("test_empty_dir");
if dir.exists() {
remove_dir_all(&dir).expect("Could not free test directory");
}
create_dir(&dir).expect("Could not create test directory");
2019-08-13 18:01:17 +00:00
let allowed = is_directory_quasi_empty(&dir)
.expect("An error happened reading the directory's contents");
remove_dir(&dir).unwrap();
assert_eq!(true, allowed);
}
#[test]
fn init_non_empty_directory() {
let mut dir = temp_dir();
dir.push("test_non_empty_dir");
if dir.exists() {
remove_dir_all(&dir).expect("Could not free test directory");
}
create_dir(&dir).expect("Could not create test directory");
let mut content = dir.clone();
content.push("content");
create_dir(&content).unwrap();
2019-08-13 18:01:17 +00:00
let allowed = is_directory_quasi_empty(&dir)
.expect("An error happened reading the directory's contents");
remove_dir(&content).unwrap();
remove_dir(&dir).unwrap();
assert_eq!(false, allowed);
}
#[test]
fn init_quasi_empty_directory() {
let mut dir = temp_dir();
dir.push("test_quasi_empty_dir");
if dir.exists() {
remove_dir_all(&dir).expect("Could not free test directory");
}
create_dir(&dir).expect("Could not create test directory");
let mut git = dir.clone();
git.push(".git");
create_dir(&git).unwrap();
2019-08-13 18:01:17 +00:00
let allowed = is_directory_quasi_empty(&dir)
.expect("An error happened reading the directory's contents");
remove_dir(&git).unwrap();
remove_dir(&dir).unwrap();
assert_eq!(true, allowed);
}
#[test]
fn populate_existing_directory() {
let mut dir = temp_dir();
dir.push("test_existing_dir");
if dir.exists() {
remove_dir_all(&dir).expect("Could not free test directory");
}
create_dir(&dir).expect("Could not create test directory");
populate(&dir, true, "").expect("Could not populate zola directories");
assert_eq!(true, dir.join("config.toml").exists());
assert_eq!(true, dir.join("content").exists());
assert_eq!(true, dir.join("templates").exists());
assert_eq!(true, dir.join("static").exists());
assert_eq!(true, dir.join("themes").exists());
assert_eq!(true, dir.join("sass").exists());
remove_dir_all(&dir).unwrap();
}
#[test]
fn populate_non_existing_directory() {
let mut dir = temp_dir();
dir.push("test_non_existing_dir");
if dir.exists() {
remove_dir_all(&dir).expect("Could not free test directory");
}
populate(&dir, true, "").expect("Could not populate zola directories");
assert_eq!(true, dir.exists());
assert_eq!(true, dir.join("config.toml").exists());
assert_eq!(true, dir.join("content").exists());
assert_eq!(true, dir.join("templates").exists());
assert_eq!(true, dir.join("static").exists());
assert_eq!(true, dir.join("themes").exists());
assert_eq!(true, dir.join("sass").exists());
remove_dir_all(&dir).unwrap();
}
#[test]
fn populate_without_sass() {
let mut dir = temp_dir();
dir.push("test_wihout_sass_dir");
if dir.exists() {
remove_dir_all(&dir).expect("Could not free test directory");
}
create_dir(&dir).expect("Could not create test directory");
populate(&dir, false, "").expect("Could not populate zola directories");
assert_eq!(false, dir.join("sass").exists());
remove_dir_all(&dir).unwrap();
}
}