about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/tools/miri/miri-script/Cargo.lock299
-rw-r--r--src/tools/miri/miri-script/Cargo.toml1
-rw-r--r--src/tools/miri/miri-script/src/commands.rs20
-rw-r--r--src/tools/miri/miri-script/src/main.rs184
4 files changed, 150 insertions, 354 deletions
diff --git a/src/tools/miri/miri-script/Cargo.lock b/src/tools/miri/miri-script/Cargo.lock
index be6eea0ed5d..cf6062d7d7f 100644
--- a/src/tools/miri/miri-script/Cargo.lock
+++ b/src/tools/miri/miri-script/Cargo.lock
@@ -3,121 +3,12 @@
 version = 3
 
 [[package]]
-name = "anstream"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
-dependencies = [
- "anstyle",
- "anstyle-parse",
- "anstyle-query",
- "anstyle-wincon",
- "colorchoice",
- "is-terminal",
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d"
-
-[[package]]
-name = "anstyle-parse"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee"
-dependencies = [
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle-query"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
-dependencies = [
- "windows-sys",
-]
-
-[[package]]
-name = "anstyle-wincon"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
-dependencies = [
- "anstyle",
- "windows-sys",
-]
-
-[[package]]
 name = "anyhow"
 version = "1.0.71"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
 
 [[package]]
-name = "bitflags"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "cc"
-version = "1.0.79"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
-
-[[package]]
-name = "clap"
-version = "4.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34d21f9bf1b425d2968943631ec91202fe5e837264063503708b83013f8fc938"
-dependencies = [
- "clap_builder",
- "clap_derive",
- "once_cell",
-]
-
-[[package]]
-name = "clap_builder"
-version = "4.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd"
-dependencies = [
- "anstream",
- "anstyle",
- "bitflags",
- "clap_lex",
- "strsim",
-]
-
-[[package]]
-name = "clap_derive"
-version = "4.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "clap_lex"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
-
-[[package]]
-name = "colorchoice"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
-
-[[package]]
 name = "dunce"
 version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -130,62 +21,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
 
 [[package]]
-name = "errno"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
-dependencies = [
- "errno-dragonfly",
- "libc",
- "windows-sys",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
-name = "heck"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
-
-[[package]]
-name = "hermit-abi"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
-
-[[package]]
-name = "io-lifetimes"
-version = "1.0.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
-dependencies = [
- "hermit-abi",
- "libc",
- "windows-sys",
-]
-
-[[package]]
-name = "is-terminal"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
-dependencies = [
- "hermit-abi",
- "io-lifetimes",
- "rustix",
- "windows-sys",
-]
-
-[[package]]
 name = "itertools"
 version = "0.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -201,17 +36,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
 
 [[package]]
-name = "linux-raw-sys"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
-
-[[package]]
 name = "miri-script"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "clap",
  "dunce",
  "itertools",
  "path_macro",
@@ -235,24 +63,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a6e819bbd49d5939f682638fa54826bf1650abddcd65d000923de8ad63cc7d15"
 
 [[package]]
-name = "proc-macro2"
-version = "1.0.60"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
 name = "rustc_version"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -262,20 +72,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "rustix"
-version = "0.37.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
-dependencies = [
- "bitflags",
- "errno",
- "io-lifetimes",
- "libc",
- "linux-raw-sys",
- "windows-sys",
-]
-
-[[package]]
 name = "same-file"
 version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -297,35 +93,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
 
 [[package]]
-name = "strsim"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
-[[package]]
-name = "syn"
-version = "2.0.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
-
-[[package]]
-name = "utf8parse"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
-
-[[package]]
 name = "walkdir"
 version = "2.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -378,72 +145,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
-name = "windows-sys"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-dependencies = [
- "windows-targets",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
-dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
-
-[[package]]
 name = "xshell"
 version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/miri/miri-script/Cargo.toml b/src/tools/miri/miri-script/Cargo.toml
index 197f6abd990..c0414a2fe37 100644
--- a/src/tools/miri/miri-script/Cargo.toml
+++ b/src/tools/miri/miri-script/Cargo.toml
@@ -11,7 +11,6 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-clap = {version = "4.2", features = ["derive", "env"]}
 which = "4.4"
 walkdir = "2.3"
 itertools = "0.10"
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 33e407a65da..66c2a4b0fd6 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -79,13 +79,11 @@ impl Command {
             Command::Fmt { flags } => Self::fmt(flags),
             Command::Clippy { flags } => Self::clippy(flags),
             Command::Cargo { flags } => Self::cargo(flags),
-            Command::ManySeeds { command, seed_start, seeds } =>
-                Self::many_seeds(command, seed_start, seeds),
+            Command::ManySeeds { command } => Self::many_seeds(command),
             Command::Bench { benches } => Self::bench(benches),
             Command::Toolchain { flags } => Self::toolchain(flags),
             Command::RustcPull { commit } => Self::rustc_pull(commit.clone()),
-            Command::RustcPush { rustc_git, github_user, branch } =>
-                Self::rustc_push(rustc_git, github_user, branch),
+            Command::RustcPush { github_user, branch } => Self::rustc_push(github_user, branch),
         }
     }
 
@@ -178,7 +176,7 @@ impl Command {
         Ok(())
     }
 
-    fn rustc_push(rustc_git: Option<String>, github_user: String, branch: String) -> Result<()> {
+    fn rustc_push(github_user: String, branch: String) -> Result<()> {
         let sh = shell()?;
         sh.change_dir(miri_dir()?);
         let base = sh.read_file("rust-version")?.trim().to_owned();
@@ -188,7 +186,7 @@ impl Command {
         }
 
         // Find a repo we can do our preparation in.
-        if let Some(rustc_git) = rustc_git {
+        if let Ok(rustc_git) = env::var("RUSTC_GIT") {
             // If rustc_git is `Some`, we'll use an existing fork for the branch updates.
             sh.change_dir(rustc_git);
         } else {
@@ -254,7 +252,15 @@ impl Command {
         Ok(())
     }
 
-    fn many_seeds(command: Vec<OsString>, seed_start: u64, seed_count: u64) -> Result<()> {
+    fn many_seeds(command: Vec<OsString>) -> Result<()> {
+        let seed_start: u64 = env::var("MIRI_SEED_START")
+            .unwrap_or_else(|_| "0".into())
+            .parse()
+            .context("failed to parse MIRI_SEED_START")?;
+        let seed_count: u64 = env::var("MIRI_SEEDS")
+            .unwrap_or_else(|_| "256".into())
+            .parse()
+            .context("failed to parse MIRI_SEEDS")?;
         let seed_end = seed_start + seed_count;
         let Some((command_name, trailing_args)) = command.split_first() else {
             bail!("expected many-seeds command to be non-empty");
diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs
index ce00de5ac54..849a9168028 100644
--- a/src/tools/miri/miri-script/src/main.rs
+++ b/src/tools/miri/miri-script/src/main.rs
@@ -1,19 +1,12 @@
 mod commands;
 mod util;
 
+use std::env;
 use std::ffi::OsString;
 
-use anyhow::Result;
-use clap::{Parser, Subcommand};
+use anyhow::{anyhow, bail, Result};
 
-#[derive(Parser, Clone, Debug)]
-#[command(author, about, long_about = None)]
-pub struct Cli {
-    #[command(subcommand)]
-    pub command: Command,
-}
-
-#[derive(Subcommand, Clone, Debug)]
+#[derive(Clone, Debug)]
 pub enum Command {
     /// Installs the miri driver and cargo-miri.
     /// Sets up the rpath such that the installed binary should work in any
@@ -21,83 +14,58 @@ pub enum Command {
     /// sysroot, to prevent conflicts with other toolchains.
     Install {
         /// Flags that are passed through to `cargo install`.
-        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<OsString>,
     },
     /// Just build miri.
     Build {
         /// Flags that are passed through to `cargo build`.
-        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<OsString>,
     },
     /// Just check miri.
     Check {
         /// Flags that are passed through to `cargo check`.
-        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<OsString>,
     },
     /// Build miri, set up a sysroot and then run the test suite.
     Test {
-        #[arg(long, default_value_t = false)]
         bless: bool,
         /// Flags that are passed through to `cargo test`.
-        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<OsString>,
     },
     /// Build miri, set up a sysroot and then run the driver with the given <flags>.
     /// (Also respects MIRIFLAGS environment variable.)
     Run {
-        #[arg(long, default_value_t = false)]
         dep: bool,
-        /// Flags that are passed through to `miri`
-        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
+        /// Flags that are passed through to `miri`.
         flags: Vec<OsString>,
     },
     /// Format all sources and tests.
     Fmt {
         /// Flags that are passed through to `rustfmt`.
-        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<OsString>,
     },
     /// Runs clippy on all sources.
     Clippy {
         /// Flags that are passed through to `cargo clippy`.
-        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         flags: Vec<OsString>,
     },
     /// Runs just `cargo <flags>` with the Miri-specific environment variables.
     /// Mainly meant to be invoked by rust-analyzer.
-    Cargo {
-        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
-        flags: Vec<OsString>,
-    },
+    Cargo { flags: Vec<OsString> },
     /// Runs <command> over and over again with different seeds for Miri. The MIRIFLAGS
     /// variable is set to its original value appended with ` -Zmiri-seed=$SEED` for
     /// many different seeds.
-    ManySeeds {
-        /// Starting seed.
-        #[arg(long, env = "MIRI_SEED_START", default_value_t = 0)]
-        seed_start: u64,
-        /// Amount of seeds to try.
-        #[arg(long, env = "MIRI_SEEDS", default_value_t = 256)]
-        seeds: u64,
-        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
-        command: Vec<OsString>,
-    },
+    ManySeeds { command: Vec<OsString> },
     /// Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed.
     Bench {
         /// List of benchmarks to run. By default all benchmarks are run.
-        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
         benches: Vec<OsString>,
     },
     /// Update and activate the rustup toolchain 'miri' to the commit given in the
     /// `rust-version` file.
     /// `rustup-toolchain-install-master` must be installed for this to work. Any extra
     /// flags are passed to `rustup-toolchain-install-master`.
-    Toolchain {
-        #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
-        flags: Vec<OsString>,
-    },
+    Toolchain { flags: Vec<OsString> },
     /// Pull and merge Miri changes from the rustc repo. Defaults to fetching the latest
     /// rustc commit. The fetched commit is stored in the `rust-version` file, so the
     /// next `./miri toolchain` will install the rustc that just got pulled.
@@ -105,16 +73,138 @@ pub enum Command {
     /// Push Miri changes back to the rustc repo. This will pull a copy of the rustc
     /// history into the Miri repo, unless you set the RUSTC_GIT env var to an existing
     /// clone of the rustc repo.
-    RustcPush {
-        #[arg(long, env = "RUSTC_GIT")]
-        rustc_git: Option<String>,
-        github_user: String,
-        branch: String,
-    },
+    RustcPush { github_user: String, branch: String },
 }
 
+const HELP: &str = r#"  COMMANDS
+
+./miri build <flags>:
+Just build miri. <flags> are passed to `cargo build`.
+
+./miri check <flags>:
+Just check miri. <flags> are passed to `cargo check`.
+
+./miri test [--bless] <flags>:
+Build miri, set up a sysroot and then run the test suite. <flags> are passed
+to the final `cargo test` invocation.
+
+./miri run [--dep] <flags>:
+Build miri, set up a sysroot and then run the driver with the given <flags>.
+(Also respects MIRIFLAGS environment variable.)
+
+./miri fmt <flags>:
+Format all sources and tests. <flags> are passed to `rustfmt`.
+
+./miri clippy <flags>:
+Runs clippy on all sources. <flags> are passed to `cargo clippy`.
+
+./miri cargo <flags>:
+Runs just `cargo <flags>` with the Miri-specific environment variables.
+Mainly meant to be invoked by rust-analyzer.
+
+./miri install <flags>:
+Installs the miri driver and cargo-miri. <flags> are passed to `cargo
+install`. Sets up the rpath such that the installed binary should work in any
+working directory. Note that the binaries are placed in the `miri` toolchain
+sysroot, to prevent conflicts with other toolchains.
+
+./miri many-seeds <command>:
+Runs <command> over and over again with different seeds for Miri. The MIRIFLAGS
+variable is set to its original value appended with ` -Zmiri-seed=$SEED` for
+many different seeds. The MIRI_SEEDS variable controls how many seeds are being
+tried; MIRI_SEED_START controls the first seed to try.
+
+./miri bench <benches>:
+Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed.
+<benches> can explicitly list the benchmarks to run; by default, all of them are run.
+
+./miri toolchain <flags>:
+Update and activate the rustup toolchain 'miri' to the commit given in the
+`rust-version` file.
+`rustup-toolchain-install-master` must be installed for this to work. Any extra
+flags are passed to `rustup-toolchain-install-master`.
+
+./miri rustc-pull <commit>:
+Pull and merge Miri changes from the rustc repo. Defaults to fetching the latest
+rustc commit. The fetched commit is stored in the `rust-version` file, so the
+next `./miri toolchain` will install the rustc that just got pulled.
+
+./miri rustc-push <github user> <branch>:
+Push Miri changes back to the rustc repo. This will pull a copy of the rustc
+history into the Miri repo, unless you set the RUSTC_GIT env var to an existing
+clone of the rustc repo.
+
+  ENVIRONMENT VARIABLES
+
+MIRI_SYSROOT:
+If already set, the "sysroot setup" step is skipped.
+
+CARGO_EXTRA_FLAGS:
+Pass extra flags to all cargo invocations. (Ignored by `./miri cargo`.)"#;
+
 fn main() -> Result<()> {
-    let args = Cli::parse();
-    args.command.exec()?;
+    // We are hand-rolling our own argument parser, since `clap` can't express what we need
+    // (https://github.com/clap-rs/clap/issues/5055).
+    let mut args = env::args_os().peekable();
+    args.next().unwrap(); // skip program name
+    let command = match args.next().and_then(|s| s.into_string().ok()).as_deref() {
+        Some("build") => Command::Build { flags: args.collect() },
+        Some("check") => Command::Check { flags: args.collect() },
+        Some("test") => {
+            let bless = args.peek().is_some_and(|a| a.to_str() == Some("--bless"));
+            if bless {
+                // Consume the flag.
+                args.next().unwrap();
+            }
+            Command::Test { bless, flags: args.collect() }
+        }
+        Some("run") => {
+            let dep = args.peek().is_some_and(|a| a.to_str() == Some("--dep"));
+            if dep {
+                // Consume the flag.
+                args.next().unwrap();
+            }
+            Command::Run { dep, flags: args.collect() }
+        }
+        Some("fmt") => Command::Fmt { flags: args.collect() },
+        Some("clippy") => Command::Clippy { flags: args.collect() },
+        Some("cargo") => Command::Cargo { flags: args.collect() },
+        Some("install") => Command::Install { flags: args.collect() },
+        Some("many-seeds") => Command::ManySeeds { command: args.collect() },
+        Some("bench") => Command::Bench { benches: args.collect() },
+        Some("toolchain") => Command::Toolchain { flags: args.collect() },
+        Some("rustc-pull") => {
+            let commit = args.next().map(|a| a.to_string_lossy().into_owned());
+            if args.next().is_some() {
+                bail!("Too many arguments for `./miri rustc-pull`");
+            }
+            Command::RustcPull { commit }
+        }
+        Some("rustc-push") => {
+            let github_user = args
+                .next()
+                .ok_or_else(|| {
+                    anyhow!("Missing first argument for `./miri rustc-push GITHUB_USER BRANCH`")
+                })?
+                .to_string_lossy()
+                .into_owned();
+            let branch = args
+                .next()
+                .ok_or_else(|| {
+                    anyhow!("Missing second argument for `./miri rustc-push GITHUB_USER BRANCH`")
+                })?
+                .to_string_lossy()
+                .into_owned();
+            if args.next().is_some() {
+                bail!("Too many arguments for `./miri rustc-push GITHUB_USER BRANCH`");
+            }
+            Command::RustcPush { github_user, branch }
+        }
+        _ => {
+            eprintln!("Unknown or missing command. Usage:\n\n{HELP}");
+            std::process::exit(1);
+        }
+    };
+    command.exec()?;
     Ok(())
 }