v2_argh_wrapper/
lib.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use anyhow::{bail, Error};
6use log::warn;
7
8/// Loads an argh struct from the command line.
9///
10/// We can't just use the one-line argh parse in v2, because that writes to stdout
11/// and stdout doesn't currently work in v2 components. Instead, grab and
12/// log the output.
13pub fn load_command_line<T: argh::FromArgs>() -> Result<T, Error> {
14    load_from_strings(std::env::args().collect::<Vec<_>>())
15}
16
17fn load_from_strings<T: argh::FromArgs>(arg_strings: Vec<String>) -> Result<T, Error> {
18    let arg_strs: Vec<&str> = arg_strings.iter().map(|s| s.as_str()).collect();
19    match T::from_args(&[arg_strs[0]], &arg_strs[1..]) {
20        Ok(args) => Ok(args),
21        Err(output) => {
22            for line in output.output.split("\n") {
23                warn!("CmdLine: {}", line);
24            }
25            match output.status {
26                Ok(()) => bail!("Exited as requested by command line args"),
27                Err(()) => bail!("Exited due to bad command line args"),
28            }
29        }
30    }
31}
32
33#[cfg(test)]
34mod test {
35    use super::*;
36    use argh::FromArgs;
37
38    /// Top-level command.
39    #[derive(FromArgs, PartialEq, Debug)]
40    struct OuterArgs {
41        /// subcommands
42        #[argh(subcommand)]
43        sub: SubChoices,
44    }
45
46    /// Sub struct options
47    #[derive(FromArgs, PartialEq, Debug)]
48    #[argh(subcommand)]
49    enum SubChoices {
50        Child(CreateChildArgs),
51    }
52
53    /// One (the only) possible subcommmand
54    #[derive(FromArgs, PartialEq, Debug)]
55    #[argh(subcommand, name = "child")]
56    struct CreateChildArgs {
57        /// argh requires doc commands on everything
58        #[argh(option)]
59        option: u32,
60    }
61
62    #[fuchsia::test]
63    fn args_work() -> Result<(), Error> {
64        let arg_strings = vec![
65            "program_name".to_string(),
66            "child".to_string(),
67            "--option".to_string(),
68            "42".to_string(),
69        ];
70        let args = load_from_strings::<OuterArgs>(arg_strings)?;
71        let SubChoices::Child(child_args) = args.sub;
72        assert_eq!(child_args.option, 42);
73        Ok(())
74    }
75}