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