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.

166 lines
5.3KB

  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) => {
  27. bail!(
  28. "Could not read `{}` because of error: {}",
  29. path.to_string_lossy().to_string(),
  30. e
  31. );
  32. }
  33. };
  34. // If any entry raises an error or isn't hidden (i.e. starts with `.`), we raise an error
  35. if entries.any(|x| match x {
  36. Ok(file) => !file
  37. .file_name()
  38. .to_str()
  39. .expect("Could not convert filename to &str")
  40. .starts_with('.'),
  41. Err(_) => true,
  42. }) {
  43. return Ok(false);
  44. }
  45. return Ok(true);
  46. }
  47. Ok(false)
  48. }
  49. pub fn create_new_project(name: &str) -> Result<()> {
  50. let path = Path::new(name);
  51. // Better error message than the rust default
  52. if path.exists() {
  53. if !is_directory_quasi_empty(&path)? {
  54. if name == "." {
  55. bail!("The current directory is not an empty folder (hidden files are ignored).");
  56. } else {
  57. bail!(
  58. "`{}` is not an empty folder (hidden files are ignored).",
  59. path.to_string_lossy().to_string()
  60. )
  61. }
  62. }
  63. } else {
  64. create_dir(path)?;
  65. }
  66. console::info("Welcome to Zola!");
  67. let base_url = ask_url("> What is the URL of your site?", "https://example.com")?;
  68. let compile_sass = ask_bool("> Do you want to enable Sass compilation?", true)?;
  69. let highlight = ask_bool("> Do you want to enable syntax highlighting?", false)?;
  70. let search = ask_bool("> Do you want to build a search index of the content?", false)?;
  71. let config = CONFIG
  72. .trim_start()
  73. .replace("%BASE_URL%", &base_url)
  74. .replace("%COMPILE_SASS%", &format!("{}", compile_sass))
  75. .replace("%SEARCH%", &format!("{}", search))
  76. .replace("%HIGHLIGHT%", &format!("{}", highlight));
  77. create_file(&path.join("config.toml"), &config)?;
  78. create_dir(path.join("content"))?;
  79. create_dir(path.join("templates"))?;
  80. create_dir(path.join("static"))?;
  81. create_dir(path.join("themes"))?;
  82. if compile_sass {
  83. create_dir(path.join("sass"))?;
  84. }
  85. println!();
  86. console::success(&format!("Done! Your site was created in {:?}", canonicalize(path).unwrap()));
  87. println!();
  88. console::info(
  89. "Get started by moving into the directory and using the built-in server: `zola serve`",
  90. );
  91. println!("Visit https://www.getzola.org for the full documentation.");
  92. Ok(())
  93. }
  94. #[cfg(test)]
  95. mod tests {
  96. use super::*;
  97. use std::env::temp_dir;
  98. use std::fs::{create_dir, remove_dir, remove_dir_all};
  99. #[test]
  100. fn init_empty_directory() {
  101. let mut dir = temp_dir();
  102. dir.push("test_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 allowed = is_directory_quasi_empty(&dir)
  108. .expect("An error happened reading the directory's contents");
  109. remove_dir(&dir).unwrap();
  110. assert_eq!(true, allowed);
  111. }
  112. #[test]
  113. fn init_non_empty_directory() {
  114. let mut dir = temp_dir();
  115. dir.push("test_non_empty_dir");
  116. if dir.exists() {
  117. remove_dir_all(&dir).expect("Could not free test directory");
  118. }
  119. create_dir(&dir).expect("Could not create test directory");
  120. let mut content = dir.clone();
  121. content.push("content");
  122. create_dir(&content).unwrap();
  123. let allowed = is_directory_quasi_empty(&dir)
  124. .expect("An error happened reading the directory's contents");
  125. remove_dir(&content).unwrap();
  126. remove_dir(&dir).unwrap();
  127. assert_eq!(false, allowed);
  128. }
  129. #[test]
  130. fn init_quasi_empty_directory() {
  131. let mut dir = temp_dir();
  132. dir.push("test_quasi_empty_dir");
  133. if dir.exists() {
  134. remove_dir_all(&dir).expect("Could not free test directory");
  135. }
  136. create_dir(&dir).expect("Could not create test directory");
  137. let mut git = dir.clone();
  138. git.push(".git");
  139. create_dir(&git).unwrap();
  140. let allowed = is_directory_quasi_empty(&dir)
  141. .expect("An error happened reading the directory's contents");
  142. remove_dir(&git).unwrap();
  143. remove_dir(&dir).unwrap();
  144. assert_eq!(true, allowed);
  145. }
  146. }