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.
lolistealer/src/args.rs

139 lines
3.6 KiB

use super::*;
use lazy_static::lazy_static;
use std::{
error,
fmt,
path::{
PathBuf,
Path,
},
};
lazy_static! {
pub static ref PROGRAM_NAME: &'static str = Box::leak(std::env::args().next().unwrap().into_boxed_str());
}
/// Print usage then exit with code `1`
pub fn usage() -> !
{
println!(concat!("lolistealer version ", env!("CARGO_PKG_VERSION")));
println!(concat!(" written by ",env!("CARGO_PKG_AUTHORS")," with <3"));
println!(" licensed with GNU GPL 3.0 or later\n");
println!("Usage: {} [-q] [--rating <rating>] [--tags <filter expr>] [<outputs...>]", &PROGRAM_NAME[..]);
println!("Usage: {} --help", &PROGRAM_NAME[..]);
println!("Options:");
println!(" -q\t\t\tQuiet mode, do not output progress");
println!(" --rating <rating>\tEither `s`afe, `q`uestionable, or `e`xplicit");
println!(" --tags <filter expr>\tFilter downloaded images out by tags, see below for format.");
println!("Tags filter expreession:");
println!(" tag_name\tMust contain this tag");
println!(" -tag_name\tMust not contains this tag");
println!(" +tag_name\tMust contains at least one tag prepended with `+`");
println!("Note:");
println!(" Tag filter expreession is a single argument, tags must be seperated with spaces. e.g. 'tag1 -tag2 +tag3 +tag4'");
#[cfg(feature="async")]
println!("\n (compiled with threading support)");
std::process::exit(1)
}
/// Parse the system args
pub fn parse_args() -> Result<Mode, Error>
{
parse(std::env::args().skip(1))
}
fn try_dir(path: impl AsRef<Path>) -> Result<config::OutputType, Error>
{
let path = path.as_ref();
if path.is_dir() {
Ok(config::OutputType::Directory(path.to_owned()))
} else if !path.exists() {
Ok(config::OutputType::File(path.to_owned()))
} else {
Err(Error::FileExists(path.to_owned()))
}
}
#[derive(Debug)]
pub enum Mode {
Normal(config::Config),
Help,
}
fn parse<I>(args: I) -> Result<Mode, Error>
where I: IntoIterator<Item=String>
{
let mut args = args.into_iter();
let mut rating = config::Rating::default();
let mut paths = Vec::new();
let mut one = String::default();
let mut reading = true;
let mut tags = Vec::new();
let mut verbose = Default::default();
macro_rules! take_one {
() => {
{
if let Some(new) = args.next() {
one = new;
true
} else {
false
}
}
};
}
while let Some(arg) = args.next()
{
if reading {
match arg.to_lowercase().trim() {
"-" => reading = false,
"--help" => return Ok(Mode::Help),
"-q" => verbose = config::Verbosity::Silent,
"--rating" if take_one!() => rating = one.parse::<config::Rating>()?,
"--tags" if take_one!() => tags = tags::parse(&one),
_ => paths.push(try_dir(arg)?),
}
} else {
paths.push(try_dir(arg)?);
}
}
if paths.len() < 1 {
return Err(Error::NoOutput);
}
Ok(Mode::Normal(config::Config{rating, output: paths, tags, verbose}))
}
#[derive(Debug)]
pub enum Error {
UnknownRating(String),
FileExists(PathBuf),
NoOutput,
Internal(Box<dyn error::Error>),
Unknown,
}
impl error::Error for Error{}
impl fmt::Display for Error
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match self {
Error::NoOutput => write!(f, "need at least one output, try `{} --help`", &PROGRAM_NAME[..]),
Error::UnknownRating(rating) => write!(f, "{} is not a valid rating", rating),
Error::FileExists(path) => write!(f, "file already exists: {:?}", path),
Error::Internal(bx) => write!(f, "internal error: {}", bx),
_ => write!(f, "unknown error"),
}
}
}