diff --git a/src/cli.rs b/src/cli.rs index c6246bd..e424d93 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -191,8 +191,7 @@ It's also possible to specify the preference using environment variables. See ClapCommand { - subcommand_gen("eval") -} - -pub fn deprecated_alias() -> ClapCommand { - subcommand_gen("introspect").hide(true) -} - -fn subcommand_gen(name: &'static str) -> ClapCommand { - ClapCommand::new(name) - .about("Evaluate an expression using the complete configuration") - .long_about(r#"Evaluate an expression using the complete configuration +#[derive(Debug, Args)] +#[command( + name = "eval", + alias = "introspect", + about = "Evaluate an expression using the complete configuration", + long_about = r#"Evaluate an expression using the complete configuration Your expression should take an attribute set with keys `pkgs`, `lib` and `nodes` (like a NixOS module) and return a JSON-serializable value. For example, to retrieve the configuration of one node, you may write something like: { nodes, ... }: nodes.node-a.config.networking.hostName -"#) - .arg(Arg::new("expression_file") - .index(1) - .value_name("FILE") - .help("The .nix file containing the expression") - .num_args(1) - .value_parser(value_parser!(PathBuf))) - .arg(Arg::new("expression") - .short('E') - .value_name("EXPRESSION") - .help("The Nix expression") - .num_args(1)) - .arg(Arg::new("instantiate") - .long("instantiate") - .help("Actually instantiate the expression") - .num_args(0)) +"# +)] +pub struct Opts { + #[arg(short = 'E', value_name = "EXPRESSION", help = "The Nix expression")] + expression: Option, + #[arg(long, help = "Actually instantiate the expression")] + instantiate: bool, + #[arg( + value_name = "FILE", + help = "The .nix file containing the expression", + conflicts_with("expression") + )] + expression_file: Option, +} + +pub fn subcommand() -> ClapCommand { + Opts::augment_args(ClapCommand::new("eval")) } pub async fn run(global_args: &ArgMatches, local_args: &ArgMatches) -> Result<(), ColmenaError> { @@ -54,31 +49,29 @@ pub async fn run(global_args: &ArgMatches, local_args: &ArgMatches) -> Result<() .await .unwrap(); - if !(local_args.contains_id("expression") ^ local_args.contains_id("expression_file")) { - log::error!("Either an expression (-E) or a .nix file containing an expression should be specified, not both."); - quit::with_code(1); - } + let Opts { + instantiate, + expression, + expression_file, + } = Opts::from_arg_matches(local_args).expect("Failed to parse args"); - let expression = if local_args.contains_id("expression") { - local_args - .get_one::("expression") - .unwrap() - .to_owned() - } else { - let path = local_args - .get_one::("expression_file") - .unwrap() - .to_owned(); - format!( - "import {}", - path.canonicalize() - .expect("Could not generate absolute path to expression file.") - .to_str() - .unwrap() - ) + let expression = expression_file + .map(|path| { + format!( + "import {}", + path.canonicalize() + .expect("Could not generate absolute path to expression file.") + .to_str() + .unwrap() + ) + }) + .or(expression); + + let Some(expression) = expression else { + log::error!("Provide either an expression (-E) or a .nix file containing an expression."); + quit::with_code(1); }; - let instantiate = local_args.get_flag("instantiate"); let result = hive.introspect(expression, instantiate).await?; if instantiate {