mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-24 07:44:10 +00:00
perform filesystem probe once before running bins checks concurrently
this avoids concurrent write attempts to the output directory
This commit is contained in:
parent
207104010a
commit
0513ba4d65
@ -5,94 +5,126 @@
|
|||||||
//! huge amount of bloat to the Git history, so it's good to just ensure we
|
//! huge amount of bloat to the Git history, so it's good to just ensure we
|
||||||
//! don't do that again.
|
//! don't do that again.
|
||||||
|
|
||||||
use std::path::Path;
|
pub use os_impl::*;
|
||||||
|
|
||||||
// All files are executable on Windows, so just check on Unix.
|
// All files are executable on Windows, so just check on Unix.
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub fn check(_path: &Path, _output: &Path, _bad: &mut bool) {}
|
mod os_impl {
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
pub fn check_filesystem_support(_sources: &[&Path], _output: &Path) -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check(_path: &Path, _bad: &mut bool) {}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn check(path: &Path, output: &Path, bad: &mut bool) {
|
mod os_impl {
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::os::unix::prelude::*;
|
use std::os::unix::prelude::*;
|
||||||
|
use std::path::Path;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
|
enum FilesystemSupport {
|
||||||
|
Supported,
|
||||||
|
Unsupported,
|
||||||
|
ReadOnlyFs,
|
||||||
|
}
|
||||||
|
|
||||||
|
use FilesystemSupport::*;
|
||||||
|
|
||||||
fn is_executable(path: &Path) -> std::io::Result<bool> {
|
fn is_executable(path: &Path) -> std::io::Result<bool> {
|
||||||
Ok(path.metadata()?.mode() & 0o111 != 0)
|
Ok(path.metadata()?.mode() & 0o111 != 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We want to avoid false positives on filesystems that do not support the
|
pub fn check_filesystem_support(sources: &[&Path], output: &Path) -> bool {
|
||||||
// executable bit. This occurs on some versions of Window's linux subsystem,
|
// We want to avoid false positives on filesystems that do not support the
|
||||||
// for example.
|
// executable bit. This occurs on some versions of Window's linux subsystem,
|
||||||
//
|
// for example.
|
||||||
// We try to create the temporary file first in the src directory, which is
|
//
|
||||||
// the preferred location as it's most likely to be on the same filesystem,
|
// We try to create the temporary file first in the src directory, which is
|
||||||
// and then in the output (`build`) directory if that fails. Sometimes we
|
// the preferred location as it's most likely to be on the same filesystem,
|
||||||
// see the source directory mounted as read-only which means we can't
|
// and then in the output (`build`) directory if that fails. Sometimes we
|
||||||
// readily create a file there to test.
|
// see the source directory mounted as read-only which means we can't
|
||||||
//
|
// readily create a file there to test.
|
||||||
// See #36706 and #74753 for context.
|
//
|
||||||
//
|
// See #36706 and #74753 for context.
|
||||||
// We also add the thread ID to avoid threads trampling on each others files.
|
|
||||||
let file_name = format!("t{}.tidy-test-file", std::thread::current().id().as_u64());
|
|
||||||
let mut temp_path = path.join(&file_name);
|
|
||||||
match fs::File::create(&temp_path).or_else(|_| {
|
|
||||||
temp_path = output.join(&file_name);
|
|
||||||
fs::File::create(&temp_path)
|
|
||||||
}) {
|
|
||||||
Ok(file) => {
|
|
||||||
let exec = is_executable(&temp_path).unwrap_or(false);
|
|
||||||
std::mem::drop(file);
|
|
||||||
std::fs::remove_file(&temp_path).expect("Deleted temp file");
|
|
||||||
if exec {
|
|
||||||
// If the file is executable, then we assume that this
|
|
||||||
// filesystem does not track executability, so skip this check.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
// If the directory is read-only or we otherwise don't have rights,
|
|
||||||
// just don't run this check.
|
|
||||||
//
|
|
||||||
// 30 is the "Read-only filesystem" code at least in one CI
|
|
||||||
// environment.
|
|
||||||
if e.raw_os_error() == Some(30) {
|
|
||||||
eprintln!("tidy: Skipping binary file check, read-only filesystem");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
panic!("unable to create temporary file `{:?}`: {:?}", temp_path, e);
|
fn check_dir(dir: &Path) -> FilesystemSupport {
|
||||||
|
let path = dir.join("tidy-test-file");
|
||||||
|
match fs::File::create(&path) {
|
||||||
|
Ok(file) => {
|
||||||
|
let exec = is_executable(&path).unwrap_or(false);
|
||||||
|
std::mem::drop(file);
|
||||||
|
std::fs::remove_file(&path).expect("Deleted temp file");
|
||||||
|
// If the file is executable, then we assume that this
|
||||||
|
// filesystem does not track executability, so skip this check.
|
||||||
|
return if exec { Unsupported } else { Supported };
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// If the directory is read-only or we otherwise don't have rights,
|
||||||
|
// just don't run this check.
|
||||||
|
//
|
||||||
|
// 30 is the "Read-only filesystem" code at least in one CI
|
||||||
|
// environment.
|
||||||
|
if e.raw_os_error() == Some(30) {
|
||||||
|
eprintln!("tidy: Skipping binary file check, read-only filesystem");
|
||||||
|
return ReadOnlyFs;
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("unable to create temporary file `{:?}`: {:?}", path, e);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for &source_dir in sources {
|
||||||
|
match check_dir(source_dir) {
|
||||||
|
Unsupported => return false,
|
||||||
|
ReadOnlyFs => {
|
||||||
|
return match check_dir(output) {
|
||||||
|
Supported => true,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
super::walk_no_read(
|
#[cfg(unix)]
|
||||||
path,
|
pub fn check(path: &Path, bad: &mut bool) {
|
||||||
&mut |path| super::filter_dirs(path) || path.ends_with("src/etc"),
|
crate::walk_no_read(
|
||||||
&mut |entry| {
|
path,
|
||||||
let file = entry.path();
|
&mut |path| crate::filter_dirs(path) || path.ends_with("src/etc"),
|
||||||
let filename = file.file_name().unwrap().to_string_lossy();
|
&mut |entry| {
|
||||||
let extensions = [".py", ".sh"];
|
let file = entry.path();
|
||||||
if extensions.iter().any(|e| filename.ends_with(e)) {
|
let filename = file.file_name().unwrap().to_string_lossy();
|
||||||
return;
|
let extensions = [".py", ".sh"];
|
||||||
}
|
if extensions.iter().any(|e| filename.ends_with(e)) {
|
||||||
|
return;
|
||||||
if t!(is_executable(&file), file) {
|
|
||||||
let rel_path = file.strip_prefix(path).unwrap();
|
|
||||||
let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
|
|
||||||
let output = Command::new("git")
|
|
||||||
.arg("ls-files")
|
|
||||||
.arg(&git_friendly_path)
|
|
||||||
.current_dir(path)
|
|
||||||
.stderr(Stdio::null())
|
|
||||||
.output()
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
panic!("could not run git ls-files: {}", e);
|
|
||||||
});
|
|
||||||
let path_bytes = rel_path.as_os_str().as_bytes();
|
|
||||||
if output.status.success() && output.stdout.starts_with(path_bytes) {
|
|
||||||
tidy_error!(bad, "binary checked into source: {}", file.display());
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
if t!(is_executable(&file), file) {
|
||||||
)
|
let rel_path = file.strip_prefix(path).unwrap();
|
||||||
|
let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
|
||||||
|
let output = Command::new("git")
|
||||||
|
.arg("ls-files")
|
||||||
|
.arg(&git_friendly_path)
|
||||||
|
.current_dir(path)
|
||||||
|
.stderr(Stdio::null())
|
||||||
|
.output()
|
||||||
|
.unwrap_or_else(|e| {
|
||||||
|
panic!("could not run git ls-files: {}", e);
|
||||||
|
});
|
||||||
|
let path_bytes = rel_path.as_os_str().as_bytes();
|
||||||
|
if output.status.success() && output.stdout.starts_with(path_bytes) {
|
||||||
|
tidy_error!(bad, "binary checked into source: {}", file.display());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
//! to be used by tools.
|
//! to be used by tools.
|
||||||
|
|
||||||
#![cfg_attr(bootstrap, feature(str_split_once))]
|
#![cfg_attr(bootstrap, feature(str_split_once))]
|
||||||
#![feature(thread_id_value)]
|
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
@ -55,12 +54,6 @@ pub mod unit_tests;
|
|||||||
pub mod unstable_book;
|
pub mod unstable_book;
|
||||||
|
|
||||||
fn filter_dirs(path: &Path) -> bool {
|
fn filter_dirs(path: &Path) -> bool {
|
||||||
// Filter out temporary files used by the bins module to probe the filesystem
|
|
||||||
match path.extension() {
|
|
||||||
Some(ext) if ext == "tidy-test-file" => return true,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let skip = [
|
let skip = [
|
||||||
"compiler/rustc_codegen_cranelift",
|
"compiler/rustc_codegen_cranelift",
|
||||||
"src/llvm-project",
|
"src/llvm-project",
|
||||||
|
@ -75,9 +75,14 @@ fn main() {
|
|||||||
check!(unit_tests, &compiler_path);
|
check!(unit_tests, &compiler_path);
|
||||||
check!(unit_tests, &library_path);
|
check!(unit_tests, &library_path);
|
||||||
|
|
||||||
check!(bins, &src_path, &output_directory);
|
if bins::check_filesystem_support(
|
||||||
check!(bins, &compiler_path, &output_directory);
|
&[&src_path, &compiler_path, &library_path],
|
||||||
check!(bins, &library_path, &output_directory);
|
&output_directory,
|
||||||
|
) {
|
||||||
|
check!(bins, &src_path);
|
||||||
|
check!(bins, &compiler_path);
|
||||||
|
check!(bins, &library_path);
|
||||||
|
}
|
||||||
|
|
||||||
check!(style, &src_path);
|
check!(style, &src_path);
|
||||||
check!(style, &compiler_path);
|
check!(style, &compiler_path);
|
||||||
|
Loading…
Reference in New Issue
Block a user