mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-06 19:45:29 +00:00
Minor refactor to archive handling code
This commit is contained in:
parent
69b1db4a35
commit
8483739184
@ -1,11 +1,12 @@
|
|||||||
//! SevenZip archive format compress function
|
//! SevenZip archive format compress function
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env, io,
|
||||||
fs::File,
|
|
||||||
io::{Read, Seek, Write},
|
io::{Read, Seek, Write},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use fs_err as fs;
|
||||||
use same_file::Handle;
|
use same_file::Handle;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -24,12 +25,14 @@ pub fn compress_sevenz<W>(
|
|||||||
where
|
where
|
||||||
W: Write + Seek,
|
W: Write + Seek,
|
||||||
{
|
{
|
||||||
let mut writer = sevenz_rust::SevenZWriter::new(writer).map_err(crate::Error::SevenzipError)?;
|
let mut writer = sevenz_rust::SevenZWriter::new(writer)?;
|
||||||
let output_handle = Handle::from_path(output_path);
|
let output_handle = Handle::from_path(output_path);
|
||||||
|
|
||||||
for filename in files {
|
for filename in files {
|
||||||
let previous_location = cd_into_same_dir_as(filename)?;
|
let previous_location = cd_into_same_dir_as(filename)?;
|
||||||
|
|
||||||
// Safe unwrap, input shall be treated before
|
// Unwrap safety:
|
||||||
|
// paths should be canonicalized by now, and the root directory rejected.
|
||||||
let filename = filename.file_name().unwrap();
|
let filename = filename.file_name().unwrap();
|
||||||
|
|
||||||
for entry in file_visibility_policy.build_walker(filename) {
|
for entry in file_visibility_policy.build_walker(filename) {
|
||||||
@ -37,7 +40,7 @@ where
|
|||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
|
|
||||||
// If the output_path is the same as the input file, warn the user and skip the input (in order to avoid compression recursion)
|
// If the output_path is the same as the input file, warn the user and skip the input (in order to avoid compression recursion)
|
||||||
if let Ok(ref handle) = output_handle {
|
if let Ok(handle) = &output_handle {
|
||||||
if matches!(Handle::from_path(path), Ok(x) if &x == handle) {
|
if matches!(Handle::from_path(path), Ok(x) if &x == handle) {
|
||||||
warning!(
|
warning!(
|
||||||
"The output file and the input file are the same: `{}`, skipping...",
|
"The output file and the input file are the same: `{}`, skipping...",
|
||||||
@ -67,22 +70,15 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if metadata.is_dir() {
|
let entry_name = path.to_str().unwrap().to_owned();
|
||||||
writer
|
let entry = sevenz_rust::SevenZArchiveEntry::from_path(path, entry_name);
|
||||||
.push_archive_entry::<std::fs::File>(
|
let entry_data = if metadata.is_dir() {
|
||||||
sevenz_rust::SevenZArchiveEntry::from_path(path, path.to_str().unwrap().to_owned()),
|
None
|
||||||
None,
|
|
||||||
)
|
|
||||||
.map_err(crate::Error::SevenzipError)?;
|
|
||||||
} else {
|
} else {
|
||||||
let reader = File::open(path)?;
|
Some(fs::File::open(path)?)
|
||||||
writer
|
};
|
||||||
.push_archive_entry::<std::fs::File>(
|
|
||||||
sevenz_rust::SevenZArchiveEntry::from_path(path, path.to_str().unwrap().to_owned()),
|
writer.push_archive_entry::<fs::File>(entry, entry_data)?;
|
||||||
Some(reader),
|
|
||||||
)
|
|
||||||
.map_err(crate::Error::SevenzipError)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
env::set_current_dir(previous_location)?;
|
env::set_current_dir(previous_location)?;
|
||||||
@ -97,7 +93,7 @@ where
|
|||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
let mut count: usize = 0;
|
let mut count: usize = 0;
|
||||||
sevenz_rust::decompress_with_extract_fn(reader, output_path, |entry, reader, dest| {
|
sevenz_rust::decompress_with_extract_fn(reader, output_path, |entry, reader, path| {
|
||||||
count += 1;
|
count += 1;
|
||||||
// Manually handle writing all files from 7z archive, due to library exluding empty files
|
// Manually handle writing all files from 7z archive, due to library exluding empty files
|
||||||
use std::io::BufWriter;
|
use std::io::BufWriter;
|
||||||
@ -107,10 +103,6 @@ where
|
|||||||
let file_path = output_path.join(entry.name());
|
let file_path = output_path.join(entry.name());
|
||||||
|
|
||||||
if entry.is_directory() {
|
if entry.is_directory() {
|
||||||
// This is printed for every file in the archive and has little
|
|
||||||
// importance for most users, but would generate lots of
|
|
||||||
// spoken text for users using screen readers, braille displays
|
|
||||||
// and so on
|
|
||||||
if !quiet {
|
if !quiet {
|
||||||
info!(
|
info!(
|
||||||
inaccessible,
|
inaccessible,
|
||||||
@ -119,12 +111,10 @@ where
|
|||||||
file_path.display()
|
file_path.display()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let dir = dest;
|
if !path.exists() {
|
||||||
if !dir.exists() {
|
fs::create_dir_all(path)?;
|
||||||
std::fs::create_dir_all(dir)?;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// same reason is in _is_dir: long, often not needed text
|
|
||||||
if !quiet {
|
if !quiet {
|
||||||
info!(
|
info!(
|
||||||
inaccessible,
|
inaccessible,
|
||||||
@ -133,27 +123,28 @@ where
|
|||||||
Bytes::new(entry.size()),
|
Bytes::new(entry.size()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let path = dest;
|
|
||||||
path.parent().and_then(|p| {
|
if let Some(parent) = path.parent() {
|
||||||
if !p.exists() {
|
if !parent.exists() {
|
||||||
std::fs::create_dir_all(p).ok()
|
fs::create_dir_all(parent)?;
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
let file = File::create(path)?;
|
|
||||||
|
let file = fs::File::create(path)?;
|
||||||
let mut writer = BufWriter::new(file);
|
let mut writer = BufWriter::new(file);
|
||||||
std::io::copy(reader, &mut writer)?;
|
io::copy(reader, &mut writer)?;
|
||||||
|
|
||||||
ft::set_file_handle_times(
|
ft::set_file_handle_times(
|
||||||
writer.get_ref(),
|
writer.get_ref().file(),
|
||||||
Some(ft::FileTime::from_system_time(entry.access_date().into())),
|
Some(ft::FileTime::from_system_time(entry.access_date().into())),
|
||||||
Some(ft::FileTime::from_system_time(entry.last_modified_date().into())),
|
Some(ft::FileTime::from_system_time(entry.last_modified_date().into())),
|
||||||
Some(ft::FileTime::from_system_time(entry.creation_date().into())),
|
Some(ft::FileTime::from_system_time(entry.creation_date().into())),
|
||||||
)
|
)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
})
|
})?;
|
||||||
.map_err(crate::Error::SevenzipError)?;
|
|
||||||
Ok(count)
|
Ok(count)
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,8 @@ where
|
|||||||
for filename in input_filenames {
|
for filename in input_filenames {
|
||||||
let previous_location = utils::cd_into_same_dir_as(filename)?;
|
let previous_location = utils::cd_into_same_dir_as(filename)?;
|
||||||
|
|
||||||
// Safe unwrap, input shall be treated before
|
// Unwrap safety:
|
||||||
|
// paths should be canonicalized by now, and the root directory rejected.
|
||||||
let filename = filename.file_name().unwrap();
|
let filename = filename.file_name().unwrap();
|
||||||
|
|
||||||
for entry in file_visibility_policy.build_walker(filename) {
|
for entry in file_visibility_policy.build_walker(filename) {
|
||||||
@ -104,7 +105,7 @@ where
|
|||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
|
|
||||||
// If the output_path is the same as the input file, warn the user and skip the input (in order to avoid compression recursion)
|
// If the output_path is the same as the input file, warn the user and skip the input (in order to avoid compression recursion)
|
||||||
if let Ok(ref handle) = output_handle {
|
if let Ok(handle) = &output_handle {
|
||||||
if matches!(Handle::from_path(path), Ok(x) if &x == handle) {
|
if matches!(Handle::from_path(path), Ok(x) if &x == handle) {
|
||||||
warning!(
|
warning!(
|
||||||
"The output file and the input file are the same: `{}`, skipping...",
|
"The output file and the input file are the same: `{}`, skipping...",
|
||||||
|
@ -167,7 +167,8 @@ where
|
|||||||
for filename in input_filenames {
|
for filename in input_filenames {
|
||||||
let previous_location = cd_into_same_dir_as(filename)?;
|
let previous_location = cd_into_same_dir_as(filename)?;
|
||||||
|
|
||||||
// Safe unwrap, input shall be treated before
|
// Unwrap safety:
|
||||||
|
// paths should be canonicalized by now, and the root directory rejected.
|
||||||
let filename = filename.file_name().unwrap();
|
let filename = filename.file_name().unwrap();
|
||||||
|
|
||||||
for entry in file_visibility_policy.build_walker(filename) {
|
for entry in file_visibility_policy.build_walker(filename) {
|
||||||
@ -175,7 +176,7 @@ where
|
|||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
|
|
||||||
// If the output_path is the same as the input file, warn the user and skip the input (in order to avoid compression recursion)
|
// If the output_path is the same as the input file, warn the user and skip the input (in order to avoid compression recursion)
|
||||||
if let Ok(ref handle) = output_handle {
|
if let Ok(handle) = &output_handle {
|
||||||
if matches!(Handle::from_path(path), Ok(x) if &x == handle) {
|
if matches!(Handle::from_path(path), Ok(x) if &x == handle) {
|
||||||
warning!(
|
warning!(
|
||||||
"The output file and the input file are the same: `{}`, skipping...",
|
"The output file and the input file are the same: `{}`, skipping...",
|
||||||
|
@ -103,8 +103,7 @@ pub fn list_archive_contents(
|
|||||||
is_dir: entry.is_directory(),
|
is_dir: entry.is_directory(),
|
||||||
}));
|
}));
|
||||||
Ok(true)
|
Ok(true)
|
||||||
})
|
})?;
|
||||||
.map_err(crate::Error::SevenzipError)?;
|
|
||||||
Box::new(files.into_iter())
|
Box::new(files.into_iter())
|
||||||
}
|
}
|
||||||
Gzip | Bzip | Lz4 | Lzma | Snappy | Zstd => {
|
Gzip | Bzip | Lz4 | Lzma | Snappy | Zstd => {
|
||||||
|
@ -189,6 +189,12 @@ impl From<unrar::error::UnrarError> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<sevenz_rust::Error> for Error {
|
||||||
|
fn from(err: sevenz_rust::Error) -> Self {
|
||||||
|
Self::SevenzipError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<ignore::Error> for Error {
|
impl From<ignore::Error> for Error {
|
||||||
fn from(err: ignore::Error) -> Self {
|
fn from(err: ignore::Error) -> Self {
|
||||||
Self::WalkdirError {
|
Self::WalkdirError {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user