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>
This commit is contained in:
David Wood 2022-04-06 04:16:07 +01:00
parent 4e1927db3c
commit fc3cca24f1
5 changed files with 93 additions and 41 deletions

View File

@ -11,7 +11,7 @@ use std::error::Error;
use std::fmt; use std::fmt;
use std::fs; use std::fs;
use std::io; use std::io;
use std::path::Path; use std::path::{Path, PathBuf};
use tracing::{instrument, trace}; use tracing::{instrument, trace};
#[cfg(parallel_compiler)] #[cfg(parallel_compiler)]
@ -45,7 +45,7 @@ pub enum TranslationBundleError {
/// Failed to add `FluentResource` to `FluentBundle`. /// Failed to add `FluentResource` to `FluentBundle`.
AddResource(FluentError), AddResource(FluentError),
/// `$sysroot/share/locale/$locale` does not exist. /// `$sysroot/share/locale/$locale` does not exist.
MissingLocale(io::Error), MissingLocale,
/// Cannot read directory entries of `$sysroot/share/locale/$locale`. /// Cannot read directory entries of `$sysroot/share/locale/$locale`.
ReadLocalesDir(io::Error), ReadLocalesDir(io::Error),
/// Cannot read directory entry of `$sysroot/share/locale/$locale`. /// 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) write!(f, "could not parse ftl file: {}", e)
} }
TranslationBundleError::AddResource(e) => write!(f, "failed to add resource: {}", e), TranslationBundleError::AddResource(e) => write!(f, "failed to add resource: {}", e),
TranslationBundleError::MissingLocale(e) => { TranslationBundleError::MissingLocale => write!(f, "missing locale directory"),
write!(f, "missing locale directory: {}", e)
}
TranslationBundleError::ReadLocalesDir(e) => { TranslationBundleError::ReadLocalesDir(e) => {
write!(f, "could not read locales dir: {}", e) write!(f, "could not read locales dir: {}", e)
} }
@ -84,7 +82,7 @@ impl Error for TranslationBundleError {
TranslationBundleError::ReadFtl(e) => Some(e), TranslationBundleError::ReadFtl(e) => Some(e),
TranslationBundleError::ParseFtl(e) => Some(e), TranslationBundleError::ParseFtl(e) => Some(e),
TranslationBundleError::AddResource(e) => Some(e), TranslationBundleError::AddResource(e) => Some(e),
TranslationBundleError::MissingLocale(e) => Some(e), TranslationBundleError::MissingLocale => None,
TranslationBundleError::ReadLocalesDir(e) => Some(e), TranslationBundleError::ReadLocalesDir(e) => Some(e),
TranslationBundleError::ReadLocalesDirEntry(e) => Some(e), TranslationBundleError::ReadLocalesDirEntry(e) => Some(e),
TranslationBundleError::LocaleIsNotDir => None, TranslationBundleError::LocaleIsNotDir => None,
@ -113,7 +111,8 @@ impl From<Vec<FluentError>> for TranslationBundleError {
/// (overriding any conflicting messages). /// (overriding any conflicting messages).
#[instrument(level = "trace")] #[instrument(level = "trace")]
pub fn fluent_bundle( pub fn fluent_bundle(
sysroot: &Path, mut user_provided_sysroot: Option<PathBuf>,
mut sysroot_candidates: Vec<PathBuf>,
requested_locale: Option<LanguageIdentifier>, requested_locale: Option<LanguageIdentifier>,
additional_ftl_path: Option<&Path>, additional_ftl_path: Option<&Path>,
with_directionality_markers: bool, 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 the user requests the default locale then don't try to load anything.
if !requested_fallback_locale && let Some(requested_locale) = requested_locale { if !requested_fallback_locale && let Some(requested_locale) = requested_locale {
let mut sysroot = sysroot.to_path_buf(); let mut found_resources = false;
sysroot.push("share"); for sysroot in user_provided_sysroot.iter_mut().chain(sysroot_candidates.iter_mut()) {
sysroot.push("locale"); sysroot.push("share");
sysroot.push(requested_locale.to_string()); sysroot.push("locale");
trace!(?sysroot); sysroot.push(requested_locale.to_string());
trace!(?sysroot);
let _ = sysroot.try_exists().map_err(TranslationBundleError::MissingLocale)?; if !sysroot.exists() {
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"); trace!("skipping");
continue; continue;
} }
let resource_str = if !sysroot.is_dir() {
fs::read_to_string(path).map_err(TranslationBundleError::ReadFtl)?; return Err(TranslationBundleError::LocaleIsNotDir);
let resource = }
FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?;
trace!(?resource); for entry in sysroot.read_dir().map_err(TranslationBundleError::ReadLocalesDir)? {
bundle.add_resource(resource).map_err(TranslationBundleError::from)?; 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);
} }
} }

View File

@ -44,6 +44,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
let sess = build_session( let sess = build_session(
sessopts, sessopts,
None, None,
None,
registry, registry,
DiagnosticOutput::Default, DiagnosticOutput::Default,
Default::default(), Default::default(),

View File

@ -83,9 +83,23 @@ pub fn create_session(
// target_override is documented to be called before init(), so this is okay // target_override is documented to be called before init(), so this is okay
let target_override = codegen_backend.target_override(&sopts); 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( let mut sess = session::build_session(
sopts, sopts,
input_path, input_path,
bundle,
descriptions, descriptions,
diagnostic_output, diagnostic_output,
lint_caps, lint_caps,

View File

@ -20,8 +20,8 @@ use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType};
use rustc_errors::json::JsonEmitter; use rustc_errors::json::JsonEmitter;
use rustc_errors::registry::Registry; use rustc_errors::registry::Registry;
use rustc_errors::{ use rustc_errors::{
fallback_fluent_bundle, fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, EmissionGuarantee,
EmissionGuarantee, ErrorGuaranteed, FluentBundle, MultiSpan, ErrorGuaranteed, FluentBundle, MultiSpan,
}; };
use rustc_macros::HashStable_Generic; use rustc_macros::HashStable_Generic;
pub use rustc_span::def_id::StableCrateId; pub use rustc_span::def_id::StableCrateId;
@ -1162,6 +1162,7 @@ pub enum DiagnosticOutput {
pub fn build_session( pub fn build_session(
sopts: config::Options, sopts: config::Options,
local_crate_source_file: Option<PathBuf>, local_crate_source_file: Option<PathBuf>,
bundle: Option<Lrc<rustc_errors::FluentBundle>>,
registry: rustc_errors::registry::Registry, registry: rustc_errors::registry::Registry,
diagnostics_output: DiagnosticOutput, diagnostics_output: DiagnosticOutput,
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>, driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
@ -1214,16 +1215,17 @@ pub fn build_session(
hash_kind, 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 = let fallback_bundle =
fallback_fluent_bundle(sopts.debugging_opts.translate_directionality_markers) match fallback_fluent_bundle(sopts.debugging_opts.translate_directionality_markers) {
.expect("failed to load fallback fluent bundle"); Ok(bundle) => bundle,
Err(e) => {
early_error(
sopts.error_format,
&format!("failed to load fallback fluent bundle: {e}"),
);
}
};
let emitter = let emitter =
default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle, write_dest); default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle, write_dest);

View File

@ -15,7 +15,9 @@ normal: basic-translation.rs
custom: basic-translation.rs basic-translation.ftl custom: basic-translation.rs basic-translation.ftl
$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/basic-translation.ftl 2>&1 | grep "this is a test message" $(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 sysroot: basic-translation.rs basic-translation.ftl
mkdir $(FAKEROOT) mkdir $(FAKEROOT)
ln -s $(SYSROOT)/* $(FAKEROOT) ln -s $(SYSROOT)/* $(FAKEROOT)
@ -31,3 +33,27 @@ sysroot: basic-translation.rs basic-translation.ftl
mkdir -p $(FAKEROOT)/share/locale/zh-CN/ mkdir -p $(FAKEROOT)/share/locale/zh-CN/
ln -s $(CURDIR)/basic-translation.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl 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" $(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"