use clap::crate_description; use clap::{Arg, ArgMatches}; use std::env; use std::fs::canonicalize; use std::net::SocketAddr; use std::path::{Path, PathBuf}; use crate::BoxResult; const ABOUT: &str = concat!("\n", crate_description!()); // Add extra newline. fn app() -> clap::Command<'static> { let arg_port = Arg::new("port") .short('p') .long("port") .default_value("5000") .help("Specify port to listen on") .value_name("port"); let arg_address = Arg::new("address") .short('b') .long("bind") .default_value("127.0.0.1") .help("Specify bind address") .value_name("address"); let arg_path = Arg::new("path") .default_value(".") .allow_invalid_utf8(true) .help("Path to a directory for serving files"); clap::command!() .about(ABOUT) .arg(arg_address) .arg(arg_port) .arg(arg_path) } pub fn matches() -> ArgMatches { app().get_matches() } #[derive(Debug, Clone, Eq, PartialEq)] pub struct Args { pub address: String, pub port: u16, pub path: PathBuf, } impl Args { /// Parse command-line arguments. /// /// If a parsing error ocurred, exit the process and print out informative /// error message to user. pub fn parse(matches: ArgMatches) -> BoxResult<Args> { let address = matches.value_of("address").unwrap_or_default().to_owned(); let port = matches.value_of_t::<u16>("port")?; let path = matches.value_of_os("path").unwrap_or_default(); let path = Args::parse_path(path)?; Ok(Args { address, port, path, }) } /// Parse path. fn parse_path<P: AsRef<Path>>(path: P) -> BoxResult<PathBuf> { let path = path.as_ref(); if !path.exists() { bail!("error: path \"{}\" doesn't exist", path.display()); } env::current_dir() .and_then(|mut p| { p.push(path); // If path is absolute, it replaces the current path. canonicalize(p) }) .or_else(|err| { bail!( "error: failed to access path \"{}\": {}", path.display(), err, ) }) } /// Construct socket address from arguments. pub fn address(&self) -> BoxResult<SocketAddr> { format!("{}:{}", self.address, self.port) .parse() .or_else(|err| { bail!( "error: invalid address {}:{} : {}", self.address, self.port, err, ) }) } }