diff options
author | Sven-Hendrik Haase <svenstaro@gmail.com> | 2019-02-16 20:40:19 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-16 20:40:19 +0000 |
commit | 9c4e46fa570e6e4498f3d9643cc4627705c53e5a (patch) | |
tree | cf4efcc073766edb3b1bb6529be4c3f0ae8ada83 /src/args.rs | |
parent | Add rsync to alpine image to allow for syncing files into it (diff) | |
parent | Updated README (diff) | |
download | miniserve-9c4e46fa570e6e4498f3d9643cc4627705c53e5a.tar.gz miniserve-9c4e46fa570e6e4498f3d9643cc4627705c53e5a.zip |
Merge pull request #35 from boastful-squirrel/structopt
Switched to structopt
Diffstat (limited to 'src/args.rs')
-rw-r--r-- | src/args.rs | 217 |
1 files changed, 83 insertions, 134 deletions
diff --git a/src/args.rs b/src/args.rs index ae86108..637c224 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,173 +1,122 @@ -use crate::auth; -use crate::listing; -use clap::{crate_authors, crate_description, crate_name, crate_version}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::path::PathBuf; +use structopt::StructOpt; + +use crate::auth; +use crate::listing; /// Possible characters for random routes const ROUTE_ALPHABET: [char; 16] = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', ]; -/// Checks wether a path is valid, i.e. it exists on the system and points to a file/directory -fn is_valid_path(path: String) -> Result<(), String> { - let path_to_check = PathBuf::from(path); - if path_to_check.is_file() || path_to_check.is_dir() { - return Ok(()); - } - Err(String::from( - "Path either doesn't exist or is not a regular file or a directory", - )) -} +#[derive(StructOpt, Debug)] +#[structopt( + name = "miniserve", + raw(global_settings = "&[structopt::clap::AppSettings::ColoredHelp]") +)] +struct CLIArgs { + /// Be verbose, includes emitting access logs + #[structopt(short = "v", long = "verbose")] + verbose: bool, -/// Checks wether a port is valid -fn is_valid_port(port: String) -> Result<(), String> { - port.parse::<u16>() - .and(Ok(())) - .or_else(|e| Err(e.to_string())) -} + /// Which path to serve + #[structopt(name = "PATH", parse(from_os_str))] + path: Option<PathBuf>, + + /// Port to use + #[structopt(short = "p", long = "port", default_value = "8080")] + port: u16, + /// Interface to listen on + #[structopt( + short = "i", + long = "if", + parse(try_from_str = "parse_interface"), + raw(number_of_values = "1") + )] + interfaces: Vec<IpAddr>, + + /// Set authentication (username:password) + #[structopt(short = "a", long = "auth", parse(try_from_str = "parse_auth"))] + auth: Option<(String, String)>, + + /// Generate a random 6-hexdigit route + #[structopt(long = "random-route")] + random_route: bool, + + /// Sort files + #[structopt( + short = "s", + long = "sort", + raw( + possible_values = "&listing::SortingMethods::variants()", + case_insensitive = "true" + ) + )] + sort_method: Option<listing::SortingMethods>, + + /// Reverse sorting + #[structopt(long = "reverse")] + reverse_sort: bool, + + /// Do not follow symbolic links + #[structopt(short = "P", long = "no-symlinks")] + no_symlinks: bool, +} /// Checks wether an interface is valid, i.e. it can be parsed into an IP address -fn is_valid_interface(interface: String) -> Result<(), String> { - interface - .parse::<IpAddr>() - .and(Ok(())) - .or_else(|e| Err(e.to_string())) +fn parse_interface(src: &str) -> Result<IpAddr, std::net::AddrParseError> { + src.parse::<IpAddr>() } /// Checks wether the auth string is valid, i.e. it follows the syntax username:password -fn is_valid_auth(auth: String) -> Result<(), String> { - auth.find(':') - .ok_or_else(|| "Correct format is username:password".to_owned()) - .map(|_| ()) +fn parse_auth(src: &str) -> Result<(String, String), String> { + match src.find(':') { + Some(_) => { + let split = src.split(':').collect::<Vec<_>>(); + Ok((split[0].to_owned(), split[1].to_owned())) + } + None => Err("Correct format is username:password".to_owned()), + } } /// Parses the command line arguments pub fn parse_args() -> crate::MiniserveConfig { - use clap::{App, AppSettings, Arg}; - - let matches = App::new(crate_name!()) - .version(crate_version!()) - .author(crate_authors!()) - .about(crate_description!()) - .global_setting(AppSettings::ColoredHelp) - .arg( - Arg::with_name("verbose") - .short("v") - .long("verbose") - .help("Be verbose, includes emitting access logs"), - ) - .arg( - Arg::with_name("PATH") - .required(false) - .validator(is_valid_path) - .help("Which path to serve"), - ) - .arg( - Arg::with_name("port") - .short("p") - .long("port") - .help("Port to use") - .validator(is_valid_port) - .required(false) - .default_value("8080") - .takes_value(true), - ) - .arg( - Arg::with_name("interfaces") - .short("i") - .long("if") - .help("Interface to listen on") - .validator(is_valid_interface) - .required(false) - .takes_value(true) - .multiple(true), - ) - .arg( - Arg::with_name("auth") - .short("a") - .long("auth") - .validator(is_valid_auth) - .help("Set authentication (username:password)") - .takes_value(true), - ) - .arg( - Arg::with_name("random-route") - .long("random-route") - .help("Generate a random 6-hexdigit route"), - ) - .arg( - Arg::with_name("sort") - .short("s") - .long("sort") - .possible_values(&["natural", "alpha", "dirsfirst"]) - .default_value("natural") - .help("Sort files"), - ) - .arg( - Arg::with_name("reverse") - .long("reverse") - .help("Reverse sorting order"), - ) - .arg( - Arg::with_name("no-symlinks") - .short("P") - .long("no-symlinks") - .help("Do not follow symbolic links"), - ) - .get_matches(); - - let verbose = matches.is_present("verbose"); - let no_symlinks = matches.is_present("no-symlinks"); - let path = matches.value_of("PATH"); - let port = matches.value_of("port").unwrap().parse().unwrap(); - let interfaces = if let Some(interfaces) = matches.values_of("interfaces") { - interfaces.map(|x| x.parse().unwrap()).collect() + let args = CLIArgs::from_args(); + + let interfaces = if !args.interfaces.is_empty() { + args.interfaces } else { vec![ IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), ] }; - let auth = if let Some(auth_split) = matches.value_of("auth").map(|x| x.splitn(2, ':')) { - let auth_vec = auth_split.collect::<Vec<&str>>(); - if auth_vec.len() == 2 { - Some(auth::BasicAuthParams { - username: auth_vec[0].to_owned(), - password: auth_vec[1].to_owned(), - }) - } else { - None - } - } else { - None + + let auth = match args.auth { + Some((username, password)) => Some(auth::BasicAuthParams { username, password }), + None => None, }; - let random_route = if matches.is_present("random-route") { + let random_route = if args.random_route { Some(nanoid::custom(6, &ROUTE_ALPHABET)) } else { None }; - let sort_method = matches - .value_of("sort") - .unwrap() - .parse::<listing::SortingMethods>() - .unwrap(); - - let reverse_sort = matches.is_present("reverse"); + let path_explicitly_chosen = args.path.is_some(); crate::MiniserveConfig { - verbose, - path: PathBuf::from(path.unwrap_or(".")), - port, + verbose: args.verbose, + path: args.path.unwrap_or_else(|| PathBuf::from(".")), + port: args.port, interfaces, auth, - path_explicitly_chosen: path.is_some(), - no_symlinks, + path_explicitly_chosen, + no_symlinks: args.no_symlinks, random_route, - sort_method, - reverse_sort, + sort_method: args.sort_method.unwrap_or(listing::SortingMethods::Natural), + reverse_sort: args.reverse_sort, } } |