You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

150 lines
5.1KB

  1. use std::fs::{canonicalize, create_dir};
  2. use std::path::Path;
  3. use errors::Result;
  4. use utils::fs::create_file;
  5. use console;
  6. use prompt::{ask_bool, ask_url};
  7. const CONFIG: &str = r#"
  8. # The URL the site will be built for
  9. base_url = "%BASE_URL%"
  10. # Whether to automatically compile all Sass files in the sass directory
  11. compile_sass = %COMPILE_SASS%
  12. # Whether to do syntax highlighting
  13. # Theme can be customised by setting the `highlight_theme` variable to a theme supported by Zola
  14. highlight_code = %HIGHLIGHT%
  15. # Whether to build a search index to be used later on by a JavaScript library
  16. build_search_index = %SEARCH%
  17. [extra]
  18. # Put all your custom variables here
  19. "#;
  20. // Given a path, return true if it is a directory and it doesn't have any
  21. // non-hidden files, otherwise return false (path is assumed to exist)
  22. pub fn is_directory_quasi_empty(path: &Path) -> Result<bool> {
  23. if path.is_dir() {
  24. let mut entries = match path.read_dir() {
  25. Ok(entries) => entries,
  26. Err(e) => { bail!("Could not read `{}` because of error: {}", path.to_string_lossy().to_string(), e); }
  27. };
  28. // If any entry raises an error or isn't hidden (i.e. starts with `.`), we raise an error
  29. if entries.any(|x| match x {
  30. Ok(file) => !file.file_name().to_str().expect("Could not convert filename to &str").starts_with("."),
  31. Err(_) => true
  32. }) {
  33. return Ok(false)
  34. }
  35. return Ok(true)
  36. } else {
  37. return Ok(false)
  38. }
  39. }
  40. pub fn create_new_project(name: &str) -> Result<()> {
  41. let path = Path::new(name);
  42. // Better error message than the rust default
  43. if path.exists() {
  44. if !is_directory_quasi_empty(&path)? {
  45. if name == "." {
  46. bail!("The current directory is not an empty folder (hidden files are ignored).");
  47. } else {
  48. bail!("`{}` is not an empty folder (hidden files are ignored).", path.to_string_lossy().to_string())
  49. }
  50. }
  51. } else {
  52. create_dir(path)?;
  53. }
  54. console::info("Welcome to Zola!");
  55. let base_url = ask_url("> What is the URL of your site?", "https://example.com")?;
  56. let compile_sass = ask_bool("> Do you want to enable Sass compilation?", true)?;
  57. let highlight = ask_bool("> Do you want to enable syntax highlighting?", false)?;
  58. let search = ask_bool("> Do you want to build a search index of the content?", false)?;
  59. let config = CONFIG
  60. .trim_start()
  61. .replace("%BASE_URL%", &base_url)
  62. .replace("%COMPILE_SASS%", &format!("{}", compile_sass))
  63. .replace("%SEARCH%", &format!("{}", search))
  64. .replace("%HIGHLIGHT%", &format!("{}", highlight));
  65. create_file(&path.join("config.toml"), &config)?;
  66. create_dir(path.join("content"))?;
  67. create_dir(path.join("templates"))?;
  68. create_dir(path.join("static"))?;
  69. create_dir(path.join("themes"))?;
  70. if compile_sass {
  71. create_dir(path.join("sass"))?;
  72. }
  73. println!();
  74. console::success(&format!("Done! Your site was created in {:?}", canonicalize(path).unwrap()));
  75. println!();
  76. console::info(
  77. "Get started by moving into the directory and using the built-in server: `zola serve`",
  78. );
  79. println!("Visit https://www.getzola.org for the full documentation.");
  80. Ok(())
  81. }
  82. #[cfg(test)]
  83. mod tests {
  84. use std::env::temp_dir;
  85. use std::fs::{create_dir,remove_dir,remove_dir_all};
  86. use super::*;
  87. #[test]
  88. fn init_empty_directory() {
  89. let mut dir = temp_dir();
  90. dir.push("test_empty_dir");
  91. if dir.exists() {
  92. remove_dir_all(&dir).expect("Could not free test directory");
  93. }
  94. create_dir(&dir).expect("Could not create test directory");
  95. let allowed = is_directory_quasi_empty(&dir).expect("An error happened reading the directory's contents");
  96. remove_dir(&dir).unwrap();
  97. assert_eq!(true, allowed);
  98. }
  99. #[test]
  100. fn init_non_empty_directory() {
  101. let mut dir = temp_dir();
  102. dir.push("test_non_empty_dir");
  103. if dir.exists() {
  104. remove_dir_all(&dir).expect("Could not free test directory");
  105. }
  106. create_dir(&dir).expect("Could not create test directory");
  107. let mut content = dir.clone();
  108. content.push("content");
  109. create_dir(&content).unwrap();
  110. let allowed = is_directory_quasi_empty(&dir).expect("An error happened reading the directory's contents");
  111. remove_dir(&content).unwrap();
  112. remove_dir(&dir).unwrap();
  113. assert_eq!(false, allowed);
  114. }
  115. #[test]
  116. fn init_quasi_empty_directory() {
  117. let mut dir = temp_dir();
  118. dir.push("test_quasi_empty_dir");
  119. if dir.exists() {
  120. remove_dir_all(&dir).expect("Could not free test directory");
  121. }
  122. create_dir(&dir).expect("Could not create test directory");
  123. let mut git = dir.clone();
  124. git.push(".git");
  125. create_dir(&git).unwrap();
  126. let allowed = is_directory_quasi_empty(&dir).expect("An error happened reading the directory's contents");
  127. remove_dir(&git).unwrap();
  128. remove_dir(&dir).unwrap();
  129. assert_eq!(true, allowed);
  130. }
  131. }