Skip to main content

ic_query/
lib.rs

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