aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md3
-rw-r--r--Cargo.lock112
-rw-r--r--Cargo.toml3
-rw-r--r--README.md91
-rw-r--r--src/args.rs75
-rw-r--r--src/main.rs23
-rw-r--r--src/renderer.rs2
-rw-r--r--tests/cli.rs3
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`
diff --git a/Cargo.lock b/Cargo.lock
index ec29418..2be4620 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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",
diff --git a/Cargo.toml b/Cargo.toml
index 72e82b9..4efc015 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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"] }
diff --git a/README.md b/README.md
index ba007e2..a481b67 100644
--- a/README.md
+++ b/README.md
@@ -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.