]> git.lizzy.rs Git - rust.git/blob - src/tools/x/src/main.rs
Rollup merge of #101175 - tmandry:curse-push-hook, r=jyn514
[rust.git] / src / tools / x / src / main.rs
1 //! Run `x.py` from any subdirectory of a rust compiler checkout.
2 //!
3 //! We prefer `exec`, to avoid adding an extra process in the process tree.
4 //! However, since `exec` isn't available on Windows, we indirect through
5 //! `exec_or_status`, which will call `exec` on unix and `status` on Windows.
6 //!
7 //! We use `python`, `python3`, or `python2` as the python interpreter to run
8 //! `x.py`, in that order of preference.
9
10 use std::{
11     env, io,
12     process::{self, Command, ExitStatus},
13 };
14
15 const PYTHON: &str = "python";
16 const PYTHON2: &str = "python2";
17 const PYTHON3: &str = "python3";
18
19 fn python() -> &'static str {
20     let val = match env::var_os("PATH") {
21         Some(val) => val,
22         None => return PYTHON,
23     };
24
25     let mut python2 = false;
26     let mut python3 = false;
27
28     for dir in env::split_paths(&val) {
29         // `python` should always take precedence over python2 / python3 if it exists
30         if dir.join(PYTHON).exists() {
31             return PYTHON;
32         }
33
34         python2 |= dir.join(PYTHON2).exists();
35         python3 |= dir.join(PYTHON3).exists();
36     }
37
38     // try 3 before 2
39     if python3 {
40         PYTHON3
41     } else if python2 {
42         PYTHON2
43     } else {
44         // Python was not found on path, so exit
45         eprintln!("Unable to find python in your PATH. Please check it is installed.");
46         process::exit(1);
47     }
48 }
49
50 #[cfg(unix)]
51 fn exec_or_status(command: &mut Command) -> io::Result<ExitStatus> {
52     use std::os::unix::process::CommandExt;
53     Err(command.exec())
54 }
55
56 #[cfg(not(unix))]
57 fn exec_or_status(command: &mut Command) -> io::Result<ExitStatus> {
58     command.status()
59 }
60
61 fn main() {
62     let current = match env::current_dir() {
63         Ok(dir) => dir,
64         Err(err) => {
65             eprintln!("Failed to get current directory: {err}");
66             process::exit(1);
67         }
68     };
69
70     for dir in current.ancestors() {
71         let candidate = dir.join("x.py");
72
73         if candidate.exists() {
74             let mut python = Command::new(python());
75
76             python.arg(&candidate).args(env::args().skip(1)).current_dir(dir);
77
78             let result = exec_or_status(&mut python);
79
80             match result {
81                 Err(error) => {
82                     eprintln!("Failed to invoke `{}`: {}", candidate.display(), error);
83                 }
84                 Ok(status) => {
85                     process::exit(status.code().unwrap_or(1));
86                 }
87             }
88         }
89     }
90
91     eprintln!(
92         "x.py not found. Please run inside of a checkout of `https://github.com/rust-lang/rust`."
93     );
94
95     process::exit(1);
96 }