diff --git a/Cargo.lock b/Cargo.lock index 01378d301..be46441b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -164,9 +164,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.5.0" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" dependencies = [ "anstyle", "anstyle-parse", @@ -197,17 +197,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] name = "anstyle-wincon" -version = "2.1.0" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -355,7 +355,7 @@ dependencies = [ "futures-lite", "rustix 0.37.25", "signal-hook", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -454,17 +454,6 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1181e1e0d1fce796a03db1ae795d67167da795f9cf4a39c37589e85ef57f26d3" -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -669,7 +658,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -720,24 +709,9 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_lex 0.2.4", - "indexmap 1.9.3", - "strsim", - "termcolor", - "textwrap", -] - -[[package]] -name = "clap" -version = "4.4.3" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84ed82781cea27b43c9b106a979fe450a13a31aab0500595fb3fc06616de08e6" +checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" dependencies = [ "clap_builder", "clap_derive", @@ -745,21 +719,21 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.2" +version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" +checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" dependencies = [ "anstream", "anstyle", - "clap_lex 0.5.1", + "clap_lex", "strsim", ] [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", @@ -769,18 +743,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "clap_lex" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "cobs" @@ -919,7 +884,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.4.3", + "clap", "criterion-plot", "is-terminal", "itertools", @@ -1114,7 +1079,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1191,7 +1156,7 @@ checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd" dependencies = [ "errno-dragonfly", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1548,15 +1513,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.2" @@ -1614,7 +1570,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1798,9 +1754,9 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1824,9 +1780,9 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi", "rustix 0.38.13", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1883,7 +1839,7 @@ dependencies = [ "anyhow", "base64 0.21.4", "bytecount", - "clap 4.4.3", + "clap", "fancy-regex", "fraction", "getrandom 0.2.10", @@ -1952,7 +1908,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb" dependencies = [ "cfg-if 1.0.0", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2083,7 +2039,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2267,7 +2223,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.2", + "hermit-abi", "libc", ] @@ -2319,12 +2275,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "os_str_bytes" -version = "6.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac" - [[package]] name = "panic-message" version = "0.3.0" @@ -2357,7 +2307,7 @@ dependencies = [ "libc", "redox_syscall 0.3.5", "smallvec", - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -2637,7 +2587,7 @@ dependencies = [ "libc", "log", "pin-project-lite 0.2.13", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2717,7 +2667,7 @@ dependencies = [ "libc", "socket2 0.5.4", "tracing", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -3020,7 +2970,7 @@ dependencies = [ "io-lifetimes", "libc", "linux-raw-sys 0.3.8", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -3033,7 +2983,7 @@ dependencies = [ "errno 0.3.3", "libc", "linux-raw-sys 0.4.7", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -3100,7 +3050,7 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -3453,7 +3403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -3668,12 +3618,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - [[package]] name = "thiserror" version = "1.0.48" @@ -3830,7 +3774,7 @@ dependencies = [ "pin-project-lite 0.2.13", "socket2 0.5.4", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -4344,7 +4288,7 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", ] [[package]] @@ -4353,7 +4297,16 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", ] [[package]] @@ -4362,21 +4315,42 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm", + "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm", + "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.34.0" @@ -4389,6 +4363,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.34.0" @@ -4401,6 +4381,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.34.0" @@ -4413,6 +4399,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.34.0" @@ -4425,12 +4417,24 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.34.0" @@ -4443,6 +4447,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winreg" version = "0.50.0" @@ -4450,7 +4460,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if 1.0.0", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -4595,7 +4605,7 @@ name = "zenoh-examples" version = "0.11.0-dev" dependencies = [ "async-std", - "clap 3.2.25", + "clap", "env_logger", "flume", "futures", @@ -4614,7 +4624,7 @@ version = "0.11.0-dev" dependencies = [ "async-std", "bincode", - "clap 3.2.25", + "clap", "env_logger", "flume", "futures", @@ -4857,7 +4867,7 @@ name = "zenoh-plugin-example" version = "0.11.0-dev" dependencies = [ "async-std", - "clap 3.2.25", + "clap", "env_logger", "futures", "log", @@ -4876,7 +4886,7 @@ dependencies = [ "anyhow", "async-std", "base64 0.21.4", - "clap 3.2.25", + "clap", "env_logger", "flume", "futures", @@ -4903,7 +4913,7 @@ dependencies = [ "async-global-executor", "async-std", "async-trait", - "clap 3.2.25", + "clap", "crc", "derive-new", "env_logger", @@ -5029,7 +5039,7 @@ version = "0.11.0-dev" dependencies = [ "async-std", "async-trait", - "clap 3.2.25", + "clap", "const_format", "flume", "futures", @@ -5068,7 +5078,7 @@ name = "zenohd" version = "0.11.0-dev" dependencies = [ "async-std", - "clap 3.2.25", + "clap", "env_logger", "futures", "git-version", diff --git a/Cargo.toml b/Cargo.toml index 55797ab0d..4cba5d4dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,7 +79,7 @@ async-std = { version = "=1.12.0", default-features = false } # Default features async-trait = "0.1.60" base64 = "0.21.4" bincode = "1.3.3" -clap = "3.2.23" +clap = { version = "4.4.11", features = ["derive"] } const_format = "0.2.30" crc = "3.0.1" criterion = "0.5" @@ -128,7 +128,7 @@ rustls = { version = "0.21.5", features = ["dangerous_configuration"] } rustls-native-certs = "0.6.2" rustls-pemfile = "1.0.2" schemars = "0.8.12" -secrecy = {version = "0.8.0", features = ["serde", "alloc"]} +secrecy = { version = "0.8.0", features = ["serde", "alloc"] } serde = { version = "1.0.154", default-features = false, features = [ "derive", ] } # Default features are disabled due to usage in no_std crates @@ -137,7 +137,7 @@ serde_yaml = "0.9.19" sha3 = "0.10.6" shared_memory = "0.12.4" shellexpand = "3.0.0" -socket2 = { version ="0.5.1", features = [ "all" ] } +socket2 = { version = "0.5.1", features = ["all"] } stop-token = "0.7.0" syn = "2.0" tide = "0.16.0" diff --git a/examples/Cargo.toml b/examples/Cargo.toml index b0f6507d2..0330972ca 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -42,7 +42,7 @@ transport_unixpipe = ["zenoh/transport_unixpipe"] [dependencies] async-std = { workspace = true, features = ["attributes"] } -clap = { workspace = true } +clap = { workspace = true, features = ["derive"] } env_logger = { workspace = true } flume = { workspace = true } futures = { workspace = true } diff --git a/examples/examples/z_delete.rs b/examples/examples/z_delete.rs index 183fcfbaf..f80e199d6 100644 --- a/examples/examples/z_delete.rs +++ b/examples/examples/z_delete.rs @@ -11,9 +11,10 @@ // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; +use clap::Parser; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -31,51 +32,16 @@ async fn main() { session.close().res().await.unwrap(); } -fn parse_args() -> (Config, String) { - let args = App::new("zenoh delete example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg( - Arg::from_usage( - "-k, --key=[KEYEXPR] 'The key expression matching resources to delete.'", - ) - .default_value("demo/example/zenoh-rs-put"), - ) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - - let key_expr = args.value_of("key").unwrap().to_string(); +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[arg(short, long, default_value = "demo/example/zenoh-rs-put")] + /// The key expression to write to. + key: KeyExpr<'static>, + #[command(flatten)] + common: CommonArgs, +} - (config, key_expr) +fn parse_args() -> (Config, KeyExpr<'static>) { + let args = Args::parse(); + (args.common.into(), args.key) } diff --git a/examples/examples/z_forward.rs b/examples/examples/z_forward.rs index c5280f3c5..5dd786843 100644 --- a/examples/examples/z_forward.rs +++ b/examples/examples/z_forward.rs @@ -11,9 +11,10 @@ // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; +use clap::Parser; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; use zenoh_ext::SubscriberForward; #[async_std::main] @@ -34,55 +35,19 @@ async fn main() { subscriber.forward(publisher).await.unwrap(); } -fn parse_args() -> (Config, String, String) { - let args = App::new("zenoh sub example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage("-k, --key=[KEYEXPR] 'The key expression to subscribe to.'") - .default_value("demo/example/**"), - ) - .arg( - Arg::from_usage("-f, --forward=[KEYEXPR] 'The key expression to forward to.'") - .default_value("demo/forward"), - ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - - let key_expr = args.value_of("key").unwrap().to_string(); - - let forward = args.value_of("forward").unwrap().to_string(); +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[arg(short, long, default_value = "demo/example/**")] + /// The key expression to subscribe to. + key: KeyExpr<'static>, + #[arg(short, long, default_value = "demo/forward")] + /// The key expression to forward to. + forward: KeyExpr<'static>, + #[command(flatten)] + common: CommonArgs, +} - (config, key_expr, forward) +fn parse_args() -> (Config, KeyExpr<'static>, KeyExpr<'static>) { + let args = Args::parse(); + (args.common.into(), args.key, args.forward) } diff --git a/examples/examples/z_get.rs b/examples/examples/z_get.rs index 70bec5adb..57c36c2e6 100644 --- a/examples/examples/z_get.rs +++ b/examples/examples/z_get.rs @@ -11,11 +11,12 @@ // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; +use clap::Parser; use std::convert::TryFrom; use std::time::Duration; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -49,72 +50,49 @@ async fn main() { } } -fn parse_args() -> (Config, String, Option, QueryTarget, Duration) { - let args = App::new("zenoh query example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage("-s, --selector=[SELECTOR] 'The selection of resources to query'") - .default_value("demo/example/**"), - ) - .arg(Arg::from_usage( - "-v, --value=[VALUE] 'An optional value to put in the query.'", - )) - .arg( - Arg::from_usage("-t, --target=[TARGET] 'The target queryables of the query'") - .possible_values(["BEST_MATCHING", "ALL", "ALL_COMPLETE"]) - .default_value("BEST_MATCHING"), - ) - .arg( - Arg::from_usage("-o, --timeout=[TIME] 'The query timeout in milliseconds'") - .default_value("10000"), - ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - - let selector = args.value_of("selector").unwrap().to_string(); - - let value = args.value_of("value").map(ToOwned::to_owned); - - let target = match args.value_of("target") { - Some("BEST_MATCHING") => QueryTarget::BestMatching, - Some("ALL") => QueryTarget::All, - Some("ALL_COMPLETE") => QueryTarget::AllComplete, - _ => QueryTarget::default(), - }; +#[derive(clap::ValueEnum, Clone, Copy, Debug)] +#[value(rename_all = "SCREAMING_SNAKE_CASE")] +enum Qt { + BestMatching, + All, + AllComplete, +} - let timeout = Duration::from_millis(args.value_of("timeout").unwrap().parse::().unwrap()); +#[derive(Parser, Clone, Debug)] +struct Args { + #[arg(short, long, default_value = "demo/example/**")] + /// The selection of resources to query + selector: Selector<'static>, + #[arg(short, long)] + /// An optional value to put in the query. + value: Option, + #[arg(short, long, default_value = "BEST_MATCHING")] + /// The target queryables of the query. + target: Qt, + #[arg(short = 'o', long, default_value = "10000")] + /// The query timeout in milliseconds. + timeout: u64, + #[command(flatten)] + common: CommonArgs, +} - (config, selector, value, target, timeout) +fn parse_args() -> ( + Config, + Selector<'static>, + Option, + QueryTarget, + Duration, +) { + let args = Args::parse(); + ( + args.common.into(), + args.selector, + args.value, + match args.target { + Qt::BestMatching => QueryTarget::BestMatching, + Qt::All => QueryTarget::All, + Qt::AllComplete => QueryTarget::AllComplete, + }, + Duration::from_millis(args.timeout), + ) } diff --git a/examples/examples/z_get_liveliness.rs b/examples/examples/z_get_liveliness.rs index 03e3566df..e0aaf8cd2 100644 --- a/examples/examples/z_get_liveliness.rs +++ b/examples/examples/z_get_liveliness.rs @@ -11,11 +11,12 @@ // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; +use clap::Parser; use std::convert::TryFrom; use std::time::Duration; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -43,55 +44,20 @@ async fn main() { } } -fn parse_args() -> (Config, String, Duration) { - let args = App::new("zenoh liveliness query example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage("-k, --key_expr=[KEYEXPR] 'The key expression matching liveliness tokens to query.'") - .default_value("group1/**"), - ) - .arg( - Arg::from_usage("-o, --timeout=[TIME] 'The query timeout in milliseconds'") - .default_value("10000"), - ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - - let key_expr = args.value_of("key_expr").unwrap().to_string(); - - let timeout = Duration::from_millis(args.value_of("timeout").unwrap().parse::().unwrap()); +#[derive(Parser, Clone, Debug)] +struct Args { + #[arg(short, long, default_value = "group1/**")] + /// The key expression matching liveliness tokens to query. + key_expr: KeyExpr<'static>, + #[arg(short = 'o', long, default_value = "10000")] + /// The query timeout in milliseconds. + timeout: u64, + #[command(flatten)] + common: CommonArgs, +} - (config, key_expr, timeout) +fn parse_args() -> (Config, KeyExpr<'static>, Duration) { + let args = Args::parse(); + let timeout = Duration::from_millis(args.timeout); + (args.common.into(), args.key_expr, timeout) } diff --git a/examples/examples/z_info.rs b/examples/examples/z_info.rs index ccf51b211..ce752b2e7 100644 --- a/examples/examples/z_info.rs +++ b/examples/examples/z_info.rs @@ -11,9 +11,10 @@ // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; +use clap::Parser; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -37,43 +38,13 @@ async fn main() { ); } -fn parse_args() -> Config { - let args = App::new("zenoh info example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[command(flatten)] + common: CommonArgs, +} - config +fn parse_args() -> Config { + let args = Args::parse(); + args.common.into() } diff --git a/examples/examples/z_liveliness.rs b/examples/examples/z_liveliness.rs index ae691f286..41890f7d7 100644 --- a/examples/examples/z_liveliness.rs +++ b/examples/examples/z_liveliness.rs @@ -12,12 +12,12 @@ // ZettaScale Zenoh Team, // use async_std::task::sleep; -use clap::{App, Arg}; +use clap::Parser; use futures::prelude::*; -use std::convert::TryFrom; use std::time::Duration; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -58,51 +58,16 @@ async fn main() { } } -fn parse_args() -> (Config, KeyExpr<'static>) { - let args = App::new("zenoh liveliness example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage("-k, --key=[KEYEXPR] 'The key expression of the liveliness token.'") - .default_value("group1/zenoh-rs"), - ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - - let key_expr = KeyExpr::try_from(args.value_of("key").unwrap()) - .unwrap() - .into_owned(); +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[arg(short, long, default_value = "group1/zenoh-rs")] + /// The key expression of the liveliness token. + key: KeyExpr<'static>, + #[command(flatten)] + common: CommonArgs, +} - (config, key_expr) +fn parse_args() -> (Config, KeyExpr<'static>) { + let args = Args::parse(); + (args.common.into(), args.key) } diff --git a/examples/examples/z_ping.rs b/examples/examples/z_ping.rs index 173d270a8..fe5ed4d46 100644 --- a/examples/examples/z_ping.rs +++ b/examples/examples/z_ping.rs @@ -11,13 +11,12 @@ // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; -#[cfg(not(feature = "shared-memory"))] -use std::process::exit; +use clap::Parser; use std::time::{Duration, Instant}; use zenoh::config::Config; use zenoh::prelude::sync::*; use zenoh::publication::CongestionControl; +use zenoh_examples::CommonArgs; fn main() { // initiate logging @@ -77,68 +76,26 @@ fn main() { } } -fn parse_args() -> (Config, Duration, usize, usize) { - let args = App::new("zenoh roundtrip ping example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage("-n, --samples=[N] 'The number of round-trips to measure'") - .default_value("100"), - ) - .arg( - Arg::from_usage("-w, --warmup=[N] 'The number of seconds to warm up'") - .default_value("1"), - ) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .arg(Arg::from_usage("--enable-shm 'Enable SHM transport.'")) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - " 'Sets the size of the payload to publish'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - if args.is_present("enable-shm") { - #[cfg(feature = "shared-memory")] - config.transport.shared_memory.set_enabled(true).unwrap(); - #[cfg(not(feature = "shared-memory"))] - { - println!("enable-shm argument: SHM cannot be enabled, because Zenoh is compiled without shared-memory feature!"); - exit(-1); - } - } - - let n: usize = args.value_of("samples").unwrap().parse().unwrap(); - let w: f64 = args.value_of("warmup").unwrap().parse().unwrap(); - let size: usize = args.value_of("PAYLOAD_SIZE").unwrap().parse().unwrap(); +#[derive(Parser)] +struct Args { + #[arg(short, long, default_value = "1")] + /// The number of seconds to warm up (float) + warmup: f64, + #[arg(short = 'n', long, default_value = "100")] + /// The number of round-trips to measure + samples: usize, + /// Sets the size of the payload to publish + payload_size: usize, + #[command(flatten)] + common: CommonArgs, +} - (config, Duration::from_secs_f64(w), size, n) +fn parse_args() -> (Config, Duration, usize, usize) { + let args = Args::parse(); + ( + args.common.into(), + Duration::from_secs_f64(args.warmup), + args.payload_size, + args.samples, + ) } diff --git a/examples/examples/z_pong.rs b/examples/examples/z_pong.rs index d1c7bbb86..f05707543 100644 --- a/examples/examples/z_pong.rs +++ b/examples/examples/z_pong.rs @@ -13,12 +13,11 @@ use std::io::{stdin, Read}; // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; -#[cfg(not(feature = "shared-memory"))] -use std::process::exit; +use clap::Parser; use zenoh::config::Config; use zenoh::prelude::sync::*; use zenoh::publication::CongestionControl; +use zenoh_examples::CommonArgs; fn main() { // initiate logging @@ -48,53 +47,13 @@ fn main() { for _ in stdin().bytes().take_while(|b| !matches!(b, Ok(b'q'))) {} } -fn parse_args() -> Config { - let args = App::new("zenoh roundtrip pong example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .arg(Arg::from_usage("--enable-shm 'Enable SHM transport.'")) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - if args.is_present("enable-shm") { - #[cfg(feature = "shared-memory")] - config.transport.shared_memory.set_enabled(true).unwrap(); - #[cfg(not(feature = "shared-memory"))] - { - println!("enable-shm argument: SHM cannot be enabled, because Zenoh is compiled without shared-memory feature!"); - exit(-1); - } - } +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[command(flatten)] + common: CommonArgs, +} - config +fn parse_args() -> Config { + let args = Args::parse(); + args.common.into() } diff --git a/examples/examples/z_pub.rs b/examples/examples/z_pub.rs index 2632eeeda..54563df1d 100644 --- a/examples/examples/z_pub.rs +++ b/examples/examples/z_pub.rs @@ -12,10 +12,11 @@ // ZettaScale Zenoh Team, // use async_std::task::sleep; -use clap::{App, Arg}; +use clap::Parser; use std::time::Duration; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -38,54 +39,19 @@ async fn main() { } } -fn parse_args() -> (Config, String, String) { - let args = App::new("zenoh pub example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage("-k, --key=[KEYEXPR] 'The key expression to publish onto.'") - .default_value("demo/example/zenoh-rs-pub"), - ) - .arg( - Arg::from_usage("-v, --value=[VALUE] 'The value to publish.'") - .default_value("Pub from Rust!"), - ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - - let key_expr = args.value_of("key").unwrap().to_string(); - let value = args.value_of("value").unwrap().to_string(); +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[arg(short, long, default_value = "demo/example/zenoh-rs-pub")] + /// The key expression to write to. + key: KeyExpr<'static>, + #[arg(short, long, default_value = "Put from Rust")] + /// The value to write. + value: String, + #[command(flatten)] + common: CommonArgs, +} - (config, key_expr, value) +fn parse_args() -> (Config, KeyExpr<'static>, String) { + let args = Args::parse(); + (args.common.into(), args.key, args.value) } diff --git a/examples/examples/z_pub_shm.rs b/examples/examples/z_pub_shm.rs index 335fc5dbe..fc329cadf 100644 --- a/examples/examples/z_pub_shm.rs +++ b/examples/examples/z_pub_shm.rs @@ -12,11 +12,12 @@ // ZettaScale Zenoh Team, // use async_std::task::sleep; -use clap::{App, Arg}; +use clap::Parser; use std::time::Duration; use zenoh::config::Config; use zenoh::prelude::r#async::*; use zenoh::shm::SharedMemoryManager; +use zenoh_examples::CommonArgs; const N: usize = 10; const K: u32 = 3; @@ -104,54 +105,19 @@ async fn main() -> Result<(), zenoh::Error> { Ok(()) } -fn parse_args() -> (Config, String, String) { - let args = App::new("zenoh shared-memory pub example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage("-p, --path=[PATH] 'The key expression to publish onto.'") - .default_value("demo/example/zenoh-rs-pub"), - ) - .arg( - Arg::from_usage("-v, --value=[VALUE] 'The value of to publish.'") - .default_value("Pub from SharedMemory Rust!"), - ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - - let path = args.value_of("path").unwrap(); - let value = args.value_of("value").unwrap(); +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[arg(short, long, default_value = "demo/example/zenoh-rs-pub")] + /// The key expression to publish onto. + path: KeyExpr<'static>, + #[arg(short, long, default_value = "Pub from SharedMemory Rust!")] + /// The value of to publish. + value: String, + #[command(flatten)] + common: CommonArgs, +} - (config, path.to_string(), value.to_string()) +fn parse_args() -> (Config, KeyExpr<'static>, String) { + let args = Args::parse(); + (args.common.into(), args.path, args.value) } diff --git a/examples/examples/z_pub_shm_thr.rs b/examples/examples/z_pub_shm_thr.rs index f72a7b46b..9921c869e 100644 --- a/examples/examples/z_pub_shm_thr.rs +++ b/examples/examples/z_pub_shm_thr.rs @@ -11,11 +11,12 @@ // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; +use clap::Parser; use zenoh::config::Config; use zenoh::prelude::r#async::*; use zenoh::publication::CongestionControl; use zenoh::shm::SharedMemoryManager; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -46,62 +47,20 @@ async fn main() { } } -fn parse_args() -> (Config, usize, usize) { - let args = App::new("zenoh shared-memory throughput pub example") - .arg( - Arg::from_usage("-s, --shared-memory=[MB] 'shared memory size in MBytes'") - .default_value("32"), - ) - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - " 'Sets the size of the payload to publish'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - let sm_size = args - .value_of("shared-memory") - .unwrap() - .parse::() - .unwrap() - * 1024 - * 1024; +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[arg(short, long, default_value = "32")] + /// shared memory size in MBytes. + shared_memory: usize, + /// Sets the size of the payload to publish. + payload_size: usize, + #[command(flatten)] + common: CommonArgs, +} - let size = args - .value_of("PAYLOAD_SIZE") - .unwrap() - .parse::() - .unwrap(); - (config, sm_size, size) +fn parse_args() -> (Config, usize, usize) { + let args = Args::parse(); + let sm_size = args.shared_memory * 1024 * 1024; + let size = args.payload_size; + (args.common.into(), sm_size, size) } diff --git a/examples/examples/z_pub_thr.rs b/examples/examples/z_pub_thr.rs index b761128f3..433444b8d 100644 --- a/examples/examples/z_pub_thr.rs +++ b/examples/examples/z_pub_thr.rs @@ -11,13 +11,12 @@ // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; +use clap::Parser; use std::convert::TryInto; -#[cfg(not(feature = "shared-memory"))] -use std::process::exit; use zenoh::config::Config; use zenoh::prelude::sync::*; use zenoh::publication::CongestionControl; +use zenoh_examples::CommonArgs; fn main() { // initiate logging @@ -56,80 +55,36 @@ fn main() { } } -fn parse_args() -> (Config, usize, Priority, bool, usize) { - let args = App::new("zenoh throughput pub example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-p, --priority=[PRIO]... 'Priority for sending data.'", - )) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage("-t, --print 'Print the statistics.'")) - .arg( - Arg::from_usage( - "-n, --number=[number] 'Number of messages in each throughput measurements.'", - ) - .default_value("100000"), - ) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .arg(Arg::from_usage("--enable-shm 'Enable SHM transport.'")) - .arg(Arg::from_usage( - " 'Sets the size of the payload to publish'", - )) - .get_matches(); +#[derive(Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[arg(short, long)] + /// Priority for sending data + priority: Option, + #[arg(short = 't', long)] + /// Print the statistics + print: bool, + #[arg(short, long, default_value = "100000")] + /// Number of messages in each throughput measurements + number: usize, + /// Sets the size of the payload to publish + payload_size: usize, + #[command(flatten)] + common: CommonArgs, +} - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; +fn parse_args() -> (Config, usize, Priority, bool, usize) { + let args = Args::parse(); let mut prio = Priority::default(); - if let Some(p) = args.value_of("priority") { - prio = p.parse::().unwrap().try_into().unwrap(); - } - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); + if let Some(p) = args.priority { + prio = p.try_into().unwrap(); } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - if args.is_present("enable-shm") { - #[cfg(feature = "shared-memory")] - config.transport.shared_memory.set_enabled(true).unwrap(); - #[cfg(not(feature = "shared-memory"))] - { - println!("enable-shm argument: SHM cannot be enabled, because Zenoh is compiled without shared-memory feature!"); - exit(-1); - } - } - - let number: usize = args.value_of("number").unwrap().parse().unwrap(); - - let size = args - .value_of("PAYLOAD_SIZE") - .unwrap() - .parse::() - .unwrap(); - (config, size, prio, args.is_present("print"), number) + ( + args.common.into(), + args.payload_size, + prio, + args.print, + args.number, + ) } diff --git a/examples/examples/z_pull.rs b/examples/examples/z_pull.rs index cd36fc57f..812c47294 100644 --- a/examples/examples/z_pull.rs +++ b/examples/examples/z_pull.rs @@ -13,11 +13,12 @@ // use async_std::prelude::FutureExt; use async_std::task::sleep; -use clap::{App, Arg}; +use clap::Parser; use futures::prelude::*; use std::time::Duration; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -70,49 +71,16 @@ async fn main() { subs.race(keyb).await; } -fn parse_args() -> (Config, String) { - let args = App::new("zenoh pull example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage("-k, --key=[KEYEXPR] 'The key expression matching resources to pull'") - .default_value("demo/example/**"), - ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - - let key_expr = args.value_of("key").unwrap().to_string(); +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct SubArgs { + #[arg(short, long, default_value = "demo/example/**")] + /// The Key Expression to subscribe to. + key: KeyExpr<'static>, + #[command(flatten)] + common: CommonArgs, +} - (config, key_expr) +fn parse_args() -> (Config, KeyExpr<'static>) { + let args = SubArgs::parse(); + (args.common.into(), args.key) } diff --git a/examples/examples/z_put.rs b/examples/examples/z_put.rs index 2cc3d15bb..9b625be55 100644 --- a/examples/examples/z_put.rs +++ b/examples/examples/z_put.rs @@ -11,9 +11,10 @@ // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; +use clap::Parser; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -29,54 +30,19 @@ async fn main() { session.put(&key_expr, value).res().await.unwrap(); } -fn parse_args() -> (Config, String, String) { - let args = App::new("zenoh put example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage("-k, --key=[KEYEXPR] 'The key expression to write.'") - .default_value("demo/example/zenoh-rs-put"), - ) - .arg( - Arg::from_usage("-v, --value=[VALUE] 'The value to write.'") - .default_value("Put from Rust!"), - ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - - let key_expr = args.value_of("key").unwrap().to_string(); - let value = args.value_of("value").unwrap().to_string(); +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[arg(short, long, default_value = "demo/example/zenoh-rs-put")] + /// The key expression to write to. + key: KeyExpr<'static>, + #[arg(short, long, default_value = "Put from Rust")] + /// The value to write. + value: String, + #[command(flatten)] + common: CommonArgs, +} - (config, key_expr, value) +fn parse_args() -> (Config, KeyExpr<'static>, String) { + let args = Args::parse(); + (args.common.into(), args.key, args.value) } diff --git a/examples/examples/z_put_float.rs b/examples/examples/z_put_float.rs index 439bb04c3..cc667df02 100644 --- a/examples/examples/z_put_float.rs +++ b/examples/examples/z_put_float.rs @@ -11,9 +11,10 @@ // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; +use clap::Parser; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -31,59 +32,19 @@ async fn main() { session.close().res().await.unwrap(); } -// -// Argument parsing -- look at the main for the zenoh-related code -// -fn parse_args() -> (Config, String, f64) { - let default_value = std::f64::consts::PI.to_string(); - - let args = App::new("zenoh put float example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg( - Arg::from_usage("-k, --key=[KEYEXPR] 'The key expression to put.'") - .default_value("demo/example/zenoh-rs-put"), - ) - .arg( - Arg::from_usage("-v, --value=[VALUE] 'The float value to put.'") - .default_value(&default_value), - ) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - - let key_expr = args.value_of("key").unwrap().to_string(); - let value: f64 = args.value_of("value").unwrap().parse().unwrap(); +#[derive(clap::Parser, Clone, PartialEq, Debug)] +struct Args { + #[arg(short, long, default_value = "demo/example/zenoh-rs-put")] + /// The key expression to write to. + key: KeyExpr<'static>, + #[arg(short, long, default_value_t = std::f64::consts::PI)] + /// The value to write. + value: f64, + #[command(flatten)] + common: CommonArgs, +} - (config, key_expr, value) +fn parse_args() -> (Config, KeyExpr<'static>, f64) { + let args = Args::parse(); + (args.common.into(), args.key, args.value) } diff --git a/examples/examples/z_queryable.rs b/examples/examples/z_queryable.rs index 751a794a3..5738c67f6 100644 --- a/examples/examples/z_queryable.rs +++ b/examples/examples/z_queryable.rs @@ -12,14 +12,14 @@ // ZettaScale Zenoh Team, // use async_std::task::sleep; -use clap::{App, Arg}; +use clap::Parser; use futures::prelude::*; use futures::select; -use std::convert::TryFrom; use std::sync::atomic::Ordering::Relaxed; use std::time::Duration; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -29,7 +29,6 @@ async fn main() { let (config, key_expr, value, complete) = parse_args(); let send_errors = std::sync::atomic::AtomicBool::new(false); - let key_expr = KeyExpr::try_from(key_expr).unwrap(); println!("Opening session..."); let session = zenoh::open(config).res().await.unwrap(); @@ -85,59 +84,22 @@ async fn main() { } } -fn parse_args() -> (Config, String, String, bool) { - let args = App::new("zenoh queryable example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage( - "-k, --key=[KEYEXPR] 'The key expression matching queries to reply to.'", - ) - .default_value("demo/example/zenoh-rs-queryable"), - ) - .arg( - Arg::from_usage("-v, --value=[VALUE] 'The value to reply to queries.'") - .default_value("Queryable from Rust!"), - ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .arg(Arg::from_usage( - "--complete 'Declare the queryable as complete w.r.t. the key expression.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - let key_expr = args.value_of("key").unwrap().to_string(); - let value = args.value_of("value").unwrap().to_string(); - let complete = args.is_present("complete"); +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[arg(short, long, default_value = "demo/example/zenoh-rs-queryable")] + /// The key expression matching queries to reply to. + key: KeyExpr<'static>, + #[arg(short, long, default_value = "Queryable from Rust")] + /// The value to reply to queries. + value: String, + #[arg(long)] + /// Declare the queryable as complete w.r.t. the key expression. + complete: bool, + #[command(flatten)] + common: CommonArgs, +} - (config, key_expr, value, complete) +fn parse_args() -> (Config, KeyExpr<'static>, String, bool) { + let args = Args::parse(); + (args.common.into(), args.key, args.value, args.complete) } diff --git a/examples/examples/z_storage.rs b/examples/examples/z_storage.rs index 1d5287c72..79164c914 100644 --- a/examples/examples/z_storage.rs +++ b/examples/examples/z_storage.rs @@ -14,13 +14,14 @@ #![recursion_limit = "256"] use async_std::task::sleep; -use clap::{App, Arg}; +use clap::Parser; use futures::prelude::*; use futures::select; use std::collections::HashMap; use std::time::Duration; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -82,53 +83,19 @@ async fn main() { } } -fn parse_args() -> (Config, String, bool) { - let args = App::new("zenoh storage example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage("-k, --key=[KEYEXPR] 'The selection of resources to store'") - .default_value("demo/example/**"), - ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .arg(Arg::from_usage( - "--complete 'Declare the storage as complete w.r.t. the key expression.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - - let key_expr = args.value_of("key").unwrap().to_string(); - let complete = args.is_present("complete"); +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[arg(short, long, default_value = "demo/example/**")] + /// The selection of resources to store. + key: KeyExpr<'static>, + #[arg(long)] + /// Declare the storage as complete w.r.t. the key expression. + complete: bool, + #[command(flatten)] + common: CommonArgs, +} - (config, key_expr, complete) +fn parse_args() -> (Config, KeyExpr<'static>, bool) { + let args = Args::parse(); + (args.common.into(), args.key, args.complete) } diff --git a/examples/examples/z_sub.rs b/examples/examples/z_sub.rs index af23760e9..0542f8587 100644 --- a/examples/examples/z_sub.rs +++ b/examples/examples/z_sub.rs @@ -12,13 +12,13 @@ // ZettaScale Zenoh Team, // use async_std::task::sleep; -use clap::{App, Arg}; +use clap::Parser; use futures::prelude::*; use futures::select; -use std::convert::TryFrom; use std::time::Duration; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -61,51 +61,16 @@ async fn main() { } } -fn parse_args() -> (Config, KeyExpr<'static>) { - let args = App::new("zenoh sub example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage("-k, --key=[KEYEXPR] 'The key expression to subscribe to.'") - .default_value("demo/example/**"), - ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - - let key_expr = KeyExpr::try_from(args.value_of("key").unwrap()) - .unwrap() - .into_owned(); +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct SubArgs { + #[arg(short, long, default_value = "demo/example/**")] + /// The Key Expression to subscribe to. + key: KeyExpr<'static>, + #[command(flatten)] + common: CommonArgs, +} - (config, key_expr) +fn parse_args() -> (Config, KeyExpr<'static>) { + let args = SubArgs::parse(); + (args.common.into(), args.key) } diff --git a/examples/examples/z_sub_liveliness.rs b/examples/examples/z_sub_liveliness.rs index ebb4a8706..52ba53875 100644 --- a/examples/examples/z_sub_liveliness.rs +++ b/examples/examples/z_sub_liveliness.rs @@ -12,13 +12,13 @@ // ZettaScale Zenoh Team, // use async_std::task::sleep; -use clap::{App, Arg}; +use clap::Parser; use futures::prelude::*; use futures::select; -use std::convert::TryFrom; use std::time::Duration; use zenoh::config::Config; use zenoh::prelude::r#async::*; +use zenoh_examples::CommonArgs; #[async_std::main] async fn main() { @@ -67,51 +67,16 @@ async fn main() { } } -fn parse_args() -> (Config, KeyExpr<'static>) { - let args = App::new("zenoh liveliness sub example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage("-k, --key=[KEYEXPR] 'The key expression mathing liveliness changes to subscribe to.'") - .default_value("group1/**"), - ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - - let key_expr = KeyExpr::try_from(args.value_of("key").unwrap()) - .unwrap() - .into_owned(); +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[arg(short, long, default_value = "group1/**")] + /// The key expression to write to. + key: KeyExpr<'static>, + #[command(flatten)] + common: CommonArgs, +} - (config, key_expr) +fn parse_args() -> (Config, KeyExpr<'static>) { + let args = Args::parse(); + (args.common.into(), args.key) } diff --git a/examples/examples/z_sub_thr.rs b/examples/examples/z_sub_thr.rs index c6c1846f5..671e50f88 100644 --- a/examples/examples/z_sub_thr.rs +++ b/examples/examples/z_sub_thr.rs @@ -11,13 +11,12 @@ // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; +use clap::Parser; use std::io::{stdin, Read}; -#[cfg(not(feature = "shared-memory"))] -use std::process::exit; use std::time::Instant; use zenoh::config::Config; use zenoh::prelude::sync::*; +use zenoh_examples::CommonArgs; struct Stats { round_count: usize, @@ -101,66 +100,19 @@ fn main() { } } -fn parse_args() -> (Config, usize, usize) { - let args = App::new("zenoh throughput sub example") - .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), - ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg( - Arg::from_usage("-s, --samples=[number] 'Number of throughput measurements.'") - .default_value("10"), - ) - .arg( - Arg::from_usage( - "-n, --number=[number] 'Number of messages in each throughput measurements.'", - ) - .default_value("100000"), - ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage("--enable-shm 'Enable SHM transport.'")) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) - .get_matches(); - - let mut config = if let Some(conf_file) = args.value_of("config") { - Config::from_file(conf_file).unwrap() - } else { - Config::default() - }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { - config.set_mode(Some(mode)).unwrap(); - } - if let Some(values) = args.values_of("connect") { - config.connect.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if let Some(values) = args.values_of("listen") { - config.listen.endpoints = values.map(|v| v.parse().unwrap()).collect(); - } - if args.is_present("no-multicast-scouting") { - config.scouting.multicast.set_enabled(Some(false)).unwrap(); - } - if args.is_present("enable-shm") { - #[cfg(feature = "shared-memory")] - config.transport.shared_memory.set_enabled(true).unwrap(); - #[cfg(not(feature = "shared-memory"))] - { - println!("enable-shm argument: SHM cannot be enabled, because Zenoh is compiled without shared-memory feature!"); - exit(-1); - } - } - - let samples: usize = args.value_of("samples").unwrap().parse().unwrap(); - let number: usize = args.value_of("number").unwrap().parse().unwrap(); +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +struct Args { + #[arg(short, long, default_value = "10")] + /// Number of throughput measurements. + samples: usize, + #[arg(short, long, default_value = "100000")] + /// Number of messages in each throughput measurements. + number: usize, + #[command(flatten)] + common: CommonArgs, +} - (config, samples, number) +fn parse_args() -> (Config, usize, usize) { + let args = Args::parse(); + (args.common.into(), args.samples, args.number) } diff --git a/examples/src/lib.rs b/examples/src/lib.rs index 8f5ad114a..e7c00cb60 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -1,3 +1,78 @@ //! Examples on using Zenoh. //! See the code in ../examples/ //! Check ../README.md for usage. +//! +use zenoh::config::Config; + +#[derive(clap::ValueEnum, Default, Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum Wai { + #[default] + Peer, + Client, + Router, +} +impl core::fmt::Display for Wai { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + core::fmt::Debug::fmt(&self, f) + } +} +#[derive(clap::Parser, Clone, PartialEq, Eq, Hash, Debug)] +pub struct CommonArgs { + #[arg(short, long)] + /// A configuration file. + config: Option, + #[arg(short, long, default_value_t)] + /// The Zenoh session mode. + mode: Wai, + #[arg(short = 'e', long)] + /// Endpoints to connect to. + connect: Vec, + #[arg(short, long)] + /// Endpoints to listen on. + listen: Vec, + #[arg(long)] + /// Disable the multicast-based scouting mechanism. + no_multicast_scouting: bool, + #[arg(long)] + /// Disable the multicast-based scouting mechanism. + enable_shm: bool, +} + +impl From for Config { + fn from(value: CommonArgs) -> Self { + (&value).into() + } +} +impl From<&CommonArgs> for Config { + fn from(value: &CommonArgs) -> Self { + let mut config = match &value.config { + Some(path) => Config::from_file(path).unwrap(), + None => Config::default(), + }; + match value.mode { + Wai::Peer => config.set_mode(Some(zenoh::scouting::WhatAmI::Peer)), + Wai::Client => config.set_mode(Some(zenoh::scouting::WhatAmI::Client)), + Wai::Router => config.set_mode(Some(zenoh::scouting::WhatAmI::Router)), + } + .unwrap(); + if !value.connect.is_empty() { + config.connect.endpoints = value.connect.iter().map(|v| v.parse().unwrap()).collect(); + } + if !value.listen.is_empty() { + config.listen.endpoints = value.listen.iter().map(|v| v.parse().unwrap()).collect(); + } + if value.no_multicast_scouting { + config.scouting.multicast.set_enabled(Some(false)).unwrap(); + } + if value.enable_shm { + #[cfg(feature = "shared-memory")] + config.transport.shared_memory.set_enabled(true).unwrap(); + #[cfg(not(feature = "shared-memory"))] + { + println!("enable-shm argument: SHM cannot be enabled, because Zenoh is compiled without shared-memory feature!"); + std::process::exit(-1); + } + } + config + } +} diff --git a/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs b/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs index daf3f80d2..d196b52c5 100644 --- a/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs +++ b/plugins/zenoh-plugin-rest/examples/z_serve_sse.rs @@ -11,7 +11,7 @@ // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; +use clap::{arg, Command}; use std::time::Duration; use zenoh::prelude::r#async::*; use zenoh::publication::CongestionControl; @@ -85,50 +85,45 @@ async fn main() { } fn parse_args() -> Config { - let args = App::new("zenoh ssl server example") + let args = Command::new("zenoh ssl server example") .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), + arg!(-m --mode [MODE] "The zenoh session mode (peer by default).") + .value_parser(["peer", "client"]), + ) + .arg(arg!(-e --connect [ENDPOINT]... "Endpoints to connect to.")) + .arg(arg!(-l --listen [ENDPOINT]... "Endpoints to listen on.")) + .arg(arg!(-c --config [FILE] "A configuration file.")) + .arg( + arg!(--no-multicast-scouting "Disable the multicast-based scouting mechanism." + ), ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) .get_matches(); - let mut config = if let Some(conf_file) = args.value_of("config") { + let mut config = if let Some(conf_file) = args.get_one::<&String>("config") { Config::from_file(conf_file).unwrap() } else { Config::default() }; - match args.value_of("mode").map(|m| m.parse()) { + match args.get_one::<&String>("mode").map(|m| m.parse()) { Some(Ok(mode)) => { config.set_mode(Some(mode)).unwrap(); } Some(Err(e)) => panic!("Invalid mode: {}", e), None => {} }; - if let Some(values) = args.values_of("connect") { + if let Some(values) = args.get_many::<&String>("connect") { config .connect .endpoints - .extend(values.map(|v| v.parse().unwrap())) + .extend(values.into_iter().map(|v| v.parse().unwrap())) } - if let Some(values) = args.values_of("listen") { + if let Some(values) = args.get_many::<&String>("listen") { config .listen .endpoints - .extend(values.map(|v| v.parse().unwrap())) + .extend(values.into_iter().map(|v| v.parse().unwrap())) } - if args.is_present("no-multicast-scouting") { + if args.get_flag("no-multicast-scouting") { config.scouting.multicast.set_enabled(Some(false)).unwrap(); } diff --git a/zenoh-ext/Cargo.toml b/zenoh-ext/Cargo.toml index 84c6baf83..91b0283dd 100644 --- a/zenoh-ext/Cargo.toml +++ b/zenoh-ext/Cargo.toml @@ -46,7 +46,7 @@ zenoh-sync = { workspace = true } zenoh-util = { workspace = true } [dev-dependencies] -clap = { workspace = true } +clap = { workspace = true, features = ["derive"] } [[example]] name = "z_query_sub" diff --git a/zenoh-ext/examples/z_pub_cache.rs b/zenoh-ext/examples/z_pub_cache.rs index 67879087a..516cb3bd8 100644 --- a/zenoh-ext/examples/z_pub_cache.rs +++ b/zenoh-ext/examples/z_pub_cache.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use async_std::task::sleep; -use clap::{App, Arg}; +use clap::{arg, Command}; use std::time::Duration; use zenoh::config::{Config, ModeDependentValue}; use zenoh::prelude::r#async::*; @@ -46,61 +46,48 @@ async fn main() { } fn parse_args() -> (Config, String, String, usize, Option) { - let args = App::new("zenoh-ext pub cache example") + let args = Command::new("zenoh-ext pub cache example") .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), + arg!(-m --mode [MODE] "The zenoh session mode (peer by default)") + .value_parser(["peer", "client"]), ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) + .arg(arg!(-e --connect [ENDPOINT]... "Endpoints to connect to.")) + .arg(arg!(-l --listen [ENDPOINT]... "Endpoints to listen on.")) .arg( - Arg::from_usage("-k, --key=[KEYEXPR] 'The key expression to publish.'") + arg!(-k --key [KEYEXPR] "The key expression to publish.") .default_value("demo/example/zenoh-rs-pub"), ) + .arg(arg!(-v --value [VALUE] "The value to publish.").default_value("Pub from Rust!")) .arg( - Arg::from_usage("-v, --value=[VALUE] 'The value to publish.'") - .default_value("Pub from Rust!"), - ) - .arg( - Arg::from_usage("-h, --history=[SIZE] 'The number of publications to keep in cache'") + arg!(-h --history [SIZE] "The number of publications to keep in cache") .default_value("1"), ) - .arg(Arg::from_usage( - "-x, --prefix=[STRING] 'An optional queryable prefix'", - )) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) + .arg(arg!(-x --prefix [STRING] "An optional queryable prefix")) + .arg(arg!(-c --config [FILE] "A configuration file.")) + .arg(arg!(--no-multicast-scouting "Disable the multicast-based scouting mechanism.")) .get_matches(); - let mut config = if let Some(conf_file) = args.value_of("config") { + let mut config = if let Some(conf_file) = args.get_one::<&String>("config") { Config::from_file(conf_file).unwrap() } else { Config::default() }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { + if let Some(Ok(mode)) = args.get_one::<&String>("mode").map(|mode| mode.parse()) { config.set_mode(Some(mode)).unwrap(); } - if let Some(values) = args.values_of("connect") { + if let Some(values) = args.get_many::<&String>("connect") { config .connect .endpoints .extend(values.map(|v| v.parse().unwrap())) } - if let Some(values) = args.values_of("listen") { + if let Some(values) = args.get_many::<&String>("listen") { config .listen .endpoints .extend(values.map(|v| v.parse().unwrap())) } - if args.is_present("no-multicast-scouting") { + if args.get_flag("no-multicast-scouting") { config.scouting.multicast.set_enabled(Some(false)).unwrap(); } @@ -110,10 +97,10 @@ fn parse_args() -> (Config, String, String, usize, Option) { .set_enabled(Some(ModeDependentValue::Unique(true))) .unwrap(); - let key_expr = args.value_of("key").unwrap().to_string(); - let value = args.value_of("value").unwrap().to_string(); - let history: usize = args.value_of("history").unwrap().parse().unwrap(); - let prefix = args.value_of("prefix").map(String::from); + let key_expr = args.get_one::<&String>("key").unwrap().to_string(); + let value = args.get_one::<&String>("value").unwrap().to_string(); + let history: usize = args.get_one::<&String>("history").unwrap().parse().unwrap(); + let prefix = args.get_one::<&String>("prefix").map(|s| (*s).to_owned()); (config, key_expr, value, history, prefix) } diff --git a/zenoh-ext/examples/z_query_sub.rs b/zenoh-ext/examples/z_query_sub.rs index 6c53ebd03..4d308bca5 100644 --- a/zenoh-ext/examples/z_query_sub.rs +++ b/zenoh-ext/examples/z_query_sub.rs @@ -12,7 +12,8 @@ // ZettaScale Zenoh Team, // use async_std::task::sleep; -use clap::{App, Arg}; +use clap::arg; +use clap::Command; use futures::prelude::*; use futures::select; use std::time::Duration; @@ -77,58 +78,50 @@ async fn main() { } fn parse_args() -> (Config, String, Option) { - let args = App::new("zenoh-ext query sub example") + let args = Command::new("zenoh-ext query sub example") .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), + arg!(-m --mode [MODE] "The zenoh session mode (peer by default).") + .value_parser(["peer", "client"]), ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", - )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", - )) + .arg(arg!(-e --connect [ENDPOINT]... "Endpoints to connect to.")) + .arg(arg!(-l --listen [ENDPOINT]... "Endpoints to listen on.")) .arg( - Arg::from_usage("-k, --key=[KEYEXPR] 'The key expression to subscribe onto'") + arg!(-k --key [KEYEXPR] "The key expression to subscribe onto") .default_value("demo/example/**"), ) .arg( - Arg::from_usage("-q, --query=[SELECTOR] 'The selector to use for queries (by default it's same than 'selector' option)'"), + arg!(-q --query [SELECTOR] "The selector to use for queries (by default it's same than 'selector' option)") ) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", - )) - .arg(Arg::from_usage( - "--no-multicast-scouting 'Disable the multicast-based scouting mechanism.'", - )) + .arg(arg!(-c --config [FILE] "A configuration file.")) + .arg(arg!(--no-multicast-scouting "Disable the multicast-based scouting mechanism.")) .get_matches(); - let mut config = if let Some(conf_file) = args.value_of("config") { + let mut config = if let Some(conf_file) = args.get_one::<&String>("config") { Config::from_file(conf_file).unwrap() } else { Config::default() }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { + if let Some(Ok(mode)) = args.get_one::<&String>("mode").map(|mode| mode.parse()) { config.set_mode(Some(mode)).unwrap(); } - if let Some(values) = args.values_of("connect") { + if let Some(values) = args.get_many::<&String>("connect") { config .connect .endpoints .extend(values.map(|v| v.parse().unwrap())) } - if let Some(values) = args.values_of("listen") { + if let Some(values) = args.get_many::<&String>("listen") { config .listen .endpoints .extend(values.map(|v| v.parse().unwrap())) } - if args.is_present("no-multicast-scouting") { + if args.get_flag("no-multicast-scouting") { config.scouting.multicast.set_enabled(Some(false)).unwrap(); } - let key_expr = args.value_of("key").unwrap().to_string(); - let query = args.value_of("query").map(ToString::to_string); + let key_expr = args.get_one::<&String>("key").unwrap().to_string(); + let query = args.get_one::<&String>("query").map(ToString::to_string); (config, key_expr, query) } diff --git a/zenoh-ext/examples/z_view_size.rs b/zenoh-ext/examples/z_view_size.rs index 7f9c1d179..575604885 100644 --- a/zenoh-ext/examples/z_view_size.rs +++ b/zenoh-ext/examples/z_view_size.rs @@ -11,7 +11,7 @@ // Contributors: // ZettaScale Zenoh Team, // -use clap::{App, Arg}; +use clap::{arg, Command}; use std::sync::Arc; use std::time::Duration; use zenoh::config::Config; @@ -50,59 +50,59 @@ async fn main() { } fn parse_args() -> (Config, String, Option, usize, u64) { - let args = App::new("zenoh-ext group view size example") + let args = Command::new("zenoh-ext group view size example") .arg( - Arg::from_usage("-m, --mode=[MODE] 'The zenoh session mode (peer by default).") - .possible_values(["peer", "client"]), + arg!(-m --mode [MODE] "The zenoh session mode (peer by default).") + .value_parser(["peer", "client"]), ) - .arg(Arg::from_usage( - "-e, --connect=[ENDPOINT]... 'Endpoints to connect to.'", + .arg(arg!( + -e --connect [ENDPOINT]... "Endpoints to connect to." )) - .arg(Arg::from_usage( - "-l, --listen=[ENDPOINT]... 'Endpoints to listen on.'", + .arg(arg!( + -l --listen [ENDPOINT]... "Endpoints to listen on." )) - .arg(Arg::from_usage( - "-c, --config=[FILE] 'A configuration file.'", + .arg(arg!( + -c --config [FILE] "A configuration file." )) - .arg(Arg::from_usage( - "-g, --group=[STRING] 'The group name'", + .arg(arg!( + -g --group [STRING] "The group name" ).default_value("zgroup")) - .arg(Arg::from_usage( - "-i, --id=[STRING] 'The group member id (default is the zenoh ID)'", + .arg(arg!( + -i --id [STRING] "The group member id (default is the zenoh ID)" )) - .arg(Arg::from_usage( - "-s, --size=[INT] 'The expected group size. The example will wait for the group to reach this size'", + .arg(arg!( + -s --size [INT] "The expected group size. The example will wait for the group to reach this size" ).default_value("3")) - .arg(Arg::from_usage( - "-t, --timeout=[SEC] 'The duration (in seconds) this example will wait for the group to reach the expected size.'", + .arg(arg!( + -t --timeout [SEC] "The duration (in seconds) this example will wait for the group to reach the expected size." ).default_value("15")) .get_matches(); - let mut config = if let Some(conf_file) = args.value_of("config") { + let mut config = if let Some(conf_file) = args.get_one::<&String>("config") { Config::from_file(conf_file).unwrap() } else { Config::default() }; - if let Some(Ok(mode)) = args.value_of("mode").map(|mode| mode.parse()) { + if let Some(Ok(mode)) = args.get_one::<&String>("mode").map(|mode| mode.parse()) { config.set_mode(Some(mode)).unwrap(); } - if let Some(values) = args.values_of("connect") { + if let Some(values) = args.get_many::<&String>("connect") { config .connect .endpoints .extend(values.map(|v| v.parse().unwrap())) } - if let Some(values) = args.values_of("listen") { + if let Some(values) = args.get_many::<&String>("listen") { config .listen .endpoints .extend(values.map(|v| v.parse().unwrap())) } - let group = args.value_of("group").unwrap().to_string(); - let id = args.value_of("id").map(String::from); - let size: usize = args.value_of("size").unwrap().parse().unwrap(); - let timeout: u64 = args.value_of("timeout").unwrap().parse().unwrap(); + let group = args.get_one::<&String>("group").unwrap().to_string(); + let id = args.get_one::<&String>("id").map(|v| (*v).to_owned()); + let size: usize = args.get_one::<&String>("size").unwrap().parse().unwrap(); + let timeout: u64 = args.get_one::<&String>("timeout").unwrap().parse().unwrap(); (config, group, id, size, timeout) } diff --git a/zenoh/src/selector.rs b/zenoh/src/selector.rs index 025645612..2a9a38c02 100644 --- a/zenoh/src/selector.rs +++ b/zenoh/src/selector.rs @@ -25,6 +25,7 @@ use std::{ collections::HashMap, convert::TryFrom, hash::Hash, + str::FromStr, }; /// A selector is the combination of a [Key Expression](crate::prelude::KeyExpr), which defines the @@ -483,6 +484,12 @@ impl<'a> TryFrom<&'a str> for Selector<'a> { } } } +impl FromStr for Selector<'static> { + type Err = zenoh_result::Error; + fn from_str(s: &str) -> Result { + s.to_owned().try_into() + } +} impl<'a> TryFrom<&'a String> for Selector<'a> { type Error = zenoh_result::Error; diff --git a/zenohd/Cargo.toml b/zenohd/Cargo.toml index 754198dc7..e3177a565 100644 --- a/zenohd/Cargo.toml +++ b/zenohd/Cargo.toml @@ -31,7 +31,7 @@ shared-memory = ["zenoh/shared-memory"] [dependencies] async-std = { workspace = true, features = ["attributes"] } -clap = { workspace = true } +clap = { workspace = true, features = ["derive"] } env_logger = { workspace = true } futures = { workspace = true } git-version = { workspace = true } diff --git a/zenohd/src/main.rs b/zenohd/src/main.rs index 56c56bc53..c864c303b 100644 --- a/zenohd/src/main.rs +++ b/zenohd/src/main.rs @@ -12,7 +12,7 @@ // ZettaScale Zenoh Team, // use async_std::task; -use clap::{ArgMatches, Command}; +use clap::Parser; use futures::future; use git_version::git_version; use std::collections::HashSet; @@ -29,6 +29,56 @@ lazy_static::lazy_static!( const DEFAULT_LISTENER: &str = "tcp/[::]:7447"; +#[derive(Debug, Parser)] +#[command(version=GIT_VERSION, long_version=LONG_VERSION.as_str(), about="The zenoh router")] +struct Args { + /// The configuration file. Currently, this file must be a valid JSON5 or YAML file. + #[arg(short, long, value_name = "PATH")] + config: Option, + /// Locators on which this router will listen for incoming sessions. Repeat this option to open several listeners. + #[arg(short, long, value_name = "ENDPOINT")] + listen: Vec, + /// A peer locator this router will try to connect to. + /// Repeat this option to connect to several peers. + #[arg(short = 'e', long, value_name = "ENDPOINT")] + connect: Vec, + /// The identifier (as an hexadecimal string, with odd number of chars - e.g.: A0B23...) that zenohd must use. If not set, a random unsigned 128bit integer will be used. + /// WARNING: this identifier must be unique in the system and must be 16 bytes maximum (32 chars)! + #[arg(short, long)] + id: Option, + /// A plugin that MUST be loaded. You can give just the name of the plugin, zenohd will search for a library named 'libzenoh_plugin_.so' (exact name depending the OS). Or you can give such a string: ": + /// Repeat this option to load several plugins. If loading failed, zenohd will exit. + #[arg(short = 'P', long)] + plugin: Vec, + /// Directory where to search for plugins libraries to load. + /// Repeat this option to specify several search directories. + #[arg(long, value_name = "PATH")] + plugin_search_dir: Vec, + /// By default zenohd adds a HLC-generated Timestamp to each routed Data if there isn't already one. This option disables this feature. + #[arg(long)] + no_timestamp: bool, + /// By default zenohd replies to multicast scouting messages for being discovered by peers and clients. This option disables this feature. + #[arg(long)] + no_multicast_scouting: bool, + /// Configures HTTP interface for the REST API (enabled by default on port 8000). Accepted values: + /// - a port number + /// - a string with format `:` (to bind the HTTP server to a specific interface) + /// - `none` to disable the REST API + #[arg(long, value_name = "SOCKET")] + rest_http_port: Option, + /// Allows arbitrary configuration changes as column-separated KEY:VALUE pairs, where: + /// - KEY must be a valid config path. + /// - VALUE must be a valid JSON5 string that can be deserialized to the expected type for the KEY field. + /// Examples: + /// --cfg='startup/subscribe:["demo/**"]' + /// --cfg='plugins/storage_manager/storages/demo:{key_expr:"demo/example/**",volume:"memory"}' + #[arg(long)] + cfg: Vec, + /// Configure the read and/or write permissions on the admin space. Default is read only. + #[arg(long, default_value = "r", value_name = "[r|w|rw|none]")] + adminspace_permissions: String, +} + fn main() { task::block_on(async { let mut log_builder = @@ -40,39 +90,7 @@ fn main() { log::info!("zenohd {}", *LONG_VERSION); - let app = Command::new("The zenoh router") - .version(GIT_VERSION) - .long_version(LONG_VERSION.as_str()).args( - &[ -clap::arg!(-c --config [FILE] "The configuration file. Currently, this file must be a valid JSON5 or YAML file."), -clap::Arg::new("listen").short('l').long("listen").value_name("ENDPOINT").help(r"A locator on which this router will listen for incoming sessions. -Repeat this option to open several listeners.").takes_value(true).multiple_occurrences(true), -clap::Arg::new("connect").short('e').long("connect").value_name("ENDPOINT").help(r"A peer locator this router will try to connect to. -Repeat this option to connect to several peers.").takes_value(true).multiple_occurrences(true), -clap::Arg::new("id").short('i').long("id").value_name("HEX_STRING").help(r"The identifier (as an hexadecimal string, with odd number of chars - e.g.: A0B23...) that zenohd must use. If not set, a random unsigned 128bit integer will be used. -WARNING: this identifier must be unique in the system and must be 16 bytes maximum (32 chars)!").multiple_values(false).multiple_occurrences(false), -clap::Arg::new("plugin").short('P').long("plugin").value_name("PLUGIN").takes_value(true).multiple_occurrences(true).help(r#"A plugin that MUST be loaded. You can give just the name of the plugin, zenohd will search for a library named 'libzenoh_plugin_.so' (exact name depending the OS). Or you can give such a string: ":". -Repeat this option to load several plugins. If loading failed, zenohd will exit."#), -clap::Arg::new("plugin-search-dir").long("plugin-search-dir").takes_value(true).multiple_occurrences(true).value_name("DIRECTORY").help(r"A directory where to search for plugins libraries to load. -Repeat this option to specify several search directories."), -clap::arg!(--"no-timestamp" r"By default zenohd adds a HLC-generated Timestamp to each routed Data if there isn't already one. This option disables this feature."), -clap::arg!(--"no-multicast-scouting" r"By default zenohd replies to multicast scouting messages for being discovered by peers and clients. This option disables this feature."), -clap::arg!(--"rest-http-port" [SOCKET] r"Configures HTTP interface for the REST API (enabled by default). Accepted values: - - a port number - - a string with format `:` (to bind the HTTP server to a specific interface) - - `none` to disable the REST API -").default_value("8000").multiple_values(false).multiple_occurrences(false), -clap::Arg::new("cfg").long("cfg").takes_value(true).multiple_occurrences(true).value_name("KEY:VALUE").help( -r#"Allows arbitrary configuration changes as column-separated KEY:VALUE pairs, where: - - KEY must be a valid config path. - - VALUE must be a valid JSON5 string that can be deserialized to the expected type for the KEY field. -Examples: ---cfg='startup/subscribe:["demo/**"]' ---cfg='plugins/storage_manager/storages/demo:{key_expr:"demo/example/**",volume:"memory"}'"#), -clap::Arg::new("adminspace-permissions").long("adminspace-permissions").value_name("[r|w|rw|none]").help(r"Configure the read and/or write permissions on the admin space. Default is read only."), - ] - ); - let args = app.get_matches(); + let args = Args::parse(); let config = config_from_args(&args); log::info!("Initial conf: {}", &config); @@ -150,9 +168,10 @@ clap::Arg::new("adminspace-permissions").long("adminspace-permissions").value_na }); } -fn config_from_args(args: &ArgMatches) -> Config { +fn config_from_args(args: &Args) -> Config { let mut config = args - .value_of("config") + .config + .as_ref() .map_or_else(Config::default, |conf_file| { Config::from_file(conf_file).unwrap() }); @@ -160,15 +179,13 @@ fn config_from_args(args: &ArgMatches) -> Config { if config.mode().is_none() { config.set_mode(Some(WhatAmI::Router)).unwrap(); } - if args.occurrences_of("id") > 0 { - config - .set_id(args.value_of("id").unwrap().parse().unwrap()) - .unwrap(); + if let Some(id) = &args.id { + config.set_id(id.parse().unwrap()).unwrap(); } // apply '--rest-http-port' to config only if explicitly set (overwritting config), // or if no config file is set (to apply its default value) - if args.occurrences_of("rest-http-port") > 0 || args.occurrences_of("config") == 0 { - let value = args.value_of("rest-http-port").unwrap(); + if args.rest_http_port.is_some() || args.config.is_none() { + let value = args.rest_http_port.as_deref().unwrap_or("8000"); if !value.eq_ignore_ascii_case("none") { config .insert_json5("plugins/rest/http_port", &format!(r#""{value}""#)) @@ -178,33 +195,32 @@ fn config_from_args(args: &ArgMatches) -> Config { .unwrap(); } } - if let Some(plugins_search_dirs) = args.values_of("plugin-search-dir") { + if !args.plugin_search_dir.is_empty() { config - .set_plugins_search_dirs(plugins_search_dirs.map(|c| c.to_owned()).collect()) + .set_plugins_search_dirs(args.plugin_search_dir.clone()) .unwrap(); } - if let Some(plugins) = args.values_of("plugin") { - for plugin in plugins { - match plugin.split_once(':') { - Some((name, path)) => { - config - .insert_json5(&format!("plugins/{name}/__required__"), "true") - .unwrap(); - config - .insert_json5(&format!("plugins/{name}/__path__"), &format!("\"{path}\"")) - .unwrap(); - } - None => config - .insert_json5(&format!("plugins/{plugin}/__required__"), "true") - .unwrap(), + for plugin in &args.plugin { + match plugin.split_once(':') { + Some((name, path)) => { + config + .insert_json5(&format!("plugins/{name}/__required__"), "true") + .unwrap(); + config + .insert_json5(&format!("plugins/{name}/__path__"), &format!("\"{path}\"")) + .unwrap(); } + None => config + .insert_json5(&format!("plugins/{plugin}/__required__"), "true") + .unwrap(), } } - if let Some(peers) = args.values_of("connect") { + if !args.connect.is_empty() { config .connect .set_endpoints( - peers + args.connect + .iter() .map(|v| match v.parse::() { Ok(v) => v, Err(e) => { @@ -215,11 +231,12 @@ fn config_from_args(args: &ArgMatches) -> Config { ) .unwrap(); } - if let Some(listeners) = args.values_of("listen") { + if !args.listen.is_empty() { config .listen .set_endpoints( - listeners + args.listen + .iter() .map(|v| match v.parse::() { Ok(v) => v, Err(e) => { @@ -236,7 +253,7 @@ fn config_from_args(args: &ArgMatches) -> Config { .endpoints .push(DEFAULT_LISTENER.parse().unwrap()) } - if args.is_present("no-timestamp") { + if args.no_timestamp { config .timestamping .set_enabled(Some(ModeDependentValue::Unique(false))) @@ -244,7 +261,7 @@ fn config_from_args(args: &ArgMatches) -> Config { }; match ( config.scouting.multicast.enabled().is_none(), - args.is_present("no-multicast-scouting"), + args.no_multicast_scouting, ) { (_, true) => { config.scouting.multicast.set_enabled(Some(false)).unwrap(); @@ -254,43 +271,41 @@ fn config_from_args(args: &ArgMatches) -> Config { } (false, false) => {} }; - if let Some(permissions) = args.value_of("adminspace-permissions") { - match permissions { - "r" => config - .adminspace - .set_permissions(PermissionsConf { - read: true, - write: false, - }) - .unwrap(), - "w" => config - .adminspace - .set_permissions(PermissionsConf { - read: false, - write: true, - }) - .unwrap(), - "rw" => config - .adminspace - .set_permissions(PermissionsConf { - read: true, - write: true, - }) - .unwrap(), - "none" => config - .adminspace - .set_permissions(PermissionsConf { - read: false, - write: false, - }) - .unwrap(), - s => panic!( - r#"Invalid option: --adminspace-permissions={} - Accepted values: "r", "w", "rw" or "none""#, - s - ), - }; + match args.adminspace_permissions.as_str() { + "r" => config + .adminspace + .set_permissions(PermissionsConf { + read: true, + write: false, + }) + .unwrap(), + "w" => config + .adminspace + .set_permissions(PermissionsConf { + read: false, + write: true, + }) + .unwrap(), + "rw" => config + .adminspace + .set_permissions(PermissionsConf { + read: true, + write: true, + }) + .unwrap(), + "none" => config + .adminspace + .set_permissions(PermissionsConf { + read: false, + write: false, + }) + .unwrap(), + s => panic!( + r#"Invalid option: --adminspace-permissions={} - Accepted values: "r", "w", "rw" or "none""#, + s + ), }; - for json in args.values_of("cfg").unwrap_or_default() { + for json in &args.cfg { if let Some((key, value)) = json.split_once(':') { match json5::Deserializer::from_str(value) { Ok(mut deserializer) => {