diff --git a/Cargo.lock b/Cargo.lock index 86f6da87..53d1af09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -166,6 +166,7 @@ dependencies = [ "cargo_metadata", "clap", "clap_complete", + "color-print", "console", "cp_r", "ctrlc", @@ -193,7 +194,7 @@ dependencies = [ "similar", "strum", "subprocess", - "syn", + "syn 2.0.48", "tempfile", "time", "toml", @@ -297,7 +298,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -306,6 +307,27 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +[[package]] +name = "color-print" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a858372ff14bab9b1b30ea504f2a4bc534582aee3e42ba2d41d2a7baba63d5d" +dependencies = [ + "color-print-proc-macro", +] + +[[package]] +name = "color-print-proc-macro" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e37866456a721d0a404439a1adae37a31be4e0055590d053dfe6981e05003f" +dependencies = [ + "nom", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "colorchoice" version = "1.0.0" @@ -1002,7 +1024,7 @@ checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -1071,7 +1093,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn", + "syn 2.0.48", ] [[package]] @@ -1084,6 +1106,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.48" @@ -1151,7 +1184,7 @@ checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -1258,7 +1291,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.48", ] [[package]] @@ -1360,7 +1393,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.48", "wasm-bindgen-shared", ] @@ -1382,7 +1415,7 @@ checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.48", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 340b0db6..97955ed5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ clap = { version = "4.4", features = [ "wrap_help", ] } clap_complete = "4" +color-print = "0.3" console = "0.15" ctrlc = { version = "3.2.1", features = ["termination"] } fastrand = "2" diff --git a/src/main.rs b/src/main.rs index edfe6938..73c6b0ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,6 +42,7 @@ use clap::builder::styling::{self}; use clap::builder::Styles; use clap::{ArgAction, CommandFactory, Parser, ValueEnum}; use clap_complete::{generate, Shell}; +use color_print::cstr; use tracing::debug; use crate::build_dir::BuildDir; @@ -65,6 +66,8 @@ const NAME: &str = env!("CARGO_PKG_NAME"); /// A comment marker inserted next to changes, so they can be easily found. static MUTATION_MARKER_COMMENT: &str = "/* ~ changed by cargo-mutants ~ */"; +static SPONSOR_MESSAGE: &str = cstr!("Support and accelerate cargo-mutants at <>"); + #[mutants::skip] // only visual effects, not worth testing fn clap_styles() -> Styles { styling::Styles::styled() @@ -95,39 +98,48 @@ pub enum BaselineStrategy { /// /// See for more information. #[derive(Parser, PartialEq, Debug)] -#[command(author, about)] +#[command( + author, + about, + after_help = SPONSOR_MESSAGE, +)] struct Args { /// show cargo output for all invocations (very verbose). - #[arg(long)] + #[arg(long, help_heading = "Output")] all_logs: bool, /// baseline strategy: check that tests pass in an unmutated tree before testing mutants. - #[arg(long, value_enum, default_value_t = BaselineStrategy::Run)] + #[arg(long, value_enum, default_value_t = BaselineStrategy::Run, help_heading = "Execution")] baseline: BaselineStrategy, /// print mutants that were caught by tests. - #[arg(long, short = 'v')] + #[arg(long, short = 'v', help_heading = "Output")] caught: bool, /// cargo check generated mutants, but don't run tests. - #[arg(long)] + #[arg(long, help_heading = "Execution")] check: bool, - /// generate autocompletions for the given shell. - #[arg(long)] - completions: Option, - /// show the mutation diffs. - #[arg(long)] + #[arg(long, help_heading = "Filters")] diff: bool, /// rust crate directory to examine. - #[arg(long, short = 'd', conflicts_with = "manifest_path")] + #[arg( + long, + short = 'd', + conflicts_with = "manifest_path", + help_heading = "Input" + )] dir: Option, + /// generate autocompletions for the given shell. + #[arg(long)] + completions: Option, + /// return this error values from functions returning Result: /// for example, `::anyhow::anyhow!("mutated")`. - #[arg(long)] + #[arg(long, help_heading = "Generate")] error: Vec, /// regex for mutations to examine, matched against the names shown by `--list`. @@ -136,38 +148,44 @@ struct Args { short = 'F', alias = "regex", alias = "examine-regex", - alias = "examine-re" + alias = "examine-re", + help_heading = "Filters" )] examine_re: Vec, /// glob for files to exclude; with no glob, all files are included; globs containing /// slash match the entire path. If used together with `--file` argument, then the files to be examined are matched before the files to be excluded. - #[arg(long, short = 'e')] + #[arg(long, short = 'e', help_heading = "Filters")] exclude: Vec, /// regex for mutations to exclude, matched against the names shown by `--list`. - #[arg(long, short = 'E', alias = "exclude-regex")] + #[arg(long, short = 'E', alias = "exclude-regex", help_heading = "Filters")] exclude_re: Vec, /// glob for files to examine; with no glob, all files are examined; globs containing /// slash match the entire path. If used together with `--exclude` argument, then the files to be examined are matched before the files to be excluded. - #[arg(long, short = 'f')] + #[arg(long, short = 'f', help_heading = "Filters")] file: Vec, /// don't copy files matching gitignore patterns. - #[arg(long, action = ArgAction::Set, default_value = "true")] + #[arg(long, action = ArgAction::Set, default_value = "true", help_heading = "Copying")] gitignore: bool, /// run this many cargo build/test jobs in parallel. - #[arg(long, short = 'j', env = "CARGO_MUTANTS_JOBS")] + #[arg( + long, + short = 'j', + env = "CARGO_MUTANTS_JOBS", + help_heading = "Execution" + )] jobs: Option, /// output json (only for --list). - #[arg(long)] + #[arg(long, help_heading = "Output")] json: bool, /// don't delete the scratch directories, for debugging. - #[arg(long)] + #[arg(long, help_heading = "Debug")] leak_dirs: bool, /// log level for stdout (trace, debug, info, warn, error). @@ -175,76 +193,81 @@ struct Args { long, short = 'L', default_value = "info", - env = "CARGO_MUTANTS_TRACE_LEVEL" + env = "CARGO_MUTANTS_TRACE_LEVEL", + help_heading = "Debug" )] level: tracing::Level, /// just list possible mutants, don't run them. - #[arg(long)] + #[arg(long, help_heading = "Execution")] list: bool, /// list source files, don't run anything. - #[arg(long)] + #[arg(long, help_heading = "Execution")] list_files: bool, /// path to Cargo.toml for the package to mutate. - #[arg(long)] + #[arg(long, help_heading = "Input")] manifest_path: Option, /// don't read .cargo/mutants.toml. - #[arg(long)] + #[arg(long, help_heading = "Input")] no_config: bool, /// don't copy the /target directory, and don't build the source tree first. - #[arg(long)] + #[arg(long, help_heading = "Copying")] no_copy_target: bool, /// don't print times or tree sizes, to make output deterministic. - #[arg(long)] + #[arg(long, help_heading = "Output")] no_times: bool, /// include line & column numbers in the mutation list. - #[arg(long, action = ArgAction::Set, default_value = "true")] + #[arg(long, action = ArgAction::Set, default_value = "true", help_heading = "Output")] line_col: bool, /// create mutants.out within this directory. - #[arg(long, short = 'o')] + #[arg(long, short = 'o', help_heading = "Output")] output: Option, /// include only mutants in code touched by this diff. - #[arg(long, short = 'D')] + #[arg(long, short = 'D', help_heading = "Filters")] in_diff: Option, /// minimum timeout for tests, in seconds, as a lower bound on the auto-set time. - #[arg(long, env = "CARGO_MUTANTS_MINIMUM_TEST_TIMEOUT")] + #[arg( + long, + env = "CARGO_MUTANTS_MINIMUM_TEST_TIMEOUT", + help_heading = "Execution" + )] minimum_test_timeout: Option, /// only test mutants from these packages. - #[arg(id = "package", long, short = 'p')] + #[arg(id = "package", long, short = 'p', help_heading = "Filters")] mutate_packages: Vec, /// run mutants in random order. - #[arg(long)] + #[arg(long, help_heading = "Execution")] shuffle: bool, /// run mutants in the fixed order they occur in the source tree. - #[arg(long)] + #[arg(long, help_heading = "Execution")] no_shuffle: bool, /// run only one shard of all generated mutants: specify as e.g. 1/4. - #[arg(long)] + #[arg(long, help_heading = "Execution")] shard: Option, /// tool used to run test suites: cargo or nextest. - #[arg(long)] + #[arg(long, help_heading = "Execution")] test_tool: Option, /// maximum run time for all cargo commands, in seconds. - #[arg(long, short = 't')] + #[arg(long, short = 't', help_heading = "Execution")] timeout: Option, /// print mutations that failed to check or build. - #[arg(long, short = 'V')] + #[arg(long, short = 'V', help_heading = "Output")] unviable: bool, /// show version and quit. @@ -252,17 +275,22 @@ struct Args { version: bool, /// test every package in the workspace. - #[arg(long)] + #[arg(long, help_heading = "Filters")] workspace: bool, /// additional args for all cargo invocations. - #[arg(long, short = 'C', allow_hyphen_values = true)] + #[arg( + long, + short = 'C', + allow_hyphen_values = true, + help_heading = "Execution" + )] cargo_arg: Vec, // The following option captures all the remaining non-option args, to // send to cargo. /// pass remaining arguments to cargo test after all options and after `--`. - #[arg(last = true)] + #[arg(last = true, help_heading = "Execution")] cargo_test_args: Vec, }