Skip to content

Commit

Permalink
[eclipse-iceoryx#98] Implement iox2 nodes details
Browse files Browse the repository at this point in the history
  • Loading branch information
orecham committed Sep 19, 2024
1 parent 7489fe4 commit d248edf
Show file tree
Hide file tree
Showing 8 changed files with 324 additions and 58 deletions.
1 change: 1 addition & 0 deletions iceoryx2-cli/iox2-nodes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ version = { workspace = true }
iceoryx2 = { workspace = true }
iceoryx2-bb-log = { workspace = true }
iceoryx2-cli-utils = { workspace = true }
iceoryx2-pal-posix = {workspace = true}

anyhow = { workspace = true }
better-panic = { workspace = true }
Expand Down
79 changes: 71 additions & 8 deletions iceoryx2-cli/iox2-nodes/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

use std::str::FromStr;

use clap::Args;
use clap::Parser;
use clap::Subcommand;
use clap::ValueEnum;

use iceoryx2_cli_utils::help_template;
use iceoryx2_cli_utils::Format;
use iceoryx2_pal_posix::posix::pid_t;

#[derive(Parser)]
#[command(
Expand All @@ -30,20 +35,78 @@ pub struct Cli {
#[clap(subcommand)]
pub action: Option<Action>,

#[clap(long, short = 'f', value_enum, global = true)]
pub format: Option<Format>,
#[clap(long, short = 'f', value_enum, global = true, value_enum, default_value_t = Format::Ron)]
pub format: Format,
}

#[derive(Parser)]
#[derive(Clone, Debug)]
pub enum NodeIdentifier {
Name(String),
Id(String),
Pid(pid_t),
}

fn is_valid_hex(s: &str) -> bool {
s.len() == 32 && s.chars().all(|c| c.is_ascii_hexdigit())
}

impl FromStr for NodeIdentifier {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(pid) = s.parse::<pid_t>() {
Ok(NodeIdentifier::Pid(pid))
} else if is_valid_hex(s) {
Ok(NodeIdentifier::Id(s.to_string()))
} else {
Ok(NodeIdentifier::Name(s.to_string()))
}
}
}

#[derive(Debug, Clone, ValueEnum)]
#[clap(rename_all = "PascalCase")]
#[derive(Default)]
pub enum StateFilter {
Alive,
Dead,
Inaccessible,
Undefined,
#[default]
All,
}

#[derive(Debug, Clone, Args)]
pub struct ListFilter {
#[clap(short, long, value_enum, default_value_t = StateFilter::All)]
pub state: StateFilter,
}

#[derive(Args)]
pub struct ListOptions {
#[command(flatten)]
pub filter: ListFilter,
}

#[derive(Debug, Clone, Args)]
pub struct DetailsFilter {
#[clap(short, long, value_enum, default_value_t = StateFilter::All)]
pub state: StateFilter,
}

#[derive(Args)]
pub struct DetailsOptions {
#[clap(help = "")]
pub node: String,
#[clap(help = "Name, ID or PID")]
pub node: NodeIdentifier,

#[command(flatten)]
pub filter: DetailsFilter,
}

#[derive(Subcommand)]
pub enum Action {
#[clap(about = "")]
List,
#[clap(about = "")]
#[clap(about = "List all existing nodes")]
List(ListOptions),
#[clap(about = "Show details of an existing node")]
Details(DetailsOptions),
}
37 changes: 33 additions & 4 deletions iceoryx2-cli/iox2-nodes/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,24 @@
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

use anyhow::{Context, Result};
use anyhow::{Context, Error, Result};
use iceoryx2::prelude::*;
use iceoryx2_cli_utils::output::NodeDescription;
use iceoryx2_cli_utils::output::NodeDescriptor;
use iceoryx2_cli_utils::output::NodeList;
use iceoryx2_cli_utils::Filter;
use iceoryx2_cli_utils::Format;

pub fn list(format: Format) -> Result<()> {
use crate::cli::DetailsFilter;
use crate::cli::ListFilter;
use crate::cli::NodeIdentifier;

pub fn list(filter: ListFilter, format: Format) -> Result<()> {
let mut nodes = Vec::<NodeDescriptor>::new();
Node::<ipc::Service>::list(Config::global_config(), |node_state| {
nodes.push(NodeDescriptor::from(&node_state));
Node::<ipc::Service>::list(Config::global_config(), |node| {
if filter.matches(&node) {
nodes.push(NodeDescriptor::from(&node));
}
CallbackProgression::Continue
})
.context("failed to retrieve nodes")?;
Expand All @@ -34,3 +42,24 @@ pub fn list(format: Format) -> Result<()> {

Ok(())
}

pub fn details(identifier: NodeIdentifier, filter: DetailsFilter, format: Format) -> Result<()> {
let mut error: Option<Error> = None;

Node::<ipc::Service>::list(Config::global_config(), |node| {
if identifier.matches(&node) && filter.matches(&node) {
match format.as_string(&NodeDescription::from(&node)) {
Ok(output) => {
print!("{}", output);
}
Err(e) => {
error = Some(e);
}
}
}
CallbackProgression::Continue
})
.context("failed to retrieve nodes")?;

Ok(())
}
78 changes: 78 additions & 0 deletions iceoryx2-cli/iox2-nodes/src/filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) 2024 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available under the
// terms of the Apache Software License 2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
// which is available at https://opensource.org/licenses/MIT.
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

use crate::cli::DetailsFilter;
use crate::cli::ListFilter;
use crate::cli::NodeIdentifier;
use crate::cli::StateFilter;
use iceoryx2::node::NodeState;
use iceoryx2::node::NodeView;
use iceoryx2::service::ipc::Service;
use iceoryx2_cli_utils::output::NodeIdString;
use iceoryx2_cli_utils::Filter;

impl Filter<NodeState<Service>> for NodeIdentifier {
fn matches(&self, node: &NodeState<Service>) -> bool {
match self {
NodeIdentifier::Name(ref name) => match node {
NodeState::Alive(view) => view
.details()
.as_ref()
.map(|details| details.name().as_str() == name)
.unwrap_or(false),
NodeState::Dead(view) => view
.details()
.as_ref()
.map(|details| details.name().as_str() == name)
.unwrap_or(false),
NodeState::Inaccessible(_) | NodeState::Undefined(_) => false,
},
NodeIdentifier::Id(ref id) => match node {
NodeState::Alive(view) => NodeIdString::from(view.id()) == **id,
NodeState::Dead(view) => NodeIdString::from(view.id()) == **id,
NodeState::Inaccessible(node_id) => NodeIdString::from(node_id) == **id,
NodeState::Undefined(node_id) => NodeIdString::from(node_id) == **id,
},
NodeIdentifier::Pid(pid) => match node {
NodeState::Alive(view) => view.id().pid().value() == *pid,
NodeState::Dead(view) => view.id().pid().value() == *pid,
NodeState::Inaccessible(node_id) => node_id.pid().value() == *pid,
NodeState::Undefined(node_id) => node_id.pid().value() == *pid,
},
}
}
}

impl Filter<NodeState<Service>> for StateFilter {
fn matches(&self, node: &NodeState<Service>) -> bool {
matches!(
(self, node),
(StateFilter::Alive, NodeState::Alive(_))
| (StateFilter::Dead, NodeState::Dead(_))
| (StateFilter::Inaccessible, NodeState::Inaccessible(_))
| (StateFilter::Undefined, NodeState::Undefined(_))
| (StateFilter::All, _)
)
}
}

impl Filter<NodeState<Service>> for ListFilter {
fn matches(&self, node: &NodeState<Service>) -> bool {
self.state.matches(node)
}
}

impl Filter<NodeState<Service>> for DetailsFilter {
fn matches(&self, node: &NodeState<Service>) -> bool {
self.state.matches(node)
}
}
13 changes: 9 additions & 4 deletions iceoryx2-cli/iox2-nodes/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@

mod cli;
mod commands;
mod filter;

use clap::CommandFactory;
use clap::Parser;
use cli::Cli;
use iceoryx2_bb_log::{set_log_level, LogLevel};
use iceoryx2_cli_utils::Format;

#[cfg(not(debug_assertions))]
use human_panic::setup_panic;
Expand All @@ -44,12 +44,17 @@ fn main() {
Ok(cli) => {
if let Some(action) = cli.action {
match action {
cli::Action::List => {
if let Err(e) = commands::list(cli.format.unwrap_or(Format::Ron)) {
cli::Action::List(options) => {
if let Err(e) = commands::list(options.filter, cli.format) {
eprintln!("Failed to list nodes: {}", e);
}
}
cli::Action::Details(_) => todo!(),
cli::Action::Details(options) => {
if let Err(e) = commands::details(options.node, options.filter, cli.format)
{
eprintln!("Failed to retrieve node details: {}", e);
}
}
}
} else {
Cli::command().print_help().expect("Failed to print help");
Expand Down
3 changes: 2 additions & 1 deletion iceoryx2-cli/iox2-services/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
//
// SPDX-License-Identifier: Apache-2.0 OR MIT

use crate::cli::DetailsFilter;
use anyhow::{Context, Error, Result};
use iceoryx2::prelude::*;
use iceoryx2_cli_utils::output::ServiceDescription;
Expand All @@ -19,6 +18,8 @@ use iceoryx2_cli_utils::output::ServiceList;
use iceoryx2_cli_utils::Filter;
use iceoryx2_cli_utils::Format;

use crate::cli::DetailsFilter;

pub fn list(format: Format) -> Result<()> {
let mut services = ServiceList::new();

Expand Down
1 change: 1 addition & 0 deletions iceoryx2-cli/utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ version = { workspace = true }

[dependencies]
iceoryx2 = { workspace = true }
iceoryx2-pal-posix = {workspace = true}

anyhow = { workspace = true }
clap = { workspace = true }
Expand Down
Loading

0 comments on commit d248edf

Please sign in to comment.