1use clap::Parser;
2
3#[derive(Debug, Parser)]
4#[command(author, version, about, long_about = None)]
5struct Args {
6 #[arg(long)]
7 bin: Option<String>,
8 #[arg(long)]
9 force: bool,
10}
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct CliArgs {
14 pub bin: Option<String>,
15 pub force: bool,
16}
17
18pub fn parse_args<I, T>(args: I) -> Result<CliArgs, clap::Error>
19where
20 I: IntoIterator<Item = T>,
21 T: Into<std::ffi::OsString> + Clone,
22{
23 let mut args_iter = args.into_iter();
24 let program = args_iter.next();
25 let mut remaining: Vec<T> = args_iter.collect();
26
27 if remaining
28 .first()
29 .map(|arg| arg.clone().into())
30 .as_ref()
31 .map(|arg| arg == "dev-install")
32 .unwrap_or(false)
33 {
34 remaining.remove(0);
35 }
36
37 let mut argv = Vec::with_capacity(1 + remaining.len());
38 if let Some(program) = program {
39 argv.push(program);
40 }
41 argv.extend(remaining);
42
43 let parsed = Args::try_parse_from(argv)?;
44 Ok(CliArgs {
45 bin: parsed.bin,
46 force: parsed.force,
47 })
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 #[test]
55 fn parses_default_args() {
56 let args = parse_args(["cargo-dev-install"]).expect("parse args");
57 assert_eq!(
58 args,
59 CliArgs {
60 bin: None,
61 force: false,
62 }
63 );
64 }
65
66 #[test]
67 fn parses_bin_and_force() {
68 let args =
69 parse_args(["cargo-dev-install", "--bin", "demo", "--force"]).expect("parse args");
70 assert_eq!(
71 args,
72 CliArgs {
73 bin: Some("demo".to_string()),
74 force: true,
75 }
76 );
77 }
78
79 #[test]
80 fn parses_subcommand_invocation() {
81 let args = parse_args(["cargo", "dev-install", "--force"]).expect("parse args");
82 assert_eq!(
83 args,
84 CliArgs {
85 bin: None,
86 force: true,
87 }
88 );
89 }
90
91 #[test]
92 fn errors_on_unknown_flag() {
93 let err = parse_args(["cargo-dev-install", "--unknown"])
94 .expect_err("expected error for unknown flag");
95 assert_eq!(err.kind(), clap::error::ErrorKind::UnknownArgument);
96 }
97}