use super::ListCommandError;
use crate::args::{default_dfx, flag_arg, parse_matches, value_arg};
use clap::Command as ClapCommand;
use std::ffi::OsString;
const LIST_HELP_AFTER: &str = "\
Examples:
canic list test
canic list test --from user_hub
canic list test --root uzt4z-lp777-77774-qaabq-cai";
const CONFIG_HELP_AFTER: &str = "\
Examples:
canic config test
canic config test --from user_hub
canic config test --verbose";
#[derive(Clone, Debug, Eq, PartialEq)]
pub(super) struct ListOptions {
pub(super) source: ListSource,
pub(super) fleet: String,
pub(super) root: Option<String>,
pub(super) anchor: Option<String>,
pub(super) network: Option<String>,
pub(super) dfx: String,
pub(super) verbose: bool,
}
impl ListOptions {
pub(super) fn parse_list<I>(args: I) -> Result<Self, ListCommandError>
where
I: IntoIterator<Item = OsString>,
{
let matches =
parse_matches(list_command(), args).map_err(|_| ListCommandError::Usage(usage()))?;
Ok(Self::from_matches(&matches, ListSource::RootRegistry))
}
pub(super) fn parse_config<I>(args: I) -> Result<Self, ListCommandError>
where
I: IntoIterator<Item = OsString>,
{
let matches = parse_matches(config_command(), args)
.map_err(|_| ListCommandError::Usage(config_usage()))?;
Ok(Self::from_matches(&matches, ListSource::Config))
}
fn from_matches(matches: &clap::ArgMatches, source: ListSource) -> Self {
Self {
source,
fleet: optional_string(matches, "fleet").expect("clap requires fleet"),
root: optional_string(matches, "root"),
anchor: optional_string(matches, "from"),
network: optional_string(matches, "network"),
dfx: optional_string(matches, "dfx").unwrap_or_else(default_dfx),
verbose: optional_bool(matches, "verbose"),
}
}
}
fn optional_string(matches: &clap::ArgMatches, id: &str) -> Option<String> {
matches.try_get_one::<String>(id).ok().flatten().cloned()
}
fn optional_bool(matches: &clap::ArgMatches, id: &str) -> bool {
matches
.try_get_one::<bool>(id)
.ok()
.flatten()
.copied()
.unwrap_or(false)
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(super) enum ListSource {
Config,
RootRegistry,
}
fn list_command() -> ClapCommand {
base_list_options(ClapCommand::new("list").bin_name("canic list"))
.about("List canisters registered by the deployed root")
.arg(
value_arg("fleet")
.value_name("fleet")
.required(true)
.help("Fleet name to inspect"),
)
.arg(
value_arg("root")
.long("root")
.value_name("name-or-principal")
.help("Query a specific root canister registry"),
)
.arg(
value_arg("from")
.long("from")
.value_name("name-or-principal")
.help("Render a subtree anchored at one canister"),
)
.arg(
value_arg("dfx")
.long("dfx")
.value_name("path")
.help("Path to the dfx executable"),
)
.after_help(LIST_HELP_AFTER)
}
fn config_command() -> ClapCommand {
base_list_options(ClapCommand::new("config").bin_name("canic config"))
.about("List canisters declared by the selected fleet config")
.arg(
value_arg("fleet")
.value_name("fleet")
.required(true)
.help("Fleet name to inspect"),
)
.arg(
value_arg("from")
.long("from")
.value_name("role")
.help("Show one declared role"),
)
.arg(
flag_arg("verbose")
.long("verbose")
.help("Show indented declared config details under each role"),
)
.after_help(CONFIG_HELP_AFTER)
}
fn base_list_options(command: ClapCommand) -> ClapCommand {
command.disable_help_flag(true).arg(
value_arg("network")
.long("network")
.value_name("name")
.help("DFX network to inspect"),
)
}
pub(super) fn usage() -> String {
let mut command = list_command();
command.render_help().to_string()
}
pub(super) fn config_usage() -> String {
let mut command = config_command();
command.render_help().to_string()
}