run_make_support/
scoped_run.rs

1//! Collection of helpers that try to maintain certain properties while running a test closure.
2
3use std::path::Path;
4
5use crate::fs;
6use crate::path_helpers::cwd;
7use crate::targets::is_windows;
8
9/// Ensure that the path P is read-only while the test runs, and restore original permissions at the
10/// end so compiletest can clean up. This will panic on Windows if the path is a directory (as it
11/// would otherwise do nothing)
12///
13/// # Pitfalls
14///
15/// - Some CI runners are ran as root which may bypass read-only permission restrictions. Unclear
16///   exactly when such scenarios occur.
17///
18/// # FIXME
19///
20/// FIXME(Oneirical): This will no longer be required after compiletest receives the ability to
21/// manipulate read-only files. See <https://github.com/rust-lang/rust/issues/126334>.
22#[track_caller]
23pub fn test_while_readonly<P, F>(path: P, closure: F)
24where
25    P: AsRef<Path>,
26    F: FnOnce() + std::panic::UnwindSafe,
27{
28    let path = path.as_ref();
29    if is_windows() && path.is_dir() {
30        eprintln!("This helper function cannot be used on Windows to make directories readonly.");
31        eprintln!(
32            "See the official documentation:
33            https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.set_readonly"
34        );
35        panic!("`test_while_readonly` on directory detected while on Windows.");
36    }
37    let metadata = fs::metadata(&path);
38    let original_perms = metadata.permissions();
39
40    let mut new_perms = original_perms.clone();
41    new_perms.set_readonly(true);
42    fs::set_permissions(&path, new_perms);
43
44    let success = std::panic::catch_unwind(closure);
45
46    fs::set_permissions(&path, original_perms);
47    success.unwrap();
48}
49
50/// This function is designed for running commands in a temporary directory that is cleared after
51/// the function ends.
52///
53/// What this function does:
54/// 1. Creates a temporary directory (`tmpdir`)
55/// 2. Copies all files from the current directory to `tmpdir`
56/// 3. Changes the current working directory to `tmpdir`
57/// 4. Calls `callback`
58/// 5. Switches working directory back to the original one
59/// 6. Removes `tmpdir`
60pub fn run_in_tmpdir<F: FnOnce()>(callback: F) {
61    let original_dir = cwd();
62    let tmpdir = original_dir.join("../temporary-directory");
63    fs::copy_dir_all(".", &tmpdir);
64
65    std::env::set_current_dir(&tmpdir).unwrap();
66    callback();
67    std::env::set_current_dir(original_dir).unwrap();
68    fs::remove_dir_all(tmpdir);
69}