From 7786f7f38842d705f1d031c5ba08b10ef5638927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:01:49 +0800 Subject: [PATCH 1/3] run-make-support: add `sysroot` helper Convenience helper for `rustc --print=sysroot`. --- src/tools/run-make-support/src/external_deps/rustc.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index 8894ea7fb209b..b70db7130f677 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -1,5 +1,6 @@ use std::ffi::{OsStr, OsString}; -use std::path::Path; +use std::path::{Path, PathBuf}; +use std::str::FromStr as _; use crate::command::Command; use crate::env::env_var; @@ -390,3 +391,10 @@ impl Rustc { self } } + +/// Query the sysroot path corresponding `rustc --print=sysroot`. +#[track_caller] +pub fn sysroot() -> PathBuf { + let path = rustc().print("sysroot").run().stdout_utf8(); + PathBuf::from_str(path.trim()).unwrap() +} From 1912d565a8c6aa6ebe82b7fc753b07a89ff2b664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:03:21 +0800 Subject: [PATCH 2/3] run-make-support: improve docs for `assert_exit_code` --- src/tools/run-make-support/src/command.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index b4dc753ab5347..c31e79e167389 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -388,9 +388,15 @@ impl CompletedProcess { self } + /// Check the **exit status** of the process. On Unix, this is *not* the **wait status**. + /// + /// See [`std::process::ExitStatus::code`]. This is not to be confused with + /// [`std::process::ExitCode`]. #[track_caller] pub fn assert_exit_code(&self, code: i32) -> &Self { - assert!(self.output.status.code() == Some(code)); + // FIXME(jieyouxu): this should really be named `exit_status`, because std has an `ExitCode` + // that means a different thing. + assert_eq!(self.output.status.code(), Some(code)); self } } From 388a52f55151186731eec45f52a3786112ee3dcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= <39484203+jieyouxu@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:03:18 +0800 Subject: [PATCH 3/3] tests: port `translation` to rmake.rs Co-authored-by: Oneirical --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/translation/Makefile | 78 -------- tests/run-make/translation/rmake.rs | 174 ++++++++++++++++++ 3 files changed, 174 insertions(+), 79 deletions(-) delete mode 100644 tests/run-make/translation/Makefile create mode 100644 tests/run-make/translation/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 6f0fd09b353a5..e75d3dc2147bc 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,3 +1,2 @@ run-make/split-debuginfo/Makefile run-make/symbol-mangling-hashed/Makefile -run-make/translation/Makefile diff --git a/tests/run-make/translation/Makefile b/tests/run-make/translation/Makefile deleted file mode 100644 index 07e0547cfa090..0000000000000 --- a/tests/run-make/translation/Makefile +++ /dev/null @@ -1,78 +0,0 @@ -include ../tools.mk - -# This test uses `ln -s` rather than copying to save testing time, but its -# usage doesn't work on Windows. -# ignore-windows - -SYSROOT:=$(shell $(RUSTC) --print sysroot) -FAKEROOT=$(TMPDIR)/fakeroot -RUSTC_LOG:=rustc_error_messages -export RUSTC_TRANSLATION_NO_DEBUG_ASSERT:=1 - -all: normal custom missing broken sysroot sysroot-invalid sysroot-missing - -# Check that the test works normally, using the built-in fallback bundle. -normal: test.rs - $(RUSTC) $< 2>&1 | $(CGREP) "struct literal body without path" - -# Check that a primary bundle can be loaded and will be preferentially used -# where possible. -custom: test.rs working.ftl - $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/working.ftl 2>&1 | $(CGREP) "this is a test message" - -# Check that a primary bundle with a broken message (e.g. a interpolated -# variable is missing) will use the fallback bundle. -missing: test.rs missing.ftl - $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/missing.ftl 2>&1 | $(CGREP) "struct literal body without path" - -# Check that a primary bundle without the desired message will use the fallback -# bundle. -broken: test.rs broken.ftl - $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/broken.ftl 2>&1 | $(CGREP) "struct literal body without path" - -# 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: test.rs working.ftl - rm -rf $(FAKEROOT) - 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 - # When download-rustc is enabled, `$(SYSROOT)` will have a share directory. Delete the link to it. - rm -f $(FAKEROOT)/share - mkdir -p $(FAKEROOT)/share/locale/zh-CN/ - ln -s $(CURDIR)/working.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl - $(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | $(CGREP) "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 | $(CGREP) "missing locale directory" - -# Check that the compiler errors out when the directory for the locale in the -# sysroot is actually a file. -sysroot-invalid: test.rs working.ftl - rm -rf $(FAKEROOT) - 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 - mkdir -p $(FAKEROOT)/share/locale - touch $(FAKEROOT)/share/locale/zh-CN - $(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | $(CGREP) "`\$sysroot/share/locales/\$locale` is not a directory" diff --git a/tests/run-make/translation/rmake.rs b/tests/run-make/translation/rmake.rs new file mode 100644 index 0000000000000..79b9c0dd67896 --- /dev/null +++ b/tests/run-make/translation/rmake.rs @@ -0,0 +1,174 @@ +//! Smoke test for the rustc diagnostics translation infrastructure. +//! +//! # References +//! +//! - Current tracking issue: . +//! - Old tracking issue: +//! - Initial translation infra implementation: . + +// This test uses symbolic links to stub out a fake sysroot to save testing time. +//@ needs-symlink +//@ needs-subprocess + +#![deny(warnings)] + +use std::path::{Path, PathBuf}; + +use run_make_support::rustc::sysroot; +use run_make_support::{cwd, rfs, run_in_tmpdir, rustc}; + +fn main() { + builtin_fallback_bundle(); + additional_primary_bundle(); + missing_slug_prefers_fallback_bundle(); + broken_primary_bundle_prefers_fallback_bundle(); + locale_sysroot(); + missing_sysroot(); + file_sysroot(); +} + +/// Check that the test works normally, using the built-in fallback bundle. +fn builtin_fallback_bundle() { + rustc().input("test.rs").run_fail().assert_stderr_contains("struct literal body without path"); +} + +/// Check that a primary bundle can be loaded and will be preferentially used where possible. +fn additional_primary_bundle() { + rustc() + .input("test.rs") + .arg("-Ztranslate-additional-ftl=working.ftl") + .run_fail() + .assert_stderr_contains("this is a test message"); +} + +/// Check that a primary bundle without the desired message will use the fallback bundle. +fn missing_slug_prefers_fallback_bundle() { + rustc() + .input("test.rs") + .arg("-Ztranslate-additional-ftl=missing.ftl") + .run_fail() + .assert_stderr_contains("struct literal body without path"); +} + +/// Check that a primary bundle with a broken message (e.g. an interpolated variable is not +/// provided) will use the fallback bundle. +fn broken_primary_bundle_prefers_fallback_bundle() { + // FIXME(#135817): as of the rmake.rs port, the compiler actually ICEs on the additional + // `broken.ftl`, even though the original intention seems to be that it should gracefully + // failover to the fallback bundle. + + rustc() + .env("RUSTC_ICE", "0") // disable ICE dump file, not needed + .input("test.rs") + .arg("-Ztranslate-additional-ftl=broken.ftl") + .run_fail() + .assert_exit_code(101); +} + +#[track_caller] +fn shallow_symlink_dir_entries(src_dir: &Path, dst_dir: &Path) { + for entry in rfs::read_dir(src_dir) { + let entry = entry.unwrap(); + let src_entry_path = entry.path(); + let src_filename = src_entry_path.file_name().unwrap(); + let meta = rfs::symlink_metadata(&src_entry_path); + + if meta.is_symlink() || meta.is_file() { + rfs::symlink_file(&src_entry_path, dst_dir.join(src_filename)); + } else if meta.is_dir() { + rfs::symlink_dir(&src_entry_path, dst_dir.join(src_filename)); + } else { + unreachable!() + } + } +} + +#[track_caller] +fn shallow_symlink_dir_entries_materialize_single_dir( + src_dir: &Path, + dst_dir: &Path, + dir_filename: &str, +) { + shallow_symlink_dir_entries(src_dir, dst_dir); + rfs::remove_file(dst_dir.join(dir_filename)); + rfs::create_dir_all(dst_dir.join(dir_filename)); +} + +#[track_caller] +fn setup_fakeroot_parents() -> PathBuf { + let sysroot = sysroot(); + let fakeroot = cwd().join("fakeroot"); + rfs::create_dir_all(&fakeroot); + shallow_symlink_dir_entries_materialize_single_dir(&sysroot, &fakeroot, "lib"); + shallow_symlink_dir_entries_materialize_single_dir( + &sysroot.join("lib"), + &fakeroot.join("lib"), + "rustlib", + ); + shallow_symlink_dir_entries_materialize_single_dir( + &sysroot.join("lib").join("rustlib"), + &fakeroot.join("lib").join("rustlib"), + "src", + ); + shallow_symlink_dir_entries( + &sysroot.join("lib").join("rustlib").join("src"), + &fakeroot.join("lib").join("rustlib").join("src"), + ); + fakeroot +} + +/// 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. +fn locale_sysroot() { + run_in_tmpdir(|| { + let fakeroot = setup_fakeroot_parents(); + + // When download-rustc is enabled, real sysroot will have a share directory. Delete the link + // to it. + let _ = std::fs::remove_file(fakeroot.join("share")); + + let fake_locale_path = fakeroot.join("share").join("locale").join("zh-CN"); + rfs::create_dir_all(&fake_locale_path); + rfs::symlink_file( + cwd().join("working.ftl"), + fake_locale_path.join("basic-translation.ftl"), + ); + + rustc() + .env("RUSTC_ICE", "0") + .input("test.rs") + .sysroot(&fakeroot) + .arg("-Ztranslate-lang=zh-CN") + .run_fail() + .assert_stderr_contains("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. +fn missing_sysroot() { + run_in_tmpdir(|| { + rustc() + .input("test.rs") + .arg("-Ztranslate-lang=tlh") + .run_fail() + .assert_stderr_contains("missing locale directory"); + }); +} + +/// Check that the compiler errors out when the directory for the locale in the sysroot is actually +/// a file. +fn file_sysroot() { + run_in_tmpdir(|| { + let fakeroot = setup_fakeroot_parents(); + rfs::create_dir_all(fakeroot.join("share").join("locale")); + rfs::write(fakeroot.join("share").join("locale").join("zh-CN"), b"not a dir"); + + rustc() + .input("test.rs") + .sysroot(&fakeroot) + .arg("-Ztranslate-lang=zh-CN") + .run_fail() + .assert_stderr_contains("is not a directory"); + }); +}