diff --git a/crates/rari-doc/src/error.rs b/crates/rari-doc/src/error.rs index 35bd832..b23708d 100644 --- a/crates/rari-doc/src/error.rs +++ b/crates/rari-doc/src/error.rs @@ -110,6 +110,12 @@ pub enum DocError { SlugRequiredForSidebarEntry, #[error("Invalid sidebar entry")] InvalidSidebarEntry, + #[error( + "The document's slug ({0}) doesn't match its disk folder name ({1}): expected path ({2})" + )] + SlugFolderMismatch(String, String, String), + #[error("Fatal error reading docs")] + DocsReadError, } /// Represents various errors that can occur while processing URLs. diff --git a/crates/rari-doc/src/pages/types/doc.rs b/crates/rari-doc/src/pages/types/doc.rs index 45dcaff..7ee75d7 100644 --- a/crates/rari-doc/src/pages/types/doc.rs +++ b/crates/rari-doc/src/pages/types/doc.rs @@ -9,6 +9,7 @@ use rari_md::m2h; use rari_types::fm_types::{FeatureStatus, PageType}; use rari_types::locale::{default_locale, Locale}; use rari_types::RariEnv; +use rari_utils::concat_strs; use rari_utils::io::read_to_string; use serde::{Deserialize, Serialize}; use serde_yaml_ng::Value; @@ -307,7 +308,29 @@ fn read_doc(path: impl Into) -> Result { let path = full_path .strip_prefix(root_for_locale(locale)?)? .to_path_buf(); - + let folder_path = path + .strip_prefix(locale.as_folder_str()) + .ok() + .and_then(|path| path.parent()); + let folder_path_from_slug = url_to_folder_path(&slug); + if Some(folder_path_from_slug.as_path()) != folder_path { + return Err(DocError::SlugFolderMismatch( + slug, + concat_strs!( + locale.as_folder_str(), + "/", + folder_path + .map(|path| path.to_string_lossy()) + .unwrap_or_default() + .as_ref() + ), + concat_strs!( + locale.as_folder_str(), + "/", + folder_path_from_slug.to_string_lossy().as_ref() + ), + )); + } Ok(Doc { meta: Meta { title, diff --git a/crates/rari-doc/src/reader.rs b/crates/rari-doc/src/reader.rs index e979450..f390d41 100644 --- a/crates/rari-doc/src/reader.rs +++ b/crates/rari-doc/src/reader.rs @@ -6,6 +6,7 @@ //! efficiency of reading large sets of documentation files. use std::path::Path; +use std::sync::atomic::{AtomicBool, Ordering}; use rari_types::globals::settings; use tracing::error; @@ -48,22 +49,27 @@ pub fn read_docs_parallel>( let stdout_thread = std::thread::spawn(move || rx.into_iter().collect()); // For testing, we do not pay attention to the .gitignore files (walk_builder's // default is to obey them). The test configuration has `reader_ignores_gitignore = true`. + let success = AtomicBool::new(true); let ignore_gitignore = !settings().reader_ignores_gitignore; walk_builder(paths, glob)? .git_ignore(ignore_gitignore) .build_parallel() .run(|| { let tx = tx.clone(); + let success = &success; Box::new(move |result| { if let Ok(f) = result { if f.file_type().map(|ft| ft.is_file()).unwrap_or(false) { let p = f.into_path(); match T::read(p, None) { Ok(doc) => { - tx.send(Ok(doc)).unwrap(); + if let Err(e) = tx.send(Ok(doc)) { + error!("{e}"); + } } Err(e) => { error!("{e}"); + success.store(false, Ordering::Relaxed); //tx.send(Err(e.into())).unwrap(); } } @@ -74,5 +80,10 @@ pub fn read_docs_parallel>( }); drop(tx); - stdout_thread.join().unwrap() + let docs = stdout_thread.join().unwrap(); + if success.load(Ordering::Relaxed) { + docs + } else { + Err(DocError::DocsReadError) + } }