From 2150c74aa37f61f6b7780935bbb6c40522201c8b Mon Sep 17 00:00:00 2001 From: Jose Quintana <1700322+joseluisq@users.noreply.github.com> Date: Mon, 5 Jun 2023 02:05:58 +0200 Subject: [PATCH] feat: support for boolean flags without explicit values (#215) the following boolean flag variants are now possible. Implicit example: static-web-server --root public/ --compression -z Explicit example (note the are no spaces in between): static-web-server --root public/ --compression=false -z Note also that this PR migrates to the latest clap v4. --- Cargo.lock | 261 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------------------------------------------------- Cargo.toml | 2 +- src/directory_listing.rs | 16 +++++++--------- src/server.rs | 2 +- src/settings/cli.rs | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------ src/settings/mod.rs | 4 ++-- 6 files changed, 278 insertions(+), 191 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e2c3d05..0fd3507 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,55 @@ dependencies = [ ] [[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + +[[package]] name = "anyhow" version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -79,17 +128,6 @@ dependencies = [ ] [[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -233,42 +271,51 @@ dependencies = [ [[package]] name = "clap" -version = "3.2.25" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +checksum = "b4ed2379f8603fa2b7509891660e802b88c70a79a6427a70abb5968054de2c28" dependencies = [ - "atty", - "bitflags", + "clap_builder", "clap_derive", - "clap_lex", - "indexmap", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72394f3339a76daf211e57d4bcb374410f3965dcc606dd0e03738c7888766980" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", "strsim", - "termcolor", - "textwrap", ] [[package]] name = "clap_derive" -version = "3.2.25" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +checksum = "59e9ef9a08ee1c0e1f2e162121665ac45ac3783b0f897db7244ae75ad9a8f65b" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.109", + "syn", ] [[package]] name = "clap_lex" -version = "0.2.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "core-foundation-sys" @@ -321,6 +368,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] name = "flate2" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -479,21 +547,18 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" dependencies = [ "libc", ] [[package]] name = "hermit-abi" -version = "0.2.6" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" [[package]] name = "http" @@ -615,6 +680,29 @@ dependencies = [ ] [[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] name = "itertools" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -666,6 +754,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] name = "listenfd" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -770,12 +864,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" [[package]] -name = "os_str_bytes" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" - -[[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -827,7 +915,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", ] [[package]] @@ -849,30 +937,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] name = "proc-macro2" version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -932,6 +996,20 @@ dependencies = [ ] [[package]] +name = "rustix" +version = "0.37.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] name = "rustls" version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1001,7 +1079,7 @@ checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", ] [[package]] @@ -1032,7 +1110,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", ] [[package]] @@ -1172,17 +1250,6 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" @@ -1193,21 +1260,6 @@ dependencies = [ ] [[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - -[[package]] name = "thread_local" version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1263,7 +1315,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", ] [[package]] @@ -1386,6 +1438,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] name = "uuid" version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1440,7 +1498,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.18", + "syn", "wasm-bindgen-shared", ] @@ -1462,7 +1520,7 @@ checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.18", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1506,15 +1564,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index bc9e4c5..da62d8f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ rustls-pemfile = { version = "1.0", optional = true } serde = { version = "1.0", default-features = false, features = ["derive"] } serde_ignored = "0.1" serde_repr = "0.1" -clap = { version = "3.0", features = ["derive", "env"] } +clap = { version = "4.3", features = ["derive", "env"] } chrono = { version = "0.4", default-features = false, features = ["std", "clock"] } tokio = { version = "1", default-features = false, features = ["rt-multi-thread", "macros", "fs", "io-util", "signal"] } tokio-rustls = { version = "0.24", optional = true } diff --git a/src/directory_listing.rs b/src/directory_listing.rs index 952db87..fb13ed5 100644 --- a/src/directory_listing.rs +++ b/src/directory_listing.rs @@ -9,7 +9,7 @@ #![allow(missing_docs)] use chrono::{DateTime, Local, NaiveDateTime, Utc}; -use clap::arg_enum; +use clap::ValueEnum; use futures_util::future::Either; use futures_util::{future, FutureExt}; use headers::{ContentLength, ContentType, HeaderMapExt}; @@ -25,14 +25,12 @@ use std::time::{SystemTime, UNIX_EPOCH}; use crate::{exts::http::MethodExt, Context, Result}; -arg_enum! { - #[derive(Debug, Serialize, Deserialize, Clone)] - #[serde(rename_all = "lowercase")] - /// Directory listing output format for file entries. - pub enum DirListFmt { - Html, - Json, - } +#[derive(Debug, Serialize, Deserialize, Clone, ValueEnum)] +#[serde(rename_all = "lowercase")] +/// Directory listing output format for file entries. +pub enum DirListFmt { + Html, + Json, } /// Provides directory listing support for the current request. diff --git a/src/server.rs b/src/server.rs index 93630b2..0fbbfe1 100644 --- a/src/server.rs +++ b/src/server.rs @@ -196,7 +196,7 @@ impl Server { // Directory listing format let dir_listing_format = general.directory_listing_format; - tracing::info!("directory listing format: {}", dir_listing_format); + tracing::info!("directory listing format: {:?}", dir_listing_format); // Cache control headers option let cache_control_headers = general.cache_control_headers; diff --git a/src/settings/cli.rs b/src/settings/cli.rs index aa2b896..d6e34fc 100644 --- a/src/settings/cli.rs +++ b/src/settings/cli.rs @@ -5,28 +5,28 @@ //! The server CLI options -use clap::StructOpt; +use clap::Parser; use std::path::PathBuf; use crate::directory_listing::DirListFmt; /// General server configuration available in CLI and config file options. -#[derive(Debug, StructOpt)] -#[structopt(about, author, version)] +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] pub struct General { - #[structopt(long, short = 'a', default_value = "::", env = "SERVER_HOST")] + #[arg(long, short = 'a', default_value = "::", env = "SERVER_HOST")] /// Host address (E.g 127.0.0.1 or ::1) pub host: String, - #[structopt(long, short = 'p', default_value = "80", env = "SERVER_PORT")] + #[arg(long, short = 'p', default_value = "80", env = "SERVER_PORT")] /// Host port pub port: u16, - #[structopt( + #[arg( long, short = 'f', env = "SERVER_LISTEN_FD", - conflicts_with_all(&["host", "port", "https-redirect"]) + conflicts_with_all(&["host", "port", "https_redirect"]) )] /// Instead of binding to a TCP port, accept incoming connections to an already-bound TCP /// socket listener on the specified file descriptor number (usually zero). Requires that the @@ -39,7 +39,7 @@ pub struct General { #[cfg_attr( not(wasm), - structopt( + arg( long, short = 'n', default_value = "1", @@ -48,7 +48,7 @@ pub struct General { )] #[cfg_attr( wasm, - structopt( + arg( long, short = 'n', default_value = "2", @@ -63,7 +63,7 @@ pub struct General { #[cfg_attr( not(wasm), - structopt( + arg( long, short = 'b', default_value = "512", @@ -72,7 +72,7 @@ pub struct General { )] #[cfg_attr( wasm, - structopt( + arg( long, short = 'b', default_value = "20", @@ -82,11 +82,11 @@ pub struct General { /// Maximum number of blocking threads pub max_blocking_threads: usize, - #[structopt(long, short = 'd', default_value = "./public", env = "SERVER_ROOT")] + #[arg(long, short = 'd', default_value = "./public", env = "SERVER_ROOT")] /// Root directory path of static files. pub root: PathBuf, - #[structopt( + #[arg( long, default_value = "./public/50x.html", env = "SERVER_ERROR_PAGE_50X" @@ -94,7 +94,7 @@ pub struct General { /// HTML file path for 50x errors. If the path is not specified or simply doesn't exist then the server will use a generic HTML error message. pub page50x: PathBuf, - #[structopt( + #[arg( long, default_value = "./public/404.html", env = "SERVER_ERROR_PAGE_404" @@ -102,15 +102,15 @@ pub struct General { /// HTML file path for 404 errors. If the path is not specified or simply doesn't exist then the server will use a generic HTML error message. pub page404: PathBuf, - #[structopt(long, env = "SERVER_FALLBACK_PAGE")] + #[arg(long, env = "SERVER_FALLBACK_PAGE")] /// HTML file path that is used for GET requests when the requested path doesn't exist. The fallback page is served with a 200 status code, useful when using client routers. If the path is not specified or simply doesn't exist then this feature will not be active. pub page_fallback: Option, - #[structopt(long, short = 'g', default_value = "error", env = "SERVER_LOG_LEVEL")] + #[arg(long, short = 'g', default_value = "error", env = "SERVER_LOG_LEVEL")] /// Specify a logging level in lower case. Values: error, warn, info, debug or trace pub log_level: String, - #[structopt( + #[arg( long, short = 'c', default_value = "", @@ -119,7 +119,7 @@ pub struct General { /// Specify an optional CORS list of allowed origin hosts separated by commas. Host ports or protocols aren't being checked. Use an asterisk (*) to allow any host. pub cors_allow_origins: String, - #[structopt( + #[arg( long, short = 'j', default_value = "origin, content-type", @@ -128,7 +128,7 @@ pub struct General { /// Specify an optional CORS list of allowed headers separated by commas. Default "origin, content-type". It requires `--cors-allow-origins` to be used along with. pub cors_allow_headers: String, - #[structopt( + #[arg( long, default_value = "origin, content-type", env = "SERVER_CORS_EXPOSE_HEADERS" @@ -136,35 +136,41 @@ pub struct General { /// Specify an optional CORS list of exposed headers separated by commas. Default "origin, content-type". It requires `--cors-expose-origins` to be used along with. pub cors_expose_headers: String, - #[structopt( + #[arg( long, short = 't', - parse(try_from_str), default_value = "false", - env = "SERVER_HTTP2_TLS" + default_missing_value("true"), + num_args(0..=1), + require_equals(true), + action = clap::ArgAction::Set, + env = "SERVER_HTTP2_TLS", )] #[cfg(feature = "http2")] #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] /// Enable HTTP/2 with TLS support. pub http2: bool, - #[structopt(long, required_if_eq("http2", "true"), env = "SERVER_HTTP2_TLS_CERT")] + #[arg(long, required_if_eq("http2", "true"), env = "SERVER_HTTP2_TLS_CERT")] #[cfg(feature = "http2")] #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] /// Specify the file path to read the certificate. pub http2_tls_cert: Option, - #[structopt(long, required_if_eq("http2", "true"), env = "SERVER_HTTP2_TLS_KEY")] + #[arg(long, required_if_eq("http2", "true"), env = "SERVER_HTTP2_TLS_KEY")] #[cfg(feature = "http2")] #[cfg_attr(docsrs, doc(cfg(feature = "http2")))] /// Specify the file path to read the private key. pub http2_tls_key: Option, - #[structopt( + #[arg( long, - requires_if("true", "http2"), - parse(try_from_str), default_value = "false", + default_missing_value("true"), + num_args(0..=1), + require_equals(true), + action = clap::ArgAction::Set, + requires_if("true", "http2"), env = "SERVER_HTTPS_REDIRECT" )] #[cfg(feature = "http2")] @@ -172,9 +178,9 @@ pub struct General { /// Redirect all requests with scheme "http" to "https" for the current server instance. It depends on "http2" to be enabled. pub https_redirect: bool, - #[structopt( + #[arg( long, - requires_if("true", "https-redirect"), + requires_if("true", "https_redirect"), default_value = "localhost", env = "SERVER_HTTPS_REDIRECT_HOST" )] @@ -183,9 +189,9 @@ pub struct General { /// Canonical host name or IP of the HTTPS (HTTPS/2) server. It depends on "https_redirect" to be enabled. pub https_redirect_host: String, - #[structopt( + #[arg( long, - requires_if("true", "https-redirect"), + requires_if("true", "https_redirect"), default_value = "80", env = "SERVER_HTTPS_REDIRECT_FROM_PORT" )] @@ -194,9 +200,9 @@ pub struct General { /// HTTP host port where the redirect server will listen for requests to redirect them to HTTPS. It depends on "https_redirect" to be enabled. pub https_redirect_from_port: u16, - #[structopt( + #[arg( long, - requires_if("true", "https-redirect"), + requires_if("true", "https_redirect"), default_value = "localhost", env = "SERVER_HTTPS_REDIRECT_FROM_HOSTS" )] @@ -207,114 +213,145 @@ pub struct General { #[cfg(feature = "compression")] #[cfg_attr(docsrs, doc(cfg(feature = "compression")))] - #[structopt( + #[arg( long, short = 'x', - parse(try_from_str), default_value = "true", - env = "SERVER_COMPRESSION" + default_missing_value("true"), + num_args(0..=1), + require_equals(true), + action = clap::ArgAction::Set, + env = "SERVER_COMPRESSION", )] /// Gzip, Deflate, Brotli or Zstd compression on demand determined by the Accept-Encoding header and applied to text-based web file types only. pub compression: bool, #[cfg(feature = "compression")] #[cfg_attr(docsrs, doc(cfg(feature = "compression")))] - #[structopt( + #[arg( long, - parse(try_from_str), default_value = "false", - env = "SERVER_COMPRESSION_STATIC" + default_missing_value("true"), + num_args(0..=1), + require_equals(true), + action = clap::ArgAction::Set, + env = "SERVER_COMPRESSION_STATIC", )] /// Look up the pre-compressed file variant (`.gz`, `.br` or `.zst`) on disk of a requested file and serves it directly if available. /// The compression type is determined by the `Accept-Encoding` header. pub compression_static: bool, - #[structopt( + #[arg( long, short = 'z', - parse(try_from_str), default_value = "false", - env = "SERVER_DIRECTORY_LISTING" + default_missing_value("true"), + num_args(0..=1), + require_equals(true), + action = clap::ArgAction::Set, + env = "SERVER_DIRECTORY_LISTING", )] /// Enable directory listing for all requests ending with the slash character (‘/’). pub directory_listing: bool, - #[structopt( + #[arg( long, - required_if_eq("directory-listing", "true"), + requires_if("true", "directory_listing"), default_value = "6", env = "SERVER_DIRECTORY_LISTING_ORDER" )] /// Specify a default code number to order directory listing entries per `Name`, `Last modified` or `Size` attributes (columns). Code numbers supported: 0 (Name asc), 1 (Name desc), 2 (Last modified asc), 3 (Last modified desc), 4 (Size asc), 5 (Size desc). Default 6 (unordered) pub directory_listing_order: u8, - #[structopt( + #[arg( long, - required_if_eq("directory-listing", "true"), + value_enum, + requires_if("true", "directory_listing"), default_value = "html", env = "SERVER_DIRECTORY_LISTING_FORMAT", - case_insensitive = true + ignore_case(true) )] /// Specify a content format for directory listing entries. Formats supported: "html" or "json". Default "html". pub directory_listing_format: DirListFmt, - #[structopt( + #[arg( long, - parse(try_from_str), - default_value_if("http2", Some("true"), Some("true")), default_value = "false", - env = "SERVER_SECURITY_HEADERS" + default_value_if("http2", "true", Some("true")), + default_missing_value("true"), + num_args(0..=1), + require_equals(true), + action = clap::ArgAction::Set, + env = "SERVER_SECURITY_HEADERS", )] /// Enable security headers by default when HTTP/2 feature is activated. /// Headers included: "Strict-Transport-Security: max-age=63072000; includeSubDomains; preload" (2 years max-age), /// "X-Frame-Options: DENY", "X-XSS-Protection: 1; mode=block" and "Content-Security-Policy: frame-ancestors 'self'". pub security_headers: bool, - #[structopt( + #[arg( long, short = 'e', - parse(try_from_str), default_value = "true", env = "SERVER_CACHE_CONTROL_HEADERS" )] + #[arg( + long, + short = 'e', + default_value = "true", + default_missing_value("true"), + num_args(0..=1), + require_equals(true), + action = clap::ArgAction::Set, + env = "SERVER_CACHE_CONTROL_HEADERS", + )] /// Enable cache control headers for incoming requests based on a set of file types. The file type list can be found on `src/control_headers.rs` file. pub cache_control_headers: bool, /// It provides The "Basic" HTTP Authentication scheme using credentials as "user-id:password" pairs. Password must be encoded using the "BCrypt" password-hashing function. - #[structopt(long, default_value = "", env = "SERVER_BASIC_AUTH")] + #[arg(long, default_value = "", env = "SERVER_BASIC_AUTH")] pub basic_auth: String, - #[structopt(long, short = 'q', default_value = "0", env = "SERVER_GRACE_PERIOD")] + #[arg(long, short = 'q', default_value = "0", env = "SERVER_GRACE_PERIOD")] /// Defines a grace period in seconds after a `SIGTERM` signal is caught which will delay the server before to shut it down gracefully. The maximum value is 255 seconds. pub grace_period: u8, - #[structopt(long, short = 'w', env = "SERVER_CONFIG_FILE")] + #[arg(long, short = 'w', env = "SERVER_CONFIG_FILE")] /// Server TOML configuration file path. pub config_file: Option, - #[structopt( + #[arg( long, - parse(try_from_str), default_value = "false", - env = "SERVER_LOG_REMOTE_ADDRESS" + default_missing_value("true"), + num_args(0..=1), + require_equals(true), + action = clap::ArgAction::Set, + env = "SERVER_LOG_REMOTE_ADDRESS", )] /// Log incoming requests information along with its remote address if available using the `info` log level. pub log_remote_address: bool, - #[structopt( + #[arg( long, - parse(try_from_str), default_value = "true", - env = "SERVER_REDIRECT_TRAILING_SLASH" + default_missing_value("true"), + num_args(0..=1), + require_equals(true), + action = clap::ArgAction::Set, + env = "SERVER_REDIRECT_TRAILING_SLASH", )] /// Check for a trailing slash in the requested directory URI and redirect permanently (308) to the same path with a trailing slash suffix if it is missing. pub redirect_trailing_slash: bool, - #[structopt( + #[arg( long, - parse(try_from_str), default_value = "false", - env = "SERVER_IGNORE_HIDDEN_FILES" + default_missing_value("true"), + num_args(0..=1), + require_equals(true), + action = clap::ArgAction::Set, + env = "SERVER_IGNORE_HIDDEN_FILES", )] /// Ignore hidden files/directories (dotfiles), preventing them to be served and being included in auto HTML index pages (directory listing). pub ignore_hidden_files: bool, @@ -323,32 +360,35 @@ pub struct General { // Windows specific arguments and commands // #[cfg(windows)] - #[structopt( + #[arg( long, short = 's', - parse(try_from_str), default_value = "false", - env = "SERVER_WINDOWS_SERVICE" + default_missing_value("true"), + num_args(0..=1), + require_equals(true), + action = clap::ArgAction::Set, + env = "SERVER_WINDOWS_SERVICE", )] /// Tell the web server to run in a Windows Service context. Note that the `install` subcommand will enable this option automatically. pub windows_service: bool, // Windows commands #[cfg(windows)] - #[structopt(subcommand)] + #[command(subcommand)] /// Subcommands to install or uninstall the SWS Windows Service. pub commands: Option, } #[cfg(windows)] -#[derive(Debug, StructOpt)] +#[derive(Debug, clap::Subcommand)] /// Subcommands to install or uninstall the SWS Windows Service. pub enum Commands { /// Install a Windows Service for the web server. - #[structopt(name = "install")] + #[command(name = "install")] Install {}, /// Uninstall the current Windows Service. - #[structopt(name = "uninstall")] + #[command(name = "uninstall")] Uninstall {}, } diff --git a/src/settings/mod.rs b/src/settings/mod.rs index bf94bd8..746d9d7 100644 --- a/src/settings/mod.rs +++ b/src/settings/mod.rs @@ -6,7 +6,7 @@ //! Module that provides all settings of SWS. //! -use clap::StructOpt; +use clap::Parser; use globset::{Glob, GlobMatcher}; use headers::HeaderMap; use hyper::StatusCode; @@ -68,7 +68,7 @@ pub struct Settings { impl Settings { /// Handles CLI and config file options and converging them into one. pub fn get() -> Result { - let opts = General::from_args(); + let opts = General::parse(); // Define the general CLI/file options let mut host = opts.host; -- libgit2 1.7.2