Skip to main content

bootstrap/core/config/
flags.rs

1//! Command-line interface of the bootstrap build system.
2//!
3//! This module implements the command-line parsing of the build system which
4//! has various flags to configure how it's run.
5
6use std::path::{Path, PathBuf};
7
8use clap::{CommandFactory, Parser, ValueEnum};
9use clap_complete::Generator;
10#[cfg(feature = "tracing")]
11use tracing::instrument;
12
13use crate::core::backend::CodegenBackendKind;
14use crate::core::build_steps::perf::PerfArgs;
15use crate::core::build_steps::setup::Profile;
16use crate::core::build_steps::test::TestTarget;
17use crate::core::builder::{Builder, Kind};
18use crate::core::config::Config;
19use crate::core::config::target_selection::{TargetSelectionList, target_selection_list};
20use crate::core::session::Session;
21use crate::utils::helpers;
22
23#[derive(Copy, Clone, Default, Debug, ValueEnum)]
24pub enum Color {
25    Always,
26    Never,
27    #[default]
28    Auto,
29}
30
31/// Whether to deny warnings, emit them as warnings, or use the default behavior
32#[derive(Copy, Clone, Default, Debug, ValueEnum)]
33pub enum Warnings {
34    Deny,
35    Warn,
36    #[default]
37    Default,
38}
39
40/// Deserialized version of all flags for this compile.
41#[derive(Debug, Parser)]
42#[command(
43    override_usage = "x.py <subcommand> [options] [<paths>...]",
44    disable_help_subcommand(true),
45    about = "",
46    next_line_help(false)
47)]
48pub struct Flags {
49    #[command(subcommand)]
50    pub cmd: Subcommand,
51
52    #[arg(global = true, short, long, action = clap::ArgAction::Count, conflicts_with = "quiet")]
53    /// use verbose output (-vv for very verbose)
54    pub verbose: u8, // each extra -v after the first is passed to Cargo
55    #[arg(global = true, short, long, conflicts_with = "verbose")]
56    /// use quiet output
57    pub quiet: bool,
58    #[arg(global = true, short, long)]
59    /// use incremental compilation
60    pub incremental: bool,
61    #[arg(global = true, long, value_hint = clap::ValueHint::FilePath, value_name = "FILE")]
62    /// TOML configuration file for build
63    pub config: Option<PathBuf>,
64    #[arg(global = true, long, value_hint = clap::ValueHint::DirPath, value_name = "DIR")]
65    /// Build directory, overrides `build.build-dir` in `bootstrap.toml`
66    pub build_dir: Option<PathBuf>,
67
68    #[arg(global = true, long, value_hint = clap::ValueHint::Other, value_name = "BUILD")]
69    /// host target of the stage0 compiler
70    pub build: Option<String>,
71
72    #[arg(global = true, long, value_hint = clap::ValueHint::Other, value_name = "HOST", value_parser = target_selection_list)]
73    /// host targets to build
74    pub host: Option<TargetSelectionList>,
75
76    #[arg(global = true, long, value_hint = clap::ValueHint::Other, value_name = "TARGET", value_parser = target_selection_list)]
77    /// target targets to build
78    pub target: Option<TargetSelectionList>,
79
80    #[arg(global = true, long, value_name = "PATH")]
81    /// build paths to exclude
82    pub exclude: Vec<PathBuf>, // keeping for client backward compatibility
83    #[arg(global = true, long, value_name = "PATH")]
84    /// build paths to skip
85    pub skip: Vec<PathBuf>,
86    #[arg(global = true, long)]
87    /// include default paths in addition to the provided ones
88    pub include_default_paths: bool,
89
90    /// rustc error format
91    #[arg(global = true, value_hint = clap::ValueHint::Other, long)]
92    pub rustc_error_format: Option<String>,
93
94    #[arg(global = true, long, value_hint = clap::ValueHint::CommandString, value_name = "CMD")]
95    /// command to run on failure
96    pub on_fail: Option<String>,
97    #[arg(global = true, long)]
98    /// dry run; don't build anything
99    pub dry_run: bool,
100    /// Indicates whether to dump the work done from bootstrap shims
101    #[arg(global = true, long)]
102    pub dump_bootstrap_shims: bool,
103    #[arg(global = true, value_hint = clap::ValueHint::Other, long, value_name = "N")]
104    /// stage to build (indicates compiler to use/test, e.g., stage 0 uses the
105    /// bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)
106    pub stage: Option<u32>,
107
108    #[arg(global = true, value_hint = clap::ValueHint::Other, long, value_name = "N")]
109    /// stage(s) to keep without recompiling
110    /// (pass multiple times to keep e.g., both stages 0 and 1)
111    pub keep_stage: Vec<u32>,
112    #[arg(global = true, value_hint = clap::ValueHint::Other, long, value_name = "N")]
113    /// stage(s) of the standard library to keep without recompiling
114    /// (pass multiple times to keep e.g., both stages 0 and 1)
115    pub keep_stage_std: Vec<u32>,
116    #[arg(global = true, long, value_hint = clap::ValueHint::DirPath, value_name = "DIR")]
117    /// path to the root of the rust checkout
118    pub src: Option<PathBuf>,
119
120    #[arg(
121        global = true,
122        short,
123        long,
124        value_hint = clap::ValueHint::Other,
125        value_name = "JOBS"
126    )]
127    /// number of jobs to run in parallel
128    pub jobs: Option<u32>,
129    // This overrides the deny-warnings configuration option,
130    // which passes -Dwarnings to the compiler invocations.
131    #[arg(global = true, long)]
132    #[arg(value_enum, default_value_t=Warnings::Default, value_name = "deny|warn")]
133    /// if value is deny, will deny warnings
134    /// if value is warn, will emit warnings
135    /// otherwise, use the default configured behaviour
136    pub warnings: Warnings,
137
138    #[arg(global = true, long)]
139    /// use message-format=json
140    pub json_output: bool,
141    #[arg(global = true, long)]
142    /// only build proc-macros and build scripts (for rust-analyzer)
143    pub compile_time_deps: bool,
144
145    #[arg(global = true, long, value_name = "STYLE")]
146    #[arg(value_enum, default_value_t = Color::Auto)]
147    /// whether to use color in cargo and rustc output
148    pub color: Color,
149
150    #[arg(global = true, long)]
151    /// Bootstrap uses this value to decide whether it should bypass locking the build process.
152    /// This is rarely needed (e.g., compiling the std library for different targets in parallel).
153    ///
154    /// Unless you know exactly what you are doing, you probably don't need this.
155    pub bypass_bootstrap_lock: bool,
156
157    /// generate PGO profile with rustc build
158    #[arg(global = true, value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")]
159    // FIXME: Remove this option at the end of 2026
160    pub rust_profile_generate: Option<PathBuf>,
161    /// use PGO profile for rustc build
162    // FIXME: Remove this option at the end of 2026
163    #[arg(global = true, value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")]
164    pub rust_profile_use: Option<PathBuf>,
165    /// use PGO profile for LLVM build
166    // FIXME: Remove this option at the end of 2026
167    #[arg(global = true, value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")]
168    pub llvm_profile_use: Option<PathBuf>,
169    // LLVM doesn't support a custom location for generating profile
170    // information.
171    //
172    // llvm_out/build/profiles/ is the location this writes to.
173    /// generate PGO profile with llvm built for rustc
174    // FIXME: Remove this option at the end of 2026
175    #[arg(global = true, long)]
176    pub llvm_profile_generate: bool,
177    /// Enable BOLT link flags
178    #[arg(global = true, long)]
179    pub enable_bolt_settings: bool,
180    /// Skip stage0 compiler validation
181    #[arg(global = true, long)]
182    pub skip_stage0_validation: bool,
183    /// Additional reproducible artifacts that should be added to the reproducible artifacts archive.
184    #[arg(global = true, long)]
185    pub reproducible_artifact: Vec<String>,
186    #[arg(global = true)]
187    /// paths for the subcommand
188    pub paths: Vec<PathBuf>,
189    /// override options in bootstrap.toml
190    #[arg(global = true, value_hint = clap::ValueHint::Other, long, value_name = "section.option=value")]
191    pub set: Vec<String>,
192    /// arguments passed to subcommands
193    #[arg(global = true, last(true), value_name = "ARGS")]
194    pub free_args: Vec<String>,
195    /// Make bootstrap to behave as it's running on the CI environment or not.
196    #[arg(global = true, long, value_name = "bool")]
197    pub ci: Option<bool>,
198    /// Skip checking the standard library if `rust.download-rustc` isn't available.
199    /// This is mostly for RA as building the stage1 compiler to check the library tree
200    /// on each code change might be too much for some computers.
201    #[arg(global = true, long)]
202    pub skip_std_check_if_no_download_rustc: bool,
203}
204
205impl Flags {
206    /// Check if `<cmd> -h -v` was passed.
207    /// If yes, print the available paths and return `true`.
208    pub fn try_parse_verbose_help(args: &[String]) -> bool {
209        // We need to check for `<cmd> -h -v`, in which case we list the paths
210        #[derive(Parser)]
211        #[command(disable_help_flag(true))]
212        struct HelpVerboseOnly {
213            #[arg(short, long)]
214            help: bool,
215            #[arg(global = true, short, long, action = clap::ArgAction::Count)]
216            pub verbose: u8,
217            #[arg(value_enum)]
218            cmd: Kind,
219        }
220        if let Ok(HelpVerboseOnly { help: true, verbose: 1.., cmd: subcommand }) =
221            HelpVerboseOnly::try_parse_from(normalize_args(args))
222        {
223            println!("NOTE: updating submodules before printing available paths");
224            let flags = Self::parse(&[String::from("build")]);
225            let config = Config::parse(flags);
226            let sess = Session::new(config);
227            let paths = Builder::get_help(&sess, subcommand);
228            if let Some(s) = paths {
229                println!("{s}");
230            } else {
231                panic!("No paths available for subcommand `{}`", subcommand.as_str());
232            }
233            true
234        } else {
235            false
236        }
237    }
238
239    #[cfg_attr(
240        feature = "tracing",
241        instrument(level = "trace", name = "Flags::parse", skip_all, fields(args = ?args))
242    )]
243    pub fn parse(args: &[String]) -> Self {
244        Flags::parse_from(normalize_args(args))
245    }
246}
247
248fn normalize_args(args: &[String]) -> Vec<String> {
249    let first = String::from("x.py");
250    let it = std::iter::once(first).chain(args.iter().cloned());
251    it.collect()
252}
253
254#[derive(Debug, Clone, clap::Subcommand)]
255pub enum Subcommand {
256    #[command(visible_aliases = ["b"], long_about = "\n
257    Arguments:
258        This subcommand accepts a number of paths to directories to the crates
259        and/or artifacts to compile. For example, for a quick build of a usable
260        compiler:
261            ./x.py build --stage 1 library/std
262        This will build a compiler and standard library from the local source code.
263        Once this is done, build/$ARCH/stage1 contains a usable compiler.
264        If no arguments are passed then the default artifacts for that stage are
265        compiled. For example:
266            ./x.py build --stage 0
267            ./x.py build ")]
268    /// Compile either the compiler or libraries
269    Build {
270        #[arg(long)]
271        /// Pass `--timings` to Cargo to get crate build timings
272        timings: bool,
273    },
274    #[command(visible_aliases = ["c"], long_about = "\n
275    Arguments:
276        This subcommand accepts a number of paths to directories to the crates
277        and/or artifacts to compile. For example:
278            ./x.py check library/std
279        If no arguments are passed then many artifacts are checked.")]
280    /// Compile either the compiler or libraries, using cargo check
281    Check {
282        #[arg(long)]
283        /// Check all targets
284        all_targets: bool,
285        #[arg(long)]
286        /// Pass `--timings` to Cargo to get crate build timings
287        timings: bool,
288    },
289    /// Run Clippy (uses rustup/cargo-installed clippy binary)
290    #[command(long_about = "\n
291    Arguments:
292        This subcommand accepts a number of paths to directories to the crates
293        and/or artifacts to run clippy against. For example:
294            ./x.py clippy library/core
295            ./x.py clippy library/core library/proc_macro")]
296    Clippy {
297        #[arg(long)]
298        fix: bool,
299        #[arg(long, requires = "fix")]
300        allow_dirty: bool,
301        #[arg(long, requires = "fix")]
302        allow_staged: bool,
303        /// clippy lints to allow
304        #[arg(global = true, short = 'A', action = clap::ArgAction::Append, value_name = "LINT")]
305        allow: Vec<String>,
306        /// clippy lints to deny
307        #[arg(global = true, short = 'D', action = clap::ArgAction::Append, value_name = "LINT")]
308        deny: Vec<String>,
309        /// clippy lints to warn on
310        #[arg(global = true, short = 'W', action = clap::ArgAction::Append, value_name = "LINT")]
311        warn: Vec<String>,
312        /// clippy lints to forbid
313        #[arg(global = true, short = 'F', action = clap::ArgAction::Append, value_name = "LINT")]
314        forbid: Vec<String>,
315    },
316
317    /// Run cargo fix
318    #[command(long_about = "\n
319    Arguments:
320        This subcommand accepts a number of paths to directories to the crates
321        and/or artifacts to run `cargo fix` against. For example:
322            ./x.py fix library/core
323            ./x.py fix library/core library/proc_macro")]
324    Fix {
325        /// Pass `--allow-dirty` to `cargo fix`, allowing it to run even if the
326        /// current git checkout has uncommitted changes.
327        #[arg(long)]
328        allow_dirty: bool,
329    },
330
331    /// Run rustfmt
332    #[command(
333        name = "fmt",
334        long_about = "\n
335    Arguments:
336        This subcommand optionally accepts a `--check` flag which succeeds if
337        formatting is correct and fails if it is not. For example:
338            ./x.py fmt
339            ./x.py fmt --check"
340    )]
341    Format {
342        /// check formatting instead of applying
343        #[arg(long)]
344        check: bool,
345
346        /// apply to all appropriate files, not just those that have been modified
347        #[arg(long)]
348        all: bool,
349    },
350    #[command(visible_aliases = ["d"], long_about = "\n
351    Arguments:
352        This subcommand accepts a number of paths to directories of documentation
353        to build. For example:
354            ./x.py doc src/doc/book
355            ./x.py doc src/doc/nomicon
356            ./x.py doc src/doc/book library/std
357            ./x.py doc library/std --json
358            ./x.py doc library/std --open
359        If no arguments are passed then everything is documented:
360            ./x.py doc
361            ./x.py doc --stage 1")]
362    /// Build documentation
363    Doc {
364        #[arg(long)]
365        /// open the docs in a browser
366        open: bool,
367        #[arg(long)]
368        /// render the documentation in JSON format in addition to the usual HTML format
369        json: bool,
370    },
371    #[command(visible_aliases = ["t"], long_about = "\n
372    Arguments:
373        This subcommand accepts a number of paths to test directories that
374        should be compiled and run. For example:
375            ./x.py test tests/ui
376            ./x.py test library/std --test-args hash_map
377            ./x.py test library/std --stage 0 --all-targets
378            ./x.py test tests/ui --bless
379            ./x.py test tests/ui --compare-mode next-solver
380        Note that `test tests/* --stage N` does NOT depend on `build compiler/rustc --stage N`;
381        just like `build library/std --stage N` it tests the compiler produced by the previous
382        stage.
383        Execute tool tests with a tool name argument:
384            ./x.py test tidy
385        If no arguments are passed then the complete artifacts for that stage are
386        compiled and tested.
387            ./x.py test
388            ./x.py test --stage 1")]
389    /// Build and run some test suites
390    Test {
391        #[arg(long)]
392        /// run all tests regardless of failure
393        no_fail_fast: bool,
394        #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
395        /// extra arguments to be passed for the test tool being used
396        /// (e.g. libtest, compiletest or rustdoc)
397        test_args: Vec<String>,
398        /// extra options to pass the compiler when running compiletest tests
399        #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
400        compiletest_rustc_args: Vec<String>,
401        #[arg(long)]
402        /// Run all test targets (no doc tests)
403        all_targets: bool,
404        #[arg(long)]
405        /// Only run doc tests
406        doc: bool,
407        /// Only run unit and integration tests
408        #[arg(long)]
409        tests: bool,
410        #[arg(long)]
411        /// whether to automatically update stderr/stdout files
412        bless: bool,
413        #[arg(long)]
414        /// comma-separated list of other files types to check (accepts py, py:lint,
415        /// py:fmt, shell, cpp, cpp:fmt, js, js:lint, js:typecheck, spellcheck)
416        ///
417        /// Any argument can be prefixed with "auto:" to only run if
418        /// relevant files are modified (eg. "auto:py").
419        extra_checks: Option<String>,
420        #[arg(long)]
421        /// rerun tests even if the inputs are unchanged
422        force_rerun: bool,
423        #[arg(long)]
424        /// only run tests that result has been changed
425        only_modified: bool,
426        #[arg(long, value_name = "COMPARE MODE")]
427        /// mode describing what file the actual ui output will be compared to
428        compare_mode: Option<String>,
429        #[arg(long, value_name = "check | build | run")]
430        /// force {check,build,run}-pass tests to this mode.
431        pass: Option<String>,
432        #[arg(long, value_name = "auto | always | never")]
433        /// whether to execute run-* tests
434        run: Option<String>,
435        #[arg(long)]
436        /// enable this to generate a Rustfix coverage file, which is saved in
437        /// `/<build_base>/rustfix_missing_coverage.txt`
438        rustfix_coverage: bool,
439        #[arg(long)]
440        /// don't capture stdout/stderr of tests
441        no_capture: bool,
442        #[arg(long, default_value_t = true, action = clap::ArgAction::Set, default_missing_value = "true", num_args = 0..=1, require_equals = true)]
443        /// whether to show verbose subprocess output for run-make tests;
444        /// set to false to suppress output for passing tests (e.g. for cg_clif with --no-capture)
445        verbose_run_make_subprocess_output: bool,
446        #[arg(long)]
447        /// Use a different codegen backend when running tests.
448        test_codegen_backend: Option<CodegenBackendKind>,
449        #[arg(long)]
450        /// Ignore `//@ ignore-backends` directives.
451        bypass_ignore_backends: bool,
452
453        /// Deprecated. Use `--all-targets` or `--tests` instead.
454        #[arg(long)]
455        #[doc(hidden)]
456        no_doc: bool,
457
458        /// Record all the failed tests in a file in the build directory.
459        ///
460        /// On subsequent invocations, this set of tests can be rerun by passing `--rerun`
461        #[arg(long)]
462        record: bool,
463        /// Rerun tests that previously failed, and stored with `--record`.
464        #[arg(long)]
465        rerun: bool,
466    },
467    /// Build and run some test suites *in Miri*
468    Miri {
469        #[arg(long)]
470        /// run all tests regardless of failure
471        no_fail_fast: bool,
472        #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
473        /// extra arguments to be passed for the test tool being used
474        /// (e.g. libtest, compiletest or rustdoc)
475        test_args: Vec<String>,
476        #[arg(long)]
477        /// Run all test targets (no doc tests)
478        all_targets: bool,
479        #[arg(long)]
480        /// Only run doc tests
481        doc: bool,
482        /// Only run unit and integration tests
483        #[arg(long)]
484        tests: bool,
485
486        /// Deprecated. Use `--all-targets` or `--tests` instead.
487        #[arg(long)]
488        #[doc(hidden)]
489        no_doc: bool,
490    },
491    /// Build and run some benchmarks
492    Bench {
493        #[arg(long, allow_hyphen_values(true))]
494        test_args: Vec<String>,
495    },
496    /// Clean out build directories
497    Clean {
498        #[arg(long)]
499        /// Clean the entire build directory (not used by default)
500        all: bool,
501        #[arg(long, value_name = "N")]
502        /// Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used.
503        stage: Option<u32>,
504    },
505    /// Build distribution artifacts
506    Dist,
507    /// Install distribution artifacts
508    Install,
509    #[command(visible_aliases = ["r"], long_about = "\n
510    Arguments:
511        This subcommand accepts a number of paths to tools to build and run. For
512        example:
513            ./x.py run src/tools/bump-stage0
514        At least a tool needs to be called.")]
515    /// Run tools contained in this repository
516    Run {
517        /// arguments for the tool
518        #[arg(long, allow_hyphen_values(true))]
519        args: Vec<String>,
520    },
521    /// Set up the environment for development
522    #[command(long_about = format!(
523        "\n
524x.py setup creates a `bootstrap.toml` which changes the defaults for x.py itself,
525as well as setting up a git pre-push hook, VS Code config and toolchain link.
526Arguments:
527    This subcommand accepts a 'profile' to use for builds. For example:
528        ./x.py setup library
529    The profile is optional and you will be prompted interactively if it is not given.
530    The following profiles are available:
531{}
532    To only set up the git hook, editor config or toolchain link, you may use
533        ./x.py setup hook
534        ./x.py setup editor
535        ./x.py setup link", Profile::all_for_help("        ").trim_end()))]
536    Setup {
537        /// Either the profile for `bootstrap.toml` or another setup action.
538        /// May be omitted to set up interactively
539        #[arg(value_name = "<PROFILE>|hook|editor|link")]
540        profile: Option<PathBuf>,
541    },
542    /// Vendor dependencies
543    Vendor {
544        /// Additional `Cargo.toml` to sync and vendor
545        #[arg(long)]
546        sync: Vec<PathBuf>,
547        /// Always include version in subdir name
548        #[arg(long)]
549        versioned_dirs: bool,
550    },
551    /// Perform profiling and benchmarking of the compiler using `rustc-perf`.
552    Perf(PerfArgs),
553}
554
555impl Default for Subcommand {
556    fn default() -> Self {
557        Subcommand::Build { timings: false }
558    }
559}
560
561impl Subcommand {
562    pub fn compiletest_rustc_args(&self) -> Vec<&str> {
563        match *self {
564            Subcommand::Test { ref compiletest_rustc_args, .. } => {
565                compiletest_rustc_args.iter().flat_map(|s| s.split_whitespace()).collect()
566            }
567            _ => vec![],
568        }
569    }
570
571    pub fn fail_fast(&self) -> bool {
572        match *self {
573            Subcommand::Test { no_fail_fast, .. } | Subcommand::Miri { no_fail_fast, .. } => {
574                !no_fail_fast
575            }
576            _ => false,
577        }
578    }
579
580    pub fn test_target(&self) -> TestTarget {
581        match *self {
582            Subcommand::Test { mut all_targets, doc, tests, no_doc, .. }
583            | Subcommand::Miri { mut all_targets, doc, tests, no_doc, .. } => {
584                // for backwards compatibility --no-doc keeps working
585                all_targets = all_targets || no_doc;
586
587                match (all_targets, doc, tests) {
588                    (true, true, _) | (true, _, true) | (_, true, true) => {
589                        panic!("You can only set one of `--all-targets`, `--doc` and `--tests`.")
590                    }
591                    (true, false, false) => TestTarget::AllTargets,
592                    (false, true, false) => TestTarget::DocOnly,
593                    (false, false, true) => TestTarget::Tests,
594                    (false, false, false) => TestTarget::Default,
595                }
596            }
597            _ => TestTarget::Default,
598        }
599    }
600
601    pub fn no_doc(&self) -> bool {
602        match *self {
603            Subcommand::Test { no_doc, .. } | Subcommand::Miri { no_doc, .. } => no_doc,
604            _ => false,
605        }
606    }
607
608    pub fn bless(&self) -> bool {
609        match *self {
610            Subcommand::Test { bless, .. } => bless,
611            _ => false,
612        }
613    }
614
615    pub fn extra_checks(&self) -> Option<&str> {
616        match *self {
617            Subcommand::Test { ref extra_checks, .. } => extra_checks.as_ref().map(String::as_str),
618            _ => None,
619        }
620    }
621
622    pub fn only_modified(&self) -> bool {
623        match *self {
624            Subcommand::Test { only_modified, .. } => only_modified,
625            _ => false,
626        }
627    }
628
629    pub fn force_rerun(&self) -> bool {
630        match *self {
631            Subcommand::Test { force_rerun, .. } => force_rerun,
632            _ => false,
633        }
634    }
635
636    pub fn no_capture(&self) -> bool {
637        match *self {
638            Subcommand::Test { no_capture, .. } => no_capture,
639            _ => false,
640        }
641    }
642
643    pub fn verbose_run_make_subprocess_output(&self) -> bool {
644        match *self {
645            Subcommand::Test { verbose_run_make_subprocess_output, .. } => {
646                verbose_run_make_subprocess_output
647            }
648            _ => true,
649        }
650    }
651
652    pub fn rustfix_coverage(&self) -> bool {
653        match *self {
654            Subcommand::Test { rustfix_coverage, .. } => rustfix_coverage,
655            _ => false,
656        }
657    }
658
659    pub fn compare_mode(&self) -> Option<&str> {
660        match *self {
661            Subcommand::Test { ref compare_mode, .. } => compare_mode.as_ref().map(|s| &s[..]),
662            _ => None,
663        }
664    }
665
666    pub fn pass(&self) -> Option<&str> {
667        match *self {
668            Subcommand::Test { ref pass, .. } => pass.as_ref().map(|s| &s[..]),
669            _ => None,
670        }
671    }
672
673    pub fn run(&self) -> Option<&str> {
674        match *self {
675            Subcommand::Test { ref run, .. } => run.as_ref().map(|s| &s[..]),
676            _ => None,
677        }
678    }
679
680    pub fn open(&self) -> bool {
681        match *self {
682            Subcommand::Doc { open, .. } => open,
683            _ => false,
684        }
685    }
686
687    pub fn json(&self) -> bool {
688        match *self {
689            Subcommand::Doc { json, .. } => json,
690            _ => false,
691        }
692    }
693
694    pub fn timings(&self) -> bool {
695        match *self {
696            Subcommand::Build { timings, .. } | Subcommand::Check { timings, .. } => timings,
697            _ => false,
698        }
699    }
700
701    pub fn vendor_versioned_dirs(&self) -> bool {
702        match *self {
703            Subcommand::Vendor { versioned_dirs, .. } => versioned_dirs,
704            _ => false,
705        }
706    }
707
708    pub fn vendor_sync_args(&self) -> Vec<PathBuf> {
709        match self {
710            Subcommand::Vendor { sync, .. } => sync.clone(),
711            _ => vec![],
712        }
713    }
714
715    pub fn test_codegen_backend(&self) -> Option<&CodegenBackendKind> {
716        match self {
717            Subcommand::Test { test_codegen_backend, .. } => test_codegen_backend.as_ref(),
718            _ => None,
719        }
720    }
721
722    pub fn bypass_ignore_backends(&self) -> bool {
723        match self {
724            Subcommand::Test { bypass_ignore_backends, .. } => *bypass_ignore_backends,
725            _ => false,
726        }
727    }
728
729    pub fn record(&self) -> bool {
730        match self {
731            Subcommand::Test { record, .. } => *record,
732            _ => false,
733        }
734    }
735
736    pub fn rerun(&self) -> bool {
737        match self {
738            Subcommand::Test { rerun, .. } => *rerun,
739            _ => false,
740        }
741    }
742}
743
744/// Returns the shell completion for a given shell, if the result differs from the current
745/// content of `path`. If `path` does not exist, always returns `Some`.
746pub fn get_completion(shell: &dyn Generator, path: &Path) -> Option<String> {
747    let mut cmd = Flags::command();
748    let current = if !path.exists() {
749        String::new()
750    } else {
751        std::fs::read_to_string(path).unwrap_or_else(|_| {
752            eprintln!("couldn't read {}", path.display());
753            helpers::exit_process(1);
754        })
755    };
756    let mut buf = Vec::new();
757    let (bin_name, _) = path
758        .file_name()
759        .expect("path should be a regular file")
760        .to_str()
761        .expect("file name should be UTF-8")
762        .rsplit_once('.')
763        .expect("file name should have an extension");
764
765    // We sort of replicate `clap_complete::generate` here, because we want to call it with
766    // `&dyn Generator`, but that function requires `G: Generator` instead.
767    cmd.set_bin_name(bin_name);
768    cmd.build();
769    shell.generate(&cmd, &mut buf);
770    if buf == current.as_bytes() {
771        return None;
772    }
773    Some(String::from_utf8(buf).expect("completion script should be UTF-8"))
774}
775
776/// Return the top level help of the bootstrap.
777pub fn top_level_help() -> String {
778    let mut cmd = Flags::command();
779    cmd.render_help().to_string()
780}