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