Skip to content

compiletest: consistently use camino::{Utf8Path,Utf8PathBuf} throughout #139695

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 14, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
@@ -719,6 +719,7 @@ version = "0.0.0"
dependencies = [
"anstyle-svg",
"build_helper",
"camino",
"colored",
"diff",
"getopts",
@@ -4671,6 +4672,7 @@ name = "rustdoc-gui-test"
version = "0.1.0"
dependencies = [
"build_helper",
"camino",
"compiletest",
"getopts",
"walkdir",
1 change: 1 addition & 0 deletions src/tools/compiletest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@ doctest = false
# tidy-alphabetical-start
anstyle-svg = "0.1.3"
build_helper = { path = "../../build_helper" }
camino = "1"
colored = "2"
diff = "0.1.10"
getopts = "0.2"
71 changes: 41 additions & 30 deletions src/tools/compiletest/src/common.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
use std::collections::{BTreeSet, HashMap, HashSet};
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str::FromStr;
use std::sync::OnceLock;
use std::{fmt, iter};

use build_helper::git::GitConfig;
use camino::{Utf8Path, Utf8PathBuf};
use semver::Version;
use serde::de::{Deserialize, Deserializer, Error as _};

pub use self::Mode::*;
use crate::executor::{ColorConfig, OutputFormat};
use crate::util::{PathBufExt, add_dylib_path};
use crate::util::{Utf8PathBufExt, add_dylib_path};

macro_rules! string_enum {
($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => {
@@ -183,25 +182,25 @@ pub struct Config {
pub fail_fast: bool,

/// The library paths required for running the compiler.
pub compile_lib_path: PathBuf,
pub compile_lib_path: Utf8PathBuf,

/// The library paths required for running compiled programs.
pub run_lib_path: PathBuf,
pub run_lib_path: Utf8PathBuf,

/// The rustc executable.
pub rustc_path: PathBuf,
pub rustc_path: Utf8PathBuf,

/// The cargo executable.
pub cargo_path: Option<PathBuf>,
pub cargo_path: Option<Utf8PathBuf>,

/// Rustc executable used to compile run-make recipes.
pub stage0_rustc_path: Option<PathBuf>,
pub stage0_rustc_path: Option<Utf8PathBuf>,

/// The rustdoc executable.
pub rustdoc_path: Option<PathBuf>,
pub rustdoc_path: Option<Utf8PathBuf>,

/// The coverage-dump executable.
pub coverage_dump_path: Option<PathBuf>,
pub coverage_dump_path: Option<Utf8PathBuf>,

/// The Python executable to use for LLDB and htmldocck.
pub python: String,
@@ -213,27 +212,27 @@ pub struct Config {
pub jsondoclint_path: Option<String>,

/// The LLVM `FileCheck` binary path.
pub llvm_filecheck: Option<PathBuf>,
pub llvm_filecheck: Option<Utf8PathBuf>,

/// Path to LLVM's bin directory.
pub llvm_bin_dir: Option<PathBuf>,
pub llvm_bin_dir: Option<Utf8PathBuf>,

/// The path to the Clang executable to run Clang-based tests with. If
/// `None` then these tests will be ignored.
pub run_clang_based_tests_with: Option<String>,

/// The directory containing the sources.
pub src_root: PathBuf,
pub src_root: Utf8PathBuf,
/// The directory containing the test suite sources. Must be a subdirectory of `src_root`.
pub src_test_suite_root: PathBuf,
pub src_test_suite_root: Utf8PathBuf,

/// Root build directory (e.g. `build/`).
pub build_root: PathBuf,
pub build_root: Utf8PathBuf,
/// Test suite specific build directory (e.g. `build/host/test/ui/`).
pub build_test_suite_root: PathBuf,
pub build_test_suite_root: Utf8PathBuf,

/// The directory containing the compiler sysroot
pub sysroot_base: PathBuf,
pub sysroot_base: Utf8PathBuf,

/// The number of the stage under test.
pub stage: u32,
@@ -301,7 +300,7 @@ pub struct Config {
pub host: String,

/// Path to / name of the Microsoft Console Debugger (CDB) executable
pub cdb: Option<OsString>,
pub cdb: Option<Utf8PathBuf>,

/// Version of CDB
pub cdb_version: Option<[u16; 4]>,
@@ -322,7 +321,7 @@ pub struct Config {
pub system_llvm: bool,

/// Path to the android tools
pub android_cross_path: PathBuf,
pub android_cross_path: Utf8PathBuf,

/// Extra parameter to run adb on arm-linux-androideabi
pub adb_path: String,
@@ -346,7 +345,7 @@ pub struct Config {
pub color: ColorConfig,

/// where to find the remote test client process, if we're using it
pub remote_test_client: Option<PathBuf>,
pub remote_test_client: Option<Utf8PathBuf>,

/// mode describing what file the actual ui output will be compared to
pub compare_mode: Option<CompareMode>,
@@ -414,7 +413,7 @@ pub struct Config {
/// Path to minicore aux library, used for `no_core` tests that need `core` stubs in
/// cross-compilation scenarios that do not otherwise want/need to `-Zbuild-std`. Used in e.g.
/// ABI tests.
pub minicore_path: PathBuf,
pub minicore_path: Utf8PathBuf,
}

impl Config {
@@ -804,8 +803,8 @@ fn serde_parse_u32<'de, D: Deserializer<'de>>(deserializer: D) -> Result<u32, D:

#[derive(Debug, Clone)]
pub struct TestPaths {
pub file: PathBuf, // e.g., compile-test/foo/bar/baz.rs
pub relative_dir: PathBuf, // e.g., foo/bar
pub file: Utf8PathBuf, // e.g., compile-test/foo/bar/baz.rs
pub relative_dir: Utf8PathBuf, // e.g., foo/bar
}

/// Used by `ui` tests to generate things like `foo.stderr` from `foo.rs`.
@@ -814,7 +813,7 @@ pub fn expected_output_path(
revision: Option<&str>,
compare_mode: &Option<CompareMode>,
kind: &str,
) -> PathBuf {
) -> Utf8PathBuf {
assert!(UI_EXTENSIONS.contains(&kind));
let mut parts = Vec::new();

@@ -865,7 +864,7 @@ pub const UI_COVERAGE_MAP: &str = "cov-map";
/// ```
///
/// This is created early when tests are collected to avoid race conditions.
pub fn output_relative_path(config: &Config, relative_dir: &Path) -> PathBuf {
pub fn output_relative_path(config: &Config, relative_dir: &Utf8Path) -> Utf8PathBuf {
config.build_test_suite_root.join(relative_dir)
}

@@ -874,10 +873,10 @@ pub fn output_testname_unique(
config: &Config,
testpaths: &TestPaths,
revision: Option<&str>,
) -> PathBuf {
) -> Utf8PathBuf {
let mode = config.compare_mode.as_ref().map_or("", |m| m.to_str());
let debugger = config.debugger.as_ref().map_or("", |m| m.to_str());
PathBuf::from(&testpaths.file.file_stem().unwrap())
Utf8PathBuf::from(&testpaths.file.file_stem().unwrap())
.with_extra_extension(config.mode.output_dir_disambiguator())
.with_extra_extension(revision.unwrap_or(""))
.with_extra_extension(mode)
@@ -887,20 +886,32 @@ pub fn output_testname_unique(
/// Absolute path to the directory where all output for the given
/// test/revision should reside. Example:
/// /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/
pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
pub fn output_base_dir(
config: &Config,
testpaths: &TestPaths,
revision: Option<&str>,
) -> Utf8PathBuf {
output_relative_path(config, &testpaths.relative_dir)
.join(output_testname_unique(config, testpaths, revision))
}

/// Absolute path to the base filename used as output for the given
/// test/revision. Example:
/// /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/testname
pub fn output_base_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
pub fn output_base_name(
config: &Config,
testpaths: &TestPaths,
revision: Option<&str>,
) -> Utf8PathBuf {
output_base_dir(config, testpaths, revision).join(testpaths.file.file_stem().unwrap())
}

/// Absolute path to the directory to use for incremental compilation. Example:
/// /path/to/build/host-tuple/test/ui/relative/testname.mode/testname.inc
pub fn incremental_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
pub fn incremental_dir(
config: &Config,
testpaths: &TestPaths,
revision: Option<&str>,
) -> Utf8PathBuf {
output_base_name(config, testpaths, revision).with_extension("inc")
}
17 changes: 10 additions & 7 deletions src/tools/compiletest/src/compute_diff.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::VecDeque;
use std::fs::{File, FileType};
use std::path::Path;

use camino::Utf8Path;

#[derive(Debug, PartialEq)]
pub enum DiffLine {
@@ -112,8 +113,8 @@ pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> S
/// Returns whether any data was actually written.
pub(crate) fn write_filtered_diff<Filter>(
diff_filename: &str,
out_dir: &Path,
compare_dir: &Path,
out_dir: &Utf8Path,
compare_dir: &Utf8Path,
verbose: bool,
filter: Filter,
) -> bool
@@ -123,19 +124,21 @@ where
use std::io::{Read, Write};
let mut diff_output = File::create(diff_filename).unwrap();
let mut wrote_data = false;
for entry in walkdir::WalkDir::new(out_dir) {
for entry in walkdir::WalkDir::new(out_dir.as_std_path()) {
let entry = entry.expect("failed to read file");
let extension = entry.path().extension().and_then(|p| p.to_str());
if filter(entry.file_type(), extension) {
let expected_path = compare_dir.join(entry.path().strip_prefix(&out_dir).unwrap());
let expected_path = compare_dir
.as_std_path()
.join(entry.path().strip_prefix(&out_dir.as_std_path()).unwrap());
let expected = if let Ok(s) = std::fs::read(&expected_path) { s } else { continue };
let actual_path = entry.path();
let actual = std::fs::read(&actual_path).unwrap();
let diff = unified_diff::diff(
&expected,
&expected_path.to_string_lossy(),
&expected_path.to_str().unwrap(),
&actual,
&actual_path.to_string_lossy(),
&actual_path.to_str().unwrap(),
3,
);
wrote_data |= !diff.is_empty();
27 changes: 13 additions & 14 deletions src/tools/compiletest/src/debuggers.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::env;
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::Arc;

use camino::{Utf8Path, Utf8PathBuf};

use crate::common::{Config, Debugger};

pub(crate) fn configure_cdb(config: &Config) -> Option<Arc<Config>> {
@@ -78,12 +78,15 @@ fn is_pc_windows_msvc_target(target: &str) -> bool {
target.ends_with("-pc-windows-msvc")
}

fn find_cdb(target: &str) -> Option<OsString> {
fn find_cdb(target: &str) -> Option<Utf8PathBuf> {
if !(cfg!(windows) && is_pc_windows_msvc_target(target)) {
return None;
}

let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?;
let pf86 = Utf8PathBuf::from_path_buf(
env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?.into(),
)
.unwrap();
let cdb_arch = if cfg!(target_arch = "x86") {
"x86"
} else if cfg!(target_arch = "x86_64") {
@@ -96,8 +99,7 @@ fn find_cdb(target: &str) -> Option<OsString> {
return None; // No compatible CDB.exe in the Windows 10 SDK
};

let mut path = PathBuf::new();
path.push(pf86);
let mut path = pf86;
path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too?
path.push(cdb_arch);
path.push(r"cdb.exe");
@@ -106,15 +108,15 @@ fn find_cdb(target: &str) -> Option<OsString> {
return None;
}

Some(path.into_os_string())
Some(path)
}

/// Returns Path to CDB
pub(crate) fn analyze_cdb(
cdb: Option<String>,
target: &str,
) -> (Option<OsString>, Option<[u16; 4]>) {
let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target));
) -> (Option<Utf8PathBuf>, Option<[u16; 4]>) {
let cdb = cdb.map(Utf8PathBuf::from).or_else(|| find_cdb(target));

let mut version = None;
if let Some(cdb) = cdb.as_ref() {
@@ -143,7 +145,7 @@ pub(crate) fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> {
pub(crate) fn analyze_gdb(
gdb: Option<String>,
target: &str,
android_cross_path: &Path,
android_cross_path: &Utf8Path,
) -> (Option<String>, Option<u32>) {
#[cfg(not(windows))]
const GDB_FALLBACK: &str = "gdb";
@@ -152,10 +154,7 @@ pub(crate) fn analyze_gdb(

let fallback_gdb = || {
if is_android_gdb_target(target) {
let mut gdb_path = match android_cross_path.to_str() {
Some(x) => x.to_owned(),
None => panic!("cannot find android cross path"),
};
let mut gdb_path = android_cross_path.to_string();
gdb_path.push_str("/bin/gdb");
gdb_path
} else {
6 changes: 3 additions & 3 deletions src/tools/compiletest/src/errors.rs
Original file line number Diff line number Diff line change
@@ -2,9 +2,9 @@ use std::fmt;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;
use std::sync::OnceLock;

use camino::Utf8Path;
use regex::Regex;
use tracing::*;

@@ -102,8 +102,8 @@ impl Error {
///
/// If revision is not None, then we look
/// for `//[X]~` instead, where `X` is the current revision.
pub fn load_errors(testfile: &Path, revision: Option<&str>) -> Vec<Error> {
let rdr = BufReader::new(File::open(testfile).unwrap());
pub fn load_errors(testfile: &Utf8Path, revision: Option<&str>) -> Vec<Error> {
let rdr = BufReader::new(File::open(testfile.as_std_path()).unwrap());

// `last_nonfollow_error` tracks the most recently seen
// line with an error template that did not use the
Loading
Loading