diff options
| author | David Lönnhager <david.l@mullvad.net> | 2022-02-11 13:56:23 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2022-02-14 17:50:37 +0100 |
| commit | bc9edac3fe447240798ffa3d56aa42c211453a92 (patch) | |
| tree | 32680ab33cdf6c237ac8f5fc93cd88b16098ae19 /mullvad-cli/src | |
| parent | 990dcd256d2c1606d4b1c135a2e979e9cefb4ab7 (diff) | |
| download | mullvadvpn-bc9edac3fe447240798ffa3d56aa42c211453a92.tar.xz mullvadvpn-bc9edac3fe447240798ffa3d56aa42c211453a92.zip | |
Upgrade clap to 3.0
Diffstat (limited to 'mullvad-cli/src')
| -rw-r--r-- | mullvad-cli/src/cmds/account.rs | 40 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/auto_connect.rs | 18 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/beta_program.rs | 19 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/block_when_disconnected.rs | 15 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/bridge.rs | 132 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/connect.rs | 10 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/disconnect.rs | 10 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/dns.rs | 53 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/lan.rs | 24 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/reconnect.rs | 10 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/relay.rs | 147 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/reset.rs | 6 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/split_tunnel/linux.rs | 39 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/split_tunnel/windows.rs | 51 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/status.rs | 16 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/tunnel.rs | 146 | ||||
| -rw-r--r-- | mullvad-cli/src/cmds/version.rs | 6 | ||||
| -rw-r--r-- | mullvad-cli/src/location.rs | 32 | ||||
| -rw-r--r-- | mullvad-cli/src/main.rs | 43 |
19 files changed, 386 insertions, 431 deletions
diff --git a/mullvad-cli/src/cmds/account.rs b/mullvad-cli/src/cmds/account.rs index af3af0debd..0bbbc28024 100644 --- a/mullvad-cli/src/cmds/account.rs +++ b/mullvad-cli/src/cmds/account.rs @@ -1,5 +1,4 @@ use crate::{new_rpc_client, Command, Error, Result}; -use clap::value_t_or_exit; use itertools::Itertools; use mullvad_management_interface::{types::Timestamp, Code}; use mullvad_types::account::AccountToken; @@ -13,43 +12,38 @@ impl Command for Account { "account" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Control and display information about your Mullvad account") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand( - clap::SubCommand::with_name("set") - .about("Change account") - .arg( - clap::Arg::with_name("token") - .help("The Mullvad account token to configure the client with") - .required(false), - ), + clap::App::new("set").about("Change account").arg( + clap::Arg::new("token") + .help("The Mullvad account token to configure the client with") + .required(false), + ), ) .subcommand( - clap::SubCommand::with_name("get") + clap::App::new("get") .about("Display information about the currently configured account"), ) .subcommand( - clap::SubCommand::with_name("unset") - .about("Removes the account number from the settings"), + clap::App::new("unset").about("Removes the account number from the settings"), ) .subcommand( - clap::SubCommand::with_name("create") + clap::App::new("create") .about("Creates a new account and sets it as the active one"), ) .subcommand( - clap::SubCommand::with_name("redeem") - .about("Redeems a voucher") - .arg( - clap::Arg::with_name("voucher") - .help("The Mullvad voucher code to be submitted") - .required(true), - ), + clap::App::new("redeem").about("Redeems a voucher").arg( + clap::Arg::new("voucher") + .help("The Mullvad voucher code to be submitted") + .required(true), + ), ) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { if let Some(set_matches) = matches.subcommand_matches("set") { let mut token = match set_matches.value_of("token") { Some(token) => token.to_string(), @@ -74,7 +68,7 @@ impl Command for Account { } else if let Some(_matches) = matches.subcommand_matches("create") { self.create().await } else if let Some(matches) = matches.subcommand_matches("redeem") { - let voucher = value_t_or_exit!(matches.value_of("voucher"), String); + let voucher = matches.value_of_t_or_exit("voucher"); self.redeem_voucher(voucher).await } else { unreachable!("No account command given"); diff --git a/mullvad-cli/src/cmds/auto_connect.rs b/mullvad-cli/src/cmds/auto_connect.rs index 52e62e0c70..244968dcd7 100644 --- a/mullvad-cli/src/cmds/auto_connect.rs +++ b/mullvad-cli/src/cmds/auto_connect.rs @@ -1,5 +1,4 @@ use crate::{new_rpc_client, Command, Result}; -use clap::value_t_or_exit; pub struct AutoConnect; @@ -9,28 +8,25 @@ impl Command for AutoConnect { "auto-connect" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Control the daemon auto-connect setting") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand( - clap::SubCommand::with_name("set") + clap::App::new("set") .about("Change auto-connect setting") .arg( - clap::Arg::with_name("policy") + clap::Arg::new("policy") .required(true) .possible_values(&["on", "off"]), ), ) - .subcommand( - clap::SubCommand::with_name("get") - .about("Display the current auto-connect setting"), - ) + .subcommand(clap::App::new("get").about("Display the current auto-connect setting")) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { if let Some(set_matches) = matches.subcommand_matches("set") { - let auto_connect = value_t_or_exit!(set_matches.value_of("policy"), String); + let auto_connect = set_matches.value_of("policy").expect("missing policy"); self.set(auto_connect == "on").await } else if let Some(_matches) = matches.subcommand_matches("get") { self.get().await diff --git a/mullvad-cli/src/cmds/beta_program.rs b/mullvad-cli/src/cmds/beta_program.rs index 73a0ba15c7..871b28324e 100644 --- a/mullvad-cli/src/cmds/beta_program.rs +++ b/mullvad-cli/src/cmds/beta_program.rs @@ -1,5 +1,4 @@ use crate::{new_rpc_client, Command, Error, Result, PRODUCT_VERSION}; -use clap::value_t_or_exit; pub struct BetaProgram; @@ -9,25 +8,25 @@ impl Command for BetaProgram { "beta-program" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Receive notifications about beta updates") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand( - clap::SubCommand::with_name("set") + clap::App::new("set") .about("Change beta notifications setting") .arg( - clap::Arg::with_name("policy") + clap::Arg::new("policy") .required(true) .possible_values(&["on", "off"]), ), ) - .subcommand(clap::SubCommand::with_name("get").about("Get beta notifications setting")) + .subcommand(clap::App::new("get").about("Get beta notifications setting")) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { match matches.subcommand() { - ("get", Some(_)) => { + Some(("get", _)) => { let mut rpc = new_rpc_client().await?; let settings = rpc.get_settings(()).await?.into_inner(); let enabled_str = if settings.show_beta_releases { @@ -38,8 +37,8 @@ impl Command for BetaProgram { println!("Beta program: {}", enabled_str); Ok(()) } - ("set", Some(matches)) => { - let enable_str = value_t_or_exit!(matches.value_of("policy"), String); + Some(("set", matches)) => { + let enable_str = matches.value_of("policy").expect("missing policy"); let enable = enable_str == "on"; if !enable && PRODUCT_VERSION.contains("beta") { diff --git a/mullvad-cli/src/cmds/block_when_disconnected.rs b/mullvad-cli/src/cmds/block_when_disconnected.rs index 3cb1baff5a..3f7ebeef22 100644 --- a/mullvad-cli/src/cmds/block_when_disconnected.rs +++ b/mullvad-cli/src/cmds/block_when_disconnected.rs @@ -1,5 +1,4 @@ use crate::{new_rpc_client, Command, Result}; -use clap::value_t_or_exit; pub struct BlockWhenDisconnected; @@ -9,28 +8,28 @@ impl Command for BlockWhenDisconnected { "always-require-vpn" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Control if the system service should block network access when disconnected from VPN") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand( - clap::SubCommand::with_name("set") + clap::App::new("set") .about("Change the always require VPN setting") .arg( - clap::Arg::with_name("policy") + clap::Arg::new("policy") .required(true) .possible_values(&["on", "off"]), ), ) .subcommand( - clap::SubCommand::with_name("get") + clap::App::new("get") .about("Display the current always require VPN setting"), ) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { if let Some(set_matches) = matches.subcommand_matches("set") { - let block_when_disconnected = value_t_or_exit!(set_matches.value_of("policy"), String); + let block_when_disconnected = set_matches.value_of("policy").expect("missing policy"); self.set(block_when_disconnected == "on").await } else if let Some(_matches) = matches.subcommand_matches("get") { self.get().await diff --git a/mullvad-cli/src/cmds/bridge.rs b/mullvad-cli/src/cmds/bridge.rs index 3267ec3541..e1b0056a15 100644 --- a/mullvad-cli/src/cmds/bridge.rs +++ b/mullvad-cli/src/cmds/bridge.rs @@ -1,5 +1,4 @@ use crate::{location, new_rpc_client, Command, Error, Result}; -use clap::{value_t, values_t}; use mullvad_management_interface::types; use mullvad_types::relay_constraints::{ @@ -7,10 +6,7 @@ use mullvad_types::relay_constraints::{ }; use talpid_types::net::openvpn::{self, SHADOWSOCKS_CIPHERS}; -use std::{ - convert::TryFrom, - net::{IpAddr, SocketAddr}, -}; +use std::{convert::TryFrom, net::SocketAddr}; pub struct Bridge; @@ -20,43 +16,41 @@ impl Command for Bridge { "bridge" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Manage use of bridges") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand(create_bridge_set_subcommand()) - .subcommand( - clap::SubCommand::with_name("get").about("Get current bridge settings and state"), - ) - .subcommand(clap::SubCommand::with_name("list").about("List bridge relays")) + .subcommand(clap::App::new("get").about("Get current bridge settings and state")) + .subcommand(clap::App::new("list").about("List bridge relays")) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { match matches.subcommand() { - ("set", Some(set_matches)) => Self::handle_set(set_matches).await, - ("get", _) => Self::handle_get().await, - ("list", _) => Self::list_bridge_relays().await, + Some(("set", set_matches)) => Self::handle_set(set_matches).await, + Some(("get", _)) => Self::handle_get().await, + Some(("list", _)) => Self::list_bridge_relays().await, _ => unreachable!("unhandled command"), } } } -fn create_bridge_set_subcommand() -> clap::App<'static, 'static> { - clap::SubCommand::with_name("set") +fn create_bridge_set_subcommand() -> clap::App<'static> { + clap::App::new("set") .about("Set bridge state and settings") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand(create_set_state_subcommand()) .subcommand(create_set_custom_settings_subcommand()) .subcommand( - clap::SubCommand::with_name("provider") + clap::App::new("provider") .about( "Set hosting provider(s) to select bridge relays from. The 'list' \ command shows the available relays and their providers.", ) .arg( - clap::Arg::with_name("provider") + clap::Arg::new("provider") .help("The hosting provider(s) to use, or 'any' for no preference.") - .multiple(true) + .multiple_values(true) .required(true), ), ) @@ -66,24 +60,24 @@ fn create_bridge_set_subcommand() -> clap::App<'static, 'static> { )) } -fn create_set_custom_settings_subcommand() -> clap::App<'static, 'static> { +fn create_set_custom_settings_subcommand() -> clap::App<'static> { #[allow(unused_mut)] - let mut local_subcommand = clap::SubCommand::with_name("local") + let mut local_subcommand = clap::App::new("local") .about("Registers a local SOCKS5 proxy") .arg( - clap::Arg::with_name("local-port") + clap::Arg::new("local-port") .help("Specifies the port the local proxy server is listening on") .required(true) .index(1), ) .arg( - clap::Arg::with_name("remote-ip") + clap::Arg::new("remote-ip") .help("Specifies the IP of the proxy server peer") .required(true) .index(2), ) .arg( - clap::Arg::with_name("remote-port") + clap::Arg::new("remote-port") .help("Specifies the port of the proxy server peer") .required(true) .index(3), @@ -99,67 +93,67 @@ fn create_set_custom_settings_subcommand() -> clap::App<'static, 'static> { } #[cfg(target_os = "macos")] { - local_subcommand = local_subcommand.help( + local_subcommand = local_subcommand.about( "Registers a local SOCKS5 proxy. The server must run as root to bypass \ firewall restrictions", ); } - clap::SubCommand::with_name("custom") + clap::App::new("custom") .about("Configure a SOCKS5 proxy") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand(local_subcommand) .subcommand( - clap::SubCommand::with_name("remote") + clap::App::new("remote") .about("Registers a remote SOCKS5 proxy") .arg( - clap::Arg::with_name("remote-ip") + clap::Arg::new("remote-ip") .help("Specifies the IP of the remote proxy server") .required(true) .index(1), ) .arg( - clap::Arg::with_name("remote-port") + clap::Arg::new("remote-port") .help("Specifies the port the remote proxy server is listening on") .required(true) .index(2), ) .arg( - clap::Arg::with_name("username") + clap::Arg::new("username") .help("Specifies the username for remote authentication") .required(true) .index(3), ) .arg( - clap::Arg::with_name("password") + clap::Arg::new("password") .help("Specifies the password for remote authentication") .required(true) .index(4), ), ) .subcommand( - clap::SubCommand::with_name("shadowsocks") + clap::App::new("shadowsocks") .about("Configure bundled Shadowsocks proxy") .arg( - clap::Arg::with_name("remote-ip") + clap::Arg::new("remote-ip") .help("Specifies the IP of the remote Shadowsocks server") .required(true) .index(1), ) .arg( - clap::Arg::with_name("remote-port") + clap::Arg::new("remote-port") .help("Specifies the port of the remote Shadowsocks server") .default_value("443") .index(2), ) .arg( - clap::Arg::with_name("password") + clap::Arg::new("password") .help("Specifies the password on the remote Shadowsocks server") .default_value("mullvad") .index(3), ) .arg( - clap::Arg::with_name("cipher") + clap::Arg::new("cipher") .help("Specifies the cipher to use") .default_value("aes-256-gcm") .possible_values(SHADOWSOCKS_CIPHERS) @@ -168,31 +162,29 @@ fn create_set_custom_settings_subcommand() -> clap::App<'static, 'static> { ) } -fn create_set_state_subcommand() -> clap::App<'static, 'static> { - clap::SubCommand::with_name("state") - .about("Set bridge state") - .arg( - clap::Arg::with_name("policy") - .help("Specifies whether a bridge should be used") - .required(true) - .index(1) - .possible_values(&["auto", "on", "off"]), - ) +fn create_set_state_subcommand() -> clap::App<'static> { + clap::App::new("state").about("Set bridge state").arg( + clap::Arg::new("policy") + .help("Specifies whether a bridge should be used") + .required(true) + .index(1) + .possible_values(&["auto", "on", "off"]), + ) } impl Bridge { - async fn handle_set(matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn handle_set(matches: &clap::ArgMatches) -> Result<()> { match matches.subcommand() { - ("location", Some(location_matches)) => { + Some(("location", location_matches)) => { Self::handle_set_bridge_location(location_matches).await } - ("provider", Some(provider_matches)) => { + Some(("provider", provider_matches)) => { Self::handle_set_bridge_provider(provider_matches).await } - ("custom", Some(custom_matches)) => { + Some(("custom", custom_matches)) => { Self::handle_bridge_set_custom_settings(custom_matches).await } - ("state", Some(set_matches)) => Self::handle_set_bridge_state(set_matches).await, + Some(("state", set_matches)) => Self::handle_set_bridge_state(set_matches).await, _ => unreachable!("unhandled command"), } } @@ -222,13 +214,12 @@ impl Bridge { Ok(()) } - async fn handle_set_bridge_location(matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn handle_set_bridge_location(matches: &clap::ArgMatches) -> Result<()> { Self::update_bridge_settings(Some(location::get_constraint_from_args(matches)), None).await } - async fn handle_set_bridge_provider(matches: &clap::ArgMatches<'_>) -> Result<()> { - let providers = - values_t!(matches.values_of("provider"), String).unwrap_or_else(|e| e.exit()); + async fn handle_set_bridge_provider(matches: &clap::ArgMatches) -> Result<()> { + let providers: Vec<String> = matches.values_of_t_or_exit("provider"); let providers = if providers.iter().next().map(String::as_str) == Some("any") { vec![] } else { @@ -277,7 +268,7 @@ impl Bridge { Ok(()) } - async fn handle_set_bridge_state(matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn handle_set_bridge_state(matches: &clap::ArgMatches) -> Result<()> { let state = match matches.value_of("policy").unwrap() { "auto" => BridgeState::Auto, "on" => BridgeState::On, @@ -290,14 +281,11 @@ impl Bridge { Ok(()) } - async fn handle_bridge_set_custom_settings(matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn handle_bridge_set_custom_settings(matches: &clap::ArgMatches) -> Result<()> { if let Some(args) = matches.subcommand_matches("local") { - let local_port = - value_t!(args.value_of("local-port"), u16).unwrap_or_else(|e| e.exit()); - let remote_ip = - value_t!(args.value_of("remote-ip"), IpAddr).unwrap_or_else(|e| e.exit()); - let remote_port = - value_t!(args.value_of("remote-port"), u16).unwrap_or_else(|e| e.exit()); + let local_port = args.value_of_t_or_exit("local-port"); + let remote_ip = args.value_of_t_or_exit("remote-ip"); + let remote_port = args.value_of_t_or_exit("remote-port"); let local_proxy = openvpn::LocalProxySettings { port: local_port, @@ -314,10 +302,8 @@ impl Bridge { ))) .await?; } else if let Some(args) = matches.subcommand_matches("remote") { - let remote_ip = - value_t!(args.value_of("remote-ip"), IpAddr).unwrap_or_else(|e| e.exit()); - let remote_port = - value_t!(args.value_of("remote-port"), u16).unwrap_or_else(|e| e.exit()); + let remote_ip = args.value_of_t_or_exit("remote-ip"); + let remote_port = args.value_of_t_or_exit("remote-port"); let username = args.value_of("username"); let password = args.value_of("password"); @@ -343,12 +329,10 @@ impl Bridge { ))) .await?; } else if let Some(args) = matches.subcommand_matches("shadowsocks") { - let remote_ip = - value_t!(args.value_of("remote-ip"), IpAddr).unwrap_or_else(|e| e.exit()); - let remote_port = - value_t!(args.value_of("remote-port"), u16).unwrap_or_else(|e| e.exit()); - let password = args.value_of("password").unwrap().to_string(); - let cipher = args.value_of("cipher").unwrap().to_string(); + let remote_ip = args.value_of_t_or_exit("remote-ip"); + let remote_port = args.value_of_t_or_exit("remote-port"); + let password = args.value_of_t_or_exit("password"); + let cipher = args.value_of_t_or_exit("cipher"); let proxy = openvpn::ShadowsocksProxySettings { peer: SocketAddr::new(remote_ip, remote_port), diff --git a/mullvad-cli/src/cmds/connect.rs b/mullvad-cli/src/cmds/connect.rs index c93ed8c2e2..a184e38244 100644 --- a/mullvad-cli/src/cmds/connect.rs +++ b/mullvad-cli/src/cmds/connect.rs @@ -10,18 +10,18 @@ impl Command for Connect { "connect" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Command the client to start establishing a VPN tunnel") .arg( - clap::Arg::with_name("wait") + clap::Arg::new("wait") .long("wait") - .short("w") + .short('w') .help("Wait until connected before exiting"), ) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { let mut rpc = new_rpc_client().await?; let receiver_option = if matches.is_present("wait") { diff --git a/mullvad-cli/src/cmds/disconnect.rs b/mullvad-cli/src/cmds/disconnect.rs index 96d5843d20..9ac051ca57 100644 --- a/mullvad-cli/src/cmds/disconnect.rs +++ b/mullvad-cli/src/cmds/disconnect.rs @@ -10,18 +10,18 @@ impl Command for Disconnect { "disconnect" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Command the client to disconnect the VPN tunnel") .arg( - clap::Arg::with_name("wait") + clap::Arg::new("wait") .long("wait") - .short("w") + .short('w') .help("Wait until disconnected before exiting"), ) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { let mut rpc = new_rpc_client().await?; let receiver_option = if matches.is_present("wait") { diff --git a/mullvad-cli/src/cmds/dns.rs b/mullvad-cli/src/cmds/dns.rs index 91562ff798..72869b6c7b 100644 --- a/mullvad-cli/src/cmds/dns.rs +++ b/mullvad-cli/src/cmds/dns.rs @@ -1,7 +1,7 @@ use crate::{new_rpc_client, Command, Result}; use mullvad_management_interface::types; use mullvad_types::settings::{DnsOptions, DnsState}; -use std::convert::TryInto; +use std::{convert::TryInto, net::IpAddr}; pub struct Dns; @@ -11,45 +11,43 @@ impl Command for Dns { "dns" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Configure DNS servers to use when connected") .setting(clap::AppSettings::SubcommandRequiredElseHelp) + .subcommand(clap::App::new("get").about("Display the current DNS settings")) .subcommand( - clap::SubCommand::with_name("get").about("Display the current DNS settings"), - ) - .subcommand( - clap::SubCommand::with_name("set") + clap::App::new("set") .about("Set DNS servers to use") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand( - clap::SubCommand::with_name("default") + clap::App::new("default") .about("Use default DNS servers") .arg( - clap::Arg::with_name("block ads") + clap::Arg::new("block ads") .long("block-ads") .takes_value(false) .help("Block domain names used for ads"), ) .arg( - clap::Arg::with_name("block trackers") + clap::Arg::new("block trackers") .long("block-trackers") .takes_value(false) .help("Block domain names used for tracking"), ) .arg( - clap::Arg::with_name("block malware") + clap::Arg::new("block malware") .long("block-malware") .takes_value(false) .help("Block domains known to be used by malware"), ), ) .subcommand( - clap::SubCommand::with_name("custom") + clap::App::new("custom") .about("Set a list of custom DNS servers") .arg( - clap::Arg::with_name("servers") - .multiple(true) + clap::Arg::new("servers") + .multiple_occurrences(true) .help("One or more IP addresses pointing to DNS resolvers.") .required(true), ), @@ -57,10 +55,10 @@ impl Command for Dns { ) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { match matches.subcommand() { - ("set", Some(matches)) => match matches.subcommand() { - ("default", Some(matches)) => { + Some(("set", matches)) => match matches.subcommand() { + Some(("default", matches)) => { self.set_default( matches.is_present("block ads"), matches.is_present("block trackers"), @@ -68,12 +66,19 @@ impl Command for Dns { ) .await } - ("custom", Some(matches)) => { - self.set_custom(matches.values_of_lossy("servers")).await + Some(("custom", matches)) => { + let servers = match matches.values_of_t::<IpAddr>("servers") { + Ok(servers) => Some(servers), + Err(e) => match e.kind { + clap::ErrorKind::ArgumentNotFound => None, + _ => e.exit(), + }, + }; + self.set_custom(servers).await } _ => unreachable!("No custom-dns server command given"), }, - ("get", _) => self.get().await, + Some(("get", _)) => self.get().await, _ => unreachable!("No custom-dns command given"), } } @@ -102,13 +107,17 @@ impl Dns { Ok(()) } - async fn set_custom(&self, servers: Option<Vec<String>>) -> Result<()> { + async fn set_custom(&self, servers: Option<Vec<IpAddr>>) -> Result<()> { let mut rpc = new_rpc_client().await?; let settings = rpc.get_settings(()).await?.into_inner(); rpc.set_dns_options(types::DnsOptions { state: types::dns_options::DnsState::Custom as i32, custom_options: Some(types::CustomDnsOptions { - addresses: servers.unwrap_or_default(), + addresses: servers + .unwrap_or_default() + .into_iter() + .map(|a| a.to_string()) + .collect(), }), ..settings.tunnel_options.unwrap().dns_options.unwrap() }) diff --git a/mullvad-cli/src/cmds/lan.rs b/mullvad-cli/src/cmds/lan.rs index dd84851f33..bd43f88a6b 100644 --- a/mullvad-cli/src/cmds/lan.rs +++ b/mullvad-cli/src/cmds/lan.rs @@ -1,5 +1,4 @@ use crate::{new_rpc_client, Command, Result}; -use clap::value_t_or_exit; pub struct Lan; @@ -9,28 +8,25 @@ impl Command for Lan { "lan" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Control the allow local network sharing setting") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand( - clap::SubCommand::with_name("set") - .about("Change allow LAN setting") - .arg( - clap::Arg::with_name("policy") - .required(true) - .possible_values(&["allow", "block"]), - ), + clap::App::new("set").about("Change allow LAN setting").arg( + clap::Arg::new("policy") + .required(true) + .possible_values(&["allow", "block"]), + ), ) .subcommand( - clap::SubCommand::with_name("get") - .about("Display the current local network sharing setting"), + clap::App::new("get").about("Display the current local network sharing setting"), ) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { if let Some(set_matches) = matches.subcommand_matches("set") { - let allow_lan = value_t_or_exit!(set_matches.value_of("policy"), String); + let allow_lan = set_matches.value_of("policy").expect("missing policy"); self.set(allow_lan == "allow").await } else if let Some(_matches) = matches.subcommand_matches("get") { self.get().await diff --git a/mullvad-cli/src/cmds/reconnect.rs b/mullvad-cli/src/cmds/reconnect.rs index 87de63144f..c2a577a212 100644 --- a/mullvad-cli/src/cmds/reconnect.rs +++ b/mullvad-cli/src/cmds/reconnect.rs @@ -10,18 +10,18 @@ impl Command for Reconnect { "reconnect" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Command the client to reconnect") .arg( - clap::Arg::with_name("wait") + clap::Arg::new("wait") .long("wait") - .short("w") + .short('w') .help("Wait until reconnected before exiting"), ) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { let mut rpc = new_rpc_client().await?; let receiver_option = if matches.is_present("wait") { diff --git a/mullvad-cli/src/cmds/relay.rs b/mullvad-cli/src/cmds/relay.rs index 28baab3062..8cb9fa111b 100644 --- a/mullvad-cli/src/cmds/relay.rs +++ b/mullvad-cli/src/cmds/relay.rs @@ -1,5 +1,4 @@ use crate::{location, new_rpc_client, Command, Error, Result}; -use clap::{value_t, values_t}; use itertools::Itertools; use std::{ convert::TryFrom, @@ -20,49 +19,49 @@ impl Command for Relay { "relay" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Manage relay and tunnel constraints") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand( - clap::SubCommand::with_name("set") + clap::App::new("set") .about( "Set relay server selection parameters. Such as location and port/protocol", ) .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand( - clap::SubCommand::with_name("custom") + clap::App::new("custom") .about("Set a custom VPN relay") .setting(clap::AppSettings::SubcommandRequiredElseHelp) - .subcommand(clap::SubCommand::with_name("wireguard") + .subcommand(clap::App::new("wireguard") .arg( - clap::Arg::with_name("host") + clap::Arg::new("host") .help("Hostname or IP") .required(true), ) .arg( - clap::Arg::with_name("port") + clap::Arg::new("port") .help("Remote network port") .required(true), ) .arg( - clap::Arg::with_name("peer-pubkey") + clap::Arg::new("peer-pubkey") .help("Base64 encoded peer public key") .required(true), ) .arg( - clap::Arg::with_name("v4-gateway") + clap::Arg::new("v4-gateway") .help("IPv4 gateway address") .required(true), ) .arg( - clap::Arg::with_name("addr") + clap::Arg::new("addr") .help("Local address of wireguard tunnel") .required(true) - .multiple(true), + .multiple_values(true), ) .arg( - clap::Arg::with_name("protocol") + clap::Arg::new("protocol") .help("Transport protocol. If TCP is selected, traffic is \ sent over TCP using a udp-over-tcp proxy") .long("protocol") @@ -70,35 +69,35 @@ impl Command for Relay { .possible_values(&["udp", "tcp"]), ) .arg( - clap::Arg::with_name("v6-gateway") + clap::Arg::new("v6-gateway") .help("IPv6 gateway address") .long("v6-gateway") .takes_value(true), ) ) - .subcommand(clap::SubCommand::with_name("openvpn") + .subcommand(clap::App::new("openvpn") .arg( - clap::Arg::with_name("host") + clap::Arg::new("host") .help("Hostname or IP") .required(true), ) .arg( - clap::Arg::with_name("port") + clap::Arg::new("port") .help("Remote network port") .required(true), ) .arg( - clap::Arg::with_name("username") + clap::Arg::new("username") .help("Username to be used with the OpenVpn relay") .required(true), ) .arg( - clap::Arg::with_name("password") + clap::Arg::new("password") .help("Password to be used with the OpenVpn relay") .required(true), ) .arg( - clap::Arg::with_name("protocol") + clap::Arg::new("protocol") .help("Transport protocol") .long("protocol") .default_value("udp") @@ -112,42 +111,42 @@ impl Command for Relay { command to show available alternatives.") ) .subcommand( - clap::SubCommand::with_name("hostname") + clap::App::new("hostname") .about("Set the exact relay to use via its hostname. Shortcut for \ 'location <country> <city> <hostname>'.") .arg( - clap::Arg::with_name("hostname") + clap::Arg::new("hostname") .help("The hostname") .required(true), ), ) .subcommand( - clap::SubCommand::with_name("provider") + clap::App::new("provider") .about("Set hosting provider(s) to select relays from. The 'list' \ command shows the available relays and their providers.") .arg( - clap::Arg::with_name("provider") + clap::Arg::new("provider") .help("The hosting provider(s) to use, or 'any' for no preference.") - .multiple(true) + .multiple_values(true) .required(true) ) ) .subcommand( - clap::SubCommand::with_name("tunnel") + clap::App::new("tunnel") .about("Set tunnel protocol-specific constraints.") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand( - clap::SubCommand::with_name("openvpn") + clap::App::new("openvpn") .about("Set OpenVPN-specific constraints") .setting(clap::AppSettings::ArgRequiredElseHelp) .arg( - clap::Arg::with_name("port") + clap::Arg::new("port") .help("Port to use. Either 'any' or a specific port") .long("port") .takes_value(true), ) .arg( - clap::Arg::with_name("transport protocol") + clap::Arg::new("transport protocol") .help("Transport protocol") .long("protocol") .possible_values(&["any", "udp", "tcp"]) @@ -155,17 +154,17 @@ impl Command for Relay { ) ) .subcommand( - clap::SubCommand::with_name("wireguard") + clap::App::new("wireguard") .about("Set WireGuard-specific constraints") .setting(clap::AppSettings::ArgRequiredElseHelp) .arg( - clap::Arg::with_name("port") + clap::Arg::new("port") .help("Port to use. Either 'any' or a specific port") .long("port") .takes_value(true), ) .arg( - clap::Arg::with_name("transport protocol") + clap::Arg::new("transport protocol") .help("Transport protocol. If TCP is selected, traffic is \ sent over TCP using a udp-over-tcp proxy") .long("protocol") @@ -173,13 +172,13 @@ impl Command for Relay { .takes_value(true), ) .arg( - clap::Arg::with_name("ip version") + clap::Arg::new("ip version") .long("ipv") .possible_values(&["any", "4", "6"]) .takes_value(true), ) .arg( - clap::Arg::with_name("entry location") + clap::Arg::new("entry location") .help("Entry endpoint to use. This can be 'any', 'none', or \ any location that is valid with 'set location', \ such as 'se got'.") @@ -189,27 +188,27 @@ impl Command for Relay { ) ) ) - .subcommand(clap::SubCommand::with_name("tunnel-protocol") + .subcommand(clap::App::new("tunnel-protocol") .about("Set tunnel protocol") .arg( - clap::Arg::with_name("tunnel protocol") + clap::Arg::new("tunnel protocol") .required(true) .index(1) .possible_values(&["any", "wireguard", "openvpn", ]), ) ), ) - .subcommand(clap::SubCommand::with_name("get")) + .subcommand(clap::App::new("get")) .subcommand( - clap::SubCommand::with_name("list").about("List available countries and cities"), + clap::App::new("list").about("List available countries and cities"), ) .subcommand( - clap::SubCommand::with_name("update") + clap::App::new("update") .about("Update the list of available countries and cities"), ) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { if let Some(set_matches) = matches.subcommand_matches("set") { self.set(set_matches).await } else if matches.subcommand_matches("get").is_some() { @@ -234,7 +233,7 @@ impl Relay { Ok(()) } - async fn set(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn set(&self, matches: &clap::ArgMatches) -> Result<()> { if let Some(custom_matches) = matches.subcommand_matches("custom") { self.set_custom(custom_matches).await } else if let Some(location_matches) = matches.subcommand_matches("location") { @@ -258,11 +257,11 @@ impl Relay { } } - async fn set_custom(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn set_custom(&self, matches: &clap::ArgMatches) -> Result<()> { let custom_endpoint = match matches.subcommand() { - ("openvpn", Some(openvpn_matches)) => Self::read_custom_openvpn_relay(openvpn_matches), - ("wireguard", Some(wg_matches)) => Self::read_custom_wireguard_relay(wg_matches), - (_unknown_tunnel, _) => unreachable!("No set relay command given"), + Some(("openvpn", openvpn_matches)) => Self::read_custom_openvpn_relay(openvpn_matches), + Some(("wireguard", wg_matches)) => Self::read_custom_wireguard_relay(wg_matches), + _ => unreachable!("No set relay command given"), }; self.update_constraints(types::RelaySettingsUpdate { @@ -271,12 +270,12 @@ impl Relay { .await } - fn read_custom_openvpn_relay(matches: &clap::ArgMatches<'_>) -> types::CustomRelaySettings { - let host = value_t!(matches.value_of("host"), String).unwrap_or_else(|e| e.exit()); - let port = value_t!(matches.value_of("port"), u16).unwrap_or_else(|e| e.exit()); - let username = value_t!(matches.value_of("username"), String).unwrap_or_else(|e| e.exit()); - let password = value_t!(matches.value_of("password"), String).unwrap_or_else(|e| e.exit()); - let protocol = value_t!(matches.value_of("protocol"), String).unwrap_or_else(|e| e.exit()); + fn read_custom_openvpn_relay(matches: &clap::ArgMatches) -> types::CustomRelaySettings { + let host = matches.value_of_t_or_exit("host"); + let port = matches.value_of_t_or_exit("port"); + let username = matches.value_of_t_or_exit("username"); + let password = matches.value_of_t_or_exit("password"); + let protocol: String = matches.value_of_t_or_exit("protocol"); let protocol = Self::validate_transport_protocol(&protocol); @@ -296,24 +295,22 @@ impl Relay { } } - fn read_custom_wireguard_relay(matches: &clap::ArgMatches<'_>) -> types::CustomRelaySettings { + fn read_custom_wireguard_relay(matches: &clap::ArgMatches) -> types::CustomRelaySettings { use types::connection_config::wireguard_config; - let host = value_t!(matches.value_of("host"), String).unwrap_or_else(|e| e.exit()); - let port = value_t!(matches.value_of("port"), u16).unwrap_or_else(|e| e.exit()); - let addresses = values_t!(matches.values_of("addr"), IpAddr).unwrap_or_else(|e| e.exit()); - let peer_key_str = - value_t!(matches.value_of("peer-pubkey"), String).unwrap_or_else(|e| e.exit()); - let ipv4_gateway = - value_t!(matches.value_of("v4-gateway"), Ipv4Addr).unwrap_or_else(|e| e.exit()); - let ipv6_gateway = match value_t!(matches.value_of("v6-gateway"), Ipv6Addr) { + let host = matches.value_of_t_or_exit("host"); + let port = matches.value_of_t_or_exit("port"); + let addresses: Vec<IpAddr> = matches.values_of_t_or_exit("addr"); + let peer_key_str: String = matches.value_of_t_or_exit("peer-pubkey"); + let ipv4_gateway: Ipv4Addr = matches.value_of_t_or_exit("v4-gateway"); + let ipv6_gateway = match matches.value_of_t::<Ipv6Addr>("v6-gateway") { Ok(gateway) => Some(gateway), Err(e) => match e.kind { clap::ErrorKind::ArgumentNotFound => None, _ => e.exit(), }, }; - let protocol = value_t!(matches.value_of("protocol"), String).unwrap_or_else(|e| e.exit()); + let protocol: String = matches.value_of_t_or_exit("protocol"); let protocol = Self::validate_transport_protocol(&protocol); let mut private_key_str = String::new(); println!("Reading private key from standard input"); @@ -380,15 +377,15 @@ impl Relay { match protocol { "udp" => types::TransportProtocol::Udp, "tcp" => types::TransportProtocol::Tcp, - _ => clap::Error::with_description( - "invalid transport protocol", + _ => clap::Error::raw( clap::ErrorKind::ValueValidation, + "invalid transport protocol", ) .exit(), } } - async fn set_hostname(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn set_hostname(&self, matches: &clap::ArgMatches) -> Result<()> { let hostname = matches.value_of("hostname").unwrap(); let countries = Self::get_filtered_relays().await?; @@ -425,15 +422,11 @@ impl Relay { }) .await } else { - clap::Error::with_description( - "No matching server found", - clap::ErrorKind::ValueValidation, - ) - .exit() + clap::Error::raw(clap::ErrorKind::ValueValidation, "No matching server found").exit() } } - async fn set_location(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn set_location(&self, matches: &clap::ArgMatches) -> Result<()> { let location_constraint = location::get_constraint_from_args(matches); let mut found = false; @@ -490,10 +483,8 @@ impl Relay { .await } - async fn set_providers(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { - let providers = - values_t!(matches.values_of("provider"), String).unwrap_or_else(|e| e.exit()); - + async fn set_providers(&self, matches: &clap::ArgMatches) -> Result<()> { + let providers: Vec<String> = matches.values_of_t_or_exit("provider"); let providers = if providers.iter().next().map(String::as_str) == Some("any") { vec![] } else { @@ -511,7 +502,7 @@ impl Relay { .await } - async fn set_openvpn_constraints(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn set_openvpn_constraints(&self, matches: &clap::ArgMatches) -> Result<()> { let mut openvpn_constraints = { let mut rpc = new_rpc_client().await?; self.get_openvpn_constraints(&mut rpc).await? @@ -552,7 +543,7 @@ impl Relay { } } - async fn set_wireguard_constraints(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn set_wireguard_constraints(&self, matches: &clap::ArgMatches) -> Result<()> { let mut rpc = new_rpc_client().await?; let mut wireguard_constraints = self.get_wireguard_constraints(&mut rpc).await?; @@ -606,7 +597,7 @@ impl Relay { } } - async fn set_tunnel_protocol(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn set_tunnel_protocol(&self, matches: &clap::ArgMatches) -> Result<()> { let tunnel_type = match matches.value_of("tunnel protocol").unwrap() { "wireguard" => Some(types::TunnelType::Wireguard), "openvpn" => Some(types::TunnelType::Openvpn), @@ -775,7 +766,7 @@ fn parse_entry_location_constraint<'a, T: Iterator<Item = &'a str>>( } fn parse_transport_port( - matches: &clap::ArgMatches<'_>, + matches: &clap::ArgMatches, current_constraint: &mut Option<types::TransportPort>, ) -> Result<Option<types::TransportPort>> { let protocol = match matches.value_of("transport protocol") { diff --git a/mullvad-cli/src/cmds/reset.rs b/mullvad-cli/src/cmds/reset.rs index 963f62e005..c4cd3a8625 100644 --- a/mullvad-cli/src/cmds/reset.rs +++ b/mullvad-cli/src/cmds/reset.rs @@ -8,11 +8,11 @@ impl Command for Reset { "factory-reset" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()).about("Reset settings, caches and logs") + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()).about("Reset settings, caches and logs") } - async fn run(&self, _: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, _: &clap::ArgMatches) -> Result<()> { let mut rpc = new_rpc_client().await?; if Self::receive_confirmation() { rpc.factory_reset(()) diff --git a/mullvad-cli/src/cmds/split_tunnel/linux.rs b/mullvad-cli/src/cmds/split_tunnel/linux.rs index f9945d14d6..3480f27fb0 100644 --- a/mullvad-cli/src/cmds/split_tunnel/linux.rs +++ b/mullvad-cli/src/cmds/split_tunnel/linux.rs @@ -1,5 +1,4 @@ use crate::{new_rpc_client, Command, Result}; -use clap::value_t_or_exit; pub struct SplitTunnel; @@ -9,8 +8,8 @@ impl Command for SplitTunnel { "split-tunnel" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about( "Manage split tunneling. To launch applications outside \ the tunnel, use the program 'mullvad-exclude'.", @@ -19,55 +18,51 @@ impl Command for SplitTunnel { .subcommand(create_pid_subcommand()) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { match matches.subcommand() { - ("pid", Some(pid_matches)) => Self::handle_pid_cmd(pid_matches).await, + Some(("pid", pid_matches)) => Self::handle_pid_cmd(pid_matches).await, _ => unreachable!("unhandled comand"), } } } -fn create_pid_subcommand() -> clap::App<'static, 'static> { - clap::SubCommand::with_name("pid") +fn create_pid_subcommand() -> clap::App<'static> { + clap::App::new("pid") .about("Manage processes to exclude from the tunnel") .setting(clap::AppSettings::SubcommandRequiredElseHelp) - .subcommand( - clap::SubCommand::with_name("add").arg(clap::Arg::with_name("pid").required(true)), - ) - .subcommand( - clap::SubCommand::with_name("delete").arg(clap::Arg::with_name("pid").required(true)), - ) - .subcommand(clap::SubCommand::with_name("clear")) - .subcommand(clap::SubCommand::with_name("list")) + .subcommand(clap::App::new("add").arg(clap::Arg::new("pid").required(true))) + .subcommand(clap::App::new("delete").arg(clap::Arg::new("pid").required(true))) + .subcommand(clap::App::new("clear")) + .subcommand(clap::App::new("list")) } impl SplitTunnel { - async fn handle_pid_cmd(matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn handle_pid_cmd(matches: &clap::ArgMatches) -> Result<()> { match matches.subcommand() { - ("add", Some(matches)) => { - let pid = value_t_or_exit!(matches.value_of("pid"), i32); + Some(("add", matches)) => { + let pid: i32 = matches.value_of_t_or_exit("pid"); new_rpc_client() .await? .add_split_tunnel_process(pid) .await?; Ok(()) } - ("delete", Some(matches)) => { - let pid = value_t_or_exit!(matches.value_of("pid"), i32); + Some(("delete", matches)) => { + let pid: i32 = matches.value_of_t_or_exit("pid"); new_rpc_client() .await? .remove_split_tunnel_process(pid) .await?; Ok(()) } - ("clear", Some(_)) => { + Some(("clear", _)) => { new_rpc_client() .await? .clear_split_tunnel_processes(()) .await?; Ok(()) } - ("list", Some(_)) => { + Some(("list", _)) => { let mut pids_stream = new_rpc_client() .await? .get_split_tunnel_processes(()) diff --git a/mullvad-cli/src/cmds/split_tunnel/windows.rs b/mullvad-cli/src/cmds/split_tunnel/windows.rs index 402186a77c..0bc8d468bc 100644 --- a/mullvad-cli/src/cmds/split_tunnel/windows.rs +++ b/mullvad-cli/src/cmds/split_tunnel/windows.rs @@ -1,5 +1,4 @@ use crate::{new_rpc_client, Command, Result}; -use clap::value_t_or_exit; pub struct SplitTunnel; @@ -9,29 +8,29 @@ impl Command for SplitTunnel { "split-tunnel" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Set options for applications to exclude from the tunnel") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand(create_app_subcommand()) .subcommand( - clap::SubCommand::with_name("set") + clap::App::new("set") .about("Enable or disable split tunnel") .arg( - clap::Arg::with_name("policy") + clap::Arg::new("policy") .required(true) .possible_values(&["on", "off"]), ), ) - .subcommand(clap::SubCommand::with_name("get").about("Display the split tunnel status")) + .subcommand(clap::App::new("get").about("Display the split tunnel status")) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { match matches.subcommand() { - ("app", Some(matches)) => Self::handle_app_subcommand(matches).await, - ("get", _) => self.get().await, - ("set", Some(matches)) => { - let enabled = value_t_or_exit!(matches.value_of("policy"), String); + Some(("app", matches)) => Self::handle_app_subcommand(matches).await, + Some(("get", _)) => self.get().await, + Some(("set", matches)) => { + let enabled = matches.value_of("policy").expect("missing policy"); self.set(enabled == "on").await } _ => { @@ -41,24 +40,20 @@ impl Command for SplitTunnel { } } -fn create_app_subcommand() -> clap::App<'static, 'static> { - clap::SubCommand::with_name("app") +fn create_app_subcommand() -> clap::App<'static> { + clap::App::new("app") .about("Manage applications to exclude from the tunnel") .setting(clap::AppSettings::SubcommandRequiredElseHelp) - .subcommand(clap::SubCommand::with_name("list")) - .subcommand( - clap::SubCommand::with_name("add").arg(clap::Arg::with_name("path").required(true)), - ) - .subcommand( - clap::SubCommand::with_name("remove").arg(clap::Arg::with_name("path").required(true)), - ) - .subcommand(clap::SubCommand::with_name("clear")) + .subcommand(clap::App::new("list")) + .subcommand(clap::App::new("add").arg(clap::Arg::new("path").required(true))) + .subcommand(clap::App::new("remove").arg(clap::Arg::new("path").required(true))) + .subcommand(clap::App::new("clear")) } impl SplitTunnel { - async fn handle_app_subcommand(matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn handle_app_subcommand(matches: &clap::ArgMatches) -> Result<()> { match matches.subcommand() { - ("list", Some(_)) => { + Some(("list", _)) => { let paths = new_rpc_client() .await? .get_settings(()) @@ -75,20 +70,20 @@ impl SplitTunnel { Ok(()) } - ("add", Some(matches)) => { - let path = value_t_or_exit!(matches.value_of("path"), String); + Some(("add", matches)) => { + let path: String = matches.value_of_t_or_exit("path"); new_rpc_client().await?.add_split_tunnel_app(path).await?; Ok(()) } - ("remove", Some(matches)) => { - let path = value_t_or_exit!(matches.value_of("path"), String); + Some(("remove", matches)) => { + let path: String = matches.value_of_t_or_exit("path"); new_rpc_client() .await? .remove_split_tunnel_app(path) .await?; Ok(()) } - ("clear", Some(_)) => { + Some(("clear", _)) => { new_rpc_client().await?.clear_split_tunnel_apps(()).await?; Ok(()) } diff --git a/mullvad-cli/src/cmds/status.rs b/mullvad-cli/src/cmds/status.rs index f4e943cb3c..8c4a929c30 100644 --- a/mullvad-cli/src/cmds/status.rs +++ b/mullvad-cli/src/cmds/status.rs @@ -11,27 +11,27 @@ impl Command for Status { "status" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("View the state of the VPN tunnel") .arg( - clap::Arg::with_name("location") + clap::Arg::new("location") .long("location") - .short("l") + .short('l') .help("Prints the current location and IP. Based on GeoIP lookups"), ) .subcommand( - clap::SubCommand::with_name("listen") + clap::App::new("listen") .about("Listen for VPN tunnel state changes") .arg( - clap::Arg::with_name("verbose") - .short("v") + clap::Arg::new("verbose") + .short('v') .help("Enables verbose output"), ), ) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { let mut rpc = new_rpc_client().await?; let state = rpc.get_tunnel_state(()).await?.into_inner(); diff --git a/mullvad-cli/src/cmds/tunnel.rs b/mullvad-cli/src/cmds/tunnel.rs index 6d7be54514..f3b218648e 100644 --- a/mullvad-cli/src/cmds/tunnel.rs +++ b/mullvad-cli/src/cmds/tunnel.rs @@ -1,5 +1,4 @@ use crate::{format::print_keygen_event, new_rpc_client, Command, Error, Result}; -use clap::value_t; use mullvad_management_interface::types::{self, Timestamp, TunnelOptions}; use mullvad_types::wireguard::DEFAULT_ROTATION_INTERVAL; use std::{convert::TryFrom, time::Duration}; @@ -12,8 +11,8 @@ impl Command for Tunnel { "tunnel" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Manage tunnel specific options") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand(create_openvpn_subcommand()) @@ -21,11 +20,11 @@ impl Command for Tunnel { .subcommand(create_ipv6_subcommand()) } - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, matches: &clap::ArgMatches) -> Result<()> { match matches.subcommand() { - ("openvpn", Some(openvpn_matches)) => Self::handle_openvpn_cmd(openvpn_matches).await, - ("wireguard", Some(wg_matches)) => Self::handle_wireguard_cmd(wg_matches).await, - ("ipv6", Some(ipv6_matches)) => Self::handle_ipv6_cmd(ipv6_matches).await, + Some(("openvpn", openvpn_matches)) => Self::handle_openvpn_cmd(openvpn_matches).await, + Some(("wireguard", wg_matches)) => Self::handle_wireguard_cmd(wg_matches).await, + Some(("ipv6", ipv6_matches)) => Self::handle_ipv6_cmd(ipv6_matches).await, _ => { unreachable!("unhandled comand"); } @@ -33,8 +32,8 @@ impl Command for Tunnel { } } -fn create_wireguard_subcommand() -> clap::App<'static, 'static> { - let subcmd = clap::SubCommand::with_name("wireguard") +fn create_wireguard_subcommand() -> clap::App<'static> { + let subcmd = clap::App::new("wireguard") .about("Manage options for Wireguard tunnels") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand(create_wireguard_mtu_subcommand()) @@ -49,35 +48,33 @@ fn create_wireguard_subcommand() -> clap::App<'static, 'static> { } } -fn create_wireguard_mtu_subcommand() -> clap::App<'static, 'static> { - clap::SubCommand::with_name("mtu") +fn create_wireguard_mtu_subcommand() -> clap::App<'static> { + clap::App::new("mtu") .about("Configure the MTU of the wireguard tunnel") .setting(clap::AppSettings::SubcommandRequiredElseHelp) - .subcommand(clap::SubCommand::with_name("get")) - .subcommand(clap::SubCommand::with_name("unset")) - .subcommand( - clap::SubCommand::with_name("set").arg(clap::Arg::with_name("mtu").required(true)), - ) + .subcommand(clap::App::new("get")) + .subcommand(clap::App::new("unset")) + .subcommand(clap::App::new("set").arg(clap::Arg::new("mtu").required(true))) } -fn create_wireguard_keys_subcommand() -> clap::App<'static, 'static> { - clap::SubCommand::with_name("key") +fn create_wireguard_keys_subcommand() -> clap::App<'static> { + clap::App::new("key") .about("Manage your wireguard key") .setting(clap::AppSettings::SubcommandRequiredElseHelp) - .subcommand(clap::SubCommand::with_name("check")) - .subcommand(clap::SubCommand::with_name("regenerate")) + .subcommand(clap::App::new("check")) + .subcommand(clap::App::new("regenerate")) .subcommand(create_wireguard_keys_rotation_interval_subcommand()) } #[cfg(windows)] -fn create_wireguard_use_wg_nt_subcommand() -> clap::App<'static, 'static> { - clap::SubCommand::with_name("use-wireguard-nt") +fn create_wireguard_use_wg_nt_subcommand() -> clap::App<'static> { + clap::App::new("use-wireguard-nt") .about("Enable or disable wireguard-nt") .setting(clap::AppSettings::SubcommandRequiredElseHelp) - .subcommand(clap::SubCommand::with_name("get")) + .subcommand(clap::App::new("get")) .subcommand( - clap::SubCommand::with_name("set").arg( - clap::Arg::with_name("policy") + clap::App::new("set").arg( + clap::Arg::new("policy") .required(true) .takes_value(true) .possible_values(&["on", "off"]), @@ -85,42 +82,38 @@ fn create_wireguard_use_wg_nt_subcommand() -> clap::App<'static, 'static> { ) } -fn create_wireguard_keys_rotation_interval_subcommand() -> clap::App<'static, 'static> { - clap::SubCommand::with_name("rotation-interval") +fn create_wireguard_keys_rotation_interval_subcommand() -> clap::App<'static> { + clap::App::new("rotation-interval") .about("Manage automatic key rotation (given in hours)") .setting(clap::AppSettings::SubcommandRequiredElseHelp) - .subcommand(clap::SubCommand::with_name("get")) - .subcommand(clap::SubCommand::with_name("reset").about("Use the default rotation interval")) - .subcommand( - clap::SubCommand::with_name("set").arg(clap::Arg::with_name("interval").required(true)), - ) + .subcommand(clap::App::new("get")) + .subcommand(clap::App::new("reset").about("Use the default rotation interval")) + .subcommand(clap::App::new("set").arg(clap::Arg::new("interval").required(true))) } -fn create_openvpn_subcommand() -> clap::App<'static, 'static> { - clap::SubCommand::with_name("openvpn") +fn create_openvpn_subcommand() -> clap::App<'static> { + clap::App::new("openvpn") .about("Manage options for OpenVPN tunnels") .setting(clap::AppSettings::SubcommandRequiredElseHelp) .subcommand(create_openvpn_mssfix_subcommand()) } -fn create_openvpn_mssfix_subcommand() -> clap::App<'static, 'static> { - clap::SubCommand::with_name("mssfix") +fn create_openvpn_mssfix_subcommand() -> clap::App<'static> { + clap::App::new("mssfix") .about("Configure the optional mssfix parameter") .setting(clap::AppSettings::SubcommandRequiredElseHelp) - .subcommand(clap::SubCommand::with_name("get")) - .subcommand(clap::SubCommand::with_name("unset")) - .subcommand( - clap::SubCommand::with_name("set").arg(clap::Arg::with_name("mssfix").required(true)), - ) + .subcommand(clap::App::new("get")) + .subcommand(clap::App::new("unset")) + .subcommand(clap::App::new("set").arg(clap::Arg::new("mssfix").required(true))) } -fn create_ipv6_subcommand() -> clap::App<'static, 'static> { - clap::SubCommand::with_name("ipv6") +fn create_ipv6_subcommand() -> clap::App<'static> { + clap::App::new("ipv6") .setting(clap::AppSettings::SubcommandRequiredElseHelp) - .subcommand(clap::SubCommand::with_name("get")) + .subcommand(clap::App::new("get")) .subcommand( - clap::SubCommand::with_name("set").arg( - clap::Arg::with_name("policy") + clap::App::new("set").arg( + clap::Arg::new("policy") .required(true) .takes_value(true) .possible_values(&["on", "off"]), @@ -129,51 +122,51 @@ fn create_ipv6_subcommand() -> clap::App<'static, 'static> { } impl Tunnel { - async fn handle_openvpn_cmd(matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn handle_openvpn_cmd(matches: &clap::ArgMatches) -> Result<()> { match matches.subcommand() { - ("mssfix", Some(mssfix_matches)) => { + Some(("mssfix", mssfix_matches)) => { Self::handle_openvpn_mssfix_cmd(mssfix_matches).await } _ => unreachable!("unhandled command"), } } - async fn handle_openvpn_mssfix_cmd(matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn handle_openvpn_mssfix_cmd(matches: &clap::ArgMatches) -> Result<()> { match matches.subcommand() { - ("get", Some(_)) => Self::process_openvpn_mssfix_get().await, - ("unset", Some(_)) => Self::process_openvpn_mssfix_unset().await, - ("set", Some(set_matches)) => Self::process_openvpn_mssfix_set(set_matches).await, + Some(("get", _)) => Self::process_openvpn_mssfix_get().await, + Some(("unset", _)) => Self::process_openvpn_mssfix_unset().await, + Some(("set", set_matches)) => Self::process_openvpn_mssfix_set(set_matches).await, _ => unreachable!("unhandled command"), } } - async fn handle_wireguard_cmd(matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn handle_wireguard_cmd(matches: &clap::ArgMatches) -> Result<()> { match matches.subcommand() { - ("mtu", Some(matches)) => match matches.subcommand() { - ("get", _) => Self::process_wireguard_mtu_get().await, - ("set", Some(matches)) => Self::process_wireguard_mtu_set(matches).await, - ("unset", _) => Self::process_wireguard_mtu_unset().await, + Some(("mtu", matches)) => match matches.subcommand() { + Some(("get", _)) => Self::process_wireguard_mtu_get().await, + Some(("set", matches)) => Self::process_wireguard_mtu_set(matches).await, + Some(("unset", _)) => Self::process_wireguard_mtu_unset().await, _ => unreachable!("unhandled command"), }, - ("key", Some(matches)) => match matches.subcommand() { - ("check", _) => Self::process_wireguard_key_check().await, - ("regenerate", _) => Self::process_wireguard_key_generate().await, - ("rotation-interval", Some(matches)) => match matches.subcommand() { - ("get", _) => Self::process_wireguard_rotation_interval_get().await, - ("set", Some(matches)) => { + Some(("key", matches)) => match matches.subcommand() { + Some(("check", _)) => Self::process_wireguard_key_check().await, + Some(("regenerate", _)) => Self::process_wireguard_key_generate().await, + Some(("rotation-interval", matches)) => match matches.subcommand() { + Some(("get", _)) => Self::process_wireguard_rotation_interval_get().await, + Some(("set", matches)) => { Self::process_wireguard_rotation_interval_set(matches).await } - ("reset", _) => Self::process_wireguard_rotation_interval_reset().await, + Some(("reset", _)) => Self::process_wireguard_rotation_interval_reset().await, _ => unreachable!("unhandled command"), }, _ => unreachable!("unhandled command"), }, #[cfg(windows)] - ("use-wireguard-nt", Some(matches)) => match matches.subcommand() { - ("get", _) => Self::process_wireguard_use_wg_nt_get().await, - ("set", Some(matches)) => Self::process_wireguard_use_wg_nt_set(matches).await, + Some(("use-wireguard-nt", matches)) => match matches.subcommand() { + Some(("get", _)) => Self::process_wireguard_use_wg_nt_get().await, + Some(("set", matches)) => Self::process_wireguard_use_wg_nt_set(matches).await, _ => unreachable!("unhandled command"), }, @@ -195,8 +188,8 @@ impl Tunnel { Ok(()) } - async fn process_wireguard_mtu_set(matches: &clap::ArgMatches<'_>) -> Result<()> { - let mtu = value_t!(matches.value_of("mtu"), u16).unwrap_or_else(|e| e.exit()); + async fn process_wireguard_mtu_set(matches: &clap::ArgMatches) -> Result<()> { + let mtu = matches.value_of_t_or_exit::<u16>("mtu"); let mut rpc = new_rpc_client().await?; rpc.set_wireguard_mtu(mtu as u32).await?; println!("Wireguard MTU has been updated"); @@ -222,7 +215,7 @@ impl Tunnel { } #[cfg(windows)] - async fn process_wireguard_use_wg_nt_set(matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn process_wireguard_use_wg_nt_set(matches: &clap::ArgMatches) -> Result<()> { let new_state = matches.value_of("policy").unwrap() == "on"; let mut rpc = new_rpc_client().await?; rpc.set_use_wireguard_nt(new_state).await?; @@ -285,9 +278,8 @@ impl Tunnel { Ok(()) } - async fn process_wireguard_rotation_interval_set(matches: &clap::ArgMatches<'_>) -> Result<()> { - let rotate_interval = - value_t!(matches.value_of("interval"), u64).unwrap_or_else(|e| e.exit()); + async fn process_wireguard_rotation_interval_set(matches: &clap::ArgMatches) -> Result<()> { + let rotate_interval = matches.value_of_t_or_exit::<u64>("interval"); let mut rpc = new_rpc_client().await?; rpc.set_wireguard_rotation_interval(types::Duration::from(Duration::from_secs( 60 * 60 * rotate_interval, @@ -307,7 +299,7 @@ impl Tunnel { Ok(()) } - async fn handle_ipv6_cmd(matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn handle_ipv6_cmd(matches: &clap::ArgMatches) -> Result<()> { if matches.subcommand_matches("get").is_some() { Self::process_ipv6_get().await } else if let Some(m) = matches.subcommand_matches("set") { @@ -348,8 +340,8 @@ impl Tunnel { Ok(()) } - async fn process_openvpn_mssfix_set(matches: &clap::ArgMatches<'_>) -> Result<()> { - let new_value = value_t!(matches.value_of("mssfix"), u16).unwrap_or_else(|e| e.exit()); + async fn process_openvpn_mssfix_set(matches: &clap::ArgMatches) -> Result<()> { + let new_value = matches.value_of_t_or_exit::<u16>("mssfix"); let mut rpc = new_rpc_client().await?; rpc.set_openvpn_mssfix(new_value as u32).await?; println!("mssfix parameter has been updated"); @@ -369,7 +361,7 @@ impl Tunnel { Ok(()) } - async fn process_ipv6_set(matches: &clap::ArgMatches<'_>) -> Result<()> { + async fn process_ipv6_set(matches: &clap::ArgMatches) -> Result<()> { let enabled = matches.value_of("policy").unwrap() == "on"; let mut rpc = new_rpc_client().await?; diff --git a/mullvad-cli/src/cmds/version.rs b/mullvad-cli/src/cmds/version.rs index 08944f921b..cec13834da 100644 --- a/mullvad-cli/src/cmds/version.rs +++ b/mullvad-cli/src/cmds/version.rs @@ -8,12 +8,12 @@ impl Command for Version { "version" } - fn clap_subcommand(&self) -> clap::App<'static, 'static> { - clap::SubCommand::with_name(self.name()) + fn clap_subcommand(&self) -> clap::App<'static> { + clap::App::new(self.name()) .about("Shows current version, and the currently supported versions") } - async fn run(&self, _: &clap::ArgMatches<'_>) -> Result<()> { + async fn run(&self, _: &clap::ArgMatches) -> Result<()> { let mut rpc = new_rpc_client().await?; let current_version = rpc .get_current_version(()) diff --git a/mullvad-cli/src/location.rs b/mullvad-cli/src/location.rs index e4719f7d37..2fff68998c 100644 --- a/mullvad-cli/src/location.rs +++ b/mullvad-cli/src/location.rs @@ -1,28 +1,24 @@ use mullvad_management_interface::types::RelayLocation; -pub fn get_subcommand() -> clap::App<'static, 'static> { - clap::SubCommand::with_name("location") +pub fn get_subcommand() -> clap::App<'static> { + clap::App::new("location") .arg( - clap::Arg::with_name("country") + clap::Arg::new("country") .help("The two letter country code, or 'any' for no preference.") .required(true) .index(1) .validator(country_code_validator), ) .arg( - clap::Arg::with_name("city") + clap::Arg::new("city") .help("The three letter city code") .index(2) .validator(city_code_validator), ) - .arg( - clap::Arg::with_name("hostname") - .help("The hostname") - .index(3), - ) + .arg(clap::Arg::new("hostname").help("The hostname").index(3)) } -pub fn get_constraint_from_args(matches: &clap::ArgMatches<'_>) -> RelayLocation { +pub fn get_constraint_from_args(matches: &clap::ArgMatches) -> RelayLocation { let country = matches.value_of("country").unwrap(); let city = matches.value_of("city"); let hostname = matches.value_of("hostname"); @@ -41,9 +37,9 @@ pub fn get_constraint<T: AsRef<str>>( match (country_original, city, hostname) { ("any", None, None) => RelayLocation::default(), - ("any", ..) => clap::Error::with_description( - "City can't be given when selecting 'any' country", + ("any", ..) => clap::Error::raw( clap::ErrorKind::InvalidValue, + "City can't be given when selecting 'any' country", ) .exit(), (_, None, None) => RelayLocation { @@ -60,24 +56,24 @@ pub fn get_constraint<T: AsRef<str>>( city, hostname, }, - (..) => clap::Error::with_description( - "Invalid country, city and hostname combination given", + (..) => clap::Error::raw( clap::ErrorKind::InvalidValue, + "Invalid country, city and hostname combination given", ) .exit(), } } -pub fn country_code_validator<T: AsRef<str>>(code: T) -> std::result::Result<(), String> { - if code.as_ref().len() == 2 || code.as_ref() == "any" { +pub fn country_code_validator(code: &str) -> std::result::Result<(), String> { + if code.len() == 2 || code == "any" { Ok(()) } else { Err(String::from("Country codes must be two letters, or 'any'.")) } } -pub fn city_code_validator<T: AsRef<str>>(code: T) -> std::result::Result<(), String> { - if code.as_ref().len() == 3 { +pub fn city_code_validator(code: &str) -> std::result::Result<(), String> { + if code.len() == 3 { Ok(()) } else { Err(String::from("City codes must be three letters")) diff --git a/mullvad-cli/src/main.rs b/mullvad-cli/src/main.rs index 766fb43bad..55a195cdb8 100644 --- a/mullvad-cli/src/main.rs +++ b/mullvad-cli/src/main.rs @@ -1,6 +1,8 @@ #![deny(rust_2018_idioms)] use clap::{crate_authors, crate_description}; +#[cfg(all(unix, not(target_os = "android")))] +use clap_complete::{generator::generate_to, Shell}; use mullvad_management_interface::async_trait; use std::{collections::HashMap, io}; use talpid_types::ErrorExt; @@ -43,6 +45,10 @@ pub enum Error { #[error(display = "Failed to listen for status updates")] StatusListenerFailed, + + //#[cfg(all(unix, not(target_os = "android")) + #[error(display = "Failed to generate shell completions")] + CompletionsError(#[error(source, no_from)] io::Error), } #[tokio::main] @@ -74,17 +80,19 @@ async fn run() -> Result<()> { let commands = cmds::get_commands(); let app = build_cli(&commands); + #[cfg(all(unix, not(target_os = "android")))] let app = app.subcommand( - clap::SubCommand::with_name("shell-completions") + clap::App::new("shell-completions") .about("Generates completion scripts for your shell") .arg( - clap::Arg::with_name("SHELL") + clap::Arg::new("SHELL") .required(true) - .possible_values(&clap::Shell::variants()[..]) + .possible_values(Shell::possible_values()) .help("The shell to generate the script for"), ) .arg( - clap::Arg::with_name("DIR") + clap::Arg::new("DIR") + .allow_invalid_utf8(true) .default_value("./") .help("Output directory where the shell completions are written"), ) @@ -93,39 +101,40 @@ async fn run() -> Result<()> { let app_matches = app.get_matches(); match app_matches.subcommand() { - ("shell-completions", Some(sub_matches)) => { - let shell = sub_matches + #[cfg(all(unix, not(target_os = "android")))] + Some(("shell-completions", sub_matches)) => { + let shell: Shell = sub_matches .value_of("SHELL") .unwrap() .parse() .expect("Invalid shell"); let out_dir = sub_matches.value_of_os("DIR").unwrap(); - build_cli(&commands).gen_completions(BIN_NAME, shell, out_dir); - Ok(()) + let mut app = build_cli(&commands); + generate_to(shell, &mut app, BIN_NAME, out_dir) + .map(|_output_file| ()) + .map_err(Error::CompletionsError) } - (sub_name, Some(sub_matches)) => { + Some((sub_name, sub_matches)) => { if let Some(cmd) = commands.get(sub_name) { cmd.run(sub_matches).await } else { unreachable!("No command matched"); } } - (_, None) => { + _ => { unreachable!("No subcommand matches"); } } } -fn build_cli(commands: &HashMap<&'static str, Box<dyn Command>>) -> clap::App<'static, 'static> { +fn build_cli(commands: &HashMap<&'static str, Box<dyn Command>>) -> clap::App<'static> { clap::App::new(BIN_NAME) .version(PRODUCT_VERSION) .author(crate_authors!()) .about(crate_description!()) .setting(clap::AppSettings::SubcommandRequiredElseHelp) - .global_settings(&[ - clap::AppSettings::DisableHelpSubcommand, - clap::AppSettings::VersionlessSubcommands, - ]) + .global_setting(clap::AppSettings::DisableHelpSubcommand) + .global_setting(clap::AppSettings::DisableVersionFlag) .subcommands(commands.values().map(|cmd| cmd.clap_subcommand())) } @@ -133,7 +142,7 @@ fn build_cli(commands: &HashMap<&'static str, Box<dyn Command>>) -> clap::App<'s pub trait Command { fn name(&self) -> &'static str; - fn clap_subcommand(&self) -> clap::App<'static, 'static>; + fn clap_subcommand(&self) -> clap::App<'static>; - async fn run(&self, matches: &clap::ArgMatches<'_>) -> Result<()>; + async fn run(&self, matches: &clap::ArgMatches) -> Result<()>; } |
