about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david.wood@huawei.com>2022-04-06 04:16:07 +0100
committerDavid Wood <david.wood@huawei.com>2022-04-12 10:15:37 +0100
commitfc3cca24f1230bb308e83168a3260abf36359f85 (patch)
tree4312fa6d31df8a626db8fb8c046226261300bec9
parent4e1927db3c399fa34dc71992bd5dbec09f945c3d (diff)
downloadrust-fc3cca24f1230bb308e83168a3260abf36359f85.tar.gz
rust-fc3cca24f1230bb308e83168a3260abf36359f85.zip
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 <david.wood@huawei.com>
-rw-r--r--compiler/rustc_error_messages/src/lib.rs69
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_interface/src/util.rs14
-rw-r--r--compiler/rustc_session/src/session.rs24
-rw-r--r--src/test/run-make/translation/Makefile28
5 files changed, 94 insertions, 42 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<Vec<FluentError>> for TranslationBundleError {
 /// (overriding any conflicting messages).
 #[instrument(level = "trace")]
 pub fn fluent_bundle(
-    sysroot: &Path,
+    mut user_provided_sysroot: Option<PathBuf>,
+    mut sysroot_candidates: Vec<PathBuf>,
     requested_locale: Option<LanguageIdentifier>,
     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 _ = 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") {
+        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);
+
+            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<PathBuf>,
+    bundle: Option<Lrc<rustc_errors::FluentBundle>>,
     registry: rustc_errors::registry::Registry,
     diagnostics_output: DiagnosticOutput,
     driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
@@ -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"