1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
//! A crate for parsing YAML or TOML files from a [Hugo](https://gohugo.io/) contents directory to produce a JSON representation of the key front matter and contents of Hugo documents. It's main intent is to produce JSON to be used by [Lunr](https://lunrjs.com/) (and [Lunr-like](http://elasticlunr.com/) packages) to support search on a static Hugo site. #![warn(clippy::all, clippy::pedantic)] #![warn(missing_docs)] #![warn(missing_doc_code_examples)] #[macro_use] extern crate log; #[macro_use] extern crate serde_derive; /// Contains possible errors. pub mod hugo_to_json_error; /// Represents the result of trying to parse a file. pub mod operation_result; /// Contains the `PageIndex` data structure. pub mod page_index; /// Contains configuration options. pub mod settings; mod constants; mod file_location; mod traverse; use std::fs::{create_dir_all, File}; use std::io::{self, Write}; use std::path::PathBuf; use hugo_to_json_error::HugotoJsonError; use traverse::{TraverseResults, Traverser}; /// Given a contents directory it traverses all matching `.md` files with TOML and YAML frontmatter. /// /// # Examples /// ```no_run /// use hugo_to_json::{create_page_index, page_index::PageIndex, operation_result::OperationResult, hugo_to_json_error::HugotoJsonError}; /// use std::path::PathBuf; /// /// let traverse_result = create_page_index(PathBuf::from("/home/example_user/documents/blog/contents/"), false)?; /// // We can then see if there were any errors. /// let indices: Vec<PageIndex> = traverse_result.page_index; /// let errors: Vec<OperationResult> = traverse_result.errors; /// /// if traverse_result.error_count > 0 { /// panic!("Errors found"); // Don't do this for real! /// } /// # Ok::<(), HugotoJsonError>(()) /// ``` /// /// # Errors /// A `HugoToJsonError` should only occur if an IO error occurs trying to access the contents directory. /// All other errors are stored in the errors property of the `TraverseResults`. pub fn create_page_index( contents_directory: PathBuf, drafts: bool, ) -> Result<TraverseResults, HugotoJsonError> { let traverser = Traverser::new(contents_directory, drafts); let index = traverser.traverse_files()?; let (oks, errors): (Vec<_>, Vec<_>) = index.into_iter().partition(Result::is_ok); let index: Vec<_> = oks.into_iter().map(Result::unwrap).collect(); let errors: Vec<_> = errors.into_iter().map(Result::unwrap_err).collect(); Ok(TraverseResults::new(index, errors)) } fn write_page_index<W: Write>( mut writer: W, serialized_page_index: &str, ) -> Result<(), HugotoJsonError> { writer.write_all(serialized_page_index.as_bytes())?; Ok(()) } /// Converts a [Hugo](https://gohugo.io/) contents directory to JSON and writes it to a given location. /// If the output location is provided and it doesn't exist, it will be created. If no output location it will write to stdout. /// /// # Examples /// /// A basic example that writes to stdout. /// ```no_run /// use hugo_to_json::convert_to_json_and_write; /// use std::path::PathBuf; /// # use hugo_to_json::hugo_to_json_error::HugotoJsonError; /// convert_to_json_and_write(PathBuf::from("/home/example_user/documents/blog/contents/"), None, false)?; /// # Ok::<(), HugotoJsonError>(()) /// ``` /// /// An example that writes to a file. /// ```no_run /// use hugo_to_json::convert_to_json_and_write; /// use std::path::PathBuf; /// # use hugo_to_json::hugo_to_json_error::HugotoJsonError; /// /// let result = convert_to_json_and_write(PathBuf::from("/home/example_user/documents/blog/contents/"), Some(PathBuf::from("/home/example_user/documents/blog/static/index.json")), false)?; /// # Ok::<(), HugotoJsonError>(()) /// ``` /// /// # Errors /// Errors can occur if there is an error accessing the contents directory, serializing the page index to JSON, or performing IO writing the result out to either stdout or a file. pub fn convert_to_json_and_write( contents_directory: PathBuf, output_location: Option<PathBuf>, drafts: bool, ) -> Result<(), HugotoJsonError> { info!("Scanning {:?}", contents_directory); let traverse_results = create_page_index(contents_directory, drafts)?; let index = serde_json::to_string(&traverse_results.page_index)?; // Logging let writing_to; match output_location { Some(ref path) => writing_to = path.to_string_lossy().into_owned(), None => writing_to = String::from("stdout"), } info!("Writing index to {}", writing_to); match output_location { Some(path) => { create_dir_all(&path.with_file_name(constants::EMPTY_STRING))?; write_page_index(File::create(&path)?, &index)? } None => write_page_index(io::stdout(), &index)?, } if traverse_results.error_count > 0 { Err(HugotoJsonError::Meta { total: traverse_results.error_count, }) } else { debug!("Succesfully wrote index to {0}", writing_to); Ok(()) } }