meta: structopt 0.3 -> clap 3

pull/186/head
Jake McGinty 2022-01-11 01:51:32 -06:00
parent 97a49c5c0e
commit 8dd11977af
9 changed files with 204 additions and 114 deletions

92
Cargo.lock generated
View File

@ -105,17 +105,58 @@ dependencies = [
"ansi_term", "ansi_term",
"atty", "atty",
"bitflags", "bitflags",
"strsim", "strsim 0.8.0",
"textwrap", "textwrap 0.11.0",
"unicode-width", "unicode-width",
"vec_map", "vec_map",
] ]
[[package]]
name = "clap"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1957aa4a5fb388f0a0a73ce7556c5b42025b874e5cdc2c670775e346e97adec0"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"indexmap",
"lazy_static",
"os_str_bytes",
"strsim 0.10.0",
"termcolor",
"textwrap 0.14.2",
]
[[package]]
name = "clap_complete"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a394f7ec0715b42a4e52b294984c27c9a61f77c8d82f7774c5198350be143f19"
dependencies = [
"clap 3.0.6",
]
[[package]]
name = "clap_derive"
version = "3.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "517358c28fcef6607bf6f76108e02afad7e82297d132a6b846dcc1fc3efcd153"
dependencies = [
"heck 0.4.0",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "client" name = "client"
version = "1.5.2" version = "1.5.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap 3.0.6",
"clap_complete",
"colored", "colored",
"dialoguer", "dialoguer",
"hostsfile", "hostsfile",
@ -127,7 +168,6 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"shared", "shared",
"structopt",
"tempfile", "tempfile",
"ureq", "ureq",
"wireguard-control", "wireguard-control",
@ -319,6 +359,12 @@ dependencies = [
"unicode-segmentation", "unicode-segmentation",
] ]
[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.19" version = "0.1.19"
@ -415,6 +461,16 @@ dependencies = [
"unicode-normalization", "unicode-normalization",
] ]
[[package]]
name = "indexmap"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]] [[package]]
name = "indoc" name = "indoc"
version = "1.0.3" version = "1.0.3"
@ -660,6 +716,15 @@ version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56"
[[package]]
name = "os_str_bytes"
version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.11.2" version = "0.11.2"
@ -922,11 +987,14 @@ version = "1.5.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
"clap 3.0.6",
"clap_complete",
"colored", "colored",
"dialoguer", "dialoguer",
"hyper", "hyper",
"indoc", "indoc",
"ipnetwork", "ipnetwork",
"lazy_static",
"libc", "libc",
"libsqlite3-sys", "libsqlite3-sys",
"log", "log",
@ -939,7 +1007,6 @@ dependencies = [
"serde_json", "serde_json",
"shared", "shared",
"socket2", "socket2",
"structopt",
"subtle", "subtle",
"tempfile", "tempfile",
"thiserror", "thiserror",
@ -955,6 +1022,7 @@ version = "1.5.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"atty", "atty",
"clap 3.0.6",
"colored", "colored",
"dialoguer", "dialoguer",
"indoc", "indoc",
@ -998,13 +1066,19 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]] [[package]]
name = "structopt" name = "structopt"
version = "0.3.25" version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c" checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
dependencies = [ dependencies = [
"clap", "clap 2.34.0",
"lazy_static", "lazy_static",
"structopt-derive", "structopt-derive",
] ]
@ -1015,7 +1089,7 @@ version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
dependencies = [ dependencies = [
"heck", "heck 0.3.3",
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1081,6 +1155,12 @@ dependencies = [
"unicode-width", "unicode-width",
] ]
[[package]]
name = "textwrap"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.30" version = "1.0.30"

View File

@ -16,6 +16,8 @@ path = "src/main.rs"
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
colored = "2" colored = "2"
clap = { version = "3", features = ["derive"] }
clap_complete = "3"
dialoguer = { version = "0.9", default-features = false } dialoguer = { version = "0.9", default-features = false }
hostsfile = { path = "../hostsfile" } hostsfile = { path = "../hostsfile" }
indoc = "1" indoc = "1"
@ -26,7 +28,6 @@ regex = { version = "1", default-features = false, features = ["std"] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
shared = { path = "../shared", default-features = false } shared = { path = "../shared", default-features = false }
structopt = "0.3"
ureq = { version = "2", default-features = false, features = ["json"] } ureq = { version = "2", default-features = false, features = ["json"] }
wireguard-control = { path = "../wireguard-control" } wireguard-control = { path = "../wireguard-control" }

View File

@ -20,7 +20,7 @@ use std::{
thread, thread,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use structopt::{clap::AppSettings, StructOpt}; use clap::{AppSettings, IntoApp, Parser, Subcommand, Args};
use wireguard_control::{Device, DeviceUpdate, InterfaceName, PeerConfigBuilder, PeerInfo}; use wireguard_control::{Device, DeviceUpdate, InterfaceName, PeerConfigBuilder, PeerInfo};
mod data_store; mod data_store;
@ -46,34 +46,35 @@ macro_rules! println_pad {
} }
} }
#[derive(Clone, Debug, StructOpt)] #[derive(Clone, Debug, Parser)]
#[structopt(name = "innernet", about, global_settings(&[AppSettings::ColoredHelp, AppSettings::DeriveDisplayOrder, AppSettings::VersionlessSubcommands, AppSettings::UnifiedHelpMessage]))] #[clap(name = "innernet", author, version, about)]
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
struct Opts { struct Opts {
#[structopt(subcommand)] #[clap(subcommand)]
command: Option<Command>, command: Option<Command>,
/// Verbose output, use -vv for even higher verbositude /// Verbose output, use -vv for even higher verbositude
#[structopt(short, long, parse(from_occurrences))] #[clap(short, long, parse(from_occurrences))]
verbose: u64, verbose: u64,
#[structopt(short, long, default_value = "/etc/innernet")] #[clap(short, long, default_value = "/etc/innernet")]
config_dir: PathBuf, config_dir: PathBuf,
#[structopt(short, long, default_value = "/var/lib/innernet")] #[clap(short, long, default_value = "/var/lib/innernet")]
data_dir: PathBuf, data_dir: PathBuf,
#[structopt(flatten)] #[clap(flatten)]
network: NetworkOpts, network: NetworkOpts,
} }
#[derive(Clone, Debug, StructOpt)] #[derive(Clone, Debug, Args)]
struct HostsOpt { struct HostsOpt {
/// The path to write hosts to /// The path to write hosts to
#[structopt(long = "hosts-path", default_value = "/etc/hosts")] #[clap(long = "hosts-path", default_value = "/etc/hosts")]
hosts_path: PathBuf, hosts_path: PathBuf,
/// Don't write to any hosts files /// Don't write to any hosts files
#[structopt(long = "no-write-hosts", conflicts_with = "hosts-path")] #[clap(long = "no-write-hosts", conflicts_with = "hosts-path")]
no_write_hosts: bool, no_write_hosts: bool,
} }
@ -83,33 +84,33 @@ impl From<HostsOpt> for Option<PathBuf> {
} }
} }
#[derive(Clone, Debug, StructOpt)] #[derive(Clone, Debug, Subcommand)]
enum Command { enum Command {
/// Install a new innernet config /// Install a new innernet config
#[structopt(alias = "redeem")] #[clap(alias = "redeem")]
Install { Install {
/// Path to the invitation file /// Path to the invitation file
invite: PathBuf, invite: PathBuf,
#[structopt(flatten)] #[clap(flatten)]
hosts: HostsOpt, hosts: HostsOpt,
#[structopt(flatten)] #[clap(flatten)]
install_opts: InstallOpts, install_opts: InstallOpts,
#[structopt(flatten)] #[clap(flatten)]
nat: NatOpts, nat: NatOpts,
}, },
/// Enumerate all innernet connections /// Enumerate all innernet connections
#[structopt(alias = "list")] #[clap(alias = "list")]
Show { Show {
/// One-line peer list /// One-line peer list
#[structopt(short, long)] #[clap(short, long)]
short: bool, short: bool,
/// Display peers in a tree based on the CIDRs /// Display peers in a tree based on the CIDRs
#[structopt(short, long)] #[clap(short, long)]
tree: bool, tree: bool,
interface: Option<Interface>, interface: Option<Interface>,
@ -119,18 +120,18 @@ enum Command {
Up { Up {
/// Enable daemon mode i.e. keep the process running, while fetching /// Enable daemon mode i.e. keep the process running, while fetching
/// the latest peer list periodically /// the latest peer list periodically
#[structopt(short, long)] #[clap(short, long)]
daemon: bool, daemon: bool,
/// Keep fetching the latest peer list at the specified interval in /// Keep fetching the latest peer list at the specified interval in
/// seconds. Valid only in daemon mode /// seconds. Valid only in daemon mode
#[structopt(long, default_value = "60")] #[clap(long, default_value = "60")]
interval: u64, interval: u64,
#[structopt(flatten)] #[clap(flatten)]
hosts: HostsOpt, hosts: HostsOpt,
#[structopt(flatten)] #[clap(flatten)]
nat: NatOpts, nat: NatOpts,
interface: Option<Interface>, interface: Option<Interface>,
@ -140,10 +141,10 @@ enum Command {
Fetch { Fetch {
interface: Interface, interface: Interface,
#[structopt(flatten)] #[clap(flatten)]
hosts: HostsOpt, hosts: HostsOpt,
#[structopt(flatten)] #[clap(flatten)]
nat: NatOpts, nat: NatOpts,
}, },
@ -162,7 +163,7 @@ enum Command {
AddPeer { AddPeer {
interface: Interface, interface: Interface,
#[structopt(flatten)] #[clap(flatten)]
sub_opts: AddPeerOpts, sub_opts: AddPeerOpts,
}, },
@ -175,7 +176,7 @@ enum Command {
RenamePeer { RenamePeer {
interface: Interface, interface: Interface,
#[structopt(flatten)] #[clap(flatten)]
sub_opts: RenamePeerOpts, sub_opts: RenamePeerOpts,
}, },
@ -183,7 +184,7 @@ enum Command {
AddCidr { AddCidr {
interface: Interface, interface: Interface,
#[structopt(flatten)] #[clap(flatten)]
sub_opts: AddCidrOpts, sub_opts: AddCidrOpts,
}, },
@ -191,7 +192,7 @@ enum Command {
DeleteCidr { DeleteCidr {
interface: Interface, interface: Interface,
#[structopt(flatten)] #[clap(flatten)]
sub_opts: DeleteCidrOpts, sub_opts: DeleteCidrOpts,
}, },
@ -200,7 +201,7 @@ enum Command {
interface: Interface, interface: Interface,
/// Display CIDRs in tree format /// Display CIDRs in tree format
#[structopt(short, long)] #[clap(short, long)]
tree: bool, tree: bool,
}, },
@ -214,7 +215,7 @@ enum Command {
AddAssociation { AddAssociation {
interface: Interface, interface: Interface,
#[structopt(flatten)] #[clap(flatten)]
sub_opts: AddAssociationOpts, sub_opts: AddAssociationOpts,
}, },
@ -228,7 +229,7 @@ enum Command {
SetListenPort { SetListenPort {
interface: Interface, interface: Interface,
#[structopt(flatten)] #[clap(flatten)]
sub_opts: ListenPortOpts, sub_opts: ListenPortOpts,
}, },
@ -236,14 +237,14 @@ enum Command {
OverrideEndpoint { OverrideEndpoint {
interface: Interface, interface: Interface,
#[structopt(flatten)] #[clap(flatten)]
sub_opts: OverrideEndpointOpts, sub_opts: OverrideEndpointOpts,
}, },
/// Generate shell completion scripts /// Generate shell completion scripts
Completions { Completions {
#[structopt(possible_values = &structopt::clap::Shell::variants(), case_insensitive = true)] #[clap(arg_enum)]
shell: structopt::clap::Shell, shell: clap_complete::Shell,
}, },
} }
@ -1138,7 +1139,7 @@ fn print_peer(peer: &PeerState, short: bool, level: usize) {
} }
fn main() { fn main() {
let opts = Opts::from_args(); let opts = Opts::parse();
util::init_logger(opts.verbose); util::init_logger(opts.verbose);
let argv0 = std::env::args().next().unwrap(); let argv0 = std::env::args().next().unwrap();
@ -1241,7 +1242,9 @@ fn run(opts: &Opts) -> Result<(), Error> {
override_endpoint(&interface, opts, sub_opts)?; override_endpoint(&interface, opts, sub_opts)?;
}, },
Command::Completions { shell } => { Command::Completions { shell } => {
Opts::clap().gen_completions_to("innernet", shell, &mut std::io::stdout()); let mut app = Opts::into_app();
let app_name = app.get_name().to_string();
clap_complete::generate(shell, &mut app, app_name, &mut std::io::stdout());
std::process::exit(0); std::process::exit(0);
}, },
} }

View File

@ -18,11 +18,14 @@ v6-test = []
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
bytes = "1" bytes = "1"
clap = { version = "3", features = ["derive"] }
clap_complete = "3"
colored = "2" colored = "2"
dialoguer = { version = "0.9", default-features = false } dialoguer = { version = "0.9", default-features = false }
hyper = { version = "0.14", default-features = false, features = ["http1", "server", "runtime", "stream"] } hyper = { version = "0.14", default-features = false, features = ["http1", "server", "runtime", "stream"] }
indoc = "1" indoc = "1"
ipnetwork = { git = "https://github.com/mcginty/ipnetwork", rev = "393f2d89e41ac6c1c0d80a31fc0997c387a7f7ba" } ipnetwork = { git = "https://github.com/mcginty/ipnetwork", rev = "393f2d89e41ac6c1c0d80a31fc0997c387a7f7ba" }
lazy_static = "1"
libc = "0.2" libc = "0.2"
libsqlite3-sys = "0.23" libsqlite3-sys = "0.23"
log = "0.4" log = "0.4"
@ -34,7 +37,6 @@ rusqlite = "0.26"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
shared = { path = "../shared" } shared = { path = "../shared" }
structopt = "0.3"
subtle = "2" subtle = "2"
thiserror = "1" thiserror = "1"
tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] } tokio = { version = "1", features = ["macros", "rt-multi-thread", "time"] }

View File

@ -9,7 +9,6 @@ use std::{
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
time::{Duration, SystemTime}, time::{Duration, SystemTime},
}; };
use structopt::lazy_static;
pub static CREATE_TABLE_SQL: &str = "CREATE TABLE peers ( pub static CREATE_TABLE_SQL: &str = "CREATE TABLE peers (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,

View File

@ -1,5 +1,6 @@
use crate::*; use crate::*;
use anyhow::anyhow; use anyhow::anyhow;
use clap::{Parser};
use db::DatabaseCidr; use db::DatabaseCidr;
use dialoguer::{theme::ColorfulTheme, Input}; use dialoguer::{theme::ColorfulTheme, Input};
use indoc::printdoc; use indoc::printdoc;
@ -22,26 +23,26 @@ fn create_database<P: AsRef<Path>>(
Ok(conn) Ok(conn)
} }
#[derive(Debug, Default, Clone, PartialEq, StructOpt)] #[derive(Debug, Default, Clone, PartialEq, Parser)]
pub struct InitializeOpts { pub struct InitializeOpts {
/// The network name (ex: evilcorp) /// The network name (ex: evilcorp)
#[structopt(long)] #[clap(long)]
pub network_name: Option<Interface>, pub network_name: Option<Interface>,
/// The network CIDR (ex: 10.42.0.0/16) /// The network CIDR (ex: 10.42.0.0/16)
#[structopt(long)] #[clap(long)]
pub network_cidr: Option<IpNetwork>, pub network_cidr: Option<IpNetwork>,
/// This server's external endpoint (ex: 100.100.100.100:51820) /// This server's external endpoint (ex: 100.100.100.100:51820)
#[structopt(long, conflicts_with = "auto-external-endpoint")] #[clap(long, conflicts_with = "auto-external-endpoint")]
pub external_endpoint: Option<Endpoint>, pub external_endpoint: Option<Endpoint>,
/// Auto-resolve external endpoint /// Auto-resolve external endpoint
#[structopt(long = "auto-external-endpoint")] #[clap(long = "auto-external-endpoint")]
pub auto_external_endpoint: bool, pub auto_external_endpoint: bool,
/// Port to listen on (for the WireGuard interface) /// Port to listen on (for the WireGuard interface)
#[structopt(long)] #[clap(long)]
pub listen_port: Option<u16>, pub listen_port: Option<u16>,
} }

View File

@ -1,4 +1,5 @@
use anyhow::{anyhow, bail}; use anyhow::{anyhow, bail};
use clap::{AppSettings, IntoApp, Parser, Subcommand};
use colored::*; use colored::*;
use dialoguer::Confirm; use dialoguer::Confirm;
use hyper::{http, server::conn::AddrStream, Body, Request, Response}; use hyper::{http, server::conn::AddrStream, Body, Request, Response};
@ -23,7 +24,6 @@ use std::{
sync::Arc, sync::Arc,
time::Duration, time::Duration,
}; };
use structopt::{clap::AppSettings, StructOpt};
use subtle::ConstantTimeEq; use subtle::ConstantTimeEq;
use wireguard_control::{Backend, Device, DeviceUpdate, InterfaceName, Key, PeerConfigBuilder}; use wireguard_control::{Backend, Device, DeviceUpdate, InterfaceName, Key, PeerConfigBuilder};
@ -44,28 +44,29 @@ pub use shared::{Association, AssociationContents};
pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const VERSION: &str = env!("CARGO_PKG_VERSION");
#[derive(Debug, StructOpt)] #[derive(Debug, Parser)]
#[structopt(name = "innernet-server", about, global_settings(&[AppSettings::ColoredHelp, AppSettings::DeriveDisplayOrder, AppSettings::VersionlessSubcommands, AppSettings::UnifiedHelpMessage]))] #[clap(name = "innernet-server", author, version, about)]
#[clap(global_setting(AppSettings::DeriveDisplayOrder))]
struct Opts { struct Opts {
#[structopt(subcommand)] #[clap(subcommand)]
command: Command, command: Command,
#[structopt(short, long, default_value = "/etc/innernet-server")] #[clap(short, long, default_value = "/etc/innernet-server")]
config_dir: PathBuf, config_dir: PathBuf,
#[structopt(short, long, default_value = "/var/lib/innernet-server")] #[clap(short, long, default_value = "/var/lib/innernet-server")]
data_dir: PathBuf, data_dir: PathBuf,
#[structopt(flatten)] #[clap(flatten)]
network: NetworkOpts, network: NetworkOpts,
} }
#[derive(Debug, StructOpt)] #[derive(Debug, Subcommand)]
enum Command { enum Command {
/// Create a new network. /// Create a new network.
#[structopt(alias = "init")] #[clap(alias = "init")]
New { New {
#[structopt(flatten)] #[clap(flatten)]
opts: InitializeOpts, opts: InitializeOpts,
}, },
@ -76,7 +77,7 @@ enum Command {
Serve { Serve {
interface: Interface, interface: Interface,
#[structopt(flatten)] #[clap(flatten)]
network: NetworkOpts, network: NetworkOpts,
}, },
@ -84,7 +85,7 @@ enum Command {
AddPeer { AddPeer {
interface: Interface, interface: Interface,
#[structopt(flatten)] #[clap(flatten)]
args: AddPeerOpts, args: AddPeerOpts,
}, },
@ -92,7 +93,7 @@ enum Command {
RenamePeer { RenamePeer {
interface: Interface, interface: Interface,
#[structopt(flatten)] #[clap(flatten)]
args: RenamePeerOpts, args: RenamePeerOpts,
}, },
@ -100,7 +101,7 @@ enum Command {
AddCidr { AddCidr {
interface: Interface, interface: Interface,
#[structopt(flatten)] #[clap(flatten)]
args: AddCidrOpts, args: AddCidrOpts,
}, },
@ -108,14 +109,14 @@ enum Command {
DeleteCidr { DeleteCidr {
interface: Interface, interface: Interface,
#[structopt(flatten)] #[clap(flatten)]
args: DeleteCidrOpts, args: DeleteCidrOpts,
}, },
/// Generate shell completion scripts /// Generate shell completion scripts
Completions { Completions {
#[structopt(possible_values = &structopt::clap::Shell::variants(), case_insensitive = true)] #[clap(arg_enum)]
shell: structopt::clap::Shell, shell: clap_complete::Shell,
}, },
} }
@ -235,7 +236,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
pretty_env_logger::init(); pretty_env_logger::init();
let opts = Opts::from_args(); let opts = Opts::parse();
if unsafe { libc::getuid() } != 0 && !matches!(opts.command, Command::Completions { .. }) { if unsafe { libc::getuid() } != 0 && !matches!(opts.command, Command::Completions { .. }) {
return Err("innernet-server must run as root.".into()); return Err("innernet-server must run as root.".into());
@ -260,7 +261,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Command::AddCidr { interface, args } => add_cidr(&interface, &conf, args)?, Command::AddCidr { interface, args } => add_cidr(&interface, &conf, args)?,
Command::DeleteCidr { interface, args } => delete_cidr(&interface, &conf, args)?, Command::DeleteCidr { interface, args } => delete_cidr(&interface, &conf, args)?,
Command::Completions { shell } => { Command::Completions { shell } => {
Opts::clap().gen_completions_to("innernet-server", shell, &mut std::io::stdout()); let mut app = Opts::into_app();
let app_name = app.get_name().to_string();
clap_complete::generate(shell, &mut app, app_name, &mut std::io::stdout());
std::process::exit(0); std::process::exit(0);
}, },
} }

View File

@ -9,6 +9,7 @@ version = "1.5.2"
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
atty = "0.2" atty = "0.2"
clap = { version = "3", features = ["derive"] }
colored = "2.0" colored = "2.0"
dialoguer = { version = "0.9", default-features = false } dialoguer = { version = "0.9", default-features = false }
indoc = "1" indoc = "1"

View File

@ -1,4 +1,5 @@
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
use clap::Args;
use ipnetwork::IpNetwork; use ipnetwork::IpNetwork;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex; use regex::Regex;
@ -13,7 +14,6 @@ use std::{
time::{Duration, SystemTime}, time::{Duration, SystemTime},
vec, vec,
}; };
use structopt::StructOpt;
use url::Host; use url::Host;
use wireguard_control::{ use wireguard_control::{
AllowedIp, Backend, InterfaceName, InvalidInterfaceName, Key, PeerConfig, PeerConfigBuilder, AllowedIp, Backend, InterfaceName, InvalidInterfaceName, Key, PeerConfig, PeerConfigBuilder,
@ -283,102 +283,102 @@ pub struct RedeemContents {
pub public_key: String, pub public_key: String,
} }
#[derive(Debug, Clone, PartialEq, StructOpt)] #[derive(Debug, Clone, PartialEq, Args)]
pub struct InstallOpts { pub struct InstallOpts {
/// Set a specific interface name /// Set a specific interface name
#[structopt(long, conflicts_with = "default-name")] #[clap(long, conflicts_with = "default-name")]
pub name: Option<String>, pub name: Option<String>,
/// Use the network name inside the invitation as the interface name /// Use the network name inside the invitation as the interface name
#[structopt(long = "default-name")] #[clap(long = "default-name")]
pub default_name: bool, pub default_name: bool,
/// Delete the invitation after a successful install /// Delete the invitation after a successful install
#[structopt(short, long)] #[clap(short, long)]
pub delete_invite: bool, pub delete_invite: bool,
} }
#[derive(Debug, Clone, PartialEq, StructOpt)] #[derive(Debug, Clone, PartialEq, Args)]
pub struct AddPeerOpts { pub struct AddPeerOpts {
/// Name of new peer /// Name of new peer
#[structopt(long)] #[clap(long)]
pub name: Option<Hostname>, pub name: Option<Hostname>,
/// Specify desired IP of new peer (within parent CIDR) /// Specify desired IP of new peer (within parent CIDR)
#[structopt(long, conflicts_with = "auto-ip")] #[clap(long, conflicts_with = "auto-ip")]
pub ip: Option<IpAddr>, pub ip: Option<IpAddr>,
/// Auto-assign the peer the first available IP within the CIDR /// Auto-assign the peer the first available IP within the CIDR
#[structopt(long = "auto-ip")] #[clap(long = "auto-ip")]
pub auto_ip: bool, pub auto_ip: bool,
/// Name of CIDR to add new peer under /// Name of CIDR to add new peer under
#[structopt(long)] #[clap(long)]
pub cidr: Option<String>, pub cidr: Option<String>,
/// Make new peer an admin? /// Make new peer an admin?
#[structopt(long)] #[clap(long)]
pub admin: Option<bool>, pub admin: Option<bool>,
/// Bypass confirmation /// Bypass confirmation
#[structopt(long)] #[clap(long)]
pub yes: bool, pub yes: bool,
/// Save the config to the given location /// Save the config to the given location
#[structopt(long)] #[clap(long)]
pub save_config: Option<String>, pub save_config: Option<String>,
/// Invite expiration period (eg. '30d', '7w', '2h', '60m', '1000s') /// Invite expiration period (eg. '30d', '7w', '2h', '60m', '1000s')
#[structopt(long)] #[clap(long)]
pub invite_expires: Option<Timestring>, pub invite_expires: Option<Timestring>,
} }
#[derive(Debug, Clone, PartialEq, StructOpt)] #[derive(Debug, Clone, PartialEq, Args)]
pub struct RenamePeerOpts { pub struct RenamePeerOpts {
/// Name of peer to rename /// Name of peer to rename
#[structopt(long)] #[clap(long)]
pub name: Option<Hostname>, pub name: Option<Hostname>,
/// The new name of the peer /// The new name of the peer
#[structopt(long)] #[clap(long)]
pub new_name: Option<Hostname>, pub new_name: Option<Hostname>,
/// Bypass confirmation /// Bypass confirmation
#[structopt(long)] #[clap(long)]
pub yes: bool, pub yes: bool,
} }
#[derive(Debug, Clone, PartialEq, StructOpt)] #[derive(Debug, Clone, PartialEq, Args)]
pub struct AddCidrOpts { pub struct AddCidrOpts {
/// The CIDR name (eg. 'engineers') /// The CIDR name (eg. 'engineers')
#[structopt(long)] #[clap(long)]
pub name: Option<Hostname>, pub name: Option<Hostname>,
/// The CIDR network (eg. '10.42.5.0/24') /// The CIDR network (eg. '10.42.5.0/24')
#[structopt(long)] #[clap(long)]
pub cidr: Option<IpNetwork>, pub cidr: Option<IpNetwork>,
/// The CIDR parent name /// The CIDR parent name
#[structopt(long)] #[clap(long)]
pub parent: Option<String>, pub parent: Option<String>,
/// Bypass confirmation /// Bypass confirmation
#[structopt(long)] #[clap(long)]
pub yes: bool, pub yes: bool,
} }
#[derive(Debug, Clone, PartialEq, StructOpt)] #[derive(Debug, Clone, PartialEq, Args)]
pub struct DeleteCidrOpts { pub struct DeleteCidrOpts {
/// The CIDR name (eg. 'engineers') /// The CIDR name (eg. 'engineers')
#[structopt(long)] #[clap(long)]
pub name: Option<String>, pub name: Option<String>,
/// Bypass confirmation /// Bypass confirmation
#[structopt(long)] #[clap(long)]
pub yes: bool, pub yes: bool,
} }
#[derive(Debug, Clone, PartialEq, StructOpt)] #[derive(Debug, Clone, PartialEq, Args)]
pub struct AddAssociationOpts { pub struct AddAssociationOpts {
/// The first cidr to associate /// The first cidr to associate
pub cidr1: Option<String>, pub cidr1: Option<String>,
@ -387,49 +387,49 @@ pub struct AddAssociationOpts {
pub cidr2: Option<String>, pub cidr2: Option<String>,
} }
#[derive(Debug, Clone, PartialEq, StructOpt)] #[derive(Debug, Clone, PartialEq, Args)]
pub struct ListenPortOpts { pub struct ListenPortOpts {
/// The listen port you'd like to set for the interface /// The listen port you'd like to set for the interface
#[structopt(short, long)] #[clap(short, long)]
pub listen_port: Option<u16>, pub listen_port: Option<u16>,
/// Unset the local listen port to use a randomized port /// Unset the local listen port to use a randomized port
#[structopt(short, long, conflicts_with = "listen-port")] #[clap(short, long, conflicts_with = "listen-port")]
pub unset: bool, pub unset: bool,
/// Bypass confirmation /// Bypass confirmation
#[structopt(long)] #[clap(long)]
pub yes: bool, pub yes: bool,
} }
#[derive(Debug, Clone, PartialEq, StructOpt)] #[derive(Debug, Clone, PartialEq, Args)]
pub struct OverrideEndpointOpts { pub struct OverrideEndpointOpts {
/// The listen port you'd like to set for the interface /// The listen port you'd like to set for the interface
#[structopt(short, long)] #[clap(short, long)]
pub endpoint: Option<Endpoint>, pub endpoint: Option<Endpoint>,
/// Unset an existing override to use the automatic endpoint discovery /// Unset an existing override to use the automatic endpoint discovery
#[structopt(short, long, conflicts_with = "endpoint")] #[clap(short, long, conflicts_with = "endpoint")]
pub unset: bool, pub unset: bool,
/// Bypass confirmation /// Bypass confirmation
#[structopt(long)] #[clap(long)]
pub yes: bool, pub yes: bool,
} }
#[derive(Debug, Clone, StructOpt)] #[derive(Debug, Clone, Args)]
pub struct NatOpts { pub struct NatOpts {
#[structopt(long)] #[clap(long)]
/// Don't attempt NAT traversal. Note that this still will report candidates /// Don't attempt NAT traversal. Note that this still will report candidates
/// unless you also specify to exclude all NAT candidates. /// unless you also specify to exclude all NAT candidates.
pub no_nat_traversal: bool, pub no_nat_traversal: bool,
#[structopt(long)] #[clap(long)]
/// Exclude one or more CIDRs from NAT candidate reporting. /// Exclude one or more CIDRs from NAT candidate reporting.
/// ex. --exclude-nat-candidates '0.0.0.0/0' would report no candidates. /// ex. --exclude-nat-candidates '0.0.0.0/0' would report no candidates.
pub exclude_nat_candidates: Vec<IpNetwork>, pub exclude_nat_candidates: Vec<IpNetwork>,
#[structopt(long, conflicts_with = "exclude-nat-candidates")] #[clap(long, conflicts_with = "exclude-nat-candidates")]
/// Don't report any candidates to coordinating server. /// Don't report any candidates to coordinating server.
/// Shorthand for --exclude-nat-candidates '0.0.0.0/0'. /// Shorthand for --exclude-nat-candidates '0.0.0.0/0'.
pub no_nat_candidates: bool, pub no_nat_candidates: bool,
@ -454,19 +454,19 @@ impl NatOpts {
} }
} }
#[derive(Debug, Clone, Copy, StructOpt)] #[derive(Debug, Clone, Copy, Args)]
pub struct NetworkOpts { pub struct NetworkOpts {
#[structopt(long)] #[clap(long)]
/// Whether the routing should be done by innernet or is done by an /// Whether the routing should be done by innernet or is done by an
/// external tool like e.g. babeld. /// external tool like e.g. babeld.
pub no_routing: bool, pub no_routing: bool,
#[structopt(long, default_value, possible_values = Backend::variants())] #[clap(long, default_value_t, possible_values = Backend::variants())]
/// Specify a WireGuard backend to use. /// Specify a WireGuard backend to use.
/// If not set, innernet will auto-select based on availability. /// If not set, innernet will auto-select based on availability.
pub backend: Backend, pub backend: Backend,
#[structopt(long)] #[clap(long)]
/// Specify the desired MTU for your interface (default: 1420 for IPv4 and 1400 for IPv6). /// Specify the desired MTU for your interface (default: 1420 for IPv4 and 1400 for IPv6).
pub mtu: Option<u32>, pub mtu: Option<u32>,
} }