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