1#[cfg(feature = "host")]
2#[macro_use]
3mod macros;
4#[cfg(feature = "cli")]
5mod data_center;
6#[cfg(feature = "host")]
7mod leaf;
8pub mod node;
9#[cfg(feature = "cli")]
10mod node_operator;
11#[cfg(feature = "cli")]
12mod node_provider;
13pub mod proposals;
14pub mod registry;
15#[cfg(feature = "host")]
16pub mod render;
17#[cfg(feature = "cli")]
18mod subnet;
19#[cfg(feature = "cli")]
20mod topology;
21
22#[cfg(all(test, feature = "cli"))]
23mod tests;
24
25#[cfg(feature = "cli")]
26use crate::{
27 cli::{
28 clap::{
29 parse_matches_or_usage, parse_required_subcommand_or_usage, passthrough_subcommand,
30 render_help,
31 },
32 common::{CurrentUnixSecsError, OutputFormat, current_unix_secs, write_text_or_json},
33 help::{collect_args_or_print_help_or_version, collect_args_or_print_help_or_version_flag},
34 },
35 nns::{
36 data_center::report::NnsDataCenterHostError, node::report::NnsNodeHostError,
37 node_operator::report::NnsNodeOperatorHostError,
38 node_provider::report::NnsNodeProviderHostError, proposals::NnsProposalHostError,
39 registry::report::NnsRegistryHostError, topology::report::NnsTopologyHostError,
40 },
41 project::icp_root as project_icp_root,
42 subnet_catalog::SubnetCatalogHostError,
43 version_text,
44};
45#[cfg(feature = "cli")]
46use clap::{ArgMatches, Command as ClapCommand};
47#[cfg(feature = "cli")]
48use std::{ffi::OsString, io, path::PathBuf};
49#[cfg(feature = "cli")]
50use thiserror::Error as ThisError;
51
52#[cfg(feature = "cli")]
56#[derive(Debug, ThisError)]
57pub enum NnsCommandError {
58 #[error("{0}")]
59 Usage(String),
60
61 #[error(transparent)]
62 SubnetHost(#[from] SubnetCatalogHostError),
63
64 #[error(transparent)]
65 DataCenterHost(#[from] NnsDataCenterHostError),
66
67 #[error(transparent)]
68 NodeHost(#[from] NnsNodeHostError),
69
70 #[error(transparent)]
71 NodeProviderHost(#[from] NnsNodeProviderHostError),
72
73 #[error(transparent)]
74 NodeOperatorHost(#[from] NnsNodeOperatorHostError),
75
76 #[error(transparent)]
77 ProposalHost(#[from] NnsProposalHostError),
78
79 #[error(transparent)]
80 RegistryHost(#[from] NnsRegistryHostError),
81
82 #[error(transparent)]
83 TopologyHost(#[from] NnsTopologyHostError),
84
85 #[error(transparent)]
86 Clock(#[from] CurrentUnixSecsError),
87
88 #[error(transparent)]
89 Io(#[from] io::Error),
90
91 #[error(transparent)]
92 Json(#[from] serde_json::Error),
93}
94
95#[cfg(feature = "cli")]
96pub fn run<I>(args: I) -> Result<(), NnsCommandError>
97where
98 I: IntoIterator<Item = OsString>,
99{
100 let Some(args) = command_args(args, usage) else {
101 return Ok(());
102 };
103 let (command, args) = parse_nns_required_subcommand(nns_command(), args, usage)?;
104
105 match command.as_str() {
106 "subnet" => subnet::run(args),
107 "data-center" => data_center::run(args),
108 "node" => node::run(args),
109 "node-provider" => node_provider::run(args),
110 "node-operator" => node_operator::run(args),
111 "proposal" => proposals::run(args),
112 "registry" => registry::run(args),
113 "topology" => topology::run(args),
114 _ => unreachable!("nns dispatch command only defines known commands"),
115 }
116}
117
118#[cfg(feature = "cli")]
119pub(in crate::nns) fn command_args<I>(
120 args: I,
121 usage: impl FnOnce() -> String,
122) -> Option<Vec<OsString>>
123where
124 I: IntoIterator<Item = OsString>,
125{
126 collect_args_or_print_help_or_version(args, usage, version_text())
127}
128
129#[cfg(feature = "cli")]
130pub(in crate::nns) fn command_flag_args<I>(
131 args: I,
132 usage: impl FnOnce() -> String,
133) -> Option<Vec<OsString>>
134where
135 I: IntoIterator<Item = OsString>,
136{
137 collect_args_or_print_help_or_version_flag(args, usage, version_text())
138}
139
140#[cfg(feature = "cli")]
141pub(in crate::nns) fn parse_nns_matches<I>(
142 command: ClapCommand,
143 args: I,
144 usage: impl FnOnce() -> String,
145) -> Result<ArgMatches, NnsCommandError>
146where
147 I: IntoIterator<Item = OsString>,
148{
149 parse_matches_or_usage(command, args, usage).map_err(NnsCommandError::Usage)
150}
151
152#[cfg(feature = "cli")]
153pub(in crate::nns) fn parse_nns_required_subcommand<I>(
154 command: ClapCommand,
155 args: I,
156 usage: impl FnOnce() -> String,
157) -> Result<(String, Vec<OsString>), NnsCommandError>
158where
159 I: IntoIterator<Item = OsString>,
160{
161 parse_required_subcommand_or_usage(command, args, usage).map_err(NnsCommandError::Usage)
162}
163
164#[cfg(feature = "cli")]
165fn now_unix_secs() -> Result<u64, NnsCommandError> {
166 Ok(current_unix_secs()?)
167}
168
169#[cfg(feature = "cli")]
170fn command_icp_root() -> Result<PathBuf, NnsCommandError> {
171 project_icp_root().map_err(|err| NnsCommandError::Usage(err.to_string()))
172}
173
174#[cfg(feature = "cli")]
175fn nns_command() -> ClapCommand {
176 ClapCommand::new("nns")
177 .bin_name("icq nns")
178 .about("Inspect NNS metadata")
179 .disable_help_flag(true)
180 .subcommand(passthrough_subcommand(
181 ClapCommand::new("subnet").about("Inspect and refresh NNS subnet metadata"),
182 ))
183 .subcommand(passthrough_subcommand(
184 ClapCommand::new("data-center").about("Inspect NNS data-center metadata"),
185 ))
186 .subcommand(passthrough_subcommand(
187 ClapCommand::new("node").about("Inspect NNS node metadata"),
188 ))
189 .subcommand(passthrough_subcommand(
190 ClapCommand::new("node-provider").about("Inspect NNS node-provider metadata"),
191 ))
192 .subcommand(passthrough_subcommand(
193 ClapCommand::new("node-operator").about("Inspect NNS node-operator metadata"),
194 ))
195 .subcommand(passthrough_subcommand(
196 ClapCommand::new("proposal").about("Inspect NNS governance proposals"),
197 ))
198 .subcommand(passthrough_subcommand(
199 ClapCommand::new("registry").about("Inspect NNS registry metadata"),
200 ))
201 .subcommand(passthrough_subcommand(
202 ClapCommand::new("topology").about("Summarize joined NNS topology metadata"),
203 ))
204}
205
206#[cfg(feature = "cli")]
207fn usage() -> String {
208 render_help(nns_command())
209}