From fc3cca24f1230bb308e83168a3260abf36359f85 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 6 Apr 2022 04:16:07 +0100 Subject: [PATCH] sess: try sysroot candidates for fluent bundle Instead of checking only the user provided sysroot or the default (when no sysroot is provided), search user provided sysroot and then check default sysroots for locale requested by the user. Signed-off-by: David Wood --- compiler/rustc_error_messages/src/lib.rs | 67 ++++++++++++++---------- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_interface/src/util.rs | 14 +++++ compiler/rustc_session/src/session.rs | 24 +++++---- src/test/run-make/translation/Makefile | 28 +++++++++- 5 files changed, 93 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 88f3b547605..b33e6b66117 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -11,7 +11,7 @@ use std::error::Error; use std::fmt; use std::fs; use std::io; -use std::path::Path; +use std::path::{Path, PathBuf}; use tracing::{instrument, trace}; #[cfg(parallel_compiler)] @@ -45,7 +45,7 @@ pub enum TranslationBundleError { /// Failed to add `FluentResource` to `FluentBundle`. AddResource(FluentError), /// `$sysroot/share/locale/$locale` does not exist. - MissingLocale(io::Error), + MissingLocale, /// Cannot read directory entries of `$sysroot/share/locale/$locale`. ReadLocalesDir(io::Error), /// Cannot read directory entry of `$sysroot/share/locale/$locale`. @@ -62,9 +62,7 @@ impl fmt::Display for TranslationBundleError { write!(f, "could not parse ftl file: {}", e) } TranslationBundleError::AddResource(e) => write!(f, "failed to add resource: {}", e), - TranslationBundleError::MissingLocale(e) => { - write!(f, "missing locale directory: {}", e) - } + TranslationBundleError::MissingLocale => write!(f, "missing locale directory"), TranslationBundleError::ReadLocalesDir(e) => { write!(f, "could not read locales dir: {}", e) } @@ -84,7 +82,7 @@ impl Error for TranslationBundleError { TranslationBundleError::ReadFtl(e) => Some(e), TranslationBundleError::ParseFtl(e) => Some(e), TranslationBundleError::AddResource(e) => Some(e), - TranslationBundleError::MissingLocale(e) => Some(e), + TranslationBundleError::MissingLocale => None, TranslationBundleError::ReadLocalesDir(e) => Some(e), TranslationBundleError::ReadLocalesDirEntry(e) => Some(e), TranslationBundleError::LocaleIsNotDir => None, @@ -113,7 +111,8 @@ impl From> for TranslationBundleError { /// (overriding any conflicting messages). #[instrument(level = "trace")] pub fn fluent_bundle( - sysroot: &Path, + mut user_provided_sysroot: Option, + mut sysroot_candidates: Vec, requested_locale: Option, additional_ftl_path: Option<&Path>, with_directionality_markers: bool, @@ -140,33 +139,43 @@ pub fn fluent_bundle( // If the user requests the default locale then don't try to load anything. if !requested_fallback_locale && let Some(requested_locale) = requested_locale { - let mut sysroot = sysroot.to_path_buf(); - sysroot.push("share"); - sysroot.push("locale"); - sysroot.push(requested_locale.to_string()); - trace!(?sysroot); + let mut found_resources = false; + for sysroot in user_provided_sysroot.iter_mut().chain(sysroot_candidates.iter_mut()) { + sysroot.push("share"); + sysroot.push("locale"); + sysroot.push(requested_locale.to_string()); + trace!(?sysroot); - let _ = sysroot.try_exists().map_err(TranslationBundleError::MissingLocale)?; - - if !sysroot.is_dir() { - return Err(TranslationBundleError::LocaleIsNotDir); - } - - for entry in sysroot.read_dir().map_err(TranslationBundleError::ReadLocalesDir)? { - let entry = entry.map_err(TranslationBundleError::ReadLocalesDirEntry)?; - let path = entry.path(); - trace!(?path); - if path.extension().and_then(|s| s.to_str()) != Some("ftl") { + if !sysroot.exists() { trace!("skipping"); continue; } - let resource_str = - fs::read_to_string(path).map_err(TranslationBundleError::ReadFtl)?; - let resource = - FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?; - trace!(?resource); - bundle.add_resource(resource).map_err(TranslationBundleError::from)?; + if !sysroot.is_dir() { + return Err(TranslationBundleError::LocaleIsNotDir); + } + + for entry in sysroot.read_dir().map_err(TranslationBundleError::ReadLocalesDir)? { + let entry = entry.map_err(TranslationBundleError::ReadLocalesDirEntry)?; + let path = entry.path(); + trace!(?path); + if path.extension().and_then(|s| s.to_str()) != Some("ftl") { + trace!("skipping"); + continue; + } + + let resource_str = + fs::read_to_string(path).map_err(TranslationBundleError::ReadFtl)?; + let resource = + FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?; + trace!(?resource); + bundle.add_resource(resource).map_err(TranslationBundleError::from)?; + found_resources = true; + } + } + + if !found_resources { + return Err(TranslationBundleError::MissingLocale); } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index a3570320767..fe75ee8b37b 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -44,6 +44,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { let sess = build_session( sessopts, None, + None, registry, DiagnosticOutput::Default, Default::default(), diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 592cf60e6c3..3fa8017dc93 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -83,9 +83,23 @@ pub fn create_session( // target_override is documented to be called before init(), so this is okay let target_override = codegen_backend.target_override(&sopts); + let bundle = match rustc_errors::fluent_bundle( + sopts.maybe_sysroot.clone(), + sysroot_candidates(), + sopts.debugging_opts.translate_lang.clone(), + sopts.debugging_opts.translate_additional_ftl.as_deref(), + sopts.debugging_opts.translate_directionality_markers, + ) { + Ok(bundle) => bundle, + Err(e) => { + early_error(sopts.error_format, &format!("failed to load fluent bundle: {e}")); + } + }; + let mut sess = session::build_session( sopts, input_path, + bundle, descriptions, diagnostic_output, lint_caps, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 9881046ddfa..d70f89760a1 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -20,8 +20,8 @@ use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType}; use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ - fallback_fluent_bundle, fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, - EmissionGuarantee, ErrorGuaranteed, FluentBundle, MultiSpan, + fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, EmissionGuarantee, + ErrorGuaranteed, FluentBundle, MultiSpan, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -1162,6 +1162,7 @@ pub enum DiagnosticOutput { pub fn build_session( sopts: config::Options, local_crate_source_file: Option, + bundle: Option>, registry: rustc_errors::registry::Registry, diagnostics_output: DiagnosticOutput, driver_lint_caps: FxHashMap, @@ -1214,16 +1215,17 @@ pub fn build_session( hash_kind, )); - let bundle = fluent_bundle( - &sysroot, - sopts.debugging_opts.translate_lang.clone(), - sopts.debugging_opts.translate_additional_ftl.as_deref(), - sopts.debugging_opts.translate_directionality_markers, - ) - .expect("failed to load fluent bundle"); let fallback_bundle = - fallback_fluent_bundle(sopts.debugging_opts.translate_directionality_markers) - .expect("failed to load fallback fluent bundle"); + match fallback_fluent_bundle(sopts.debugging_opts.translate_directionality_markers) { + Ok(bundle) => bundle, + Err(e) => { + early_error( + sopts.error_format, + &format!("failed to load fallback fluent bundle: {e}"), + ); + } + }; + let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle, write_dest); diff --git a/src/test/run-make/translation/Makefile b/src/test/run-make/translation/Makefile index 22a3bf57ecf..bfff75e7acb 100644 --- a/src/test/run-make/translation/Makefile +++ b/src/test/run-make/translation/Makefile @@ -15,7 +15,9 @@ normal: basic-translation.rs custom: basic-translation.rs basic-translation.ftl $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/basic-translation.ftl 2>&1 | grep "this is a test message" -# Make a local copy of the sysroot and add the custom locale to it. +# Check that a locale can be loaded from the sysroot given a language +# identifier by making a local copy of the sysroot and adding the custom locale +# to it. sysroot: basic-translation.rs basic-translation.ftl mkdir $(FAKEROOT) ln -s $(SYSROOT)/* $(FAKEROOT) @@ -31,3 +33,27 @@ sysroot: basic-translation.rs basic-translation.ftl mkdir -p $(FAKEROOT)/share/locale/zh-CN/ ln -s $(CURDIR)/basic-translation.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl $(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | grep "this is a test message" + +# Check that the compiler errors out when the sysroot requested cannot be +# found. This test might start failing if there actually exists a Klingon +# translation of rustc's error messages. +sysroot-missing: + $(RUSTC) $< -Ztranslate-lang=tlh 2>&1 || grep "missing locale directory" + +# Check that the compiler errors out when the sysroot requested cannot be +# found. This test might start failing if there actually exists a Klingon +# translation of rustc's error messages. +sysroot-invalid: basic-translation.rs basic-translation.ftl + mkdir $(FAKEROOT) + ln -s $(SYSROOT)/* $(FAKEROOT) + rm -f $(FAKEROOT)/lib + mkdir $(FAKEROOT)/lib + ln -s $(SYSROOT)/lib/* $(FAKEROOT)/lib + rm -f $(FAKEROOT)/lib/rustlib + mkdir $(FAKEROOT)/lib/rustlib + ln -s $(SYSROOT)/lib/rustlib/* $(FAKEROOT)/lib/rustlib + rm -f $(FAKEROOT)/lib/rustlib/src + mkdir $(FAKEROOT)/lib/rustlib/src + ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src + touch $(FAKEROOT)/share/locale/zh-CN/ + $(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 || grep "`\$sysroot/share/locales/\$locale` is not a directory"