From 4488aedb5949d66e5b1fc6e7c72b206c1bf182b7 Mon Sep 17 00:00:00 2001 From: Florian Dieminger Date: Tue, 28 Jan 2025 20:56:26 +0100 Subject: [PATCH] feat(tools): add validate-redirects and support locale arg * add validate-redirects command * support locale arguments for fix-redirects --- crates/rari-cli/main.rs | 23 +- crates/rari-tools/src/add_redirect.rs | 10 +- crates/rari-tools/src/error.rs | 4 + crates/rari-tools/src/redirects.rs | 244 +++++++++++++++--- crates/rari-tools/src/remove.rs | 10 +- crates/rari-tools/src/sidebars.rs | 2 +- .../rari-tools/src/sync_translated_content.rs | 64 +++-- .../src/tests/fixtures/redirects.rs | 15 +- crates/rari-tools/src/utils.rs | 2 +- 9 files changed, 277 insertions(+), 97 deletions(-) diff --git a/crates/rari-cli/main.rs b/crates/rari-cli/main.rs index 101a09a8..34d7c9f8 100644 --- a/crates/rari-cli/main.rs +++ b/crates/rari-cli/main.rs @@ -31,7 +31,7 @@ use rari_tools::add_redirect::add_redirect; use rari_tools::history::gather_history; use rari_tools::inventory::gather_inventory; use rari_tools::r#move::r#move; -use rari_tools::redirects::fix_redirects; +use rari_tools::redirects::{fix_redirects, validate_redirects}; use rari_tools::remove::remove; use rari_tools::sidebars::{fmt_sidebars, sync_sidebars}; use rari_tools::sync_translated_content::sync_translated_content; @@ -104,7 +104,9 @@ enum ContentSubcommand { /// /// This shortens multiple redirect chains to single ones. /// This is also run as part of sync_translated_content. - FixRedirects, + FixRedirects(FixRedirectArgs), + /// Validate redirects. + ValidateRedirects(ValidateRedirectArgs), /// Create content inventory as JSON Inventory, } @@ -136,6 +138,16 @@ struct AddRedirectArgs { to_url: String, } +#[derive(Args)] +struct ValidateRedirectArgs { + locales: Option>, +} + +#[derive(Args)] +struct FixRedirectArgs { + locales: Option>, +} + #[derive(Args)] struct SyncTranslatedContentArgs { locales: Option>, @@ -467,8 +479,11 @@ fn main() -> Result<(), Error> { ContentSubcommand::SyncSidebars => { sync_sidebars()?; } - ContentSubcommand::FixRedirects => { - fix_redirects()?; + ContentSubcommand::FixRedirects(args) => { + fix_redirects(args.locales.as_deref())?; + } + ContentSubcommand::ValidateRedirects(args) => { + validate_redirects(args.locales.as_deref())?; } ContentSubcommand::Inventory => { gather_inventory()?; diff --git a/crates/rari-tools/src/add_redirect.rs b/crates/rari-tools/src/add_redirect.rs index c50fc416..860342a4 100644 --- a/crates/rari-tools/src/add_redirect.rs +++ b/crates/rari-tools/src/add_redirect.rs @@ -96,7 +96,7 @@ mod test { ]; let _docs = DocFixtures::new(&slugs, Locale::EnUs); let _redirects = RedirectFixtures::new( - &vec![( + &[( "docs/Web/API/Something".to_string(), "docs/Web/API/SomethingElse".to_string(), )], @@ -122,7 +122,7 @@ mod test { fn test_add_redirect_missing_target() { let slugs = vec!["Web/API/ExampleOne".to_string()]; let _docs = DocFixtures::new(&slugs, Locale::EnUs); - let _redirects = RedirectFixtures::new(&vec![], Locale::EnUs); + let _redirects = RedirectFixtures::new(&[], Locale::EnUs); let result = do_add_redirect( "/en-US/docs/Web/API/ExampleGone", @@ -136,8 +136,8 @@ mod test { let slugs = vec!["Web/API/ExampleOne".to_string()]; let _docs = DocFixtures::new(&slugs, Locale::EnUs); let _docs_pt = DocFixtures::new(&slugs, Locale::PtBr); - let _redirects = RedirectFixtures::new(&vec![], Locale::EnUs); - let _redirects_pt = RedirectFixtures::new(&vec![], Locale::PtBr); + let _redirects = RedirectFixtures::new(&[], Locale::EnUs); + let _redirects_pt = RedirectFixtures::new(&[], Locale::PtBr); // Locales do not match let result = do_add_redirect( @@ -166,7 +166,7 @@ mod test { fn test_add_redirect_external() { let slugs = vec!["Web/API/ExampleOne".to_string()]; let _docs = DocFixtures::new(&slugs, Locale::EnUs); - let _redirects = RedirectFixtures::new(&vec![], Locale::EnUs); + let _redirects = RedirectFixtures::new(&[], Locale::EnUs); let result = do_add_redirect("/en-US/docs/Web/API/ExampleGone", "https://example.com/"); assert!(result.is_ok()); diff --git a/crates/rari-tools/src/error.rs b/crates/rari-tools/src/error.rs index 2c48ec04..59ef10e4 100644 --- a/crates/rari-tools/src/error.rs +++ b/crates/rari-tools/src/error.rs @@ -45,6 +45,10 @@ pub enum ToolError { InvalidRedirectFromURL(String), #[error("Invalid 'to' URL for redirect: {0}")] InvalidRedirectToURL(String), + #[error("Invalid redirects: not in alphabetical order: {0} -> {1} before {2} -> {3}")] + InvalidRedirectOrder(String, String, String, String), + #[error("Invalid redirect for {0} -> {1} or {2} -> {3}")] + InvalidRedirect(String, String, String, String), #[error(transparent)] RedirectError(#[from] RedirectError), #[error("Invalid yaml {0}")] diff --git a/crates/rari-tools/src/redirects.rs b/crates/rari-tools/src/redirects.rs index 5f9886ed..f876e7bf 100644 --- a/crates/rari-tools/src/redirects.rs +++ b/crates/rari-tools/src/redirects.rs @@ -212,10 +212,13 @@ pub fn add_redirects(locale: Locale, update_pairs: &[(String, String)]) -> Resul let mut pairs = HashMap::new(); let path = redirects_path(locale)?; - if let Err(e) = read_redirects_raw(&path, &mut pairs) { - error!("Error reading redirects: {e}"); - return Err(ToolError::ReadRedirectsError(e.to_string())); - } + match read_redirects_raw(&path) { + Ok(iter) => pairs.extend(iter), + Err(e) => { + error!("Error reading redirects: {e}"); + return Err(ToolError::ReadRedirectsError(e.to_string())); + } + }; // Separate the pairs into case-only changes and proper redirects let (case_changed_targets, new_pairs) = separate_case_changes(update_pairs); @@ -240,57 +243,183 @@ pub fn add_redirects(locale: Locale, update_pairs: &[(String, String)]) -> Resul Ok(()) } -/// Optimizes redirect rules based on all supported locales. +/// Optimizes and rewrites redirect rules for supported locales. +/// +/// This function: +/// 1. Loads all existing redirects into a unified data structure +/// 2. Runs the `short_cuts` algorithm to optimize the redirect paths +/// 3. Validates and cleans the redirects across locale boundaries +/// 4. Overwrites the original redirect files with optimized versions /// -/// It loads all redirects into a single structure and runs the short_cuts algorithm on it. -/// The goal is to optimize redirects across locale boundaries. +/// An optional locale filter can be provided to only dix specific locales. +/// +/// # Arguments /// -/// This function overwrites all redirect files. +/// * `locale_filter` - Optional slice of locales to fix. If None, fixes all locales. /// /// # Returns /// -/// - `Ok(())` if all operations complete successfully. -/// - `Err(ToolError)` if any step fails, such as: -/// - Invalid locale strings that cannot be parsed. -/// - I/O errors during file reading or writing. -/// - Errors from the `short_cuts` processing function. -pub fn fix_redirects() -> Result<(), ToolError> { +/// - `Ok(())` if optimization succeeds and files are written successfully +/// - `Err(ToolError)` if: +/// - A locale string is invalid or cannot be parsed +/// - File I/O operations fail during read/write +/// - The `short_cuts` optimization encounters errors +/// - Validation of the optimized redirects fails +pub fn fix_redirects(locale_filter: Option<&[Locale]>) -> Result<(), ToolError> { let locales = Locale::for_generic_and_spas(); let mut pairs = HashMap::new(); for locale in locales { let path = redirects_path(*locale)?; - read_redirects_raw(&path, &mut pairs)?; + pairs.extend(read_redirects_raw(&path)?); } - let clean_pairs: HashMap = short_cuts(&pairs)?.into_iter().collect(); - // Split the clean pairs into their respective locales - let locale_pairs = clean_pairs.into_iter().try_fold( - HashMap::>::new(), - |mut acc, (from, to)| -> Result>, ToolError> { - // Extract the locale string from the 'from' path - let locale_str = from.split('/').nth(1).unwrap_or_default(); - - // Parse the locale string into a Locale enum - let locale = Locale::from_str(locale_str).map_err(|_| { - ToolError::InvalidLocale(Cow::Owned(format!( - "Cannot detect a valid locale for '{}'. Search for a '{}\t{}' pair in all _redirects.txt files to locate the problem.", - from, from, to - ))) - })?; - let locale_map = acc.entry(locale).or_default(); - locale_map.insert(from, to); - Ok(acc) - }, - )?; + let locale_pairs = fix_redirects_internal(&pairs)?; // Write the updated maps back to their redirects files - for (locale, pairs) in &locale_pairs { + for (locale, pairs) in locale_pairs.iter().filter(|(locale, _)| { + if let Some(locale_filter) = locale_filter { + locale_filter.contains(locale) + } else { + true + } + }) { let path = redirects_path(*locale)?; write_redirects(&path, pairs)?; } Ok(()) } +/// Fix redirects for supported locales by optimizing redirect paths. +/// +/// This function takes a set of redirect pairs and processes them as follows: +/// 1. Separates the pairs into case-only changes and proper redirects +/// 2. Removes any old redirects that conflict with the new ones +/// 3. Fixes redirect target cases +/// 4. Runs `short_cuts` algorithm to optimize paths +/// 5. Validates the cleaned redirects +/// +/// The function returns a mapping of locales to their cleaned redirects. +/// +/// # Parameters +/// +/// - `pairs`: Map of redirect pairs representing the from/to paths +/// +/// # Returns +/// +/// - `Ok(HashMap>)`: Map of locales to their cleaned redirects +/// - `Err(ToolError)`: If validation fails or cycles are detected in the redirect graph +/// +/// # Errors +/// +/// - `ToolError::InvalidLocale`: If a locale in a redirect path is invalid +/// - `ToolError::RedirectError`: If redirect validation fails or cycles are detected +fn fix_redirects_internal( + pairs: &HashMap, impl AsRef>, +) -> Result>, ToolError> { + let clean_pairs: HashMap = short_cuts(pairs)?.into_iter().collect(); + + // Split the clean pairs into their respective locales + let locale_pairs = clean_pairs.into_iter().try_fold( + HashMap::>::new(), + |mut acc, (from, to)| -> Result>, ToolError> { + // Extract the locale string from the 'from' path + let locale_str = from.split('/').nth(1).unwrap_or_default(); + + // Parse the locale string into a Locale enum + let locale = Locale::from_str(locale_str).map_err(|_| { + ToolError::InvalidLocale(Cow::Owned(format!( + "Cannot detect a valid locale for '{}'. Search for a '{}\t{}' pair in all _redirects.txt files to locate the problem.", + from, from, to + ))) + })?; + let locale_map = acc.entry(locale).or_default(); + locale_map.insert(from, to); + Ok(acc) + }, +)?; + Ok(locale_pairs) +} + +/// Validates all redirects for supported locales. +/// +/// This function checks the validity and optimal structure of redirect files: +/// 1. Reads all redirects files +/// 2. Validates that redirects are stored in sorted order within each file (only if filter applies) +/// 3. Applies `fix_redirects_internal` to optimize and check for cycles +/// 4. Compares generated optimized redirects against existing ones if filter applies. +/// +/// # Parameters +/// +/// * `locale_filter` - Optional slice of locales to validate. If None, validates all locales. +/// +/// # Returns +/// +/// * `Ok(())` - All redirect files are valid and optimally structured +/// * `Err(ToolError)` if: +/// - Redirects are not in sorted order +/// - Redirect optimization would change existing redirects +/// - Invalid locales found in redirect paths +/// - Cycles detected in redirect graph +/// +/// # Errors +/// +/// - `ToolError::InvalidRedirectOrder` if redirects are not sorted +/// - `ToolError::InvalidRedirect` if optimized redirects differ from existing ones +/// - `ToolError::InvalidLocale` if invalid locale found in redirect path +/// - `ToolError::RedirectError` if cycles detected in redirect graph_redirects +pub fn validate_redirects(locale_filter: Option<&[Locale]>) -> Result<(), ToolError> { + let locales = Locale::for_generic_and_spas(); + let locales_to_validate = locale_filter.unwrap_or(locales); + + let mut pairs = HashMap::new(); + for locale in locales { + let path = redirects_path(*locale)?; + let iter = read_redirects_raw(&path)?.into_iter(); + if locales_to_validate.contains(locale) { + let v = iter.collect::>(); + if let Some(t) = v.windows(2).find(|t| t[0].0 > t[1].0) { + return Err(ToolError::InvalidRedirectOrder( + t[0].0.to_string(), + t[0].1.to_string(), + t[1].0.to_string(), + t[0].1.to_string(), + )); + } + pairs.extend(v); + } else { + pairs.extend(iter); + } + } + + let mut locale_pairs = fix_redirects_internal(&pairs)?; + + for locale in locales_to_validate { + let locale_prefix = concat_strs!("/", locale.as_url_str(), "/"); + let old_sorted_map: BTreeMap<_, _> = pairs + .iter() + .filter(|(from, _)| from.starts_with(&locale_prefix)) + .collect(); + let new_sorted_map: BTreeMap<_, _> = locale_pairs + .remove(locale) + .unwrap_or_default() + .into_iter() + .collect(); + + for (old, new) in old_sorted_map.into_iter().zip(new_sorted_map.into_iter()) { + if old.0 != &new.0 || old.1 != &new.1 { + return Err(ToolError::InvalidRedirect( + old.0.clone(), + old.1.clone(), + new.0, + new.1, + )); + } + } + } + + Ok(()) +} + /// Gets the path to the redirects file for a specific locale. pub(crate) fn redirects_path(locale: Locale) -> Result { let root = root_for_locale(locale)?; @@ -501,10 +630,9 @@ fn check_url_invalid_symbols(url: &str) -> Result<(), ToolError> { /// * **File Read Error:** If the file at the specified `path` cannot be opened or read. pub(crate) fn read_redirects_raw( path: &Path, - map: &mut HashMap, -) -> Result<(), ToolError> { +) -> Result, ToolError> { let lines = read_lines(path)?; - map.extend(lines.map_while(Result::ok).filter_map(|line| { + let iter = lines.map_while(Result::ok).filter_map(|line| { if line.starts_with('#') { return None; } @@ -514,10 +642,9 @@ pub(crate) fn read_redirects_raw( } else { None } - })); - Ok(()) + }); + Ok(iter) } - /// Writes the redirects from the HashMap to the specified file path. /// /// Each redirect is written in the format: `from to`. @@ -681,6 +808,7 @@ use serial_test::file_serial; mod tests { use super::*; use crate::tests::fixtures::docs::DocFixtures; + use crate::tests::fixtures::redirects::RedirectFixtures; fn s(s: &str) -> String { s.to_string() @@ -1116,4 +1244,36 @@ mod tests { "The transitive redirects do not match the expected shortcuts." ); } + + #[test] + fn validate_invalid() { + let pairs = [ + ("/en-US/docs/A", "/en-US/docs/B"), + ("/en-US/docs/B", "/en-US/docs/C"), + ] + .map(|(a, b)| (a.to_string(), b.to_string())) + .into_iter() + .collect::>(); + let _all_redirects = RedirectFixtures::all_locales_empty(); + let _redirects = RedirectFixtures::new(&pairs, Locale::EnUs); + let res = validate_redirects(Some(&[Locale::EnUs])); + println!("{res:?}"); + assert!(matches!(res, Err(ToolError::InvalidRedirect(..)))) + } + + #[test] + fn validate_order() { + let pairs = [ + ("/en-US/docs/B", "/en-US/docs/C"), + ("/en-US/docs/A", "/en-US/docs/C"), + ] + .map(|(a, b)| (a.to_string(), b.to_string())) + .into_iter() + .collect::>(); + let _all_redirects = RedirectFixtures::all_locales_empty(); + let _redirects = RedirectFixtures::new(&pairs, Locale::EnUs); + let res = validate_redirects(Some(&[Locale::EnUs])); + println!("{res:?}"); + assert!(matches!(res, Err(ToolError::InvalidRedirectOrder(..)))) + } } diff --git a/crates/rari-tools/src/remove.rs b/crates/rari-tools/src/remove.rs index e5d01e1a..59b9e3f8 100644 --- a/crates/rari-tools/src/remove.rs +++ b/crates/rari-tools/src/remove.rs @@ -414,7 +414,7 @@ mod test { ]; let _docs = DocFixtures::new(&slugs, Locale::EnUs); let _wikihistory = WikihistoryFixtures::new(&slugs, Locale::EnUs); - let _redirects = RedirectFixtures::new(&vec![], Locale::EnUs); + let _redirects = RedirectFixtures::new(&[], Locale::EnUs); let _sidebars = SidebarFixtures::default(); let result = do_remove( @@ -453,7 +453,7 @@ mod test { ]; let _docs = DocFixtures::new(&slugs, Locale::EnUs); let _wikihistory = WikihistoryFixtures::new(&slugs, Locale::EnUs); - let _redirects = RedirectFixtures::new(&vec![], Locale::EnUs); + let _redirects = RedirectFixtures::new(&[], Locale::EnUs); let _sidebars = SidebarFixtures::default(); let result = do_remove("Web/API/ExampleOne", Locale::EnUs, false, None, false); @@ -481,7 +481,7 @@ mod test { ]; let _docs = DocFixtures::new(&slugs, Locale::EnUs); let _wikihistory = WikihistoryFixtures::new(&slugs, Locale::EnUs); - let _redirects = RedirectFixtures::new(&vec![], Locale::EnUs); + let _redirects = RedirectFixtures::new(&[], Locale::EnUs); let _sidebars = SidebarFixtures::default(); let result = do_remove("Web/API/ExampleOne", Locale::EnUs, true, None, false); @@ -512,7 +512,7 @@ mod test { ]; let _docs = DocFixtures::new(&slugs, Locale::EnUs); let _wikihistory = WikihistoryFixtures::new(&slugs, Locale::EnUs); - let _redirects = RedirectFixtures::new(&vec![], Locale::EnUs); + let _redirects = RedirectFixtures::new(&[], Locale::EnUs); let _sidebars = SidebarFixtures::default(); let result = do_remove( @@ -559,7 +559,7 @@ mod test { ]; let _docs = DocFixtures::new(&slugs, Locale::PtBr); let _wikihistory = WikihistoryFixtures::new(&slugs, Locale::PtBr); - let _redirects = RedirectFixtures::new(&vec![], Locale::PtBr); + let _redirects = RedirectFixtures::new(&[], Locale::PtBr); let _sidebars = SidebarFixtures::default(); let result = do_remove( diff --git a/crates/rari-tools/src/sidebars.rs b/crates/rari-tools/src/sidebars.rs index ad446f18..f0f639de 100644 --- a/crates/rari-tools/src/sidebars.rs +++ b/crates/rari-tools/src/sidebars.rs @@ -24,7 +24,7 @@ type Pairs<'a> = &'a [Pair<'a>]; pub fn sync_sidebars() -> Result<(), ToolError> { let mut redirects = HashMap::new(); let path = redirects_path(Locale::default())?; - read_redirects_raw(&path, &mut redirects)?; + redirects.extend(read_redirects_raw(&path)?); let pairs = redirects .iter() .map(|(from, to)| { diff --git a/crates/rari-tools/src/sync_translated_content.rs b/crates/rari-tools/src/sync_translated_content.rs index 545dc884..1f399871 100644 --- a/crates/rari-tools/src/sync_translated_content.rs +++ b/crates/rari-tools/src/sync_translated_content.rs @@ -36,7 +36,7 @@ pub fn sync_translated_content( )), ); } - fix_redirects()?; + fix_redirects(Some(locales))?; if verbose { tracing::info!("{}", green.apply_to("Reading all documents.")); @@ -446,14 +446,14 @@ mod test { let _es_redirects = RedirectFixtures::new(&es_redirects, Locale::Es); let _es_wikihistory = WikihistoryFixtures::new(&es_slugs, Locale::Es); - let _de_redirects = RedirectFixtures::new(&vec![], Locale::De); - let _fr_redirects = RedirectFixtures::new(&vec![], Locale::Fr); - let _ja_redirects = RedirectFixtures::new(&vec![], Locale::Ja); - let _ko_redirects = RedirectFixtures::new(&vec![], Locale::Ko); - let _ptbr_redirects = RedirectFixtures::new(&vec![], Locale::PtBr); - let _ru_redirects = RedirectFixtures::new(&vec![], Locale::Ru); - let _zhcn_redirects = RedirectFixtures::new(&vec![], Locale::ZhCn); - let _zhtw_redirects = RedirectFixtures::new(&vec![], Locale::ZhTw); + let _de_redirects = RedirectFixtures::new(&[], Locale::De); + let _fr_redirects = RedirectFixtures::new(&[], Locale::Fr); + let _ja_redirects = RedirectFixtures::new(&[], Locale::Ja); + let _ko_redirects = RedirectFixtures::new(&[], Locale::Ko); + let _ptbr_redirects = RedirectFixtures::new(&[], Locale::PtBr); + let _ru_redirects = RedirectFixtures::new(&[], Locale::Ru); + let _zhcn_redirects = RedirectFixtures::new(&[], Locale::ZhCn); + let _zhtw_redirects = RedirectFixtures::new(&[], Locale::ZhTw); let result = sync_translated_content(&[Locale::Es], false); assert!(result.is_ok()); @@ -501,14 +501,14 @@ mod test { let _es_redirects = RedirectFixtures::new(&es_redirects, Locale::Es); let _es_wikihistory = WikihistoryFixtures::new(&es_slugs, Locale::Es); - let _de_redirects = RedirectFixtures::new(&vec![], Locale::De); - let _fr_redirects = RedirectFixtures::new(&vec![], Locale::Fr); - let _ja_redirects = RedirectFixtures::new(&vec![], Locale::Ja); - let _ko_redirects = RedirectFixtures::new(&vec![], Locale::Ko); - let _ptbr_redirects = RedirectFixtures::new(&vec![], Locale::PtBr); - let _ru_redirects = RedirectFixtures::new(&vec![], Locale::Ru); - let _zhcn_redirects = RedirectFixtures::new(&vec![], Locale::ZhCn); - let _zhtw_redirects = RedirectFixtures::new(&vec![], Locale::ZhTw); + let _de_redirects = RedirectFixtures::new(&[], Locale::De); + let _fr_redirects = RedirectFixtures::new(&[], Locale::Fr); + let _ja_redirects = RedirectFixtures::new(&[], Locale::Ja); + let _ko_redirects = RedirectFixtures::new(&[], Locale::Ko); + let _ptbr_redirects = RedirectFixtures::new(&[], Locale::PtBr); + let _ru_redirects = RedirectFixtures::new(&[], Locale::Ru); + let _zhcn_redirects = RedirectFixtures::new(&[], Locale::ZhCn); + let _zhtw_redirects = RedirectFixtures::new(&[], Locale::ZhTw); let result = sync_translated_content(&[Locale::Es], false); assert!(result.is_ok()); @@ -544,11 +544,8 @@ mod test { assert!(orphaned_path.exists()); let mut redirects = HashMap::new(); - read_redirects_raw( - redirects_path(Locale::Es).unwrap().as_path(), - &mut redirects, - ) - .unwrap(); + redirects + .extend(read_redirects_raw(redirects_path(Locale::Es).unwrap().as_path()).unwrap()); assert_eq!(redirects.len(), 2); assert_eq!( redirects.get("/es/docs/Web/API/Other").unwrap(), @@ -582,14 +579,14 @@ mod test { let _es_redirects = RedirectFixtures::new(&es_redirects, Locale::Es); let _es_wikihistory = WikihistoryFixtures::new(&es_slugs, Locale::Es); - let _de_redirects = RedirectFixtures::new(&vec![], Locale::De); - let _fr_redirects = RedirectFixtures::new(&vec![], Locale::Fr); - let _ja_redirects = RedirectFixtures::new(&vec![], Locale::Ja); - let _ko_redirects = RedirectFixtures::new(&vec![], Locale::Ko); - let _ptbr_redirects = RedirectFixtures::new(&vec![], Locale::PtBr); - let _ru_redirects = RedirectFixtures::new(&vec![], Locale::Ru); - let _zhcn_redirects = RedirectFixtures::new(&vec![], Locale::ZhCn); - let _zhtw_redirects = RedirectFixtures::new(&vec![], Locale::ZhTw); + let _de_redirects = RedirectFixtures::new(&[], Locale::De); + let _fr_redirects = RedirectFixtures::new(&[], Locale::Fr); + let _ja_redirects = RedirectFixtures::new(&[], Locale::Ja); + let _ko_redirects = RedirectFixtures::new(&[], Locale::Ko); + let _ptbr_redirects = RedirectFixtures::new(&[], Locale::PtBr); + let _ru_redirects = RedirectFixtures::new(&[], Locale::Ru); + let _zhcn_redirects = RedirectFixtures::new(&[], Locale::ZhCn); + let _zhtw_redirects = RedirectFixtures::new(&[], Locale::ZhTw); let result = sync_translated_content(&[Locale::Es], false); assert!(result.is_ok()); @@ -624,11 +621,8 @@ mod test { assert!(moved_path.exists()); let mut redirects = HashMap::new(); - read_redirects_raw( - redirects_path(Locale::Es).unwrap().as_path(), - &mut redirects, - ) - .unwrap(); + redirects + .extend(read_redirects_raw(redirects_path(Locale::Es).unwrap().as_path()).unwrap()); assert_eq!(redirects.len(), 1); assert_eq!( redirects.get("/es/docs/Web/API/Other").unwrap(), diff --git a/crates/rari-tools/src/tests/fixtures/redirects.rs b/crates/rari-tools/src/tests/fixtures/redirects.rs index cafc3c28..02431bb7 100644 --- a/crates/rari-tools/src/tests/fixtures/redirects.rs +++ b/crates/rari-tools/src/tests/fixtures/redirects.rs @@ -10,15 +10,22 @@ pub(crate) struct RedirectFixtures { } impl RedirectFixtures { - pub fn new(entries: &Vec<(String, String)>, locale: Locale) -> Self { + pub fn new(entries: &[(String, String)], locale: Locale) -> Self { Self::new_internal(entries, locale, false) } #[allow(dead_code)] - pub fn debug_new(entries: &Vec<(String, String)>, locale: Locale) -> Self { + pub fn debug_new(entries: &[(String, String)], locale: Locale) -> Self { Self::new_internal(entries, locale, true) } - fn new_internal(entries: &Vec<(String, String)>, locale: Locale, do_not_remove: bool) -> Self { + pub fn all_locales_empty() -> Vec { + Locale::for_generic_and_spas() + .iter() + .map(|locale| Self::new_internal(&[], *locale, false)) + .collect() + } + + fn new_internal(entries: &[(String, String)], locale: Locale, do_not_remove: bool) -> Self { // create wiki history file for each slug in the vector, in the configured root directory for the locale let mut folder_path = PathBuf::new(); folder_path.push(root_for_locale(locale).unwrap()); @@ -60,6 +67,6 @@ impl Drop for RedirectFixtures { return; } - fs::remove_file(&self.path).unwrap(); + fs::remove_file(&self.path).ok(); } } diff --git a/crates/rari-tools/src/utils.rs b/crates/rari-tools/src/utils.rs index 07cbddbe..09ced119 100644 --- a/crates/rari-tools/src/utils.rs +++ b/crates/rari-tools/src/utils.rs @@ -45,7 +45,7 @@ pub(crate) fn read_all_doc_pages() -> Result) pub(crate) fn get_redirects_map(locale: Locale) -> HashMap { let redirects_path = redirects_path(locale).unwrap(); let mut redirects = HashMap::new(); - redirects::read_redirects_raw(&redirects_path, &mut redirects).unwrap(); + redirects.extend(redirects::read_redirects_raw(&redirects_path).unwrap()); redirects }