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
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)
|
|
}
|
|
}
|