Skip to main content

ic_query/
lib.rs

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