diff --git a/zkstack_cli/crates/zkstack/src/commands/dev/commands/status.rs b/zkstack_cli/crates/zkstack/src/commands/dev/commands/status.rs index 5e158cd1d85c..bad40addcf21 100644 --- a/zkstack_cli/crates/zkstack/src/commands/dev/commands/status.rs +++ b/zkstack_cli/crates/zkstack/src/commands/dev/commands/status.rs @@ -9,8 +9,11 @@ use serde_json::Value; use xshell::Shell; use crate::{ - commands::dev::messages::{MSG_API_CONFIG_NOT_FOUND_ERR, MSG_STATUS_URL_HELP}, + commands::dev::messages::{ + MSG_API_CONFIG_NOT_FOUND_ERR, MSG_STATUS_PORTS_HELP, MSG_STATUS_URL_HELP, + }, messages::MSG_CHAIN_NOT_FOUND_ERR, + utils::ports::EcosystemPortsScanner, }; const DEFAULT_LINE_WIDTH: usize = 32; @@ -31,6 +34,8 @@ struct Component { pub struct StatusArgs { #[clap(long, short = 'u', help = MSG_STATUS_URL_HELP)] pub url: Option, + #[clap(long, short = 'p', help = MSG_STATUS_PORTS_HELP)] + pub ports: bool, } struct BoxProperties { @@ -166,6 +171,41 @@ fn print_status(health_check_url: String) -> anyhow::Result<()> { Ok(()) } +fn print_ports(shell: &Shell) -> anyhow::Result<()> { + let ports = EcosystemPortsScanner::scan(shell)?; + let grouped_ports = ports.group_by_file_path(); + + let mut all_port_lines: Vec = Vec::new(); + + for (file_path, port_infos) in grouped_ports { + let mut port_info_lines = String::new(); + + for port_info in port_infos { + port_info_lines.push_str(&format!( + " - {} > {}\n", + port_info.port, port_info.description + )); + } + + all_port_lines.push(format!("{}\n{}", file_path, port_info_lines)); + } + + all_port_lines.sort_by(|a, b| { + b.lines() + .count() + .cmp(&a.lines().count()) + .then_with(|| a.cmp(b)) + }); + + let mut components_info = String::from("Used ports:\n"); + for chunk in all_port_lines.chunks(2) { + components_info.push_str(&bordered_boxes(&chunk[0], chunk.get(1))); + } + + logger::info(components_info); + Ok(()) +} + fn deslugify(name: &str) -> String { name.split('_') .map(|word| { @@ -188,6 +228,10 @@ fn deslugify(name: &str) -> String { } pub async fn run(shell: &Shell, args: StatusArgs) -> anyhow::Result<()> { + if args.ports { + return print_ports(shell); + } + let health_check_url = if let Some(url) = args.url { url } else { diff --git a/zkstack_cli/crates/zkstack/src/commands/dev/messages.rs b/zkstack_cli/crates/zkstack/src/commands/dev/messages.rs index 1321cd975269..a75ae5f60789 100644 --- a/zkstack_cli/crates/zkstack/src/commands/dev/messages.rs +++ b/zkstack_cli/crates/zkstack/src/commands/dev/messages.rs @@ -235,3 +235,4 @@ pub(super) const MSG_INVALID_L1_RPC_URL_ERR: &str = "Invalid L1 RPC URL"; pub(super) const MSG_STATUS_ABOUT: &str = "Get status of the server"; pub(super) const MSG_API_CONFIG_NOT_FOUND_ERR: &str = "API config not found"; pub(super) const MSG_STATUS_URL_HELP: &str = "URL of the health check endpoint"; +pub(super) const MSG_STATUS_PORTS_HELP: &str = "Show used ports"; diff --git a/zkstack_cli/crates/zkstack/src/utils/ports.rs b/zkstack_cli/crates/zkstack/src/utils/ports.rs index 34605f5cd29f..6c299b999136 100644 --- a/zkstack_cli/crates/zkstack/src/utils/ports.rs +++ b/zkstack_cli/crates/zkstack/src/utils/ports.rs @@ -15,7 +15,7 @@ pub struct EcosystemPorts { pub ports: HashMap>, } -#[derive(Debug, Default, PartialEq, Eq)] +#[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct PortInfo { pub port: u16, pub file_path: String, @@ -159,6 +159,19 @@ impl EcosystemPorts { Ok(()) } + + pub fn group_by_file_path(&self) -> HashMap> { + let mut grouped_ports: HashMap> = HashMap::new(); + for port_infos in self.ports.values() { + for port_info in port_infos { + grouped_ports + .entry(port_info.file_path.clone()) + .or_default() + .push(port_info.clone()); + } + } + grouped_ports + } } impl fmt::Display for EcosystemPorts {