Initial vendor packages

Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
2024-01-08 01:21:28 +04:00
parent 5ecd8cf2cb
commit 1b6a04ca55
7309 changed files with 2160054 additions and 0 deletions

View File

@ -0,0 +1,35 @@
```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...
```

View File

@ -0,0 +1,60 @@
use std::path::PathBuf;
use clap::{arg, command, value_parser, ArgAction, Command};
fn main() {
let matches = command!() // requires `cargo` feature
.arg(arg!([name] "Optional name to operate on"))
.arg(
arg!(
-c --config <FILE> "Sets a custom config file"
)
// We don't have syntax yet for optional options, so manually calling `required`
.required(false)
.value_parser(value_parser!(PathBuf)),
)
.arg(arg!(
-d --debug ... "Turn debugging information on"
))
.subcommand(
Command::new("test")
.about("does testing things")
.arg(arg!(-l --list "lists test values").action(ArgAction::SetTrue)),
)
.get_matches();
// You can check the value provided by positional arguments, or option arguments
if let Some(name) = matches.get_one::<String>("name") {
println!("Value for name: {name}");
}
if let Some(config_path) = matches.get_one::<PathBuf>("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")
{
0 => println!("Debug mode is off"),
1 => println!("Debug mode is kind of on"),
2 => println!("Debug mode is on"),
_ => println!("Don't be crazy"),
}
// You can check for the existence of subcommands, and if found use their
// 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") {
// "$ myapp test -l" was run
println!("Printing testing lists...");
} else {
println!("Not printing testing lists...");
}
}
// Continued program logic goes here...
}

View File

@ -0,0 +1,17 @@
```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
```

View File

@ -0,0 +1,18 @@
use clap::{arg, command, ArgAction};
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))
.get_matches();
println!(
"two: {:?}",
matches.get_one::<String>("two").expect("required")
);
println!(
"one: {:?}",
matches.get_one::<String>("one").expect("required")
);
}

View File

@ -0,0 +1,16 @@
```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
```

View File

@ -0,0 +1,20 @@
use clap::{arg, Command};
fn main() {
let matches = Command::new("MyApp")
.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))
.get_matches();
println!(
"two: {:?}",
matches.get_one::<String>("two").expect("required")
);
println!(
"one: {:?}",
matches.get_one::<String>("one").expect("required")
);
}

View File

@ -0,0 +1,16 @@
```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 [..]
```

View File

@ -0,0 +1,18 @@
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))
.get_matches();
println!(
"two: {:?}",
matches.get_one::<String>("two").expect("required")
);
println!(
"one: {:?}",
matches.get_one::<String>("one").expect("required")
);
}

View File

@ -0,0 +1,26 @@
```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'.
```

View File

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

View File

@ -0,0 +1,21 @@
```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
```

View File

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

View File

@ -0,0 +1,30 @@
```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")
```

View File

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

View File

@ -0,0 +1,30 @@
```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")
```

View File

@ -0,0 +1,14 @@
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"));
}

View File

@ -0,0 +1,20 @@
```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")
```

View File

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

View File

@ -0,0 +1,23 @@
```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"]
```

View File

@ -0,0 +1,15 @@
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);
}

View File

@ -0,0 +1,59 @@
```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
```
Since we specified [`Command::propagate_version`][crate::Command::propagate_version], the `--version` flag
is available in all subcommands:
```console
$ 03_04_subcommands --version
clap [..]
$ 03_04_subcommands add --version
clap-add [..]
```

View File

@ -0,0 +1,22 @@
use clap::{arg, command, Command};
fn main() {
let matches = command!() // requires `cargo` feature
.propagate_version(true)
.subcommand_required(true)
.arg_required_else_help(true)
.subcommand(
Command::new("add")
.about("Adds files to myapp")
.arg(arg!([NAME])),
)
.get_matches();
match matches.subcommand() {
Some(("add", sub_matches)) => println!(
"'myapp add' was used, name is: {:?}",
sub_matches.get_one::<String>("NAME")
),
_ => unreachable!("Exhausted list of subcommands and subcommand_required prevents `None`"),
}
}

View File

@ -0,0 +1,20 @@
```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
```

View File

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

View File

@ -0,0 +1,47 @@
```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'.
```

View File

@ -0,0 +1,66 @@
use clap::{arg, builder::PossibleValue, command, value_parser, ValueEnum};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
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 std::fmt::Display for Mode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_possible_value()
.expect("no values are skipped")
.get_name()
.fmt(f)
}
}
impl std::str::FromStr for Mode {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
for variant in Self::value_variants() {
if variant.to_possible_value().unwrap().matches(s, false) {
return Ok(*variant);
}
}
Err(format!("invalid variant: {s}"))
}
}
fn main() {
let matches = command!() // requires `cargo` feature
.arg(
arg!(<MODE>)
.help("What mode to run the program in")
.value_parser(value_parser!(Mode)),
)
.get_matches();
// Note, it's safe to call unwrap() because the arg is required
match matches
.get_one::<Mode>("MODE")
.expect("'MODE' is required and parsing will fail if its missing")
{
Mode::Fast => {
println!("Hare");
}
Mode::Slow => {
println!("Tortoise");
}
}
}

View File

@ -0,0 +1,27 @@
```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'.
```

View File

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

View File

@ -0,0 +1,29 @@
```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'.
```

View File

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

View File

@ -0,0 +1,29 @@
```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'.
```

View File

@ -0,0 +1,36 @@
use std::ops::RangeInclusive;
use clap::{arg, command};
fn main() {
let matches = command!() // requires `cargo` feature
.arg(
arg!(<PORT>)
.help("Network port to use")
.value_parser(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")
.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> {
let port: usize = s
.parse()
.map_err(|_| format!("`{s}` isn't a port number"))?;
if PORT_RANGE.contains(&port) {
Ok(port as u16)
} else {
Err(format!(
"port not in range {}-{}",
PORT_RANGE.start(),
PORT_RANGE.end()
))
}
}

View File

@ -0,0 +1,53 @@
```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
```

View File

@ -0,0 +1,78 @@
use std::path::PathBuf;
use clap::{arg, command, value_parser, ArgAction, ArgGroup};
fn main() {
// Create application like normal
let matches = command!() // requires `cargo` feature
// 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))
// Create a group, make it required, and add the above arguments
.group(
ArgGroup::new("vers")
.required(true)
.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!(--"spec-in" <SPEC_IN> "some special input argument")
.value_parser(value_parser!(PathBuf))
.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"),
)
.get_matches();
// Let's assume the old version 1.2.3
let mut major = 1;
let mut minor = 2;
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()
} 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"),
);
match (maj, min, pat) {
(true, _, _) => major += 1,
(_, true, _) => minor += 1,
(_, _, true) => patch += 1,
_ => unreachable!(),
};
format!("{major}.{minor}.{patch}")
};
println!("Version: {version}");
// Check for usage of -c
if matches.contains_id("config") {
let input = matches
.get_one::<PathBuf>("INPUT_FILE")
.unwrap_or_else(|| matches.get_one::<PathBuf>("spec-in").unwrap())
.display();
println!(
"Doing work using input {} and config {}",
input,
matches.get_one::<PathBuf>("config").unwrap().display()
);
}
}

View File

@ -0,0 +1,52 @@
```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
```

View File

@ -0,0 +1,84 @@
use std::path::PathBuf;
use clap::error::ErrorKind;
use clap::{arg, command, value_parser, ArgAction};
fn main() {
// Create application like normal
let mut cmd = command!() // requires `cargo` feature
// 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))
// 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)),
)
// 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)));
let matches = cmd.get_matches_mut();
// Let's assume the old version 1.2.3
let mut major = 1;
let mut minor = 2;
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") {
cmd.error(
ErrorKind::ArgumentConflict,
"Can't do relative and absolute version change",
)
.exit();
}
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"),
);
match (maj, min, pat) {
(true, false, false) => major += 1,
(false, true, false) => minor += 1,
(false, false, true) => patch += 1,
_ => {
cmd.error(
ErrorKind::ArgumentConflict,
"Can only modify one version field",
)
.exit();
}
};
format!("{major}.{minor}.{patch}")
};
println!("Version: {version}");
// Check for usage of -c
if matches.contains_id("config") {
let input = matches
.get_one::<PathBuf>("INPUT_FILE")
.or_else(|| matches.get_one::<PathBuf>("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()
);
}
}

View File

@ -0,0 +1,25 @@
use clap::{arg, command, value_parser};
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")
.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)),
)
}
#[test]
fn verify_cmd() {
cmd().debug_assert();
}