Add a tool to run x.py
from any subdirectory
This adds a binary called `x` in `src/tools/x`. All it does is check the current directory and its ancestors for a file called `x.py`, and if it finds one, runs it. By installing x, you can easily `x.py` from any subdirectory. It can be installed globally with `cargo install --path src/tools/x`
This commit is contained in:
parent
4760b8fb88
commit
5fc22f1431
1
.gitignore
vendored
1
.gitignore
vendored
@ -31,6 +31,7 @@ __pycache__/
|
||||
/inst/
|
||||
/llvm/
|
||||
/mingw-build/
|
||||
/src/tools/x/target
|
||||
# Created by default with `src/ci/docker/run.sh`:
|
||||
/obj/
|
||||
/unicode-downloads
|
||||
|
@ -29,10 +29,16 @@ members = [
|
||||
"src/tools/unicode-table-generator",
|
||||
"src/tools/expand-yaml-anchors",
|
||||
]
|
||||
|
||||
exclude = [
|
||||
"build",
|
||||
# HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`.
|
||||
"obj",
|
||||
# The `x` binary is a thin wrapper that calls `x.py`, which initializes
|
||||
# submodules, before which workspace members cannot be invoked because
|
||||
# not all `Cargo.toml` files are available, so we exclude the `x` binary,
|
||||
# so it can be invoked before the current checkout is set up.
|
||||
"src/tools/x",
|
||||
]
|
||||
|
||||
[profile.release.package.compiler_builtins]
|
||||
|
5
src/tools/x/Cargo.lock
Normal file
5
src/tools/x/Cargo.lock
Normal file
@ -0,0 +1,5 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "x"
|
||||
version = "0.1.0"
|
7
src/tools/x/Cargo.toml
Normal file
7
src/tools/x/Cargo.toml
Normal file
@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "x"
|
||||
version = "0.1.0"
|
||||
description = "Run x.py slightly more conveniently"
|
||||
authors = ["Casey Rodarmor <casey@rodarmor.com>"]
|
||||
edition = "2018"
|
||||
publish = false
|
3
src/tools/x/README.md
Normal file
3
src/tools/x/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# x
|
||||
|
||||
`x` invokes `x.py` from any subdirectory.
|
92
src/tools/x/src/main.rs
Normal file
92
src/tools/x/src/main.rs
Normal file
@ -0,0 +1,92 @@
|
||||
//! Run `x.py` from any subdirectory of a rust compiler checkout.
|
||||
//!
|
||||
//! We prefer `exec`, to avoid adding an extra process in the process tree.
|
||||
//! However, since `exec` isn't available on Windows, we indirect through
|
||||
//! `exec_or_status`, which will call `exec` on unix and `status` on Windows.
|
||||
//!
|
||||
//! We use `python`, `python3`, or `python2` as the python interpreter to run
|
||||
//! `x.py`, in that order of preference.
|
||||
|
||||
use std::{
|
||||
env, io,
|
||||
process::{self, Command, ExitStatus},
|
||||
};
|
||||
|
||||
const PYTHON: &str = "python";
|
||||
const PYTHON2: &str = "python2";
|
||||
const PYTHON3: &str = "python3";
|
||||
|
||||
fn python() -> &'static str {
|
||||
let val = match env::var_os("PATH") {
|
||||
Some(val) => val,
|
||||
None => return PYTHON,
|
||||
};
|
||||
|
||||
let mut python2 = false;
|
||||
let mut python3 = false;
|
||||
|
||||
for dir in env::split_paths(&val) {
|
||||
if dir.join(PYTHON).exists() {
|
||||
return PYTHON;
|
||||
}
|
||||
|
||||
python2 |= dir.join(PYTHON2).exists();
|
||||
python3 |= dir.join(PYTHON3).exists();
|
||||
}
|
||||
|
||||
if python3 {
|
||||
PYTHON3
|
||||
} else if python2 {
|
||||
PYTHON2
|
||||
} else {
|
||||
PYTHON
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn exec_or_status(command: &mut Command) -> io::Result<ExitStatus> {
|
||||
use std::os::unix::process::CommandExt;
|
||||
Err(command.exec())
|
||||
}
|
||||
|
||||
#[cfg(not(unix))]
|
||||
fn exec_or_status(command: &mut Command) -> io::Result<ExitStatus> {
|
||||
command.status()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let current = match env::current_dir() {
|
||||
Ok(dir) => dir,
|
||||
Err(err) => {
|
||||
eprintln!("Failed to get current directory: {}", err);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
for dir in current.ancestors() {
|
||||
let candidate = dir.join("x.py");
|
||||
|
||||
if candidate.exists() {
|
||||
let mut python = Command::new(python());
|
||||
|
||||
python.arg(&candidate).args(env::args().skip(1)).current_dir(dir);
|
||||
|
||||
let result = exec_or_status(&mut python);
|
||||
|
||||
match result {
|
||||
Err(error) => {
|
||||
eprintln!("Failed to invoke `{}`: {}", candidate.display(), error);
|
||||
}
|
||||
Ok(status) => {
|
||||
process::exit(status.code().unwrap_or(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eprintln!(
|
||||
"x.py not found. Please run inside of a checkout of `https://github.com/rust-lang/rust`."
|
||||
);
|
||||
|
||||
process::exit(1);
|
||||
}
|
Loading…
Reference in New Issue
Block a user