mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-06 11:35:45 +00:00
Merge pull request #16 from vrmiguel/nightly
Update master from nightly
This commit is contained in:
commit
d3de94dfca
32
.github/workflows/build.yml
vendored
32
.github/workflows/build.yml
vendored
@ -17,37 +17,33 @@ jobs:
|
||||
- name: Install toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
toolchain: stable
|
||||
target: x86_64-unknown-linux-musl
|
||||
override: true
|
||||
|
||||
- name: Install dependencies for musl libc
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install musl-tools
|
||||
- name: Run cargo build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: build
|
||||
args: --release
|
||||
args: --release --target x86_64-unknown-linux-musl
|
||||
|
||||
- name: Run cargo test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
|
||||
- name: Install dependencies for Python test script
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install libmagic1
|
||||
python3 -m pip install python-magic
|
||||
|
||||
- name: Run test script
|
||||
run: python3 makeshift_testing.py
|
||||
|
||||
- name: Strip binary
|
||||
run: strip target/release/ouch
|
||||
run: strip target/x86_64-unknown-linux-musl/release/ouch
|
||||
|
||||
- name: Upload binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: 'ouch-ubuntu-18.04-glibc'
|
||||
path: target/release/ouch
|
||||
name: 'ouch-linux-musl'
|
||||
path: target/x86_64-unknown-linux-musl/release/ouch
|
||||
|
||||
macos:
|
||||
name: macOS
|
||||
@ -77,11 +73,6 @@ jobs:
|
||||
with:
|
||||
command: test
|
||||
|
||||
- name: Install dependencies for Python test script
|
||||
run: |
|
||||
brew install libmagic
|
||||
python3 -m pip install python-magic
|
||||
|
||||
- name: Strip binary
|
||||
run: strip target/release/ouch
|
||||
|
||||
@ -91,9 +82,6 @@ jobs:
|
||||
name: 'ouch-macOS'
|
||||
path: target/release/ouch
|
||||
|
||||
- name: Run test script
|
||||
run: python3 makeshift_testing.py
|
||||
|
||||
windows:
|
||||
name: Windows Server
|
||||
runs-on: windows-2019
|
||||
|
@ -12,10 +12,6 @@
|
||||
- [Installation](#Installation)
|
||||
- [Supported operating systems](#Supported-operating-systems)
|
||||
|
||||
**Note**
|
||||
* This README represents the new, but not yet implemented, interface that `ouch` will use.
|
||||
* For current usage instructions, check [the old README](https://github.com/vrmiguel/ouch/blob/0f453e9dfc70066056b9cc40e8032dcc6ee703bc/README.md).
|
||||
|
||||
## Usage
|
||||
|
||||
### Decompressing files
|
||||
|
@ -1,89 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
"""
|
||||
Little integration testing script while proper integration tests in Rust aren't implemented.
|
||||
"""
|
||||
|
||||
import magic, os, hashlib
|
||||
|
||||
def make_random_file():
|
||||
with open('test-file', 'wb') as fout:
|
||||
fout.write(os.urandom(2048))
|
||||
|
||||
def sanity_check_format(format: str):
|
||||
make_random_file()
|
||||
md5sum = hashlib.md5(open('test-file', 'rb').read()).hexdigest()
|
||||
os.system(f"cargo run -- -i test-file -o test-file.{format}")
|
||||
os.remove('test-file')
|
||||
os.system(f"cargo run -- -i test-file.{format}")
|
||||
if md5sum != hashlib.md5(open('test-file', 'rb').read()).hexdigest():
|
||||
print("Something went wrong with tar (de)compression.")
|
||||
os._exit(2)
|
||||
os.remove('test-file')
|
||||
os.remove(f'test-file.{format}')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
# We'll use MIME sniffing through magic numbers to
|
||||
# verify if ouch is actually outputting the file formats
|
||||
# that it should
|
||||
|
||||
m = magic.open(magic.MAGIC_MIME)
|
||||
|
||||
try:
|
||||
os.mkdir("testbuilds")
|
||||
except OSError:
|
||||
print ("Could not make testbuilds folder. Exiting.")
|
||||
os._exit(2)
|
||||
|
||||
os.chdir("testbuilds")
|
||||
|
||||
m.load()
|
||||
files = [
|
||||
"src.tar",
|
||||
"src.zip",
|
||||
"src.tar.gz",
|
||||
"src.tar.bz",
|
||||
"src.tar.bz2",
|
||||
"src.tar.lz",
|
||||
"src.tar.lzma",
|
||||
]
|
||||
|
||||
expected_mime_types = [
|
||||
"application/x-tar",
|
||||
"application/zip",
|
||||
"application/gzip",
|
||||
"application/x-bzip2",
|
||||
"application/x-bzip2",
|
||||
"application/x-xz",
|
||||
"application/x-xz"
|
||||
]
|
||||
|
||||
for file in files:
|
||||
rv = os.system(f"cargo run -- -i ../src/ -o {file}")
|
||||
if rv != 0:
|
||||
print(f"Failed while compressing {file}")
|
||||
|
||||
for (file, expected_mime) in zip(files, expected_mime_types):
|
||||
if m.file(file) != expected_mime:
|
||||
print(f"Test failed at file {file}")
|
||||
os._exit(2)
|
||||
|
||||
for (idx, file) in enumerate(files):
|
||||
rv = os.system(f"cargo run -- -i {file} -o out{idx}/")
|
||||
if rv != 0:
|
||||
print(f"Failed while decompressing {file}")
|
||||
os._exit(2)
|
||||
|
||||
os.chdir("..")
|
||||
os.system("rm -rf testbuilds")
|
||||
|
||||
# We'll now verify if ouch is not altering the data it is compressing
|
||||
# and decompressing
|
||||
|
||||
sanity_check_format("tar")
|
||||
sanity_check_format("tar.gz")
|
||||
sanity_check_format("tar.bz")
|
||||
sanity_check_format("tar.bz2")
|
||||
sanity_check_format("tar.lz")
|
||||
sanity_check_format("tar.lzma")
|
@ -91,7 +91,7 @@ impl FlagType {
|
||||
#[cfg(target_family = "windows")]
|
||||
{
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
iter = text.encode_wide
|
||||
iter = text.encode_wide();
|
||||
}
|
||||
|
||||
// 45 is the code for a hyphen
|
||||
|
@ -126,7 +126,7 @@ pub fn filter_flags(
|
||||
|
||||
// For each letter in the short arg, except the last one
|
||||
for (i, letter) in letters.iter().copied().enumerate() {
|
||||
// Safety: this loop only runs when len >= 1
|
||||
// Safety: this loop only runs when len >= 1, so this subtraction is safe
|
||||
let is_last_letter = i == letters.len() - 1;
|
||||
|
||||
let flag_info = short_flags_info.get(&letter).unwrap_or_else(|| {
|
||||
@ -149,16 +149,15 @@ pub fn filter_flags(
|
||||
}
|
||||
|
||||
// pop the next one
|
||||
let flag_argument = iter.next();
|
||||
flag_argument.unwrap_or_else(|| {
|
||||
let flag_argument = iter.next().unwrap_or_else(|| {
|
||||
panic!(
|
||||
"USer errror: argument flag `argument_flag` came at last, but it \
|
||||
requires an argument"
|
||||
)
|
||||
});
|
||||
|
||||
// Otherwise, insert it (TODO: grab next one and add it)
|
||||
// result_flags.argument_flags.insert(flag_info.long);
|
||||
// Otherwise, insert it.
|
||||
result_flags.argument_flags.insert(flag_name, flag_argument);
|
||||
} else {
|
||||
// If it was already inserted
|
||||
if result_flags.boolean_flags.contains(flag_name) {
|
||||
|
@ -5,6 +5,7 @@ pub fn trim_double_hyphen(flag_text: &str) -> &str {
|
||||
chars.as_str()
|
||||
}
|
||||
|
||||
// Currently unused
|
||||
/// Util function to skip the single leading short flag hyphen.
|
||||
pub fn trim_single_hyphen(flag_text: &str) -> &str {
|
||||
let mut chars = flag_text.chars();
|
||||
|
107
src/cli.rs
107
src/cli.rs
@ -2,6 +2,10 @@ use std::{env, ffi::OsString, io, path::PathBuf, vec::Vec};
|
||||
|
||||
use oof::{arg_flag, flag};
|
||||
|
||||
use crate::debug;
|
||||
|
||||
pub const VERSION: &str = "0.1.5";
|
||||
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
pub enum Command {
|
||||
/// Files to be compressed
|
||||
@ -66,8 +70,9 @@ pub fn parse_args_from(mut args: Vec<OsString>) -> crate::Result<ParsedArgs> {
|
||||
let mut files: Vec<PathBuf> = args.into_iter().map(PathBuf::from).collect();
|
||||
|
||||
if files.len() < 2 {
|
||||
panic!("The compress subcommands demands at least 2 arguments, see usage:.......");
|
||||
return Err(crate::Error::MissingArgumentsForCompression);
|
||||
}
|
||||
|
||||
// Safety: we checked that args.len() >= 2
|
||||
let compressed_output_path = files.pop().unwrap();
|
||||
|
||||
@ -82,16 +87,18 @@ pub fn parse_args_from(mut args: Vec<OsString>) -> crate::Result<ParsedArgs> {
|
||||
// Defaults to decompression when there is no subcommand
|
||||
None => {
|
||||
flags_info.push(arg_flag!('o', "output"));
|
||||
debug!(&flags_info);
|
||||
|
||||
// Parse flags
|
||||
let (args, mut flags) = oof::filter_flags(args, &flags_info)?;
|
||||
debug!((&args, &flags));
|
||||
|
||||
let files: Vec<_> = args.into_iter().map(PathBuf::from).collect();
|
||||
// TODO: This line doesn't seem to be working correctly
|
||||
let output_folder = flags.take_arg("output").map(PathBuf::from);
|
||||
|
||||
// Is the output here fully correct?
|
||||
// With the paths not canonicalized?
|
||||
|
||||
let command = Command::Decompress {
|
||||
files,
|
||||
output_folder,
|
||||
@ -102,98 +109,4 @@ pub fn parse_args_from(mut args: Vec<OsString>) -> crate::Result<ParsedArgs> {
|
||||
};
|
||||
|
||||
Ok(parsed_args)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn gen_args(text: &str) -> Vec<OsString> {
|
||||
let args = text.split_whitespace();
|
||||
args.map(OsString::from).collect()
|
||||
}
|
||||
|
||||
// // util for test the argument parsing
|
||||
// macro_rules! test {
|
||||
// ($expected_command:expr, $input_text:expr) => {{
|
||||
// assert_eq!(
|
||||
// $expected_command,
|
||||
// oof::try_arg_parsing($input_text.split_whitespace())
|
||||
// )
|
||||
// }};
|
||||
// }
|
||||
|
||||
macro_rules! parse {
|
||||
($input_text:expr) => {{
|
||||
let args = gen_args($input_text);
|
||||
parse_args_from(args).unwrap()
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
// The absolute flags that ignore all the other argparsing rules are --help and --version
|
||||
fn test_absolute_flags() {
|
||||
let expected = Command::ShowHelp;
|
||||
assert_eq!(expected, parse!("").command);
|
||||
assert_eq!(expected, parse!("-h").command);
|
||||
assert_eq!(expected, parse!("--help").command);
|
||||
assert_eq!(expected, parse!("aaaaaaaa --help -o -e aaa").command);
|
||||
assert_eq!(expected, parse!("aaaaaaaa -h").command);
|
||||
assert_eq!(expected, parse!("--help compress aaaaaaaa").command);
|
||||
assert_eq!(expected, parse!("compress --help").command);
|
||||
assert_eq!(expected, parse!("--version --help").command);
|
||||
assert_eq!(expected, parse!("aaaaaaaa -v aaaa -h").command);
|
||||
|
||||
let expected = Command::ShowVersion;
|
||||
assert_eq!(expected, parse!("ouch --version").command);
|
||||
assert_eq!(expected, parse!("ouch a --version b").command);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arg_parsing_compress_subcommand() {
|
||||
let files = ["a", "b", "c"].iter().map(PathBuf::from).collect();
|
||||
|
||||
let expected = Command::Compress {
|
||||
files,
|
||||
compressed_output_path: "d".into(),
|
||||
};
|
||||
assert_eq!(expected, parse!("compress a b c d").command);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arg_parsing_decompress_subcommand() {
|
||||
let files: Vec<_> = ["a", "b", "c"].iter().map(PathBuf::from).collect();
|
||||
|
||||
let expected = Command::Decompress {
|
||||
files: files.clone(),
|
||||
output_folder: None,
|
||||
};
|
||||
assert_eq!(expected, parse!("a b c").command);
|
||||
|
||||
let expected = Command::Decompress {
|
||||
files,
|
||||
output_folder: Some("folder".into()),
|
||||
};
|
||||
assert_eq!(expected, parse!("a b c --output folder").command);
|
||||
assert_eq!(expected, parse!("a b --output folder c").command);
|
||||
assert_eq!(expected, parse!("a --output folder b c").command);
|
||||
assert_eq!(expected, parse!("--output folder a b c").command);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_arg_parsing_decompress_subcommand() {
|
||||
// let files: Vec<PathBuf> = ["a", "b", "c"].iter().map(PathBuf::from).collect();
|
||||
|
||||
// let expected = Ok(Command::Decompress {
|
||||
// files: files.clone(),
|
||||
// });
|
||||
// test!(expected, "ouch a b c");
|
||||
|
||||
// let files: Vec<PathBuf> = ["a", "b", "c", "d"].iter().map(PathBuf::from).collect();
|
||||
|
||||
// let expected = Ok(Command::Decompress {
|
||||
// files: files.clone(),
|
||||
// });
|
||||
// test!(expected, "ouch a b c d");
|
||||
// }
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ impl TarCompressor {
|
||||
for entry in WalkDir::new(&filename) {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
println!("Compressing {:?}", path);
|
||||
if path.is_dir() {
|
||||
continue;
|
||||
}
|
||||
|
@ -68,7 +68,9 @@ impl ZipCompressor {
|
||||
if entry_path.is_dir() {
|
||||
continue;
|
||||
}
|
||||
|
||||
writer.start_file(entry_path.to_string_lossy(), options)?;
|
||||
println!("Compressing {:?}", entry_path);
|
||||
let file_bytes = std::fs::read(entry.path())?;
|
||||
writer.write_all(&*file_bytes)?;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ use crate::{dialogs::Confirmation, file::File, utils};
|
||||
pub struct TarDecompressor {}
|
||||
|
||||
impl TarDecompressor {
|
||||
fn unpack_files(from: File, into: &Path, flags: &oof::Flags) -> crate::Result<Vec<PathBuf>> {
|
||||
fn unpack_files(from: File, into: &Path, flags: &oof::Flags) -> crate::Result<Vec<PathBuf>> {
|
||||
println!(
|
||||
"{}: attempting to decompress {:?}",
|
||||
"ouch".bright_blue(),
|
||||
|
23
src/error.rs
23
src/error.rs
@ -15,22 +15,14 @@ pub enum Error {
|
||||
InvalidZipArchive(&'static str),
|
||||
PermissionDenied,
|
||||
UnsupportedZipArchive(&'static str),
|
||||
// InputsMustBeDecompressible(PathBuf),
|
||||
InternalError,
|
||||
CompressingRootFolder,
|
||||
MissingArgumentsForCompression,
|
||||
WalkdirError,
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
// impl std::error::Error for Error {
|
||||
// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
// // TODO: get rid of PartialEq and Eq in self::Error in order to
|
||||
// // correctly use `source`.
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
|
||||
impl fmt::Debug for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
@ -42,19 +34,18 @@ impl fmt::Display for Error {
|
||||
match self {
|
||||
Error::MissingExtensionError(filename) => {
|
||||
write!(f, "{} ", "[ERROR]".red())?;
|
||||
// TODO: show MIME type of the unsupported file
|
||||
write!(f, "cannot compress to \'{}\', likely because it has an unsupported (or missing) extension.", filename)
|
||||
}
|
||||
// Error::InputsMustBeDecompressible(file) => {
|
||||
// write!(f, "{} ", "[ERROR]".red())?;
|
||||
// write!(f, "file '{:?}' is not decompressible", file)
|
||||
// }
|
||||
Error::WalkdirError => {
|
||||
// Already printed in the From block
|
||||
write!(f, "")
|
||||
}
|
||||
Error::FileNotFound(file) => {
|
||||
write!(f, "{} ", "[ERROR]".red())?;
|
||||
// TODO: check if file == ""
|
||||
if file == &PathBuf::from("") {
|
||||
return write!(f, "file not found!");
|
||||
}
|
||||
write!(f, "file {:?} not found!", file)
|
||||
}
|
||||
Error::CompressingRootFolder => {
|
||||
@ -73,6 +64,10 @@ impl fmt::Display for Error {
|
||||
"rsync".green()
|
||||
)
|
||||
}
|
||||
Error::MissingArgumentsForCompression => {
|
||||
write!(f, "{} ", "[ERROR]".red())?;
|
||||
write!(f,"The compress subcommands demands at least 2 arguments, see usage: <TODO-USAGE>")
|
||||
}
|
||||
Error::InternalError => {
|
||||
write!(f, "{} ", "[ERROR]".red())?;
|
||||
write!(f, "You've reached an internal error! This really should not have happened.\nPlease file an issue at {}", "https://github.com/vrmiguel/ouch".green())
|
||||
|
@ -7,19 +7,20 @@ use std::{
|
||||
use colored::Colorize;
|
||||
|
||||
use crate::{
|
||||
cli::Command,
|
||||
cli::{VERSION, Command},
|
||||
compressors::{
|
||||
BzipCompressor, Compressor, Entry, GzipCompressor, LzmaCompressor, TarCompressor,
|
||||
Entry, Compressor, BzipCompressor, GzipCompressor, LzmaCompressor, TarCompressor,
|
||||
ZipCompressor,
|
||||
},
|
||||
decompressors::{
|
||||
BzipDecompressor, DecompressionResult, Decompressor, GzipDecompressor, LzmaDecompressor,
|
||||
TarDecompressor, ZipDecompressor,
|
||||
},
|
||||
dialogs::Confirmation,
|
||||
extension::{CompressionFormat, Extension},
|
||||
file::File,
|
||||
},
|
||||
dialogs::Confirmation,
|
||||
extension::{CompressionFormat, Extension},
|
||||
file::File,
|
||||
utils,
|
||||
debug
|
||||
};
|
||||
|
||||
pub struct Evaluator {}
|
||||
@ -31,6 +32,7 @@ impl Evaluator {
|
||||
pub fn get_compressor(
|
||||
file: &File,
|
||||
) -> crate::Result<(Option<BoxedCompressor>, BoxedCompressor)> {
|
||||
|
||||
let extension = match &file.extension {
|
||||
Some(extension) => extension.clone(),
|
||||
None => {
|
||||
@ -211,8 +213,8 @@ impl Evaluator {
|
||||
file_path: &Path,
|
||||
output: Option<&Path>,
|
||||
flags: &oof::Flags,
|
||||
) -> crate::Result<()> {
|
||||
let file = File::from(file_path)?;
|
||||
) -> crate::Result<()> {
|
||||
let file = debug!(File::from(file_path)?);
|
||||
let output = match output {
|
||||
Some(inner) => Some(File::from(inner)?),
|
||||
None => None,
|
||||
@ -266,9 +268,25 @@ impl Evaluator {
|
||||
Self::decompress_file(file, output_folder, flags)?;
|
||||
}
|
||||
}
|
||||
Command::ShowHelp => todo!("call help function"),
|
||||
Command::ShowVersion => todo!("call version function"),
|
||||
Command::ShowHelp => help_message(),
|
||||
Command::ShowVersion => version_message(),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn version_message() {
|
||||
println!("ouch {}", VERSION);
|
||||
}
|
||||
|
||||
fn help_message() {
|
||||
version_message();
|
||||
println!("Vinícius R. M. & João M. Bezerra");
|
||||
println!("ouch is a unified compression & decompression utility");
|
||||
println!();
|
||||
println!(" COMPRESSION USAGE:");
|
||||
println!(" ouch compress <input...> output-file");
|
||||
println!("DECOMPRESSION USAGE:");
|
||||
println!(" ouch <input> [-o/--output output-folder]");
|
||||
}
|
@ -7,7 +7,7 @@ use std::{
|
||||
|
||||
use CompressionFormat::*;
|
||||
|
||||
use crate::utils::to_utf;
|
||||
use crate::{debug, utils::to_utf};
|
||||
|
||||
/// Represents the extension of a file, but only really caring about
|
||||
/// compression formats (and .tar).
|
||||
|
@ -19,13 +19,12 @@ pub struct File<'a> {
|
||||
|
||||
impl<'a> File<'a> {
|
||||
pub fn from(path: &'a Path) -> crate::Result<Self> {
|
||||
let extension = Extension::from(path.as_ref())?;
|
||||
eprintln!("dev warning: Should we really ignore the errors from the convertion above?");
|
||||
let extension = Extension::from(path.as_ref()).ok();
|
||||
|
||||
Ok(File {
|
||||
path,
|
||||
contents_in_memory: None,
|
||||
extension: Some(extension),
|
||||
extension
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,6 @@ fn main() {
|
||||
|
||||
fn run() -> crate::Result<()> {
|
||||
let ParsedArgs { command, flags } = cli::parse_args()?;
|
||||
dbg!(&command);
|
||||
debug!(&command);
|
||||
Evaluator::evaluate(command, &flags)
|
||||
}
|
||||
|
129
src/test.rs
129
src/test.rs
@ -1,39 +1,112 @@
|
||||
// TODO: remove tests of CompressionFormat::try_from since that's no longer used anywhere
|
||||
use std::{fs, path::Path};
|
||||
|
||||
// use std::{
|
||||
// convert::TryFrom,
|
||||
// ffi::{OsStr, OsString},
|
||||
// fs,
|
||||
// path::Path,
|
||||
// };
|
||||
#[allow(dead_code)]
|
||||
// ouch's command-line logic uses fs::canonicalize on its inputs so we cannot
|
||||
// use made-up files for testing.
|
||||
// make_dummy_file therefores creates a small temporary file to bypass fs::canonicalize errors
|
||||
fn make_dummy_file<'a, P>(path: P) -> crate::Result<()>
|
||||
where
|
||||
P: AsRef<Path> + 'a,
|
||||
{
|
||||
fs::write(path.as_ref(), &[2, 3, 4, 5, 6, 7, 8, 9, 10])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// use crate::{
|
||||
// cli::Command,
|
||||
// extension::{CompressionFormat, CompressionFormat::*, Extension},
|
||||
// file::File,
|
||||
// };
|
||||
#[allow(dead_code)]
|
||||
fn make_dummy_files<'a, P>(paths: &[P]) -> crate::Result<()>
|
||||
where
|
||||
P: AsRef<Path> + 'a,
|
||||
{
|
||||
let _ = paths
|
||||
.iter()
|
||||
.map(make_dummy_file)
|
||||
.map(Result::unwrap)
|
||||
.collect::<Vec<_>>();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// // Helper
|
||||
// fn gen_args(text: &str) -> Vec<OsString> {
|
||||
// let args = text.split_whitespace();
|
||||
// args.map(OsString::from).collect()
|
||||
// }
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{make_dummy_files};
|
||||
use crate::cli;
|
||||
use crate::cli::Command;
|
||||
use std::{ffi::OsString, fs, path::PathBuf};
|
||||
|
||||
fn gen_args(text: &str) -> Vec<OsString> {
|
||||
let args = text.split_whitespace();
|
||||
args.map(OsString::from).collect()
|
||||
}
|
||||
|
||||
macro_rules! parse {
|
||||
($input_text:expr) => {{
|
||||
let args = gen_args($input_text);
|
||||
cli::parse_args_from(args).unwrap()
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
// The absolute flags that ignore all the other argparsing rules are --help and --version
|
||||
fn test_absolute_flags() {
|
||||
let expected = Command::ShowHelp;
|
||||
assert_eq!(expected, parse!("").command);
|
||||
assert_eq!(expected, parse!("-h").command);
|
||||
assert_eq!(expected, parse!("--help").command);
|
||||
assert_eq!(expected, parse!("aaaaaaaa --help -o -e aaa").command);
|
||||
assert_eq!(expected, parse!("aaaaaaaa -h").command);
|
||||
assert_eq!(expected, parse!("--help compress aaaaaaaa").command);
|
||||
assert_eq!(expected, parse!("compress --help").command);
|
||||
assert_eq!(expected, parse!("--version --help").command);
|
||||
assert_eq!(expected, parse!("aaaaaaaa -v aaaa -h").command);
|
||||
|
||||
let expected = Command::ShowVersion;
|
||||
assert_eq!(expected, parse!("ouch --version").command);
|
||||
assert_eq!(expected, parse!("ouch a --version b").command);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arg_parsing_compress_subcommand() -> crate::Result<()> {
|
||||
|
||||
let files = vec!["a", "b", "c"];
|
||||
make_dummy_files(&*files)?;
|
||||
let files= files.iter().map(fs::canonicalize).map(Result::unwrap).collect();
|
||||
|
||||
let expected = Command::Compress {
|
||||
files,
|
||||
compressed_output_path: "d".into(),
|
||||
};
|
||||
assert_eq!(expected, parse!("compress a b c d").command);
|
||||
|
||||
fs::remove_file("a")?;
|
||||
fs::remove_file("b")?;
|
||||
fs::remove_file("c")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arg_parsing_decompress_subcommand() {
|
||||
let files: Vec<_> = ["a", "b", "c"].iter().map(PathBuf::from).collect();
|
||||
|
||||
let expected = Command::Decompress {
|
||||
files: files.clone(),
|
||||
output_folder: None,
|
||||
};
|
||||
assert_eq!(expected, parse!("a b c").command);
|
||||
|
||||
let expected = Command::Decompress {
|
||||
files,
|
||||
output_folder: Some("folder".into()),
|
||||
};
|
||||
assert_eq!(expected, parse!("a b c --output folder").command);
|
||||
assert_eq!(expected, parse!("a b --output folder c").command);
|
||||
assert_eq!(expected, parse!("a --output folder b c").command);
|
||||
assert_eq!(expected, parse!("--output folder a b c").command);
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod cli {
|
||||
// use super::*;
|
||||
|
||||
// // ouch's command-line logic uses fs::canonicalize on its inputs so we cannot
|
||||
// // use made-up files for testing.
|
||||
// // make_dummy_file therefores creates a small temporary file to bypass fs::canonicalize errors
|
||||
// fn make_dummy_file<'a, P>(path: P) -> crate::Result<()>
|
||||
// where
|
||||
// P: AsRef<Path> + 'a,
|
||||
// {
|
||||
// fs::write(path.as_ref(), &[2, 3, 4, 5, 6, 7, 8, 9, 10])?;
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
// #[test]
|
||||
// fn decompress_files_into_folder() -> crate::Result<()> {
|
||||
// make_dummy_file("file.zip")?;
|
||||
|
15
src/utils.rs
15
src/utils.rs
@ -9,6 +9,19 @@ use colored::Colorize;
|
||||
|
||||
use crate::{dialogs::Confirmation, extension::CompressionFormat, file::File};
|
||||
|
||||
#[macro_export]
|
||||
#[cfg(debug_assertions)]
|
||||
macro_rules! debug {
|
||||
($x:expr) => { dbg!($x) }
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[cfg(not(debug_assertions))]
|
||||
macro_rules! debug {
|
||||
($x:expr) => { std::convert::identity($x) }
|
||||
}
|
||||
|
||||
|
||||
pub(crate) fn ensure_exists<'a, P>(path: P) -> crate::Result<()>
|
||||
where
|
||||
P: AsRef<Path> + 'a,
|
||||
@ -69,7 +82,7 @@ pub(crate) fn change_dir_and_return_parent(filename: &Path) -> crate::Result<Pat
|
||||
return Err(crate::Error::CompressingRootFolder);
|
||||
};
|
||||
|
||||
env::set_current_dir(parent).unwrap();
|
||||
env::set_current_dir(parent).ok().ok_or(crate::Error::CompressingRootFolder)?;
|
||||
|
||||
Ok(previous_location)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user