You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

185 lines
4.1 KiB

use super::*;
use std::{
num::{
NonZeroUsize,
ParseIntError,
},
path::{
PathBuf,
Path,
},
};
use lazy_static::lazy_static;
#[inline] pub fn program_name() -> &'static str
{
lazy_static!{
static ref PROG: &'static str = Box::leak(std::env::args().next().unwrap().into_boxed_str());
}
&PROG[..]
}
pub fn usage() -> !
{
#[cfg(feature="splash")]
splash::print();
println!(r"Usage: {prog} [--max-children <number>] [-] <files...>
Usage: {prog} --help
OPTIONS:
--max-children <number> Max subprocesses allowed to live at once. Infinite by default.
ENVIRONMENT VARS:
LEANIFY=<process name> Path to leanify executable, defaults to looking in `PATH' if set.", prog = program_name());
std::process::exit(1)
}
#[derive(Debug)]
pub enum Error {
#[cfg(nightly)] BadNumber(std::num::IntErrorKind),
#[cfg(not(nightly))] BadNumber(()),
NoExist(PathBuf),
Walking(dir::Error),
NoFiles,
}
impl std::error::Error for Error{}
impl std::fmt::Display for Error
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
//write!(f, "arg parsing failed: ")?;
match self {
Self::BadNumber(_v) => {
write!(f, "expected non-zero integer")?;
#[cfg(nightly)] use std::num::IntErrorKind;
#[cfg(nightly)] return match _v {
IntErrorKind::Empty => write!(f, ": argument empty"),
IntErrorKind::InvalidDigit => write!(f, ": invalid digit"),
IntErrorKind::Overflow => write!(f, ": conversion would result in overflow"),
IntErrorKind::Underflow => write!(f, ": conversion would result in underflow"),
IntErrorKind::Zero => write!(f, ": found zero"),
_=> Ok(()),
};
#[cfg(not(nightly))] Ok(())
},
Self::NoExist(path) => write!(f, "path {:?} does not exist", path),
Self::NoFiles => write!(f, "need at least one argument"),
Self::Walking(dir) => write!(f, "error walking directory structure(s): {}", dir),
}
}
}
impl From<ParseIntError> for Error
{
fn from(_er: ParseIntError) -> Self
{
#[cfg(nightly)] return Self::BadNumber(_er.kind().clone());
#[cfg(not(nightly))] Self::BadNumber
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Config
{
pub max_children: Option<NonZeroUsize>,
pub files: Vec<PathBuf>,
pub recursive: Option<NonZeroUsize>,
}
impl Default for Config
{
#[inline]
fn default() -> Self
{
Self {
max_children: None,
files: Vec::new(),
recursive: Some(unsafe{NonZeroUsize::new_unchecked(1)}),
}
}
}
/// Parse the `env::args()`
#[inline] pub async fn parse_args() -> Result<Config, Error>
{
let args = std::env::args();
if args.len() <= 1 {
println!("Warning: No arguments specified, try passing `--help`.");
}
parse(args.skip(1)).await
}
async fn parse<I,T>(args: I) -> Result<Config, Error>
where I: IntoIterator<Item=T>,
T: Into<String>
{
let mut args = args.into_iter().map(|x| x.into());
let mut cfg = Config::default();
let mut reading=true;
let mut first=true;
while let Some(arg) = args.next() {
if reading {
let lw_arg = arg.trim().to_lowercase();
if first {
match lw_arg.as_str() {
"--help" => {
usage()
},
_ => (),
}
}
first=false;
match lw_arg.as_str() {
"--max-children" => {
if let Some(nzi) = args.next() {
cfg.max_children = Some(nzi.parse()?);
continue;
}
},
"--recursive" => {
if let Some(nzi) = args.next() {
cfg.recursive = Some(nzi.parse()?);
continue;
}
},
"-r" => {
cfg.recursive = None;
},
"-" => {
reading= false;
continue;
},
_ => (),
}
}
reading = false;
let path = Path::new(&arg);
if path.is_dir() {
cfg.files.extend(dir::walk(path, cfg.recursive, dir::recommended_max_walkers()).await?);
} else if path.is_file() {
cfg.files.push(path.to_owned());
} else {
return Err(Error::NoExist(path.to_owned()));
}
}
if cfg.files.len() == 0 {
return Err(Error::NoFiles);
}
Ok(cfg)
}
impl From<dir::Error> for Error
{
fn from(from: dir::Error) -> Self
{
Self::Walking(from)
}
}