A static site generator written in Rust
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

commands.rs 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. use std::{env, fs};
  2. use fs_extra::dir;
  3. use toml::Value;
  4. use config::Config;
  5. use post::{parse_post, read_posts_dir};
  6. use write::{write_post, write_post_listing};
  7. pub fn build() {
  8. let cwd = env::current_dir().expect("Couldn't read current directory");
  9. let config = match fs::read_to_string(cwd.join("tlon.toml")) {
  10. Ok(contents) => match contents.parse::<Value>() {
  11. Ok(config) => Config {
  12. site_name: String::from(config["site_name"].as_str().unwrap()),
  13. },
  14. Err(_) => panic!("Invalid tlon.toml"),
  15. },
  16. Err(_) => {
  17. panic!("Can't find tlon.toml");
  18. }
  19. };
  20. match fs::read_dir(cwd.join("public")) {
  21. Ok(_) => {
  22. fs::remove_dir_all(cwd.join("public")).unwrap();
  23. }
  24. Err(_) => {}
  25. }
  26. fs::create_dir(cwd.join("public")).expect("Couldn't create public directory");
  27. let layout_template = fs::read_to_string(&cwd.join("templates").join("layout.html"))
  28. .expect("Couldn't find layout template");
  29. let post_template = fs::read_to_string(cwd.join("templates").join("post.html"))
  30. .expect("Couldn't find post template");
  31. let post_listing_template = fs::read_to_string(cwd.join("templates").join("post_listing.html"))
  32. .expect("Couldn't find post listing item template");
  33. let post_item_template =
  34. fs::read_to_string(cwd.join("templates").join("post_listing_item.html"))
  35. .expect("Couldn't find post listing item template");
  36. let post_paths = read_posts_dir(&cwd.join("posts"));
  37. let posts = post_paths
  38. .into_iter()
  39. .map(|path| match path {
  40. Ok(p) => {
  41. let post = parse_post(p.path());
  42. write_post(&cwd, &layout_template, &post_template, &post, &config);
  43. post
  44. }
  45. Err(err) => panic!(err),
  46. }).collect();
  47. write_post_listing(
  48. &cwd,
  49. &layout_template,
  50. &post_listing_template,
  51. &post_item_template,
  52. &posts,
  53. &config,
  54. );
  55. fs_extra::copy_items(
  56. &vec![cwd.join("css"), cwd.join("js")],
  57. cwd.join("public"),
  58. &dir::CopyOptions::new(),
  59. ).expect("Couldn't copy css/js directories");
  60. }
  61. pub fn new(name: &str) {
  62. let cwd = env::current_dir().expect("Couldn't read current directory");
  63. let project_path = cwd.join(name);
  64. fs::create_dir(&project_path).expect(&format!("Couldn't create directory '{}'", &name));
  65. fs::write(
  66. project_path.join("tlon.toml"),
  67. format!("site_name = \"{}\"", &name),
  68. ).expect("Could not create tlon.toml");
  69. for dir in &["posts", "public", "templates", "css", "js"] {
  70. fs::create_dir(&project_path.join(&dir))
  71. .expect(&format!("Couldn't create {} directory", &dir));
  72. }
  73. fs::write(project_path.join("css").join("style.css"), "")
  74. .expect("Couldn't create css/style.css");
  75. fs::write(project_path.join("js").join("index.js"), "").expect("Couldn't create js/index.js");
  76. for file in &["layout", "post_listing", "post", "post_listing_item"] {
  77. fs::write(
  78. &project_path
  79. .join("templates")
  80. .join(format!("{}.html", file)),
  81. "",
  82. ).expect(&format!("Couldn't write templates/{}.html", file));
  83. }
  84. }
  85. #[cfg(test)]
  86. mod tests {
  87. #[allow(unused_imports)]
  88. use super::*;
  89. #[allow(unused_imports)]
  90. use uuid::Uuid;
  91. #[test]
  92. fn test_new() {
  93. let temp_dir = env::temp_dir();
  94. env::set_current_dir(&temp_dir).unwrap();
  95. let uuid = Uuid::new_v4().to_string();
  96. let project_dir = temp_dir.join(&uuid);
  97. new(&uuid);
  98. for dir in &["public", "posts", "templates"] {
  99. fs::read_dir(&project_dir.join(dir)).unwrap();
  100. }
  101. assert_eq!(
  102. "",
  103. fs::read_to_string(&project_dir.join("templates").join("post_listing.html")).unwrap()
  104. );
  105. assert_eq!(
  106. "",
  107. fs::read_to_string(&project_dir.join("templates").join("layout.html")).unwrap()
  108. );
  109. assert_eq!(
  110. "",
  111. fs::read_to_string(&project_dir.join("templates").join("post_listing_item.html"))
  112. .unwrap()
  113. );
  114. assert_eq!(
  115. "",
  116. fs::read_to_string(&project_dir.join("templates").join("post.html")).unwrap()
  117. );
  118. assert_eq!(
  119. "",
  120. fs::read_to_string(&project_dir.join("css").join("style.css")).unwrap()
  121. );
  122. assert_eq!(
  123. "",
  124. fs::read_to_string(&project_dir.join("js").join("index.js")).unwrap()
  125. );
  126. assert_eq!(
  127. format!("site_name = \"{}\"", &uuid),
  128. fs::read_to_string(&project_dir.join("tlon.toml")).unwrap()
  129. );
  130. fs::remove_dir_all(project_dir).unwrap();
  131. }
  132. #[test]
  133. fn test_build() {
  134. let temp_dir = env::temp_dir();
  135. let uuid = Uuid::new_v4().to_string();
  136. let project_dir = temp_dir.join(&uuid);
  137. fs::create_dir(&project_dir).unwrap();
  138. env::set_current_dir(&project_dir).unwrap();
  139. fs::create_dir(project_dir.join("posts")).unwrap();
  140. fs::create_dir(project_dir.join("public")).unwrap();
  141. fs::create_dir(project_dir.join("templates")).unwrap();
  142. fs::create_dir(project_dir.join("css")).unwrap();
  143. fs::create_dir(project_dir.join("js")).unwrap();
  144. fs::write(
  145. project_dir.join("css").join("style.css"),
  146. "body { background: blue; }",
  147. ).unwrap();
  148. fs::write(
  149. project_dir.join("js").join("index.js"),
  150. "window.onload = function () { alert() }",
  151. ).unwrap();
  152. fs::write(
  153. project_dir.join("templates").join("layout.html"),
  154. "<html><head><title>{{ page_title }}</title></head><body>{{ contents }}</body></html>",
  155. ).unwrap();
  156. fs::write(
  157. project_dir.join("templates").join("post.html"),
  158. "<article><h1>{{ title }}</h1><div>{{ body }}</div></article>",
  159. ).unwrap();
  160. fs::write(
  161. project_dir.join("templates").join("post_listing.html"),
  162. "<ul>{{ post_listing }}</ul>",
  163. ).unwrap();
  164. fs::write(
  165. project_dir.join("templates").join("post_listing_item.html"),
  166. "<li><a href=\"/{{ slug }}\">{{ title }}</a></li>",
  167. ).unwrap();
  168. fs::write(
  169. project_dir.join("posts").join("first-post.md"),
  170. "# First post\n\nThis is the first post\n\nIt has multiple paragraphs",
  171. ).unwrap();
  172. fs::write(project_dir.join("tlon.toml"), "site_name = \"Test Site\"").unwrap();
  173. build();
  174. assert_eq!(
  175. "<html><head><title>Test Site</title></head><body><ul><li><a href=\"/fir\
  176. st-post\">First post</a></li></ul></body></html>",
  177. fs::read_to_string(project_dir.join("public").join("index.html")).unwrap(),
  178. );
  179. assert_eq!(
  180. "<html><head><title>First post | Test Site</title></head><body><article><h1>First pos\
  181. t</h1><div><p>This is the first post</p><p>It has multiple paragra\
  182. phs</p></div></article></body></html>",
  183. fs::read_to_string(
  184. project_dir
  185. .join("public")
  186. .join("first-post")
  187. .join("index.html")
  188. ).unwrap()
  189. .replace("\n", ""),
  190. );
  191. assert_eq!(
  192. "body { background: blue; }",
  193. fs::read_to_string(project_dir.join("public").join("css").join("style.css")).unwrap()
  194. );
  195. assert_eq!(
  196. "window.onload = function () { alert() }",
  197. fs::read_to_string(project_dir.join("public").join("js").join("index.js")).unwrap()
  198. );
  199. fs::remove_dir_all(project_dir).unwrap();
  200. }
  201. }