Unable to get any Argument neither from options nor subcommand options #1806
-
Rust Versionrustc 1.43.0-nightly (96bb8b31c 2020-03-05) Codeextern crate clap;
extern crate dirs;
extern crate log;
extern crate simple_logger;
use clap::{crate_version, App, Arg, SubCommand, AppSettings};
use i2p_client::I2PClient;
use ra_common::models::{Envelope, Packet, PacketType, NetworkId};
use std::panic::resume_unwind;
use std::process::exit;
fn main() {
simple_logger::init().unwrap();
let m = App::new("i2p_client")
.about("A SAM I2P client for the local I2P router instance. Not compliant with any version yet.")
.version(crate_version!())
.author("Brian Taylor <brian@resolvingarchitecture.io>")
.setting(AppSettings::ArgRequiredElseHelp)
.setting(AppSettings::ColoredHelp)
.setting(AppSettings::ColorAlways)
.arg(
Arg::with_name("alias")
.help("Provides an alias when establishing sessions. If not provided, will use 'Anon' by default.")
.short("a")
.long("alias")
.takes_value(true)
)
.arg(
Arg::with_name("min_version")
.help("Minimum SAM version")
.long("min")
.takes_value(true)
)
.arg(
Arg::with_name("max_version")
.help("Maximum SAM version")
.long("max")
.takes_value(true)
)
.arg(
Arg::with_name("max_connection_attempts")
.help("Maximum attempts to make a connection before failure is accepted. Each failed attempt results in waiting 3 seconds prior to making another attempt.")
.short("c")
.long("max_connection_attempts")
.takes_value(true)
)
.arg(
Arg::with_name("local")
.help("use local keys [true|false]; true by default; when true, it will use an internally saved keyset with provided alias if provided or 'Anon' if not - when set to false, it uses whatever the I2P router provides")
.short("l")
.long("local")
.takes_value(true),
)
.subcommand(
App::new("send")
.about("send message - untested; max message size=31,744 bytes, recommended size is <11KB")
.args(&[
Arg::with_name("to")
.help("b32 address")
.long("to")
.required(true)
.takes_value(true),
Arg::with_name("message")
.help("message to send as string - required, max size=31,744 bytes, recommended size is <11KB")
.long("message")
.min_values(1)
.max_values(31_744)
.required(true)
.takes_value(true),
])
)
.subcommand(
App::new("receive")
.about("receive messages - untested")
)
.subcommand(
App::new("aliases")
.about("list aliases")
)
.subcommand(
App::new("dest")
.about("find a specific destination using nickname (alias/domain)")
.arg(
Arg::with_name("dest_alias")
.help("alias for destination search")
.short("da")
.long("dest_alias")
.required(true)
.takes_value(true),
)
)
.get_matches();
let local = true; // default
let mut alias = String::from("Anon"); // default
if m.value_of("alias").is_some() {
alias = String::from(m.value_of("alias").unwrap());
}
let mut min_version = "1.0"; // default
if m.value_of("min_version").is_some() {
min_version = m.value_of("min_version").unwrap();
}
let mut max_version = "1.0"; // default
if m.value_of("max_version").is_some() {
max_version = m.value_of("max_version").unwrap();
}
let mut max_connection_attempts: u8 = 3; // default
if m.value_of("max_connection_attempts").is_some() {
max_connection_attempts = m.value_of("max_connection_attempts").unwrap().parse().unwrap();
}
match m.subcommand_name() {
Some("aliases") => {
aliases();
},
Some("dest") => {
if m.value_of("dest_alias").is_none() {
println!("No 'dest_alias' parameter.");
exit(-1);
}
dest(m.value_of("dest_alias").unwrap());
},
Some("send") => {
if m.value_of("message").is_none() {
println!("No 'message' parameter.");
exit(-1);
}
if m.value_of("to").is_none() {
println!("No 'to' parameter.");
exit(-1);
}
send(
String::from(m.value_of("to").unwrap()),
String::from(m.value_of("message").unwrap()),
local,
alias,
min_version,
max_version,
max_connection_attempts);
},
Some("receive") => {
receive(
local,
alias,
min_version,
max_version,
max_connection_attempts);
},
None => {
println!("No subcommand was used")
},
_ => println!("Some other subcommand was used"),
}
}
fn dest(alias: &str) {
println!("{}\n{}\n", alias, I2PClient::dest(alias));
}
fn aliases() {
let m = I2PClient::aliases();
println!("Aliases...");
for k in m.keys() {
println!("{}\n{}\n", k, m.get(k).unwrap());
}
}
fn send(to: String, message: String, use_local: bool, alias: String, min_version: &str, max_version: &str, max_connection_attempts: u8) {
match I2PClient::new(use_local, alias, min_version, max_version, max_connection_attempts) {
Ok(mut client) => {
let env = Envelope::new(0, 0, message.into_bytes());
let packet = Packet::new(
1,
PacketType::Data as u8,
NetworkId::I2P as u8,
client.local_dest.clone(),
to,
Some(env));
println!("Sending msg...");
client.send(packet);
println!("Send successful")
},
Err(e) => println!("{}", e),
_ => {}
}
}
fn receive(use_local: bool, alias: String, min_version: &str, max_version: &str, max_connection_attempts: u8) {
match I2PClient::new(use_local, alias, min_version, max_version, max_connection_attempts) {
Ok(mut client) => {
match client.receive() {
Ok(packet) => {
if packet.envelope.is_some() {
println!("msg received: {}", String::from_utf8(packet.envelope.unwrap().msg).unwrap().as_str());
}
},
Err(e) => println!("{}", e)
}
},
Err(e) => println!("{}", e)
}
} Steps to reproduce the issuesThis works (no arguments):
Main option does not work:
Subcommand option does not work:
Affected Version of
|
Beta Was this translation helpful? Give feedback.
Replies: 23 comments 2 replies
-
If I get this right, you're trying to run the binary as |
Beta Was this translation helpful? Give feedback.
-
Tried but didn't work: |
Beta Was this translation helpful? Give feedback.
-
How do I run it through the binary? |
Beta Was this translation helpful? Give feedback.
-
I can't reproduce. Code: use clap::{App, Arg, crate_version, AppSettings};
fn main() {
let m = App::new("i2p_client")
.about("A SAM I2P client for the local I2P router instance. Not compliant with any version yet.")
.version(crate_version!())
.author("Brian Taylor <brian@resolvingarchitecture.io>")
.setting(AppSettings::ArgRequiredElseHelp)
.setting(AppSettings::ColoredHelp)
.setting(AppSettings::ColorAlways)
.arg(
Arg::with_name("alias")
.help("Provides an alias when establishing sessions. If not provided, will use 'Anon' by default.")
.short("a")
.long("alias")
.takes_value(true)
)
.arg(
Arg::with_name("min_version")
.help("Minimum SAM version")
.long("min")
.takes_value(true)
)
.arg(
Arg::with_name("max_version")
.help("Maximum SAM version")
.long("max")
.takes_value(true)
)
.arg(
Arg::with_name("max_connection_attempts")
.help("Maximum attempts to make a connection before failure is accepted. Each failed attempt results in waiting 3 seconds prior to making another attempt.")
.short("c")
.long("max_connection_attempts")
.takes_value(true)
)
.arg(
Arg::with_name("local")
.help("use local keys [true|false]; true by default; when true, it will use an internally saved keyset with provided alias if provided or 'Anon' if not - when set to false, it uses whatever the I2P router provides")
.short("l")
.long("local")
.takes_value(true),
)
.subcommand(
App::new("send")
.about("send message - untested; max message size=31,744 bytes, recommended size is <11KB")
.args(&[
Arg::with_name("to")
.help("b32 address")
.long("to")
.required(true)
.takes_value(true),
Arg::with_name("message")
.help("message to send as string - required, max size=31,744 bytes, recommended size is <11KB")
.long("message")
.min_values(1)
.max_values(31_744)
.required(true)
.takes_value(true),
])
)
.subcommand(
App::new("receive")
.about("receive messages - untested")
)
.subcommand(
App::new("aliases")
.about("list aliases")
)
.subcommand(
App::new("dest")
.about("find a specific destination using nickname (alias/domain)")
.arg(
Arg::with_name("dest_alias")
.help("alias for destination search")
.short("da")
.long("dest_alias")
.required(true)
.takes_value(true),
)
)
.get_matches();
println!("{:?}", m);
}
Are you sure you're running it exactly as I do? Could you please post the error? |
Beta Was this translation helpful? Give feedback.
-
Just to be sure, could you please post the whole invocation, including the part you typed in and the output you get from it? |
Beta Was this translation helpful? Give feedback.
-
$ cargo run -- send --to 'Bob' --message 'hello' $ cargo run -- --alias Alice send --to Bob --message hello USAGE: For more information try --help |
Beta Was this translation helpful? Give feedback.
-
I think this is the part to blame: if m.value_of("message").is_none() {
println!("No 'message' parameter.");
exit(-1);
} |
Beta Was this translation helpful? Give feedback.
-
OK, the first fails because you're defining the argument as part of subcommand but you're trying to get its value from top level. Use |
Beta Was this translation helpful? Give feedback.
-
Replaced with: Some("send") => {
let am = m.subcommand().1.unwrap();
if am.subcommand_matches("message").is_none() {
println!("No 'message' parameter.");
exit(-1);
}
if am.subcommand_matches("to").is_none() {
println!("No 'to' parameter.");
exit(-1);
}
send(
String::from(m.value_of("to").unwrap()),
String::from(m.value_of("message").unwrap()),
local,
alias,
min_version,
max_version,
max_connection_attempts);
}, But still get same error. |
Beta Was this translation helpful? Give feedback.
-
If I put this piece of code: let cmd = m.subcommand().0;
println!("subcmd: {}", cmd); I get this output: |
Beta Was this translation helpful? Give feedback.
-
You were supposed to use this methods to get "submatches", and then extract the value from them. Please read the documentation for the corresponding methods: https://docs.rs/clap/2.33.0/clap/struct.ArgMatches.html#method.subcommand_matches Actually, if you're having trouble wrapping you head around raw clap, I recommend you to consider |
Beta Was this translation helpful? Give feedback.
-
Then again, this is not how |
Beta Was this translation helpful? Give feedback.
-
Oops, wrong link: https://github.com/clap-rs/clap/blob/v2.33.0/examples/20_subcommands.rs |
Beta Was this translation helpful? Give feedback.
-
Sorry, trying to understand this. Based on what you can see I'm doing, what's the simplest way to use this library? I see a lot of examples but they seem to be portions of solutions and I'm unsure how to put them together. |
Beta Was this translation helpful? Give feedback.
-
Sidenote: You seem to be using |
Beta Was this translation helpful? Give feedback.
-
I believe |
Beta Was this translation helpful? Give feedback.
-
I'm converting this into discussion since it's not an issue with clap |
Beta Was this translation helpful? Give feedback.
-
Ahhah! That last link you gave had the answer. This works: Some("send") => {
let cmd = m.subcommand().0;
println!("subcmd: {}", cmd);
let am = m.subcommand().1.unwrap();
if am.value_of("message").is_none() {
println!("No 'message' parameter.");
exit(-1);
}
if am.value_of("to").is_none() {
println!("No 'to' parameter.");
exit(-1);
}
send(
String::from(am.value_of("to").unwrap()),
String::from(am.value_of("message").unwrap()),
local,
alias,
min_version,
max_version,
max_connection_attempts);
}, |
Beta Was this translation helpful? Give feedback.
-
Thanks for your time! |
Beta Was this translation helpful? Give feedback.
-
Have a link for the second problem? :) |
Beta Was this translation helpful? Give feedback.
-
Actually, nevermind. It is now working correctly too using -- |
Beta Was this translation helpful? Give feedback.
-
Are you super duper sure it exits with
??? Because I really can't reproduce it, it just works:
Maybe some sort of miscompiled artifact? Try |
Beta Was this translation helpful? Give feedback.
-
Ah well. Nice to hear. |
Beta Was this translation helpful? Give feedback.
Oops, wrong link: https://github.com/clap-rs/clap/blob/v2.33.0/examples/20_subcommands.rs