Backed out 3 changesets (bug 1836415) for causing wd failures on allow_hosts.py.

Backed out changeset dbbb407831c0 (bug 1836415)
Backed out changeset a1fbb5a4179b (bug 1836415)
Backed out changeset e2d49a57b1c9 (bug 1836415)
This commit is contained in:
Iulian Moraru 2023-06-08 01:27:49 +03:00
Родитель 3c70421790
Коммит 9ed9b5d1c8
350 изменённых файлов: 36435 добавлений и 25737 удалений

75
Cargo.lock сгенерированный
Просмотреть файл

@ -732,45 +732,41 @@ dependencies = [
[[package]]
name = "clap"
version = "4.1.14"
version = "3.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "906f7fe1da4185b7a282b2bc90172a496f9def1aca4545fe7526810741591e14"
dependencies = [
"clap_builder",
"clap_derive",
"once_cell",
]
[[package]]
name = "clap_builder"
version = "4.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "351f9ad9688141ed83dfd8f5fb998a06225ef444b48ff4dc43de6d409b7fd10b"
checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b"
dependencies = [
"bitflags 1.3.2",
"clap_derive",
"clap_lex",
"once_cell",
"indexmap",
"lazy_static",
"strsim",
"terminal_size",
"textwrap",
]
[[package]]
name = "clap_derive"
version = "4.1.14"
version = "3.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81d7dc0031c3a59a04fc2ba395c8e2dd463cba1859275f065d225f6122221b45"
checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.18",
"syn 1.0.107",
]
[[package]]
name = "clap_lex"
version = "0.4.1"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "cmake"
@ -3842,6 +3838,12 @@ dependencies = [
"origin-trial-token",
]
[[package]]
name = "os_str_bytes"
version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
name = "osclientcerts-static"
version = "0.1.4"
@ -4114,6 +4116,30 @@ dependencies = [
"thiserror",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.107",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro-hack"
version = "0.5.20+deprecated"
@ -5111,7 +5137,16 @@ dependencies = [
[[package]]
name = "terminal_size"
version = "0.2.999"
version = "0.1.999"
[[package]]
name = "textwrap"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d"
dependencies = [
"terminal_size",
]
[[package]]
name = "thin-vec"

Просмотреть файл

@ -1,6 +1,6 @@
[package]
name = "terminal_size"
version = "0.2.999"
version = "0.1.999"
edition = "2018"
license = "MIT OR Apache-2.0"

Просмотреть файл

@ -2760,11 +2760,6 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "0.15.0 -> 0.15.2"
[[audits.textwrap]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "0.15.2 -> 0.16.0"
[[audits.thin-vec]]
who = "Aria Beingessner <a.beingessner@gmail.com>"
criteria = "safe-to-deploy"
@ -3693,30 +3688,6 @@ user-id = 6741 # Alice Ryhl (Darksonn)
start = "2021-01-11"
end = "2024-05-05"
[[trusted.clap]]
criteria = "safe-to-deploy"
user-id = 6743 # Ed Page (epage)
start = "2021-12-08"
end = "2024-06-02"
[[trusted.clap_builder]]
criteria = "safe-to-deploy"
user-id = 6743 # Ed Page (epage)
start = "2023-03-28"
end = "2024-06-02"
[[trusted.clap_derive]]
criteria = "safe-to-deploy"
user-id = 6743 # Ed Page (epage)
start = "2021-12-08"
end = "2024-06-02"
[[trusted.clap_lex]]
criteria = "safe-to-deploy"
user-id = 6743 # Ed Page (epage)
start = "2022-04-15"
end = "2024-06-02"
[[trusted.dtoa]]
criteria = "safe-to-deploy"
user-id = 3618 # David Tolnay (dtolnay)

Просмотреть файл

@ -285,6 +285,18 @@ criteria = "safe-to-deploy"
version = "1.3.3"
criteria = "safe-to-deploy"
[[exemptions.clap]]
version = "3.1.18"
criteria = "safe-to-deploy"
[[exemptions.clap_derive]]
version = "3.1.18"
criteria = "safe-to-deploy"
[[exemptions.clap_lex]]
version = "0.2.0"
criteria = "safe-to-deploy"
[[exemptions.cookie]]
version = "0.16.0"
criteria = "safe-to-run"
@ -625,6 +637,10 @@ criteria = "safe-to-deploy"
version = "1.12.0"
criteria = "safe-to-deploy"
[[exemptions.os_str_bytes]]
version = "6.1.0"
criteria = "safe-to-deploy"
[[exemptions.owning_ref]]
version = "0.4.1"
criteria = "safe-to-deploy"
@ -669,6 +685,10 @@ criteria = "safe-to-run"
version = "0.2.16"
criteria = "safe-to-deploy"
[[exemptions.proc-macro-error]]
version = "1.0.4"
criteria = "safe-to-deploy"
[[exemptions.profiling]]
version = "1.0.6"
criteria = "safe-to-deploy"
@ -801,6 +821,10 @@ criteria = "safe-to-deploy"
version = "3.3.0"
criteria = "safe-to-deploy"
[[exemptions.textwrap]]
version = "0.15.0"
criteria = "safe-to-deploy"
[[exemptions.time]]
version = "0.1.44"
criteria = "safe-to-deploy"

Просмотреть файл

@ -71,34 +71,6 @@ user-id = 3788
user-login = "emilio"
user-name = "Emilio Cobos Álvarez"
[[publisher.clap]]
version = "4.1.14"
when = "2023-03-28"
user-id = 6743
user-login = "epage"
user-name = "Ed Page"
[[publisher.clap_builder]]
version = "4.1.14"
when = "2023-03-28"
user-id = 6743
user-login = "epage"
user-name = "Ed Page"
[[publisher.clap_derive]]
version = "4.1.14"
when = "2023-03-28"
user-id = 6743
user-login = "epage"
user-name = "Ed Page"
[[publisher.clap_lex]]
version = "0.4.1"
when = "2023-03-28"
user-id = 6743
user-login = "epage"
user-name = "Ed Page"
[[publisher.core-foundation]]
version = "0.9.3"
when = "2022-02-07"
@ -958,6 +930,12 @@ criteria = "safe-to-run"
version = "1.0.12"
aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT"
[[audits.google.audits.proc-macro-error-attr]]
who = "George Burgess IV <gbiv@google.com>"
criteria = "safe-to-deploy"
version = "1.0.4"
aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT"
[[audits.google.audits.scoped-tls]]
who = "George Burgess IV <gbiv@google.com>"
criteria = "safe-to-run"

Просмотреть файл

@ -23,7 +23,7 @@ repository = "https://hg.mozilla.org/mozilla-central/file/tip/testing/geckodrive
[dependencies]
base64 = "0.21"
chrono = "0.4.6"
clap = { version = "4", default-features = false, features = ["cargo", "std", "suggestions", "wrap_help", "string"] }
clap = { version = "~3.1", default-features = false, features = ["cargo", "std", "suggestions", "wrap_help"] }
hyper = "0.14"
lazy_static = "1.0"
log = { version = "0.4", features = ["std"] }

Просмотреть файл

@ -34,7 +34,7 @@ use std::path::PathBuf;
use std::result;
use std::str::FromStr;
use clap::{Arg, ArgAction, Command};
use clap::{AppSettings, Arg, Command};
macro_rules! try_opt {
($expr:expr, $err_type:expr, $err_msg:expr) => {{
@ -190,7 +190,7 @@ fn parse_hostname(webdriver_host: &str) -> Result<Host, url::ParseError> {
///
/// This only covers domain names, not IP addresses, since IP adresses
/// are always accepted.
fn get_default_allowed_hosts(ip: IpAddr) -> Vec<Host> {
fn get_default_allowed_hosts(ip: IpAddr) -> Vec<Result<Host, url::ParseError>> {
let localhost_is_loopback = ("localhost".to_string(), 80)
.to_socket_addrs()
.map(|addr_iter| {
@ -202,50 +202,61 @@ fn get_default_allowed_hosts(ip: IpAddr) -> Vec<Host> {
.len()
> 0;
if ip.is_loopback() && localhost_is_loopback {
vec![Host::parse("localhost").unwrap()]
vec![Host::parse("localhost")]
} else {
vec![]
}
}
fn get_allowed_hosts(host: Host, allow_hosts: Option<clap::parser::ValuesRef<Host>>) -> Vec<Host> {
fn get_allowed_hosts(
host: Host,
allow_hosts: Option<clap::Values>,
) -> Result<Vec<Host>, url::ParseError> {
allow_hosts
.map(|hosts| hosts.cloned().collect())
.map(|hosts| hosts.map(Host::parse).collect::<Vec<_>>())
.unwrap_or_else(|| match host {
Host::Domain(_) => {
vec![host.clone()]
vec![Ok(host.clone())]
}
Host::Ipv4(ip) => get_default_allowed_hosts(IpAddr::V4(ip)),
Host::Ipv6(ip) => get_default_allowed_hosts(IpAddr::V6(ip)),
})
.into_iter()
.collect::<Result<Vec<Host>, url::ParseError>>()
}
fn get_allowed_origins(allow_origins: Option<clap::parser::ValuesRef<Url>>) -> Vec<Url> {
allow_origins.into_iter().flatten().cloned().collect()
fn get_allowed_origins(allow_origins: Option<clap::Values>) -> Result<Vec<Url>, url::ParseError> {
allow_origins
.map(|origins| {
origins
.map(Url::parse)
.collect::<Result<Vec<Url>, url::ParseError>>()
})
.unwrap_or_else(|| Ok(vec![]))
}
fn parse_args(cmd: &mut Command) -> ProgramResult<Operation> {
let args = cmd.try_get_matches_from_mut(env::args())?;
if args.get_flag("help") {
if args.is_present("help") {
return Ok(Operation::Help);
} else if args.get_flag("version") {
} else if args.is_present("version") {
return Ok(Operation::Version);
}
let log_level = if let Some(log_level) = args.get_one::<String>("log_level") {
Level::from_str(log_level).ok()
let log_level = if args.is_present("log_level") {
Level::from_str(args.value_of("log_level").unwrap()).ok()
} else {
Some(match args.get_count("verbosity") {
Some(match args.occurrences_of("verbosity") {
0 => Level::Info,
1 => Level::Debug,
_ => Level::Trace,
})
};
let webdriver_host = args.get_one::<String>("webdriver_host").unwrap();
let webdriver_host = args.value_of("webdriver_host").unwrap();
let webdriver_port = {
let s = args.get_one::<String>("webdriver_port").unwrap();
let s = args.value_of("webdriver_port").unwrap();
match u16::from_str(s) {
Ok(n) => n,
Err(e) => usage!("invalid --port: {}: {}", e, s),
@ -253,13 +264,12 @@ fn parse_args(cmd: &mut Command) -> ProgramResult<Operation> {
};
let android_storage = args
.get_one::<String>("android_storage")
.and_then(|arg| AndroidStorageInput::from_str(arg).ok())
.value_of_t::<AndroidStorageInput>("android_storage")
.unwrap_or(AndroidStorageInput::Auto);
let binary = args.get_one::<String>("binary").map(PathBuf::from);
let binary = args.value_of("binary").map(PathBuf::from);
let profile_root = args.get_one::<String>("profile_root").map(PathBuf::from);
let profile_root = args.value_of("profile_root").map(PathBuf::from);
// Try to create a temporary directory on startup to check that the directory exists and is writable
{
@ -273,8 +283,8 @@ fn parse_args(cmd: &mut Command) -> ProgramResult<Operation> {
}
}
let marionette_host = args.get_one::<String>("marionette_host").unwrap();
let marionette_port = match args.get_one::<String>("marionette_port") {
let marionette_host = args.value_of("marionette_host").unwrap();
let marionette_port = match args.value_of("marionette_port") {
Some(s) => match u16::from_str(s) {
Ok(n) => Some(n),
Err(e) => usage!("invalid --marionette-port: {}", e),
@ -284,7 +294,7 @@ fn parse_args(cmd: &mut Command) -> ProgramResult<Operation> {
// For Android the port on the device must be the same as the one on the
// host. For now default to 9222, which is the default for --remote-debugging-port.
let websocket_port = match args.get_one::<String>("websocket_port") {
let websocket_port = match args.value_of("websocket_port") {
Some(s) => match u16::from_str(s) {
Ok(n) => n,
Err(e) => usage!("invalid --websocket-port: {}", e),
@ -297,32 +307,38 @@ fn parse_args(cmd: &mut Command) -> ProgramResult<Operation> {
Err(e) => usage!("invalid --host {}: {}", webdriver_host, e),
};
let allow_hosts = get_allowed_hosts(host, args.get_many("allow_hosts"));
let allow_hosts = match get_allowed_hosts(host, args.values_of("allow_hosts")) {
Ok(hosts) => hosts,
Err(e) => usage!("invalid --allow-hosts {}", e),
};
let allow_origins = get_allowed_origins(args.get_many("allow_origins"));
let allow_origins = match get_allowed_origins(args.values_of("allow_origins")) {
Ok(origins) => origins,
Err(e) => usage!("invalid --allow-origins {}", e),
};
let address = server_address(webdriver_host, webdriver_port)?;
let settings = MarionetteSettings {
binary,
profile_root,
connect_existing: args.get_flag("connect_existing"),
connect_existing: args.is_present("connect_existing"),
host: marionette_host.into(),
port: marionette_port,
websocket_port,
allow_hosts: allow_hosts.clone(),
allow_origins: allow_origins.clone(),
jsdebugger: args.get_flag("jsdebugger"),
jsdebugger: args.is_present("jsdebugger"),
android_storage,
};
Ok(Operation::Server {
log_level,
log_truncate: !args.get_flag("log_no_truncate"),
log_truncate: !args.is_present("log_no_truncate"),
allow_hosts,
allow_origins,
address,
settings,
deprecated_storage_arg: args.contains_id("android_storage"),
deprecated_storage_arg: args.is_present("android_storage"),
})
}
@ -385,86 +401,40 @@ fn main() {
});
}
fn make_command() -> Command {
fn make_command<'a>() -> Command<'a> {
Command::new(format!("geckodriver {}", build::build_info()))
.disable_help_flag(true)
.disable_version_flag(true)
.setting(AppSettings::NoAutoHelp)
.setting(AppSettings::NoAutoVersion)
.about("WebDriver implementation for Firefox")
.arg(
Arg::new("allow_hosts")
.long("allow-hosts")
.num_args(1..)
.value_name("ALLOW_HOSTS")
.help("List of hostnames to allow. By default the value of --host is allowed, and in addition if that's a well known local address, other variations on well known local addresses are allowed. If --allow-hosts is provided only exactly those hosts are allowed."),
)
.arg(
Arg::new("allow_origins")
.long("allow-origins")
.num_args(1..)
.value_name("ALLOW_ORIGINS")
.help("List of request origins to allow. These must be formatted as scheme://host:port. By default any request with an origin header is rejected. If --allow-origins is provided then only exactly those origins are allowed."),
)
.arg(
Arg::new("android_storage")
.long("android-storage")
.value_parser(["auto", "app", "internal", "sdcard"])
.value_name("ANDROID_STORAGE")
.help("Selects storage location to be used for test data (deprecated)."),
)
.arg(
Arg::new("binary")
.short('b')
.long("binary")
.num_args(1)
.value_name("BINARY")
.help("Path to the Firefox binary"),
)
.arg(
Arg::new("connect_existing")
.long("connect-existing")
.requires("marionette_port")
.action(ArgAction::SetTrue)
.help("Connect to an existing Firefox instance"),
)
.arg(
Arg::new("help")
.short('h')
.long("help")
.action(ArgAction::SetTrue)
.help("Prints this message"),
)
.arg(
Arg::new("webdriver_host")
.long("host")
.num_args(1)
.takes_value(true)
.value_name("HOST")
.default_value("127.0.0.1")
.help("Host IP to use for WebDriver server"),
)
.arg(
Arg::new("jsdebugger")
.long("jsdebugger")
.action(ArgAction::SetTrue)
.help("Attach browser toolbox debugger for Firefox"),
Arg::new("webdriver_port")
.short('p')
.long("port")
.takes_value(true)
.value_name("PORT")
.default_value("4444")
.help("Port to use for WebDriver server"),
)
.arg(
Arg::new("log_level")
.long("log")
.num_args(1)
.value_name("LEVEL")
.value_parser(["fatal", "error", "warn", "info", "config", "debug", "trace"])
.help("Set Gecko log level"),
)
.arg(
Arg::new("log_no_truncate")
.long("log-no-truncate")
.action(ArgAction::SetTrue)
.help("Disable truncation of long log lines"),
Arg::new("binary")
.short('b')
.long("binary")
.takes_value(true)
.value_name("BINARY")
.help("Path to the Firefox binary"),
)
.arg(
Arg::new("marionette_host")
.long("marionette-host")
.num_args(1)
.takes_value(true)
.value_name("HOST")
.default_value("127.0.0.1")
.help("Host to use to connect to Gecko"),
@ -472,47 +442,90 @@ fn make_command() -> Command {
.arg(
Arg::new("marionette_port")
.long("marionette-port")
.num_args(1)
.takes_value(true)
.value_name("PORT")
.help("Port to use to connect to Gecko [default: system-allocated port]"),
)
.arg(
Arg::new("webdriver_port")
.short('p')
.long("port")
.num_args(1)
Arg::new("websocket_port")
.long("websocket-port")
.takes_value(true)
.value_name("PORT")
.default_value("4444")
.help("Port to use for WebDriver server"),
.conflicts_with("connect_existing")
.help("Port to use to connect to WebDriver BiDi [default: 9222]"),
)
.arg(
Arg::new("profile_root")
.long("profile-root")
.num_args(1)
.value_name("PROFILE_ROOT")
.help("Directory in which to create profiles. Defaults to the system temporary directory."),
Arg::new("connect_existing")
.long("connect-existing")
.requires("marionette_port")
.help("Connect to an existing Firefox instance"),
)
.arg(
Arg::new("jsdebugger")
.long("jsdebugger")
.help("Attach browser toolbox debugger for Firefox"),
)
.arg(
Arg::new("verbosity")
.multiple_occurrences(true)
.conflicts_with("log_level")
.short('v')
.action(ArgAction::Count)
.help("Log level verbosity (-v for debug and -vv for trace level)"),
)
.arg(
Arg::new("log_level")
.long("log")
.takes_value(true)
.value_name("LEVEL")
.possible_values(["fatal", "error", "warn", "info", "config", "debug", "trace"])
.help("Set Gecko log level"),
)
.arg(
Arg::new("log_no_truncate")
.long("log-no-truncate")
.help("Disable truncation of long log lines"),
)
.arg(
Arg::new("help")
.short('h')
.long("help")
.help("Prints this message"),
)
.arg(
Arg::new("version")
.short('V')
.long("version")
.action(ArgAction::SetTrue)
.help("Prints version and copying information"),
)
.arg(
Arg::new("websocket_port")
.long("websocket-port")
.num_args(1)
.value_name("PORT")
.conflicts_with("connect_existing")
.help("Port to use to connect to WebDriver BiDi [default: 9222]"),
Arg::new("profile_root")
.long("profile-root")
.takes_value(true)
.value_name("PROFILE_ROOT")
.help("Directory in which to create profiles. Defaults to the system temporary directory."),
)
.arg(
Arg::new("android_storage")
.long("android-storage")
.possible_values(["auto", "app", "internal", "sdcard"])
.value_name("ANDROID_STORAGE")
.help("Selects storage location to be used for test data (deprecated)."),
)
.arg(
Arg::new("allow_hosts")
.long("allow-hosts")
.takes_value(true)
.multiple_values(true)
.value_name("ALLOW_HOSTS")
.help("List of hostnames to allow. By default the value of --host is allowed, and in addition if that's a well known local address, other variations on well known local addresses are allowed. If --allow-hosts is provided only exactly those hosts are allowed."),
)
.arg(
Arg::new("allow_origins")
.long("allow-origins")
.takes_value(true)
.multiple_values(true)
.value_name("ALLOW_ORIGINS")
.help("List of request origins to allow. These must be formatted as scheme://host:port. By default any request with an origin header is rejected. If --allow-origins is provided then only exactly those origins are allowed."),
)
}

2
third_party/rust/clap/.cargo-checksum.json поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

893
third_party/rust/clap/Cargo.lock сгенерированный поставляемый

Разница между файлами не показана из-за своего большого размера Загрузить разницу

240
third_party/rust/clap/Cargo.toml поставляемый
Просмотреть файл

@ -10,10 +10,9 @@
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.64.0"
edition = "2018"
name = "clap"
version = "4.1.14"
version = "3.1.18"
include = [
"build.rs",
"src/**/*",
@ -24,6 +23,7 @@ include = [
"examples/**/*",
]
description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
documentation = "https://docs.rs/clap/"
readme = "README.md"
keywords = [
"argument",
@ -44,7 +44,7 @@ rustdoc-args = [
]
cargo-args = [
"-Zunstable-options",
"-Zrustdoc-scrape-examples",
"-Zrustdoc-scrape-examples=examples",
]
[package.metadata.playground]
@ -90,14 +90,25 @@ replace = """
exactly = 1
[[package.metadata.release.pre-release-replacements]]
file = "CITATION.cff"
search = "^date-released: ....-..-.."
replace = "date-released: {{date}}"
file = "README.md"
search = "github.com/clap-rs/clap/blob/[^/]+/"
replace = "github.com/clap-rs/clap/blob/{{tag_name}}/"
exactly = 13
prerelease = true
[[package.metadata.release.pre-release-replacements]]
file = "CITATION.cff"
search = '^version: .+\..+\..+'
replace = "version: {{version}}"
file = "README.md"
search = 'version = "[a-z0-9\.-]+"'
replace = "version = \"{{version}}\""
exactly = 1
prerelease = true
[[package.metadata.release.pre-release-replacements]]
file = "src/derive.rs"
search = "github.com/clap-rs/clap/blob/[^/]+/"
replace = "github.com/clap-rs/clap/blob/{{tag_name}}/"
exactly = 4
prerelease = true
[profile.bench]
lto = true
@ -129,10 +140,6 @@ required-features = ["cargo"]
name = "escaped-positional-derive"
required-features = ["derive"]
[[example]]
name = "find"
required-features = ["cargo"]
[[example]]
name = "git-derive"
required-features = ["derive"]
@ -144,15 +151,17 @@ required-features = ["derive"]
[[example]]
name = "busybox"
path = "examples/multicall-busybox.rs"
required-features = ["unstable-multicall"]
[[example]]
name = "hostname"
path = "examples/multicall-hostname.rs"
required-features = ["unstable-multicall"]
[[example]]
name = "repl"
path = "examples/repl.rs"
required-features = ["help"]
required-features = ["unstable-multicall"]
[[example]]
name = "01_quick"
@ -188,21 +197,11 @@ name = "03_02_option"
path = "examples/tutorial_builder/03_02_option.rs"
required-features = ["cargo"]
[[example]]
name = "03_02_option_mult"
path = "examples/tutorial_builder/03_02_option_mult.rs"
required-features = ["cargo"]
[[example]]
name = "03_03_positional"
path = "examples/tutorial_builder/03_03_positional.rs"
required-features = ["cargo"]
[[example]]
name = "03_03_positional_mult"
path = "examples/tutorial_builder/03_03_positional_mult.rs"
required-features = ["cargo"]
[[example]]
name = "03_04_subcommands"
path = "examples/tutorial_builder/03_04_subcommands.rs"
@ -221,7 +220,10 @@ required-features = ["cargo"]
[[example]]
name = "04_01_enum"
path = "examples/tutorial_builder/04_01_enum.rs"
required-features = ["cargo"]
required-features = [
"cargo",
"derive",
]
[[example]]
name = "04_02_parse"
@ -284,21 +286,11 @@ name = "03_02_option_derive"
path = "examples/tutorial_derive/03_02_option.rs"
required-features = ["derive"]
[[example]]
name = "03_02_option_mult_derive"
path = "examples/tutorial_derive/03_02_option_mult.rs"
required-features = ["derive"]
[[example]]
name = "03_03_positional_derive"
path = "examples/tutorial_derive/03_03_positional.rs"
required-features = ["derive"]
[[example]]
name = "03_03_positional_mult_derive"
path = "examples/tutorial_derive/03_03_positional_mult.rs"
required-features = ["derive"]
[[example]]
name = "03_04_subcommands_derive"
path = "examples/tutorial_derive/03_04_subcommands.rs"
@ -345,6 +337,11 @@ path = "examples/tutorial_derive/05_01_assert.rs"
test = true
required-features = ["derive"]
[[example]]
name = "custom-bool"
path = "examples/derive_ref/custom-bool.rs"
required-features = ["derive"]
[[example]]
name = "interop_augment_args"
path = "examples/derive_ref/augment_args.rs"
@ -365,38 +362,116 @@ name = "interop_flatten_hand_args"
path = "examples/derive_ref/flatten_hand_args.rs"
required-features = ["derive"]
[dependencies.clap_builder]
version = "=4.1.14"
default-features = false
[[bench]]
name = "01_default"
path = "benches/01_default.rs"
harness = false
[[bench]]
name = "02_simple"
path = "benches/02_simple.rs"
harness = false
[[bench]]
name = "03_complex"
path = "benches/03_complex.rs"
harness = false
[[bench]]
name = "04_new_help"
path = "benches/04_new_help.rs"
harness = false
[[bench]]
name = "05_ripgrep"
path = "benches/05_ripgrep.rs"
harness = false
[[bench]]
name = "06_rustup"
path = "benches/06_rustup.rs"
harness = false
[dependencies.atty]
version = "0.2"
optional = true
[dependencies.backtrace]
version = "0.3"
optional = true
[dependencies.bitflags]
version = "1.2"
[dependencies.clap_derive]
version = "=4.1.14"
version = "=3.1.18"
optional = true
[dependencies.once_cell]
version = "1.12.0"
[dependencies.clap_lex]
version = "0.2.0"
[dependencies.indexmap]
version = "1.0"
[dependencies.lazy_static]
version = "1"
optional = true
[dependencies.regex]
version = "1.0"
optional = true
[dependencies.strsim]
version = "0.10"
optional = true
[dependencies.termcolor]
version = "1.1.1"
optional = true
[dependencies.terminal_size]
version = "0.1.12"
optional = true
[dependencies.textwrap]
version = "0.15.0"
features = []
default-features = false
[dependencies.unicase]
version = "2.6"
optional = true
[dependencies.yaml-rust]
version = "0.4.1"
optional = true
[dev-dependencies.criterion]
version = "0.3.2"
[dev-dependencies.humantime]
version = "2.1.0"
version = "2"
[dev-dependencies.lazy_static]
version = "1"
[dev-dependencies.regex]
version = "1.0"
[dev-dependencies.rustversion]
version = "1.0.12"
version = "1"
[dev-dependencies.shlex]
version = "1.1.0"
[dev-dependencies.snapbox]
version = "0.4.10"
[dev-dependencies.static_assertions]
version = "1.1.0"
version = "0.2.9"
[dev-dependencies.trybuild]
version = "1.0.77"
version = "1.0.18"
[dev-dependencies.trycmd]
version = "0.14.15"
version = "0.13"
features = [
"color-auto",
"diff",
@ -404,49 +479,50 @@ features = [
]
default-features = false
[dev-dependencies.unic-emoji-char]
version = "0.9.0"
[features]
cargo = ["clap_builder/cargo"]
color = ["clap_builder/color"]
cargo = ["lazy_static"]
color = [
"atty",
"termcolor",
]
debug = [
"clap_builder/debug",
"clap_derive?/debug",
"clap_derive/debug",
"backtrace",
]
default = [
"std",
"color",
"help",
"usage",
"error-context",
"suggestions",
]
deprecated = [
"clap_builder/deprecated",
"clap_derive?/deprecated",
]
derive = [
"dep:clap_derive",
"dep:once_cell",
"clap_derive",
"lazy_static",
]
env = []
std = ["indexmap/std"]
suggestions = ["strsim"]
unicode = [
"textwrap/unicode-width",
"unicase",
]
env = ["clap_builder/env"]
error-context = ["clap_builder/error-context"]
help = ["clap_builder/help"]
std = ["clap_builder/std"]
string = ["clap_builder/string"]
suggestions = ["clap_builder/suggestions"]
unicode = ["clap_builder/unicode"]
unstable-doc = [
"clap_builder/unstable-doc",
"derive",
"cargo",
"wrap_help",
"yaml",
"env",
"unicode",
"regex",
"unstable-replace",
"unstable-multicall",
"unstable-grouped",
]
unstable-grouped = ["clap_builder/unstable-grouped"]
unstable-replace = ["clap_builder/unstable-replace"]
unstable-v5 = [
"clap_builder/unstable-v5",
"clap_derive?/unstable-v5",
"deprecated",
unstable-grouped = []
unstable-multicall = []
unstable-replace = []
unstable-v4 = ["clap_derive/unstable-v4"]
wrap_help = [
"terminal_size",
"textwrap/terminal_size",
]
usage = ["clap_builder/usage"]
wrap_help = ["clap_builder/wrap_help"]
yaml = ["yaml-rust"]

2
third_party/rust/clap/LICENSE-MIT поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2015-2022 Kevin B. Knapp and Clap Contributors
Copyright (c) 2015-2016 Kevin B. Knapp
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

148
third_party/rust/clap/README.md поставляемый
Просмотреть файл

@ -1,24 +1,160 @@
<!-- omit in TOC -->
# clap
> **Command Line Argument Parser for Rust**
[![Crates.io](https://img.shields.io/crates/v/clap?style=flat-square)](https://crates.io/crates/clap)
[![Crates.io](https://img.shields.io/crates/d/clap?style=flat-square)](https://crates.io/crates/clap)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](LICENSE-APACHE)
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](LICENSE-MIT)
[![Build Status](https://img.shields.io/github/actions/workflow/status/clap-rs/clap/ci.yml?branch=master&style=flat-square)](https://github.com/clap-rs/clap/actions/workflows/ci.yml?query=branch%3Amaster)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/v3.1.18/LICENSE-APACHE)
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/v3.1.18/LICENSE-MIT)
[![Build Status](https://img.shields.io/github/workflow/status/clap-rs/clap/CI/staging?style=flat-square)](https://github.com/clap-rs/clap/actions/workflows/ci.yml?query=branch%3Astaging)
[![Coverage Status](https://img.shields.io/coveralls/github/clap-rs/clap/master?style=flat-square)](https://coveralls.io/github/clap-rs/clap?branch=master)
[![Contributors](https://img.shields.io/github/contributors/clap-rs/clap?style=flat-square)](https://github.com/clap-rs/clap/graphs/contributors)
Dual-licensed under [Apache 2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT).
1. [About](#about)
2. Tutorial: [Builder API](https://github.com/clap-rs/clap/blob/v3.1.18/examples/tutorial_builder/README.md), [Derive API](https://github.com/clap-rs/clap/blob/v3.1.18/examples/tutorial_derive/README.md)
3. [Examples](https://github.com/clap-rs/clap/blob/v3.1.18/examples/README.md)
4. [API Reference](https://docs.rs/clap)
- [Derive Reference](https://github.com/clap-rs/clap/blob/v3.1.18/examples/derive_ref/README.md)
- [Feature Flags](#feature-flags)
5. [CHANGELOG](https://github.com/clap-rs/clap/blob/v3.1.18/CHANGELOG.md)
6. [FAQ](https://github.com/clap-rs/clap/blob/v3.1.18/docs/FAQ.md)
7. [Questions & Discussions](https://github.com/clap-rs/clap/discussions)
8. [Contributing](https://github.com/clap-rs/clap/blob/v3.1.18/CONTRIBUTING.md)
8. [Sponsors](#sponsors)
## About
Create your command-line parser, with all of the bells and whistles, declaratively or procedurally.
For more details, see:
- [docs.rs](https://docs.rs/clap/latest/clap/)
- [examples](examples/)
### Example
This uses our
[Derive API](https://github.com/clap-rs/clap/blob/v3.1.18/examples/tutorial_derive/README.md)
which provides access to the [Builder API](https://github.com/clap-rs/clap/blob/v3.1.18/examples/tutorial_builder/README.md) as attributes on a `struct`:
<!-- Copied from examples/demo.{rs,md} -->
```rust,no_run
use clap::Parser;
/// Simple program to greet a person
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
/// Name of the person to greet
#[clap(short, long)]
name: String,
/// Number of times to greet
#[clap(short, long, default_value_t = 1)]
count: u8,
}
fn main() {
let args = Args::parse();
for _ in 0..args.count {
println!("Hello {}!", args.name)
}
}
```
Add this to `Cargo.toml`:
```toml
[dependencies]
clap = { version = "3.1.18", features = ["derive"] }
```
```bash
$ demo --help
clap [..]
Simple program to greet a person
USAGE:
demo[EXE] [OPTIONS] --name <NAME>
OPTIONS:
-c, --count <COUNT> Number of times to greet [default: 1]
-h, --help Print help information
-n, --name <NAME> Name of the person to greet
-V, --version Print version information
```
*(version number and `.exe` extension on windows replaced by placeholders)*
### Aspirations
- Out of the box, users get a polished CLI experience
- Including common argument behavior, help generation, suggested fixes for users, colored output, [shell completions](https://github.com/clap-rs/clap/tree/master/clap_complete), etc
- Flexible enough to port your existing CLI interface
- However, we won't necessarily streamline support for each use case
- Reasonable parse performance
- Resilient maintainership, including
- Willing to break compatibility rather than batching up breaking changes in large releases
- Leverage feature flags to keep to one active branch
- Being under [WG-CLI](https://github.com/rust-cli/team/) to increase the bus factor
- We follow semver and will wait about 6-9 months between major breaking changes
- We will support the last two minor Rust releases (MSRV, currently 1.54.0)
While these aspirations can be at odds with fast build times and low binary
size, we will still strive to keep these reasonable for the flexibility you
get. Check out the
[argparse-benchmarks](https://github.com/rust-cli/argparse-benchmarks-rs) for
CLI parsers optimized for other use cases.
### Selecting an API
Why use the declarative [Derive API](https://github.com/clap-rs/clap/blob/v3.1.18/examples/tutorial_derive/README.md):
- Easier to read, write, and modify
- Easier to keep the argument declaration and reading of argument in sync
- Easier to reuse, e.g. [clap-verbosity-flag](https://crates.io/crates/clap-verbosity-flag)
Why use the procedural [Builder API](https://github.com/clap-rs/clap/blob/v3.1.18/examples/tutorial_builder/README.md):
- Faster compile times if you aren't already using other procedural macros
- More flexible, e.g. you can look up how many times an argument showed up,
what its values were, and what were the indexes of those values. The Derive
API can only report presence, number of occurrences, or values but no indices
or combinations of data.
### Related Projects
- [wild](https://crates.io/crates/wild) for supporting wildcards (`*`) on Windows like you do Linux
- [argfile](https://crates.io/crates/argfile) for loading additional arguments from a file (aka response files)
- [shadow-rs](https://crates.io/crates/shadow-rs) for generating `Command::long_version`
- [clap_lex](https://crates.io/crates/clap_lex) for a lighter-weight, battle-tested CLI parser
- [clap_mangen](https://crates.io/crates/clap_mangen) for generating man page source (roff)
- [clap_complete](https://crates.io/crates/clap_complete) for shell completion support
- [clap-verbosity-flag](https://crates.io/crates/clap-verbosity-flag)
- [clap-cargo](https://crates.io/crates/clap-cargo)
- [concolor-clap](https://crates.io/crates/concolor-clap)
- [Command-line Apps for Rust](https://rust-cli.github.io/book/index.html) book
- [`trycmd`](https://crates.io/crates/trycmd): Snapshot testing
- Or for more control, [`assert_cmd`](https://crates.io/crates/assert_cmd) and [`assert_fs`](https://crates.io/crates/assert_fs)
## Feature Flags
### Default Features
* **std**: _Not Currently Used._ Placeholder for supporting `no_std` environments in a backwards compatible manner.
* **color**: Turns on colored error messages.
* **suggestions**: Turns on the `Did you mean '--myoption'?` feature for when users make typos.
#### Optional features
* **derive**: Enables the custom derive (i.e. `#[derive(Parser)]`). Without this you must use one of the other methods of creating a `clap` CLI listed above.
* **cargo**: Turns on macros that read values from `CARGO_*` environment variables.
* **env**: Turns on the usage of environment variables during parsing.
* **regex**: Enables regex validators.
* **unicode**: Turns on support for unicode characters (including emoji) in arguments and help messages.
* **wrap_help**: Turns on the help text wrapping feature, based on the terminal size.
#### Experimental features
**Warning:** These may contain breaking changes between minor releases.
* **unstable-replace**: Enable [`Command::replace`](https://github.com/clap-rs/clap/issues/2836)
* **unstable-multicall**: Enable [`Command::multicall`](https://github.com/clap-rs/clap/issues/2861)
* **unstable-grouped**: Enable [`ArgMatches::grouped_values_of`](https://github.com/clap-rs/clap/issues/2924)
* **unstable-v4**: Preview features which will be stable on the v4.0 release
## Sponsors

15
third_party/rust/clap/benches/01_default.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,15 @@
use clap::Command;
use criterion::{criterion_group, criterion_main, Criterion};
pub fn build_empty(c: &mut Criterion) {
c.bench_function("build_empty", |b| b.iter(|| Command::new("claptests")));
}
pub fn parse_empty(c: &mut Criterion) {
c.bench_function("parse_empty", |b| {
b.iter(|| Command::new("claptests").get_matches_from(vec![""]))
});
}
criterion_group!(benches, build_empty, parse_empty);
criterion_main!(benches);

104
third_party/rust/clap/benches/02_simple.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,104 @@
use clap::{arg, Arg, Command};
use criterion::{criterion_group, criterion_main, Criterion};
macro_rules! create_app {
() => {{
Command::new("claptests")
.version("0.1")
.about("tests clap library")
.author("Kevin K. <kbknapp@gmail.com>")
.arg(arg!(-f --flag "tests flags"))
.arg(arg!(-o --option <opt> "tests options").required(false))
.arg(arg!([positional] "tests positional"))
}};
}
pub fn build_simple(c: &mut Criterion) {
c.bench_function("build_simple", |b| b.iter(|| create_app!()));
}
pub fn build_with_flag(c: &mut Criterion) {
c.bench_function("build_with_flag", |b| {
b.iter(|| Command::new("claptests").arg(arg!(-s --some "something")))
});
}
pub fn build_with_flag_ref(c: &mut Criterion) {
c.bench_function("build_with_flag_ref", |b| {
b.iter(|| {
let arg = arg!(-s --some "something");
Command::new("claptests").arg(&arg)
})
});
}
pub fn build_with_opt(c: &mut Criterion) {
c.bench_function("build_with_opt", |b| {
b.iter(|| Command::new("claptests").arg(arg!(-s --some <FILE> "something")))
});
}
pub fn build_with_opt_ref(c: &mut Criterion) {
c.bench_function("build_with_opt_ref", |b| {
b.iter(|| {
let arg = arg!(-s --some <FILE> "something");
Command::new("claptests").arg(&arg)
})
});
}
pub fn build_with_pos(c: &mut Criterion) {
c.bench_function("build_with_pos", |b| {
b.iter(|| Command::new("claptests").arg(Arg::new("some")))
});
}
pub fn build_with_pos_ref(c: &mut Criterion) {
c.bench_function("build_with_pos_ref", |b| {
b.iter(|| {
let arg = Arg::new("some");
Command::new("claptests").arg(&arg)
})
});
}
pub fn parse_simple_with_flag(c: &mut Criterion) {
c.bench_function("parse_simple_with_flag", |b| {
b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"]))
});
}
pub fn parse_simple_with_opt(c: &mut Criterion) {
c.bench_function("parse_simple_with_opt", |b| {
b.iter(|| create_app!().get_matches_from(vec!["myprog", "-o", "option1"]))
});
}
pub fn parse_simple_with_pos(c: &mut Criterion) {
c.bench_function("parse_simple_with_pos", |b| {
b.iter(|| create_app!().get_matches_from(vec!["myprog", "arg1"]))
});
}
pub fn parse_simple_with_complex(c: &mut Criterion) {
c.bench_function("parse_simple_with_complex", |b| {
b.iter(|| create_app!().get_matches_from(vec!["myprog", "-o", "option1", "-f", "arg1"]))
});
}
criterion_group!(
benches,
parse_simple_with_complex,
parse_simple_with_pos,
parse_simple_with_opt,
parse_simple_with_flag,
build_with_pos_ref,
build_with_pos,
build_with_opt_ref,
build_with_opt,
build_with_flag_ref,
build_with_flag,
build_simple
);
criterion_main!(benches);

307
third_party/rust/clap/benches/03_complex.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,307 @@
use clap::{arg, Arg, Command};
use criterion::{criterion_group, criterion_main, Criterion};
static OPT3_VALS: [&str; 2] = ["fast", "slow"];
static POS3_VALS: [&str; 2] = ["vi", "emacs"];
macro_rules! create_app {
() => {{
Command::new("claptests")
.version("0.1")
.about("tests clap library")
.author("Kevin K. <kbknapp@gmail.com>")
.arg(arg!(-o --option <opt> ... "tests options").required(false))
.arg(arg!([positional] "tests positionals"))
.arg(arg!(-f --flag ... "tests flags").global(true))
.args(&[
arg!(flag2: -F "tests flags with exclusions")
.conflicts_with("flag")
.requires("option2"),
arg!(option2: --"long-option-2" <option2> "tests long options with exclusions")
.required(false)
.conflicts_with("option")
.requires("positional2"),
arg!([positional2] "tests positionals with exclusions"),
arg!(-O --Option <option3> "tests options with specific value sets")
.required(false)
.possible_values(OPT3_VALS),
arg!([positional3] ... "tests positionals with specific values")
.possible_values(POS3_VALS),
arg!(--multvals "Tests multiple values not mult occs").required(false).value_names(&["one", "two"]),
arg!(
--multvalsmo "Tests multiple values, not mult occs"
).multiple_values(true).required(false).value_names(&["one", "two"]),
arg!(--minvals2 <minvals> ... "Tests 2 min vals").min_values(2).multiple_values(true).required(false),
arg!(--maxvals3 <maxvals> ... "Tests 3 max vals").max_values(3).multiple_values(true).required(false),
])
.subcommand(
Command::new("subcmd")
.about("tests subcommands")
.version("0.1")
.author("Kevin K. <kbknapp@gmail.com>")
.arg(arg!(-o --option <scoption> ... "tests options").required(false))
.arg(arg!([scpositional] "tests positionals"))
)
}};
}
pub fn build_from_builder(c: &mut Criterion) {
c.bench_function("build_from_builder", |b| {
b.iter(|| {
Command::new("claptests")
.version("0.1")
.about("tests clap library")
.author("Kevin K. <kbknapp@gmail.com>")
.arg(
Arg::new("opt")
.help("tests options")
.short('o')
.long("option")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
)
.arg(Arg::new("positional").help("tests positionals").index(1))
.arg(
Arg::new("flag")
.short('f')
.help("tests flags")
.long("flag")
.global(true)
.multiple_occurrences(true),
)
.arg(
Arg::new("flag2")
.short('F')
.help("tests flags with exclusions")
.conflicts_with("flag")
.requires("option2"),
)
.arg(
Arg::new("option2")
.help("tests long options with exclusions")
.conflicts_with("option")
.requires("positional2")
.takes_value(true)
.long("long-option-2"),
)
.arg(
Arg::new("positional2")
.index(3)
.help("tests positionals with exclusions"),
)
.arg(
Arg::new("option3")
.short('O')
.long("Option")
.takes_value(true)
.help("tests options with specific value sets")
.possible_values(OPT3_VALS),
)
.arg(
Arg::new("positional3")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.help("tests positionals with specific values")
.index(4)
.possible_values(POS3_VALS),
)
.arg(
Arg::new("multvals")
.long("multvals")
.help("Tests multiple values, not mult occs")
.value_names(&["one", "two"]),
)
.arg(
Arg::new("multvalsmo")
.long("multvalsmo")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.help("Tests multiple values, not mult occs")
.value_names(&["one", "two"]),
)
.arg(
Arg::new("minvals")
.long("minvals2")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.help("Tests 2 min vals")
.min_values(2),
)
.arg(
Arg::new("maxvals")
.long("maxvals3")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.help("Tests 3 max vals")
.max_values(3),
)
.subcommand(
Command::new("subcmd")
.about("tests subcommands")
.version("0.1")
.author("Kevin K. <kbknapp@gmail.com>")
.arg(
Arg::new("scoption")
.short('o')
.long("option")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.help("tests options"),
)
.arg(Arg::new("scpositional").index(1).help("tests positionals")),
)
})
});
}
pub fn parse_complex(c: &mut Criterion) {
c.bench_function("parse_complex", |b| {
b.iter(|| create_app!().get_matches_from(vec![""]))
});
}
pub fn parse_complex_with_flag(c: &mut Criterion) {
c.bench_function("parse_complex_with_flag", |b| {
b.iter(|| create_app!().get_matches_from(vec!["myprog", "-f"]))
});
}
pub fn parse_complex_with_opt(c: &mut Criterion) {
c.bench_function("parse_complex_with_opt", |b| {
b.iter(|| create_app!().get_matches_from(vec!["myprog", "-o", "option1"]))
});
}
pub fn parse_complex_with_pos(c: &mut Criterion) {
c.bench_function("parse_complex_with_pos", |b| {
b.iter(|| create_app!().get_matches_from(vec!["myprog", "arg1"]))
});
}
pub fn parse_complex_with_sc(c: &mut Criterion) {
c.bench_function("parse_complex_with_sc", |b| {
b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd"]))
});
}
pub fn parse_complex_with_sc_flag(c: &mut Criterion) {
c.bench_function("parse_complex_with_sc_flag", |b| {
b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd", "-f"]))
});
}
pub fn parse_complex_with_sc_opt(c: &mut Criterion) {
c.bench_function("parse_complex_with_sc_opt", |b| {
b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd", "-o", "option1"]))
});
}
pub fn parse_complex_with_sc_pos(c: &mut Criterion) {
c.bench_function("parse_complex_with_sc_pos", |b| {
b.iter(|| create_app!().get_matches_from(vec!["myprog", "subcmd", "arg1"]))
});
}
pub fn parse_complex1(c: &mut Criterion) {
c.bench_function("parse_complex1", |b| {
b.iter(|| {
create_app!().get_matches_from(vec![
"myprog",
"-ff",
"-o",
"option1",
"arg1",
"-O",
"fast",
"arg2",
"--multvals",
"one",
"two",
"emacs",
])
})
});
}
pub fn parse_complex2(c: &mut Criterion) {
c.bench_function("parse_complex2", |b| {
b.iter(|| {
create_app!().get_matches_from(vec![
"myprog",
"arg1",
"-f",
"arg2",
"--long-option-2",
"some",
"-O",
"slow",
"--multvalsmo",
"one",
"two",
"--minvals2",
"3",
"2",
"1",
])
})
});
}
pub fn parse_args_negate_scs(c: &mut Criterion) {
c.bench_function("parse_args_negate_scs", |b| {
b.iter(|| {
create_app!()
.args_conflicts_with_subcommands(true)
.get_matches_from(vec![
"myprog",
"arg1",
"-f",
"arg2",
"--long-option-2",
"some",
"-O",
"slow",
"--multvalsmo",
"one",
"two",
"--minvals2",
"3",
"2",
"1",
])
})
});
}
pub fn parse_complex_with_sc_complex(c: &mut Criterion) {
c.bench_function("parse_complex_with_sc_complex", |b| {
b.iter(|| {
create_app!().get_matches_from(vec!["myprog", "subcmd", "-f", "-o", "option1", "arg1"])
})
});
}
criterion_group!(
benches,
build_from_builder,
parse_complex,
parse_complex_with_flag,
parse_complex_with_opt,
parse_complex_with_pos,
parse_complex_with_sc,
parse_complex_with_sc_flag,
parse_complex_with_sc_opt,
parse_complex_with_sc_pos,
parse_complex1,
parse_complex2,
parse_args_negate_scs,
parse_complex_with_sc_complex
);
criterion_main!(benches);

223
third_party/rust/clap/benches/04_new_help.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,223 @@
use clap::Command;
use clap::{arg, Arg};
use criterion::{criterion_group, criterion_main, Criterion};
use std::io::Cursor;
fn build_help(cmd: &mut Command) -> String {
let mut buf = Cursor::new(Vec::with_capacity(50));
cmd.write_help(&mut buf).unwrap();
let content = buf.into_inner();
String::from_utf8(content).unwrap()
}
fn app_example1<'c>() -> Command<'c> {
Command::new("MyApp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
.arg(
arg!(
-c --config <FILE> "Sets a custom config file"
)
.required(false),
)
.arg(arg!(<output> "Sets an optional output file"))
.arg(arg!(d: -d ... "Turn debugging information on"))
.subcommand(
Command::new("test")
.about("does testing things")
.arg(arg!(-l --list "lists test values")),
)
}
fn app_example2<'c>() -> Command<'c> {
Command::new("MyApp")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
}
fn app_example3<'c>() -> Command<'c> {
Command::new("MyApp")
.arg(
Arg::new("debug")
.help("turn on debugging information")
.short('d'),
)
.args(&[
Arg::new("config")
.help("sets the config file to use")
.takes_value(true)
.short('c')
.long("config"),
Arg::new("input")
.help("the input file to use")
.required(true),
])
.arg(arg!(--license "display the license file"))
.arg(arg!([output] "Supply an output file to use"))
.arg(
arg!(
-i --int <IFACE> "Set an interface to use"
)
.required(false),
)
}
fn app_example4<'c>() -> Command<'c> {
Command::new("MyApp")
.about("Parses an input file to do awesome things")
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.arg(
Arg::new("debug")
.help("turn on debugging information")
.short('d')
.long("debug"),
)
.arg(
Arg::new("config")
.help("sets the config file to use")
.short('c')
.long("config"),
)
.arg(
Arg::new("input")
.help("the input file to use")
.index(1)
.required(true),
)
}
fn app_example5<'c>() -> Command<'c> {
Command::new("MyApp").arg(
Arg::new("awesome")
.help("turns up the awesome")
.short('a')
.long("awesome")
.multiple_occurrences(true),
)
}
fn app_example6<'c>() -> Command<'c> {
Command::new("MyApp")
.arg(
Arg::new("input")
.help("the input file to use")
.index(1)
.requires("config")
.required(true),
)
.arg(Arg::new("config").help("the config file to use").index(2))
}
fn app_example7<'c>() -> Command<'c> {
Command::new("MyApp")
.arg(Arg::new("config"))
.arg(Arg::new("output"))
.arg(
Arg::new("input")
.help("the input file to use")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.required(true)
.short('i')
.long("input")
.requires("config")
.conflicts_with("output"),
)
}
fn app_example8<'c>() -> Command<'c> {
Command::new("MyApp")
.arg(Arg::new("config"))
.arg(Arg::new("output"))
.arg(
Arg::new("input")
.help("the input file to use")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true)
.required(true)
.short('i')
.long("input")
.requires("config")
.conflicts_with("output"),
)
}
fn app_example10<'c>() -> Command<'c> {
Command::new("myapp").about("does awesome things").arg(
Arg::new("CONFIG")
.help("The config file to use (default is \"config.json\")")
.short('c')
.takes_value(true),
)
}
pub fn example1(c: &mut Criterion) {
let mut cmd = app_example1();
c.bench_function("example1", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example2(c: &mut Criterion) {
let mut cmd = app_example2();
c.bench_function("example2", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example3(c: &mut Criterion) {
let mut cmd = app_example3();
c.bench_function("example3", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example4(c: &mut Criterion) {
let mut cmd = app_example4();
c.bench_function("example4", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example5(c: &mut Criterion) {
let mut cmd = app_example5();
c.bench_function("example5", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example6(c: &mut Criterion) {
let mut cmd = app_example6();
c.bench_function("example6", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example7(c: &mut Criterion) {
let mut cmd = app_example7();
c.bench_function("example7", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example8(c: &mut Criterion) {
let mut cmd = app_example8();
c.bench_function("example8", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example10(c: &mut Criterion) {
let mut cmd = app_example10();
c.bench_function("example10", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn example4_template(c: &mut Criterion) {
let mut cmd = app_example4().help_template("{bin} {version}\n{author}\n{about}\n\nUSAGE:\n {usage}\n\nOPTIONS:\n{options}\n\nARGS:\n{args}\n");
c.bench_function("example4_template", |b| b.iter(|| build_help(&mut cmd)));
}
criterion_group!(
benches,
example1,
example2,
example3,
example4,
example5,
example6,
example7,
example8,
example10,
example4_template
);
criterion_main!(benches);

952
third_party/rust/clap/benches/05_ripgrep.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,952 @@
// Used to simulate a fairly large number of options/flags and parsing with thousands of positional
// args
//
// CLI used is adapted from ripgrep 48a8a3a691220f9e5b2b08f4051abe8655ea7e8a
use clap::{Arg, Command};
use criterion::{criterion_group, criterion_main, Criterion};
use std::collections::HashMap;
use std::io::Cursor;
use lazy_static::lazy_static;
pub fn build_rg_with_short_help(c: &mut Criterion) {
c.bench_function("build_rg_with_short_help", |b| b.iter(app_short));
}
pub fn build_rg_with_long_help(c: &mut Criterion) {
c.bench_function("build_rg_with_long_help", |b| b.iter(app_long));
}
pub fn write_rg_short_help(c: &mut Criterion) {
let mut cmd = app_short();
c.bench_function("write_rg_short_help", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn write_rg_long_help(c: &mut Criterion) {
let mut cmd = app_long();
c.bench_function("write_rg_long_help", |b| b.iter(|| build_help(&mut cmd)));
}
pub fn parse_rg(c: &mut Criterion) {
c.bench_function("parse_rg", |b| {
b.iter(|| app_short().get_matches_from(vec!["rg", "pat"]))
});
}
pub fn parse_rg_with_complex(c: &mut Criterion) {
c.bench_function("parse_rg_with_complex", |b| {
b.iter(|| {
app_short().get_matches_from(vec![
"rg",
"pat",
"-cFlN",
"-pqr=some",
"--null",
"--no-filename",
"--no-messages",
"-SH",
"-C5",
"--follow",
"-e some",
])
})
});
}
pub fn parse_rg_with_lots(c: &mut Criterion) {
c.bench_function("parse_rg_with_lots", |b| {
b.iter(|| {
app_short().get_matches_from(vec![
"rg", "pat", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some", "some", "some", "some", "some",
"some", "some", "some", "some", "some", "some",
])
})
});
}
const ABOUT: &str = "
ripgrep (rg) recursively searches your current directory for a regex pattern.
ripgrep's regex engine uses finite automata and guarantees linear time
searching. Because of this, features like backreferences and arbitrary
lookaround are not supported.
Project home page: https://github.com/BurntSushi/ripgrep
Use -h for short descriptions and --help for more details.";
const USAGE: &str = "
rg [OPTIONS] <pattern> [<path> ...]
rg [OPTIONS] [-e PATTERN | -f FILE ]... [<path> ...]
rg [OPTIONS] --files [<path> ...]
rg [OPTIONS] --type-list";
const TEMPLATE: &str = "\
{bin} {version}
{author}
{about}
USAGE:{usage}
ARGS:
{positionals}
OPTIONS:
{options}";
/// Build a clap application with short help strings.
fn app_short() -> Command<'static> {
cmd(false, |k| USAGES[k].short)
}
/// Build a clap application with long help strings.
fn app_long() -> Command<'static> {
cmd(true, |k| USAGES[k].long)
}
/// Build the help text of an application.
fn build_help(cmd: &mut Command) -> String {
let mut buf = Cursor::new(Vec::with_capacity(50));
cmd.write_help(&mut buf).unwrap();
let content = buf.into_inner();
String::from_utf8(content).unwrap()
}
/// Build a clap application parameterized by usage strings.
///
/// The function given should take a clap argument name and return a help
/// string. `cmd` will panic if a usage string is not defined.
///
/// This is an intentionally stand-alone module so that it can be used easily
/// in a `build.rs` script to build shell completion files.
fn cmd<F>(_next_line_help: bool, doc: F) -> Command<'static>
where
F: Fn(&'static str) -> &'static str,
{
let arg = |name| Arg::new(name).help(doc(name));
let flag = |name| arg(name).long(name);
Command::new("ripgrep")
.author("BurntSushi") // simulating since it's only a bench
.version("0.4.0") // Simulating
.about(ABOUT)
.max_term_width(100)
.override_usage(USAGE)
.help_template(TEMPLATE)
// Handle help/version manually to make their output formatting
// consistent with short/long views.
.arg(arg("help-short").short('h'))
.arg(flag("help"))
.arg(flag("version").short('V'))
// First, set up primary positional/flag arguments.
.arg(arg("pattern").required_unless_present_any(&[
"file",
"files",
"help-short",
"help",
"regexp",
"type-list",
"version",
]))
.arg(
arg("path")
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
)
.arg(
flag("regexp")
.short('e')
.allow_hyphen_values(true)
.multiple_occurrences(true)
.takes_value(true)
.value_name("pattern"),
)
.arg(
flag("files")
// This should also conflict with `pattern`, but the first file
// path will actually be in `pattern`.
.conflicts_with_all(&["file", "regexp", "type-list"]),
)
.arg(flag("type-list").conflicts_with_all(&["file", "files", "pattern", "regexp"]))
// Second, set up common flags.
.arg(flag("text").short('a'))
.arg(flag("count").short('c'))
.arg(
flag("color")
.value_name("WHEN")
.takes_value(true)
.hide_possible_values(true)
.possible_values(["never", "auto", "always", "ansi"]),
)
.arg(
flag("colors")
.value_name("SPEC")
.multiple_occurrences(true)
.takes_value(true),
)
.arg(flag("fixed-strings").short('F'))
.arg(
flag("glob")
.short('g')
.multiple_occurrences(true)
.takes_value(true)
.value_name("GLOB"),
)
.arg(flag("ignore-case").short('i'))
.arg(flag("line-number").short('n'))
.arg(flag("no-line-number").short('N'))
.arg(flag("quiet").short('q'))
.arg(
flag("type")
.short('t')
.multiple_occurrences(true)
.takes_value(true)
.value_name("TYPE"),
)
.arg(
flag("type-not")
.short('T')
.multiple_occurrences(true)
.takes_value(true)
.value_name("TYPE"),
)
.arg(flag("unrestricted").short('u').multiple_occurrences(true))
.arg(flag("invert-match").short('v'))
.arg(flag("word-regexp").short('w'))
// Third, set up less common flags.
.arg(
flag("after-context")
.short('A')
.value_name("NUM")
.validator(validate_number),
)
.arg(
flag("before-context")
.short('B')
.value_name("NUM")
.validator(validate_number),
)
.arg(
flag("context")
.short('C')
.value_name("NUM")
.validator(validate_number),
)
.arg(flag("column"))
.arg(flag("context-separator").value_name("SEPARATOR"))
.arg(flag("debug"))
.arg(
flag("file")
.short('f')
.value_name("FILE")
.multiple_occurrences(true),
)
.arg(flag("files-with-matches").short('l'))
.arg(flag("files-without-match"))
.arg(flag("with-filename").short('H'))
.arg(flag("no-filename"))
.arg(flag("heading").overrides_with("no-heading"))
.arg(flag("no-heading").overrides_with("heading"))
.arg(flag("hidden"))
.arg(
flag("ignore-file")
.value_name("FILE")
.multiple_occurrences(true),
)
.arg(flag("follow").short('L'))
.arg(
flag("max-count")
.short('m')
.value_name("NUM")
.validator(validate_number),
)
.arg(
flag("maxdepth")
.value_name("NUM")
.validator(validate_number),
)
.arg(flag("mmap"))
.arg(flag("no-messages"))
.arg(flag("no-mmap"))
.arg(flag("no-ignore"))
.arg(flag("no-ignore-parent"))
.arg(flag("no-ignore-vcs"))
.arg(flag("null"))
.arg(flag("path-separator").value_name("SEPARATOR"))
.arg(flag("pretty").short('p'))
.arg(flag("replace").short('r').value_name("ARG"))
.arg(flag("case-sensitive").short('s'))
.arg(flag("smart-case").short('S'))
.arg(flag("sort-files"))
.arg(
flag("threads")
.short('j')
.value_name("ARG")
.validator(validate_number),
)
.arg(flag("vimgrep"))
.arg(
flag("type-add")
.value_name("TYPE")
.multiple_occurrences(true),
)
.arg(
flag("type-clear")
.value_name("TYPE")
.multiple_occurrences(true),
)
}
struct Usage {
short: &'static str,
long: &'static str,
}
macro_rules! doc {
($map:expr, $name:expr, $short:expr) => {
doc!($map, $name, $short, $short)
};
($map:expr, $name:expr, $short:expr, $long:expr) => {
$map.insert(
$name,
Usage {
short: $short,
long: concat!($long, "\n "),
},
);
};
}
lazy_static! {
static ref USAGES: HashMap<&'static str, Usage> = {
let mut h = HashMap::new();
doc!(
h,
"help-short",
"Show short help output.",
"Show short help output. Use --help to show more details."
);
doc!(
h,
"help",
"Show verbose help output.",
"When given, more details about flags are provided."
);
doc!(h, "version", "Print version information.");
doc!(
h,
"pattern",
"A regular expression used for searching.",
"A regular expression used for searching. Multiple patterns \
may be given. To match a pattern beginning with a -, use [-]."
);
doc!(
h,
"regexp",
"A regular expression used for searching.",
"A regular expression used for searching. Multiple patterns \
may be given. To match a pattern beginning with a -, use [-]."
);
doc!(
h,
"path",
"A file or directory to search.",
"A file or directory to search. Directories are searched \
recursively."
);
doc!(
h,
"files",
"Print each file that would be searched.",
"Print each file that would be searched without actually \
performing the search. This is useful to determine whether a \
particular file is being searched or not."
);
doc!(
h,
"type-list",
"Show all supported file types.",
"Show all supported file types and their corresponding globs."
);
doc!(h, "text", "Search binary files as if they were text.");
doc!(h, "count", "Only show count of matches for each file.");
doc!(
h,
"color",
"When to use color. [default: auto]",
"When to use color in the output. The possible values are \
never, auto, always or ansi. The default is auto. When always \
is used, coloring is attempted based on your environment. When \
ansi used, coloring is forcefully done using ANSI escape color \
codes."
);
doc!(
h,
"colors",
"Configure color settings and styles.",
"This flag specifies color settings for use in the output. \
This flag may be provided multiple times. Settings are applied \
iteratively. Colors are limited to one of eight choices: \
red, blue, green, cyan, magenta, yellow, white and black. \
Styles are limited to nobold, bold, nointense or intense.\n\n\
The format of the flag is {type}:{attribute}:{value}. {type} \
should be one of path, line or match. {attribute} can be fg, bg \
or style. {value} is either a color (for fg and bg) or a text \
style. A special format, {type}:none, will clear all color \
settings for {type}.\n\nFor example, the following command will \
change the match color to magenta and the background color for \
line numbers to yellow:\n\n\
rg --colors 'match:fg:magenta' --colors 'line:bg:yellow' foo."
);
doc!(
h,
"fixed-strings",
"Treat the pattern as a literal string.",
"Treat the pattern as a literal string instead of a regular \
expression. When this flag is used, special regular expression \
meta characters such as (){}*+. do not need to be escaped."
);
doc!(
h,
"glob",
"Include or exclude files/directories.",
"Include or exclude files/directories for searching that \
match the given glob. This always overrides any other \
ignore logic. Multiple glob flags may be used. Globbing \
rules match .gitignore globs. Precede a glob with a ! \
to exclude it."
);
doc!(
h,
"ignore-case",
"Case insensitive search.",
"Case insensitive search. This is overridden by \
--case-sensitive."
);
doc!(
h,
"line-number",
"Show line numbers.",
"Show line numbers (1-based). This is enabled by default when \
searching in a tty."
);
doc!(
h,
"no-line-number",
"Suppress line numbers.",
"Suppress line numbers. This is enabled by default when NOT \
searching in a tty."
);
doc!(
h,
"quiet",
"Do not print anything to stdout.",
"Do not print anything to stdout. If a match is found in a file, \
stop searching. This is useful when ripgrep is used only for \
its exit code."
);
doc!(
h,
"type",
"Only search files matching TYPE.",
"Only search files matching TYPE. Multiple type flags may be \
provided. Use the --type-list flag to list all available \
types."
);
doc!(
h,
"type-not",
"Do not search files matching TYPE.",
"Do not search files matching TYPE. Multiple type-not flags may \
be provided. Use the --type-list flag to list all available \
types."
);
doc!(
h,
"unrestricted",
"Reduce the level of \"smart\" searching.",
"Reduce the level of \"smart\" searching. A single -u \
won't respect .gitignore (etc.) files. Two -u flags will \
additionally search hidden files and directories. Three \
-u flags will additionally search binary files. -uu is \
roughly equivalent to grep -r and -uuu is roughly \
equivalent to grep -a -r."
);
doc!(
h,
"invert-match",
"Invert matching.",
"Invert matching. Show lines that don't match given patterns."
);
doc!(
h,
"word-regexp",
"Only show matches surrounded by word boundaries.",
"Only show matches surrounded by word boundaries. This is \
equivalent to putting \\b before and after all of the search \
patterns."
);
doc!(h, "after-context", "Show NUM lines after each match.");
doc!(h, "before-context", "Show NUM lines before each match.");
doc!(h, "context", "Show NUM lines before and after each match.");
doc!(
h,
"column",
"Show column numbers",
"Show column numbers (1-based). This only shows the column \
numbers for the first match on each line. This does not try \
to account for Unicode. One byte is equal to one column. This \
implies --line-number."
);
doc!(
h,
"context-separator",
"Set the context separator string. [default: --]",
"The string used to separate non-contiguous context lines in the \
output. Escape sequences like \\x7F or \\t may be used. The \
default value is --."
);
doc!(
h,
"debug",
"Show debug messages.",
"Show debug messages. Please use this when filing a bug report."
);
doc!(
h,
"file",
"Search for patterns from the given file.",
"Search for patterns from the given file, with one pattern per \
line. When this flag is used or multiple times or in \
combination with the -e/--regexp flag, then all patterns \
provided are searched. Empty pattern lines will match all input \
lines, and the newline is not counted as part of the pattern."
);
doc!(
h,
"files-with-matches",
"Only show the path of each file with at least one match."
);
doc!(
h,
"files-without-match",
"Only show the path of each file that contains zero matches."
);
doc!(
h,
"with-filename",
"Show file name for each match.",
"Prefix each match with the file name that contains it. This is \
the default when more than one file is searched."
);
doc!(
h,
"no-filename",
"Never show the file name for a match.",
"Never show the file name for a match. This is the default when \
one file is searched."
);
doc!(
h,
"heading",
"Show matches grouped by each file.",
"This shows the file name above clusters of matches from each \
file instead of showing the file name for every match. This is \
the default mode at a tty."
);
doc!(
h,
"no-heading",
"Don't group matches by each file.",
"Don't group matches by each file. If -H/--with-filename is \
enabled, then file names will be shown for every line matched. \
This is the default mode when not at a tty."
);
doc!(
h,
"hidden",
"Search hidden files and directories.",
"Search hidden files and directories. By default, hidden files \
and directories are skipped."
);
doc!(
h,
"ignore-file",
"Specify additional ignore files.",
"Specify additional ignore files for filtering file paths. \
Ignore files should be in the gitignore format and are matched \
relative to the current working directory. These ignore files \
have lower precedence than all other ignore files. When \
specifying multiple ignore files, earlier files have lower \
precedence than later files."
);
doc!(h, "follow", "Follow symbolic links.");
doc!(
h,
"max-count",
"Limit the number of matches.",
"Limit the number of matching lines per file searched to NUM."
);
doc!(
h,
"maxdepth",
"Descend at most NUM directories.",
"Limit the depth of directory traversal to NUM levels beyond \
the paths given. A value of zero only searches the \
starting-points themselves.\n\nFor example, \
'rg --maxdepth 0 dir/' is a no-op because dir/ will not be \
descended into. 'rg --maxdepth 1 dir/' will search only the \
direct children of dir/."
);
doc!(
h,
"mmap",
"Searching using memory maps when possible.",
"Search using memory maps when possible. This is enabled by \
default when ripgrep thinks it will be faster. Note that memory \
map searching doesn't currently support all options, so if an \
incompatible option (e.g., --context) is given with --mmap, \
then memory maps will not be used."
);
doc!(
h,
"no-messages",
"Suppress all error messages.",
"Suppress all error messages. This is equivalent to redirecting \
stderr to /dev/null."
);
doc!(
h,
"no-mmap",
"Never use memory maps.",
"Never use memory maps, even when they might be faster."
);
doc!(
h,
"no-ignore",
"Don't respect ignore files.",
"Don't respect ignore files (.gitignore, .ignore, etc.). This \
implies --no-ignore-parent and --no-ignore-vcs."
);
doc!(
h,
"no-ignore-parent",
"Don't respect ignore files in parent directories.",
"Don't respect ignore files (.gitignore, .ignore, etc.) in \
parent directories."
);
doc!(
h,
"no-ignore-vcs",
"Don't respect VCS ignore files",
"Don't respect version control ignore files (.gitignore, etc.). \
This implies --no-ignore-parent. Note that .ignore files will \
continue to be respected."
);
doc!(
h,
"null",
"Print NUL byte after file names",
"Whenever a file name is printed, follow it with a NUL byte. \
This includes printing file names before matches, and when \
printing a list of matching files such as with --count, \
--files-with-matches and --files. This option is useful for use \
with xargs."
);
doc!(
h,
"path-separator",
"Path separator to use when printing file paths.",
"The path separator to use when printing file paths. This \
defaults to your platform's path separator, which is / on Unix \
and \\ on Windows. This flag is intended for overriding the \
default when the environment demands it (e.g., cygwin). A path \
separator is limited to a single byte."
);
doc!(h, "pretty", "Alias for --color always --heading -n.");
doc!(
h,
"replace",
"Replace matches with string given.",
"Replace every match with the string given when printing \
results. Neither this flag nor any other flag will modify your \
files.\n\nCapture group indices (e.g., $5) and names \
(e.g., $foo) are supported in the replacement string.\n\n\
Note that the replacement by default replaces each match, and \
NOT the entire line. To replace the entire line, you should \
match the entire line."
);
doc!(
h,
"case-sensitive",
"Search case sensitively.",
"Search case sensitively. This overrides -i/--ignore-case and \
-S/--smart-case."
);
doc!(
h,
"smart-case",
"Smart case search.",
"Searches case insensitively if the pattern is all lowercase. \
Search case sensitively otherwise. This is overridden by \
either -s/--case-sensitive or -i/--ignore-case."
);
doc!(
h,
"sort-files",
"Sort results by file path. Implies --threads=1.",
"Sort results by file path. Note that this currently \
disables all parallelism and runs search in a single thread."
);
doc!(
h,
"threads",
"The approximate number of threads to use.",
"The approximate number of threads to use. A value of 0 (which \
is the default) causes ripgrep to choose the thread count \
using heuristics."
);
doc!(
h,
"vimgrep",
"Show results in vim compatible format.",
"Show results with every match on its own line, including \
line numbers and column numbers. With this option, a line with \
more than one match will be printed more than once."
);
doc!(
h,
"type-add",
"Add a new glob for a file type.",
"Add a new glob for a particular file type. Only one glob can be \
added at a time. Multiple --type-add flags can be provided. \
Unless --type-clear is used, globs are added to any existing \
globs defined inside of ripgrep.\n\nNote that this MUST be \
passed to every invocation of ripgrep. Type settings are NOT \
persisted.\n\nExample: \
rg --type-add 'foo:*.foo' -tfoo PATTERN.\n\n\
--type-add can also be used to include rules from other types \
with the special include directive. The include directive \
permits specifying one or more other type names (separated by a \
comma) that have been defined and its rules will automatically \
be imported into the type specified. For example, to create a \
type called src that matches C++, Python and Markdown files, one \
can use:\n\n\
--type-add 'src:include:cpp,py,md'\n\n\
Additional glob rules can still be added to the src type by \
using the --type-add flag again:\n\n\
--type-add 'src:include:cpp,py,md' --type-add 'src:*.foo'\n\n\
Note that type names must consist only of Unicode letters or \
numbers. Punctuation characters are not allowed."
);
doc!(
h,
"type-clear",
"Clear globs for given file type.",
"Clear the file type globs previously defined for TYPE. This \
only clears the default type definitions that are found inside \
of ripgrep.\n\nNote that this MUST be passed to every \
invocation of ripgrep. Type settings are NOT persisted."
);
h
};
}
fn validate_number(s: &str) -> Result<(), String> {
s.parse::<usize>()
.map(|_| ())
.map_err(|err| err.to_string())
}
criterion_group!(
benches,
build_rg_with_short_help,
build_rg_with_long_help,
write_rg_short_help,
write_rg_long_help,
parse_rg,
parse_rg_with_complex,
parse_rg_with_lots
);
criterion_main!(benches);

412
third_party/rust/clap/benches/06_rustup.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,412 @@
// Used to simulate a fairly large number of subcommands
//
// CLI used is from rustup 408ed84f0e50511ed44a405dd91365e5da588790
use clap::{AppSettings, Arg, ArgGroup, Command};
use criterion::{criterion_group, criterion_main, Criterion};
pub fn build_rustup(c: &mut Criterion) {
c.bench_function("build_rustup", |b| b.iter(build_cli));
}
pub fn parse_rustup(c: &mut Criterion) {
c.bench_function("parse_rustup", |b| {
b.iter(|| build_cli().get_matches_from(vec![""]))
});
}
pub fn parse_rustup_with_sc(c: &mut Criterion) {
c.bench_function("parse_rustup_with_sc", |b| {
b.iter(|| build_cli().get_matches_from(vec!["rustup override add stable"]))
});
}
fn build_cli() -> Command<'static> {
Command::new("rustup")
.version("0.9.0") // Simulating
.about("The Rust toolchain installer")
.after_help(RUSTUP_HELP)
.setting(AppSettings::DeriveDisplayOrder)
// .setting(AppSettings::SubcommandRequiredElseHelp)
.arg(
Arg::new("verbose")
.help("Enable verbose output")
.short('v')
.long("verbose"),
)
.subcommand(
Command::new("show")
.about("Show the active and installed toolchains")
.after_help(SHOW_HELP),
)
.subcommand(
Command::new("install")
.about("Update Rust toolchains")
.after_help(TOOLCHAIN_INSTALL_HELP)
.hide(true) // synonym for 'toolchain install'
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
Command::new("update")
.about("Update Rust toolchains")
.after_help(UPDATE_HELP)
.arg(Arg::new("toolchain").required(true))
.arg(
Arg::new("no-self-update")
.help("Don't perform self update when running the `rustup` command")
.long("no-self-update")
.hide(true),
),
)
.subcommand(
Command::new("default")
.about("Set the default toolchain")
.after_help(DEFAULT_HELP)
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
Command::new("toolchain")
.about("Modify or query the installed toolchains")
.after_help(TOOLCHAIN_HELP)
.setting(AppSettings::DeriveDisplayOrder)
// .setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(Command::new("list").about("List installed toolchains"))
.subcommand(
Command::new("install")
.about("Install or update a given toolchain")
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
Command::new("uninstall")
.about("Uninstall a toolchain")
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
Command::new("link")
.about("Create a custom toolchain by symlinking to a directory")
.arg(Arg::new("toolchain").required(true))
.arg(Arg::new("path").required(true)),
)
.subcommand(
Command::new("update")
.hide(true) // synonym for 'install'
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
Command::new("add")
.hide(true) // synonym for 'install'
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
Command::new("remove")
.hide(true) // synonym for 'uninstall'
.arg(Arg::new("toolchain").required(true)),
),
)
.subcommand(
Command::new("target")
.about("Modify a toolchain's supported targets")
.setting(AppSettings::DeriveDisplayOrder)
// .setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
Command::new("list")
.about("List installed and available targets")
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
)
.subcommand(
Command::new("add")
.about("Add a target to a Rust toolchain")
.arg(Arg::new("target").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
)
.subcommand(
Command::new("remove")
.about("Remove a target from a Rust toolchain")
.arg(Arg::new("target").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
)
.subcommand(
Command::new("install")
.hide(true) // synonym for 'add'
.arg(Arg::new("target").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
)
.subcommand(
Command::new("uninstall")
.hide(true) // synonym for 'remove'
.arg(Arg::new("target").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
),
)
.subcommand(
Command::new("component")
.about("Modify a toolchain's installed components")
.setting(AppSettings::DeriveDisplayOrder)
// .setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(
Command::new("list")
.about("List installed and available components")
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
)
.subcommand(
Command::new("add")
.about("Add a component to a Rust toolchain")
.arg(Arg::new("component").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true))
.arg(Arg::new("target").long("target").takes_value(true)),
)
.subcommand(
Command::new("remove")
.about("Remove a component from a Rust toolchain")
.arg(Arg::new("component").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true))
.arg(Arg::new("target").long("target").takes_value(true)),
),
)
.subcommand(
Command::new("override")
.about("Modify directory toolchain overrides")
.after_help(OVERRIDE_HELP)
.setting(AppSettings::DeriveDisplayOrder)
// .setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(Command::new("list").about("List directory toolchain overrides"))
.subcommand(
Command::new("set")
.about("Set the override toolchain for a directory")
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
Command::new("unset")
.about("Remove the override toolchain for a directory")
.after_help(OVERRIDE_UNSET_HELP)
.arg(
Arg::new("path")
.long("path")
.takes_value(true)
.help("Path to the directory"),
)
.arg(
Arg::new("nonexistent")
.long("nonexistent")
.help("Remove override toolchain for all nonexistent directories"),
),
)
.subcommand(
Command::new("add")
.hide(true) // synonym for 'set'
.arg(Arg::new("toolchain").required(true)),
)
.subcommand(
Command::new("remove")
.hide(true) // synonym for 'unset'
.about("Remove the override toolchain for a directory")
.arg(Arg::new("path").long("path").takes_value(true))
.arg(
Arg::new("nonexistent")
.long("nonexistent")
.help("Remove override toolchain for all nonexistent directories"),
),
),
)
.subcommand(
Command::new("run")
.about("Run a command with an environment configured for a given toolchain")
.after_help(RUN_HELP)
.trailing_var_arg(true)
.arg(Arg::new("toolchain").required(true))
.arg(
Arg::new("command")
.required(true)
.takes_value(true)
.multiple_values(true)
.multiple_occurrences(true),
),
)
.subcommand(
Command::new("which")
.about("Display which binary will be run for a given command")
.arg(Arg::new("command").required(true)),
)
.subcommand(
Command::new("doc")
.about("Open the documentation for the current toolchain")
.after_help(DOC_HELP)
.arg(
Arg::new("book")
.long("book")
.help("The Rust Programming Language book"),
)
.arg(
Arg::new("std")
.long("std")
.help("Standard library API documentation"),
)
.group(ArgGroup::new("page").args(&["book", "std"])),
)
.subcommand(
Command::new("man")
.about("View the man page for a given command")
.arg(Arg::new("command").required(true))
.arg(Arg::new("toolchain").long("toolchain").takes_value(true)),
)
.subcommand(
Command::new("self")
.about("Modify the rustup installation")
.setting(AppSettings::DeriveDisplayOrder)
.subcommand(Command::new("update").about("Download and install updates to rustup"))
.subcommand(
Command::new("uninstall")
.about("Uninstall rustup.")
.arg(Arg::new("no-prompt").short('y')),
)
.subcommand(
Command::new("upgrade-data").about("Upgrade the internal data format."),
),
)
.subcommand(
Command::new("telemetry")
.about("rustup telemetry commands")
.hide(true)
.setting(AppSettings::DeriveDisplayOrder)
.subcommand(Command::new("enable").about("Enable rustup telemetry"))
.subcommand(Command::new("disable").about("Disable rustup telemetry"))
.subcommand(Command::new("analyze").about("Analyze stored telemetry")),
)
.subcommand(
Command::new("set")
.about("Alter rustup settings")
.subcommand(
Command::new("default-host")
.about("The triple used to identify toolchains when not specified")
.arg(Arg::new("host_triple").required(true)),
),
)
}
static RUSTUP_HELP: &str = r"
rustup installs The Rust Programming Language from the official
release channels, enabling you to easily switch between stable, beta,
and nightly compilers and keep them updated. It makes cross-compiling
simpler with binary builds of the standard library for common platforms.
If you are new to Rust consider running `rustup doc --book`
to learn Rust.";
static SHOW_HELP: &str = r"
Shows the name of the active toolchain and the version of `rustc`.
If the active toolchain has installed support for additional
compilation targets, then they are listed as well.
If there are multiple toolchains installed then all installed
toolchains are listed as well.";
static UPDATE_HELP: &str = r"
With no toolchain specified, the `update` command updates each of the
installed toolchains from the official release channels, then updates
rustup itself.
If given a toolchain argument then `update` updates that toolchain,
the same as `rustup toolchain install`.
'toolchain' specifies a toolchain name, such as 'stable', 'nightly',
or '1.8.0'. For more information see `rustup help toolchain`.";
static TOOLCHAIN_INSTALL_HELP: &str = r"
Installs a specific rust toolchain.
The 'install' command is an alias for 'rustup update <toolchain>'.
'toolchain' specifies a toolchain name, such as 'stable', 'nightly',
or '1.8.0'. For more information see `rustup help toolchain`.";
static DEFAULT_HELP: &str = r"
Sets the default toolchain to the one specified. If the toolchain is
not already installed then it is installed first.";
static TOOLCHAIN_HELP: &str = r"
Many `rustup` commands deal with *toolchains*, a single installation
of the Rust compiler. `rustup` supports multiple types of
toolchains. The most basic track the official release channels:
'stable', 'beta' and 'nightly'; but `rustup` can also install
toolchains from the official archives, for alternate host platforms,
and from local builds.
Standard release channel toolchain names have the following form:
<channel>[-<date>][-<host>]
<channel> = stable|beta|nightly|<version>
<date> = YYYY-MM-DD
<host> = <target-triple>
'channel' is either a named release channel or an explicit version
number, such as '1.8.0'. Channel names can be optionally appended with
an archive date, as in 'nightly-2014-12-18', in which case the
toolchain is downloaded from the archive for that date.
Finally, the host may be specified as a target triple. This is most
useful for installing a 32-bit compiler on a 64-bit platform, or for
installing the [MSVC-based toolchain] on Windows. For example:
rustup toolchain install stable-x86_64-pc-windows-msvc
For convenience, elements of the target triple that are omitted will be
inferred, so the above could be written:
$ rustup default stable-msvc
Toolchain names that don't name a channel instead can be used to name
custom toolchains with the `rustup toolchain link` command.";
static OVERRIDE_HELP: &str = r"
Overrides configure rustup to use a specific toolchain when
running in a specific directory.
Directories can be assigned their own Rust toolchain with
`rustup override`. When a directory has an override then
any time `rustc` or `cargo` is run inside that directory,
or one of its child directories, the override toolchain
will be invoked.
To pin to a specific nightly:
rustup override set nightly-2014-12-18
Or a specific stable release:
rustup override set 1.0.0
To see the active toolchain use `rustup show`. To remove the override
and use the default toolchain again, `rustup override unset`.";
static OVERRIDE_UNSET_HELP: &str = r"
If `--path` argument is present, removes the override toolchain for
the specified directory. If `--nonexistent` argument is present, removes
the override toolchain for all nonexistent directories. Otherwise,
removes the override toolchain for the current directory.";
static RUN_HELP: &str = r"
Configures an environment to use the given toolchain and then runs
the specified program. The command may be any program, not just
rustc or cargo. This can be used for testing arbitrary toolchains
without setting an override.
Commands explicitly proxied by `rustup` (such as `rustc` and `cargo`)
also have a shorthand for this available. The toolchain can be set by
using `+toolchain` as the first argument. These are equivalent:
cargo +nightly build
rustup run nightly cargo build";
static DOC_HELP: &str = r"
Opens the documentation for the currently active toolchain with the
default browser.
By default, it opens the documentation index. Use the various flags to
open specific pieces of documentation.";
criterion_group!(benches, build_rustup, parse_rustup, parse_rustup_with_sc);
criterion_main!(benches);

46
third_party/rust/clap/examples/README.md поставляемый
Просмотреть файл

@ -1,16 +1,40 @@
# Examples
We try to focus our documentation on the [four types of
documentation](https://documentation.divio.com/). Examples fit into this by
providing:
- [Cookbook / How-To Guides](https://docs.rs/clap/latest/clap/_cookbook/index.html)
- Tutorials ([derive](https://docs.rs/clap/latest/clap/_derive/_tutorial/index.html), [builder](https://docs.rs/clap/latest/clap/_tutorial/index.html))
This directory contains the source for the above.
- Basic demo: [derive](demo.md)
- Typed arguments: [derive](typed-derive.md)
- Topics:
- Custom `parse()`
- Custom cargo command: [builder](cargo-example.md), [derive](cargo-example-derive.md)
- Topics:
- Subcommands
- Cargo plugins
- git-like interface: [builder](git.md), [derive](git-derive.md)
- Topics:
- Subcommands
- External subcommands
- Optional subcommands
- Default subcommands
- pacman-like interface: [builder](pacman.md)
- Topics:
- Flag subcommands
- Conflicting arguments
- Escaped positionals with `--`: [builder](escaped-positional.md), [derive](escaped-positional-derive.md)
- Multi-call
- busybox: [builder](multicall-busybox.md)
- Topics:
- Subcommands
- hostname: [builder](multicall-hostname.md)
- Topics:
- Subcommands
- repl: [builder](repl.rs)
- Topics:
- Read-Eval-Print Loops / Custom command lines
## Contributing
New examples should fit within the above structure and support their narrative
- Add the example to [Cargo.toml](../Cargo.toml) for any `required-features`
- Document how the example works with a `.md` file which will be verified using [trycmd](https://docs.rs/trycmd)
- Pull the `.rs` and `.md` file into the appropriate module doc comment to be accessible on docs.rs
New examples:
- Building: They must be added to [Cargo.toml](../../Cargo.toml) with the appropriate `required-features`.
- Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax
- Link the `.md` file from here
See also the general [CONTRIBUTING](../CONTRIBUTING.md).

Просмотреть файл

@ -1,3 +1,5 @@
*Jump to [source](cargo-example-derive.rs)*
For more on creating a custom subcommand, see [the cargo
book](https://doc.rust-lang.org/cargo/reference/external-tools.html#custom-subcommands).
The crate [`clap-cargo`](https://github.com/crate-ci/clap-cargo) can help in
@ -6,24 +8,29 @@ mimicking cargo's interface.
The help looks like:
```console
$ cargo-example-derive --help
Usage: cargo <COMMAND>
cargo
Commands:
example-derive A simple to use, efficient, and full-featured Command Line Argument Parser
help Print this message or the help of the given subcommand(s)
USAGE:
cargo <SUBCOMMAND>
Options:
-h, --help Print help
OPTIONS:
-h, --help Print help information
SUBCOMMANDS:
example-derive A simple to use, efficient, and full-featured Command Line Argument Parser
help Print this message or the help of the given subcommand(s)
$ cargo-example-derive example-derive --help
cargo-example-derive [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: cargo example-derive [OPTIONS]
USAGE:
cargo example-derive [OPTIONS]
Options:
--manifest-path <MANIFEST_PATH>
-h, --help Print help
-V, --version Print version
OPTIONS:
-h, --help Print help information
--manifest-path <MANIFEST_PATH>
-V, --version Print version information
```

Просмотреть файл

@ -1,20 +1,22 @@
// Note: this requires the `derive` feature
use clap::Parser;
#[derive(Parser)] // requires `derive` feature
#[command(name = "cargo")]
#[command(bin_name = "cargo")]
enum CargoCli {
ExampleDerive(ExampleDeriveArgs),
#[derive(Parser)]
#[clap(name = "cargo")]
#[clap(bin_name = "cargo")]
enum Cargo {
ExampleDerive(ExampleDerive),
}
#[derive(clap::Args)]
#[command(author, version, about, long_about = None)]
struct ExampleDeriveArgs {
#[arg(long)]
#[clap(author, version, about, long_about = None)]
struct ExampleDerive {
#[clap(long, parse(from_os_str))]
manifest_path: Option<std::path::PathBuf>,
}
fn main() {
let CargoCli::ExampleDerive(args) = CargoCli::parse();
let Cargo::ExampleDerive(args) = Cargo::parse();
println!("{:?}", args.manifest_path);
}

Просмотреть файл

@ -1,3 +1,5 @@
*Jump to [source](cargo-example.rs)*
For more on creating a custom subcommand, see [the cargo
book](https://doc.rust-lang.org/cargo/reference/external-tools.html#custom-subcommands).
The crate [`clap-cargo`](https://github.com/crate-ci/clap-cargo) can help in
@ -6,24 +8,29 @@ mimicking cargo's interface.
The help looks like:
```console
$ cargo-example --help
Usage: cargo <COMMAND>
cargo
Commands:
example A simple to use, efficient, and full-featured Command Line Argument Parser
help Print this message or the help of the given subcommand(s)
USAGE:
cargo <SUBCOMMAND>
Options:
-h, --help Print help
OPTIONS:
-h, --help Print help information
SUBCOMMANDS:
example A simple to use, efficient, and full-featured Command Line Argument Parser
help Print this message or the help of the given subcommand(s)
$ cargo-example example --help
cargo-example [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: cargo example [OPTIONS]
USAGE:
cargo example [OPTIONS]
Options:
--manifest-path <PATH>
-h, --help Print help
-V, --version Print version
OPTIONS:
-h, --help Print help information
--manifest-path <PATH>
-V, --version Print version information
```

Просмотреть файл

@ -1,3 +1,5 @@
// Note: this requires the `cargo` feature
fn main() {
let cmd = clap::Command::new("cargo")
.bin_name("cargo")
@ -5,7 +7,8 @@ fn main() {
.subcommand(
clap::command!("example").arg(
clap::arg!(--"manifest-path" <PATH>)
.value_parser(clap::value_parser!(std::path::PathBuf)),
.required(false)
.allow_invalid_utf8(true),
),
);
let matches = cmd.get_matches();
@ -13,6 +16,8 @@ fn main() {
Some(("example", matches)) => matches,
_ => unreachable!("clap should ensure we don't get here"),
};
let manifest_path = matches.get_one::<std::path::PathBuf>("manifest-path");
let manifest_path = matches
.value_of_os("manifest-path")
.map(std::path::PathBuf::from);
println!("{:?}", manifest_path);
}

23
third_party/rust/clap/examples/demo.md поставляемый
Просмотреть файл

@ -1,17 +1,20 @@
*Jump to [source](demo.rs)*
**This requires enabling the `derive` feature flag.**
Used to validate README.md's content
```console
$ demo --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: demo[EXE] [OPTIONS] --name <NAME>
USAGE:
demo[EXE] [OPTIONS] --name <NAME>
Options:
-n, --name <NAME> Name of the person to greet
-c, --count <COUNT> Number of times to greet [default: 1]
-h, --help Print help
-V, --version Print version
$ demo --name Me
Hello Me!
OPTIONS:
-c, --count <COUNT> Number of times to greet [default: 1]
-h, --help Print help information
-n, --name <NAME> Name of the person to greet
-V, --version Print version information
```
*(version number and `.exe` extension on windows replaced by placeholders)*

8
third_party/rust/clap/examples/demo.rs поставляемый
Просмотреть файл

@ -1,15 +1,17 @@
// Note: this requires the `derive` feature
use clap::Parser;
/// Simple program to greet a person
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
#[clap(author, version, about, long_about = None)]
struct Args {
/// Name of the person to greet
#[arg(short, long)]
#[clap(short, long)]
name: String,
/// Number of times to greet
#[arg(short, long, default_value_t = 1)]
#[clap(short, long, default_value_t = 1)]
count: u8,
}

429
third_party/rust/clap/examples/derive_ref/README.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,429 @@
# Derive Reference
1. [Overview](#overview)
2. [Attributes](#attributes)
1. [Terminology](#terminology)
2. [Command Attributes](#command-attributes)
3. [Arg Attributes](#arg-attributes)
4. [Arg Enum Attributes](#arg-enum-attributes)
5. [Possible Value Attributes](#possible-value-attributes)
3. [Arg Types](#arg-types)
4. [Doc Comments](#doc-comments)
5. [Tips](#tips)
6. [Mixing Builder and Derive APIS](#mixing-builder-and-derive-apis)
## Overview
To derive `clap` types, you need to enable the `derive` feature flag.
See [demo.rs](../demo.rs) and [demo.md](../demo.md) for a brief example.
Let's start by breaking down the anatomy of the derive attributes:
```rust
use clap::{Parser, Args, Subcommand, ArgEnum};
/// Doc comment
#[derive(Parser)]
#[clap(APP ATTRIBUTE)]
struct Cli {
/// Doc comment
#[clap(ARG ATTRIBUTE)]
field: UserType,
#[clap(arg_enum, ARG ATTRIBUTE...)]
field: EnumValues,
#[clap(flatten)]
delegate: Struct,
#[clap(subcommand)]
command: Command,
}
/// Doc comment
#[derive(Args)]
#[clap(PARENT APP ATTRIBUTE)]
struct Struct {
/// Doc comment
#[clap(ARG ATTRIBUTE)]
field: UserType,
}
/// Doc comment
#[derive(Subcommand)]
#[clap(PARENT APP ATTRIBUTE)]
enum Command {
/// Doc comment
#[clap(APP ATTRIBUTE)]
Variant1(Struct),
/// Doc comment
#[clap(APP ATTRIBUTE)]
Variant2 {
/// Doc comment
#[clap(ARG ATTRIBUTE)]
field: UserType,
}
}
/// Doc comment
#[derive(ArgEnum)]
#[clap(ARG ENUM ATTRIBUTE)]
enum EnumValues {
/// Doc comment
#[clap(POSSIBLE VALUE ATTRIBUTE)]
Variant1,
}
fn main() {
let cli = Cli::parse();
}
```
- `Parser` parses arguments into a `struct` (arguments) or `enum` (subcommands).
- `Args` allows defining a set of re-usable arguments that get merged into their parent container.
- `Subcommand` defines available subcommands.
- Subcommand arguments can be defined in a struct-variant or automatically flattened with a tuple-variant.
- `ArgEnum` allows parsing a value directly into an `enum`, erroring on unsupported values.
- The derive doesn't work on enums that contain non-unit variants, unless they are skipped
See also the [tutorial](../tutorial_derive/README.md) and [examples](../README.md).
## Attributes
### Terminology
**Raw attributes** are forwarded directly to the underlying `clap` builder. Any
`Command`, `Arg`, or `PossibleValue` method can be used as an attribute.
Raw attributes come in two different syntaxes:
```rust
#[clap(
global = true, // name = arg form, neat for one-arg methods
required_if_eq("out", "file") // name(arg1, arg2, ...) form.
)]
```
- `method = arg` can only be used for methods which take only one argument.
- `method(arg1, arg2)` can be used with any method.
As long as `method_name` is not one of the magical methods - it will be
translated into a mere method call.
**Magic attributes** have post-processing done to them, whether that is
- Providing of defaults
- Special behavior is triggered off of it
Magic attributes are more constrained in the syntax they support, usually just
`<attr> = <value>` though some use `<attr>(<value>)` instead. See the specific
magic attributes documentation for details. This allows users to access the
raw behavior of an attribute via `<attr>(<value>)` syntax.
**NOTE:** Some attributes are inferred from [Arg Types](#arg-types) and [Doc
Comments](#doc-comments). Explicit attributes take precedence over inferred
attributes.
### Command Attributes
These correspond to a `clap::Command` which is used for both top-level parsers and
when defining subcommands.
**Magic attributes:**
- `name = <expr>`: `clap::Command::name`
- When not present: [crate `name`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-name-field) (`Parser` container), variant name (`Subcommand` variant)
- `version [= <expr>]`: `clap::Command::version`
- When not present: no version set
- Without `<expr>`: defaults to [crate `version`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field)
- `author [= <expr>]`: `clap::Command::author`
- When not present: no author set
- Without `<expr>`: defaults to [crate `authors`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-authors-field)
- `about [= <expr>]`: `clap::Command::about`
- When not present: [Doc comment summary](#doc-comments)
- Without `<expr>`: [crate `description`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-description-field) (`Parser` container)
- **TIP:** When a doc comment is also present, you most likely want to add
`#[clap(long_about = None)]` to clear the doc comment so only `about`
gets shown with both `-h` and `--help`.
- `long_about = <expr>`: `clap::Command::long_about`
- When not present: [Doc comment](#doc-comments) if there is a blank line, else nothing
- `verbatim_doc_comment`: Minimizes pre-processing when converting doc comments to `about` / `long_about`
- `next_display_order`: `clap::Command::next_display_order`
- `next_help_heading`: `clap::Command::next_help_heading`
- When `flatten`ing `Args`, this is scoped to just the args in this struct and any struct `flatten`ed into it
- `rename_all = <expr>`: Override default field / variant name case conversion for `Command::name` / `Arg::name`
- When not present: `kebab-case`
- Available values: `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `snake_case`, `lower`, `UPPER`, `verbatim`
- `rename_all_env = <expr>`: Override default field name case conversion for env variables for `clap::Arg::env`
- When not present: `SCREAMING_SNAKE_CASE`
- Available values: `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `snake_case`, `lower`, `UPPER`, `verbatim`
And for `Subcommand` variants:
- `skip`: Ignore this variant
- `flatten`: Delegates to the variant for more subcommands (must implement `Subcommand`)
- `subcommand`: Nest subcommands under the current set of subcommands (must implement `Subcommand`)
- `external_subcommand`: `clap::Command::allow_external_subcommand(true)`
- Variant must be either `Variant(Vec<String>)` or `Variant(Vec<OsString>)`
**Raw attributes:** Any [`Command` method](https://docs.rs/clap/latest/clap/type.Command.html) can also be used as an attribute, see [Terminology](#terminology) for syntax.
- e.g. `#[clap(arg_required_else_help(true))]` would translate to `cmd.arg_required_else_help(true)`
### Arg Attributes
These correspond to a `clap::Arg`.
**Magic attributes**:
- `name = <expr>`: `clap::Arg::new`
- When not present: case-converted field name is used
- `help = <expr>`: `clap::Arg::help`
- When not present: [Doc comment summary](#doc-comments)
- `long_help = <expr>`: `clap::Arg::long_help`
- When not present: [Doc comment](#doc-comments) if there is a blank line, else nothing
- `verbatim_doc_comment`: Minimizes pre-processing when converting doc comments to `help` / `long_help`
- `short [= <char>]`: `clap::Arg::short`
- When not present: no short set
- Without `<char>`: defaults to first character in the case-converted field name
- `long [= <str>]`: `clap::Arg::long`
- When not present: no long set
- Without `<str>`: defaults to the case-converted field name
- `env [= <str>]`: `clap::Arg::env` (needs `env` feature enabled)
- When not present: no env set
- Without `<str>`: defaults to the case-converted field name
- `flatten`: Delegates to the field for more arguments (must implement `Args`)
- Only `help_heading` can be used with `flatten`. See
[clap-rs/clap#3269](https://github.com/clap-rs/clap/issues/3269) for why
arg attributes are not generally supported.
- **Tip:** Though we do apply a flattened `Args`'s Parent Command Attributes, this
makes reuse harder. Generally prefer putting the cmd attributes on the `Parser`
or on the flattened field.
- `subcommand`: Delegates definition of subcommands to the field (must implement `Subcommand`)
- When `Option<T>`, the subcommand becomes optional
- `from_global`: Read a `clap::Arg::global` argument (raw attribute), regardless of what subcommand you are in
- `parse(<kind> [= <function>])`: `clap::Arg::validator` and `clap::ArgMatches::values_of_t`
- Default: `try_from_str`
- Warning: for `Path` / `OsString`, be sure to use `try_from_os_str`
- See [Arg Types](#arg-types) for more details
- `arg_enum`: Parse the value using the `ArgEnum` trait
- `skip [= <expr>]`: Ignore this field, filling in with `<expr>`
- Without `<expr>`: fills the field with `Default::default()`
- `default_value = <str>`: `clap::Arg::default_value` and `clap::Arg::required(false)`
- `default_value_t [= <expr>]`: `clap::Arg::default_value` and `clap::Arg::required(false)`
- Requires `std::fmt::Display` or `#[clap(arg_enum)]`
- Without `<expr>`, relies on `Default::default()`
- `default_value_os_t [= <expr>]`: `clap::Arg::default_value_os` and `clap::Arg::required(false)`
- Requires `std::convert::Into<OsString>` or `#[clap(arg_enum)]`
- Without `<expr>`, relies on `Default::default()`
**Raw attributes:** Any [`Arg` method](https://docs.rs/clap/latest/clap/struct.Arg.html) can also be used as an attribute, see [Terminology](#terminology) for syntax.
- e.g. `#[clap(max_values(3))]` would translate to `arg.max_values(3)`
### Arg Enum Attributes
- `rename_all = <expr>`: Override default field / variant name case conversion for `PossibleValue::new`
- When not present: `kebab-case`
- Available values: `camelCase`, `kebab-case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `snake_case`, `lower`, `UPPER`, `verbatim`
### Possible Value Attributes
These correspond to a `clap::PossibleValue`.
**Magic attributes**:
- `name = <expr>`: `clap::PossibleValue::new`
- When not present: case-converted field name is used
- `help = <expr>`: `clap::PossibleValue::help`
- When not present: [Doc comment summary](#doc-comments)
**Raw attributes:** Any [`PossibleValue` method](https://docs.rs/clap/latest/clap/struct.PossibleValue.html) can also be used as an attribute, see [Terminology](#terminology) for syntax.
- e.g. `#[clap(alias("foo"))]` would translate to `pv.alias("foo")`
## Arg Types
`clap` assumes some intent based on the type used:
| Type | Effect | Implies |
|---------------------|--------------------------------------|------------------------------------------------------------------|
| `bool` | flag | `#[clap(parse(from_flag))]` |
| `Option<T>` | optional argument | `.takes_value(true).required(false)` |
| `Option<Option<T>>` | optional value for optional argument | `.takes_value(true).required(false).min_values(0).max_values(1)` |
| `T` | required argument | `.takes_value(true).required(!has_default)` |
| `Vec<T>` | `0..` occurrences of argument | `.takes_value(true).required(false).multiple_occurrences(true)` |
| `Option<Vec<T>>` | `0..` occurrences of argument | `.takes_value(true).required(false).multiple_occurrences(true)` |
Notes:
- For custom type behavior, you can override the implied attributes/settings and/or set additional ones
- For example, see [custom-bool](./custom-bool.md)
- `Option<Vec<T>>` will be `None` instead of `vec![]` if no arguments are provided.
- This gives the user some flexibility in designing their argument, like with `min_values(0)`
You can then support your custom type with `#[clap(parse(<kind> [= <function>]))]`:
| `<kind>` | Signature | Default `<function>` |
|--------------------------|---------------------------------------|---------------------------------|
| `from_str` | `fn(&str) -> T` | `::std::convert::From::from` |
| `try_from_str` (default) | `fn(&str) -> Result<T, E>` | `::std::str::FromStr::from_str` |
| `from_os_str` | `fn(&OsStr) -> T` | `::std::convert::From::from` |
| `try_from_os_str` | `fn(&OsStr) -> Result<T, OsString>` | (no default function) |
| `from_occurrences` | `fn(u64) -> T` | `value as T` |
| `from_flag` | `fn(bool) -> T` | `::std::convert::From::from` |
Notes:
- `from_os_str`:
- Implies `arg.takes_value(true).allow_invalid_utf8(true)`
- `try_from_os_str`:
- Implies `arg.takes_value(true).allow_invalid_utf8(true)`
- `from_occurrences`:
- Implies `arg.takes_value(false).multiple_occurrences(true)`
- Reads from `clap::ArgMatches::occurrences_of` rather than a `value_of` function
- Note: operations on values, like `default_value`, are unlikely to do what you want
- `from_flag`
- Implies `arg.takes_value(false)`
- Reads from `clap::ArgMatches::is_present` rather than a `value_of` function
- Note: operations on values, like `default_value`, are unlikely to do what you want
**Warning:**
- To support non-UTF8 paths, you must use `parse(from_os_str)`, otherwise
`clap` will use `clap::ArgMatches::value_of` with `PathBuf::FromStr`.
## Doc Comments
In clap, help messages for the whole binary can be specified
via [`Command::about`] and [`Command::long_about`] while help messages
for individual arguments can be specified via [`Arg::help`] and [`Arg::long_help`]".
`long_*` variants are used when user calls the program with
`--help` and "short" variants are used with `-h` flag.
```rust
# use clap::Parser;
#[derive(Parser)]
#[clap(about = "I am a program and I work, just pass `-h`", long_about = None)]
struct Foo {
#[clap(short, help = "Pass `-h` and you'll see me!")]
bar: String,
}
```
For convenience, doc comments can be used instead of raw methods
(this example works exactly like the one above):
```rust
# use clap::Parser;
#[derive(Parser)]
/// I am a program and I work, just pass `-h`
struct Foo {
/// Pass `-h` and you'll see me!
bar: String,
}
```
**NOTE:** Attributes have priority over doc comments!
**Top level doc comments always generate `Command::about/long_about` calls!**
If you really want to use the `Command::about/long_about` methods (you likely don't),
use the `about` / `long_about` attributes to override the calls generated from
the doc comment. To clear `long_about`, you can use
`#[clap(long_about = None)]`.
**TIP:** Set `#![deny(missing_docs)]` to catch missing `--help` documentation at compile time.
### Pre-processing
```rust
# use clap::Parser;
#[derive(Parser)]
/// Hi there, I'm Robo!
///
/// I like beeping, stumbling, eating your electricity,
/// and making records of you singing in a shower.
/// Pay up, or I'll upload it to youtube!
struct Robo {
/// Call my brother SkyNet.
///
/// I am artificial superintelligence. I won't rest
/// until I'll have destroyed humanity. Enjoy your
/// pathetic existence, you mere mortals.
#[clap(long)]
kill_all_humans: bool,
}
```
A doc comment consists of three parts:
- Short summary
- A blank line (whitespace only)
- Detailed description, all the rest
The summary corresponds with `Command::about` / `Arg::help`. When a blank line is
present, the whole doc comment will be passed to `Command::long_about` /
`Arg::long_help`. Or in other words, a doc may result in just a `Command::about` /
`Arg::help` or `Command::about` / `Arg::help` and `Command::long_about` /
`Arg::long_help`
In addition, when `verbatim_doc_comment` is not present, `clap` applies some preprocessing, including:
- Strip leading and trailing whitespace from every line, if present.
- Strip leading and trailing blank lines, if present.
- Interpret each group of non-empty lines as a word-wrapped paragraph.
We replace newlines within paragraphs with spaces to allow the output
to be re-wrapped to the terminal width.
- Strip any excess blank lines so that there is exactly one per paragraph break.
- If the first paragraph ends in exactly one period,
remove the trailing period (i.e. strip trailing periods but not trailing ellipses).
Sometimes you don't want this preprocessing to apply, for example the comment contains
some ASCII art or markdown tables, you would need to preserve LFs along with
blank lines and the leading/trailing whitespace. When you pass use the
`verbatim_doc_comment` magic attribute, you preserve
them.
**Note:** Keep in mind that `verbatim_doc_comment` will *still*
- Remove one leading space from each line, even if this attribute is present,
to allow for a space between `///` and the content.
- Remove leading and trailing blank lines
## Tips
- To get access to a `Command` call `CommandFactory::command` (implemented when deriving `Parser`)
- Proactively check for bad `Command` configurations by calling `Command::debug_assert` in a test ([example](../tutorial_derive/05_01_assert.rs))
## Mixing Builder and Derive APIs
The builder and derive APIs do not live in isolation. They can work together, which is especially helpful if some arguments can be specified at compile-time while others must be specified at runtime.
### Using derived arguments in a builder application
*[Jump to source](augment_args.rs)*
When using the derive API, you can `#[clap(flatten)]` a struct deriving `Args` into a struct deriving `Args` or `Parser`. This example shows how you can augment a `Command` instance created using the builder API with `Args` created using the derive API.
It uses the `Args::augment_args` method to add the arguments to the `Command` instance.
Crates such as [clap-verbosity-flag](https://github.com/rust-cli/clap-verbosity-flag) provide structs that implement `Args` or `Parser`. Without the technique shown in this example, it would not be possible to use such crates with the builder API. `augment_args` to the rescue!
### Using derived subcommands in a builder application
*[Jump to source](augment_subcommands.rs)*
When using the derive API, you can use `#[clap(subcommand)]` inside the struct to add subcommands. The type of the field is usually an enum that derived `Parser`. However, you can also add the subcommands in that enum to a `Command` instance created with the builder API.
It uses the `Subcommand::augment_subcommands` method to add the subcommands to the `Command` instance.
### Adding hand-implemented subcommands to a derived application
*[Jump to source](hand_subcommand.rs)*
When using the derive API, you can use `#[clap(subcommand)]` inside the struct to add subcommands. The type of the field is usually an enum that derived `Parser`. However, you can also implement the `Subcommand` trait manually on this enum (or any other type) and it can still be used inside the struct created with the derive API. The implementation of the `Subcommand` trait will use the builder API to add the subcommands to the `Command` instance created behind the scenes for you by the derive API.
Notice how in the previous example we used `augment_subcommands` on an enum that derived `Parser`, whereas now we implement `augment_subcommands` ourselves, but the derive API calls it automatically since we used the `#[clap(subcommand)]` attribute.
### Flattening hand-implemented args into a derived application
*[Jump to source](flatten_hand_args.rs)*
When using the derive API, you can use `#[clap(flatten)]` inside the struct to add arguments as if they were added directly to the containing struct. The type of the field is usually an struct that derived `Args`. However, you can also implement the `Args` trait manually on this struct (or any other type) and it can still be used inside the struct created with the derive API. The implementation of the `Args` trait will use the builder API to add the arguments to the `Command` instance created behind the scenes for you by the derive API.
Notice how in the example 1 we used `augment_args` on the struct that derived `Parser`, whereas now we implement `augment_args` ourselves, but the derive API calls it automatically since we used the `#[clap(flatten)]` attribute.

Просмотреть файл

@ -1,21 +1,21 @@
use clap::{arg, Args, Command, FromArgMatches as _};
use clap::{arg, Args as _, Command, FromArgMatches as _, Parser};
#[derive(Args, Debug)]
#[derive(Parser, Debug)]
struct DerivedArgs {
#[arg(short, long)]
#[clap(short, long)]
derived: bool,
}
fn main() {
let cli = Command::new("CLI").arg(arg!(-b - -built).action(clap::ArgAction::SetTrue));
let cli = Command::new("CLI").arg(arg!(-b - -built));
// Augment built args with derived args
let cli = DerivedArgs::augment_args(cli);
let matches = cli.get_matches();
println!("Value of built: {:?}", matches.get_flag("built"));
println!("Value of built: {:?}", matches.is_present("built"));
println!(
"Value of derived via ArgMatches: {:?}",
matches.get_flag("derived")
matches.is_present("derived")
);
// Since DerivedArgs implements FromArgMatches, we can extract it from the unstructured ArgMatches.
@ -23,5 +23,5 @@ fn main() {
let derived_matches = DerivedArgs::from_arg_matches(&matches)
.map_err(|err| err.exit())
.unwrap();
println!("Value of derived: {derived_matches:#?}");
println!("Value of derived: {:#?}", derived_matches);
}

Просмотреть файл

@ -3,7 +3,7 @@ use clap::{Command, FromArgMatches as _, Parser, Subcommand as _};
#[derive(Parser, Debug)]
enum Subcommands {
Derived {
#[arg(short, long)]
#[clap(short, long)]
derived_flag: bool,
},
}
@ -17,5 +17,5 @@ fn main() {
let derived_subcommands = Subcommands::from_arg_matches(&matches)
.map_err(|err| err.exit())
.unwrap();
println!("Derived subcommands: {derived_subcommands:#?}");
println!("Derived subcommands: {:#?}", derived_subcommands);
}

47
third_party/rust/clap/examples/derive_ref/custom-bool.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,47 @@
*Jump to [source](custom-bool.rs)*
Example of overriding the magic `bool` behavior
```console
$ custom-bool --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
custom-bool[EXE] [OPTIONS] --foo <FOO> <BOOM>
ARGS:
<BOOM>
OPTIONS:
--bar <BAR> [default: false]
--foo <FOO>
-h, --help Print help information
-V, --version Print version information
$ custom-bool
? failed
error: The following required arguments were not provided:
--foo <FOO>
<BOOM>
USAGE:
custom-bool[EXE] [OPTIONS] --foo <FOO> <BOOM>
For more information try --help
$ custom-bool --foo true false
[examples/derive_ref/custom-bool.rs:31] opt = Opt {
foo: true,
bar: false,
boom: false,
}
$ custom-bool --foo true --bar true false
[examples/derive_ref/custom-bool.rs:31] opt = Opt {
foo: true,
bar: true,
boom: false,
}
```

32
third_party/rust/clap/examples/derive_ref/custom-bool.rs поставляемый Normal file
Просмотреть файл

@ -0,0 +1,32 @@
use clap::Parser;
#[derive(Parser, Debug, PartialEq)]
#[clap(author, version, about, long_about = None)]
struct Opt {
// Default parser for `try_from_str` is FromStr::from_str.
// `impl FromStr for bool` parses `true` or `false` so this
// works as expected.
#[clap(long, parse(try_from_str))]
foo: bool,
// Of course, this could be done with an explicit parser function.
#[clap(long, parse(try_from_str = true_or_false), default_value_t)]
bar: bool,
// `bool` can be positional only with explicit `parse(...)` annotation
#[clap(parse(try_from_str))]
boom: bool,
}
fn true_or_false(s: &str) -> Result<bool, &'static str> {
match s {
"true" => Ok(true),
"false" => Ok(false),
_ => Err("expected `true` or `false`"),
}
}
fn main() {
let opt = Opt::parse();
dbg!(opt);
}

Просмотреть файл

@ -1,5 +1,5 @@
use clap::error::Error;
use clap::{Arg, ArgAction, ArgMatches, Args, Command, FromArgMatches, Parser};
use clap::{Arg, ArgMatches, Args, Command, FromArgMatches, Parser};
#[derive(Debug)]
struct CliArgs {
@ -10,82 +10,44 @@ struct CliArgs {
impl FromArgMatches for CliArgs {
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
let mut matches = matches.clone();
Self::from_arg_matches_mut(&mut matches)
}
fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
Ok(Self {
foo: matches.get_flag("foo"),
bar: matches.get_flag("bar"),
quuz: matches.remove_one::<String>("quuz"),
foo: matches.is_present("foo"),
bar: matches.is_present("bar"),
quuz: matches.value_of("quuz").map(|quuz| quuz.to_owned()),
})
}
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
let mut matches = matches.clone();
self.update_from_arg_matches_mut(&mut matches)
}
fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> {
self.foo |= matches.get_flag("foo");
self.bar |= matches.get_flag("bar");
if let Some(quuz) = matches.remove_one::<String>("quuz") {
self.quuz = Some(quuz);
self.foo |= matches.is_present("foo");
self.bar |= matches.is_present("bar");
if let Some(quuz) = matches.value_of("quuz") {
self.quuz = Some(quuz.to_owned());
}
Ok(())
}
}
impl Args for CliArgs {
fn augment_args(cmd: Command) -> Command {
cmd.arg(
Arg::new("foo")
.short('f')
.long("foo")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("bar")
.short('b')
.long("bar")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("quuz")
.short('q')
.long("quuz")
.action(ArgAction::Set),
)
fn augment_args(cmd: Command<'_>) -> Command<'_> {
cmd.arg(Arg::new("foo").short('f').long("foo"))
.arg(Arg::new("bar").short('b').long("bar"))
.arg(Arg::new("quuz").short('q').long("quuz").takes_value(true))
}
fn augment_args_for_update(cmd: Command) -> Command {
cmd.arg(
Arg::new("foo")
.short('f')
.long("foo")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("bar")
.short('b')
.long("bar")
.action(ArgAction::SetTrue),
)
.arg(
Arg::new("quuz")
.short('q')
.long("quuz")
.action(ArgAction::Set),
)
fn augment_args_for_update(cmd: Command<'_>) -> Command<'_> {
cmd.arg(Arg::new("foo").short('f').long("foo"))
.arg(Arg::new("bar").short('b').long("bar"))
.arg(Arg::new("quuz").short('q').long("quuz").takes_value(true))
}
}
#[derive(Parser, Debug)]
struct Cli {
#[arg(short, long)]
#[clap(short, long)]
top_level: bool,
#[command(flatten)]
#[clap(flatten)]
more_args: CliArgs,
}
fn main() {
let args = Cli::parse();
println!("{args:#?}");
println!("{:#?}", args);
}

Просмотреть файл

@ -7,7 +7,7 @@ struct AddArgs {
}
#[derive(Parser, Debug)]
struct RemoveArgs {
#[arg(short, long)]
#[clap(short, long)]
force: bool,
name: Vec<String>,
}
@ -24,7 +24,7 @@ impl FromArgMatches for CliSub {
Some(("add", args)) => Ok(Self::Add(AddArgs::from_arg_matches(args)?)),
Some(("remove", args)) => Ok(Self::Remove(RemoveArgs::from_arg_matches(args)?)),
Some((_, _)) => Err(Error::raw(
ErrorKind::InvalidSubcommand,
ErrorKind::UnrecognizedSubcommand,
"Valid subcommands are `add` and `remove`",
)),
None => Err(Error::raw(
@ -39,7 +39,7 @@ impl FromArgMatches for CliSub {
Some(("remove", args)) => *self = Self::Remove(RemoveArgs::from_arg_matches(args)?),
Some((_, _)) => {
return Err(Error::raw(
ErrorKind::InvalidSubcommand,
ErrorKind::UnrecognizedSubcommand,
"Valid subcommands are `add` and `remove`",
))
}
@ -50,12 +50,12 @@ impl FromArgMatches for CliSub {
}
impl Subcommand for CliSub {
fn augment_subcommands(cmd: Command) -> Command {
fn augment_subcommands(cmd: Command<'_>) -> Command<'_> {
cmd.subcommand(AddArgs::augment_args(Command::new("add")))
.subcommand(RemoveArgs::augment_args(Command::new("remove")))
.subcommand_required(true)
}
fn augment_subcommands_for_update(cmd: Command) -> Command {
fn augment_subcommands_for_update(cmd: Command<'_>) -> Command<'_> {
cmd.subcommand(AddArgs::augment_args(Command::new("add")))
.subcommand(RemoveArgs::augment_args(Command::new("remove")))
.subcommand_required(true)
@ -67,13 +67,13 @@ impl Subcommand for CliSub {
#[derive(Parser, Debug)]
struct Cli {
#[arg(short, long)]
#[clap(short, long)]
top_level: bool,
#[command(subcommand)]
#[clap(subcommand)]
subcommand: CliSub,
}
fn main() {
let args = Cli::parse();
println!("{args:#?}");
println!("{:#?}", args);
}

Просмотреть файл

@ -35,11 +35,14 @@ Value of derived: DerivedArgs {
```console
$ interop_augment_args --unknown
? failed
error: unexpected argument '--unknown' found
error: Found argument '--unknown' which wasn't expected, or isn't valid in this context
Usage: interop_augment_args[EXE] [OPTIONS]
If you tried to supply `--unknown` as a value rather than a flag, use `-- --unknown`
For more information, try '--help'.
USAGE:
interop_augment_args[EXE] [OPTIONS]
For more information try --help
```
@ -70,22 +73,26 @@ Derived subcommands: Derived {
```console
$ interop_augment_subcommands derived --unknown
? failed
error: unexpected argument '--unknown' found
error: Found argument '--unknown' which wasn't expected, or isn't valid in this context
Usage: interop_augment_subcommands[EXE] derived [OPTIONS]
If you tried to supply `--unknown` as a value rather than a flag, use `-- --unknown`
For more information, try '--help'.
USAGE:
interop_augment_subcommands[EXE] derived [OPTIONS]
For more information try --help
```
```console
$ interop_augment_subcommands unknown
? failed
error: unrecognized subcommand 'unknown'
error: Found argument 'unknown' which wasn't expected, or isn't valid in this context
Usage: interop_augment_subcommands[EXE] [COMMAND]
USAGE:
interop_augment_subcommands[EXE] [SUBCOMMAND]
For more information, try '--help'.
For more information try --help
```
@ -94,16 +101,12 @@ For more information, try '--help'.
```console
$ interop_hand_subcommand
? failed
Usage: interop_hand_subcommand[EXE] [OPTIONS] <COMMAND>
error: 'interop_hand_subcommand[EXE]' requires a subcommand but one was not provided
Commands:
add
remove
help Print this message or the help of the given subcommand(s)
USAGE:
interop_hand_subcommand[EXE] [OPTIONS] <SUBCOMMAND>
Options:
-t, --top-level
-h, --help Print help
For more information try --help
```
@ -140,13 +143,14 @@ Cli {
```console
$ interop_hand_subcommand add --unknown
? failed
error: unexpected argument '--unknown' found
error: Found argument '--unknown' which wasn't expected, or isn't valid in this context
note: to pass '--unknown' as a value, use '-- --unknown'
If you tried to supply `--unknown` as a value rather than a flag, use `-- --unknown`
Usage: interop_hand_subcommand[EXE] add [NAME]...
USAGE:
interop_hand_subcommand[EXE] add [NAME]...
For more information, try '--help'.
For more information try --help
```
@ -185,11 +189,12 @@ Cli {
```console
$ interop_hand_subcommand unknown
? failed
error: unrecognized subcommand 'unknown'
error: Found argument 'unknown' which wasn't expected, or isn't valid in this context
Usage: interop_hand_subcommand[EXE] [OPTIONS] <COMMAND>
USAGE:
interop_hand_subcommand[EXE] [OPTIONS] <SUBCOMMAND>
For more information, try '--help'.
For more information try --help
```
@ -239,10 +244,13 @@ Cli {
```console
$ interop_flatten_hand_args --unknown
? failed
error: unexpected argument '--unknown' found
error: Found argument '--unknown' which wasn't expected, or isn't valid in this context
Usage: interop_flatten_hand_args[EXE] [OPTIONS]
If you tried to supply `--unknown` as a value rather than a flag, use `-- --unknown`
For more information, try '--help'.
USAGE:
interop_flatten_hand_args[EXE] [OPTIONS]
For more information try --help
```

Просмотреть файл

@ -1,22 +1,26 @@
**This requires enabling the [`derive` feature flag][crate::_features].**
*Jump to [source](escaped-positional-derive.rs)*
**This requires enabling the `derive` feature flag.**
You can use `--` to escape further arguments.
Let's see what this looks like in the help:
```console
$ escaped-positional-derive --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: escaped-positional-derive[EXE] [OPTIONS] [-- <SLOP>...]
USAGE:
escaped-positional-derive[EXE] [OPTIONS] [-- <SLOP>...]
Arguments:
[SLOP]...
ARGS:
<SLOP>...
Options:
-f
-p <PEAR>
-h, --help Print help
-V, --version Print version
OPTIONS:
-f
-h, --help Print help information
-p <PEAR>
-V, --version Print version information
```
@ -33,11 +37,12 @@ Notice that we can't pass positional arguments before `--`:
```console
$ escaped-positional-derive foo bar
? failed
error: unexpected argument 'foo' found
error: Found argument 'foo' which wasn't expected, or isn't valid in this context
Usage: escaped-positional-derive[EXE] [OPTIONS] [-- <SLOP>...]
USAGE:
escaped-positional-derive[EXE] [OPTIONS] [-- <SLOP>...]
For more information, try '--help'.
For more information try --help
```

Просмотреть файл

@ -1,15 +1,17 @@
// Note: this requires the `derive` feature
use clap::Parser;
#[derive(Parser)] // requires `derive` feature
#[command(author, version, about, long_about = None)]
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
struct Cli {
#[arg(short = 'f')]
#[clap(short = 'f')]
eff: bool,
#[arg(short = 'p', value_name = "PEAR")]
#[clap(short = 'p', value_name = "PEAR")]
pea: Option<String>,
#[arg(last = true)]
#[clap(last = true)]
slop: Vec<String>,
}

Просмотреть файл

@ -1,22 +1,26 @@
**This requires enabling the [`cargo` feature flag][crate::_features].**
*Jump to [source](escaped-positional.rs)*
**This requires enabling the `cargo` feature flag.**
You can use `--` to escape further arguments.
Let's see what this looks like in the help:
```console
$ escaped-positional --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: escaped-positional[EXE] [OPTIONS] [-- <SLOP>...]
USAGE:
escaped-positional[EXE] [OPTIONS] [-- <SLOP>...]
Arguments:
[SLOP]...
ARGS:
<SLOP>...
Options:
-f
-p <PEAR>
-h, --help Print help
-V, --version Print version
OPTIONS:
-f
-h, --help Print help information
-p <PEAR>
-V, --version Print version information
```
@ -33,11 +37,12 @@ Notice that we can't pass positional arguments before `--`:
```console
$ escaped-positional foo bar
? failed
error: unexpected argument 'foo' found
error: Found argument 'foo' which wasn't expected, or isn't valid in this context
Usage: escaped-positional[EXE] [OPTIONS] [-- <SLOP>...]
USAGE:
escaped-positional[EXE] [OPTIONS] [-- <SLOP>...]
For more information, try '--help'.
For more information try --help
```

Просмотреть файл

@ -1,32 +1,26 @@
use clap::{arg, command, value_parser, ArgAction};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = command!() // requires `cargo` feature
.arg(arg!(eff: -f).action(ArgAction::SetTrue))
.arg(arg!(pea: -p <PEAR>).value_parser(value_parser!(String)))
let matches = command!()
.arg(arg!(eff: -f))
.arg(arg!(pea: -p <PEAR>).required(false))
.arg(
// Indicates that `slop` is only accessible after `--`.
arg!(slop: [SLOP])
.num_args(1..)
.last(true)
.value_parser(value_parser!(String)),
arg!(slop: [SLOP]).multiple_occurrences(true).last(true), // Indicates that `slop` is only accessible after `--`.
)
.get_matches();
// This is what will happen with `myprog -f -p=bob -- sloppy slop slop`...
// -f used: true
println!("-f used: {:?}", matches.get_flag("eff"));
// -p's value: Some("bob")
println!("-p's value: {:?}", matches.get_one::<String>("pea"));
// 'slops' values: Some(["sloppy", "slop", "slop"])
println!("-f used: {:?}", matches.is_present("eff")); // -f used: true
println!("-p's value: {:?}", matches.value_of("pea")); // -p's value: Some("bob")
println!(
"'slops' values: {:?}",
matches
.get_many::<String>("slop")
.values_of("slop")
.map(|vals| vals.collect::<Vec<_>>())
.unwrap_or_default()
);
); // 'slops' values: Some(["sloppy", "slop", "slop"])
// Continued program logic goes here...
}

45
third_party/rust/clap/examples/find.md поставляемый
Просмотреть файл

@ -1,45 +0,0 @@
`find` is an example of position-sensitive flags
```console
$ find --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: find[EXE] [OPTIONS]
Options:
-h, --help Print help
-V, --version Print version
TESTS:
--empty File is empty and is either a regular file or a directory
--name <NAME> Base of file name (the path with the leading directories removed) matches shell
pattern pattern
OPERATORS:
-o, --or expr2 is not evaluate if exp1 is true
-a, --and Same as `expr1 expr1`
$ find --empty -o --name .keep
[
(
"empty",
Bool(
true,
),
),
(
"or",
Bool(
true,
),
),
(
"name",
String(
".keep",
),
),
]
```

99
third_party/rust/clap/examples/find.rs поставляемый
Просмотреть файл

@ -1,99 +0,0 @@
use std::collections::BTreeMap;
use clap::{arg, command, ArgGroup, ArgMatches, Command};
fn main() {
let matches = cli().get_matches();
let values = Value::from_matches(&matches);
println!("{:#?}", values);
}
fn cli() -> Command {
command!()
.group(ArgGroup::new("tests").multiple(true))
.next_help_heading("TESTS")
.args([
arg!(--empty "File is empty and is either a regular file or a directory").group("tests"),
arg!(--name <NAME> "Base of file name (the path with the leading directories removed) matches shell pattern pattern").group("tests"),
])
.group(ArgGroup::new("operators").multiple(true))
.next_help_heading("OPERATORS")
.args([
arg!(-o - -or "expr2 is not evaluate if exp1 is true").group("operators"),
arg!(-a - -and "Same as `expr1 expr1`").group("operators"),
])
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Value {
Bool(bool),
String(String),
}
impl Value {
pub fn from_matches(matches: &ArgMatches) -> Vec<(clap::Id, Self)> {
let mut values = BTreeMap::new();
for id in matches.ids() {
if matches.try_get_many::<clap::Id>(id.as_str()).is_ok() {
// ignore groups
continue;
}
let value_source = matches
.value_source(id.as_str())
.expect("id came from matches");
if value_source != clap::parser::ValueSource::CommandLine {
// Any other source just gets tacked on at the end (like default values)
continue;
}
if Self::extract::<String>(matches, id, &mut values) {
continue;
}
if Self::extract::<bool>(matches, id, &mut values) {
continue;
}
unimplemented!("unknown type for {}: {:?}", id, matches);
}
values.into_values().collect::<Vec<_>>()
}
fn extract<T: Clone + Into<Value> + Send + Sync + 'static>(
matches: &ArgMatches,
id: &clap::Id,
output: &mut BTreeMap<usize, (clap::Id, Self)>,
) -> bool {
match matches.try_get_many::<T>(id.as_str()) {
Ok(Some(values)) => {
for (value, index) in values.zip(
matches
.indices_of(id.as_str())
.expect("id came from matches"),
) {
output.insert(index, (id.clone(), value.clone().into()));
}
true
}
Ok(None) => {
unreachable!("`ids` only reports what is present")
}
Err(clap::parser::MatchesError::UnknownArgument { .. }) => {
unreachable!("id came from matches")
}
Err(clap::parser::MatchesError::Downcast { .. }) => false,
Err(_) => {
unreachable!("id came from matches")
}
}
}
}
impl From<String> for Value {
fn from(other: String) -> Self {
Self::String(other)
}
}
impl From<bool> for Value {
fn from(other: bool) -> Self {
Self::Bool(other)
}
}

157
third_party/rust/clap/examples/git-derive.md поставляемый
Просмотреть файл

@ -1,4 +1,6 @@
**This requires enabling the [`derive` feature flag][crate::_features].**
*Jump to [source](git-derive.rs)*
**This requires enabling the `derive` feature flag.**
Git is an example of several common subcommand patterns.
@ -6,47 +8,51 @@ Help:
```console
$ git-derive
? failed
git
A fictional versioning CLI
Usage: git-derive[EXE] <COMMAND>
USAGE:
git-derive[EXE] <SUBCOMMAND>
Commands:
clone Clones repos
diff Compare two commits
push pushes things
add adds things
stash
help Print this message or the help of the given subcommand(s)
OPTIONS:
-h, --help Print help information
Options:
-h, --help Print help
SUBCOMMANDS:
add adds things
clone Clones repos
help Print this message or the help of the given subcommand(s)
push pushes things
stash
$ git-derive help
git
A fictional versioning CLI
Usage: git-derive[EXE] <COMMAND>
USAGE:
git-derive[EXE] <SUBCOMMAND>
Commands:
clone Clones repos
diff Compare two commits
push pushes things
add adds things
stash
help Print this message or the help of the given subcommand(s)
OPTIONS:
-h, --help Print help information
Options:
-h, --help Print help
SUBCOMMANDS:
add adds things
clone Clones repos
help Print this message or the help of the given subcommand(s)
push pushes things
stash
$ git-derive help add
git-derive[EXE]-add
adds things
Usage: git-derive[EXE] add <PATH>...
USAGE:
git-derive[EXE] add <PATH>...
Arguments:
<PATH>... Stuff to add
ARGS:
<PATH>... Stuff to add
Options:
-h, --help Print help
OPTIONS:
-h, --help Print help information
```
@ -54,15 +60,17 @@ A basic argument:
```console
$ git-derive add
? failed
git-derive[EXE]-add
adds things
Usage: git-derive[EXE] add <PATH>...
USAGE:
git-derive[EXE] add <PATH>...
Arguments:
<PATH>... Stuff to add
ARGS:
<PATH>... Stuff to add
Options:
-h, --help Print help
OPTIONS:
-h, --help Print help information
$ git-derive add Cargo.toml Cargo.lock
Adding ["Cargo.toml", "Cargo.lock"]
@ -72,43 +80,52 @@ Adding ["Cargo.toml", "Cargo.lock"]
Default subcommand:
```console
$ git-derive stash -h
Usage: git-derive[EXE] stash [OPTIONS]
git-derive[EXE] stash <COMMAND>
git-derive[EXE]-stash
Commands:
push
pop
apply
help Print this message or the help of the given subcommand(s)
USAGE:
git-derive[EXE] stash [OPTIONS]
git-derive[EXE] stash <SUBCOMMAND>
Options:
-m, --message <MESSAGE>
-h, --help Print help
OPTIONS:
-h, --help Print help information
-m, --message <MESSAGE>
SUBCOMMANDS:
apply
help Print this message or the help of the given subcommand(s)
pop
push
$ git-derive stash push -h
Usage: git-derive[EXE] stash push [OPTIONS]
git-derive[EXE]-stash-push
Options:
-m, --message <MESSAGE>
-h, --help Print help
USAGE:
git-derive[EXE] stash push [OPTIONS]
OPTIONS:
-h, --help Print help information
-m, --message <MESSAGE>
$ git-derive stash pop -h
Usage: git-derive[EXE] stash pop [STASH]
git-derive[EXE]-stash-pop
Arguments:
[STASH]
USAGE:
git-derive[EXE] stash pop [STASH]
Options:
-h, --help Print help
ARGS:
<STASH>
OPTIONS:
-h, --help Print help information
$ git-derive stash -m "Prototype"
Pushing StashPushArgs { message: Some("Prototype") }
Pushing StashPush { message: Some("Prototype") }
$ git-derive stash pop
Popping None
$ git-derive stash push -m "Prototype"
Pushing StashPushArgs { message: Some("Prototype") }
Pushing StashPush { message: Some("Prototype") }
$ git-derive stash pop
Popping None
@ -121,39 +138,3 @@ $ git-derive custom-tool arg1 --foo bar
Calling out to "custom-tool" with ["arg1", "--foo", "bar"]
```
Last argument:
```console
$ git-derive diff --help
Compare two commits
Usage: git-derive[EXE] diff [OPTIONS] [COMMIT] [COMMIT] [-- <PATH>]
Arguments:
[COMMIT]
[COMMIT]
[PATH]
Options:
--color[=<WHEN>] [default: auto] [possible values: always, auto, never]
-h, --help Print help
$ git-derive diff
Diffing stage..worktree (color=auto)
$ git-derive diff ./src
Diffing stage..worktree ./src (color=auto)
$ git-derive diff HEAD ./src
Diffing HEAD..worktree ./src (color=auto)
$ git-derive diff HEAD~~ -- HEAD
Diffing HEAD~~..worktree HEAD (color=auto)
$ git-derive diff --color
Diffing stage..worktree (color=always)
$ git-derive diff --color=never
Diffing stage..worktree (color=never)
```

119
third_party/rust/clap/examples/git-derive.rs поставляемый
Просмотреть файл

@ -1,99 +1,65 @@
use std::ffi::OsStr;
// Note: this requires the `derive` feature
use std::ffi::OsString;
use std::path::PathBuf;
use clap::{Args, Parser, Subcommand, ValueEnum};
use clap::{Args, Parser, Subcommand};
/// A fictional versioning CLI
#[derive(Debug, Parser)] // requires `derive` feature
#[command(name = "git")]
#[command(about = "A fictional versioning CLI", long_about = None)]
#[derive(Debug, Parser)]
#[clap(name = "git")]
#[clap(about = "A fictional versioning CLI", long_about = None)]
struct Cli {
#[command(subcommand)]
#[clap(subcommand)]
command: Commands,
}
#[derive(Debug, Subcommand)]
enum Commands {
/// Clones repos
#[command(arg_required_else_help = true)]
#[clap(arg_required_else_help = true)]
Clone {
/// The remote to clone
remote: String,
},
/// Compare two commits
Diff {
#[arg(value_name = "COMMIT")]
base: Option<OsString>,
#[arg(value_name = "COMMIT")]
head: Option<OsString>,
#[arg(last = true)]
path: Option<OsString>,
#[arg(
long,
require_equals = true,
value_name = "WHEN",
num_args = 0..=1,
default_value_t = ColorWhen::Auto,
default_missing_value = "always",
value_enum
)]
color: ColorWhen,
},
/// pushes things
#[command(arg_required_else_help = true)]
#[clap(arg_required_else_help = true)]
Push {
/// The remote to target
remote: String,
},
/// adds things
#[command(arg_required_else_help = true)]
#[clap(arg_required_else_help = true)]
Add {
/// Stuff to add
#[arg(required = true)]
#[clap(required = true, parse(from_os_str))]
path: Vec<PathBuf>,
},
Stash(StashArgs),
#[command(external_subcommand)]
Stash(Stash),
#[clap(external_subcommand)]
External(Vec<OsString>),
}
#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)]
enum ColorWhen {
Always,
Auto,
Never,
}
impl std::fmt::Display for ColorWhen {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_possible_value()
.expect("no values are skipped")
.get_name()
.fmt(f)
}
}
#[derive(Debug, Args)]
#[command(args_conflicts_with_subcommands = true)]
struct StashArgs {
#[command(subcommand)]
#[clap(args_conflicts_with_subcommands = true)]
struct Stash {
#[clap(subcommand)]
command: Option<StashCommands>,
#[command(flatten)]
push: StashPushArgs,
#[clap(flatten)]
push: StashPush,
}
#[derive(Debug, Subcommand)]
enum StashCommands {
Push(StashPushArgs),
Push(StashPush),
Pop { stash: Option<String> },
Apply { stash: Option<String> },
}
#[derive(Debug, Args)]
struct StashPushArgs {
#[arg(short, long)]
struct StashPush {
#[clap(short, long)]
message: Option<String>,
}
@ -102,56 +68,25 @@ fn main() {
match args.command {
Commands::Clone { remote } => {
println!("Cloning {remote}");
}
Commands::Diff {
mut base,
mut head,
mut path,
color,
} => {
if path.is_none() {
path = head;
head = None;
if path.is_none() {
path = base;
base = None;
}
}
let base = base
.as_deref()
.map(|s| s.to_str().unwrap())
.unwrap_or("stage");
let head = head
.as_deref()
.map(|s| s.to_str().unwrap())
.unwrap_or("worktree");
let path = path.as_deref().unwrap_or_else(|| OsStr::new(""));
println!(
"Diffing {}..{} {} (color={})",
base,
head,
path.to_string_lossy(),
color
);
println!("Cloning {}", remote);
}
Commands::Push { remote } => {
println!("Pushing to {remote}");
println!("Pushing to {}", remote);
}
Commands::Add { path } => {
println!("Adding {path:?}");
println!("Adding {:?}", path);
}
Commands::Stash(stash) => {
let stash_cmd = stash.command.unwrap_or(StashCommands::Push(stash.push));
match stash_cmd {
StashCommands::Push(push) => {
println!("Pushing {push:?}");
println!("Pushing {:?}", push);
}
StashCommands::Pop { stash } => {
println!("Popping {stash:?}");
println!("Popping {:?}", stash);
}
StashCommands::Apply { stash } => {
println!("Applying {stash:?}");
println!("Applying {:?}", stash);
}
}
}

151
third_party/rust/clap/examples/git.md поставляемый
Просмотреть файл

@ -1,50 +1,56 @@
*Jump to [source](git.rs)*
Git is an example of several common subcommand patterns.
Help:
```console
$ git
? failed
git
A fictional versioning CLI
Usage: git[EXE] <COMMAND>
USAGE:
git[EXE] <SUBCOMMAND>
Commands:
clone Clones repos
diff Compare two commits
push pushes things
add adds things
stash
help Print this message or the help of the given subcommand(s)
OPTIONS:
-h, --help Print help information
Options:
-h, --help Print help
SUBCOMMANDS:
add adds things
clone Clones repos
help Print this message or the help of the given subcommand(s)
push pushes things
stash
$ git help
git
A fictional versioning CLI
Usage: git[EXE] <COMMAND>
USAGE:
git[EXE] <SUBCOMMAND>
Commands:
clone Clones repos
diff Compare two commits
push pushes things
add adds things
stash
help Print this message or the help of the given subcommand(s)
OPTIONS:
-h, --help Print help information
Options:
-h, --help Print help
SUBCOMMANDS:
add adds things
clone Clones repos
help Print this message or the help of the given subcommand(s)
push pushes things
stash
$ git help add
git[EXE]-add
adds things
Usage: git[EXE] add <PATH>...
USAGE:
git[EXE] add <PATH>...
Arguments:
<PATH>... Stuff to add
ARGS:
<PATH>... Stuff to add
Options:
-h, --help Print help
OPTIONS:
-h, --help Print help information
```
@ -52,15 +58,17 @@ A basic argument:
```console
$ git add
? failed
git[EXE]-add
adds things
Usage: git[EXE] add <PATH>...
USAGE:
git[EXE] add <PATH>...
Arguments:
<PATH>... Stuff to add
ARGS:
<PATH>... Stuff to add
Options:
-h, --help Print help
OPTIONS:
-h, --help Print help information
$ git add Cargo.toml Cargo.lock
Adding ["Cargo.toml", "Cargo.lock"]
@ -70,34 +78,43 @@ Adding ["Cargo.toml", "Cargo.lock"]
Default subcommand:
```console
$ git stash -h
Usage: git[EXE] stash [OPTIONS]
git[EXE] stash <COMMAND>
git[EXE]-stash
Commands:
push
pop
apply
help Print this message or the help of the given subcommand(s)
USAGE:
git[EXE] stash [OPTIONS]
git[EXE] stash <SUBCOMMAND>
Options:
-m, --message <MESSAGE>
-h, --help Print help
OPTIONS:
-h, --help Print help information
-m, --message <MESSAGE>
SUBCOMMANDS:
apply
help Print this message or the help of the given subcommand(s)
pop
push
$ git stash push -h
Usage: git[EXE] stash push [OPTIONS]
git[EXE]-stash-push
Options:
-m, --message <MESSAGE>
-h, --help Print help
USAGE:
git[EXE] stash push [OPTIONS]
OPTIONS:
-h, --help Print help information
-m, --message <MESSAGE>
$ git stash pop -h
Usage: git[EXE] stash pop [STASH]
git[EXE]-stash-pop
Arguments:
[STASH]
USAGE:
git[EXE] stash pop [STASH]
Options:
-h, --help Print help
ARGS:
<STASH>
OPTIONS:
-h, --help Print help information
$ git stash -m "Prototype"
Pushing Some("Prototype")
@ -119,39 +136,3 @@ $ git custom-tool arg1 --foo bar
Calling out to "custom-tool" with ["arg1", "--foo", "bar"]
```
Last argument:
```console
$ git diff --help
Compare two commits
Usage: git[EXE] diff [OPTIONS] [COMMIT] [COMMIT] [-- <PATH>]
Arguments:
[COMMIT]
[COMMIT]
[PATH]
Options:
--color[=<WHEN>] [default: auto] [possible values: always, auto, never]
-h, --help Print help
$ git diff
Diffing stage..worktree (color=auto)
$ git diff ./src
Diffing stage..worktree ./src (color=auto)
$ git diff HEAD ./src
Diffing HEAD..worktree ./src (color=auto)
$ git diff HEAD~~ -- HEAD
Diffing HEAD~~..worktree HEAD (color=auto)
$ git diff --color
Diffing stage..worktree (color=always)
$ git diff --color=never
Diffing stage..worktree (color=never)
```

82
third_party/rust/clap/examples/git.rs поставляемый
Просмотреть файл

@ -1,35 +1,22 @@
use std::ffi::OsString;
// Note: this requires the `cargo` feature
use std::path::PathBuf;
use clap::{arg, Command};
fn cli() -> Command {
fn cli() -> Command<'static> {
Command::new("git")
.about("A fictional versioning CLI")
.subcommand_required(true)
.arg_required_else_help(true)
.allow_external_subcommands(true)
.allow_invalid_utf8_for_external_subcommands(true)
.subcommand(
Command::new("clone")
.about("Clones repos")
.arg(arg!(<REMOTE> "The remote to clone"))
.arg_required_else_help(true),
)
.subcommand(
Command::new("diff")
.about("Compare two commits")
.arg(arg!(base: [COMMIT]))
.arg(arg!(head: [COMMIT]))
.arg(arg!(path: [PATH]).last(true))
.arg(
arg!(--color <WHEN>)
.value_parser(["always", "auto", "never"])
.num_args(0..=1)
.require_equals(true)
.default_value("auto")
.default_missing_value("always"),
),
)
.subcommand(
Command::new("push")
.about("pushes things")
@ -40,7 +27,7 @@ fn cli() -> Command {
Command::new("add")
.about("adds things")
.arg_required_else_help(true)
.arg(arg!(<PATH> ... "Stuff to add").value_parser(clap::value_parser!(PathBuf))),
.arg(arg!(<PATH> ... "Stuff to add").allow_invalid_utf8(true)),
)
.subcommand(
Command::new("stash")
@ -52,8 +39,8 @@ fn cli() -> Command {
)
}
fn push_args() -> Vec<clap::Arg> {
vec![arg!(-m --message <MESSAGE>)]
fn push_args() -> Vec<clap::Arg<'static>> {
vec![arg!(-m --message <MESSAGE>).required(false)]
}
fn main() {
@ -63,59 +50,37 @@ fn main() {
Some(("clone", sub_matches)) => {
println!(
"Cloning {}",
sub_matches.get_one::<String>("REMOTE").expect("required")
sub_matches.value_of("REMOTE").expect("required")
);
}
Some(("diff", sub_matches)) => {
let color = sub_matches
.get_one::<String>("color")
.map(|s| s.as_str())
.expect("defaulted in clap");
let mut base = sub_matches.get_one::<String>("base").map(|s| s.as_str());
let mut head = sub_matches.get_one::<String>("head").map(|s| s.as_str());
let mut path = sub_matches.get_one::<String>("path").map(|s| s.as_str());
if path.is_none() {
path = head;
head = None;
if path.is_none() {
path = base;
base = None;
}
}
let base = base.unwrap_or("stage");
let head = head.unwrap_or("worktree");
let path = path.unwrap_or("");
println!("Diffing {base}..{head} {path} (color={color})");
}
Some(("push", sub_matches)) => {
println!(
"Pushing to {}",
sub_matches.get_one::<String>("REMOTE").expect("required")
sub_matches.value_of("REMOTE").expect("required")
);
}
Some(("add", sub_matches)) => {
let paths = sub_matches
.get_many::<PathBuf>("PATH")
.into_iter()
.flatten()
.values_of_os("PATH")
.unwrap_or_default()
.map(PathBuf::from)
.collect::<Vec<_>>();
println!("Adding {paths:?}");
println!("Adding {:?}", paths);
}
Some(("stash", sub_matches)) => {
let stash_command = sub_matches.subcommand().unwrap_or(("push", sub_matches));
match stash_command {
("apply", sub_matches) => {
let stash = sub_matches.get_one::<String>("STASH");
println!("Applying {stash:?}");
let stash = sub_matches.value_of("STASH");
println!("Applying {:?}", stash);
}
("pop", sub_matches) => {
let stash = sub_matches.get_one::<String>("STASH");
println!("Popping {stash:?}");
let stash = sub_matches.value_of("STASH");
println!("Popping {:?}", stash);
}
("push", sub_matches) => {
let message = sub_matches.get_one::<String>("message");
println!("Pushing {message:?}");
let message = sub_matches.value_of("message");
println!("Pushing {:?}", message);
}
(name, _) => {
unreachable!("Unsupported subcommand `{}`", name)
@ -124,13 +89,12 @@ fn main() {
}
Some((ext, sub_matches)) => {
let args = sub_matches
.get_many::<OsString>("")
.into_iter()
.flatten()
.values_of_os("")
.unwrap_or_default()
.collect::<Vec<_>>();
println!("Calling out to {ext:?} with {args:?}");
println!("Calling out to {:?} with {:?}", ext, args);
}
_ => unreachable!(), // If all subcommands are defined above, anything else is unreachable!()
_ => unreachable!(), // If all subcommands are defined above, anything else is unreachabe!()
}
// Continued program logic goes here...

Просмотреть файл

@ -1,4 +1,8 @@
See the documentation for [`Command::multicall`][crate::Command::multicall] for rationale.
*Jump to [source](multicall-busybox.rs)*
Example of a busybox-style multicall program
See the documentation for `clap::Command::multicall` for rationale.
This example omits every command except true and false,
which are the most trivial to implement,
@ -25,15 +29,18 @@ Though users must pass something:
```console
$ busybox
? failed
Usage: busybox [OPTIONS] [APPLET]
busybox
USAGE:
busybox [OPTIONS] [APPLET]
OPTIONS:
-h, --help Print help information
--install <install> Install hardlinks for all subcommands in path
APPLETS:
true does nothing successfully
false does nothing unsuccessfully
help Print this message or the help of the given subcommand(s)
Options:
--install <install> Install hardlinks for all subcommands in path
-h, --help Print help
false does nothing unsuccessfully
help Print this message or the help of the given subcommand(s)
true does nothing successfully
```

Просмотреть файл

@ -1,9 +1,10 @@
use std::path::PathBuf;
// Note: this requires the `unstable-multicall` feature
use std::process::exit;
use clap::{value_parser, Arg, ArgAction, Command};
use clap::{Arg, Command};
fn applet_commands() -> [Command; 2] {
fn applet_commands() -> [Command<'static>; 2] {
[
Command::new("true").about("does nothing successfully"),
Command::new("false").about("does nothing unsuccessfully"),
@ -23,9 +24,9 @@ fn main() {
.long("install")
.help("Install hardlinks for all subcommands in path")
.exclusive(true)
.action(ArgAction::Set)
.takes_value(true)
.default_missing_value("/usr/local/bin")
.value_parser(value_parser!(PathBuf)),
.use_value_delimiter(false),
)
.subcommands(applet_commands()),
)
@ -34,7 +35,7 @@ fn main() {
let matches = cmd.get_matches();
let mut subcommand = matches.subcommand();
if let Some(("busybox", cmd)) = subcommand {
if cmd.contains_id("install") {
if cmd.occurrences_of("install") > 0 {
unimplemented!("Make hardlinks to the executable here");
}
subcommand = cmd.subcommand();

Просмотреть файл

@ -1,4 +1,8 @@
See the documentation for [`Command::multicall`][crate::Command::multicall] for rationale.
*Jump to [source](multicall-hostname.rs)*
Example of a `hostname-style` multicall program
See the documentation for `clap::Command::multicall` for rationale.
This example omits the implementation of displaying address config

Просмотреть файл

@ -1,3 +1,5 @@
// Note: this requires the `unstable-multicall` feature
use clap::Command;
fn main() {

44
third_party/rust/clap/examples/pacman.md поставляемый
Просмотреть файл

@ -1,3 +1,5 @@
*Jump to [source](pacman.rs)*
[`pacman`](https://wiki.archlinux.org/index.php/pacman) defines subcommands via flags.
Here, `-S` is a short flag subcommand:
@ -35,31 +37,36 @@ Searching for name...
In the help, this looks like:
```console
$ pacman -h
pacman 5.2.1
Pacman Development Team
package manager utility
Usage: pacman[EXE] <COMMAND>
USAGE:
pacman[EXE] <SUBCOMMAND>
Commands:
query, -Q, --query Query the package database.
sync, -S, --sync Synchronize packages.
help Print this message or the help of the given subcommand(s)
OPTIONS:
-h, --help Print help information
-V, --version Print version information
Options:
-h, --help Print help
-V, --version Print version
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
query -Q --query Query the package database.
sync -S --sync Synchronize packages.
$ pacman -S -h
pacman[EXE]-sync
Synchronize packages.
Usage: pacman[EXE] {sync|--sync|-S} [OPTIONS] [package]...
USAGE:
pacman[EXE] {sync|--sync|-S} [OPTIONS] [--] [package]...
Arguments:
[package]... packages
ARGS:
<package>... packages
Options:
-s, --search <search>... search remote repositories for matching strings
-i, --info view package information
-h, --help Print help
OPTIONS:
-h, --help Print help information
-i, --info view package information
-s, --search <search>... search remote repositories for matching strings
```
@ -67,11 +74,12 @@ And errors:
```console
$ pacman -S -s foo -i bar
? failed
error: the argument '--search <search>...' cannot be used with '--info'
error: The argument '--search <search>...' cannot be used with '--info'
Usage: pacman[EXE] {sync|--sync|-S} --search <search>... <package>...
USAGE:
pacman[EXE] {sync|--sync|-S} --search <search>... <package>...
For more information, try '--help'.
For more information try --help
```

53
third_party/rust/clap/examples/pacman.rs поставляемый
Просмотреть файл

@ -1,4 +1,4 @@
use clap::{Arg, ArgAction, Command};
use clap::{Arg, Command};
fn main() {
let matches = Command::new("pacman")
@ -21,8 +21,8 @@ fn main() {
.long("search")
.help("search locally installed packages for matching strings")
.conflicts_with("info")
.action(ArgAction::Set)
.num_args(1..),
.takes_value(true)
.multiple_values(true),
)
.arg(
Arg::new("info")
@ -30,8 +30,8 @@ fn main() {
.short('i')
.conflicts_with("search")
.help("view package information")
.action(ArgAction::Set)
.num_args(1..),
.takes_value(true)
.multiple_values(true),
),
)
// Sync subcommand
@ -47,8 +47,8 @@ fn main() {
.short('s')
.long("search")
.conflicts_with("info")
.action(ArgAction::Set)
.num_args(1..)
.takes_value(true)
.multiple_values(true)
.help("search remote repositories for matching strings"),
)
.arg(
@ -56,52 +56,43 @@ fn main() {
.long("info")
.conflicts_with("search")
.short('i')
.action(ArgAction::SetTrue)
.help("view package information"),
)
.arg(
Arg::new("package")
.help("packages")
.required_unless_present("search")
.action(ArgAction::Set)
.num_args(1..),
.takes_value(true)
.multiple_values(true),
),
)
.get_matches();
match matches.subcommand() {
Some(("sync", sync_matches)) => {
if sync_matches.contains_id("search") {
let packages: Vec<_> = sync_matches
.get_many::<String>("search")
.expect("contains_id")
.map(|s| s.as_str())
.collect();
if sync_matches.is_present("search") {
let packages: Vec<_> = sync_matches.values_of("search").unwrap().collect();
let values = packages.join(", ");
println!("Searching for {values}...");
println!("Searching for {}...", values);
return;
}
let packages: Vec<_> = sync_matches
.get_many::<String>("package")
.expect("is present")
.map(|s| s.as_str())
.collect();
let packages: Vec<_> = sync_matches.values_of("package").unwrap().collect();
let values = packages.join(", ");
if sync_matches.get_flag("info") {
println!("Retrieving info for {values}...");
if sync_matches.is_present("info") {
println!("Retrieving info for {}...", values);
} else {
println!("Installing {values}...");
println!("Installing {}...", values);
}
}
Some(("query", query_matches)) => {
if let Some(packages) = query_matches.get_many::<String>("info") {
let comma_sep = packages.map(|s| s.as_str()).collect::<Vec<_>>().join(", ");
println!("Retrieving info for {comma_sep}...");
} else if let Some(queries) = query_matches.get_many::<String>("search") {
let comma_sep = queries.map(|s| s.as_str()).collect::<Vec<_>>().join(", ");
println!("Searching Locally for {comma_sep}...");
if let Some(packages) = query_matches.values_of("info") {
let comma_sep = packages.collect::<Vec<_>>().join(", ");
println!("Retrieving info for {}...", comma_sep);
} else if let Some(queries) = query_matches.values_of("search") {
let comma_sep = queries.collect::<Vec<_>>().join(", ");
println!("Searching Locally for {}...", comma_sep);
} else {
println!("Displaying all locally installed packages...");
}

8
third_party/rust/clap/examples/repl.rs поставляемый
Просмотреть файл

@ -1,3 +1,5 @@
// Note: this requires the `unstable-multicall` feature
use std::io::Write;
use clap::Command;
@ -17,7 +19,7 @@ fn main() -> Result<(), String> {
}
}
Err(err) => {
write!(std::io::stdout(), "{err}").map_err(|e| e.to_string())?;
write!(std::io::stdout(), "{}", err).map_err(|e| e.to_string())?;
std::io::stdout().flush().map_err(|e| e.to_string())?;
}
}
@ -29,7 +31,7 @@ fn main() -> Result<(), String> {
fn respond(line: &str) -> Result<bool, String> {
let args = shlex::split(line).ok_or("error: Invalid quoting")?;
let matches = cli()
.try_get_matches_from(args)
.try_get_matches_from(&args)
.map_err(|e| e.to_string())?;
match matches.subcommand() {
Some(("ping", _matches)) => {
@ -48,7 +50,7 @@ fn respond(line: &str) -> Result<bool, String> {
Ok(false)
}
fn cli() -> Command {
fn cli() -> Command<'static> {
// strip out usage
const PARSER_TEMPLATE: &str = "\
{all-args}

Просмотреть файл

@ -1,35 +0,0 @@
```console
$ 01_quick --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 01_quick[EXE] [OPTIONS] [name] [COMMAND]
Commands:
test does testing things
help Print this message or the help of the given subcommand(s)
Arguments:
[name] Optional name to operate on
Options:
-c, --config <FILE> Sets a custom config file
-d, --debug... Turn debugging information on
-h, --help Print help
-V, --version Print version
```
By default, the program does nothing:
```console
$ 01_quick
Debug mode is off
```
But you can mix and match the various features
```console
$ 01_quick -dd test
Debug mode is on
Not printing testing lists...
```

Просмотреть файл

@ -1,9 +1,10 @@
use std::path::PathBuf;
// Note: this requires the `cargo` feature
use clap::{arg, command, value_parser, ArgAction, Command};
use clap::{arg, command, Command};
use std::path::Path;
fn main() {
let matches = command!() // requires `cargo` feature
let matches = command!()
.arg(arg!([name] "Optional name to operate on"))
.arg(
arg!(
@ -11,7 +12,8 @@ fn main() {
)
// We don't have syntax yet for optional options, so manually calling `required`
.required(false)
.value_parser(value_parser!(PathBuf)),
// Support non-UTF8 paths
.allow_invalid_utf8(true),
)
.arg(arg!(
-d --debug ... "Turn debugging information on"
@ -19,25 +21,23 @@ fn main() {
.subcommand(
Command::new("test")
.about("does testing things")
.arg(arg!(-l --list "lists test values").action(ArgAction::SetTrue)),
.arg(arg!(-l --list "lists test values")),
)
.get_matches();
// You can check the value provided by positional arguments, or option arguments
if let Some(name) = matches.get_one::<String>("name") {
if let Some(name) = matches.value_of("name") {
println!("Value for name: {}", name);
}
if let Some(config_path) = matches.get_one::<PathBuf>("config") {
if let Some(raw_config) = matches.value_of_os("config") {
let config_path = Path::new(raw_config);
println!("Value for config: {}", config_path.display());
}
// You can see how many times a particular flag or argument occurred
// Note, only flags can have multiple occurrences
match matches
.get_one::<u8>("debug")
.expect("Count's are defaulted")
{
match matches.occurrences_of("debug") {
0 => println!("Debug mode is off"),
1 => println!("Debug mode is kind of on"),
2 => println!("Debug mode is on"),
@ -48,7 +48,7 @@ fn main() {
// matches just as you would the top level cmd
if let Some(matches) = matches.subcommand_matches("test") {
// "$ myapp test" was run
if matches.get_flag("list") {
if matches.is_present("list") {
// "$ myapp test -l" was run
println!("Printing testing lists...");
} else {

Просмотреть файл

@ -1,17 +0,0 @@
```console
$ 02_app_settings --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 02_app_settings[EXE] --two <VALUE> --one <VALUE>
Options:
--two <VALUE>
--one <VALUE>
-h, --help
Print help
-V, --version
Print version
```

Просмотреть файл

@ -1,18 +1,16 @@
use clap::{arg, command, ArgAction};
// Note: this requires the `cargo` feature
use clap::{arg, command, AppSettings};
fn main() {
let matches = command!() // requires `cargo` feature
.next_line_help(true)
.arg(arg!(--two <VALUE>).required(true).action(ArgAction::Set))
.arg(arg!(--one <VALUE>).required(true).action(ArgAction::Set))
let matches = command!()
.args_override_self(true)
.global_setting(AppSettings::DeriveDisplayOrder)
.allow_negative_numbers(true)
.arg(arg!(--two <VALUE>))
.arg(arg!(--one <VALUE>))
.get_matches();
println!(
"two: {:?}",
matches.get_one::<String>("two").expect("required")
);
println!(
"one: {:?}",
matches.get_one::<String>("one").expect("required")
);
println!("two: {:?}", matches.value_of("two").expect("required"));
println!("one: {:?}", matches.value_of("one").expect("required"));
}

Просмотреть файл

@ -1,16 +0,0 @@
```console
$ 02_apps --help
Does awesome things
Usage: 02_apps[EXE] --two <VALUE> --one <VALUE>
Options:
--two <VALUE>
--one <VALUE>
-h, --help Print help
-V, --version Print version
$ 02_apps --version
MyApp 1.0
```

Просмотреть файл

@ -5,16 +5,10 @@ fn main() {
.version("1.0")
.author("Kevin K. <kbknapp@gmail.com>")
.about("Does awesome things")
.arg(arg!(--two <VALUE>).required(true))
.arg(arg!(--one <VALUE>).required(true))
.arg(arg!(--two <VALUE>))
.arg(arg!(--one <VALUE>))
.get_matches();
println!(
"two: {:?}",
matches.get_one::<String>("two").expect("required")
);
println!(
"one: {:?}",
matches.get_one::<String>("one").expect("required")
);
println!("two: {:?}", matches.value_of("two").expect("required"));
println!("one: {:?}", matches.value_of("one").expect("required"));
}

Просмотреть файл

@ -1,16 +0,0 @@
```console
$ 02_crate --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 02_crate[EXE] --two <VALUE> --one <VALUE>
Options:
--two <VALUE>
--one <VALUE>
-h, --help Print help
-V, --version Print version
$ 02_crate --version
clap [..]
```

Просмотреть файл

@ -1,18 +1,13 @@
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
// requires `cargo` feature, reading name, version, author, and description from `Cargo.toml`
let matches = command!()
.arg(arg!(--two <VALUE>).required(true))
.arg(arg!(--one <VALUE>).required(true))
.arg(arg!(--two <VALUE>))
.arg(arg!(--one <VALUE>))
.get_matches();
println!(
"two: {:?}",
matches.get_one::<String>("two").expect("required")
);
println!(
"one: {:?}",
matches.get_one::<String>("one").expect("required")
);
println!("two: {:?}", matches.value_of("two").expect("required"));
println!("one: {:?}", matches.value_of("one").expect("required"));
}

Просмотреть файл

@ -1,26 +0,0 @@
```console
$ 03_01_flag_bool --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 03_01_flag_bool[EXE] [OPTIONS]
Options:
-v, --verbose
-h, --help Print help
-V, --version Print version
$ 03_01_flag_bool
verbose: false
$ 03_01_flag_bool --verbose
verbose: true
$ 03_01_flag_bool --verbose --verbose
? failed
error: the argument '--verbose' cannot be used multiple times
Usage: 03_01_flag_bool[EXE] [OPTIONS]
For more information, try '--help'.
```

Просмотреть файл

@ -1,14 +1,9 @@
use clap::{command, Arg, ArgAction};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = command!() // requires `cargo` feature
.arg(
Arg::new("verbose")
.short('v')
.long("verbose")
.action(ArgAction::SetTrue),
)
.get_matches();
let matches = command!().arg(arg!(-v - -verbose)).get_matches();
println!("verbose: {:?}", matches.get_flag("verbose"));
println!("verbose: {:?}", matches.is_present("verbose"));
}

Просмотреть файл

@ -1,21 +0,0 @@
```console
$ 03_01_flag_count --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 03_01_flag_count[EXE] [OPTIONS]
Options:
-v, --verbose...
-h, --help Print help
-V, --version Print version
$ 03_01_flag_count
verbose: 0
$ 03_01_flag_count --verbose
verbose: 1
$ 03_01_flag_count --verbose --verbose
verbose: 2
```

Просмотреть файл

@ -1,14 +1,9 @@
use clap::{command, Arg, ArgAction};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = command!() // requires `cargo` feature
.arg(
Arg::new("verbose")
.short('v')
.long("verbose")
.action(ArgAction::Count),
)
.get_matches();
let matches = command!().arg(arg!(-v --verbose ...)).get_matches();
println!("verbose: {:?}", matches.get_count("verbose"));
println!("verbose: {:?}", matches.occurrences_of("verbose"));
}

Просмотреть файл

@ -1,30 +0,0 @@
```console
$ 03_02_option --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 03_02_option[EXE] [OPTIONS]
Options:
-n, --name <name>
-h, --help Print help
-V, --version Print version
$ 03_02_option
name: None
$ 03_02_option --name bob
name: Some("bob")
$ 03_02_option --name=bob
name: Some("bob")
$ 03_02_option -n bob
name: Some("bob")
$ 03_02_option -n=bob
name: Some("bob")
$ 03_02_option -nbob
name: Some("bob")
```

Просмотреть файл

@ -1,9 +1,11 @@
use clap::{command, Arg};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = command!() // requires `cargo` feature
.arg(Arg::new("name").short('n').long("name"))
let matches = command!()
.arg(arg!(-n --name <NAME>).required(false))
.get_matches();
println!("name: {:?}", matches.get_one::<String>("name"));
println!("name: {:?}", matches.value_of("name"));
}

Просмотреть файл

@ -1,30 +0,0 @@
```console
$ 03_02_option_mult --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 03_02_option_mult[EXE] [OPTIONS]
Options:
-n, --name <name>
-h, --help Print help
-V, --version Print version
$ 03_02_option_mult
name: None
$ 03_02_option_mult --name bob
name: Some("bob")
$ 03_02_option_mult --name=bob
name: Some("bob")
$ 03_02_option_mult -n bob
name: Some("bob")
$ 03_02_option_mult -n=bob
name: Some("bob")
$ 03_02_option_mult -nbob
name: Some("bob")
```

Просмотреть файл

@ -1,14 +0,0 @@
use clap::{command, Arg, ArgAction};
fn main() {
let matches = command!() // requires `cargo` feature
.arg(
Arg::new("name")
.short('n')
.long("name")
.action(ArgAction::Append),
)
.get_matches();
println!("name: {:?}", matches.get_one::<String>("name"));
}

Просмотреть файл

@ -1,20 +0,0 @@
```console
$ 03_03_positional --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 03_03_positional[EXE] [name]
Arguments:
[name]
Options:
-h, --help Print help
-V, --version Print version
$ 03_03_positional
name: None
$ 03_03_positional bob
name: Some("bob")
```

Просмотреть файл

@ -1,9 +1,9 @@
use clap::{command, Arg};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = command!() // requires `cargo` feature
.arg(Arg::new("name"))
.get_matches();
let matches = command!().arg(arg!([NAME])).get_matches();
println!("name: {:?}", matches.get_one::<String>("name"));
println!("NAME: {:?}", matches.value_of("NAME"));
}

Просмотреть файл

@ -1,23 +0,0 @@
```console
$ 03_03_positional_mult --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 03_03_positional_mult[EXE] [name]...
Arguments:
[name]...
Options:
-h, --help Print help
-V, --version Print version
$ 03_03_positional_mult
names: []
$ 03_03_positional_mult bob
names: ["bob"]
$ 03_03_positional_mult bob john
names: ["bob", "john"]
```

Просмотреть файл

@ -1,15 +0,0 @@
use clap::{command, Arg, ArgAction};
fn main() {
let matches = command!() // requires `cargo` feature
.arg(Arg::new("name").action(ArgAction::Append))
.get_matches();
let args = matches
.get_many::<String>("name")
.unwrap_or_default()
.map(|v| v.as_str())
.collect::<Vec<_>>();
println!("names: {:?}", &args);
}

Просмотреть файл

@ -1,58 +0,0 @@
```console
$ 03_04_subcommands help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 03_04_subcommands[EXE] <COMMAND>
Commands:
add Adds files to myapp
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
$ 03_04_subcommands help add
Adds files to myapp
Usage: 03_04_subcommands[EXE] add [NAME]
Arguments:
[NAME]
Options:
-h, --help Print help
-V, --version Print version
$ 03_04_subcommands add bob
'myapp add' was used, name is: Some("bob")
```
Because we set [`Command::arg_required_else_help`][crate::Command::arg_required_else_help]:
```console
$ 03_04_subcommands
? failed
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 03_04_subcommands[EXE] <COMMAND>
Commands:
add Adds files to myapp
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
```
Because we set [`Command::propagate_version`][crate::Command::propagate_version]:
```console
$ 03_04_subcommands --version
clap [..]
$ 03_04_subcommands add --version
clap-add [..]
```

Просмотреть файл

@ -1,7 +1,9 @@
// Note: this requires the `cargo` feature
use clap::{arg, command, Command};
fn main() {
let matches = command!() // requires `cargo` feature
let matches = command!()
.propagate_version(true)
.subcommand_required(true)
.arg_required_else_help(true)
@ -15,7 +17,7 @@ fn main() {
match matches.subcommand() {
Some(("add", sub_matches)) => println!(
"'myapp add' was used, name is: {:?}",
sub_matches.get_one::<String>("NAME")
sub_matches.value_of("NAME")
),
_ => unreachable!("Exhausted list of subcommands and subcommand_required prevents `None`"),
}

Просмотреть файл

@ -1,20 +0,0 @@
```console
$ 03_05_default_values --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 03_05_default_values[EXE] [PORT]
Arguments:
[PORT] [default: 2020]
Options:
-h, --help Print help
-V, --version Print version
$ 03_05_default_values
port: 2020
$ 03_05_default_values 22
port: 22
```

Просмотреть файл

@ -1,18 +1,16 @@
use clap::{arg, command, value_parser};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = command!() // requires `cargo` feature
.arg(
arg!([PORT])
.value_parser(value_parser!(u16))
.default_value("2020"),
)
let matches = command!()
.arg(arg!([NAME]).default_value("alice"))
.get_matches();
println!(
"port: {:?}",
"NAME: {:?}",
matches
.get_one::<u16>("PORT")
.value_of("NAME")
.expect("default ensures there is always a value")
);
}

Просмотреть файл

@ -1,47 +0,0 @@
```console
$ 04_01_enum --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 04_01_enum[EXE] <MODE>
Arguments:
<MODE>
What mode to run the program in
Possible values:
- fast: Run swiftly
- slow: Crawl slowly but steadily
Options:
-h, --help
Print help (see a summary with '-h')
-V, --version
Print version
$ 04_01_enum -h
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 04_01_enum[EXE] <MODE>
Arguments:
<MODE> What mode to run the program in [possible values: fast, slow]
Options:
-h, --help Print help (see more with '--help')
-V, --version Print version
$ 04_01_enum fast
Hare
$ 04_01_enum slow
Tortoise
$ 04_01_enum medium
? failed
error: invalid value 'medium' for '<MODE>'
[possible values: fast, slow]
For more information, try '--help'.
```

Просмотреть файл

@ -1,22 +1,18 @@
use clap::{arg, builder::PossibleValue, command, value_parser, ValueEnum};
// Note: this requires the `cargo` feature
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
use clap::{arg, command, ArgEnum, PossibleValue};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ArgEnum)]
enum Mode {
Fast,
Slow,
}
// Can also be derived with feature flag `derive`
impl ValueEnum for Mode {
fn value_variants<'a>() -> &'a [Self] {
&[Mode::Fast, Mode::Slow]
}
fn to_possible_value<'a>(&self) -> Option<PossibleValue> {
Some(match self {
Mode::Fast => PossibleValue::new("fast").help("Run swiftly"),
Mode::Slow => PossibleValue::new("slow").help("Crawl slowly but steadily"),
})
impl Mode {
pub fn possible_values() -> impl Iterator<Item = PossibleValue<'static>> {
Mode::value_variants()
.iter()
.filter_map(ArgEnum::to_possible_value)
}
}
@ -38,22 +34,22 @@ impl std::str::FromStr for Mode {
return Ok(*variant);
}
}
Err(format!("invalid variant: {}", s))
Err(format!("Invalid variant: {}", s))
}
}
fn main() {
let matches = command!() // requires `cargo` feature
let matches = command!()
.arg(
arg!(<MODE>)
.help("What mode to run the program in")
.value_parser(value_parser!(Mode)),
.possible_values(Mode::possible_values()),
)
.get_matches();
// Note, it's safe to call unwrap() because the arg is required
match matches
.get_one::<Mode>("MODE")
.value_of_t("MODE")
.expect("'MODE' is required and parsing will fail if its missing")
{
Mode::Fast => {

Просмотреть файл

@ -1,27 +0,0 @@
```console
$ 04_01_possible --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 04_01_possible[EXE] <MODE>
Arguments:
<MODE> What mode to run the program in [possible values: fast, slow]
Options:
-h, --help Print help
-V, --version Print version
$ 04_01_possible fast
Hare
$ 04_01_possible slow
Tortoise
$ 04_01_possible medium
? failed
error: invalid value 'medium' for '<MODE>'
[possible values: fast, slow]
For more information, try '--help'.
```

Просмотреть файл

@ -1,19 +1,20 @@
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = command!() // requires `cargo` feature
let matches = command!()
.arg(
arg!(<MODE>)
.help("What mode to run the program in")
.value_parser(["fast", "slow"]),
.possible_values(["fast", "slow"]),
)
.get_matches();
// Note, it's safe to call unwrap() because the arg is required
match matches
.get_one::<String>("MODE")
.value_of("MODE")
.expect("'MODE' is required and parsing will fail if its missing")
.as_str()
{
"fast" => {
println!("Hare");

Просмотреть файл

@ -1,29 +0,0 @@
```console
$ 04_02_parse --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 04_02_parse[EXE] <PORT>
Arguments:
<PORT> Network port to use
Options:
-h, --help Print help
-V, --version Print version
$ 04_02_parse 22
PORT = 22
$ 04_02_parse foobar
? failed
error: invalid value 'foobar' for '<PORT>': invalid digit found in string
For more information, try '--help'.
$ 04_02_parse_derive 0
? failed
error: invalid value '0' for '<PORT>': 0 is not in 1..=65535
For more information, try '--help'.
```

Просмотреть файл

@ -1,17 +1,19 @@
use clap::{arg, command, value_parser};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = command!() // requires `cargo` feature
let matches = command!()
.arg(
arg!(<PORT>)
.help("Network port to use")
.value_parser(value_parser!(u16).range(1..)),
.validator(|s| s.parse::<usize>()),
)
.get_matches();
// Note, it's safe to call unwrap() because the arg is required
let port: u16 = *matches
.get_one::<u16>("PORT")
let port: usize = matches
.value_of_t("PORT")
.expect("'PORT' is required and parsing will fail if its missing");
println!("PORT = {}", port);
}

Просмотреть файл

@ -1,29 +0,0 @@
```console
$ 04_02_validate --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 04_02_validate[EXE] <PORT>
Arguments:
<PORT> Network port to use
Options:
-h, --help Print help
-V, --version Print version
$ 04_02_validate 22
PORT = 22
$ 04_02_validate foobar
? failed
error: invalid value 'foobar' for '<PORT>': `foobar` isn't a port number
For more information, try '--help'.
$ 04_02_validate 0
? failed
error: invalid value '0' for '<PORT>': port not in range 1-65535
For more information, try '--help'.
```

Просмотреть файл

@ -1,34 +1,36 @@
// Note: this requires the `cargo` feature
use std::ops::RangeInclusive;
use clap::{arg, command};
fn main() {
let matches = command!() // requires `cargo` feature
let matches = command!()
.arg(
arg!(<PORT>)
.help("Network port to use")
.value_parser(port_in_range),
.validator(port_in_range),
)
.get_matches();
// Note, it's safe to call unwrap() because the arg is required
let port: u16 = *matches
.get_one::<u16>("PORT")
let port: usize = matches
.value_of_t("PORT")
.expect("'PORT' is required and parsing will fail if its missing");
println!("PORT = {}", port);
}
const PORT_RANGE: RangeInclusive<usize> = 1..=65535;
fn port_in_range(s: &str) -> Result<u16, String> {
fn port_in_range(s: &str) -> Result<(), String> {
let port: usize = s
.parse()
.map_err(|_| format!("`{}` isn't a port number", s))?;
if PORT_RANGE.contains(&port) {
Ok(port as u16)
Ok(())
} else {
Err(format!(
"port not in range {}-{}",
"Port not in range {}-{}",
PORT_RANGE.start(),
PORT_RANGE.end()
))

Просмотреть файл

@ -1,53 +0,0 @@
```console
$ 04_03_relations --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 04_03_relations[EXE] [OPTIONS] <--set-ver <VER>|--major|--minor|--patch> [INPUT_FILE]
Arguments:
[INPUT_FILE] some regular input
Options:
--set-ver <VER> set version manually
--major auto inc major
--minor auto inc minor
--patch auto inc patch
--spec-in <SPEC_IN> some special input argument
-c <CONFIG>
-h, --help Print help
-V, --version Print version
$ 04_03_relations
? failed
error: the following required arguments were not provided:
<--set-ver <VER>|--major|--minor|--patch>
Usage: 04_03_relations[EXE] <--set-ver <VER>|--major|--minor|--patch> [INPUT_FILE]
For more information, try '--help'.
$ 04_03_relations --major
Version: 2.2.3
$ 04_03_relations --major --minor
? failed
error: the argument '--major' cannot be used with '--minor'
Usage: 04_03_relations[EXE] <--set-ver <VER>|--major|--minor|--patch> [INPUT_FILE]
For more information, try '--help'.
$ 04_03_relations --major -c config.toml
? failed
error: the following required arguments were not provided:
<INPUT_FILE|--spec-in <SPEC_IN>>
Usage: 04_03_relations[EXE] -c <CONFIG> <--set-ver <VER>|--major|--minor|--patch> <INPUT_FILE|--spec-in <SPEC_IN>>
For more information, try '--help'.
$ 04_03_relations --major -c config.toml --spec-in input.txt
Version: 2.2.3
Doing work using input input.txt and config config.toml
```

Просмотреть файл

@ -1,40 +1,32 @@
use std::path::PathBuf;
// Note: this requires the `cargo` feature
use clap::{arg, command, value_parser, ArgAction, ArgGroup};
use clap::{arg, command, ArgGroup};
fn main() {
// Create application like normal
let matches = command!() // requires `cargo` feature
let matches = command!()
// Add the version arguments
.arg(arg!(--"set-ver" <VER> "set version manually"))
.arg(arg!(--major "auto inc major").action(ArgAction::SetTrue))
.arg(arg!(--minor "auto inc minor").action(ArgAction::SetTrue))
.arg(arg!(--patch "auto inc patch").action(ArgAction::SetTrue))
.arg(arg!(--"set-ver" <VER> "set version manually").required(false))
.arg(arg!(--major "auto inc major"))
.arg(arg!(--minor "auto inc minor"))
.arg(arg!(--patch "auto inc patch"))
// Create a group, make it required, and add the above arguments
.group(
ArgGroup::new("vers")
.required(true)
.args(["set-ver", "major", "minor", "patch"]),
.args(&["set-ver", "major", "minor", "patch"]),
)
// Arguments can also be added to a group individually, these two arguments
// are part of the "input" group which is not required
.arg(
arg!([INPUT_FILE] "some regular input")
.value_parser(value_parser!(PathBuf))
.group("input"),
)
.arg(arg!([INPUT_FILE] "some regular input").group("input"))
.arg(
arg!(--"spec-in" <SPEC_IN> "some special input argument")
.value_parser(value_parser!(PathBuf))
.required(false)
.group("input"),
)
// Now let's assume we have a -c [config] argument which requires one of
// (but **not** both) the "input" arguments
.arg(
arg!(config: -c <CONFIG>)
.value_parser(value_parser!(PathBuf))
.requires("input"),
)
.arg(arg!(config: -c <CONFIG>).required(false).requires("input"))
.get_matches();
// Let's assume the old version 1.2.3
@ -43,14 +35,14 @@ fn main() {
let mut patch = 3;
// See if --set-ver was used to set the version manually
let version = if let Some(ver) = matches.get_one::<String>("set-ver") {
ver.to_owned()
let version = if let Some(ver) = matches.value_of("set-ver") {
ver.to_string()
} else {
// Increment the one requested (in a real program, we'd reset the lower numbers)
let (maj, min, pat) = (
matches.get_flag("major"),
matches.get_flag("minor"),
matches.get_flag("patch"),
matches.is_present("major"),
matches.is_present("minor"),
matches.is_present("patch"),
);
match (maj, min, pat) {
(true, _, _) => major += 1,
@ -64,15 +56,14 @@ fn main() {
println!("Version: {}", version);
// Check for usage of -c
if matches.contains_id("config") {
if matches.is_present("config") {
let input = matches
.get_one::<PathBuf>("INPUT_FILE")
.unwrap_or_else(|| matches.get_one::<PathBuf>("spec-in").unwrap())
.display();
.value_of("INPUT_FILE")
.unwrap_or_else(|| matches.value_of("spec-in").unwrap());
println!(
"Doing work using input {} and config {}",
input,
matches.get_one::<PathBuf>("config").unwrap().display()
matches.value_of("config").unwrap()
);
}
}

Просмотреть файл

@ -1,52 +0,0 @@
```console
$ 04_04_custom --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 04_04_custom[EXE] [OPTIONS] [INPUT_FILE]
Arguments:
[INPUT_FILE] some regular input
Options:
--set-ver <VER> set version manually
--major auto inc major
--minor auto inc minor
--patch auto inc patch
--spec-in <SPEC_IN> some special input argument
-c <CONFIG>
-h, --help Print help
-V, --version Print version
$ 04_04_custom
? failed
error: Can only modify one version field
Usage: 04_04_custom[EXE] [OPTIONS] [INPUT_FILE]
For more information, try '--help'.
$ 04_04_custom --major
Version: 2.2.3
$ 04_04_custom --major --minor
? failed
error: Can only modify one version field
Usage: 04_04_custom[EXE] [OPTIONS] [INPUT_FILE]
For more information, try '--help'.
$ 04_04_custom --major -c config.toml
? failed
Version: 2.2.3
error: INPUT_FILE or --spec-in is required when using --config
Usage: 04_04_custom[EXE] [OPTIONS] [INPUT_FILE]
For more information, try '--help'.
$ 04_04_custom --major -c config.toml --spec-in input.txt
Version: 2.2.3
Doing work using input input.txt and config config.toml
```

Просмотреть файл

@ -1,26 +1,22 @@
use std::path::PathBuf;
// Note: this requires the `cargo` feature
use clap::error::ErrorKind;
use clap::{arg, command, value_parser, ArgAction};
use clap::{arg, command, ErrorKind};
fn main() {
// Create application like normal
let mut cmd = command!() // requires `cargo` feature
let mut cmd = command!()
// Add the version arguments
.arg(arg!(--"set-ver" <VER> "set version manually"))
.arg(arg!(--major "auto inc major").action(ArgAction::SetTrue))
.arg(arg!(--minor "auto inc minor").action(ArgAction::SetTrue))
.arg(arg!(--patch "auto inc patch").action(ArgAction::SetTrue))
.arg(arg!(--"set-ver" <VER> "set version manually").required(false))
.arg(arg!(--major "auto inc major"))
.arg(arg!(--minor "auto inc minor"))
.arg(arg!(--patch "auto inc patch"))
// Arguments can also be added to a group individually, these two arguments
// are part of the "input" group which is not required
.arg(arg!([INPUT_FILE] "some regular input").value_parser(value_parser!(PathBuf)))
.arg(
arg!(--"spec-in" <SPEC_IN> "some special input argument")
.value_parser(value_parser!(PathBuf)),
)
.arg(arg!([INPUT_FILE] "some regular input"))
.arg(arg!(--"spec-in" <SPEC_IN> "some special input argument").required(false))
// Now let's assume we have a -c [config] argument which requires one of
// (but **not** both) the "input" arguments
.arg(arg!(config: -c <CONFIG>).value_parser(value_parser!(PathBuf)));
.arg(arg!(config: -c <CONFIG>).required(false));
let matches = cmd.get_matches_mut();
// Let's assume the old version 1.2.3
@ -29,8 +25,9 @@ fn main() {
let mut patch = 3;
// See if --set-ver was used to set the version manually
let version = if let Some(ver) = matches.get_one::<String>("set-ver") {
if matches.get_flag("major") || matches.get_flag("minor") || matches.get_flag("patch") {
let version = if let Some(ver) = matches.value_of("set-ver") {
if matches.is_present("major") || matches.is_present("minor") || matches.is_present("patch")
{
cmd.error(
ErrorKind::ArgumentConflict,
"Can't do relative and absolute version change",
@ -41,9 +38,9 @@ fn main() {
} else {
// Increment the one requested (in a real program, we'd reset the lower numbers)
let (maj, min, pat) = (
matches.get_flag("major"),
matches.get_flag("minor"),
matches.get_flag("patch"),
matches.is_present("major"),
matches.is_present("minor"),
matches.is_present("patch"),
);
match (maj, min, pat) {
(true, false, false) => major += 1,
@ -63,22 +60,21 @@ fn main() {
println!("Version: {}", version);
// Check for usage of -c
if matches.contains_id("config") {
if matches.is_present("config") {
let input = matches
.get_one::<PathBuf>("INPUT_FILE")
.or_else(|| matches.get_one::<PathBuf>("spec-in"))
.value_of("INPUT_FILE")
.or_else(|| matches.value_of("spec-in"))
.unwrap_or_else(|| {
cmd.error(
ErrorKind::MissingRequiredArgument,
"INPUT_FILE or --spec-in is required when using --config",
)
.exit()
})
.display();
});
println!(
"Doing work using input {} and config {}",
input,
matches.get_one::<PathBuf>("config").unwrap().display()
matches.value_of("config").unwrap()
);
}
}

Просмотреть файл

@ -1,25 +1,26 @@
use clap::{arg, command, value_parser};
// Note: this requires the `cargo` feature
use clap::{arg, command};
fn main() {
let matches = cmd().get_matches();
// Note, it's safe to call unwrap() because the arg is required
let port: usize = *matches
.get_one::<usize>("PORT")
let port: usize = matches
.value_of_t("PORT")
.expect("'PORT' is required and parsing will fail if its missing");
println!("PORT = {}", port);
}
fn cmd() -> clap::Command {
command!() // requires `cargo` feature
.arg(
arg!(<PORT>)
.help("Network port to use")
.value_parser(value_parser!(usize)),
)
fn cmd() -> clap::Command<'static> {
command!().arg(
arg!(<PORT>)
.help("Network port to use")
.validator(|s| s.parse::<usize>()),
)
}
#[test]
fn verify_cmd() {
fn verify_app() {
cmd().debug_assert();
}

664
third_party/rust/clap/examples/tutorial_builder/README.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,664 @@
# Tutorial
*Jump to [derive tutorial](../tutorial_derive/README.md)*
1. [Quick Start](#quick-start)
2. [Configuring the Parser](#configuring-the-parser)
3. [Adding Arguments](#adding-arguments)
1. [Positionals](#positionals)
2. [Options](#options)
3. [Flags](#flags)
4. [Subcommands](#subcommands)
5. [Defaults](#defaults)
4. Validation
1. [Enumerated values](#enumerated-values)
2. [Validated values](#validated-values)
3. [Argument Relations](#argument-relations)
4. [Custom Validation](#custom-validation)
5. [Tips](#tips)
6. [Contributing](#contributing)
## Quick Start
You can create an application with several arguments using usage strings.
[Example:](01_quick.rs)
```console
$ 01_quick --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
01_quick[EXE] [OPTIONS] [name] [SUBCOMMAND]
ARGS:
<name> Optional name to operate on
OPTIONS:
-c, --config <FILE> Sets a custom config file
-d, --debug Turn debugging information on
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
test does testing things
```
By default, the program does nothing:
```console
$ 01_quick
Debug mode is off
```
But you can mix and match the various features
```console
$ 01_quick -dd test
Debug mode is on
Not printing testing lists...
```
## Configuring the Parser
You use the `Command` the start building a parser.
[Example:](02_apps.rs)
```console
$ 02_apps --help
MyApp 1.0
Kevin K. <kbknapp@gmail.com>
Does awesome things
USAGE:
02_apps[EXE] --two <VALUE> --one <VALUE>
OPTIONS:
-h, --help Print help information
--one <VALUE>
--two <VALUE>
-V, --version Print version information
$ 02_apps --version
MyApp 1.0
```
You can use `command!()` to fill these fields in from your `Cargo.toml`
file. **This requires the `cargo` feature flag.**
[Example:](02_crate.rs)
```console
$ 02_crate --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
02_crate[EXE] --two <VALUE> --one <VALUE>
OPTIONS:
-h, --help Print help information
--one <VALUE>
--two <VALUE>
-V, --version Print version information
$ 02_crate --version
clap [..]
```
You can use `Command` methods to change the application level behavior of clap.
[Example:](02_app_settings.rs)
```console
$ 02_app_settings --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
02_app_settings[EXE] --two <VALUE> --one <VALUE>
OPTIONS:
--two <VALUE>
--one <VALUE>
-h, --help Print help information
-V, --version Print version information
$ 02_app_settings --one -1 --one -3 --two 10
two: "10"
one: "-3"
```
## Adding Arguments
### Positionals
You can have users specify values by their position on the command-line:
[Example:](03_03_positional.rs)
```console
$ 03_03_positional --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_03_positional[EXE] [NAME]
ARGS:
<NAME>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
$ 03_03_positional
NAME: None
$ 03_03_positional bob
NAME: Some("bob")
```
### Options
You can name your arguments with a flag:
- Order doesn't matter
- They can be optional
- Intent is clearer
[Example:](03_02_option.rs)
```console
$ 03_02_option --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_02_option[EXE] [OPTIONS]
OPTIONS:
-h, --help Print help information
-n, --name <NAME>
-V, --version Print version information
$ 03_02_option
name: None
$ 03_02_option --name bob
name: Some("bob")
$ 03_02_option --name=bob
name: Some("bob")
$ 03_02_option -n bob
name: Some("bob")
$ 03_02_option -n=bob
name: Some("bob")
$ 03_02_option -nbob
name: Some("bob")
```
### Flags
Flags can also be switches that can be on/off:
[Example:](03_01_flag_bool.rs)
```console
$ 03_01_flag_bool --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_01_flag_bool[EXE] [OPTIONS]
OPTIONS:
-h, --help Print help information
-v, --verbose
-V, --version Print version information
$ 03_01_flag_bool
verbose: false
$ 03_01_flag_bool --verbose
verbose: true
$ 03_01_flag_bool --verbose --verbose
? failed
error: The argument '--verbose' was provided more than once, but cannot be used multiple times
USAGE:
03_01_flag_bool[EXE] [OPTIONS]
For more information try --help
```
Or counted.
[Example:](03_01_flag_count.rs)
```console
$ 03_01_flag_count --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_01_flag_count[EXE] [OPTIONS]
OPTIONS:
-h, --help Print help information
-v, --verbose
-V, --version Print version information
$ 03_01_flag_count
verbose: 0
$ 03_01_flag_count --verbose
verbose: 1
$ 03_01_flag_count --verbose --verbose
verbose: 2
```
### Subcommands
Subcommands are defined as `Command`s that get added via `Command::subcommand`. Each
instance of a Subcommand can have its own version, author(s), Args, and even its own
subcommands.
[Example:](03_04_subcommands.rs)
```console
$ 03_04_subcommands help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_04_subcommands[EXE] <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
add Adds files to myapp
help Print this message or the help of the given subcommand(s)
$ 03_04_subcommands help add
03_04_subcommands[EXE]-add [..]
Adds files to myapp
USAGE:
03_04_subcommands[EXE] add [NAME]
ARGS:
<NAME>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
$ 03_04_subcommands add bob
'myapp add' was used, name is: Some("bob")
```
Because we set `Command::arg_required_else_help`:
```console
$ 03_04_subcommands
? failed
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_04_subcommands[EXE] <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
add Adds files to myapp
help Print this message or the help of the given subcommand(s)
```
Because we set `Command::propagate_version`:
```console
$ 03_04_subcommands --version
clap [..]
$ 03_04_subcommands add --version
03_04_subcommands[EXE]-add [..]
```
### Defaults
We've previously showed that arguments can be `required` or optional. When
optional, you work with a `Option` and can `unwrap_or`. Alternatively, you can
set `Arg::default_value`.
[Example:](03_05_default_values.rs)
```console
$ 03_05_default_values --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
03_05_default_values[EXE] [NAME]
ARGS:
<NAME> [default: alice]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
$ 03_05_default_values
NAME: "alice"
$ 03_05_default_values bob
NAME: "bob"
```
## Validation
### Enumerated values
If you have arguments of specific values you want to test for, you can use the
`Arg::possible_values()`.
This allows you specify the valid values for that argument. If the user does not use one of
those specific values, they will receive a graceful exit with error message informing them
of the mistake, and what the possible valid values are
[Example:](04_01_possible.rs)
```console
$ 04_01_possible --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
04_01_possible[EXE] <MODE>
ARGS:
<MODE> What mode to run the program in [possible values: fast, slow]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
$ 04_01_possible fast
Hare
$ 04_01_possible slow
Tortoise
$ 04_01_possible medium
? failed
error: "medium" isn't a valid value for '<MODE>'
[possible values: fast, slow]
USAGE:
04_01_possible[EXE] <MODE>
For more information try --help
```
When enabling the `derive` feature, you can use `ArgEnum` to take care of the boiler plate for you, giving the same results.
[Example:](04_01_enum.rs)
```console
$ 04_01_enum --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
04_01_enum[EXE] <MODE>
ARGS:
<MODE> What mode to run the program in [possible values: fast, slow]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
$ 04_01_enum fast
Hare
$ 04_01_enum slow
Tortoise
$ 04_01_enum medium
? failed
error: "medium" isn't a valid value for '<MODE>'
[possible values: fast, slow]
USAGE:
04_01_enum[EXE] <MODE>
For more information try --help
```
### Validated values
More generally, you can parse into any data type.
[Example:](04_02_parse.rs)
```console
$ 04_02_parse --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
04_02_parse[EXE] <PORT>
ARGS:
<PORT> Network port to use
OPTIONS:
-h, --help Print help information
-V, --version Print version information
$ 04_02_parse 22
PORT = 22
$ 04_02_parse foobar
? failed
error: Invalid value "foobar" for '<PORT>': invalid digit found in string
For more information try --help
```
A custom validator can be used to improve the error messages or provide additional validation:
[Example:](04_02_validate.rs)
```console
$ 04_02_validate --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
04_02_validate[EXE] <PORT>
ARGS:
<PORT> Network port to use
OPTIONS:
-h, --help Print help information
-V, --version Print version information
$ 04_02_validate 22
PORT = 22
$ 04_02_validate foobar
? failed
error: Invalid value "foobar" for '<PORT>': `foobar` isn't a port number
For more information try --help
$ 04_02_validate 0
? failed
error: Invalid value "0" for '<PORT>': Port not in range 1-65535
For more information try --help
```
### Argument Relations
You can declare dependencies or conflicts between `Arg`s or even `ArgGroup`s.
`ArgGroup`s make it easier to declare relations instead of having to list each
individually, or when you want a rule to apply "any but not all" arguments.
Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be
present out of a given set. Imagine that you had multiple arguments, and you want one of them to
be required, but making all of them required isn't feasible because perhaps they conflict with
each other.
[Example:](04_03_relations.rs)
```console
$ 04_03_relations --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
04_03_relations[EXE] [OPTIONS] <--set-ver <VER>|--major|--minor|--patch> [INPUT_FILE]
ARGS:
<INPUT_FILE> some regular input
OPTIONS:
-c <CONFIG>
-h, --help Print help information
--major auto inc major
--minor auto inc minor
--patch auto inc patch
--set-ver <VER> set version manually
--spec-in <SPEC_IN> some special input argument
-V, --version Print version information
$ 04_03_relations
? failed
error: The following required arguments were not provided:
<--set-ver <VER>|--major|--minor|--patch>
USAGE:
04_03_relations[EXE] [OPTIONS] <--set-ver <VER>|--major|--minor|--patch> [INPUT_FILE]
For more information try --help
$ 04_03_relations --major
Version: 2.2.3
$ 04_03_relations --major --minor
? failed
error: The argument '--major' cannot be used with '--minor'
USAGE:
04_03_relations[EXE] <--set-ver <VER>|--major|--minor|--patch>
For more information try --help
$ 04_03_relations --major -c config.toml
? failed
error: The following required arguments were not provided:
<INPUT_FILE|--spec-in <SPEC_IN>>
USAGE:
04_03_relations[EXE] -c <CONFIG> <--set-ver <VER>|--major|--minor|--patch> <INPUT_FILE|--spec-in <SPEC_IN>>
For more information try --help
$ 04_03_relations --major -c config.toml --spec-in input.txt
Version: 2.2.3
Doing work using input input.txt and config config.toml
```
### Custom Validation
As a last resort, you can create custom errors with the basics of clap's formatting.
[Example:](04_04_custom.rs)
```console
$ 04_04_custom --help
clap [..]
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
04_04_custom[EXE] [OPTIONS] [INPUT_FILE]
ARGS:
<INPUT_FILE> some regular input
OPTIONS:
-c <CONFIG>
-h, --help Print help information
--major auto inc major
--minor auto inc minor
--patch auto inc patch
--set-ver <VER> set version manually
--spec-in <SPEC_IN> some special input argument
-V, --version Print version information
$ 04_04_custom
? failed
error: Can only modify one version field
USAGE:
04_04_custom[EXE] [OPTIONS] [INPUT_FILE]
For more information try --help
$ 04_04_custom --major
Version: 2.2.3
$ 04_04_custom --major --minor
? failed
error: Can only modify one version field
USAGE:
04_04_custom[EXE] [OPTIONS] [INPUT_FILE]
For more information try --help
$ 04_04_custom --major -c config.toml
? failed
Version: 2.2.3
error: INPUT_FILE or --spec-in is required when using --config
USAGE:
04_04_custom[EXE] [OPTIONS] [INPUT_FILE]
For more information try --help
$ 04_04_custom --major -c config.toml --spec-in input.txt
Version: 2.2.3
Doing work using input input.txt and config config.toml
```
## Tips
- For more complex demonstration of features, see our [examples](../README.md).
- Proactively check for bad `Command` configurations by calling `Command::debug_assert` in a test ([example](05_01_assert.rs))
## Contributing
New example code:
- Please update the corresponding section in the [derive tutorial](../tutorial_derive/README.md)
- Building: They must be added to [Cargo.toml](../../Cargo.toml) with the appropriate `required-features`.
- Testing: Ensure there is a markdown file with [trycmd](https://docs.rs/trycmd) syntax (generally they'll go in here).
See also the general [CONTRIBUTING](../../CONTRIBUTING.md).

Просмотреть файл

@ -1,35 +0,0 @@
```console
$ 01_quick_derive --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 01_quick_derive[EXE] [OPTIONS] [NAME] [COMMAND]
Commands:
test does testing things
help Print this message or the help of the given subcommand(s)
Arguments:
[NAME] Optional name to operate on
Options:
-c, --config <FILE> Sets a custom config file
-d, --debug... Turn debugging information on
-h, --help Print help
-V, --version Print version
```
By default, the program does nothing:
```console
$ 01_quick_derive
Debug mode is off
```
But you can mix and match the various features
```console
$ 01_quick_derive -dd test
Debug mode is on
Not printing testing lists...
```

Просмотреть файл

@ -3,20 +3,20 @@ use std::path::PathBuf;
use clap::{Parser, Subcommand};
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[clap(author, version, about, long_about = None)]
struct Cli {
/// Optional name to operate on
name: Option<String>,
/// Sets a custom config file
#[arg(short, long, value_name = "FILE")]
#[clap(short, long, parse(from_os_str), value_name = "FILE")]
config: Option<PathBuf>,
/// Turn debugging information on
#[arg(short, long, action = clap::ArgAction::Count)]
debug: u8,
#[clap(short, long, parse(from_occurrences))]
debug: usize,
#[command(subcommand)]
#[clap(subcommand)]
command: Option<Commands>,
}
@ -25,7 +25,7 @@ enum Commands {
/// does testing things
Test {
/// lists test values
#[arg(short, long)]
#[clap(short, long)]
list: bool,
},
}
@ -35,7 +35,7 @@ fn main() {
// You can check the value provided by positional arguments, or option arguments
if let Some(name) = cli.name.as_deref() {
println!("Value for name: {name}");
println!("Value for name: {}", name);
}
if let Some(config_path) = cli.config.as_deref() {

Просмотреть файл

@ -1,17 +0,0 @@
```console
$ 02_app_settings_derive --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 02_app_settings_derive[EXE] --two <TWO> --one <ONE>
Options:
--two <TWO>
--one <ONE>
-h, --help
Print help
-V, --version
Print version
```

Просмотреть файл

@ -1,12 +1,14 @@
use clap::Parser;
use clap::{AppSettings, Parser};
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[command(next_line_help = true)]
#[clap(author, version, about, long_about = None)]
#[clap(args_override_self = true)]
#[clap(allow_negative_numbers = true)]
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
struct Cli {
#[arg(long)]
#[clap(long)]
two: String,
#[arg(long)]
#[clap(long)]
one: String,
}

Просмотреть файл

@ -1,16 +0,0 @@
```console
$ 02_apps_derive --help
Does awesome things
Usage: 02_apps_derive[EXE] --two <TWO> --one <ONE>
Options:
--two <TWO>
--one <ONE>
-h, --help Print help
-V, --version Print version
$ 02_apps_derive --version
MyApp 1.0
```

Просмотреть файл

@ -1,14 +1,14 @@
use clap::Parser;
#[derive(Parser)]
#[command(name = "MyApp")]
#[command(author = "Kevin K. <kbknapp@gmail.com>")]
#[command(version = "1.0")]
#[command(about = "Does awesome things", long_about = None)]
#[clap(name = "MyApp")]
#[clap(author = "Kevin K. <kbknapp@gmail.com>")]
#[clap(version = "1.0")]
#[clap(about = "Does awesome things", long_about = None)]
struct Cli {
#[arg(long)]
#[clap(long)]
two: String,
#[arg(long)]
#[clap(long)]
one: String,
}

Просмотреть файл

@ -1,16 +0,0 @@
```console
$ 02_crate_derive --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 02_crate_derive[EXE] --two <TWO> --one <ONE>
Options:
--two <TWO>
--one <ONE>
-h, --help Print help
-V, --version Print version
$ 02_crate_derive --version
clap [..]
```

Просмотреть файл

@ -1,11 +1,11 @@
use clap::Parser;
#[derive(Parser)]
#[command(author, version, about, long_about = None)] // Read from `Cargo.toml`
#[clap(author, version, about, long_about = None)]
struct Cli {
#[arg(long)]
#[clap(long)]
two: String,
#[arg(long)]
#[clap(long)]
one: String,
}

Просмотреть файл

@ -1,26 +0,0 @@
```console
$ 03_01_flag_bool_derive --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 03_01_flag_bool_derive[EXE] [OPTIONS]
Options:
-v, --verbose
-h, --help Print help
-V, --version Print version
$ 03_01_flag_bool_derive
verbose: false
$ 03_01_flag_bool_derive --verbose
verbose: true
$ 03_01_flag_bool_derive --verbose --verbose
? failed
error: the argument '--verbose' cannot be used multiple times
Usage: 03_01_flag_bool_derive[EXE] [OPTIONS]
For more information, try '--help'.
```

Просмотреть файл

@ -1,9 +1,9 @@
use clap::Parser;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[clap(author, version, about, long_about = None)]
struct Cli {
#[arg(short, long)]
#[clap(short, long)]
verbose: bool,
}

Просмотреть файл

@ -1,21 +0,0 @@
```console
$ 03_01_flag_count_derive --help
A simple to use, efficient, and full-featured Command Line Argument Parser
Usage: 03_01_flag_count_derive[EXE] [OPTIONS]
Options:
-v, --verbose...
-h, --help Print help
-V, --version Print version
$ 03_01_flag_count_derive
verbose: 0
$ 03_01_flag_count_derive --verbose
verbose: 1
$ 03_01_flag_count_derive --verbose --verbose
verbose: 2
```

Просмотреть файл

@ -1,10 +1,10 @@
use clap::Parser;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
#[clap(author, version, about, long_about = None)]
struct Cli {
#[arg(short, long, action = clap::ArgAction::Count)]
verbose: u8,
#[clap(short, long, parse(from_occurrences))]
verbose: usize,
}
fn main() {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше