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#[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#[cfg(feature = "cli")]
68pub fn run_from_env() -> Result<(), IcQueryError> {
69 run(std::env::args_os().skip(1))
70}
71
72#[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;