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.

120 lines
3.7KB

  1. use std::io::prelude::*;
  2. use std::fs::{File, create_dir_all, read_dir, copy};
  3. use std::path::{Path, PathBuf};
  4. use walkdir::WalkDir;
  5. use errors::{Result, ResultExt};
  6. /// Create a file with the content given
  7. pub fn create_file(path: &Path, content: &str) -> Result<()> {
  8. let mut file = File::create(&path)?;
  9. file.write_all(content.as_bytes())?;
  10. Ok(())
  11. }
  12. /// Create a directory at the given path if it doesn't exist already
  13. pub fn ensure_directory_exists(path: &Path) -> Result<()> {
  14. if !path.exists() {
  15. create_directory(path)?;
  16. }
  17. Ok(())
  18. }
  19. /// Very similar to `create_dir` from the std except it checks if the folder
  20. /// exists before creating it
  21. pub fn create_directory(path: &Path) -> Result<()> {
  22. if !path.exists() {
  23. create_dir_all(path)
  24. .chain_err(|| format!("Was not able to create folder {}", path.display()))?;
  25. }
  26. Ok(())
  27. }
  28. /// Return the content of a file, with error handling added
  29. pub fn read_file(path: &Path) -> Result<String> {
  30. let mut content = String::new();
  31. File::open(path)
  32. .chain_err(|| format!("Failed to open '{:?}'", path.display()))?
  33. .read_to_string(&mut content)?;
  34. Ok(content)
  35. }
  36. /// Looks into the current folder for the path and see if there's anything that is not a .md
  37. /// file. Those will be copied next to the rendered .html file
  38. pub fn find_related_assets(path: &Path) -> Vec<PathBuf> {
  39. let mut assets = vec![];
  40. for entry in read_dir(path).unwrap().filter_map(|e| e.ok()) {
  41. let entry_path = entry.path();
  42. if entry_path.is_file() {
  43. match entry_path.extension() {
  44. Some(e) => match e.to_str() {
  45. Some("md") => continue,
  46. _ => assets.push(entry_path.to_path_buf()),
  47. },
  48. None => continue,
  49. }
  50. }
  51. }
  52. assets
  53. }
  54. /// Copy a file but takes into account where to start the copy as
  55. /// there might be folders we need to create on the way
  56. pub fn copy_file(src: &Path, dest: &PathBuf, base_path: &PathBuf) -> Result<()> {
  57. let relative_path = src.strip_prefix(base_path).unwrap();
  58. let target_path = dest.join(relative_path);
  59. if let Some(parent_directory) = target_path.parent() {
  60. create_dir_all(parent_directory)?;
  61. }
  62. copy(src, target_path)?;
  63. Ok(())
  64. }
  65. pub fn copy_directory(src: &PathBuf, dest: &PathBuf) -> Result<()> {
  66. for entry in WalkDir::new(src).into_iter().filter_map(|e| e.ok()) {
  67. let relative_path = entry.path().strip_prefix(src).unwrap();
  68. let target_path = dest.join(relative_path);
  69. if entry.path().is_dir() {
  70. if !target_path.exists() {
  71. create_directory(&target_path)?;
  72. }
  73. } else {
  74. copy_file(entry.path(), dest, src)?;
  75. }
  76. }
  77. Ok(())
  78. }
  79. #[cfg(test)]
  80. mod tests {
  81. use std::fs::File;
  82. use tempdir::TempDir;
  83. use super::{find_related_assets};
  84. #[test]
  85. fn can_find_related_assets() {
  86. let tmp_dir = TempDir::new("example").expect("create temp dir");
  87. File::create(tmp_dir.path().join("index.md")).unwrap();
  88. File::create(tmp_dir.path().join("example.js")).unwrap();
  89. File::create(tmp_dir.path().join("graph.jpg")).unwrap();
  90. File::create(tmp_dir.path().join("fail.png")).unwrap();
  91. let assets = find_related_assets(tmp_dir.path());
  92. assert_eq!(assets.len(), 3);
  93. assert_eq!(assets.iter().filter(|p| p.extension().unwrap() != "md").count(), 3);
  94. assert_eq!(assets.iter().filter(|p| p.file_name().unwrap() == "example.js").count(), 1);
  95. assert_eq!(assets.iter().filter(|p| p.file_name().unwrap() == "graph.jpg").count(), 1);
  96. assert_eq!(assets.iter().filter(|p| p.file_name().unwrap() == "fail.png").count(), 1);
  97. }
  98. }