1 use std::{convert::TryFrom, path::PathBuf, vec::Vec};
3 use clap::{Arg, Values};
7 use crate::extensions::CompressionExtension;
10 #[derive(PartialEq, Eq, Debug)]
11 pub enum CommandType {
13 // Files to be compressed
17 // Files to be decompressed and their extensions
18 Vec<(PathBuf, CompressionExtension)>,
22 #[derive(PartialEq, Eq, Debug)]
24 pub command_type: CommandType,
25 pub output: Option<File>,
28 pub fn clap_app<'a, 'b>() -> clap::App<'a, 'b> {
29 clap::App::new("ouch")
31 .about("ouch is a unified compression & decompression utility")
32 .help_message("Displays this message and exits")
34 clap::AppSettings::ColoredHelp,
35 clap::AppSettings::ArgRequiredElseHelp,
38 Arg::with_name("input")
43 .help("Input files (TODO description)")
47 Arg::with_name("output")
48 // --output/-o not required when output can be inferred from the input files
53 .help("Output file (TODO description)")
58 pub fn get_matches() -> clap::ArgMatches<'static> {
59 clap_app().get_matches()
62 // holy spaghetti code
63 impl TryFrom<clap::ArgMatches<'static>> for Command {
64 type Error = error::Error;
66 fn try_from(matches: clap::ArgMatches<'static>) -> error::OuchResult<Command> {
67 let process_decompressible_input = |input_files: Values| {
69 input_files.map(|filename| (filename, CompressionExtension::try_from(filename)));
71 for file in input_files.clone() {
72 if let (file, Err(_)) = file {
73 // eprintln!("{}: file '{}' is not decompressible.", "error".red(), file);
74 return Err(error::Error::InputsMustHaveBeenDecompressible(file.into()));
79 .map(|(filename, extension)| (PathBuf::from(filename), extension.unwrap()))
84 // * Case 1: output not supplied, therefore try to infer output by checking if all input files are decompressible
85 // * Case 2: output supplied
87 let output_was_supplied = matches.is_present("output");
89 let input_files = matches.values_of("input").unwrap(); // Safe to unwrap since input is an obligatory argument
91 if output_was_supplied {
92 let output_file = matches.value_of("output").unwrap(); // Safe unwrap since we've established that output was supplied
94 let output_file_extension = CompressionExtension::try_from(output_file);
95 let output_is_compressible = output_file_extension.is_ok();
96 if output_is_compressible {
98 "{}: trying to compress input files into '{}'",
103 let input_files = input_files.map(PathBuf::from).collect();
106 command_type: CommandType::Compression(input_files),
107 output: Some(File::WithExtension((
109 output_file_extension.unwrap(),
113 // Checking if input files are decompressible
115 let input_files = process_decompressible_input(input_files)?;
118 "{}: attempting to decompress input files into {}",
123 command_type: CommandType::Decompression(input_files),
124 output: Some(File::WithoutExtension(output_file.into())),
128 // else: output file not supplied
129 // Case 1: all input files are decompressible
131 let input_files = process_decompressible_input(input_files)?;
133 command_type: CommandType::Decompression(input_files),