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, collect_args_or_print_help_or_version_flag},
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 command_flag_args<I>(
126 args: I,
127 usage: impl FnOnce() -> String,
128) -> Option<Vec<OsString>>
129where
130 I: IntoIterator<Item = OsString>,
131{
132 collect_args_or_print_help_or_version_flag(args, usage, version_text())
133}
134
135#[cfg(feature = "cli")]
136pub(in crate::nns) fn parse_nns_matches<I>(
137 command: ClapCommand,
138 args: I,
139 usage: impl FnOnce() -> String,
140) -> Result<ArgMatches, NnsCommandError>
141where
142 I: IntoIterator<Item = OsString>,
143{
144 parse_matches_or_usage(command, args, usage).map_err(NnsCommandError::Usage)
145}
146
147#[cfg(feature = "cli")]
148pub(in crate::nns) fn parse_nns_required_subcommand<I>(
149 command: ClapCommand,
150 args: I,
151 usage: impl FnOnce() -> String,
152) -> Result<(String, Vec<OsString>), NnsCommandError>
153where
154 I: IntoIterator<Item = OsString>,
155{
156 parse_required_subcommand_or_usage(command, args, usage).map_err(NnsCommandError::Usage)
157}
158
159#[cfg(feature = "cli")]
160fn now_unix_secs() -> Result<u64, NnsCommandError> {
161 Ok(current_unix_secs()?)
162}
163
164#[cfg(feature = "cli")]
165fn command_icp_root() -> Result<PathBuf, NnsCommandError> {
166 project_icp_root().map_err(|err| NnsCommandError::Usage(err.to_string()))
167}
168
169#[cfg(feature = "cli")]
170fn nns_command() -> ClapCommand {
171 ClapCommand::new("nns")
172 .bin_name("icq nns")
173 .about("Inspect NNS metadata")
174 .disable_help_flag(true)
175 .subcommand(passthrough_subcommand(
176 ClapCommand::new("subnet").about("Inspect and refresh NNS subnet metadata"),
177 ))
178 .subcommand(passthrough_subcommand(
179 ClapCommand::new("data-center").about("Inspect NNS data-center metadata"),
180 ))
181 .subcommand(passthrough_subcommand(
182 ClapCommand::new("node").about("Inspect NNS node metadata"),
183 ))
184 .subcommand(passthrough_subcommand(
185 ClapCommand::new("node-provider").about("Inspect NNS node-provider metadata"),
186 ))
187 .subcommand(passthrough_subcommand(
188 ClapCommand::new("node-operator").about("Inspect NNS node-operator metadata"),
189 ))
190 .subcommand(passthrough_subcommand(
191 ClapCommand::new("proposal").about("Inspect NNS governance proposals"),
192 ))
193 .subcommand(passthrough_subcommand(
194 ClapCommand::new("registry").about("Inspect NNS registry metadata"),
195 ))
196 .subcommand(passthrough_subcommand(
197 ClapCommand::new("topology").about("Summarize joined NNS topology metadata"),
198 ))
199}
200
201#[cfg(feature = "cli")]
202fn usage() -> String {
203 render_help(nns_command())
204}