feat(cli): introduce --version flags and a dedicated --continuous option with new short aliases
This commit is contained in:
5 files changed
+47
-14
No files matched your search
@@ -55,6 +55,10 @@ pub fn dispatch_from_argv(argv: Vec<OsString>) -> Result<AppletDispatch, String>
|
|||||||
};
|
};
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
|
"-V" | "--version" => Ok(AppletDispatch::Help(format!(
|
||||||
|
"irtt-rs {}",
|
||||||
|
env!("CARGO_PKG_VERSION")
|
||||||
|
))),
|
||||||
"-h" | "--help" => Ok(AppletDispatch::Help(dispatcher_help())),
|
"-h" | "--help" => Ok(AppletDispatch::Help(dispatcher_help())),
|
||||||
"client" => Ok(AppletDispatch::Run {
|
"client" => Ok(AppletDispatch::Run {
|
||||||
applet: RequestedApplet::Client,
|
applet: RequestedApplet::Client,
|
||||||
@@ -78,6 +82,7 @@ pub fn dispatch_from_argv(argv: Vec<OsString>) -> Result<AppletDispatch, String>
|
|||||||
|
|
||||||
pub fn dispatcher_help() -> String {
|
pub fn dispatcher_help() -> String {
|
||||||
let mut command = Command::new("irtt-rs")
|
let mut command = Command::new("irtt-rs")
|
||||||
|
.version(env!("CARGO_PKG_VERSION"))
|
||||||
.about("IRTT-compatible multi-applet dispatcher")
|
.about("IRTT-compatible multi-applet dispatcher")
|
||||||
.subcommand(Command::new("client").about(client_applet_about()))
|
.subcommand(Command::new("client").about(client_applet_about()))
|
||||||
.subcommand(Command::new("tui").about(tui_applet_about()))
|
.subcommand(Command::new("tui").about(tui_applet_about()))
|
||||||
|
|||||||
@@ -9,7 +9,11 @@ use clap::{Parser, ValueEnum};
|
|||||||
pub const DEFAULT_CLIENT_DURATION: Duration = Duration::from_secs(10);
|
pub const DEFAULT_CLIENT_DURATION: Duration = Duration::from_secs(10);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Parser)]
|
#[derive(Debug, Clone, Parser)]
|
||||||
#[command(name = "irtt-client", about = "Minimal IRTT-compatible stream client")]
|
#[command(
|
||||||
|
name = "irtt-client",
|
||||||
|
version,
|
||||||
|
about = "Minimal IRTT-compatible stream client"
|
||||||
|
)]
|
||||||
pub struct ClientArgs {
|
pub struct ClientArgs {
|
||||||
/// Server address/host, optionally prefixed with LABEL= and suffixed with @hmac=KEY. Repeat for multi-target mode.
|
/// Server address/host, optionally prefixed with LABEL= and suffixed with @hmac=KEY. Repeat for multi-target mode.
|
||||||
#[arg(
|
#[arg(
|
||||||
@@ -38,13 +42,18 @@ pub struct ClientArgs {
|
|||||||
|
|
||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
|
short = 'd',
|
||||||
default_value = "10s",
|
default_value = "10s",
|
||||||
value_parser = parse_test_duration,
|
value_parser = parse_test_duration,
|
||||||
help = "Test duration (e.g. 2.5s, 1m30s, 1h); use 0 for continuous mode",
|
help = "Test duration (e.g. 2.5s, 1m30s, 1h); use --continuous for continuous mode (0 is also accepted)",
|
||||||
long_help = "Test duration (e.g. 2.5s, 1m30s, 500us, 100ns, 1h); use 0 for continuous mode.\n\nFinite runs retain exact statistics for final summaries. Continuous mode uses bounded-memory running statistics and prints a final summary when interrupted; --targets-stdin also prints the final retained summary on EOF."
|
long_help = "Test duration (e.g. 2.5s, 1m30s, 500us, 100ns, 1h); use --continuous for continuous mode (0 is also accepted).\n\nFinite runs retain exact statistics for final summaries. Continuous mode uses bounded-memory running statistics and prints a final summary when interrupted; --targets-stdin also prints the final retained summary on EOF."
|
||||||
)]
|
)]
|
||||||
pub duration: Duration,
|
pub duration: Duration,
|
||||||
|
|
||||||
|
/// Run continuously until interrupted (equivalent to --duration 0).
|
||||||
|
#[arg(long, conflicts_with = "duration")]
|
||||||
|
pub continuous: bool,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub common: CommonClientArgs,
|
pub common: CommonClientArgs,
|
||||||
|
|
||||||
@@ -52,6 +61,7 @@ pub struct ClientArgs {
|
|||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
value_enum,
|
value_enum,
|
||||||
|
short = 'f',
|
||||||
default_value_t = OutputFormat::Table,
|
default_value_t = OutputFormat::Table,
|
||||||
long_help = "Event row output format.\n\nTable is the default interactive format. CSV, TSV, and JSON Lines default to all columns for structured export."
|
long_help = "Event row output format.\n\nTable is the default interactive format. CSV, TSV, and JSON Lines default to all columns for structured export."
|
||||||
)]
|
)]
|
||||||
@@ -83,7 +93,7 @@ pub struct ClientArgs {
|
|||||||
pub header: HeaderMode,
|
pub header: HeaderMode,
|
||||||
|
|
||||||
/// Include extra fields in table output and final summaries.
|
/// Include extra fields in table output and final summaries.
|
||||||
#[arg(long)]
|
#[arg(short = 'v', long)]
|
||||||
pub verbose: bool,
|
pub verbose: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,11 +104,15 @@ impl ClientArgs {
|
|||||||
/// called, so listing columns still needs no target.
|
/// called, so listing columns still needs no target.
|
||||||
pub async fn prepare(&self) -> Result<ManagedRunSetup, String> {
|
pub async fn prepare(&self) -> Result<ManagedRunSetup, String> {
|
||||||
if self.targets_stdin && !self.is_continuous() {
|
if self.targets_stdin && !self.is_continuous() {
|
||||||
return Err("--targets-stdin requires --duration 0".to_owned());
|
return Err("--targets-stdin requires --continuous or --duration 0".to_owned());
|
||||||
}
|
}
|
||||||
prepare_managed_run(
|
prepare_managed_run(
|
||||||
&self.common,
|
&self.common,
|
||||||
self.duration,
|
if self.continuous {
|
||||||
|
Duration::ZERO
|
||||||
|
} else {
|
||||||
|
self.duration
|
||||||
|
},
|
||||||
TargetSelection {
|
TargetSelection {
|
||||||
targets: &self.targets,
|
targets: &self.targets,
|
||||||
pacing: self.pacing,
|
pacing: self.pacing,
|
||||||
@@ -109,7 +123,7 @@ impl ClientArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_continuous(&self) -> bool {
|
pub fn is_continuous(&self) -> bool {
|
||||||
self.duration == Duration::ZERO
|
self.continuous || self.duration == Duration::ZERO
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn timestamp_mode(&self) -> TimestampArg {
|
pub fn timestamp_mode(&self) -> TimestampArg {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const DEFAULT_PORT: u16 = 2112;
|
|||||||
#[derive(Clone, Parser)]
|
#[derive(Clone, Parser)]
|
||||||
#[command(
|
#[command(
|
||||||
name = "irtt-server",
|
name = "irtt-server",
|
||||||
|
version,
|
||||||
about = "Minimal IRTT-compatible UDP server",
|
about = "Minimal IRTT-compatible UDP server",
|
||||||
after_help = "With no --bind, the server listens on the wildcard IRTT port for both address families ([::]:2112 and 0.0.0.0:2112) where the platform supports wildcard reply-source selection.\nRepeat --bind to serve multiple addresses in one process; any explicit --bind replaces the default pair entirely. All listeners use the same policy but keep independent session namespaces."
|
after_help = "With no --bind, the server listens on the wildcard IRTT port for both address families ([::]:2112 and 0.0.0.0:2112) where the platform supports wildcard reply-source selection.\nRepeat --bind to serve multiple addresses in one process; any explicit --bind replaces the default pair entirely. All listeners use the same policy but keep independent session namespaces."
|
||||||
)]
|
)]
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ use crate::shared::client::{
|
|||||||
pub const DEFAULT_TUI_DURATION: Duration = Duration::ZERO;
|
pub const DEFAULT_TUI_DURATION: Duration = Duration::ZERO;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Parser)]
|
#[derive(Debug, Clone, Parser)]
|
||||||
#[command(name = "irtt-tui", about = "Minimal IRTT-compatible TUI client")]
|
#[command(
|
||||||
|
name = "irtt-tui",
|
||||||
|
version,
|
||||||
|
about = "Minimal IRTT-compatible TUI client"
|
||||||
|
)]
|
||||||
pub struct TuiArgs {
|
pub struct TuiArgs {
|
||||||
/// Server address/host, optionally prefixed with LABEL= and suffixed with @hmac=KEY. Repeat for multi-target mode.
|
/// Server address/host, optionally prefixed with LABEL= and suffixed with @hmac=KEY. Repeat for multi-target mode.
|
||||||
#[arg(
|
#[arg(
|
||||||
@@ -33,13 +37,18 @@ pub struct TuiArgs {
|
|||||||
|
|
||||||
#[arg(
|
#[arg(
|
||||||
long,
|
long,
|
||||||
|
short = 'd',
|
||||||
default_value = "0",
|
default_value = "0",
|
||||||
value_parser = parse_test_duration,
|
value_parser = parse_test_duration,
|
||||||
help = "Test duration (e.g. 2.5s, 1m30s, 1h); use 0 for continuous mode",
|
help = "Test duration (e.g. 2.5s, 1m30s, 1h); use --continuous for continuous mode (0 is also accepted)",
|
||||||
long_help = "Test duration (e.g. 2.5s, 1m30s, 500us, 100ns, 1h); use 0 for continuous mode. The TUI defaults to continuous mode."
|
long_help = "Test duration (e.g. 2.5s, 1m30s, 500us, 100ns, 1h); use --continuous for continuous mode (0 is also accepted). The TUI defaults to continuous mode."
|
||||||
)]
|
)]
|
||||||
pub duration: Duration,
|
pub duration: Duration,
|
||||||
|
|
||||||
|
/// Run continuously until interrupted (equivalent to --duration 0).
|
||||||
|
#[arg(long, conflicts_with = "duration")]
|
||||||
|
pub continuous: bool,
|
||||||
|
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub common: CommonClientArgs,
|
pub common: CommonClientArgs,
|
||||||
}
|
}
|
||||||
@@ -52,7 +61,11 @@ impl TuiArgs {
|
|||||||
pub async fn prepare(&self) -> Result<ManagedRunSetup, String> {
|
pub async fn prepare(&self) -> Result<ManagedRunSetup, String> {
|
||||||
prepare_managed_run(
|
prepare_managed_run(
|
||||||
&self.common,
|
&self.common,
|
||||||
self.duration,
|
if self.continuous {
|
||||||
|
Duration::ZERO
|
||||||
|
} else {
|
||||||
|
self.duration
|
||||||
|
},
|
||||||
TargetSelection {
|
TargetSelection {
|
||||||
targets: &self.targets,
|
targets: &self.targets,
|
||||||
pacing: self.pacing,
|
pacing: self.pacing,
|
||||||
@@ -63,7 +76,7 @@ impl TuiArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_continuous(&self) -> bool {
|
pub fn is_continuous(&self) -> bool {
|
||||||
self.duration == Duration::ZERO
|
self.continuous || self.duration == Duration::ZERO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ pub struct CommonClientArgs {
|
|||||||
pub dual_stack: bool,
|
pub dual_stack: bool,
|
||||||
|
|
||||||
/// Positive probe interval (e.g. 2.5s, 1m30s, 500us, 100ns, 1h).
|
/// Positive probe interval (e.g. 2.5s, 1m30s, 500us, 100ns, 1h).
|
||||||
#[arg(long, default_value = "1s", value_parser = parse_duration)]
|
#[arg(short = 'i', long, default_value = "1s", value_parser = parse_duration)]
|
||||||
pub interval: Duration,
|
pub interval: Duration,
|
||||||
|
|
||||||
/// UDP payload length.
|
/// UDP payload length.
|
||||||
#[arg(long, default_value_t = 0, value_parser = parse_length)]
|
#[arg(short = 'l', long, default_value_t = 0, value_parser = parse_length)]
|
||||||
pub length: u32,
|
pub length: u32,
|
||||||
|
|
||||||
// Decode during configuration preparation so Clap cannot echo rejected keys.
|
// Decode during configuration preparation so Clap cannot echo rejected keys.
|
||||||
|
|||||||
Reference in new issue
Block a user