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