Skip to main content

ic_query/
lib.rs

1mod cache_file;
2mod cli;
3mod duration;
4mod ic_registry;
5mod nns;
6mod output;
7mod project;
8mod runtime;
9mod sns;
10pub mod subnet_catalog;
11mod table;
12
13#[cfg(test)]
14mod test_support;
15
16use crate::cli::{
17    clap::{parse_matches, string_option},
18    globals::{
19        DISPATCH_ARGS, apply_global_network, command_local_global_option,
20        top_level_dispatch_command,
21    },
22    help::{first_arg_is_help, usage},
23};
24use std::ffi::OsString;
25use thiserror::Error as ThisError;
26
27const VERSION_TEXT: &str = concat!("icq ", env!("CARGO_PKG_VERSION"));
28
29///
30/// IcQueryError
31///
32#[derive(Debug, ThisError)]
33pub enum IcQueryError {
34    #[error("{0}")]
35    Usage(String),
36
37    #[error("nns: {0}")]
38    Nns(String),
39
40    #[error("sns: {0}")]
41    Sns(String),
42}
43
44/// Run the CLI from process arguments.
45pub fn run_from_env() -> Result<(), IcQueryError> {
46    run(std::env::args_os().skip(1))
47}
48
49/// Run the CLI from an argument iterator.
50pub fn run<I>(args: I) -> Result<(), IcQueryError>
51where
52    I: IntoIterator<Item = OsString>,
53{
54    let args = args.into_iter().collect::<Vec<_>>();
55    if first_arg_is_help(&args) {
56        println!("{}", usage());
57        return Ok(());
58    }
59    if let Some(option) = command_local_global_option(&args) {
60        return Err(IcQueryError::Usage(format!(
61            "{option} is a top-level option; put it before the command\n\n{}",
62            usage()
63        )));
64    }
65
66    let matches = parse_matches(top_level_dispatch_command(), args)
67        .map_err(|_| IcQueryError::Usage(usage()))?;
68    if matches.get_flag("version") {
69        println!("{}", version_text());
70        return Ok(());
71    }
72    let global_network = string_option(&matches, "network");
73
74    let Some((command, subcommand_matches)) = matches.subcommand() else {
75        return Err(IcQueryError::Usage(usage()));
76    };
77    let mut tail = subcommand_matches
78        .get_many::<OsString>(DISPATCH_ARGS)
79        .map(|values| values.cloned().collect::<Vec<_>>())
80        .unwrap_or_default();
81    apply_global_network(command, &mut tail, global_network);
82    let tail = tail.into_iter();
83
84    match command {
85        "nns" => nns::run(tail).map_err(|err| IcQueryError::Nns(err.to_string())),
86        "sns" => sns::run(tail).map_err(|err| IcQueryError::Sns(err.to_string())),
87        _ => unreachable!("top-level dispatch command only defines known commands"),
88    }
89}
90
91#[must_use]
92pub const fn version_text() -> &'static str {
93    VERSION_TEXT
94}
95
96#[cfg(test)]
97mod tests;