mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-05 02:55:31 +00:00
First commit
This commit is contained in:
commit
08489b028c
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/target
|
416
Cargo.lock
generated
Normal file
416
Cargo.lock
generated
Normal file
@ -0,0 +1,416 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d117600f438b1707d4e4ae15d3595657288f8235a0eb593e80ecc98ab34e1bc"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bgzip"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adff113e9fe73a6d0c4efd0f143857bd6bdad40743542f3f57464398c532234f"
|
||||
dependencies = [
|
||||
"failure",
|
||||
"flate2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "bzip2"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abf8012c8a15d5df745fcf258d93e6149dcf102882c8d8702d9cff778eab43a8"
|
||||
dependencies = [
|
||||
"bzip2-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bzip2-sys"
|
||||
version = "0.1.10+1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17fa3d1ac1ca21c5c4e36a97f3c3eb25084576f6fc47bf0139c1123434216c6c"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"lazy_static",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum_primitive"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
|
||||
dependencies = [
|
||||
"num-traits 0.1.43",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"failure_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure_derive"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crc32fast",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae"
|
||||
|
||||
[[package]]
|
||||
name = "lzma-sys"
|
||||
version = "0.1.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdb4b7c3eddad11d3af9e86c487607d2d2442d185d848575365c4856ba96d619"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "niffler"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ea40fb13399dd0e9780ea3d82cb6cf27f489f63d820aa7dc9ec967750dc6d58"
|
||||
dependencies = [
|
||||
"bgzip",
|
||||
"bzip2",
|
||||
"cfg-if",
|
||||
"enum_primitive",
|
||||
"flate2",
|
||||
"thiserror",
|
||||
"xz2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||
dependencies = [
|
||||
"num-traits 0.2.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4"
|
||||
|
||||
[[package]]
|
||||
name = "ouch"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"colored",
|
||||
"niffler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "xz2"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c179869f34fc7c01830d3ce7ea2086bc3a07e0d35289b667d0a8bf910258926c"
|
||||
dependencies = [
|
||||
"lzma-sys",
|
||||
]
|
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "ouch"
|
||||
version = "0.1.0"
|
||||
authors = ["Vinícius Rodrigues Miguel <lemao.vrm07@hotmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
colored = "2.0.0"
|
||||
niffler = "2.3.1"
|
||||
clap = "2.33.3"
|
67
README.md
Normal file
67
README.md
Normal file
@ -0,0 +1,67 @@
|
||||
# ouch
|
||||
|
||||
`ouch` is the Obvious Unified Compression (and decompression) Helper.
|
||||
|
||||
## How does it work?
|
||||
|
||||
`ouch` infers commands from the extensions of its command-line options.
|
||||
|
||||
```
|
||||
ouch 0.1.0
|
||||
ouch is a unified compression & decompression utility
|
||||
|
||||
USAGE:
|
||||
ouch [OPTIONS] --input <input>...
|
||||
|
||||
FLAGS:
|
||||
-h, --help Displays this message and exits
|
||||
-V, --version Prints version information
|
||||
|
||||
OPTIONS:
|
||||
-i, --input <input>... Input files (TODO description)
|
||||
-o, --output <output> Output file (TODO description)
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
#### Decompressing a bunch of files
|
||||
|
||||
```bash
|
||||
$ ouch -i file{1..5}.zip
|
||||
info: attempting to decompress input files into single_folder
|
||||
info: done!
|
||||
```
|
||||
|
||||
When no output file is supplied, `ouch` infers that it must decompress all of its input files. This will error if any of the input files are not decompressable.
|
||||
|
||||
#### Decompressing a bunch of files into a folder
|
||||
|
||||
```bash
|
||||
$ ouch -i file{1..5}.tar.gz -o some-folder
|
||||
info: attempting to decompress input files into single_folder
|
||||
info: done!
|
||||
```
|
||||
|
||||
When the output file is not a compressed file, `ouch` will check if all input files are decompressable and infer that it must decompress them into the output file.
|
||||
|
||||
#### Compressing files
|
||||
|
||||
```bash
|
||||
$ ouch -i file{1..20} -o archive.tar
|
||||
info: trying to compress input files into 'archive.tar'
|
||||
info: done!
|
||||
```
|
||||
|
||||
### Error scenarios
|
||||
|
||||
#### No clear decompression algorithm
|
||||
|
||||
```bash
|
||||
$ ouch -i some-file -o some-folder
|
||||
error: file 'some-file' is not decompressable.
|
||||
```
|
||||
|
||||
`ouch` might (TODO!) be able to sniff a file's compression format if it isn't supplied in the future, but that is not currently implemented.
|
||||
|
||||
|
||||
|
218
src/cli.rs
Normal file
218
src/cli.rs
Normal file
@ -0,0 +1,218 @@
|
||||
use std::{convert::TryFrom, ffi::OsStr, path::PathBuf, vec::Vec};
|
||||
|
||||
use clap::{Arg};
|
||||
use colored::Colorize;
|
||||
|
||||
use crate::error;
|
||||
use crate::extensions::CompressionExtension;
|
||||
use crate::file::File;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CommandType {
|
||||
Compression(
|
||||
// Files to be compressed
|
||||
Vec<PathBuf>,
|
||||
),
|
||||
Decompression(
|
||||
// Files to be decompressed and their extensions
|
||||
Vec<(PathBuf, CompressionExtension)>,
|
||||
),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Command {
|
||||
pub command_type: CommandType,
|
||||
pub output: Option<File>,
|
||||
}
|
||||
|
||||
pub fn get_matches() -> clap::ArgMatches<'static> {
|
||||
clap::App::new("ouch")
|
||||
.version("0.1.0")
|
||||
.about("ouch is a unified compression & decompression utility")
|
||||
.help_message("Displays this message and exits")
|
||||
.settings(&[
|
||||
clap::AppSettings::ColoredHelp,
|
||||
clap::AppSettings::ArgRequiredElseHelp,
|
||||
])
|
||||
.arg(
|
||||
Arg::with_name("input")
|
||||
.required(true)
|
||||
.multiple(true)
|
||||
.long("input")
|
||||
.short("i")
|
||||
.help("Input files (TODO description)")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("output")
|
||||
// --output/-o not required when output can be inferred from the input files
|
||||
.required(false)
|
||||
.multiple(false)
|
||||
.long("output")
|
||||
.short("o")
|
||||
.help("Output file (TODO description)")
|
||||
.takes_value(true),
|
||||
)
|
||||
.get_matches()
|
||||
}
|
||||
|
||||
// holy spaghetti code
|
||||
impl TryFrom<clap::ArgMatches<'static>> for Command {
|
||||
|
||||
type Error = error::Error;
|
||||
|
||||
fn try_from(matches: clap::ArgMatches<'static>) -> error::OuchResult<Command> {
|
||||
// Possibilities:
|
||||
// * Case 1: output not supplied, therefore try to infer output by checking if all input files are decompressable
|
||||
// * Case 2: output supplied
|
||||
|
||||
let output_was_supplied = matches.is_present("output");
|
||||
|
||||
if output_was_supplied {
|
||||
let output_file = matches
|
||||
.value_of("output")
|
||||
.unwrap(); // Safe unwrap since we've established that output was supplied
|
||||
|
||||
let input_files = matches
|
||||
.values_of("input")
|
||||
.unwrap(); // Safe to unwrap since input is an obligatory argument
|
||||
// .map(PathBuf::from)
|
||||
// .collect();
|
||||
|
||||
|
||||
let output_file_extension = CompressionExtension::try_from(output_file);
|
||||
let output_is_compressable = output_file_extension.is_ok();
|
||||
if output_is_compressable {
|
||||
println!("{}: trying to compress input files into '{}'", "info".yellow(), output_file);
|
||||
|
||||
let input_files = input_files.map(PathBuf::from).collect();
|
||||
|
||||
return Ok(
|
||||
Command {
|
||||
command_type: CommandType::Compression(input_files),
|
||||
output: Some(File::WithExtension(
|
||||
(output_file.into(), output_file_extension.unwrap())
|
||||
))
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
else {
|
||||
// Checking if input files are decompressable
|
||||
let input_files = input_files
|
||||
.map(|filename| (filename, CompressionExtension::try_from(filename)));
|
||||
|
||||
for file in input_files.clone() {
|
||||
if let (file, Err(_)) = file {
|
||||
eprintln!("{}: file '{}' is not decompressable.", "error".red(), file);
|
||||
return Err(error::Error::InputsMustHaveBeenDecompressable(file.into()));
|
||||
}
|
||||
}
|
||||
|
||||
let input_files =
|
||||
input_files
|
||||
.map(|(filename, extension)|
|
||||
(PathBuf::from(filename), extension.unwrap())
|
||||
)
|
||||
.collect();
|
||||
|
||||
println!("{}: attempting to decompress input files into {}", "info".yellow(), output_file);
|
||||
return Ok(
|
||||
Command {
|
||||
command_type: CommandType::Decompression(input_files),
|
||||
output: Some(File::WithoutExtension(output_file.into()))
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// BIG TODO
|
||||
Err(error::Error::MissingExtensionError("placeholder result".into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl TryFrom<clap::ArgMatches<'static>> for ArgValues {
|
||||
// type Error = error::OuchError;
|
||||
// fn try_from(matches: clap::ArgMatches<'static>) -> error::OuchResult<ArgValues> {
|
||||
// // Case 1: -o was set
|
||||
// // Case 1.1: -o was set and has a (supported) compression file extension
|
||||
// // |--> Compress all input files into the supplied output file (no extension checks on inputs)
|
||||
// // Case 1.2: -o was set and is not a supported expression
|
||||
// // Case 2: -o was not set
|
||||
// // Case 2.1: -o was not set and all input files are (supported) compression file extensions
|
||||
// // |--> Decompress input files into inferred filenames or directories
|
||||
// // Case 2.2: -o was not set and not all input files are (supported) compression file extensions
|
||||
// // |--> Issue an error
|
||||
|
||||
// let inputs = matches
|
||||
// .values_of("input")
|
||||
// .unwrap() // Safe to unwrap since this is a required argument
|
||||
// .map(|input: &str| {
|
||||
// (
|
||||
// PathBuf::from(input),
|
||||
// CompressionExtension::try_from(input).ok(),
|
||||
// )
|
||||
// });
|
||||
|
||||
// let output_was_supplied = matches.is_present("output");
|
||||
// let inputs_are_compressed_files = inputs.clone().all(|(_, ext)| ext.is_some());
|
||||
|
||||
// match (output_was_supplied, inputs_are_compressed_files) {
|
||||
// (true, true) => {
|
||||
// // -o was set and inputs are all valid compressed files
|
||||
|
||||
// let output = matches.value_of("output").unwrap();
|
||||
// let output = PathBuf::from(output);
|
||||
// match CompressionExtension::try_from(&output) {
|
||||
// Ok(ext) => {
|
||||
// // If the output file is a valid compressed file, then we compress the input files into it
|
||||
// Ok(Self {
|
||||
// command_type: CommandType::Compress(
|
||||
// inputs.map(|(path, _)| path).collect(),
|
||||
// ),
|
||||
// output: Some((output, ext)),
|
||||
// })
|
||||
// }
|
||||
// Err(_) => {
|
||||
// // If the output file is not a compressed file, then we decompress the input files into it
|
||||
// Ok(Self {
|
||||
// command_type: CommandType::Decompress(
|
||||
// inputs.map(|(path, ext)| (path, ext.unwrap())).collect(),
|
||||
// ),
|
||||
// output: Some((output, CompressionExtension::NotCompressed)),
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// (true, false) => {
|
||||
// // -o was set and inputs are not (all) valid compressed files
|
||||
// let output_str = matches.value_of("output").unwrap();
|
||||
// let output = PathBuf::from(output_str);
|
||||
// let output_ext = match CompressionExtension::try_from(&output) {
|
||||
// Ok(ext) => ext,
|
||||
// Err(_) => {
|
||||
// return Err(error::OuchError::MissingExtensionError(output_str.into()));
|
||||
// }
|
||||
// };
|
||||
|
||||
// Ok(Self {
|
||||
// command_type: CommandType::Compress(inputs.map(|(path, _)| path).collect()),
|
||||
// output: Some((output, output_ext)),
|
||||
// })
|
||||
// }
|
||||
// (false, true) => {
|
||||
// // Case 2.1: -o was not set and all input files are (supported) compression file extensions
|
||||
// Ok(Self {
|
||||
// command_type: CommandType::Decompress(
|
||||
// inputs.map(|(path, ext)| (path, ext.unwrap())).collect(),
|
||||
// ),
|
||||
// output: None,
|
||||
// })
|
||||
// }
|
||||
// (false, false) => {
|
||||
// // Case 2.2: -o was not set and not all input files are not (supported) compression file extensions
|
||||
// Err(error::OuchError::InvalidInput)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
38
src/error.rs
Normal file
38
src/error.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use std::{fmt, path::PathBuf};
|
||||
|
||||
use colored::Colorize;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
UnknownExtensionError(String),
|
||||
MissingExtensionError(String),
|
||||
InvalidUnicode,
|
||||
InvalidInput,
|
||||
InputsMustHaveBeenDecompressable(String)
|
||||
}
|
||||
|
||||
// This should be placed somewhere else
|
||||
pub type OuchResult<T> = Result<T, Error>;
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use Error::*;
|
||||
|
||||
match self {
|
||||
InvalidInput => write!(
|
||||
f,
|
||||
"When `-o/--output` is omitted, all input files should be compressed files."
|
||||
),
|
||||
Error::MissingExtensionError(filename) => {
|
||||
write!(f, "cannot compress to \'{}\', likely because it has an unsupported (or missing) extension.", filename)
|
||||
}
|
||||
Error::InputsMustHaveBeenDecompressable(file) => {
|
||||
write!(f, "file '{}' is not decompressable", file.red())
|
||||
}
|
||||
_ => {
|
||||
// TODO
|
||||
write!(f, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
74
src/extensions.rs
Normal file
74
src/extensions.rs
Normal file
@ -0,0 +1,74 @@
|
||||
use std::{
|
||||
convert::TryFrom,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use crate::error;
|
||||
#[derive(Debug)]
|
||||
/// Accepted extensions for input and output
|
||||
pub enum CompressionExtension {
|
||||
// .gz
|
||||
Gzip,
|
||||
// .bz
|
||||
Bzip,
|
||||
// .lzma
|
||||
Lzma,
|
||||
// .tar (technically not a compression extension, but will do for now)
|
||||
Tar,
|
||||
// .zip
|
||||
Zip,
|
||||
// Not a supported compressed file extension (any other file)
|
||||
// TODO: it makes no sense for this variant to exist here
|
||||
// NotCompressed
|
||||
}
|
||||
|
||||
impl TryFrom<&PathBuf> for CompressionExtension {
|
||||
type Error = error::Error;
|
||||
|
||||
fn try_from(ext: &PathBuf) -> Result<Self, Self::Error> {
|
||||
use CompressionExtension::*;
|
||||
|
||||
let ext = match ext.extension() {
|
||||
Some(ext) => ext,
|
||||
None => {
|
||||
return Err(error::Error::MissingExtensionError(String::new()));
|
||||
}
|
||||
};
|
||||
|
||||
let ext = match ext.to_str() {
|
||||
Some(str) => str,
|
||||
None => return Err(error::Error::InvalidUnicode),
|
||||
};
|
||||
|
||||
match ext {
|
||||
"zip" => Ok(Zip),
|
||||
"tar" => Ok(Tar),
|
||||
other => Err(error::Error::UnknownExtensionError(other.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for CompressionExtension {
|
||||
type Error = error::Error;
|
||||
|
||||
fn try_from(filename: &str) -> Result<Self, Self::Error> {
|
||||
use CompressionExtension::*;
|
||||
|
||||
let filename = Path::new(filename);
|
||||
let ext = match filename.extension() {
|
||||
Some(ext) => ext,
|
||||
None => return Err(error::Error::MissingExtensionError(String::new())),
|
||||
};
|
||||
|
||||
let ext = match ext.to_str() {
|
||||
Some(str) => str,
|
||||
None => return Err(error::Error::InvalidUnicode),
|
||||
};
|
||||
|
||||
match ext {
|
||||
"zip" => Ok(Zip),
|
||||
"tar" => Ok(Tar),
|
||||
other => Err(error::Error::UnknownExtensionError(other.into())),
|
||||
}
|
||||
}
|
||||
}
|
43
src/file.rs
Normal file
43
src/file.rs
Normal file
@ -0,0 +1,43 @@
|
||||
use std::{convert::TryFrom, path::PathBuf, str::FromStr};
|
||||
|
||||
use crate::error::Error as OuchError;
|
||||
use crate::error;
|
||||
use crate::extensions::CompressionExtension;
|
||||
|
||||
// pub type File = (PathBuf, CompressionExtension);
|
||||
|
||||
// #[derive(Debug)]
|
||||
// pub struct FileWithExtension {
|
||||
// pub extension: CompressionExtension,
|
||||
// pub filename: PathBuf,
|
||||
// }
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum File {
|
||||
WithExtension((PathBuf, CompressionExtension)),
|
||||
WithoutExtension(PathBuf)
|
||||
}
|
||||
|
||||
// impl TryFrom<String> for FileWithExtension {
|
||||
// type Error = OuchError;
|
||||
|
||||
// fn try_from(filename: String) -> error::OuchResult<Self> {
|
||||
// // Safe to unwrap (infallible operation)
|
||||
// let filename = PathBuf::from_str(&filename).unwrap();
|
||||
|
||||
// let os_str = match filename.extension() {
|
||||
// Some(os_str) => os_str,
|
||||
// None => return Err(OuchError::MissingExtensionError(filename.to_string_lossy().to_string())),
|
||||
// };
|
||||
|
||||
// let extension = match CompressionExtension::try_from(os_str.into()) {
|
||||
// Ok(ext) => ext,
|
||||
// Err(err) => return Err(err),
|
||||
// };
|
||||
|
||||
// Ok(Self {
|
||||
// filename,
|
||||
// extension,
|
||||
// })
|
||||
// }
|
||||
// }
|
45
src/main.rs
Normal file
45
src/main.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use std::{convert::TryFrom, fs::File};
|
||||
|
||||
use cli::get_matches;
|
||||
|
||||
mod cli;
|
||||
mod file;
|
||||
mod extensions;
|
||||
mod error;
|
||||
|
||||
fn main() {
|
||||
|
||||
// Just testing
|
||||
|
||||
// let args: Vec<String> = std::env::args().collect();
|
||||
|
||||
// let file = std::fs::read(args[1].clone()).unwrap();
|
||||
|
||||
// match niffler::sniff(Box::new(&file[..])) {
|
||||
// Ok((reader, compression)) => {},
|
||||
// Err(err) => {}
|
||||
// }
|
||||
|
||||
// let (mut reader, compression) = niffler::sniff(Box::new(&file[..])).unwrap();
|
||||
|
||||
// match compression {
|
||||
// niffler::Format::Gzip => {}
|
||||
// niffler::Format::Bzip => {}
|
||||
// niffler::Format::Lzma => {}
|
||||
// niffler::Format::No => {}
|
||||
// }
|
||||
|
||||
// let mut contents = String::new();
|
||||
// println!("Contents: {}", reader.read_to_string(&mut contents).unwrap());
|
||||
|
||||
// dbg!(compression);
|
||||
|
||||
let matches = get_matches();
|
||||
match cli::Command::try_from(matches) {
|
||||
Ok(vals) => { dbg!(vals); },
|
||||
Err(err) => {
|
||||
print!("{}\n", err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
0
src/test.rs
Normal file
0
src/test.rs
Normal file
Loading…
x
Reference in New Issue
Block a user