Convert eval arguments to type-safe clap derive

This commit is contained in:
i1i1 2023-08-10 01:47:10 +03:00 committed by Zhaofeng Li
parent cdfc1f15a1
commit 5b8611744b
2 changed files with 45 additions and 53 deletions

View file

@ -191,8 +191,7 @@ It's also possible to specify the preference using environment variables. See <h
),
);
// deprecated alias
app = app.subcommand(command::eval::deprecated_alias());
// TODO: handle deprecated alias
#[cfg(debug_assertions)]
register_command!(test_progress, app);

View file

@ -1,44 +1,39 @@
use std::path::PathBuf;
use clap::{value_parser, Arg, ArgMatches, Command as ClapCommand, FromArgMatches};
use clap::{ArgMatches, Args, Command as ClapCommand, FromArgMatches};
use crate::error::ColmenaError;
use crate::nix::hive::HiveArgs;
pub fn subcommand() -> 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<String>,
#[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<PathBuf>,
}
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::<String>("expression")
.unwrap()
.to_owned()
} else {
let path = local_args
.get_one::<PathBuf>("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 {