]> git.proxmox.com Git - rustc.git/blame - src/bootstrap/src/core/config/flags.rs
New upstream version 1.76.0+dfsg1
[rustc.git] / src / bootstrap / src / core / config / flags.rs
CommitLineData
a7813a04
XL
1//! Command-line interface of the rustbuild 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
49aad941 6use std::path::{Path, PathBuf};
7453a54e 7
49aad941 8use clap::{CommandFactory, Parser, ValueEnum};
c30ab7b3 9
ed00b5ec
FG
10use crate::core::build_steps::setup::Profile;
11use crate::core::builder::{Builder, Kind};
12use crate::core::config::{target_selection_list, Config, TargetSelectionList};
0731742a 13use crate::{Build, DocTests};
3b2f2976 14
49aad941 15#[derive(Copy, Clone, Default, Debug, ValueEnum)]
fc512014
XL
16pub enum Color {
17 Always,
18 Never,
49aad941 19 #[default]
fc512014
XL
20 Auto,
21}
22
49aad941
FG
23/// Whether to deny warnings, emit them as warnings, or use the default behavior
24#[derive(Copy, Clone, Default, Debug, ValueEnum)]
25pub enum Warnings {
26 Deny,
27 Warn,
28 #[default]
29 Default,
fc512014
XL
30}
31
a7813a04 32/// Deserialized version of all flags for this compile.
49aad941
FG
33#[derive(Debug, Parser)]
34#[clap(
35 override_usage = "x.py <subcommand> [options] [<paths>...]",
36 disable_help_subcommand(true),
37 about = "",
38 next_line_help(false)
39)]
7453a54e 40pub struct Flags {
49aad941
FG
41 #[command(subcommand)]
42 pub cmd: Subcommand,
3b2f2976 43
49aad941
FG
44 #[arg(global(true), short, long, action = clap::ArgAction::Count)]
45 /// use verbose output (-vv for very verbose)
46 pub verbose: u8, // each extra -v after the first is passed to Cargo
47 #[arg(global(true), short, long)]
48 /// use incremental compilation
49 pub incremental: bool,
50 #[arg(global(true), long, value_hint = clap::ValueHint::FilePath, value_name = "FILE")]
51 /// TOML configuration file for build
7453a54e 52 pub config: Option<PathBuf>,
49aad941
FG
53 #[arg(global(true), long, value_hint = clap::ValueHint::DirPath, value_name = "DIR")]
54 /// Build directory, overrides `build.build-dir` in `config.toml`
064997fb 55 pub build_dir: Option<PathBuf>,
49aad941
FG
56
57 #[arg(global(true), long, value_hint = clap::ValueHint::Other, value_name = "BUILD")]
58 /// build target of the stage0 compiler
59 pub build: Option<String>,
60
61 #[arg(global(true), long, value_hint = clap::ValueHint::Other, value_name = "HOST", value_parser = target_selection_list)]
62 /// host targets to build
63 pub host: Option<TargetSelectionList>,
64
65 #[arg(global(true), long, value_hint = clap::ValueHint::Other, value_name = "TARGET", value_parser = target_selection_list)]
66 /// target targets to build
67 pub target: Option<TargetSelectionList>,
68
69 #[arg(global(true), long, value_name = "PATH")]
70 /// build paths to exclude
add651ee
FG
71 pub exclude: Vec<PathBuf>, // keeping for client backward compatibility
72 #[arg(global(true), long, value_name = "PATH")]
73 /// build paths to skip
74 pub skip: Vec<PathBuf>,
49aad941
FG
75 #[arg(global(true), long)]
76 /// include default paths in addition to the provided ones
1b1a35ee 77 pub include_default_paths: bool,
49aad941
FG
78
79 #[arg(global(true), value_hint = clap::ValueHint::Other, long)]
0531ce1d 80 pub rustc_error_format: Option<String>,
49aad941
FG
81
82 #[arg(global(true), long, value_hint = clap::ValueHint::CommandString, value_name = "CMD")]
83 /// command to run on failure
84 pub on_fail: Option<String>,
85 #[arg(global(true), long)]
86 /// dry run; don't build anything
83c7162d 87 pub dry_run: bool,
4b012472
FG
88 /// Indicates whether to dump the work done from bootstrap shims
89 #[arg(global(true), long)]
90 pub dump_bootstrap_shims: bool,
49aad941
FG
91 #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "N")]
92 /// stage to build (indicates compiler to use/test, e.g., stage 0 uses the
93 /// bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)
94 pub stage: Option<u32>,
83c7162d 95
49aad941
FG
96 #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "N")]
97 /// stage(s) to keep without recompiling
98 /// (pass multiple times to keep e.g., both stages 0 and 1)
99 pub keep_stage: Vec<u32>,
100 #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "N")]
101 /// stage(s) of the standard library to keep without recompiling
102 /// (pass multiple times to keep e.g., both stages 0 and 1)
103 pub keep_stage_std: Vec<u32>,
104 #[arg(global(true), long, value_hint = clap::ValueHint::DirPath, value_name = "DIR")]
105 /// path to the root of the rust checkout
106 pub src: Option<PathBuf>,
107
108 #[arg(
109 global(true),
110 short,
111 long,
112 value_hint = clap::ValueHint::Other,
113 default_value_t = std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get),
114 value_name = "JOBS"
115 )]
116 /// number of jobs to run in parallel
117 pub jobs: usize,
74b04a01 118 // This overrides the deny-warnings configuration option,
416331ca 119 // which passes -Dwarnings to the compiler invocations.
49aad941
FG
120 #[arg(global(true), long)]
121 #[clap(value_enum, default_value_t=Warnings::Default, value_name = "deny|warn")]
122 /// if value is deny, will deny warnings
123 /// if value is warn, will emit warnings
124 /// otherwise, use the default configured behaviour
125 pub warnings: Warnings,
126
127 #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "FORMAT")]
128 /// rustc error format
129 pub error_format: Option<String>,
130 #[arg(global(true), long)]
131 /// use message-format=json
132 pub json_output: bool,
dfeec247 133
49aad941
FG
134 #[arg(global(true), long, value_name = "STYLE")]
135 #[clap(value_enum, default_value_t = Color::Auto)]
136 /// whether to use color in cargo and rustc output
137 pub color: Color,
94222f64 138
4b012472
FG
139 #[arg(global(true), long)]
140 /// Bootstrap uses this value to decide whether it should bypass locking the build process.
141 /// This is rarely needed (e.g., compiling the std library for different targets in parallel).
142 ///
143 /// Unless you know exactly what you are doing, you probably don't need this.
144 pub bypass_bootstrap_lock: bool,
145
49aad941
FG
146 /// whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml
147 #[arg(global(true), long, value_name = "VALUE")]
148 pub llvm_skip_rebuild: Option<bool>,
149 /// generate PGO profile with rustc build
150 #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")]
151 pub rust_profile_generate: Option<String>,
152 /// use PGO profile for rustc build
153 #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")]
154 pub rust_profile_use: Option<String>,
155 /// use PGO profile for LLVM build
156 #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")]
94222f64
XL
157 pub llvm_profile_use: Option<String>,
158 // LLVM doesn't support a custom location for generating profile
159 // information.
160 //
161 // llvm_out/build/profiles/ is the location this writes to.
49aad941
FG
162 /// generate PGO profile with llvm built for rustc
163 #[arg(global(true), long)]
94222f64 164 pub llvm_profile_generate: bool,
ed00b5ec
FG
165 /// Enable BOLT link flags
166 #[arg(global(true), long)]
167 pub enable_bolt_settings: bool,
168 /// Skip stage0 compiler validation
169 #[arg(global(true), long)]
170 pub skip_stage0_validation: bool,
add651ee 171 /// Additional reproducible artifacts that should be added to the reproducible artifacts archive.
49aad941 172 #[arg(global(true), long)]
add651ee 173 pub reproducible_artifact: Vec<String>,
49aad941
FG
174 #[arg(global(true))]
175 /// paths for the subcommand
176 pub paths: Vec<PathBuf>,
177 /// override options in config.toml
178 #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "section.option=value")]
179 pub set: Vec<String>,
180 /// arguments passed to subcommands
181 #[arg(global(true), last(true), value_name = "ARGS")]
182 pub free_args: Vec<String>,
183}
184
185impl Flags {
186 pub fn parse(args: &[String]) -> Self {
187 let first = String::from("x.py");
188 let it = std::iter::once(&first).chain(args.iter());
189 // We need to check for `<cmd> -h -v`, in which case we list the paths
190 #[derive(Parser)]
191 #[clap(disable_help_flag(true))]
192 struct HelpVerboseOnly {
193 #[arg(short, long)]
194 help: bool,
195 #[arg(global(true), short, long, action = clap::ArgAction::Count)]
196 pub verbose: u8,
197 #[arg(value_enum)]
198 cmd: Kind,
199 }
200 if let Ok(HelpVerboseOnly { help: true, verbose: 1.., cmd: subcommand }) =
201 HelpVerboseOnly::try_parse_from(it.clone())
202 {
ed00b5ec 203 println!("NOTE: updating submodules before printing available paths");
49aad941
FG
204 let config = Config::parse(&[String::from("build")]);
205 let build = Build::new(config);
206 let paths = Builder::get_help(&build, subcommand);
207 if let Some(s) = paths {
add651ee 208 println!("{s}");
49aad941
FG
209 } else {
210 panic!("No paths available for subcommand `{}`", subcommand.as_str());
211 }
add651ee 212 crate::exit!(0);
49aad941 213 }
9ffffee4 214
49aad941
FG
215 Flags::parse_from(it)
216 }
32a655c1
SL
217}
218
49aad941 219#[derive(Debug, Clone, Default, clap::Subcommand)]
c30ab7b3 220pub enum Subcommand {
49aad941
FG
221 #[clap(aliases = ["b"], long_about = "\n
222 Arguments:
223 This subcommand accepts a number of paths to directories to the crates
224 and/or artifacts to compile. For example, for a quick build of a usable
225 compiler:
226 ./x.py build --stage 1 library/std
227 This will build a compiler and standard library from the local source code.
228 Once this is done, build/$ARCH/stage1 contains a usable compiler.
229 If no arguments are passed then the default artifacts for that stage are
230 compiled. For example:
231 ./x.py build --stage 0
232 ./x.py build ")]
233 /// Compile either the compiler or libraries
234 #[default]
235 Build,
236 #[clap(aliases = ["c"], long_about = "\n
237 Arguments:
238 This subcommand accepts a number of paths to directories to the crates
239 and/or artifacts to compile. For example:
240 ./x.py check library/std
241 If no arguments are passed then many artifacts are checked.")]
242 /// Compile either the compiler or libraries, using cargo check
2c00a5a8 243 Check {
49aad941
FG
244 #[arg(long)]
245 /// Check all targets
246 all_targets: bool,
2c00a5a8 247 },
49aad941
FG
248 /// Run Clippy (uses rustup/cargo-installed clippy binary)
249 #[clap(long_about = "\n
250 Arguments:
251 This subcommand accepts a number of paths to directories to the crates
252 and/or artifacts to run clippy against. For example:
253 ./x.py clippy library/core
254 ./x.py clippy library/core library/proc_macro")]
dc9dc135 255 Clippy {
49aad941 256 #[arg(long)]
29967ef6 257 fix: bool,
49aad941
FG
258 /// clippy lints to allow
259 #[arg(global(true), short = 'A', action = clap::ArgAction::Append, value_name = "LINT")]
260 allow: Vec<String>,
261 /// clippy lints to deny
262 #[arg(global(true), short = 'D', action = clap::ArgAction::Append, value_name = "LINT")]
263 deny: Vec<String>,
264 /// clippy lints to warn on
265 #[arg(global(true), short = 'W', action = clap::ArgAction::Append, value_name = "LINT")]
266 warn: Vec<String>,
267 /// clippy lints to forbid
268 #[arg(global(true), short = 'F', action = clap::ArgAction::Append, value_name = "LINT")]
269 forbid: Vec<String>,
dc9dc135 270 },
49aad941
FG
271 /// Run cargo fix
272 #[clap(long_about = "\n
273 Arguments:
274 This subcommand accepts a number of paths to directories to the crates
275 and/or artifacts to run `cargo fix` against. For example:
276 ./x.py fix library/core
277 ./x.py fix library/core library/proc_macro")]
278 Fix,
279 #[clap(
280 name = "fmt",
281 long_about = "\n
282 Arguments:
283 This subcommand optionally accepts a `--check` flag which succeeds if formatting is correct and
284 fails if it is not. For example:
285 ./x.py fmt
286 ./x.py fmt --check"
287 )]
288 /// Run rustfmt
dfeec247 289 Format {
49aad941
FG
290 /// check formatting instead of applying
291 #[arg(long)]
dfeec247
XL
292 check: bool,
293 },
49aad941
FG
294 #[clap(aliases = ["d"], long_about = "\n
295 Arguments:
296 This subcommand accepts a number of paths to directories of documentation
297 to build. For example:
298 ./x.py doc src/doc/book
299 ./x.py doc src/doc/nomicon
300 ./x.py doc src/doc/book library/std
301 ./x.py doc library/std --json
302 ./x.py doc library/std --open
303 If no arguments are passed then everything is documented:
304 ./x.py doc
305 ./x.py doc --stage 1")]
306 /// Build documentation
c30ab7b3 307 Doc {
49aad941
FG
308 #[arg(long)]
309 /// open the docs in a browser
f9f354fc 310 open: bool,
49aad941
FG
311 #[arg(long)]
312 /// render the documentation in JSON format in addition to the usual HTML format
2b03887a 313 json: bool,
c30ab7b3 314 },
49aad941
FG
315 #[clap(aliases = ["t"], long_about = "\n
316 Arguments:
317 This subcommand accepts a number of paths to test directories that
318 should be compiled and run. For example:
319 ./x.py test tests/ui
320 ./x.py test library/std --test-args hash_map
321 ./x.py test library/std --stage 0 --no-doc
322 ./x.py test tests/ui --bless
fe692bf9 323 ./x.py test tests/ui --compare-mode next-solver
49aad941
FG
324 Note that `test tests/* --stage N` does NOT depend on `build compiler/rustc --stage N`;
325 just like `build library/std --stage N` it tests the compiler produced by the previous
326 stage.
327 Execute tool tests with a tool name argument:
328 ./x.py test tidy
329 If no arguments are passed then the complete artifacts for that stage are
330 compiled and tested.
331 ./x.py test
332 ./x.py test --stage 1")]
333 /// Build and run some test suites
c30ab7b3 334 Test {
49aad941
FG
335 #[arg(long)]
336 /// run all tests regardless of failure
337 no_fail_fast: bool,
338 #[arg(long, value_name = "SUBSTRING")]
339 /// skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times
add651ee 340 skip: Vec<PathBuf>,
49aad941
FG
341 #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
342 /// extra arguments to be passed for the test tool being used
343 /// (e.g. libtest, compiletest or rustdoc)
344 test_args: Vec<String>,
345 /// extra options to pass the compiler when running tests
346 #[arg(long, value_name = "ARGS", allow_hyphen_values(true))]
347 rustc_args: Vec<String>,
348 #[arg(long)]
349 /// do not run doc tests
350 no_doc: bool,
351 #[arg(long)]
352 /// only run doc tests
353 doc: bool,
354 #[arg(long)]
355 /// whether to automatically update stderr/stdout files
94b46f34 356 bless: bool,
49aad941 357 #[arg(long)]
add651ee
FG
358 /// comma-separated list of other files types to check (accepts py, py:lint,
359 /// py:fmt, shell)
360 extra_checks: Option<String>,
361 #[arg(long)]
49aad941 362 /// rerun tests even if the inputs are unchanged
94222f64 363 force_rerun: bool,
49aad941
FG
364 #[arg(long)]
365 /// only run tests that result has been changed
366 only_modified: bool,
367 #[arg(long, value_name = "COMPARE MODE")]
368 /// mode describing what file the actual ui output will be compared to
94b46f34 369 compare_mode: Option<String>,
49aad941
FG
370 #[arg(long, value_name = "check | build | run")]
371 /// force {check,build,run}-pass tests to this mode.
dc9dc135 372 pass: Option<String>,
49aad941
FG
373 #[arg(long, value_name = "auto | always | never")]
374 /// whether to execute run-* tests
17df50a5 375 run: Option<String>,
49aad941
FG
376 #[arg(long)]
377 /// enable this to generate a Rustfix coverage file, which is saved in
378 /// `/<build_base>/rustfix_missing_coverage.txt`
532ac7d7 379 rustfix_coverage: bool,
c30ab7b3 380 },
49aad941 381 /// Build and run some benchmarks
476ff2be 382 Bench {
49aad941 383 #[arg(long, allow_hyphen_values(true))]
476ff2be
SL
384 test_args: Vec<String>,
385 },
49aad941 386 /// Clean out build directories
ea8adc8c 387 Clean {
49aad941 388 #[arg(long)]
add651ee 389 /// Clean the entire build directory (not used by default)
ea8adc8c 390 all: bool,
add651ee
FG
391 #[arg(long, value_name = "N")]
392 /// Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used.
393 stage: Option<u32>,
ea8adc8c 394 },
49aad941
FG
395 /// Build distribution artifacts
396 Dist,
397 /// Install distribution artifacts
398 Install,
399 #[clap(aliases = ["r"], long_about = "\n
400 Arguments:
401 This subcommand accepts a number of paths to tools to build and run. For
402 example:
403 ./x.py run src/tools/expand-yaml-anchors
404 At least a tool needs to be called.")]
405 /// Run tools contained in this repository
ba9703b0 406 Run {
49aad941
FG
407 /// arguments for the tool
408 #[arg(long, allow_hyphen_values(true))]
487cf647 409 args: Vec<String>,
ba9703b0 410 },
49aad941
FG
411 /// Set up the environment for development
412 #[clap(long_about = format!(
413 "\n
9ffffee4 414x.py setup creates a `config.toml` which changes the defaults for x.py itself,
49aad941 415as well as setting up a git pre-push hook, VS Code config and toolchain link.
1b1a35ee
XL
416Arguments:
417 This subcommand accepts a 'profile' to use for builds. For example:
1b1a35ee 418 ./x.py setup library
29967ef6
XL
419 The profile is optional and you will be prompted interactively if it is not given.
420 The following profiles are available:
9ffffee4 421{}
49aad941 422 To only set up the git hook, VS Code config or toolchain link, you may use
9ffffee4
FG
423 ./x.py setup hook
424 ./x.py setup vscode
49aad941
FG
425 ./x.py setup link", Profile::all_for_help(" ").trim_end()))]
426 Setup {
427 /// Either the profile for `config.toml` or another setup action.
428 /// May be omitted to set up interactively
429 #[arg(value_name = "<PROFILE>|hook|vscode|link")]
430 profile: Option<PathBuf>,
431 },
432 /// Suggest a subset of tests to run, based on modified files
433 #[clap(long_about = "\n")]
434 Suggest {
435 /// run suggested tests
436 #[arg(long)]
437 run: bool,
438 },
7453a54e
SL
439}
440
c30ab7b3 441impl Subcommand {
04454e1e
FG
442 pub fn kind(&self) -> Kind {
443 match self {
444 Subcommand::Bench { .. } => Kind::Bench,
445 Subcommand::Build { .. } => Kind::Build,
446 Subcommand::Check { .. } => Kind::Check,
447 Subcommand::Clippy { .. } => Kind::Clippy,
448 Subcommand::Doc { .. } => Kind::Doc,
449 Subcommand::Fix { .. } => Kind::Fix,
450 Subcommand::Format { .. } => Kind::Format,
451 Subcommand::Test { .. } => Kind::Test,
452 Subcommand::Clean { .. } => Kind::Clean,
453 Subcommand::Dist { .. } => Kind::Dist,
454 Subcommand::Install { .. } => Kind::Install,
455 Subcommand::Run { .. } => Kind::Run,
456 Subcommand::Setup { .. } => Kind::Setup,
353b0b11 457 Subcommand::Suggest { .. } => Kind::Suggest,
04454e1e
FG
458 }
459 }
460
2c00a5a8
XL
461 pub fn rustc_args(&self) -> Vec<&str> {
462 match *self {
dfeec247
XL
463 Subcommand::Test { ref rustc_args, .. } => {
464 rustc_args.iter().flat_map(|s| s.split_whitespace()).collect()
465 }
487cf647
FG
466 _ => vec![],
467 }
468 }
469
041b39d2 470 pub fn fail_fast(&self) -> bool {
7cac9316 471 match *self {
49aad941 472 Subcommand::Test { no_fail_fast, .. } => !no_fail_fast,
7cac9316
XL
473 _ => false,
474 }
475 }
0531ce1d 476
83c7162d 477 pub fn doc_tests(&self) -> DocTests {
0531ce1d 478 match *self {
49aad941
FG
479 Subcommand::Test { doc, no_doc, .. } => {
480 if doc {
481 DocTests::Only
482 } else if no_doc {
483 DocTests::No
484 } else {
485 DocTests::Yes
486 }
487 }
83c7162d 488 _ => DocTests::Yes,
0531ce1d
XL
489 }
490 }
94b46f34
XL
491
492 pub fn bless(&self) -> bool {
493 match *self {
494 Subcommand::Test { bless, .. } => bless,
495 _ => false,
496 }
497 }
498
add651ee
FG
499 pub fn extra_checks(&self) -> Option<&str> {
500 match *self {
501 Subcommand::Test { ref extra_checks, .. } => extra_checks.as_ref().map(String::as_str),
502 _ => None,
503 }
504 }
505
9ffffee4
FG
506 pub fn only_modified(&self) -> bool {
507 match *self {
508 Subcommand::Test { only_modified, .. } => only_modified,
509 _ => false,
510 }
511 }
512
94222f64
XL
513 pub fn force_rerun(&self) -> bool {
514 match *self {
515 Subcommand::Test { force_rerun, .. } => force_rerun,
516 _ => false,
517 }
518 }
519
532ac7d7
XL
520 pub fn rustfix_coverage(&self) -> bool {
521 match *self {
522 Subcommand::Test { rustfix_coverage, .. } => rustfix_coverage,
523 _ => false,
524 }
525 }
526
94b46f34
XL
527 pub fn compare_mode(&self) -> Option<&str> {
528 match *self {
dfeec247 529 Subcommand::Test { ref compare_mode, .. } => compare_mode.as_ref().map(|s| &s[..]),
94b46f34
XL
530 _ => None,
531 }
532 }
dc9dc135
XL
533
534 pub fn pass(&self) -> Option<&str> {
535 match *self {
dfeec247 536 Subcommand::Test { ref pass, .. } => pass.as_ref().map(|s| &s[..]),
dc9dc135
XL
537 _ => None,
538 }
539 }
f9f354fc 540
17df50a5
XL
541 pub fn run(&self) -> Option<&str> {
542 match *self {
543 Subcommand::Test { ref run, .. } => run.as_ref().map(|s| &s[..]),
544 _ => None,
545 }
546 }
547
f9f354fc
XL
548 pub fn open(&self) -> bool {
549 match *self {
550 Subcommand::Doc { open, .. } => open,
551 _ => false,
552 }
553 }
2b03887a
FG
554
555 pub fn json(&self) -> bool {
556 match *self {
557 Subcommand::Doc { json, .. } => json,
558 _ => false,
559 }
560 }
7453a54e 561}
32a655c1 562
49aad941
FG
563/// Returns the shell completion for a given shell, if the result differs from the current
564/// content of `path`. If `path` does not exist, always returns `Some`.
565pub fn get_completion<G: clap_complete::Generator>(shell: G, path: &Path) -> Option<String> {
566 let mut cmd = Flags::command();
567 let current = if !path.exists() {
568 String::new()
569 } else {
570 std::fs::read_to_string(path).unwrap_or_else(|_| {
571 eprintln!("couldn't read {}", path.display());
add651ee 572 crate::exit!(1)
49aad941
FG
573 })
574 };
575 let mut buf = Vec::new();
576 clap_complete::generate(shell, &mut cmd, "x.py", &mut buf);
577 if buf == current.as_bytes() {
578 return None;
416331ca 579 }
49aad941 580 Some(String::from_utf8(buf).expect("completion script should be UTF-8"))
416331ca 581}