mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-05 02:55:31 +00:00
Feature-gate RAR support
This commit is contained in:
parent
642552f75b
commit
fa2d214fee
@ -31,7 +31,7 @@ snap = "1.1.1"
|
||||
tar = "0.4.40"
|
||||
tempfile = "3.8.1"
|
||||
time = { version = "0.3.30", default-features = false }
|
||||
unrar = "0.5.2"
|
||||
unrar = { version = "0.5.2", optional = true }
|
||||
xz2 = "0.1.7"
|
||||
zip = { version = "0.6.6", default-features = false, features = ["time"] }
|
||||
zstd = { version = "0.13.0", default-features = false }
|
||||
|
@ -1,6 +1,9 @@
|
||||
//! Archive compression algorithms
|
||||
|
||||
#[cfg(feature = "unrar")]
|
||||
pub mod rar;
|
||||
#[cfg(not(feature = "unrar"))]
|
||||
pub mod rar_stub;
|
||||
pub mod sevenz;
|
||||
pub mod tar;
|
||||
pub mod zip;
|
||||
|
@ -4,7 +4,7 @@ use std::path::Path;
|
||||
|
||||
use unrar::{self, Archive};
|
||||
|
||||
use crate::{info, list::FileInArchive, warning};
|
||||
use crate::{error::Error, info, list::FileInArchive};
|
||||
|
||||
/// Unpacks the archive given by `archive_path` into the folder given by `output_folder`.
|
||||
/// Assumes that output_folder is empty
|
||||
@ -49,8 +49,8 @@ pub fn list_archive(archive_path: &Path) -> impl Iterator<Item = crate::Result<F
|
||||
})
|
||||
}
|
||||
|
||||
pub fn no_compression_notice() {
|
||||
const MESSAGE: &str = "Creating '.rar' archives is not supported due to licensing restrictions";
|
||||
|
||||
warning!("{}", MESSAGE);
|
||||
pub fn no_compression() -> Error {
|
||||
Error::UnsupportedFormat {
|
||||
reason: "Creating RAR archives is not allowed due to licensing restrictions.".into(),
|
||||
}
|
||||
}
|
||||
|
7
src/archive/rar_stub.rs
Normal file
7
src/archive/rar_stub.rs
Normal file
@ -0,0 +1,7 @@
|
||||
use crate::Error;
|
||||
|
||||
pub fn no_support() -> Error {
|
||||
Error::UnsupportedFormat {
|
||||
reason: "RAR support is disabled for this build, possibly due to licensing restrictions.".into(),
|
||||
}
|
||||
}
|
@ -124,8 +124,11 @@ pub fn compress_files(
|
||||
io::copy(&mut vec_buffer, &mut writer)?;
|
||||
}
|
||||
Rar => {
|
||||
archive::rar::no_compression_notice();
|
||||
return Ok(false);
|
||||
#[cfg(feature = "unrar")]
|
||||
return Err(archive::rar::no_compression());
|
||||
|
||||
#[cfg(not(feature = "unrar"))]
|
||||
return Err(archive::rar_stub::no_support());
|
||||
}
|
||||
SevenZip => {
|
||||
if !formats.is_empty() {
|
||||
|
@ -146,6 +146,7 @@ pub fn decompress_file(
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "unrar")]
|
||||
Rar => {
|
||||
type UnpackResult = crate::Result<usize>;
|
||||
let unpack_fn: Box<dyn FnOnce(&Path) -> UnpackResult> = if formats.len() > 1 {
|
||||
@ -164,6 +165,10 @@ pub fn decompress_file(
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "unrar"))]
|
||||
Rar => {
|
||||
return Err(crate::archive::rar_stub::no_support());
|
||||
}
|
||||
SevenZip => {
|
||||
if formats.len() > 1 {
|
||||
warn_user_about_loading_sevenz_in_memory();
|
||||
|
@ -78,6 +78,7 @@ pub fn list_archive_contents(
|
||||
|
||||
Box::new(crate::archive::zip::list_archive(zip_archive))
|
||||
}
|
||||
#[cfg(feature = "unrar")]
|
||||
Rar => {
|
||||
if formats.len() > 1 {
|
||||
let mut temp_file = tempfile::NamedTempFile::new()?;
|
||||
@ -87,6 +88,10 @@ pub fn list_archive_contents(
|
||||
Box::new(crate::archive::rar::list_archive(archive_path))
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "unrar"))]
|
||||
Rar => {
|
||||
return Err(crate::archive::rar_stub::no_support());
|
||||
}
|
||||
SevenZip => {
|
||||
if formats.len() > 1 {
|
||||
warn_user_about_loading_zip_in_memory();
|
||||
|
@ -36,6 +36,9 @@ pub enum Error {
|
||||
InvalidFormat { reason: String },
|
||||
/// From sevenz_rust::Error
|
||||
SevenzipError(sevenz_rust::Error),
|
||||
/// Recognised but unsupported format
|
||||
// currently only RAR when built without the `unrar` feature
|
||||
UnsupportedFormat { reason: String },
|
||||
}
|
||||
|
||||
/// Alias to std's Result with ouch's Error
|
||||
@ -142,6 +145,9 @@ impl fmt::Display for Error {
|
||||
Error::InvalidFormat { reason } => FinalError::with_title("Invalid archive format").detail(reason.clone()),
|
||||
Error::Custom { reason } => reason.clone(),
|
||||
Error::SevenzipError(reason) => FinalError::with_title("7z error").detail(reason.to_string()),
|
||||
Error::UnsupportedFormat { reason } => {
|
||||
FinalError::with_title("Recognised but unsupported format").detail(reason.clone())
|
||||
}
|
||||
};
|
||||
|
||||
write!(f, "{err}")
|
||||
@ -181,6 +187,7 @@ impl From<zip::result::ZipError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "unrar")]
|
||||
impl From<unrar::error::UnrarError> for Error {
|
||||
fn from(err: unrar::error::UnrarError) -> Self {
|
||||
Self::Custom {
|
||||
|
@ -8,10 +8,28 @@ use self::CompressionFormat::*;
|
||||
use crate::{error::Error, warning};
|
||||
|
||||
pub const SUPPORTED_EXTENSIONS: &[&str] = &[
|
||||
"tar", "zip", "bz", "bz2", "gz", "lz4", "xz", "lzma", "sz", "zst", "rar", "7z",
|
||||
"tar",
|
||||
"zip",
|
||||
"bz",
|
||||
"bz2",
|
||||
"gz",
|
||||
"lz4",
|
||||
"xz",
|
||||
"lzma",
|
||||
"sz",
|
||||
"zst",
|
||||
#[cfg(feature = "unrar")]
|
||||
"rar",
|
||||
"7z",
|
||||
];
|
||||
|
||||
pub const SUPPORTED_ALIASES: &[&str] = &["tgz", "tbz", "tlz4", "txz", "tzlma", "tsz", "tzst"];
|
||||
pub const PRETTY_SUPPORTED_EXTENSIONS: &str = "tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, rar";
|
||||
|
||||
#[cfg(not(feature = "unrar"))]
|
||||
pub const PRETTY_SUPPORTED_EXTENSIONS: &str = "tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, 7z";
|
||||
#[cfg(feature = "unrar")]
|
||||
pub const PRETTY_SUPPORTED_EXTENSIONS: &str = "tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, rar, 7z";
|
||||
|
||||
pub const PRETTY_SUPPORTED_ALIASES: &str = "tgz, tbz, tlz4, txz, tzlma, tsz, tzst";
|
||||
|
||||
/// A wrapper around `CompressionFormat` that allows combinations like `tgz`
|
||||
@ -74,6 +92,7 @@ pub enum CompressionFormat {
|
||||
Zstd,
|
||||
/// .zip
|
||||
Zip,
|
||||
// even if built without RAR support, we still want to recognise the format
|
||||
/// .rar
|
||||
Rar,
|
||||
/// .7z
|
||||
|
@ -1,10 +1,7 @@
|
||||
#[macro_use]
|
||||
mod utils;
|
||||
|
||||
use std::{
|
||||
iter::once,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use std::{iter::once, path::PathBuf};
|
||||
|
||||
use fs_err as fs;
|
||||
use parse_display::Display;
|
||||
@ -154,20 +151,20 @@ fn multiple_files(
|
||||
assert_same_directory(before, after, !matches!(ext, DirectoryExtension::Zip));
|
||||
}
|
||||
|
||||
// test .rar decompression
|
||||
fn test_unpack_rar_single(input: &Path) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let dir = tempdir()?;
|
||||
let dirpath = dir.path();
|
||||
let unpacked_path = &dirpath.join("testfile.txt");
|
||||
ouch!("-A", "d", input, "-d", dirpath);
|
||||
let content = fs::read_to_string(unpacked_path)?;
|
||||
assert_eq!(content, "Testing 123\n");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "unrar")]
|
||||
#[test]
|
||||
fn unpack_rar() -> Result<(), Box<dyn std::error::Error>> {
|
||||
fn test_unpack_rar_single(input: &std::path::Path) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let dir = tempdir()?;
|
||||
let dirpath = dir.path();
|
||||
let unpacked_path = &dirpath.join("testfile.txt");
|
||||
ouch!("-A", "d", input, "-d", dirpath);
|
||||
let content = fs::read_to_string(unpacked_path)?;
|
||||
assert_eq!(content, "Testing 123\n");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let mut datadir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR")?);
|
||||
datadir.push("tests/data");
|
||||
["testfile.rar3.rar.gz", "testfile.rar5.rar"]
|
||||
|
@ -0,0 +1,14 @@
|
||||
---
|
||||
source: tests/ui.rs
|
||||
expression: "run_ouch(\"ouch decompress a\", dir)"
|
||||
---
|
||||
[ERROR] Cannot decompress files
|
||||
- Files with missing extensions: <TMP_DIR>/a
|
||||
- Decompression formats are detected automatically from file extension
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint:
|
||||
hint: Alternatively, you can pass an extension to the '--format' flag:
|
||||
hint: ouch decompress <TMP_DIR>/a --format tar.gz
|
||||
|
@ -0,0 +1,12 @@
|
||||
---
|
||||
source: tests/ui.rs
|
||||
expression: "run_ouch(\"ouch decompress a b.unknown\", dir)"
|
||||
---
|
||||
[ERROR] Cannot decompress files
|
||||
- Files with unsupported extensions: <TMP_DIR>/b.unknown
|
||||
- Files with missing extensions: <TMP_DIR>/a
|
||||
- Decompression formats are detected automatically from file extension
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
|
@ -0,0 +1,14 @@
|
||||
---
|
||||
source: tests/ui.rs
|
||||
expression: "run_ouch(\"ouch decompress b.unknown\", dir)"
|
||||
---
|
||||
[ERROR] Cannot decompress files
|
||||
- Files with unsupported extensions: <TMP_DIR>/b.unknown
|
||||
- Decompression formats are detected automatically from file extension
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, rar, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint:
|
||||
hint: Alternatively, you can pass an extension to the '--format' flag:
|
||||
hint: ouch decompress <TMP_DIR>/b.unknown --format tar.gz
|
||||
|
@ -6,7 +6,7 @@ expression: "run_ouch(\"ouch decompress a\", dir)"
|
||||
- Files with missing extensions: <TMP_DIR>/a
|
||||
- Decompression formats are detected automatically from file extension
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, rar
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint:
|
||||
hint: Alternatively, you can pass an extension to the '--format' flag:
|
@ -7,6 +7,6 @@ expression: "run_ouch(\"ouch decompress a b.unknown\", dir)"
|
||||
- Files with missing extensions: <TMP_DIR>/a
|
||||
- Decompression formats are detected automatically from file extension
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, rar
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
|
@ -6,7 +6,7 @@ expression: "run_ouch(\"ouch decompress b.unknown\", dir)"
|
||||
- Files with unsupported extensions: <TMP_DIR>/b.unknown
|
||||
- Decompression formats are detected automatically from file extension
|
||||
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, rar
|
||||
hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst, 7z
|
||||
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
|
||||
hint:
|
||||
hint: Alternatively, you can pass an extension to the '--format' flag:
|
14
tests/ui.rs
14
tests/ui.rs
@ -65,9 +65,17 @@ fn ui_test_err_decompress_missing_extension() {
|
||||
|
||||
run_in(dir, "touch", "a b.unknown").unwrap();
|
||||
|
||||
ui!(run_ouch("ouch decompress a", dir));
|
||||
ui!(run_ouch("ouch decompress a b.unknown", dir));
|
||||
ui!(run_ouch("ouch decompress b.unknown", dir));
|
||||
let name = {
|
||||
let suffix = if cfg!(feature = "unrar") {
|
||||
"with_rar"
|
||||
} else {
|
||||
"without_rar"
|
||||
};
|
||||
format!("ui_test_err_decompress_missing_extension_{suffix}")
|
||||
};
|
||||
ui!(format!("{name}-1"), run_ouch("ouch decompress a", dir));
|
||||
ui!(format!("{name}-2"), run_ouch("ouch decompress a b.unknown", dir));
|
||||
ui!(format!("{name}-3"), run_ouch("ouch decompress b.unknown", dir));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Loading…
x
Reference in New Issue
Block a user