Skip to main content

ic_query/
lib.rs

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