diff options
-rw-r--r-- | CHANGELOG.md | 3 | ||||
-rw-r--r-- | Cargo.lock | 112 | ||||
-rw-r--r-- | Cargo.toml | 3 | ||||
-rw-r--r-- | README.md | 91 | ||||
-rw-r--r-- | src/args.rs | 75 | ||||
-rw-r--r-- | src/main.rs | 23 | ||||
-rw-r--r-- | src/renderer.rs | 2 | ||||
-rw-r--r-- | tests/cli.rs | 3 |
8 files changed, 198 insertions, 114 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index de21ba6..f583251 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Fix behavior of downloading symlinks by upgrading to actix-web 4 [#582](https://github.com/svenstaro/miniserve/pull/582) [#462](https://github.com/svenstaro/miniserve/issues/462) (thanks @aliemjay) - List directory if index file not found [#583](https://github.com/svenstaro/miniserve/pull/583) [#275](https://github.com/svenstaro/miniserve/pull/583) (thanks @aliemjay) - Add special colors for visited links [#521](https://github.com/svenstaro/miniserve/pull/521) (thanks @raffomania) +- Switch from structopt to clap v3 [#587](https://github.com/svenstaro/miniserve/pull/587) + + This enables slightly nicer help output as well as much better completions. ## [0.15.0] - 2021-08-27 - Add hardened systemd template unit file to `packaging/miniserve@.service` @@ -551,13 +551,54 @@ dependencies = [ "ansi_term 0.11.0", "atty", "bitflags", - "strsim", - "textwrap", + "strsim 0.8.0", + "textwrap 0.11.0", "unicode-width", "vec_map", ] [[package]] +name = "clap" +version = "3.0.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcd70aa5597dbc42f7217a543f9ef2768b2ef823ba29036072d30e1d88e98406" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim 0.10.0", + "termcolor", + "terminal_size", + "textwrap 0.14.2", + "vec_map", +] + +[[package]] +name = "clap_derive" +version = "3.0.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5bb0d655624a0b8770d1c178fb8ffcb1f91cc722cb08f451e3dc72465421ac" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_generate" +version = "3.0.0-beta.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d9b1abef93569f290952eff3c4a0a92d6767bb5158db095b4dc9a512b1c3643" +dependencies = [ + "clap 3.0.0-beta.4", +] + +[[package]] name = "codemap" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -901,7 +942,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82317908bc4204532d098390f8e041693aaeab95cf7351f774bdacf253b1c8ed" dependencies = [ "beef", - "clap", + "clap 2.33.3", "codemap", "indexmap", "lasso", @@ -1174,9 +1215,9 @@ checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" [[package]] name = "libflate" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d87eae36b3f680f7f01645121b782798b56ef33c53f83d1c66ba3a22b60bfe3" +checksum = "16364af76ebb39b5869bb32c81fa93573267cd8c62bb3474e28d78fac3fb141e" dependencies = [ "adler32", "crc32fast", @@ -1333,6 +1374,8 @@ dependencies = [ "bytesize", "chrono", "chrono-humanize", + "clap 3.0.0-beta.4", + "clap_generate", "futures", "grass", "hex", @@ -1356,7 +1399,6 @@ dependencies = [ "serde", "sha2", "simplelog", - "structopt", "strum", "strum_macros", "tar", @@ -1493,6 +1535,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] +name = "os_str_bytes" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6acbef58a60fe69ab50510a55bc8cdd4d6cf2283d27ad338f54cb52747a9cf2d" + +[[package]] name = "output_vt100" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2329,28 +2377,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] -name = "structopt" -version = "0.3.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69b041cdcb67226aca307e6e7be44c8806423d83e018bd662360a93dabce4d71" -dependencies = [ - "clap", - "lazy_static", - "structopt-derive", -] - -[[package]] -name = "structopt-derive" -version = "0.4.15" +name = "strsim" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7813934aecf5f51a54775e00068c237de98489463968231a51746bbbc03f9c10" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "strum" @@ -2427,6 +2457,16 @@ dependencies = [ ] [[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + +[[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2436,19 +2476,29 @@ dependencies = [ ] [[package]] +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" +dependencies = [ + "terminal_size", + "unicode-width", +] + +[[package]] name = "thiserror" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1c319f97498ee34e17e1d7813fcd28a0ec1aaf350a4c44883d2fe741edb1c70" +checksum = "283d5230e63df9608ac7d9691adc1dfb6e701225436eb64d0b9a7f0a5a04f6ec" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf955fbafde33573fd32e90312488fa2ea68f7a220a5faab1809fa90690224f" +checksum = "fa3884228611f5cd3608e2d409bf7dce832e4eb3135e3f11addbd7e41bd68e71" dependencies = [ "proc-macro2", "quote", @@ -30,7 +30,8 @@ port_check = "0.1" bytesize = "1" nanoid = "0.4" alphanumeric-sort = "1" -structopt = "0.3" +clap = { version = "3.0.0-beta.4", features = ["wrap_help"] } +clap_generate = "3.0.0-beta.4" chrono = "0.4" chrono-humanize = "0.2" serde = { version = "1", features = ["derive"] } @@ -79,101 +79,108 @@ Sometimes this is just a more practical and quick way than doing things properly ## Usage - miniserve 0.15.0 + miniserve 0.15.1-alpha.0 + Sven-Hendrik Haase <svenstaro@gmail.com>, Boastful Squirrel <boastful.squirrel@gmail.com> + For when you really just want to serve some files over HTTP right now! USAGE: miniserve [FLAGS] [OPTIONS] [--] [PATH] + ARGS: + <PATH> + Which path to serve + FLAGS: -D, --dirs-first List directories first - -r, --enable-tar - Enable uncompressed tar archive generation + -F, --hide-version-footer + Hide version footer -g, --enable-tar-gz Enable gz-compressed tar archive generation - -z, --enable-zip - Enable zip archive generation - - WARNING: Zipping large directories can result in out-of-memory exception because zip generation is done in - memory and cannot be sent on the fly - -u, --upload-files - Enable file uploading - -h, --help - Prints help information + Print help information -H, --hidden Show hidden files - -F, --hide-version-footer - Hide version footer + -o, --overwrite-files + Enable overriding existing files during file upload -P, --no-symlinks Do not follow symbolic links - -o, --overwrite-files - Enable overriding existing files during file upload - -q, --qrcode Enable QR code display + -r, --enable-tar + Enable uncompressed tar archive generation + --random-route Generate a random 6-hexdigit route - -V, --version - Prints version information + -u, --upload-files + Enable file uploading -v, --verbose Be verbose, includes emitting access logs + -V, --version + Print version information + + -z, --enable-zip + Enable zip archive generation + + WARNING: Zipping large directories can result in out-of-memory exception because zip + generation is done in memory and cannot be sent on the fly OPTIONS: - -a, --auth <auth>... - Set authentication. Currently supported formats: username:password, username:sha256:hash, - username:sha512:hash (e.g. joe:123, + -a, --auth <AUTH>... + Set authentication. Currently supported formats: username:password, + username:sha256:hash, username:sha512:hash (e.g. joe:123, joe:sha256:a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3) - -c, --color-scheme <color-scheme> - Default color scheme [default: squirrel] [possible values: squirrel, archlinux, + + -c, --color-scheme <COLOR_SCHEME> + Default color scheme [default: squirrel] [possible values: squirrel, archlinux, zenburn, monokai] - -d, --color-scheme-dark <color-scheme-dark> - Default color scheme [default: archlinux] [possible values: squirrel, archlinux, + + -d, --color-scheme-dark <COLOR_SCHEME_DARK> + Default color scheme [default: archlinux] [possible values: squirrel, archlinux, zenburn, monokai] - --header <header>... + + --header <HEADER>... Set custom header for responses + -i, --interfaces <INTERFACES>... + Interface to listen on + --index <index_file> The name of a directory index file to serve, like "index.html" - Normally, when miniserve serves a directory, it creates a listing for that directory. However, if a - directory contains this file, miniserve will serve that file instead. - -i, --interfaces <interfaces>... - Interface to listen on + Normally, when miniserve serves a directory, it creates a listing for that + directory. However, if a directory contains this file, miniserve will serve that + file instead. - -p, --port <port> + -p, --port <PORT> Port to use [default: 8080] --print-completions <shell> - Generate completion file for a shell [possible values: zsh, bash, fish, - powershell, elvish] - -t, --title <title> + Generate completion file for a shell [possible values: bash, elvish, fish, + powershell, zsh] + + -t, --title <TITLE> Shown instead of host in page title and heading - --tls-cert <tls-cert> + --tls-cert <TLS_CERT> TLS certificate to use - --tls-key <tls-key> + --tls-key <TLS_KEY> TLS private key to use - - ARGS: - <PATH> - Which path to serve - ## How to install <a href="https://repology.org/project/miniserve/versions"><img align="right" src="https://repology.org/badge/vertical-allrepos/miniserve.svg" alt="Packaging status"></a> diff --git a/src/args.rs b/src/args.rs index cea5658..9569ca3 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,45 +1,48 @@ use bytes::Bytes; +use clap::{Clap, ValueHint}; +use clap_generate::Shell; use http::header::{HeaderMap, HeaderName, HeaderValue}; use std::net::IpAddr; use std::path::PathBuf; -use structopt::StructOpt; use crate::auth; use crate::errors::ContextualError; use crate::renderer; -#[derive(StructOpt)] -#[structopt( +#[derive(Clap)] +#[clap( name = "miniserve", author, about, - global_settings = &[structopt::clap::AppSettings::ColoredHelp], + version, + setting = clap::AppSettings::ColoredHelp, )] pub struct CliArgs { /// Be verbose, includes emitting access logs - #[structopt(short = "v", long = "verbose")] + #[clap(short = 'v', long = "verbose")] pub verbose: bool, /// Which path to serve - #[structopt(name = "PATH", parse(from_os_str))] + #[clap(name = "PATH", parse(from_os_str), value_hint = ValueHint::AnyPath)] pub path: Option<PathBuf>, /// The name of a directory index file to serve, like "index.html" /// /// Normally, when miniserve serves a directory, it creates a listing for that directory. /// However, if a directory contains this file, miniserve will serve that file instead. - #[structopt(long, parse(from_os_str), name = "index_file")] + #[clap(long, parse(from_os_str), name = "index_file", value_hint = ValueHint::FilePath)] pub index: Option<PathBuf>, /// Port to use - #[structopt(short = "p", long = "port", default_value = "8080")] + #[clap(short = 'p', long = "port", default_value = "8080")] pub port: u16, /// Interface to listen on - #[structopt( - short = "i", + #[clap( + short = 'i', long = "interfaces", parse(try_from_str = parse_interface), + multiple_occurrences(true), number_of_values = 1, )] pub interfaces: Vec<IpAddr>, @@ -47,29 +50,30 @@ pub struct CliArgs { /// Set authentication. Currently supported formats: /// username:password, username:sha256:hash, username:sha512:hash /// (e.g. joe:123, joe:sha256:a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3) - #[structopt( - short = "a", + #[clap( + short = 'a', long = "auth", parse(try_from_str = parse_auth), + multiple_occurrences(true), number_of_values = 1, )] pub auth: Vec<auth::RequiredAuth>, /// Generate a random 6-hexdigit route - #[structopt(long = "random-route")] + #[clap(long = "random-route")] pub random_route: bool, /// Do not follow symbolic links - #[structopt(short = "P", long = "no-symlinks")] + #[clap(short = 'P', long = "no-symlinks")] pub no_symlinks: bool, /// Show hidden files - #[structopt(short = "H", long = "hidden")] + #[clap(short = 'H', long = "hidden")] pub hidden: bool, /// Default color scheme - #[structopt( - short = "c", + #[clap( + short = 'c', long = "color-scheme", default_value = "squirrel", possible_values = &renderer::THEME_SLUGS, @@ -78,8 +82,8 @@ pub struct CliArgs { pub color_scheme: String, /// Default color scheme - #[structopt( - short = "d", + #[clap( + short = 'd', long = "color-scheme-dark", default_value = "archlinux", possible_values = &renderer::THEME_SLUGS, @@ -88,60 +92,65 @@ pub struct CliArgs { pub color_scheme_dark: String, /// Enable QR code display - #[structopt(short = "q", long = "qrcode")] + #[clap(short = 'q', long = "qrcode")] pub qrcode: bool, /// Enable file uploading - #[structopt(short = "u", long = "upload-files")] + #[clap(short = 'u', long = "upload-files")] pub file_upload: bool, /// Enable overriding existing files during file upload - #[structopt(short = "o", long = "overwrite-files")] + #[clap(short = 'o', long = "overwrite-files")] pub overwrite_files: bool, /// Enable uncompressed tar archive generation - #[structopt(short = "r", long = "enable-tar")] + #[clap(short = 'r', long = "enable-tar")] pub enable_tar: bool, /// Enable gz-compressed tar archive generation - #[structopt(short = "g", long = "enable-tar-gz")] + #[clap(short = 'g', long = "enable-tar-gz")] pub enable_tar_gz: bool, /// Enable zip archive generation /// /// WARNING: Zipping large directories can result in out-of-memory exception /// because zip generation is done in memory and cannot be sent on the fly - #[structopt(short = "z", long = "enable-zip")] + #[clap(short = 'z', long = "enable-zip")] pub enable_zip: bool, /// List directories first - #[structopt(short = "D", long = "dirs-first")] + #[clap(short = 'D', long = "dirs-first")] pub dirs_first: bool, /// Shown instead of host in page title and heading - #[structopt(short = "t", long = "title")] + #[clap(short = 't', long = "title")] pub title: Option<String>, /// Set custom header for responses - #[structopt(long = "header", parse(try_from_str = parse_header), number_of_values = 1)] + #[clap( + long = "header", + parse(try_from_str = parse_header), + multiple_occurrences(true), + number_of_values = 1 + )] pub header: Vec<HeaderMap>, /// Hide version footer - #[structopt(short = "F", long = "hide-version-footer")] + #[clap(short = 'F', long = "hide-version-footer")] pub hide_version_footer: bool, /// Generate completion file for a shell - #[structopt(long = "print-completions", value_name = "shell", possible_values = &structopt::clap::Shell::variants())] - pub print_completions: Option<structopt::clap::Shell>, + #[clap(long = "print-completions", value_name = "shell", possible_values = &Shell::variants())] + pub print_completions: Option<Shell>, /// TLS certificate to use #[cfg(feature = "tls")] - #[structopt(long = "tls-cert", requires = "tls-key")] + #[clap(long = "tls-cert", requires = "tls-key", value_hint = ValueHint::FilePath)] pub tls_cert: Option<PathBuf>, /// TLS private key to use #[cfg(feature = "tls")] - #[structopt(long = "tls-key", requires = "tls-cert")] + #[clap(long = "tls-key", requires = "tls-cert", value_hint = ValueHint::FilePath)] pub tls_key: Option<PathBuf>, } diff --git a/src/main.rs b/src/main.rs index 398f580..c1d17b4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,10 +10,11 @@ use actix_web::{ Responder, }; use actix_web::{middleware, App, HttpRequest, HttpResponse}; -use anyhow::Result; +use anyhow::{bail, Result}; +use clap::{crate_version, Clap, IntoApp}; +use clap_generate::generators::{Bash, Elvish, Fish, PowerShell, Zsh}; +use clap_generate::{generate, Shell}; use log::{error, warn}; -use structopt::clap::crate_version; -use structopt::StructOpt; use yansi::{Color, Paint}; mod archive; @@ -30,10 +31,22 @@ use crate::config::MiniserveConfig; use crate::errors::ContextualError; fn main() -> Result<()> { - let args = args::CliArgs::from_args(); + let args = args::CliArgs::parse(); if let Some(shell) = args.print_completions { - args::CliArgs::clap().gen_completions_to("miniserve", shell, &mut std::io::stdout()); + let mut clap_app = args::CliArgs::into_app(); + match shell { + Shell::Bash => generate::<Bash, _>(&mut clap_app, "miniserve", &mut std::io::stdout()), + Shell::Elvish => { + generate::<Elvish, _>(&mut clap_app, "miniserve", &mut std::io::stdout()) + } + Shell::Fish => generate::<Fish, _>(&mut clap_app, "miniserve", &mut std::io::stdout()), + Shell::PowerShell => { + generate::<PowerShell, _>(&mut clap_app, "miniserve", &mut std::io::stdout()) + } + Shell::Zsh => generate::<Zsh, _>(&mut clap_app, "miniserve", &mut std::io::stdout()), + _ => bail!("Invalid shell provided!"), + } return Ok(()); } diff --git a/src/renderer.rs b/src/renderer.rs index 66f0291..901bf66 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,9 +1,9 @@ use actix_web::http::StatusCode; use chrono::{DateTime, Utc}; use chrono_humanize::Humanize; +use clap::{crate_name, crate_version}; use maud::{html, Markup, PreEscaped, DOCTYPE}; use std::time::SystemTime; -use structopt::clap::{crate_name, crate_version}; use strum::IntoEnumIterator; use crate::archive::ArchiveMethod; diff --git a/tests/cli.rs b/tests/cli.rs index f88b284..8c88c93 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -1,9 +1,10 @@ mod fixtures; use assert_cmd::prelude::*; +use clap::{crate_name, crate_version}; +use clap_generate::Shell; use fixtures::Error; use std::process::Command; -use structopt::clap::{crate_name, crate_version, Shell}; #[test] /// Show help and exit. |