Auto merge of #127760 - jieyouxu:rmake-support-reorganize, r=Kobzol

Reorganize the `run-make-support` library

The `run_make_support` library has a kitchen sink `lib.rs` that make discovery/learning very difficult. Let's try to improve that by breaking up `lib.rs` into smaller more organized modules. This is a precursor to improving the documentation and learnability of the `run_make_support` library.

### Changes

- Breakup `lib.rs` into smaller modules according to functionality
- Rename `recursive_diff` -> `assert_dirs_are_equal`
- Rename one of the `read_dir` with callback interface as `read_dir_entries`
- Coalesced fs-related stuff onto a `fs` module, re-exported to tests as `rfs`
- Minor doc improvements / fixes in a few places (I have a follow-up documentation PR planned)

This PR is best reviewed commit-by-commit.

r? `@Kobzol` (or Mark, or T-compiler or T-bootstrap)

try-job: x86_64-msvc
try-job: aarch64-apple
try-job: test-various
try-job: armhf-gnu
try-job: dist-x86_64-linux
This commit is contained in:
bors 2024-07-17 15:52:03 +00:00
commit f00f850919
104 changed files with 1064 additions and 905 deletions

View File

@ -0,0 +1,81 @@
//! A collection of helpers to construct artifact names, such as names of dynamic or static
//! librarys which are target-dependent.
use crate::targets::{is_darwin, is_msvc, is_windows};
/// Construct the static library name based on the target.
#[must_use]
pub fn static_lib_name(name: &str) -> String {
// See tools.mk (irrelevant lines omitted):
//
// ```makefile
// ifeq ($(UNAME),Darwin)
// STATICLIB = $(TMPDIR)/lib$(1).a
// else
// ifdef IS_WINDOWS
// ifdef IS_MSVC
// STATICLIB = $(TMPDIR)/$(1).lib
// else
// STATICLIB = $(TMPDIR)/lib$(1).a
// endif
// else
// STATICLIB = $(TMPDIR)/lib$(1).a
// endif
// endif
// ```
assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace");
if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") }
}
/// Construct the dynamic library name based on the target.
#[must_use]
pub fn dynamic_lib_name(name: &str) -> String {
// See tools.mk (irrelevant lines omitted):
//
// ```makefile
// ifeq ($(UNAME),Darwin)
// DYLIB = $(TMPDIR)/lib$(1).dylib
// else
// ifdef IS_WINDOWS
// DYLIB = $(TMPDIR)/$(1).dll
// else
// DYLIB = $(TMPDIR)/lib$(1).so
// endif
// endif
// ```
assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace");
let extension = dynamic_lib_extension();
if is_darwin() {
format!("lib{name}.{extension}")
} else if is_windows() {
format!("{name}.{extension}")
} else {
format!("lib{name}.{extension}")
}
}
/// Construct the dynamic library extension based on the target.
#[must_use]
pub fn dynamic_lib_extension() -> &'static str {
if is_darwin() {
"dylib"
} else if is_windows() {
"dll"
} else {
"so"
}
}
/// Construct the name of a rust library (rlib).
#[must_use]
pub fn rust_lib_name(name: &str) -> String {
format!("lib{name}.rlib")
}
/// Construct the binary (executable) name based on the target.
#[must_use]
pub fn bin_name(name: &str) -> String {
if is_windows() { format!("{name}.exe") } else { name.to_string() }
}

View File

@ -0,0 +1,73 @@
//! Collection of assertions and assertion-related helpers.
use std::panic;
use std::path::Path;
use crate::fs;
/// Assert that `actual` is equal to `expected`.
#[track_caller]
pub fn assert_equals<A: AsRef<str>, E: AsRef<str>>(actual: A, expected: E) {
let actual = actual.as_ref();
let expected = expected.as_ref();
if actual != expected {
eprintln!("=== ACTUAL TEXT ===");
eprintln!("{}", actual);
eprintln!("=== EXPECTED ===");
eprintln!("{}", expected);
panic!("expected text was not found in actual text");
}
}
/// Assert that `haystack` contains `needle`.
#[track_caller]
pub fn assert_contains<H: AsRef<str>, N: AsRef<str>>(haystack: H, needle: N) {
let haystack = haystack.as_ref();
let needle = needle.as_ref();
if !haystack.contains(needle) {
eprintln!("=== HAYSTACK ===");
eprintln!("{}", haystack);
eprintln!("=== NEEDLE ===");
eprintln!("{}", needle);
panic!("needle was not found in haystack");
}
}
/// Assert that `haystack` does not contain `needle`.
#[track_caller]
pub fn assert_not_contains<H: AsRef<str>, N: AsRef<str>>(haystack: H, needle: N) {
let haystack = haystack.as_ref();
let needle = needle.as_ref();
if haystack.contains(needle) {
eprintln!("=== HAYSTACK ===");
eprintln!("{}", haystack);
eprintln!("=== NEEDLE ===");
eprintln!("{}", needle);
panic!("needle was unexpectedly found in haystack");
}
}
/// Assert that all files in `dir1` exist and have the same content in `dir2`
pub fn assert_dirs_are_equal(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) {
let dir2 = dir2.as_ref();
fs::read_dir_entries(dir1, |entry_path| {
let entry_name = entry_path.file_name().unwrap();
if entry_path.is_dir() {
assert_dirs_are_equal(&entry_path, &dir2.join(entry_name));
} else {
let path2 = dir2.join(entry_name);
let file1 = fs::read(&entry_path);
let file2 = fs::read(&path2);
// We don't use `assert_eq!` because they are `Vec<u8>`, so not great for display.
// Why not using String? Because there might be minified files or even potentially
// binary ones, so that would display useless output.
assert!(
file1 == file2,
"`{}` and `{}` have different content",
entry_path.display(),
path2.display(),
);
}
});
}

View File

@ -5,7 +5,9 @@ use std::panic;
use std::path::Path;
use std::process::{Command as StdCommand, ExitStatus, Output, Stdio};
use crate::{assert_contains, assert_equals, assert_not_contains, handle_failed_output};
use crate::util::handle_failed_output;
use crate::{assert_contains, assert_equals, assert_not_contains};
use build_helper::drop_bomb::DropBomb;
/// This is a custom command wrapper that simplifies working with commands and makes it easier to

View File

@ -1,10 +1,12 @@
use regex::Regex;
use similar::TextDiff;
use std::path::{Path, PathBuf};
use crate::fs_wrapper;
use regex::Regex;
use similar::TextDiff;
use build_helper::drop_bomb::DropBomb;
use crate::fs;
#[cfg(test)]
mod tests;
@ -43,7 +45,7 @@ impl Diff {
/// Specify the expected output for the diff from a file.
pub fn expected_file<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
let path = path.as_ref();
let content = fs_wrapper::read_to_string(path);
let content = fs::read_to_string(path);
let name = path.to_string_lossy().to_string();
self.expected_file = Some(path.into());
@ -62,7 +64,7 @@ impl Diff {
/// Specify the actual output for the diff from a file.
pub fn actual_file<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
let path = path.as_ref();
let content = fs_wrapper::read_to_string(path);
let content = fs::read_to_string(path);
let name = path.to_string_lossy().to_string();
self.actual = Some(content);
@ -116,7 +118,7 @@ impl Diff {
if let Some(ref expected_file) = self.expected_file {
if std::env::var("RUSTC_BLESS_TEST").is_ok() {
println!("Blessing `{}`", expected_file.display());
fs_wrapper::write(expected_file, actual);
fs::write(expected_file, actual);
return;
}
}
@ -138,7 +140,7 @@ impl Diff {
if let Some(ref expected_file) = self.expected_file {
if std::env::var("RUSTC_BLESS_TEST").is_ok() {
println!("Blessing `{}`", expected_file.display());
fs_wrapper::write(expected_file, actual);
fs::write(expected_file, actual);
return;
}
}

View File

@ -0,0 +1,19 @@
use std::ffi::OsString;
#[track_caller]
#[must_use]
pub fn env_var(name: &str) -> String {
match std::env::var(name) {
Ok(v) => v,
Err(err) => panic!("failed to retrieve environment variable {name:?}: {err:?}"),
}
}
#[track_caller]
#[must_use]
pub fn env_var_os(name: &str) -> OsString {
match std::env::var_os(name) {
Some(v) => v,
None => panic!("failed to retrieve environment variable {name:?}"),
}
}

View File

@ -0,0 +1,27 @@
use std::path::PathBuf;
use crate::artifact_names::static_lib_name;
use crate::external_deps::cc::cc;
use crate::external_deps::llvm::llvm_ar;
use crate::path_helpers::path;
use crate::targets::is_msvc;
/// Builds a static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name.
#[track_caller]
pub fn build_native_static_lib(lib_name: &str) -> PathBuf {
let obj_file = if is_msvc() { format!("{lib_name}") } else { format!("{lib_name}.o") };
let src = format!("{lib_name}.c");
let lib_path = static_lib_name(lib_name);
if is_msvc() {
cc().arg("-c").out_exe(&obj_file).input(src).run();
} else {
cc().arg("-v").arg("-c").out_exe(&obj_file).input(src).run();
};
let obj_file = if is_msvc() {
PathBuf::from(format!("{lib_name}.obj"))
} else {
PathBuf::from(format!("{lib_name}.o"))
};
llvm_ar().obj_to_ar().output_input(&lib_path, &obj_file).run();
path(lib_path)
}

View File

@ -1,7 +1,10 @@
use std::path::Path;
use crate::command::Command;
use crate::{cygpath_windows, env_var, is_msvc, is_windows, uname};
use crate::{env_var, is_msvc, is_windows, uname};
// FIXME(jieyouxu): can we get rid of the `cygpath` external dependency?
use super::cygpath::get_windows_path;
/// Construct a new platform-specific C compiler invocation.
///
@ -20,7 +23,7 @@ pub struct Cc {
cmd: Command,
}
crate::impl_common_helpers!(Cc);
crate::macros::impl_common_helpers!(Cc);
impl Cc {
/// Construct a new platform-specific C compiler invocation.
@ -72,10 +75,10 @@ impl Cc {
if is_msvc() {
path.set_extension("exe");
let fe_path = cygpath_windows(&path);
let fe_path = get_windows_path(&path);
path.set_extension("");
path.set_extension("obj");
let fo_path = cygpath_windows(path);
let fo_path = get_windows_path(path);
self.cmd.arg(format!("-Fe:{fe_path}"));
self.cmd.arg(format!("-Fo:{fo_path}"));
} else {

View File

@ -16,7 +16,7 @@ pub struct Clang {
cmd: Command,
}
crate::impl_common_helpers!(Clang);
crate::macros::impl_common_helpers!(Clang);
impl Clang {
/// Construct a new `clang` invocation. `clang` is not always available for all targets.

View File

@ -0,0 +1,35 @@
use std::panic;
use std::path::Path;
use crate::command::Command;
use crate::util::handle_failed_output;
/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
/// available on the platform!
///
/// # FIXME
///
/// FIXME(jieyouxu): we should consider not depending on `cygpath`.
///
/// > The cygpath program is a utility that converts Windows native filenames to Cygwin POSIX-style
/// > pathnames and vice versa.
/// >
/// > [irrelevant entries omitted...]
/// >
/// > `-w, --windows print Windows form of NAMEs (C:\WINNT)`
/// >
/// > -- *from [cygpath documentation](https://cygwin.com/cygwin-ug-net/cygpath.html)*.
#[track_caller]
#[must_use]
pub fn get_windows_path<P: AsRef<Path>>(path: P) -> String {
let caller = panic::Location::caller();
let mut cygpath = Command::new("cygpath");
cygpath.arg("-w");
cygpath.arg(path.as_ref());
let output = cygpath.run();
if !output.status().success() {
handle_failed_output(&cygpath, output, caller.line());
}
// cygpath -w can attach a newline
output.stdout_utf8().trim().to_string()
}

View File

@ -0,0 +1,14 @@
use crate::command::Command;
use crate::source_root;
use super::python::python_command;
/// `htmldocck` is a python script which is used for rustdoc test suites, it is assumed to be
/// available at `$SOURCE_ROOT/src/etc/htmldocck.py`.
#[track_caller]
#[must_use]
pub fn htmldocck() -> Command {
let mut python = python_command();
python.arg(source_root().join("src/etc/htmldocck.py"));
python
}

View File

@ -1,6 +1,7 @@
use std::path::{Path, PathBuf};
use crate::{env_var, Command};
use crate::command::Command;
use crate::env::env_var;
/// Construct a new `llvm-readobj` invocation with the `GNU` output style.
/// This assumes that `llvm-readobj` is available at `$LLVM_BIN_DIR/llvm-readobj`.
@ -70,11 +71,11 @@ pub struct LlvmAr {
cmd: Command,
}
crate::impl_common_helpers!(LlvmReadobj);
crate::impl_common_helpers!(LlvmProfdata);
crate::impl_common_helpers!(LlvmFilecheck);
crate::impl_common_helpers!(LlvmObjdump);
crate::impl_common_helpers!(LlvmAr);
crate::macros::impl_common_helpers!(LlvmReadobj);
crate::macros::impl_common_helpers!(LlvmProfdata);
crate::macros::impl_common_helpers!(LlvmFilecheck);
crate::macros::impl_common_helpers!(LlvmObjdump);
crate::macros::impl_common_helpers!(LlvmAr);
/// Generate the path to the bin directory of LLVM.
#[must_use]

View File

@ -0,0 +1,14 @@
//! This module contains external tool dependencies that we assume are available in the environment,
//! such as `cc` or `python`.
pub mod c_build;
pub mod cc;
pub mod clang;
pub mod htmldocck;
pub mod llvm;
pub mod python;
pub mod rustc;
pub mod rustdoc;
// Library-internal external dependency.
mod cygpath;

View File

@ -0,0 +1,11 @@
use crate::command::Command;
use crate::env::env_var;
/// Obtain path of python as provided by the `PYTHON` environment variable. It is up to the caller
/// to document and check if the python version is compatible with its intended usage.
#[track_caller]
#[must_use]
pub fn python_command() -> Command {
let python_path = env_var("PYTHON");
Command::new(python_path)
}

View File

@ -1,8 +1,10 @@
use command::Command;
use std::ffi::{OsStr, OsString};
use std::path::Path;
use crate::{command, cwd, env_var, set_host_rpath};
use crate::command::Command;
use crate::env::env_var;
use crate::path_helpers::cwd;
use crate::util::set_host_rpath;
/// Construct a new `rustc` invocation. This will automatically set the library
/// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this.
@ -31,7 +33,7 @@ pub struct Rustc {
cmd: Command,
}
crate::impl_common_helpers!(Rustc);
crate::macros::impl_common_helpers!(Rustc);
#[track_caller]
fn setup_common() -> Command {

View File

@ -2,7 +2,8 @@ use std::ffi::OsStr;
use std::path::Path;
use crate::command::Command;
use crate::{env_var, env_var_os, set_host_rpath};
use crate::env::{env_var, env_var_os};
use crate::util::set_host_rpath;
/// Construct a plain `rustdoc` invocation with no flags set.
#[track_caller]
@ -22,7 +23,7 @@ pub struct Rustdoc {
cmd: Command,
}
crate::impl_common_helpers!(Rustdoc);
crate::macros::impl_common_helpers!(Rustdoc);
#[track_caller]
fn setup_common() -> Command {

View File

@ -1,17 +1,82 @@
use std::fs;
use std::io;
use std::path::Path;
// FIXME(jieyouxu): modify create_symlink to panic on windows.
/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix.
#[cfg(target_family = "windows")]
pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
if link.as_ref().exists() {
std::fs::remove_dir(link.as_ref()).unwrap();
}
std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!(
"failed to create symlink {:?} for {:?}",
link.as_ref().display(),
original.as_ref().display(),
));
}
/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix.
#[cfg(target_family = "unix")]
pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
if link.as_ref().exists() {
std::fs::remove_dir(link.as_ref()).unwrap();
}
std::os::unix::fs::symlink(original.as_ref(), link.as_ref()).expect(&format!(
"failed to create symlink {:?} for {:?}",
link.as_ref().display(),
original.as_ref().display(),
));
}
/// Copy a directory into another.
pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
fn copy_dir_all_inner(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
let dst = dst.as_ref();
if !dst.is_dir() {
std::fs::create_dir_all(&dst)?;
}
for entry in std::fs::read_dir(src)? {
let entry = entry?;
let ty = entry.file_type()?;
if ty.is_dir() {
copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
} else {
std::fs::copy(entry.path(), dst.join(entry.file_name()))?;
}
}
Ok(())
}
if let Err(e) = copy_dir_all_inner(&src, &dst) {
// Trying to give more context about what exactly caused the failure
panic!(
"failed to copy `{}` to `{}`: {:?}",
src.as_ref().display(),
dst.as_ref().display(),
e
);
}
}
/// Helper for reading entries in a given directory.
pub fn read_dir_entries<P: AsRef<Path>, F: FnMut(&Path)>(dir: P, mut callback: F) {
for entry in read_dir(dir) {
callback(&entry.unwrap().path());
}
}
/// A wrapper around [`std::fs::remove_file`] which includes the file path in the panic message.
#[track_caller]
pub fn remove_file<P: AsRef<Path>>(path: P) {
fs::remove_file(path.as_ref())
std::fs::remove_file(path.as_ref())
.expect(&format!("the file in path \"{}\" could not be removed", path.as_ref().display()));
}
/// A wrapper around [`std::fs::copy`] which includes the file path in the panic message.
#[track_caller]
pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
fs::copy(from.as_ref(), to.as_ref()).expect(&format!(
std::fs::copy(from.as_ref(), to.as_ref()).expect(&format!(
"the file \"{}\" could not be copied over to \"{}\"",
from.as_ref().display(),
to.as_ref().display(),
@ -21,21 +86,21 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
/// A wrapper around [`std::fs::File::create`] which includes the file path in the panic message.
#[track_caller]
pub fn create_file<P: AsRef<Path>>(path: P) {
fs::File::create(path.as_ref())
std::fs::File::create(path.as_ref())
.expect(&format!("the file in path \"{}\" could not be created", path.as_ref().display()));
}
/// A wrapper around [`std::fs::read`] which includes the file path in the panic message.
#[track_caller]
pub fn read<P: AsRef<Path>>(path: P) -> Vec<u8> {
fs::read(path.as_ref())
std::fs::read(path.as_ref())
.expect(&format!("the file in path \"{}\" could not be read", path.as_ref().display()))
}
/// A wrapper around [`std::fs::read_to_string`] which includes the file path in the panic message.
#[track_caller]
pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
fs::read_to_string(path.as_ref()).expect(&format!(
std::fs::read_to_string(path.as_ref()).expect(&format!(
"the file in path \"{}\" could not be read into a String",
path.as_ref().display()
))
@ -43,15 +108,15 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
/// A wrapper around [`std::fs::read_dir`] which includes the file path in the panic message.
#[track_caller]
pub fn read_dir<P: AsRef<Path>>(path: P) -> fs::ReadDir {
fs::read_dir(path.as_ref())
pub fn read_dir<P: AsRef<Path>>(path: P) -> std::fs::ReadDir {
std::fs::read_dir(path.as_ref())
.expect(&format!("the directory in path \"{}\" could not be read", path.as_ref().display()))
}
/// A wrapper around [`std::fs::write`] which includes the file path in the panic message.
#[track_caller]
pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
fs::write(path.as_ref(), contents.as_ref()).expect(&format!(
std::fs::write(path.as_ref(), contents.as_ref()).expect(&format!(
"the file in path \"{}\" could not be written to",
path.as_ref().display()
));
@ -60,7 +125,7 @@ pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
/// A wrapper around [`std::fs::remove_dir_all`] which includes the file path in the panic message.
#[track_caller]
pub fn remove_dir_all<P: AsRef<Path>>(path: P) {
fs::remove_dir_all(path.as_ref()).expect(&format!(
std::fs::remove_dir_all(path.as_ref()).expect(&format!(
"the directory in path \"{}\" could not be removed alongside all its contents",
path.as_ref().display(),
));
@ -69,7 +134,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) {
/// A wrapper around [`std::fs::create_dir`] which includes the file path in the panic message.
#[track_caller]
pub fn create_dir<P: AsRef<Path>>(path: P) {
fs::create_dir(path.as_ref()).expect(&format!(
std::fs::create_dir(path.as_ref()).expect(&format!(
"the directory in path \"{}\" could not be created",
path.as_ref().display()
));
@ -78,7 +143,7 @@ pub fn create_dir<P: AsRef<Path>>(path: P) {
/// A wrapper around [`std::fs::create_dir_all`] which includes the file path in the panic message.
#[track_caller]
pub fn create_dir_all<P: AsRef<Path>>(path: P) {
fs::create_dir_all(path.as_ref()).expect(&format!(
std::fs::create_dir_all(path.as_ref()).expect(&format!(
"the directory (and all its parents) in path \"{}\" could not be created",
path.as_ref().display()
));
@ -86,8 +151,8 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) {
/// A wrapper around [`std::fs::metadata`] which includes the file path in the panic message.
#[track_caller]
pub fn metadata<P: AsRef<Path>>(path: P) -> fs::Metadata {
fs::metadata(path.as_ref()).expect(&format!(
pub fn metadata<P: AsRef<Path>>(path: P) -> std::fs::Metadata {
std::fs::metadata(path.as_ref()).expect(&format!(
"the file's metadata in path \"{}\" could not be read",
path.as_ref().display()
))
@ -96,7 +161,7 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> fs::Metadata {
/// A wrapper around [`std::fs::rename`] which includes the file path in the panic message.
#[track_caller]
pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
fs::rename(from.as_ref(), to.as_ref()).expect(&format!(
std::fs::rename(from.as_ref(), to.as_ref()).expect(&format!(
"the file \"{}\" could not be moved over to \"{}\"",
from.as_ref().display(),
to.as_ref().display(),
@ -105,8 +170,8 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
/// A wrapper around [`std::fs::set_permissions`] which includes the file path in the panic message.
#[track_caller]
pub fn set_permissions<P: AsRef<Path>>(path: P, perm: fs::Permissions) {
fs::set_permissions(path.as_ref(), perm).expect(&format!(
pub fn set_permissions<P: AsRef<Path>>(path: P, perm: std::fs::Permissions) {
std::fs::set_permissions(path.as_ref(), perm).expect(&format!(
"the file's permissions in path \"{}\" could not be changed",
path.as_ref().display()
));

View File

@ -3,651 +3,84 @@
//! notably is built via cargo: this means that if your test wants some non-trivial utility, such
//! as `object` or `wasmparser`, they can be re-exported and be made available through this library.
pub mod cc;
pub mod clang;
mod command;
mod macros;
mod util;
pub mod artifact_names;
pub mod assertion_helpers;
pub mod diff;
pub mod fs_wrapper;
pub mod llvm;
pub mod env;
pub mod external_deps;
pub mod path_helpers;
pub mod run;
pub mod rustc;
pub mod rustdoc;
pub mod scoped_run;
pub mod string;
pub mod targets;
use std::env;
use std::ffi::OsString;
use std::fs;
use std::io;
use std::panic;
use std::path::{Path, PathBuf};
mod fs;
/// [`std::fs`] wrappers and assorted filesystem-related helpers. Public to tests as `rfs` to not be
/// confused with [`std::fs`].
pub mod rfs {
pub use crate::fs::*;
}
// Re-exports of third-party library crates.
pub use bstr;
pub use gimli;
pub use object;
pub use regex;
pub use wasmparser;
// Re-exports of external dependencies.
pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rustdoc};
// These rely on external dependencies.
pub use c_build::build_native_static_lib;
pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc};
pub use clang::{clang, Clang};
pub use diff::{diff, Diff};
pub use htmldocck::htmldocck;
pub use llvm::{
llvm_ar, llvm_filecheck, llvm_objdump, llvm_profdata, llvm_readobj, LlvmAr, LlvmFilecheck,
LlvmObjdump, LlvmProfdata, LlvmReadobj,
};
pub use run::{cmd, run, run_fail, run_with_args};
pub use python::python_command;
pub use rustc::{aux_build, bare_rustc, rustc, Rustc};
pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc};
#[track_caller]
#[must_use]
pub fn env_var(name: &str) -> String {
match env::var(name) {
Ok(v) => v,
Err(err) => panic!("failed to retrieve environment variable {name:?}: {err:?}"),
}
}
#[track_caller]
#[must_use]
pub fn env_var_os(name: &str) -> OsString {
match env::var_os(name) {
Some(v) => v,
None => panic!("failed to retrieve environment variable {name:?}"),
}
}
/// `TARGET`
#[must_use]
pub fn target() -> String {
env_var("TARGET")
}
/// Check if target is windows-like.
#[must_use]
pub fn is_windows() -> bool {
target().contains("windows")
}
/// Check if target uses msvc.
#[must_use]
pub fn is_msvc() -> bool {
target().contains("msvc")
}
/// Check if target uses macOS.
#[must_use]
pub fn is_darwin() -> bool {
target().contains("darwin")
}
#[track_caller]
#[must_use]
pub fn python_command() -> Command {
let python_path = env_var("PYTHON");
Command::new(python_path)
}
#[track_caller]
#[must_use]
pub fn htmldocck() -> Command {
let mut python = python_command();
python.arg(source_root().join("src/etc/htmldocck.py"));
python
}
/// Returns the path for a local test file.
pub fn path<P: AsRef<Path>>(p: P) -> PathBuf {
cwd().join(p.as_ref())
}
/// Path to the root rust-lang/rust source checkout.
#[must_use]
pub fn source_root() -> PathBuf {
env_var("SOURCE_ROOT").into()
}
/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix.
#[cfg(target_family = "windows")]
pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
if link.as_ref().exists() {
std::fs::remove_dir(link.as_ref()).unwrap();
}
use std::os::windows::fs;
fs::symlink_file(original.as_ref(), link.as_ref()).expect(&format!(
"failed to create symlink {:?} for {:?}",
link.as_ref().display(),
original.as_ref().display(),
));
}
/// Creates a new symlink to a path on the filesystem, adjusting for Windows or Unix.
#[cfg(target_family = "unix")]
pub fn create_symlink<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
if link.as_ref().exists() {
std::fs::remove_dir(link.as_ref()).unwrap();
}
use std::os::unix::fs;
fs::symlink(original.as_ref(), link.as_ref()).expect(&format!(
"failed to create symlink {:?} for {:?}",
link.as_ref().display(),
original.as_ref().display(),
));
}
/// Construct the static library name based on the platform.
#[must_use]
pub fn static_lib_name(name: &str) -> String {
// See tools.mk (irrelevant lines omitted):
//
// ```makefile
// ifeq ($(UNAME),Darwin)
// STATICLIB = $(TMPDIR)/lib$(1).a
// else
// ifdef IS_WINDOWS
// ifdef IS_MSVC
// STATICLIB = $(TMPDIR)/$(1).lib
// else
// STATICLIB = $(TMPDIR)/lib$(1).a
// endif
// else
// STATICLIB = $(TMPDIR)/lib$(1).a
// endif
// endif
// ```
assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace");
if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") }
}
/// Construct the dynamic library name based on the platform.
#[must_use]
pub fn dynamic_lib_name(name: &str) -> String {
// See tools.mk (irrelevant lines omitted):
//
// ```makefile
// ifeq ($(UNAME),Darwin)
// DYLIB = $(TMPDIR)/lib$(1).dylib
// else
// ifdef IS_WINDOWS
// DYLIB = $(TMPDIR)/$(1).dll
// else
// DYLIB = $(TMPDIR)/lib$(1).so
// endif
// endif
// ```
assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace");
let extension = dynamic_lib_extension();
if is_darwin() {
format!("lib{name}.{extension}")
} else if is_windows() {
format!("{name}.{extension}")
} else {
format!("lib{name}.{extension}")
}
}
#[must_use]
pub fn dynamic_lib_extension() -> &'static str {
if is_darwin() {
"dylib"
} else if is_windows() {
"dll"
} else {
"so"
}
}
/// Generate the name a rust library (rlib) would have.
#[must_use]
pub fn rust_lib_name(name: &str) -> String {
format!("lib{name}.rlib")
}
/// Construct the binary name based on platform.
#[must_use]
pub fn bin_name(name: &str) -> String {
if is_windows() { format!("{name}.exe") } else { name.to_string() }
}
/// Return the current working directory.
#[must_use]
pub fn cwd() -> PathBuf {
env::current_dir().unwrap()
}
// FIXME(Oneirical): This will no longer be required after compiletest receives the ability
// to manipulate read-only files. See https://github.com/rust-lang/rust/issues/126334
/// Ensure that the path P is read-only while the test runs, and restore original permissions
/// at the end so compiletest can clean up.
/// This will panic on Windows if the path is a directory (as it would otherwise do nothing)
#[track_caller]
pub fn test_while_readonly<P: AsRef<Path>, F: FnOnce() + std::panic::UnwindSafe>(
path: P,
closure: F,
) {
let path = path.as_ref();
if is_windows() && path.is_dir() {
eprintln!("This helper function cannot be used on Windows to make directories readonly.");
eprintln!(
"See the official documentation:
https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.set_readonly"
);
panic!("`test_while_readonly` on directory detected while on Windows.");
}
let metadata = fs_wrapper::metadata(&path);
let original_perms = metadata.permissions();
let mut new_perms = original_perms.clone();
new_perms.set_readonly(true);
fs_wrapper::set_permissions(&path, new_perms);
let success = std::panic::catch_unwind(closure);
fs_wrapper::set_permissions(&path, original_perms);
success.unwrap();
}
/// Browse the directory `path` non-recursively and return all files which respect the parameters
/// outlined by `closure`.
#[track_caller]
pub fn shallow_find_files<P: AsRef<Path>, F: Fn(&PathBuf) -> bool>(
path: P,
filter: F,
) -> Vec<PathBuf> {
let mut matching_files = Vec::new();
for entry in fs_wrapper::read_dir(path) {
let entry = entry.expect("failed to read directory entry.");
let path = entry.path();
if path.is_file() && filter(&path) {
matching_files.push(path);
}
}
matching_files
}
/// Returns true if the filename at `path` starts with `prefix`.
pub fn has_prefix<P: AsRef<Path>>(path: P, prefix: &str) -> bool {
path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().starts_with(prefix))
}
/// Returns true if the filename at `path` has the extension `extension`.
pub fn has_extension<P: AsRef<Path>>(path: P, extension: &str) -> bool {
path.as_ref().extension().is_some_and(|ext| ext == extension)
}
/// Returns true if the filename at `path` does not contain `expected`.
pub fn not_contains<P: AsRef<Path>>(path: P, expected: &str) -> bool {
!path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected))
}
/// Builds a static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name.
#[track_caller]
pub fn build_native_static_lib(lib_name: &str) -> PathBuf {
let obj_file = if is_msvc() { format!("{lib_name}") } else { format!("{lib_name}.o") };
let src = format!("{lib_name}.c");
let lib_path = static_lib_name(lib_name);
if is_msvc() {
cc().arg("-c").out_exe(&obj_file).input(src).run();
} else {
cc().arg("-v").arg("-c").out_exe(&obj_file).input(src).run();
};
let obj_file = if is_msvc() {
PathBuf::from(format!("{lib_name}.obj"))
} else {
PathBuf::from(format!("{lib_name}.o"))
};
llvm_ar().obj_to_ar().output_input(&lib_path, &obj_file).run();
path(lib_path)
}
/// Returns true if the filename at `path` is not in `expected`.
pub fn filename_not_in_denylist<P: AsRef<Path>, V: AsRef<[String]>>(path: P, expected: V) -> bool {
let expected = expected.as_ref();
path.as_ref()
.file_name()
.is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned()))
}
/// Returns true if the filename at `path` ends with `suffix`.
pub fn has_suffix<P: AsRef<Path>>(path: P, suffix: &str) -> bool {
path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().ends_with(suffix))
}
/// Gathers all files in the current working directory that have the extension `ext`, and counts
/// the number of lines within that contain a match with the regex pattern `re`.
pub fn count_regex_matches_in_files_with_extension(re: &regex::Regex, ext: &str) -> usize {
let fetched_files = shallow_find_files(cwd(), |path| has_extension(path, ext));
let mut count = 0;
for file in fetched_files {
let content = fs_wrapper::read_to_string(file);
count += content.lines().filter(|line| re.is_match(&line)).count();
}
count
}
/// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is
/// available on the platform!
#[track_caller]
#[must_use]
pub fn cygpath_windows<P: AsRef<Path>>(path: P) -> String {
let caller = panic::Location::caller();
let mut cygpath = Command::new("cygpath");
cygpath.arg("-w");
cygpath.arg(path.as_ref());
let output = cygpath.run();
if !output.status().success() {
handle_failed_output(&cygpath, output, caller.line());
}
// cygpath -w can attach a newline
output.stdout_utf8().trim().to_string()
}
/// Run `uname`. This assumes that `uname` is available on the platform!
#[track_caller]
#[must_use]
pub fn uname() -> String {
let caller = panic::Location::caller();
let mut uname = Command::new("uname");
let output = uname.run();
if !output.status().success() {
handle_failed_output(&uname, output, caller.line());
}
output.stdout_utf8()
}
fn handle_failed_output(cmd: &Command, output: CompletedProcess, caller_line_number: u32) -> ! {
if output.status().success() {
eprintln!("command unexpectedly succeeded at line {caller_line_number}");
} else {
eprintln!("command failed at line {caller_line_number}");
}
eprintln!("{cmd:?}");
eprintln!("output status: `{}`", output.status());
eprintln!("=== STDOUT ===\n{}\n\n", output.stdout_utf8());
eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8());
std::process::exit(1)
}
/// Set the runtime library path as needed for running the host rustc/rustdoc/etc.
pub fn set_host_rpath(cmd: &mut Command) {
let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR");
cmd.env(&ld_lib_path_envvar, {
let mut paths = vec![];
paths.push(cwd());
paths.push(PathBuf::from(env_var("HOST_RPATH_DIR")));
for p in env::split_paths(&env_var(&ld_lib_path_envvar)) {
paths.push(p.to_path_buf());
}
env::join_paths(paths.iter()).unwrap()
});
}
/// Read the contents of a file that cannot simply be read by
/// read_to_string, due to invalid utf8 data, then assert that it contains `expected`.
#[track_caller]
pub fn invalid_utf8_contains<P: AsRef<Path>, S: AsRef<str>>(path: P, expected: S) {
let buffer = fs_wrapper::read(path.as_ref());
let expected = expected.as_ref();
if !String::from_utf8_lossy(&buffer).contains(expected) {
eprintln!("=== FILE CONTENTS (LOSSY) ===");
eprintln!("{}", String::from_utf8_lossy(&buffer));
eprintln!("=== SPECIFIED TEXT ===");
eprintln!("{}", expected);
panic!("specified text was not found in file");
}
}
/// Read the contents of a file that cannot simply be read by
/// read_to_string, due to invalid utf8 data, then assert that it does not contain `expected`.
#[track_caller]
pub fn invalid_utf8_not_contains<P: AsRef<Path>, S: AsRef<str>>(path: P, expected: S) {
let buffer = fs_wrapper::read(path.as_ref());
let expected = expected.as_ref();
if String::from_utf8_lossy(&buffer).contains(expected) {
eprintln!("=== FILE CONTENTS (LOSSY) ===");
eprintln!("{}", String::from_utf8_lossy(&buffer));
eprintln!("=== SPECIFIED TEXT ===");
eprintln!("{}", expected);
panic!("specified text was unexpectedly found in file");
}
}
/// Copy a directory into another.
pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
fn copy_dir_all_inner(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
let dst = dst.as_ref();
if !dst.is_dir() {
std::fs::create_dir_all(&dst)?;
}
for entry in std::fs::read_dir(src)? {
let entry = entry?;
let ty = entry.file_type()?;
if ty.is_dir() {
copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
} else {
std::fs::copy(entry.path(), dst.join(entry.file_name()))?;
}
}
Ok(())
}
if let Err(e) = copy_dir_all_inner(&src, &dst) {
// Trying to give more context about what exactly caused the failure
panic!(
"failed to copy `{}` to `{}`: {:?}",
src.as_ref().display(),
dst.as_ref().display(),
e
);
}
}
/// Check that all files in `dir1` exist and have the same content in `dir2`. Panic otherwise.
pub fn recursive_diff(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) {
let dir2 = dir2.as_ref();
read_dir(dir1, |entry_path| {
let entry_name = entry_path.file_name().unwrap();
if entry_path.is_dir() {
recursive_diff(&entry_path, &dir2.join(entry_name));
} else {
let path2 = dir2.join(entry_name);
let file1 = fs_wrapper::read(&entry_path);
let file2 = fs_wrapper::read(&path2);
// We don't use `assert_eq!` because they are `Vec<u8>`, so not great for display.
// Why not using String? Because there might be minified files or even potentially
// binary ones, so that would display useless output.
assert!(
file1 == file2,
"`{}` and `{}` have different content",
entry_path.display(),
path2.display(),
);
}
});
}
pub fn read_dir<F: FnMut(&Path)>(dir: impl AsRef<Path>, mut callback: F) {
for entry in fs_wrapper::read_dir(dir) {
callback(&entry.unwrap().path());
}
}
/// Check that `actual` is equal to `expected`. Panic otherwise.
#[track_caller]
pub fn assert_equals<S1: AsRef<str>, S2: AsRef<str>>(actual: S1, expected: S2) {
let actual = actual.as_ref();
let expected = expected.as_ref();
if actual != expected {
eprintln!("=== ACTUAL TEXT ===");
eprintln!("{}", actual);
eprintln!("=== EXPECTED ===");
eprintln!("{}", expected);
panic!("expected text was not found in actual text");
}
}
/// Check that `haystack` contains `needle`. Panic otherwise.
#[track_caller]
pub fn assert_contains<S1: AsRef<str>, S2: AsRef<str>>(haystack: S1, needle: S2) {
let haystack = haystack.as_ref();
let needle = needle.as_ref();
if !haystack.contains(needle) {
eprintln!("=== HAYSTACK ===");
eprintln!("{}", haystack);
eprintln!("=== NEEDLE ===");
eprintln!("{}", needle);
panic!("needle was not found in haystack");
}
}
/// Check that `haystack` does not contain `needle`. Panic otherwise.
#[track_caller]
pub fn assert_not_contains<S1: AsRef<str>, S2: AsRef<str>>(haystack: S1, needle: S2) {
let haystack = haystack.as_ref();
let needle = needle.as_ref();
if haystack.contains(needle) {
eprintln!("=== HAYSTACK ===");
eprintln!("{}", haystack);
eprintln!("=== NEEDLE ===");
eprintln!("{}", needle);
panic!("needle was unexpectedly found in haystack");
}
}
/// This function is designed for running commands in a temporary directory
/// that is cleared after the function ends.
/// [`diff`][mod@diff] is implemented in terms of the [similar] library.
///
/// What this function does:
/// 1) Creates a temporary directory (`tmpdir`)
/// 2) Copies all files from the current directory to `tmpdir`
/// 3) Changes the current working directory to `tmpdir`
/// 4) Calls `callback`
/// 5) Switches working directory back to the original one
/// 6) Removes `tmpdir`
pub fn run_in_tmpdir<F: FnOnce()>(callback: F) {
let original_dir = cwd();
let tmpdir = original_dir.join("../temporary-directory");
copy_dir_all(".", &tmpdir);
/// [similar]: https://github.com/mitsuhiko/similar
pub use diff::{diff, Diff};
env::set_current_dir(&tmpdir).unwrap();
callback();
env::set_current_dir(original_dir).unwrap();
fs::remove_dir_all(tmpdir).unwrap();
}
/// Panic-on-fail [`std::env::var`] and [`std::env::var_os`] wrappers.
pub use env::{env_var, env_var_os};
/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
/// containing a `cmd: Command` field. The provided helpers are:
///
/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended
/// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add
/// new specific helper methods over relying on these generic argument providers.
/// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to
/// methods of the same name on [`Command`].
/// 3. Output and execution: `run` and `run_fail` are provided. These are
/// higher-level convenience methods which wait for the command to finish running and assert
/// that the command successfully ran or failed as expected. They return
/// [`CompletedProcess`], which can be used to assert the stdout/stderr/exit code of the executed
/// process.
///
/// Example usage:
///
/// ```ignore (illustrative)
/// struct CommandWrapper { cmd: Command } // <- required `cmd` field
///
/// crate::impl_common_helpers!(CommandWrapper);
///
/// impl CommandWrapper {
/// // ... additional specific helper methods
/// }
/// ```
macro_rules! impl_common_helpers {
($wrapper: ident) => {
impl $wrapper {
/// Specify an environment variable.
pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self
where
K: AsRef<::std::ffi::OsStr>,
V: AsRef<::std::ffi::OsStr>,
{
self.cmd.env(key, value);
self
}
/// Convenience helpers for running binaries and other commands.
pub use run::{cmd, run, run_fail, run_with_args};
/// Remove an environmental variable.
pub fn env_remove<K>(&mut self, key: K) -> &mut Self
where
K: AsRef<::std::ffi::OsStr>,
{
self.cmd.env_remove(key);
self
}
/// Helpers for checking target information.
pub use targets::{is_darwin, is_msvc, is_windows, target, uname};
/// Generic command argument provider. Prefer specific helper methods if possible.
/// Note that for some executables, arguments might be platform specific. For C/C++
/// compilers, arguments might be platform *and* compiler specific.
pub fn arg<S>(&mut self, arg: S) -> &mut Self
where
S: AsRef<::std::ffi::OsStr>,
{
self.cmd.arg(arg);
self
}
/// Helpers for building names of output artifacts that are potentially target-specific.
pub use artifact_names::{
bin_name, dynamic_lib_extension, dynamic_lib_name, rust_lib_name, static_lib_name,
};
/// Generic command arguments provider. Prefer specific helper methods if possible.
/// Note that for some executables, arguments might be platform specific. For C/C++
/// compilers, arguments might be platform *and* compiler specific.
pub fn args<V, S>(&mut self, args: V) -> &mut Self
where
V: AsRef<[S]>,
S: AsRef<::std::ffi::OsStr>,
{
self.cmd.args(args.as_ref());
self
}
/// Path-related helpers.
pub use path_helpers::{
cwd, filename_not_in_denylist, has_extension, has_prefix, has_suffix, not_contains, path,
shallow_find_files, source_root,
};
/// Inspect what the underlying [`Command`] is up to the
/// current construction.
pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
where
I: FnOnce(&::std::process::Command),
{
self.cmd.inspect(inspector);
self
}
/// Helpers for scoped test execution where certain properties are attempted to be maintained.
pub use scoped_run::{run_in_tmpdir, test_while_readonly};
/// Run the constructed command and assert that it is successfully run.
#[track_caller]
pub fn run(&mut self) -> crate::command::CompletedProcess {
self.cmd.run()
}
pub use assertion_helpers::{
assert_contains, assert_dirs_are_equal, assert_equals, assert_not_contains,
};
/// Run the constructed command and assert that it does not successfully run.
#[track_caller]
pub fn run_fail(&mut self) -> crate::command::CompletedProcess {
self.cmd.run_fail()
}
/// Run the command but do not check its exit status.
/// Only use if you explicitly don't care about the exit status.
/// Prefer to use [`Self::run`] and [`Self::run_fail`]
/// whenever possible.
#[track_caller]
pub fn run_unchecked(&mut self) -> crate::command::CompletedProcess {
self.cmd.run_unchecked()
}
/// Set the path where the command will be run.
pub fn current_dir<P: AsRef<::std::path::Path>>(&mut self, path: P) -> &mut Self {
self.cmd.current_dir(path);
self
}
}
};
}
use crate::command::{Command, CompletedProcess};
pub(crate) use impl_common_helpers;
pub use string::{
count_regex_matches_in_files_with_extension, invalid_utf8_contains, invalid_utf8_not_contains,
};

View File

@ -0,0 +1,113 @@
/// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct
/// containing a `cmd: Command` field. The provided helpers are:
///
/// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended
/// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add
/// new specific helper methods over relying on these generic argument providers.
/// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to
/// methods of the same name on [`Command`].
/// 3. Output and execution: `run` and `run_fail` are provided. These are higher-level convenience
/// methods which wait for the command to finish running and assert that the command successfully
/// ran or failed as expected. They return [`CompletedProcess`], which can be used to assert the
/// stdout/stderr/exit code of the executed process.
///
/// Example usage:
///
/// ```ignore (illustrative)
/// struct CommandWrapper { cmd: Command } // <- required `cmd` field
///
/// crate::macros::impl_common_helpers!(CommandWrapper);
///
/// impl CommandWrapper {
/// // ... additional specific helper methods
/// }
/// ```
///
/// [`Command`]: crate::command::Command
/// [`CompletedProcess`]: crate::command::CompletedProcess
macro_rules! impl_common_helpers {
($wrapper: ident) => {
impl $wrapper {
/// Specify an environment variable.
pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Self
where
K: AsRef<::std::ffi::OsStr>,
V: AsRef<::std::ffi::OsStr>,
{
self.cmd.env(key, value);
self
}
/// Remove an environmental variable.
pub fn env_remove<K>(&mut self, key: K) -> &mut Self
where
K: AsRef<::std::ffi::OsStr>,
{
self.cmd.env_remove(key);
self
}
/// Generic command argument provider. Prefer specific helper methods if possible.
/// Note that for some executables, arguments might be platform specific. For C/C++
/// compilers, arguments might be platform *and* compiler specific.
pub fn arg<S>(&mut self, arg: S) -> &mut Self
where
S: AsRef<::std::ffi::OsStr>,
{
self.cmd.arg(arg);
self
}
/// Generic command arguments provider. Prefer specific helper methods if possible.
/// Note that for some executables, arguments might be platform specific. For C/C++
/// compilers, arguments might be platform *and* compiler specific.
pub fn args<V, S>(&mut self, args: V) -> &mut Self
where
V: AsRef<[S]>,
S: AsRef<::std::ffi::OsStr>,
{
self.cmd.args(args.as_ref());
self
}
/// Inspect what the underlying [`Command`] is up to the
/// current construction.
pub fn inspect<I>(&mut self, inspector: I) -> &mut Self
where
I: FnOnce(&::std::process::Command),
{
self.cmd.inspect(inspector);
self
}
/// Run the constructed command and assert that it is successfully run.
#[track_caller]
pub fn run(&mut self) -> crate::command::CompletedProcess {
self.cmd.run()
}
/// Run the constructed command and assert that it does not successfully run.
#[track_caller]
pub fn run_fail(&mut self) -> crate::command::CompletedProcess {
self.cmd.run_fail()
}
/// Run the command but do not check its exit status.
/// Only use if you explicitly don't care about the exit status.
/// Prefer to use [`Self::run`] and [`Self::run_fail`]
/// whenever possible.
#[track_caller]
pub fn run_unchecked(&mut self) -> crate::command::CompletedProcess {
self.cmd.run_unchecked()
}
/// Set the path where the command will be run.
pub fn current_dir<P: AsRef<::std::path::Path>>(&mut self, path: P) -> &mut Self {
self.cmd.current_dir(path);
self
}
}
};
}
pub(crate) use impl_common_helpers;

View File

@ -0,0 +1,80 @@
//! Collection of path-related helpers.
use std::path::{Path, PathBuf};
use crate::env::env_var;
/// Return the current working directory.
///
/// This forwards to [`std::env::current_dir`], please see its docs regarding platform-specific
/// behavior.
#[must_use]
pub fn cwd() -> PathBuf {
std::env::current_dir().unwrap()
}
/// Construct a `PathBuf` relative to the current working directory by joining `cwd()` with the
/// relative path. This is mostly a convenience helper so the test writer does not need to write
/// `PathBuf::from(path_like_string)`.
///
/// # Example
///
/// ```rust
/// let p = path("support_file.txt");
/// ```
pub fn path<P: AsRef<Path>>(p: P) -> PathBuf {
cwd().join(p.as_ref())
}
/// Path to the root `rust-lang/rust` source checkout.
#[must_use]
pub fn source_root() -> PathBuf {
env_var("SOURCE_ROOT").into()
}
/// Browse the directory `path` non-recursively and return all files which respect the parameters
/// outlined by `closure`.
#[track_caller]
pub fn shallow_find_files<P: AsRef<Path>, F: Fn(&PathBuf) -> bool>(
path: P,
filter: F,
) -> Vec<PathBuf> {
let mut matching_files = Vec::new();
for entry in std::fs::read_dir(path).unwrap() {
let entry = entry.expect("failed to read directory entry.");
let path = entry.path();
if path.is_file() && filter(&path) {
matching_files.push(path);
}
}
matching_files
}
/// Returns true if the filename at `path` does not contain `expected`.
pub fn not_contains<P: AsRef<Path>>(path: P, expected: &str) -> bool {
!path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().contains(expected))
}
/// Returns true if the filename at `path` is not in `expected`.
pub fn filename_not_in_denylist<P: AsRef<Path>, V: AsRef<[String]>>(path: P, expected: V) -> bool {
let expected = expected.as_ref();
path.as_ref()
.file_name()
.is_some_and(|name| !expected.contains(&name.to_str().unwrap().to_owned()))
}
/// Returns true if the filename at `path` starts with `prefix`.
pub fn has_prefix<P: AsRef<Path>>(path: P, prefix: &str) -> bool {
path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().starts_with(prefix))
}
/// Returns true if the filename at `path` has the extension `extension`.
pub fn has_extension<P: AsRef<Path>>(path: P, extension: &str) -> bool {
path.as_ref().extension().is_some_and(|ext| ext == extension)
}
/// Returns true if the filename at `path` ends with `suffix`.
pub fn has_suffix<P: AsRef<Path>>(path: P, suffix: &str) -> bool {
path.as_ref().file_name().is_some_and(|name| name.to_str().unwrap().ends_with(suffix))
}

View File

@ -4,9 +4,8 @@ use std::panic;
use std::path::{Path, PathBuf};
use crate::command::{Command, CompletedProcess};
use crate::{cwd, env_var, is_windows, set_host_rpath};
use super::handle_failed_output;
use crate::util::{handle_failed_output, set_host_rpath};
use crate::{cwd, env_var, is_windows};
#[track_caller]
fn run_common(name: &str, args: Option<&[&str]>) -> Command {

View File

@ -0,0 +1,69 @@
//! Collection of helpers that try to maintain certain properties while running a test closure.
use std::path::Path;
use crate::fs;
use crate::path_helpers::cwd;
use crate::targets::is_windows;
/// Ensure that the path P is read-only while the test runs, and restore original permissions at the
/// end so compiletest can clean up. This will panic on Windows if the path is a directory (as it
/// would otherwise do nothing)
///
/// # Pitfalls
///
/// - Some CI runners are ran as root which may bypass read-only permission restrictions. Unclear
/// exactly when such scenarios occur.
///
/// # FIXME
///
/// FIXME(Oneirical): This will no longer be required after compiletest receives the ability to
/// manipulate read-only files. See <https://github.com/rust-lang/rust/issues/126334>.
#[track_caller]
pub fn test_while_readonly<P, F>(path: P, closure: F)
where
P: AsRef<Path>,
F: FnOnce() + std::panic::UnwindSafe,
{
let path = path.as_ref();
if is_windows() && path.is_dir() {
eprintln!("This helper function cannot be used on Windows to make directories readonly.");
eprintln!(
"See the official documentation:
https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.set_readonly"
);
panic!("`test_while_readonly` on directory detected while on Windows.");
}
let metadata = fs::metadata(&path);
let original_perms = metadata.permissions();
let mut new_perms = original_perms.clone();
new_perms.set_readonly(true);
fs::set_permissions(&path, new_perms);
let success = std::panic::catch_unwind(closure);
fs::set_permissions(&path, original_perms);
success.unwrap();
}
/// This function is designed for running commands in a temporary directory that is cleared after
/// the function ends.
///
/// What this function does:
/// 1. Creates a temporary directory (`tmpdir`)
/// 2. Copies all files from the current directory to `tmpdir`
/// 3. Changes the current working directory to `tmpdir`
/// 4. Calls `callback`
/// 5. Switches working directory back to the original one
/// 6. Removes `tmpdir`
pub fn run_in_tmpdir<F: FnOnce()>(callback: F) {
let original_dir = cwd();
let tmpdir = original_dir.join("../temporary-directory");
fs::copy_dir_all(".", &tmpdir);
std::env::set_current_dir(&tmpdir).unwrap();
callback();
std::env::set_current_dir(original_dir).unwrap();
fs::remove_dir_all(tmpdir);
}

View File

@ -0,0 +1,50 @@
use std::path::Path;
use crate::fs;
use crate::path_helpers::{cwd, has_extension, shallow_find_files};
/// Gathers all files in the current working directory that have the extension `ext`, and counts
/// the number of lines within that contain a match with the regex pattern `re`.
pub fn count_regex_matches_in_files_with_extension(re: &regex::Regex, ext: &str) -> usize {
let fetched_files = shallow_find_files(cwd(), |path| has_extension(path, ext));
let mut count = 0;
for file in fetched_files {
let content = fs::read_to_string(file);
count += content.lines().filter(|line| re.is_match(&line)).count();
}
count
}
/// Read the contents of a file that cannot simply be read by
/// [`read_to_string`][crate::fs::read_to_string], due to invalid UTF-8 data, then assert
/// that it contains `expected`.
#[track_caller]
pub fn invalid_utf8_contains<P: AsRef<Path>, S: AsRef<str>>(path: P, expected: S) {
let buffer = fs::read(path.as_ref());
let expected = expected.as_ref();
if !String::from_utf8_lossy(&buffer).contains(expected) {
eprintln!("=== FILE CONTENTS (LOSSY) ===");
eprintln!("{}", String::from_utf8_lossy(&buffer));
eprintln!("=== SPECIFIED TEXT ===");
eprintln!("{}", expected);
panic!("specified text was not found in file");
}
}
/// Read the contents of a file that cannot simply be read by
/// [`read_to_string`][crate::fs::read_to_string], due to invalid UTF-8 data, then assert
/// that it does not contain `expected`.
#[track_caller]
pub fn invalid_utf8_not_contains<P: AsRef<Path>, S: AsRef<str>>(path: P, expected: S) {
let buffer = fs::read(path.as_ref());
let expected = expected.as_ref();
if String::from_utf8_lossy(&buffer).contains(expected) {
eprintln!("=== FILE CONTENTS (LOSSY) ===");
eprintln!("{}", String::from_utf8_lossy(&buffer));
eprintln!("=== SPECIFIED TEXT ===");
eprintln!("{}", expected);
panic!("specified text was unexpectedly found in file");
}
}

View File

@ -0,0 +1,42 @@
use std::panic;
use crate::command::Command;
use crate::env_var;
use crate::util::handle_failed_output;
/// `TARGET`
#[must_use]
pub fn target() -> String {
env_var("TARGET")
}
/// Check if target is windows-like.
#[must_use]
pub fn is_windows() -> bool {
target().contains("windows")
}
/// Check if target uses msvc.
#[must_use]
pub fn is_msvc() -> bool {
target().contains("msvc")
}
/// Check if target uses macOS.
#[must_use]
pub fn is_darwin() -> bool {
target().contains("darwin")
}
/// Run `uname`. This assumes that `uname` is available on the platform!
#[track_caller]
#[must_use]
pub fn uname() -> String {
let caller = panic::Location::caller();
let mut uname = Command::new("uname");
let output = uname.run();
if !output.status().success() {
handle_failed_output(&uname, output, caller.line());
}
output.stdout_utf8()
}

View File

@ -0,0 +1,39 @@
use std::path::PathBuf;
use crate::command::{Command, CompletedProcess};
use crate::env::env_var;
use crate::path_helpers::cwd;
/// If a given [`Command`] failed (as indicated by its [`CompletedProcess`]), verbose print the
/// executed command, failure location, output status and stdout/stderr, and abort the process with
/// exit code `1`.
pub(crate) fn handle_failed_output(
cmd: &Command,
output: CompletedProcess,
caller_line_number: u32,
) -> ! {
if output.status().success() {
eprintln!("command unexpectedly succeeded at line {caller_line_number}");
} else {
eprintln!("command failed at line {caller_line_number}");
}
eprintln!("{cmd:?}");
eprintln!("output status: `{}`", output.status());
eprintln!("=== STDOUT ===\n{}\n\n", output.stdout_utf8());
eprintln!("=== STDERR ===\n{}\n\n", output.stderr_utf8());
std::process::exit(1)
}
/// Set the runtime library path as needed for running the host rustc/rustdoc/etc.
pub(crate) fn set_host_rpath(cmd: &mut Command) {
let ld_lib_path_envvar = env_var("LD_LIB_PATH_ENVVAR");
cmd.env(&ld_lib_path_envvar, {
let mut paths = vec![];
paths.push(cwd());
paths.push(PathBuf::from(env_var("HOST_RPATH_DIR")));
for p in std::env::split_paths(&env_var(&ld_lib_path_envvar)) {
paths.push(p.to_path_buf());
}
std::env::join_paths(paths.iter()).unwrap()
});
}

View File

@ -5,14 +5,14 @@
use std::path::PathBuf;
use run_make_support::{aux_build, fs_wrapper, rustc, source_root};
use run_make_support::{aux_build, rfs, rustc, source_root};
fn main() {
aux_build().input("stable.rs").emit("metadata").run();
let output =
rustc().input("main.rs").emit("metadata").extern_("stable", "libstable.rmeta").run();
let version = fs_wrapper::read_to_string(source_root().join("src/version"));
let version = rfs::read_to_string(source_root().join("src/version"));
let expected_string = format!("stable since {}", version.trim());
output.assert_stderr_contains(expected_string);
}

View File

@ -3,9 +3,7 @@
//@ ignore-cross-compile
use run_make_support::{
cc, cwd, dynamic_lib_extension, fs_wrapper, is_msvc, read_dir, run, run_fail, rustc,
};
use run_make_support::{cc, cwd, dynamic_lib_extension, is_msvc, rfs, run, run_fail, rustc};
fn main() {
rustc().input("foo.rs").run();
@ -21,14 +19,14 @@ fn main() {
run("bar");
let expected_extension = dynamic_lib_extension();
read_dir(cwd(), |path| {
rfs::read_dir_entries(cwd(), |path| {
if path.is_file()
&& path.extension().is_some_and(|ext| ext == expected_extension)
&& path.file_name().and_then(|name| name.to_str()).is_some_and(|name| {
name.ends_with(".so") || name.ends_with(".dll") || name.ends_with(".dylib")
})
{
fs_wrapper::remove_file(path);
rfs::remove_file(path);
}
});
run_fail("bar");

View File

@ -3,7 +3,7 @@
//@ ignore-cross-compile
use run_make_support::fs_wrapper::remove_file;
use run_make_support::rfs::remove_file;
use run_make_support::{cc, extra_c_flags, run, rustc, static_lib_name};
use std::fs;

View File

@ -10,7 +10,7 @@
//@ ignore-cross-compile
use run_make_support::{cc, cwd, dynamic_lib_name, fs_wrapper, is_msvc, run, rustc};
use run_make_support::{cc, cwd, dynamic_lib_name, is_msvc, rfs, run, rustc};
fn main() {
rustc().input("bar.rs").run();
@ -23,7 +23,7 @@ fn main() {
}
run("foo");
fs_wrapper::remove_file(dynamic_lib_name("foo"));
rfs::remove_file(dynamic_lib_name("foo"));
rustc().input("foo.rs").arg("-Clto").run();
run("foo");

View File

@ -10,8 +10,9 @@
use std::path::PathBuf;
use run_make_support::llvm_readobj;
use run_make_support::rfs;
use run_make_support::rustc;
use run_make_support::{cwd, env_var, read_dir, run_in_tmpdir};
use run_make_support::{cwd, env_var, run_in_tmpdir};
fn main() {
let target = env_var("TARGET");
@ -33,7 +34,7 @@ fn main() {
// Check all object files (including temporary outputs) have a `.comment`
// section with the expected content.
read_dir(cwd(), |f| {
rfs::read_dir_entries(cwd(), |f| {
if !f.extension().is_some_and(|ext| ext == "o") {
return;
}

View File

@ -14,12 +14,12 @@
#![deny(warnings)]
use run_make_support::fs_wrapper::{read, read_dir};
use run_make_support::object::read::archive::ArchiveFile;
use run_make_support::object::read::Object;
use run_make_support::object::ObjectSection;
use run_make_support::object::ObjectSymbol;
use run_make_support::object::RelocationTarget;
use run_make_support::rfs::{read, read_dir};
use run_make_support::{cmd, env_var, object};
use std::collections::HashSet;
use std::path::PathBuf;

View File

@ -9,16 +9,16 @@
//@ ignore-wasm64
// Reason: a C compiler is required for build_native_static_lib
use run_make_support::{build_native_static_lib, fs_wrapper, rustc, static_lib_name};
use run_make_support::{build_native_static_lib, rfs, rustc, static_lib_name};
fn main() {
build_native_static_lib("native");
let lib_native = static_lib_name("native");
fs_wrapper::create_dir_all("crate");
fs_wrapper::create_dir_all("native");
fs_wrapper::rename(&lib_native, format!("native/{}", &lib_native));
rfs::create_dir_all("crate");
rfs::create_dir_all("native");
rfs::rename(&lib_native, format!("native/{}", &lib_native));
rustc().input("a.rs").run();
fs_wrapper::rename("liba.rlib", "crate/liba.rlib");
rfs::rename("liba.rlib", "crate/liba.rlib");
rustc().input("b.rs").specific_library_search_path("native", "crate").run_fail();
rustc().input("b.rs").specific_library_search_path("dependency", "crate").run_fail();
rustc().input("b.rs").specific_library_search_path("crate", "crate").run();
@ -35,8 +35,8 @@ fn main() {
rustc().input("d.rs").specific_library_search_path("all", "native").run();
// Deduplication tests.
fs_wrapper::create_dir_all("e1");
fs_wrapper::create_dir_all("e2");
rfs::create_dir_all("e1");
rfs::create_dir_all("e2");
rustc().input("e.rs").output("e1/libe.rlib").run();
rustc().input("e.rs").output("e2/libe.rlib").run();

View File

@ -1,11 +1,11 @@
// Tests that const prop lints interrupting codegen don't leave `.o` files around.
use run_make_support::{cwd, fs_wrapper, rustc};
use run_make_support::{cwd, rfs, rustc};
fn main() {
rustc().input("input.rs").run_fail().assert_exit_code(1);
for entry in fs_wrapper::read_dir(cwd()) {
for entry in rfs::read_dir(cwd()) {
let entry = entry.unwrap();
let path = entry.path();

View File

@ -4,15 +4,15 @@
// and the compiler flags, and checks that the flag is favoured each time.
// See https://github.com/rust-lang/rust/pull/15518
use run_make_support::{bin_name, fs_wrapper, rustc};
use run_make_support::{bin_name, rfs, rustc};
fn main() {
rustc().input("foo.rs").run();
fs_wrapper::remove_file(bin_name("foo"));
rfs::remove_file(bin_name("foo"));
rustc().input("foo.rs").crate_name("bar").run();
fs_wrapper::remove_file(bin_name("bar"));
rfs::remove_file(bin_name("bar"));
rustc().input("foo1.rs").run();
fs_wrapper::remove_file(bin_name("foo"));
rfs::remove_file(bin_name("foo"));
rustc().input("foo1.rs").output(bin_name("bar1")).run();
fs_wrapper::remove_file(bin_name("bar1"));
rfs::remove_file(bin_name("bar1"));
}

View File

@ -1,7 +1,7 @@
// Check that valid binaries are persisted by running them, regardless of whether the
// --run or --no-run option is used.
use run_make_support::fs_wrapper::{create_dir, remove_dir_all};
use run_make_support::rfs::{create_dir, remove_dir_all};
use run_make_support::{run, rustc, rustdoc};
use std::path::Path;

View File

@ -1,6 +1,6 @@
// Tests behavior of rustdoc `--runtool`.
use run_make_support::fs_wrapper::{create_dir, remove_dir_all};
use run_make_support::rfs::{create_dir, remove_dir_all};
use run_make_support::{rustc, rustdoc};
use std::path::PathBuf;

View File

@ -4,7 +4,7 @@
// a specific expected string.
// See https://github.com/rust-lang/rust/pull/105481
use run_make_support::{cwd, fs_wrapper, rustc};
use run_make_support::{cwd, rfs, rustc};
fn main() {
rustc()
@ -13,5 +13,5 @@ fn main() {
.arg(format!("-Zdump-mono-stats={}", cwd().display()))
.arg("-Zdump-mono-stats-format=json")
.run();
assert!(fs_wrapper::read_to_string("foo.mono_items.json").contains(r#""name":"bar""#));
assert!(rfs::read_to_string("foo.mono_items.json").contains(r#""name":"bar""#));
}

View File

@ -8,7 +8,7 @@
//@ ignore-cross-compile
// Reason: the compiled binary is executed
use run_make_support::{dynamic_lib_name, fs_wrapper, run, run_fail, rustc};
use run_make_support::{dynamic_lib_name, rfs, run, run_fail, rustc};
fn main() {
rustc().input("m1.rs").arg("-Cprefer-dynamic").run();
@ -16,8 +16,8 @@ fn main() {
rustc().input("m3.rs").arg("-Cprefer-dynamic").run();
rustc().input("m4.rs").run();
run("m4");
fs_wrapper::remove_file(dynamic_lib_name("m1"));
fs_wrapper::remove_file(dynamic_lib_name("m2"));
fs_wrapper::remove_file(dynamic_lib_name("m3"));
rfs::remove_file(dynamic_lib_name("m1"));
rfs::remove_file(dynamic_lib_name("m2"));
rfs::remove_file(dynamic_lib_name("m3"));
run_fail("m4");
}

View File

@ -1,6 +1,6 @@
use std::path::Path;
use run_make_support::{fs_wrapper, rustc};
use run_make_support::{rfs, rustc};
fn emit_and_check(out_dir: &Path, out_file: &str, format: &str) {
let out_file = out_dir.join(out_file);
@ -11,7 +11,7 @@ fn emit_and_check(out_dir: &Path, out_file: &str, format: &str) {
fn main() {
let out_dir = Path::new("emit");
fs_wrapper::create_dir(&out_dir);
rfs::create_dir(&out_dir);
emit_and_check(&out_dir, "libfoo.s", "asm");
emit_and_check(&out_dir, "libfoo.bc", "llvm-bc");

View File

@ -6,13 +6,13 @@
// adding a new output type (in this test, metadata).
// See https://github.com/rust-lang/rust/issues/86044
use run_make_support::{diff, fs_wrapper, rustc};
use run_make_support::{diff, rfs, rustc};
fn main() {
fs_wrapper::create_dir("emit");
fs_wrapper::create_dir("emit/a");
fs_wrapper::create_dir("emit/b");
fs_wrapper::create_dir("emit/c");
rfs::create_dir("emit");
rfs::create_dir("emit/a");
rfs::create_dir("emit/b");
rfs::create_dir("emit/c");
// The default output name.
rustc().emit("link").input("foo.rs").run();
// The output is named with the output flag.

View File

@ -8,21 +8,21 @@
//@ ignore-cross-compile
// Reason: the compiled binary is executed
use run_make_support::{dynamic_lib_name, fs_wrapper, run, run_fail, rust_lib_name, rustc};
use run_make_support::{dynamic_lib_name, rfs, run, run_fail, rust_lib_name, rustc};
fn main() {
rustc().input("bar.rs").crate_type("rlib").crate_type("dylib").arg("-Cprefer-dynamic").run();
// By default, the rlib has priority over the dylib.
rustc().input("foo.rs").arg("--extern").arg("bar").run();
fs_wrapper::rename(dynamic_lib_name("bar"), "bar.tmp");
rfs::rename(dynamic_lib_name("bar"), "bar.tmp");
run("foo");
fs_wrapper::rename("bar.tmp", dynamic_lib_name("bar"));
rfs::rename("bar.tmp", dynamic_lib_name("bar"));
rustc().input("foo.rs").extern_("bar", rust_lib_name("bar")).arg("--extern").arg("bar").run();
fs_wrapper::rename(dynamic_lib_name("bar"), "bar.tmp");
rfs::rename(dynamic_lib_name("bar"), "bar.tmp");
run("foo");
fs_wrapper::rename("bar.tmp", dynamic_lib_name("bar"));
rfs::rename("bar.tmp", dynamic_lib_name("bar"));
// The first explicit usage of extern overrides the second pathless --extern bar.
rustc()
@ -31,13 +31,13 @@ fn main() {
.arg("--extern")
.arg("bar")
.run();
fs_wrapper::rename(dynamic_lib_name("bar"), "bar.tmp");
rfs::rename(dynamic_lib_name("bar"), "bar.tmp");
run_fail("foo");
fs_wrapper::rename("bar.tmp", dynamic_lib_name("bar"));
rfs::rename("bar.tmp", dynamic_lib_name("bar"));
// With prefer-dynamic, execution fails as it refuses to use the rlib.
rustc().input("foo.rs").arg("--extern").arg("bar").arg("-Cprefer-dynamic").run();
fs_wrapper::rename(dynamic_lib_name("bar"), "bar.tmp");
rfs::rename(dynamic_lib_name("bar"), "bar.tmp");
run_fail("foo");
fs_wrapper::rename("bar.tmp", dynamic_lib_name("bar"));
rfs::rename("bar.tmp", dynamic_lib_name("bar"));
}

View File

@ -6,9 +6,7 @@
// are named as expected.
// See https://github.com/rust-lang/rust/pull/15686
use run_make_support::{
bin_name, cwd, fs_wrapper, has_prefix, has_suffix, rustc, shallow_find_files,
};
use run_make_support::{bin_name, cwd, has_prefix, has_suffix, rfs, rustc, shallow_find_files};
fn main() {
rustc().extra_filename("bar").input("foo.rs").arg("-Csave-temps").run();
@ -16,6 +14,6 @@ fn main() {
has_prefix(path, "foobar.foo") && has_suffix(path, "0.rcgu.o")
});
let object_file = object_files.get(0).unwrap();
fs_wrapper::remove_file(object_file);
fs_wrapper::remove_file(bin_name("foobar"));
rfs::remove_file(object_file);
rfs::remove_file(bin_name("foobar"));
}

View File

@ -16,7 +16,7 @@
// If we used `rustc` the additional '-L rmake_out' option would allow rustc to
// actually find the crate.
use run_make_support::{bare_rustc, fs_wrapper, rust_lib_name, rustc};
use run_make_support::{bare_rustc, rfs, rust_lib_name, rustc};
fn main() {
rustc().crate_name("a").crate_type("rlib").input("a.rs").arg("--verbose").run();

View File

@ -24,11 +24,11 @@
// Reason: `set_readonly` has no effect on directories
// and does not prevent modification.
use run_make_support::{fs_wrapper, rustc, test_while_readonly};
use run_make_support::{rfs, rustc, test_while_readonly};
fn main() {
// Create an inaccessible directory.
fs_wrapper::create_dir("inaccessible");
rfs::create_dir("inaccessible");
test_while_readonly("inaccessible", || {
// Run rustc with `-Z temps-dir` set to a directory *inside* the inaccessible one,
// so that it can't create `tmp`.

View File

@ -13,14 +13,14 @@
//@ ignore-nvptx64-nvidia-cuda
// FIXME: can't find crate for `std`
use run_make_support::fs_wrapper as fs;
use run_make_support::rfs;
use run_make_support::rustc;
fn main() {
fs::create_dir("src");
fs::create_dir("incr");
fs::copy("a.rs", "src/main.rs");
rfs::create_dir("src");
rfs::create_dir("incr");
rfs::copy("a.rs", "src/main.rs");
rustc().incremental("incr").input("src/main.rs").run();
fs::copy("b.rs", "src/main.rs");
rfs::copy("b.rs", "src/main.rs");
rustc().incremental("incr").input("src/main.rs").run();
}

View File

@ -14,14 +14,14 @@
//@ ignore-nvptx64-nvidia-cuda
// FIXME: can't find crate for 'std'
use run_make_support::{fs_wrapper, rust_lib_name, rustc};
use run_make_support::{rfs, rust_lib_name, rustc};
fn main() {
fs_wrapper::create_dir("incr");
fs_wrapper::create_dir("src");
fs_wrapper::create_dir("src/mydir");
fs_wrapper::copy("main.rs", "src/main.rs");
rfs::create_dir("incr");
rfs::create_dir("src");
rfs::create_dir("src/mydir");
rfs::copy("main.rs", "src/main.rs");
rustc().input("src/main.rs").incremental("incr").arg("--test").run();
fs_wrapper::rename("src/main.rs", "src/mydir/main.rs");
rfs::rename("src/main.rs", "src/mydir/main.rs");
rustc().input("src/mydir/main.rs").incremental("incr").arg("--test").run();
}

View File

@ -2,14 +2,14 @@
// (in this case, foo.py and foo.natvis) are picked up when compiling incrementally.
// See https://github.com/rust-lang/rust/pull/111641
use run_make_support::{fs_wrapper, invalid_utf8_contains, invalid_utf8_not_contains, rustc};
use run_make_support::{invalid_utf8_contains, invalid_utf8_not_contains, rfs, rustc};
use std::io::Read;
fn main() {
fs_wrapper::create_file("foo.py");
fs_wrapper::write("foo.py", "GDB script v1");
fs_wrapper::create_file("foo.natvis");
fs_wrapper::write("foo.natvis", "Natvis v1");
rfs::create_file("foo.py");
rfs::write("foo.py", "GDB script v1");
rfs::create_file("foo.natvis");
rfs::write("foo.natvis", "Natvis v1");
rustc()
.input("foo.rs")
.crate_type("rlib")
@ -22,9 +22,9 @@ fn main() {
invalid_utf8_contains("libfoo.rmeta", "Natvis v1");
// Change only the GDB script and check that the change has been picked up
fs_wrapper::remove_file("foo.py");
fs_wrapper::create_file("foo.py");
fs_wrapper::write("foo.py", "GDB script v2");
rfs::remove_file("foo.py");
rfs::create_file("foo.py");
rfs::write("foo.py", "GDB script v2");
rustc()
.input("foo.rs")
.crate_type("rlib")
@ -38,9 +38,9 @@ fn main() {
invalid_utf8_contains("libfoo.rmeta", "Natvis v1");
// Now change the Natvis version and check that the change has been picked up
fs_wrapper::remove_file("foo.natvis");
fs_wrapper::create_file("foo.natvis");
fs_wrapper::write("foo.natvis", "Natvis v2");
rfs::remove_file("foo.natvis");
rfs::create_file("foo.natvis");
rfs::write("foo.natvis", "Natvis v2");
rustc()
.input("foo.rs")
.crate_type("rlib")

View File

@ -4,10 +4,10 @@
// the ensuing compilation failure is not an ICE.
// See https://github.com/rust-lang/rust/pull/85698
use run_make_support::{fs_wrapper, rustc};
use run_make_support::{rfs, rustc};
fn main() {
fs_wrapper::create_file("session");
rfs::create_file("session");
// rustc should fail to create the session directory here.
let out = rustc().input("foo.rs").crate_type("rlib").incremental("session").run_fail();
out.assert_stderr_contains("could not create incremental compilation crate directory");

View File

@ -1,6 +1,6 @@
use run_make_support::fs_wrapper::read_to_string;
use run_make_support::regex::Regex;
use run_make_support::{read_dir, rustc};
use run_make_support::rfs;
use run_make_support::rustc;
use std::ffi::OsStr;
@ -8,9 +8,9 @@ fn main() {
rustc().input("foo.rs").emit("llvm-ir").codegen_units(2).run();
let re = Regex::new(r"\bcall\b").unwrap();
let mut nb_ll = 0;
read_dir(".", |path| {
rfs::read_dir_entries(".", |path| {
if path.is_file() && path.extension().is_some_and(|ext| ext == OsStr::new("ll")) {
assert!(!re.is_match(&read_to_string(path)));
assert!(!re.is_match(&rfs::read_to_string(path)));
nb_ll += 1;
}
});

View File

@ -8,13 +8,13 @@
//@ ignore-windows
// Reason: Because of Windows exception handling, the code is not necessarily any shorter.
use run_make_support::{fs_wrapper, rustc};
use run_make_support::{rfs, rustc};
fn main() {
rustc().opt().emit("asm").input("exit-ret.rs").run();
rustc().opt().emit("asm").input("exit-unreachable.rs").run();
assert!(
fs_wrapper::read_to_string("exit-unreachable.s").lines().count()
< fs_wrapper::read_to_string("exit-ret.s").lines().count()
rfs::read_to_string("exit-unreachable.s").lines().count()
< rfs::read_to_string("exit-ret.s").lines().count()
);
}

View File

@ -4,11 +4,11 @@
// one appearing in stderr in this scenario.
// See https://github.com/rust-lang/rust/pull/12645
use run_make_support::fs_wrapper::create_file;
use run_make_support::rfs;
use run_make_support::{llvm_ar, rustc};
fn main() {
create_file("lib.rmeta");
rfs::create_file("lib.rmeta");
llvm_ar().obj_to_ar().output_input("libfoo-ffffffff-1.0.rlib", "lib.rmeta").run();
rustc().input("foo.rs").run_fail().assert_stderr_contains("found invalid metadata");
}

View File

@ -4,10 +4,10 @@
// explains that the file exists, but that its metadata is incorrect.
// See https://github.com/rust-lang/rust/pull/88368
use run_make_support::{dynamic_lib_name, fs_wrapper, rustc};
use run_make_support::{dynamic_lib_name, rfs, rustc};
fn main() {
fs_wrapper::create_file(dynamic_lib_name("foo"));
rfs::create_file(dynamic_lib_name("foo"));
rustc()
.crate_type("lib")
.extern_("foo", dynamic_lib_name("foo"))

View File

@ -4,10 +4,10 @@
// an internal compiler error (ICE).
// See https://github.com/rust-lang/rust/pull/28673
use run_make_support::{fs_wrapper, rustc, static_lib_name};
use run_make_support::{rfs, rustc, static_lib_name};
fn main() {
fs_wrapper::create_file(static_lib_name("foo"));
rfs::create_file(static_lib_name("foo"));
rustc()
.arg("-")
.crate_type("rlib")

View File

@ -3,7 +3,7 @@
#[cfg(unix)]
extern crate libc;
use run_make_support::{aux_build, fs_wrapper};
use run_make_support::{aux_build, rfs};
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
@ -20,7 +20,7 @@ fn main() {
}
fn verify(path: &Path) {
let perm = fs_wrapper::metadata(path).permissions();
let perm = rfs::metadata(path).permissions();
assert!(!perm.readonly());

View File

@ -6,12 +6,12 @@
//@ ignore-cross-compile
use run_make_support::fs_wrapper;
use run_make_support::rfs;
use run_make_support::rustc;
fn main() {
rustc().input("foo.rs").run();
rustc().arg("-Zls=root").input("foo").run();
fs_wrapper::create_file("bar");
rfs::create_file("bar");
rustc().arg("-Zls=root").input("bar").run();
}

View File

@ -7,7 +7,7 @@
//@ ignore-cross-compile
use run_make_support::fs_wrapper;
use run_make_support::rfs;
use run_make_support::{run, rust_lib_name, rustc, test_while_readonly};
fn main() {

View File

@ -4,12 +4,12 @@
// what should be done to fix the issue.
// See https://github.com/rust-lang/rust/issues/13266
use run_make_support::{fs_wrapper, rustc};
use run_make_support::{rfs, rustc};
fn main() {
fs_wrapper::create_dir("a1");
fs_wrapper::create_dir("a2");
fs_wrapper::create_dir("a3");
rfs::create_dir("a1");
rfs::create_dir("a2");
rfs::create_dir("a3");
rustc().crate_type("rlib").out_dir("a1").input("crateA1.rs").run();
rustc().crate_type("rlib").library_search_path("a1").input("crateB.rs").run();
rustc().crate_type("rlib").out_dir("a2").input("crateA2.rs").run();

View File

@ -6,7 +6,7 @@
//@ ignore-cross-compile
use run_make_support::{dynamic_lib_name, fs_wrapper, rustc};
use run_make_support::{dynamic_lib_name, rfs, rustc};
fn main() {
rustc().input("rlib.rs").crate_type("rlib").crate_type("dylib").run();
@ -16,6 +16,6 @@ fn main() {
// librlib's dynamic version needs to be removed here to prevent prog.rs from fetching
// the wrong one.
fs_wrapper::remove_file(dynamic_lib_name("rlib"));
rfs::remove_file(dynamic_lib_name("rlib"));
rustc().input("prog.rs").run_fail();
}

View File

@ -17,20 +17,20 @@
//@ ignore-nvptx64-nvidia-cuda
// FIXME: can't find crate for 'std'
use run_make_support::{fs_wrapper, rust_lib_name, rustc};
use run_make_support::{rfs, rust_lib_name, rustc};
fn main() {
fs_wrapper::create_dir("incr");
fs_wrapper::create_dir("first_src");
fs_wrapper::create_dir("output");
fs_wrapper::rename("my_lib.rs", "first_src/my_lib.rs");
fs_wrapper::rename("main.rs", "first_src/main.rs");
rfs::create_dir("incr");
rfs::create_dir("first_src");
rfs::create_dir("output");
rfs::rename("my_lib.rs", "first_src/my_lib.rs");
rfs::rename("main.rs", "first_src/main.rs");
// Build from "first_src"
std::env::set_current_dir("first_src").unwrap();
rustc().input("my_lib.rs").incremental("incr").crate_type("lib").run();
rustc().input("main.rs").incremental("incr").extern_("my_lib", rust_lib_name("my_lib")).run();
std::env::set_current_dir("..").unwrap();
fs_wrapper::rename("first_src", "second_src");
rfs::rename("first_src", "second_src");
std::env::set_current_dir("second_src").unwrap();
// Build from "second_src" - the output and incremental directory remain identical
rustc().input("my_lib.rs").incremental("incr").crate_type("lib").run();

View File

@ -1,4 +1,4 @@
use run_make_support::fs_wrapper;
use run_make_support::rfs;
use run_make_support::rustc;
fn main() {
@ -7,6 +7,6 @@ fn main() {
#[cfg(windows)]
let non_unicode: std::ffi::OsString = std::os::windows::ffi::OsStringExt::from_wide(&[0xD800]);
let output = rustc().input("non_unicode_env.rs").env("NON_UNICODE_VAR", non_unicode).run_fail();
let expected = fs_wrapper::read_to_string("non_unicode_env.stderr");
let expected = rfs::read_to_string("non_unicode_env.stderr");
output.assert_stderr_equals(expected);
}

View File

@ -1,4 +1,4 @@
use run_make_support::{fs_wrapper, rustc};
use run_make_support::{rfs, rustc};
fn main() {
#[cfg(unix)]
@ -17,8 +17,8 @@ fn main() {
}
let incr_dir = "incr-dir";
rustc().input("foo.rs").incremental(&incr_dir).run();
for crate_dir in fs_wrapper::read_dir(&incr_dir) {
fs_wrapper::create_dir(crate_dir.unwrap().path().join(&non_unicode));
for crate_dir in rfs::read_dir(&incr_dir) {
rfs::create_dir(crate_dir.unwrap().path().join(&non_unicode));
}
rustc().input("foo.rs").incremental(&incr_dir).run();
}

View File

@ -6,7 +6,7 @@
//@ ignore-cross-compile
use run_make_support::{
cwd, dynamic_lib_name, fs_wrapper, has_extension, rust_lib_name, rustc, shallow_find_files,
cwd, dynamic_lib_name, has_extension, rfs, rust_lib_name, rustc, shallow_find_files,
};
use std::path::Path;
@ -15,7 +15,7 @@ fn main() {
assert!(Path::new(&dynamic_lib_name("test")).exists());
assert!(Path::new(&rust_lib_name("test")).exists());
fs_wrapper::remove_file(rust_lib_name("test"));
rfs::remove_file(rust_lib_name("test"));
rustc().crate_type("dylib").input("test.rs").run();
assert!(shallow_find_files(cwd(), |path| { has_extension(path, "rlib") }).is_empty());
}

View File

@ -4,10 +4,10 @@
// potentially-confusing linker error.
// See https://github.com/rust-lang/rust/pull/47203
use run_make_support::{fs_wrapper, rustc};
use run_make_support::{rfs, rustc};
fn main() {
fs_wrapper::create_dir("foo");
rfs::create_dir("foo");
rustc().input("foo.rs").output("foo").run_fail().assert_stderr_contains(
r#"the generated executable for the input file "foo.rs" conflicts with the existing directory "foo""#,
);

View File

@ -4,14 +4,14 @@
//@ ignore-cross-compile
use run_make_support::{fs_wrapper, rustc};
use run_make_support::{rfs, rustc};
fn main() {
fs_wrapper::copy("foo.rs", "foo");
rfs::copy("foo.rs", "foo");
rustc().input("foo").output("foo").run_fail().assert_stderr_contains(
r#"the input file "foo" would be overwritten by the generated executable"#,
);
fs_wrapper::copy("bar.rs", "bar.rlib");
rfs::copy("bar.rs", "bar.rlib");
rustc().input("bar.rlib").output("bar.rlib").run_fail().assert_stderr_contains(
r#"the input file "bar.rlib" would be overwritten by the generated executable"#,
);

View File

@ -5,7 +5,7 @@
// See https://github.com/rust-lang/rust/pull/12020
use run_make_support::{
bin_name, dynamic_lib_name, filename_not_in_denylist, fs_wrapper, rust_lib_name, rustc,
bin_name, dynamic_lib_name, filename_not_in_denylist, rfs, rust_lib_name, rustc,
shallow_find_files, static_lib_name,
};
use std::path::PathBuf;
@ -20,10 +20,10 @@ fn assert_expected_output_files(expectations: Expectations, rustc_invocation: im
let Expectations { expected_files: must_exist, allowed_files: can_exist, test_dir: dir } =
expectations;
fs_wrapper::create_dir(&dir);
rfs::create_dir(&dir);
rustc_invocation();
for file in must_exist {
fs_wrapper::remove_file(PathBuf::from(&dir).join(&file));
rfs::remove_file(PathBuf::from(&dir).join(&file));
}
let actual_output_files =
shallow_find_files(dir, |path| filename_not_in_denylist(path, &can_exist));
@ -526,17 +526,14 @@ fn main() {
test_dir: "rlib-emits".to_string(),
},
|| {
fs_wrapper::rename("staticlib-all3/bar.bc", "rlib-emits/foo.bc");
rfs::rename("staticlib-all3/bar.bc", "rlib-emits/foo.bc");
rustc()
.input("foo.rs")
.emit("llvm-bc,link")
.crate_type("rlib")
.out_dir("rlib-emits")
.run();
assert_eq!(
fs_wrapper::read("rlib-emits/foo.bc"),
fs_wrapper::read("rlib-emits/bar.bc")
);
assert_eq!(rfs::read("rlib-emits/foo.bc"), rfs::read("rlib-emits/bar.bc"));
},
);
}

View File

@ -5,12 +5,12 @@
// conflicts. This test uses this flag and checks for successful compilation.
// See https://github.com/rust-lang/rust/pull/83846
use run_make_support::{fs_wrapper, rustc};
use run_make_support::{rfs, rustc};
use std::sync::{Arc, Barrier};
use std::thread;
fn main() {
fs_wrapper::create_file("lib.rs");
rfs::create_file("lib.rs");
let barrier = Arc::new(Barrier::new(2));
let handle = {
let barrier = Arc::clone(&barrier);

View File

@ -10,14 +10,14 @@
//@ needs-profiler-support
//@ ignore-cross-compile
use run_make_support::{fs_wrapper, llvm_filecheck, llvm_profdata, run_with_args, rustc};
use run_make_support::{llvm_filecheck, llvm_profdata, rfs, run_with_args, rustc};
use std::path::Path;
fn main() {
let path_prof_data_dir = Path::new("prof_data_dir");
let path_merged_profdata = path_prof_data_dir.join("merged.profdata");
rustc().input("opaque.rs").run();
fs_wrapper::create_dir_all(&path_prof_data_dir);
rfs::create_dir_all(&path_prof_data_dir);
rustc()
.input("interesting.rs")
.profile_generate(&path_prof_data_dir)
@ -34,8 +34,5 @@ fn main() {
.codegen_units(1)
.emit("llvm-ir")
.run();
llvm_filecheck()
.patterns("filecheck-patterns.txt")
.stdin(fs_wrapper::read("interesting.ll"))
.run();
llvm_filecheck().patterns("filecheck-patterns.txt").stdin(rfs::read("interesting.ll")).run();
}

View File

@ -9,8 +9,8 @@
//@ ignore-cross-compile
use run_make_support::{
cwd, fs_wrapper, has_extension, has_prefix, llvm_filecheck, llvm_profdata, run_with_args,
rustc, shallow_find_files,
cwd, has_extension, has_prefix, llvm_filecheck, llvm_profdata, rfs, run_with_args, rustc,
shallow_find_files,
};
fn main() {
@ -47,7 +47,7 @@ fn main() {
// line with the function name before the line with the function attributes.
// FileCheck only supports checking that something matches on the next line,
// but not if something matches on the previous line.
let ir = fs_wrapper::read_to_string("main.ll");
let ir = rfs::read_to_string("main.ll");
let lines: Vec<_> = ir.lines().rev().collect();
let mut reversed_ir = lines.join("\n");
reversed_ir.push('\n');

View File

@ -1,6 +1,6 @@
//@ ignore-cross-compile
use run_make_support::{cwd, dynamic_lib_name, fs_wrapper, read_dir, run, run_fail, rustc};
use run_make_support::{dynamic_lib_name, rfs, run, run_fail, rustc};
fn main() {
rustc().input("bar.rs").crate_type("dylib").crate_type("rlib").arg("-Cprefer-dynamic").run();
@ -8,7 +8,7 @@ fn main() {
run("foo");
fs_wrapper::remove_file(dynamic_lib_name("bar"));
rfs::remove_file(dynamic_lib_name("bar"));
// This time the command should fail.
run_fail("foo");
}

View File

@ -3,13 +3,13 @@
//@ ignore-cross-compile
use run_make_support::{dynamic_lib_name, fs_wrapper, path, run, rust_lib_name, rustc};
use run_make_support::{dynamic_lib_name, path, rfs, run, rust_lib_name, rustc};
fn main() {
rustc().input("bar.rs").crate_type("dylib").crate_type("rlib").run();
assert!(path(rust_lib_name("bar")).exists());
rustc().input("foo.rs").run();
fs_wrapper::remove_file(rust_lib_name("bar"));
fs_wrapper::remove_file(dynamic_lib_name("bar"));
rfs::remove_file(rust_lib_name("bar"));
rfs::remove_file(dynamic_lib_name("bar"));
run("foo");
}

View File

@ -5,13 +5,13 @@
// does not get an unexpected dep-info file.
// See https://github.com/rust-lang/rust/issues/112898
use run_make_support::{fs_wrapper, invalid_utf8_contains, rustc};
use run_make_support::{invalid_utf8_contains, rfs, rustc};
use std::path::Path;
fn main() {
rustc().emit("dep-info").arg("-Zunpretty=expanded").input("with-dep.rs").run();
invalid_utf8_contains("with-dep.d", "with-dep.rs");
fs_wrapper::remove_file("with-dep.d");
rfs::remove_file("with-dep.d");
rustc().emit("dep-info").arg("-Zunpretty=normal").input("with-dep.rs").run();
assert!(!Path::new("with-dep.d").exists());
}

View File

@ -10,7 +10,7 @@ use std::ffi::OsString;
use std::iter::FromIterator;
use std::path::PathBuf;
use run_make_support::{fs_wrapper, rustc};
use run_make_support::{rfs, rustc};
struct PrintCfg {
target: &'static str,
@ -96,7 +96,7 @@ fn check(PrintCfg { target, includes, disallow }: PrintCfg) {
rustc().target(target).arg(print_arg).run();
let output = fs_wrapper::read_to_string(&tmp_path);
let output = rfs::read_to_string(&tmp_path);
check_(&output, includes, disallow);
}

View File

@ -4,7 +4,7 @@
use std::ffi::OsString;
use std::path::PathBuf;
use run_make_support::{fs_wrapper, rustc, target};
use run_make_support::{rfs, rustc, target};
struct Option<'a> {
target: &'a str,
@ -49,7 +49,7 @@ fn check(args: Option) {
rustc().target(args.target).arg(print_arg).run();
fs_wrapper::read_to_string(&tmp_path)
rfs::read_to_string(&tmp_path)
};
check_(&stdout, args.includes);

View File

@ -4,7 +4,7 @@
// See https://github.com/rust-lang/rust/pull/85344
use run_make_support::bstr::ByteSlice;
use run_make_support::{bstr, fs_wrapper, is_darwin, rustc};
use run_make_support::{bstr, is_darwin, rfs, rustc};
fn main() {
let mut out_simple = rustc();
@ -60,12 +60,9 @@ fn main() {
// helper functions.
fn rmeta_contains(expected: &str) {
// Normalize to account for path differences in Windows.
if !bstr::BString::from(fs_wrapper::read("liblib.rmeta"))
.replace(b"\\", b"/")
.contains_str(expected)
{
if !bstr::BString::from(rfs::read("liblib.rmeta")).replace(b"\\", b"/").contains_str(expected) {
eprintln!("=== FILE CONTENTS (LOSSY) ===");
eprintln!("{}", String::from_utf8_lossy(&fs_wrapper::read("liblib.rmeta")));
eprintln!("{}", String::from_utf8_lossy(&rfs::read("liblib.rmeta")));
eprintln!("=== SPECIFIED TEXT ===");
eprintln!("{}", expected);
panic!("specified text was not found in file");
@ -74,12 +71,9 @@ fn rmeta_contains(expected: &str) {
fn rmeta_not_contains(expected: &str) {
// Normalize to account for path differences in Windows.
if bstr::BString::from(fs_wrapper::read("liblib.rmeta"))
.replace(b"\\", b"/")
.contains_str(expected)
{
if bstr::BString::from(rfs::read("liblib.rmeta")).replace(b"\\", b"/").contains_str(expected) {
eprintln!("=== FILE CONTENTS (LOSSY) ===");
eprintln!("{}", String::from_utf8_lossy(&fs_wrapper::read("liblib.rmeta")));
eprintln!("{}", String::from_utf8_lossy(&rfs::read("liblib.rmeta")));
eprintln!("=== SPECIFIED TEXT ===");
eprintln!("{}", expected);
panic!("specified text was not found in file");

View File

@ -3,7 +3,7 @@
use gimli::{AttributeValue, EndianRcSlice, Reader, RunTimeEndian};
use object::{Object, ObjectSection};
use run_make_support::{fs_wrapper, gimli, object, rustc};
use run_make_support::{gimli, object, rfs, rustc};
use std::collections::HashMap;
use std::path::PathBuf;
use std::rc::Rc;
@ -19,7 +19,7 @@ fn main() {
.join("DWARF")
.join("repr128");
let output =
fs_wrapper::read(if dsym_location.try_exists().unwrap() { dsym_location } else { output });
rfs::read(if dsym_location.try_exists().unwrap() { dsym_location } else { output });
let obj = object::File::parse(output.as_slice()).unwrap();
let endian = if obj.is_little_endian() { RunTimeEndian::Little } else { RunTimeEndian::Big };
let dwarf = gimli::Dwarf::load(|section| -> Result<_, ()> {

View File

@ -7,7 +7,7 @@
//@ ignore-cross-compile
use run_make_support::{bin_name, fs_wrapper, rustc};
use run_make_support::{bin_name, rfs, rustc};
use std::path::Path;
fn compile(output_file: &str, emit: Option<&str>) {

View File

@ -5,12 +5,12 @@
// the renamed library.
// See https://github.com/rust-lang/rust/pull/49253
use run_make_support::fs_wrapper;
use run_make_support::rfs;
use run_make_support::rustc;
fn main() {
rustc().extra_filename("-hash").input("foo.rs").run();
rustc().input("bar.rs").run();
fs_wrapper::rename("libfoo-hash.rlib", "libfoo-another-hash.rlib");
rfs::rename("libfoo-hash.rlib", "libfoo-another-hash.rlib");
rustc().input("baz.rs").run();
}

View File

@ -8,7 +8,7 @@
//@ ignore-cross-compile
// Reason: the compiled binary is executed
use run_make_support::{fs_wrapper, run, rust_lib_name, rustc};
use run_make_support::{rfs, run, rust_lib_name, rustc};
fn main() {
rustc().input("m1.rs").run();
@ -16,8 +16,8 @@ fn main() {
rustc().input("m3.rs").run();
rustc().input("m4.rs").run();
run("m4");
fs_wrapper::remove_file(rust_lib_name("m1"));
fs_wrapper::remove_file(rust_lib_name("m2"));
fs_wrapper::remove_file(rust_lib_name("m3"));
rfs::remove_file(rust_lib_name("m1"));
rfs::remove_file(rust_lib_name("m2"));
rfs::remove_file(rust_lib_name("m3"));
run("m4");
}

View File

@ -1,10 +1,10 @@
use run_make_support::{fs_wrapper, htmldocck, rustc, rustdoc, source_root};
use run_make_support::{htmldocck, rfs, rustc, rustdoc, source_root};
use std::path::Path;
pub fn scrape(extra_args: &[&str]) {
let out_dir = Path::new("rustdoc");
let crate_name = "foobar";
let deps = fs_wrapper::read_dir("examples")
let deps = rfs::read_dir("examples")
.filter_map(|entry| entry.ok().map(|e| e.path()))
.filter(|path| path.is_file() && path.extension().is_some_and(|ext| ext == "rs"))
.collect::<Vec<_>>();

View File

@ -1,10 +1,10 @@
use run_make_support::{fs_wrapper, rustdoc};
use run_make_support::{rfs, rustdoc};
use std::iter;
use std::path::Path;
fn generate_a_lot_of_cfgs(path: &Path) {
let content = iter::repeat("--cfg=a\n").take(100_000).collect::<String>();
fs_wrapper::write(path, content.as_bytes());
rfs::write(path, content.as_bytes());
}
fn main() {

View File

@ -1,15 +1,14 @@
// Test that rustdoc will properly load in a theme file and display it in the theme selector.
use run_make_support::{fs_wrapper, htmldocck, rustdoc, source_root};
use run_make_support::{htmldocck, rfs, rustdoc, source_root};
use std::path::Path;
fn main() {
let out_dir = Path::new("rustdoc-themes");
let test_css = "test.css";
let no_script = fs_wrapper::read_to_string(
source_root().join("src/librustdoc/html/static/css/noscript.css"),
);
let no_script =
rfs::read_to_string(source_root().join("src/librustdoc/html/static/css/noscript.css"));
let mut test_content = String::new();
let mut found_begin_light = false;
@ -24,8 +23,8 @@ fn main() {
}
}
assert!(!test_content.is_empty());
fs_wrapper::create_dir_all(&out_dir);
fs_wrapper::write(&test_css, test_content);
rfs::create_dir_all(&out_dir);
rfs::write(&test_css, test_content);
rustdoc().output(&out_dir).input("foo.rs").arg("--theme").arg(&test_css).run();
htmldocck().arg(out_dir).arg("foo.rs").run();

View File

@ -1,7 +1,7 @@
use run_make_support::fs_wrapper::copy;
use run_make_support::rfs;
use std::path::{Path, PathBuf};
use run_make_support::{copy_dir_all, recursive_diff, rustdoc};
use run_make_support::{assert_dirs_are_equal, rustdoc};
#[derive(PartialEq)]
enum JsonOutput {
@ -26,7 +26,7 @@ fn main() {
generate_docs(&out_dir, JsonOutput::No);
// Copy first output for to check if it's exactly same after second compilation.
copy_dir_all(&out_dir, &tmp_out_dir);
rfs::copy_dir_all(&out_dir, &tmp_out_dir);
// Generate html docs once again on same output.
generate_docs(&out_dir, JsonOutput::No);
@ -38,12 +38,12 @@ fn main() {
assert!(out_dir.join("foobar.json").is_file());
// Copy first json output to check if it's exactly same after second compilation.
copy(out_dir.join("foobar.json"), tmp_out_dir.join("foobar.json"));
rfs::copy(out_dir.join("foobar.json"), tmp_out_dir.join("foobar.json"));
// Generate json doc on the same output.
generate_docs(&out_dir, JsonOutput::Yes);
// Check if all docs(including both json and html formats) are still the same after multiple
// compilations.
recursive_diff(&out_dir, &tmp_out_dir);
assert_dirs_are_equal(&out_dir, &tmp_out_dir);
}

View File

@ -5,7 +5,7 @@
// See https://github.com/rust-lang/rust/pull/16367
use run_make_support::{
count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc,
count_regex_matches_in_files_with_extension, cwd, has_extension, regex, rfs, rustc,
shallow_find_files,
};

View File

@ -6,7 +6,7 @@
// See https://github.com/rust-lang/rust/pull/16367
use run_make_support::{
count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc,
count_regex_matches_in_files_with_extension, cwd, has_extension, regex, rfs, rustc,
shallow_find_files,
};

View File

@ -4,7 +4,7 @@
// See https://github.com/rust-lang/rust/pull/16367
use run_make_support::{
count_regex_matches_in_files_with_extension, cwd, fs_wrapper, has_extension, regex, rustc,
count_regex_matches_in_files_with_extension, cwd, has_extension, regex, rfs, rustc,
shallow_find_files,
};

View File

@ -11,13 +11,13 @@
//@ ignore-windows
// Reason: Windows refuses files with < and > in their names
use run_make_support::{diff, fs_wrapper, run, rustc};
use run_make_support::{diff, rfs, run, rustc};
fn main() {
fs_wrapper::create_file("<leading-lt");
fs_wrapper::write("<leading-lt", r#""comes from a file with a name that begins with <""#);
fs_wrapper::create_file("trailing-gt>");
fs_wrapper::write("trailing-gt>", r#""comes from a file with a name that ends with >""#);
rfs::create_file("<leading-lt");
rfs::write("<leading-lt", r#""comes from a file with a name that begins with <""#);
rfs::create_file("trailing-gt>");
rfs::write("trailing-gt>", r#""comes from a file with a name that ends with >""#);
rustc().input("silly-file-names.rs").output("silly-file-names").run();
let out = run("silly-file-names").stdout_utf8();
diff().expected_file("silly-file-names.run.stdout").actual_text("actual-stdout", out).run();

View File

@ -11,12 +11,12 @@
//@ ignore-cross-compile
//@ needs-symlink
use run_make_support::{create_symlink, cwd, fs_wrapper, rustc};
use run_make_support::{cwd, rfs, rustc};
fn main() {
rustc().input("foo.rs").run();
fs_wrapper::create_dir_all("other");
create_symlink("libfoo.rlib", "other");
rfs::create_dir_all("other");
rfs::create_symlink("libfoo.rlib", "other");
rustc().input("bar.rs").library_search_path(cwd()).run();
rustc().input("baz.rs").extern_("foo", "other").library_search_path(cwd()).run();
}

View File

@ -8,11 +8,11 @@
//@ ignore-cross-compile
//@ needs-symlink
use run_make_support::{create_symlink, dynamic_lib_name, fs_wrapper, rustc};
use run_make_support::{dynamic_lib_name, rfs, rustc};
fn main() {
rustc().input("foo.rs").arg("-Cprefer-dynamic").run();
fs_wrapper::create_dir_all("other");
create_symlink(dynamic_lib_name("foo"), "other");
rfs::create_dir_all("other");
rfs::create_symlink(dynamic_lib_name("foo"), "other");
rustc().input("bar.rs").library_search_path("other").run();
}

View File

@ -8,10 +8,10 @@
//@ ignore-cross-compile
//@ needs-symlink
use run_make_support::{create_symlink, cwd, rustc};
use run_make_support::{cwd, rfs, rustc};
fn main() {
rustc().input("foo.rs").crate_type("rlib").output("foo.xxx").run();
create_symlink("foo.xxx", "libfoo.rlib");
rfs::create_symlink("foo.xxx", "libfoo.rlib");
rustc().input("bar.rs").library_search_path(cwd()).run();
}

View File

@ -5,11 +5,11 @@
// using them correctly, or fails with the right error message when using them improperly.
// See https://github.com/rust-lang/rust/pull/16156
use run_make_support::{diff, fs_wrapper, rustc};
use run_make_support::{diff, rfs, rustc};
fn main() {
rustc().input("foo.rs").target("my-awesome-platform.json").crate_type("lib").emit("asm").run();
assert!(!fs_wrapper::read_to_string("foo.s").contains("morestack"));
assert!(!rfs::read_to_string("foo.s").contains("morestack"));
rustc()
.input("foo.rs")
.target("my-invalid-platform.json")
@ -40,8 +40,8 @@ fn main() {
.print("target-spec-json")
.run()
.stdout_utf8();
fs_wrapper::create_file("test-platform.json");
fs_wrapper::write("test-platform.json", test_platform.as_bytes());
rfs::create_file("test-platform.json");
rfs::write("test-platform.json", test_platform.as_bytes());
let test_platform_2 = rustc()
.arg("-Zunstable-options")
.target("test-platform.json")

View File

@ -4,10 +4,10 @@
// output successfully added the file as a dependency.
// See https://github.com/rust-lang/rust/pull/84029
use run_make_support::{fs_wrapper, rustc};
use run_make_support::{rfs, rustc};
fn main() {
rustc().input("macro_def.rs").run();
rustc().env("EXISTING_PROC_MACRO_ENV", "1").emit("dep-info").input("macro_use.rs").run();
assert!(fs_wrapper::read_to_string("macro_use.d").contains("emojis.txt:"));
assert!(rfs::read_to_string("macro_use.d").contains("emojis.txt:"));
}

View File

@ -8,7 +8,7 @@
// Reason: the binary is executed
//@ needs-profiler-support
use run_make_support::{fs_wrapper, llvm_profdata, run, rustc};
use run_make_support::{llvm_profdata, rfs, run, rustc};
fn main() {
// Generate the profile-guided-optimization (PGO) profiles
@ -19,5 +19,5 @@ fn main() {
// Use the profiles in compilation
rustc().profile_use("merged.profdata").emit("dep-info").input("main.rs").run();
// Check that the profile file is in the dep-info emit file
assert!(fs_wrapper::read_to_string("main.d").contains("merged.profdata"));
assert!(rfs::read_to_string("main.d").contains("merged.profdata"));
}

View File

@ -1,6 +1,6 @@
//@ ignore-cross-compile
use run_make_support::fs_wrapper::read;
use run_make_support::rfs;
use run_make_support::{assert_contains, run, rustc};
fn main() {
@ -11,7 +11,7 @@ fn main() {
// ... and the loads/stores must not be optimized out.
rustc().input("main.rs").emit("llvm-ir").run();
let raw_llvm_ir = read("main.ll");
let raw_llvm_ir = rfs::read("main.ll");
let llvm_ir = String::from_utf8_lossy(&raw_llvm_ir);
assert_contains(&llvm_ir, "load volatile");
assert_contains(&llvm_ir, "store volatile");

View File

@ -1,13 +1,13 @@
//@ only-wasm32-wasip1
use run_make_support::{fs_wrapper, rustc, wasmparser};
use run_make_support::{rfs, rustc, wasmparser};
use std::collections::HashMap;
fn main() {
rustc().input("foo.rs").target("wasm32-wasip1").run();
rustc().input("bar.rs").target("wasm32-wasip1").arg("-Clto").opt().run();
let file = fs_wrapper::read("bar.wasm");
let file = rfs::read("bar.wasm");
let mut custom = HashMap::new();
for payload in wasmparser::Parser::new(0).parse_all(&file) {

View File

@ -1,6 +1,6 @@
//@ only-wasm32-wasip1
use run_make_support::{fs_wrapper, rustc, wasmparser};
use run_make_support::{rfs, rustc, wasmparser};
use std::collections::HashMap;
use std::path::Path;
@ -12,7 +12,7 @@ fn main() {
fn verify(path: &Path) {
eprintln!("verify {path:?}");
let file = fs_wrapper::read(&path);
let file = rfs::read(&path);
let mut custom = HashMap::new();
for payload in wasmparser::Parser::new(0).parse_all(&file) {

View File

@ -1,6 +1,6 @@
//@ only-wasm32-wasip1
use run_make_support::{fs_wrapper, rustc, wasmparser};
use run_make_support::{rfs, rustc, wasmparser};
use std::collections::HashMap;
use std::path::Path;
use wasmparser::ExternalKind::*;
@ -33,7 +33,7 @@ fn test(args: &[&str]) {
fn verify_exports(path: &Path, exports: &[(&str, wasmparser::ExternalKind)]) {
println!("verify {path:?}");
let file = fs_wrapper::read(path);
let file = rfs::read(path);
let mut wasm_exports = HashMap::new();
for payload in wasmparser::Parser::new(0).parse_all(&file) {
let payload = payload.unwrap();

View File

@ -1,6 +1,6 @@
//@ only-wasm32-wasip1
use run_make_support::{fs_wrapper, rustc, wasmparser};
use run_make_support::{rfs, rustc, wasmparser};
use std::collections::HashMap;
use wasmparser::TypeRef::Func;
@ -8,7 +8,7 @@ fn main() {
rustc().input("foo.rs").target("wasm32-wasip1").run();
rustc().input("bar.rs").target("wasm32-wasip1").arg("-Clto").opt().run();
let file = fs_wrapper::read("bar.wasm");
let file = rfs::read("bar.wasm");
let mut imports = HashMap::new();
for payload in wasmparser::Parser::new(0).parse_all(&file) {

View File

@ -1,7 +1,7 @@
//@ only-wasm32-wasip1
#![deny(warnings)]
use run_make_support::{fs_wrapper, rustc};
use run_make_support::{rfs, rustc};
fn main() {
test("a");
@ -15,7 +15,7 @@ fn test(cfg: &str) {
rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().cfg(cfg).run();
let bytes = fs_wrapper::read("foo.wasm");
let bytes = rfs::read("foo.wasm");
println!("{}", bytes.len());
assert!(bytes.len() < 40_000);
}

View File

@ -1,6 +1,6 @@
//@ only-wasm32-wasip1
use run_make_support::{fs_wrapper, rustc, wasmparser};
use run_make_support::{rfs, rustc, wasmparser};
use std::collections::HashMap;
fn main() {
@ -13,7 +13,7 @@ fn main() {
.arg("-Copt-level=z")
.run();
let file = fs_wrapper::read("main.wasm");
let file = rfs::read("main.wasm");
let mut imports = HashMap::new();
for payload in wasmparser::Parser::new(0).parse_all(&file) {

View File

@ -1,12 +1,12 @@
//@ only-wasm32-wasip1
#![deny(warnings)]
use run_make_support::{fs_wrapper, rustc};
use run_make_support::{rfs, rustc};
fn main() {
rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().run();
let bytes = fs_wrapper::read("foo.wasm");
let bytes = rfs::read("foo.wasm");
println!("{}", bytes.len());
assert!(bytes.len() < 50_000);
}

View File

@ -1,6 +1,6 @@
//@ only-wasm32-wasip1
use run_make_support::{fs_wrapper, rustc, wasmparser};
use run_make_support::{rfs, rustc, wasmparser};
use std::collections::{HashMap, HashSet};
use std::path::Path;
@ -23,7 +23,7 @@ fn test(file: &str, args: &[&str], expected_imports: &[(&str, &[&str])]) {
rustc().input(file).target("wasm32-wasip1").args(args).run();
let file = fs_wrapper::read(Path::new(file).with_extension("wasm"));
let file = rfs::read(Path::new(file).with_extension("wasm"));
let mut imports = HashMap::new();
for payload in wasmparser::Parser::new(0).parse_all(&file) {

Some files were not shown because too many files have changed in this diff Show More