Skip to main content

ic_query/
lib.rs

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