Fig and shell completions (#1638)

* Fig and shell completions lib

* Complete all the things
This commit is contained in:
Drazen Urch
2022-09-22 17:26:37 +02:00
committed by GitHub
parent 8c877d64d6
commit 0adf4df094
22 changed files with 278 additions and 73 deletions
Generated
+15
View File
@@ -681,6 +681,15 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "completions"
version = "0.1.0"
dependencies = [
"clap 3.2.8",
"clap_complete",
"clap_complete_fig",
]
[[package]]
name = "config"
version = "0.1.0"
@@ -919,6 +928,7 @@ dependencies = [
"cfg-if 0.1.10",
"clap 3.2.8",
"coconut-interface",
"completions",
"config",
"credential-storage",
"credentials",
@@ -3236,6 +3246,7 @@ dependencies = [
"clap 3.2.8",
"client-core",
"coconut-interface",
"completions",
"config",
"credential-storage",
"credentials",
@@ -3275,6 +3286,7 @@ dependencies = [
"clap 3.2.8",
"coconut-interface",
"colored",
"completions",
"config",
"credentials",
"crypto",
@@ -3317,6 +3329,7 @@ dependencies = [
"bs58",
"clap 3.2.8",
"colored",
"completions",
"config",
"crypto",
"cupid",
@@ -3355,6 +3368,7 @@ version = "1.0.2"
dependencies = [
"async-trait",
"clap 3.2.8",
"completions",
"dirs",
"futures",
"ipnetwork",
@@ -3400,6 +3414,7 @@ dependencies = [
"clap 3.2.8",
"client-core",
"coconut-interface",
"completions",
"config",
"credential-storage",
"credentials",
+1
View File
@@ -63,6 +63,7 @@ members = [
"common/topology",
"common/types",
"common/wasm-utils",
"common/completions",
"explorer-api",
"gateway",
"gateway/gateway-requests",
+2 -1
View File
@@ -9,7 +9,7 @@ edition = "2021"
async-trait = "0.1.52"
bip39 = "1.0.1"
cfg-if = "0.1"
clap = { version = "3.0.10", features = ["cargo", "derive"] }
clap = { version = "3.2", features = ["cargo", "derive"] }
pickledb = "0.4.1"
rand = "0.7.3"
serde = { version = "1.0", features = ["derive"] }
@@ -19,6 +19,7 @@ tokio = { version = "1.19.1", features = ["rt-multi-thread", "net", "signal", "m
coconut-interface = { path = "../../common/coconut-interface" }
config = { path = "../../common/config" }
completions = { path = "../../common/completions" }
credentials = { path = "../../common/credentials" }
credential-storage = { path = "../../common/credential-storage" }
crypto = { path = "../../common/crypto", features = ["rand", "asymmetric", "symmetric", "aes", "hashing"] }
+7
View File
@@ -3,6 +3,7 @@
use async_trait::async_trait;
use clap::{Args, Subcommand};
use completions::ArgShell;
use pickledb::PickleDb;
use rand::rngs::OsRng;
use std::str::FromStr;
@@ -28,6 +29,12 @@ pub(crate) enum Commands {
ListDeposits(ListDeposits),
/// Get a credential for a given deposit
GetCredential(GetCredential),
/// Generate shell completions
Completions(ArgShell),
/// Generate Fig specification
GenerateFigSpec,
}
#[async_trait]
+6
View File
@@ -12,6 +12,8 @@ cfg_if::cfg_if! {
use commands::{Commands, Execute};
use error::Result;
use network_defaults::setup_env;
use clap::CommandFactory;
use completions::fig_generate;
use clap::Parser;
use pickledb::{PickleDb, PickleDbDumpPolicy, SerializationMethod};
@@ -52,10 +54,14 @@ cfg_if::cfg_if! {
),
};
let bin_name = "nym-credential-client";
match &args.command {
Commands::Deposit(m) => m.execute(&mut db, shared_storage).await?,
Commands::ListDeposits(m) => m.execute(&mut db, shared_storage).await?,
Commands::GetCredential(m) => m.execute(&mut db, shared_storage).await?,
Commands::Completions(s) => s.generate(&mut crate::Cli::into_app(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::into_app(), bin_name)
}
Ok(())
+2 -1
View File
@@ -20,7 +20,7 @@ futures = "0.3" # bunch of futures stuff, however, now that I think about it, it
# and the single instance of abortable we have should really be refactored anyway
url = "2.2"
clap = { version = "3.2.8", features = ["cargo", "derive"] }
clap = { version = "3.2", features = ["cargo", "derive"] }
dirs = "4.0"
log = "0.4" # self explanatory
pretty_env_logger = "0.4" # for formatting log messages
@@ -34,6 +34,7 @@ tokio-tungstenite = "0.14" # websocket
client-core = { path = "../client-core" }
coconut-interface = { path = "../../common/coconut-interface", optional = true }
config = { path = "../../common/config" }
completions = { path = "../../common/completions" }
credential-storage = { path = "../../common/credential-storage" }
credentials = { path = "../../common/credentials", optional = true }
crypto = { path = "../../common/crypto" }
+12
View File
@@ -2,7 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::{Config, SocketType};
use clap::CommandFactory;
use clap::{Parser, Subcommand};
use completions::{fig_generate, ArgShell};
pub(crate) mod init;
pub(crate) mod run;
@@ -62,6 +64,12 @@ pub(crate) enum Commands {
Run(run::Run),
/// Try to upgrade the client
Upgrade(upgrade::Upgrade),
/// Generate shell completions
Completions(ArgShell),
/// Generate Fig specification
GenerateFigSpec,
}
// Configuration that can be overridden.
@@ -76,10 +84,14 @@ pub(crate) struct OverrideConfig {
}
pub(crate) async fn execute(args: &Cli) {
let bin_name = "nym-native-client";
match &args.command {
Commands::Init(m) => init::execute(m).await,
Commands::Run(m) => run::execute(m).await,
Commands::Upgrade(m) => upgrade::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::into_app(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::into_app(), bin_name),
}
}
+2 -1
View File
@@ -11,7 +11,7 @@ name = "nym_socks5"
path = "src/lib.rs"
[dependencies]
clap = { version = "3.2.8", features = ["cargo", "derive"] }
clap = { version = "3.2", features = ["cargo", "derive"] }
dirs = "4.0"
futures = "0.3"
log = "0.4"
@@ -27,6 +27,7 @@ url = "2.2"
client-core = { path = "../client-core" }
coconut-interface = { path = "../../common/coconut-interface", optional = true }
config = { path = "../../common/config" }
completions = { path = "../../common/completions" }
credential-storage = { path = "../../common/credential-storage" }
credentials = { path = "../../common/credentials", optional = true }
crypto = { path = "../../common/crypto" }
+12
View File
@@ -2,7 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
use crate::client::config::Config;
use clap::CommandFactory;
use clap::{Parser, Subcommand};
use completions::{fig_generate, ArgShell};
use config::parse_validators;
pub mod init;
@@ -63,6 +65,12 @@ pub(crate) enum Commands {
Run(run::Run),
/// Try to upgrade the client
Upgrade(upgrade::Upgrade),
/// Generate shell completions
Completions(ArgShell),
/// Generate Fig specification
GenerateFigSpec,
}
// Configuration that can be overridden.
@@ -76,10 +84,14 @@ pub(crate) struct OverrideConfig {
}
pub(crate) async fn execute(args: &Cli) {
let bin_name = "nym-socks5-client";
match &args.command {
Commands::Init(m) => init::execute(m).await,
Commands::Run(m) => run::execute(m).await,
Commands::Upgrade(m) => upgrade::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::into_app(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::into_app(), bin_name),
}
}
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "completions"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "3.2", features = ["derive"] }
clap_complete = "3.2"
clap_complete_fig = "3.2"
+58
View File
@@ -0,0 +1,58 @@
use clap::builder::Command;
use clap::clap_derive::ArgEnum;
use clap::Args;
use clap_complete::generator::generate;
use clap_complete::Shell as ClapShell;
use std::io;
pub fn fig_generate(command: &mut Command, name: &str) {
clap_complete::generate(
clap_complete_fig::Fig,
command,
name,
&mut std::io::stdout(),
)
}
#[derive(ArgEnum, Copy, Clone)]
pub enum Shell {
Bash,
Elvish,
Fish,
PowerShell,
Zsh,
}
#[derive(Args, Copy, Clone)]
pub struct ArgShell {
#[clap(arg_enum, value_name = "SHELL")]
shell: Shell,
}
impl ArgShell {
pub fn generate(&self, command: &mut Command, name: &str) {
self.shell.generate(command, name)
}
}
impl Shell {
pub fn generate(&self, command: &mut Command, name: &str) {
match &self {
Self::Bash => {
generate(ClapShell::Bash, command, name, &mut io::stdout());
}
Self::Elvish => {
generate(ClapShell::Elvish, command, name, &mut io::stdout());
}
Self::Fish => {
generate(ClapShell::Fish, command, name, &mut io::stdout());
}
Self::PowerShell => {
generate(ClapShell::PowerShell, command, name, &mut io::stdout());
}
Self::Zsh => {
generate(ClapShell::Zsh, command, name, &mut io::stdout());
}
}
}
}
+3
View File
@@ -3,10 +3,12 @@
### Added
- vesting-contract: added queries for delegation timestamps and paged query for all vesting delegations in the contract ([#1569])
- all binaries: added shell completion and [Fig](fig.io) spec generation ([#1638])
### Changed
- mixnet-contract: compounding delegator rewards now happens instantaneously as opposed to having to wait for the current epoch to finish ([#1571])
- network-requester: updated CLI to use `clap` macros ([#1638])
### Fixed
@@ -18,6 +20,7 @@
[#1569]: https://github.com/nymtech/nym/pull/1569
[#1569]: https://github.com/nymtech/nym/pull/1571
[#1613]: https://github.com/nymtech/nym/pull/1613
[#1638]: https://github.com/nymtech/nym/pull/1638
## [nym-contracts-v1.0.1](https://github.com/nymtech/nym/tree/nym-contracts-v1.0.1) (2022-06-22)
+1 -1
View File
@@ -7,7 +7,7 @@ edition = "2021"
[dependencies]
chrono = { version = "0.4.19", features = ["serde"] }
clap = { version = "3.2.8", features = ["cargo", "derive"] }
clap = { version = "3.2", features = ["cargo", "derive"] }
humantime-serde = "1.0"
isocountry = "0.3.2"
itertools = "0.10.3"
+2 -1
View File
@@ -19,7 +19,7 @@ anyhow = "1.0.53"
async-trait = { version = "0.1.51" }
bip39 = "1.0.1"
bs58 = "0.4.0"
clap = { version = "3.0.10", features = ["cargo", "derive"] }
clap = { version = "3.2", features = ["cargo", "derive"] }
colored = "2.0"
dashmap = "4.0"
dirs = "4.0"
@@ -55,6 +55,7 @@ coconut-interface = { path = "../common/coconut-interface", optional = true }
credentials = { path = "../common/credentials" }
config = { path = "../common/config" }
crypto = { path = "../common/crypto" }
completions = { path = "../common/completions" }
gateway-requests = { path = "gateway-requests" }
mixnet-client = { path = "../common/client-libs/mixnet-client" }
mixnode-common = { path = "../common/mixnode-common" }
+12
View File
@@ -4,8 +4,10 @@
use std::{process, str::FromStr};
use crate::{config::Config, Cli};
use clap::CommandFactory;
use clap::Subcommand;
use colored::Colorize;
use completions::{fig_generate, ArgShell};
use config::parse_validators;
use crypto::bech32_address_validation;
use network_defaults::var_names::{
@@ -34,6 +36,12 @@ pub(crate) enum Commands {
/// Try to upgrade the gateway
Upgrade(upgrade::Upgrade),
/// Generate shell completions
Completions(ArgShell),
/// Generate Fig specification
GenerateFigSpec,
}
// Configuration that can be overridden.
@@ -55,12 +63,16 @@ pub(crate) struct OverrideConfig {
}
pub(crate) async fn execute(args: Cli) {
let bin_name = "nym-gateway";
match &args.command {
Commands::Init(m) => init::execute(m).await,
Commands::NodeDetails(m) => node_details::execute(m).await,
Commands::Run(m) => run::execute(m).await,
Commands::Sign(m) => sign::execute(m),
Commands::Upgrade(m) => upgrade::execute(m).await,
Commands::Completions(s) => s.generate(&mut crate::Cli::into_app(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::into_app(), bin_name),
}
}
+2 -1
View File
@@ -18,7 +18,7 @@ rust-version = "1.58.1"
[dependencies]
anyhow = "1.0.40"
bs58 = "0.4.0"
clap = { version = "3.0.10", features = ["cargo", "derive"] }
clap = { version = "3.2", features = ["cargo", "derive"] }
colored = "2.0"
cupid = "0.6.1"
dirs = "4.0"
@@ -40,6 +40,7 @@ url = { version = "2.2", features = ["serde"] }
## internal
config = { path="../common/config" }
crypto = { path="../common/crypto" }
completions = { path="../common/completions" }
mixnet-client = { path="../common/client-libs/mixnet-client" }
mixnode-common = { path="../common/mixnode-common" }
nonexhaustive-delayqueue = { path="../common/nonexhaustive-delayqueue" }
+12
View File
@@ -4,8 +4,10 @@
use std::process;
use crate::{config::Config, Cli};
use clap::CommandFactory;
use clap::Subcommand;
use colored::Colorize;
use completions::{fig_generate, ArgShell};
use config::{
defaults::var_names::{API_VALIDATOR, BECH32_PREFIX, CONFIGURED},
parse_validators,
@@ -38,6 +40,12 @@ pub(crate) enum Commands {
/// Show details of this mixnode
NodeDetails(node_details::NodeDetails),
/// Generate shell completions
Completions(ArgShell),
/// Generate Fig specification
GenerateFigSpec,
}
// Configuration that can be overridden.
@@ -53,6 +61,8 @@ struct OverrideConfig {
}
pub(crate) async fn execute(args: Cli) {
let bin_name = "nym-mixnode";
match &args.command {
Commands::Describe(m) => describe::execute(m),
Commands::Init(m) => init::execute(m),
@@ -60,6 +70,8 @@ pub(crate) async fn execute(args: Cli) {
Commands::Sign(m) => sign::execute(m),
Commands::Upgrade(m) => upgrade::execute(m),
Commands::NodeDetails(m) => node_details::execute(m),
Commands::Completions(s) => s.generate(&mut crate::Cli::into_app(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::into_app(), bin_name),
}
}
+29
View File
@@ -571,6 +571,25 @@ dependencies = [
"textwrap",
]
[[package]]
name = "clap_complete"
version = "3.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f7a2e0a962c45ce25afce14220bc24f9dade0a1787f185cecf96bfba7847cd8"
dependencies = [
"clap",
]
[[package]]
name = "clap_complete_fig"
version = "3.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed37b4c0c1214673eba6ad8ea31666626bf72be98ffb323067d973c48b4964b9"
dependencies = [
"clap",
"clap_complete",
]
[[package]]
name = "clap_derive"
version = "3.2.18"
@@ -708,6 +727,15 @@ dependencies = [
"memchr",
]
[[package]]
name = "completions"
version = "0.1.0"
dependencies = [
"clap",
"clap_complete",
"clap_complete_fig",
]
[[package]]
name = "config"
version = "0.1.0"
@@ -3347,6 +3375,7 @@ version = "1.0.2"
dependencies = [
"clap",
"client-core",
"completions",
"config",
"credential-storage",
"crypto",
@@ -11,7 +11,7 @@ anyhow = "1.0"
argon2 = "0.4"
base64 = "0.13"
bip39 = "1.0"
clap = { version = "3.2.20", features = ["derive"] }
clap = { version = "3.2", features = ["derive"] }
log = "0.4"
pretty_env_logger = "0.4"
serde_json = "1.0.0"
@@ -11,7 +11,7 @@ edition = "2021"
[dependencies]
async-trait = { version = "0.1.51" }
clap = "3.2"
clap = {version = "3.2", features = ["derive"]}
dirs = "4.0"
futures = "0.3.24"
ipnetwork = "0.20.0"
@@ -30,6 +30,7 @@ tokio-tungstenite = "0.17.2"
# internal
network-defaults = { path = "../../common/network-defaults" }
nymsphinx = { path = "../../common/nymsphinx" }
completions = { path = "../../common/completions" }
ordered-buffer = {path = "../../common/socks5/ordered-buffer"}
proxy-helpers = { path = "../../common/socks5/proxy-helpers" }
socks5-requests = { path = "../../common/socks5/requests" }
+83 -62
View File
@@ -1,7 +1,10 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use clap::{App, Arg, ArgMatches};
use clap::CommandFactory;
use clap::Subcommand;
use clap::{Args, Parser};
use completions::{fig_generate, ArgShell};
use network_defaults::DEFAULT_WEBSOCKET_LISTENING_PORT;
use nymsphinx::addressing::clients::Recipient;
@@ -12,75 +15,93 @@ mod core;
mod statistics;
mod websocket;
const OPEN_PROXY_ARG: &str = "open-proxy";
const WS_PORT: &str = "websocket-port";
const ENABLE_STATISTICS: &str = "enable-statistics";
const STATISTICS_RECIPIENT: &str = "statistics-recipient";
fn parse_args() -> ArgMatches {
App::new("Nym Network Requester")
.version(env!("CARGO_PKG_VERSION"))
.author("Nymtech")
.arg(
Arg::with_name(OPEN_PROXY_ARG)
.help("specifies whether this network requester should run in 'open-proxy' mode")
.long(OPEN_PROXY_ARG)
.short('o'),
)
.arg(
Arg::with_name(WS_PORT)
.help("websocket port to bind to")
.long(WS_PORT)
.short('p')
.takes_value(true),
)
.arg(
Arg::with_name(ENABLE_STATISTICS)
.help("enable service anonymized statistics that get sent to a statistics aggregator server")
.long(ENABLE_STATISTICS),
)
.arg(
Arg::with_name(STATISTICS_RECIPIENT)
.help("mixnet client address where a statistics aggregator is running. The default value is a Nym aggregator client")
.long(STATISTICS_RECIPIENT)
.requires(ENABLE_STATISTICS)
.takes_value(true),
)
.get_matches()
#[derive(Args)]
struct Run {
/// Specifies whether this network requester should run in 'open-proxy' mode
open_proxy: bool,
/// Websocket port to bind to
websocket_port: Option<String>,
/// Enable service anonymized statistics that get sent to a statistics aggregator server
enable_statistics: bool,
/// Mixnet client address where a statistics aggregator is running. The default value is a Nym aggregator client
statistics_recipient: Option<String>,
}
impl Run {
async fn execute(&self) {
if self.open_proxy {
println!("\n\nYOU HAVE STARTED IN 'OPEN PROXY' MODE. ANYONE WITH YOUR CLIENT ADDRESS CAN MAKE REQUESTS FROM YOUR MACHINE. PLEASE QUIT IF YOU DON'T UNDERSTAND WHAT YOU'RE DOING.\n\n");
}
if self.enable_statistics {
println!("\n\nTHE NETWORK REQUESTER STATISTICS ARE ENABLED. IT WILL COLLECT AND SEND ANONYMIZED STATISTICS TO A CENTRAL SERVER. PLEASE QUIT IF YOU DON'T WANT THIS TO HAPPEN AND START WITHOUT THE {} FLAG .\n\n", ENABLE_STATISTICS);
}
let stats_provider_addr = self
.statistics_recipient
.as_ref()
.map(Recipient::try_from_base58_string)
.transpose()
.unwrap_or(None);
let uri = format!(
"ws://localhost:{}",
self.websocket_port
.as_ref()
.unwrap_or(&DEFAULT_WEBSOCKET_LISTENING_PORT.to_string())
);
println!("Starting socks5 service provider:");
let mut server = core::ServiceProvider::new(
uri,
self.open_proxy,
self.enable_statistics,
stats_provider_addr,
);
server.run().await;
}
}
#[derive(Subcommand)]
pub(crate) enum Commands {
/// Run network requester
Run(Run),
/// Generate shell completions
Completions(ArgShell),
/// Generate Fig specification
GenerateFigSpec,
}
#[derive(Parser)]
#[clap(author = "Nymtech", version, about)]
struct Cli {
#[clap(subcommand)]
command: Commands,
}
pub(crate) async fn execute(args: Cli) {
let bin_name = "nym-network-requester";
match &args.command {
Commands::Run(r) => r.execute().await,
Commands::Completions(s) => s.generate(&mut crate::Cli::into_app(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut crate::Cli::into_app(), bin_name),
}
}
#[tokio::main]
async fn main() {
setup_logging();
let matches = parse_args();
let args = Cli::parse();
let open_proxy = matches.is_present(OPEN_PROXY_ARG);
if open_proxy {
println!("\n\nYOU HAVE STARTED IN 'OPEN PROXY' MODE. ANYONE WITH YOUR CLIENT ADDRESS CAN MAKE REQUESTS FROM YOUR MACHINE. PLEASE QUIT IF YOU DON'T UNDERSTAND WHAT YOU'RE DOING.\n\n");
}
let enable_statistics = matches.is_present(ENABLE_STATISTICS);
if enable_statistics {
println!("\n\nTHE NETWORK REQUESTER STATISTICS ARE ENABLED. IT WILL COLLECT AND SEND ANONYMIZED STATISTICS TO A CENTRAL SERVER. PLEASE QUIT IF YOU DON'T WANT THIS TO HAPPEN AND START WITHOUT THE {} FLAG .\n\n", ENABLE_STATISTICS);
}
let stats_provider_addr = matches
.value_of(STATISTICS_RECIPIENT)
.map(Recipient::try_from_base58_string)
.transpose()
.unwrap_or(None);
let uri = format!(
"ws://localhost:{}",
matches
.value_of(WS_PORT)
.unwrap_or(&DEFAULT_WEBSOCKET_LISTENING_PORT.to_string())
);
println!("Starting socks5 service provider:");
let mut server =
core::ServiceProvider::new(uri, open_proxy, enable_statistics, stats_provider_addr);
server.run().await;
execute(args).await;
}
fn setup_logging() {
+3 -3
View File
@@ -7,9 +7,9 @@ edition = "2021"
[dependencies]
base64 = "0.13.0"
bs58 = "0.4"
clap = { version = "3.2.8", features = ["derive"] }
clap_complete = "3.2.4"
clap_complete_fig = "3.2.4"
clap = { version = "3.2", features = ["derive"] }
clap_complete = "3.2"
clap_complete_fig = "3.2"
dotenv = "0.15.0"
log = "0.4"
pretty_env_logger = "0.4"