Improve hints when decompressing with no extension

refactored `check_missing_formats_when_decompressing` to be aware of
missing extensions and unsupported extensions in order to give a more
detailed error message
This commit is contained in:
João M. Bezerra 2023-09-16 13:44:45 -03:00 committed by João Marcos
parent bc1d9457f0
commit a26d3d34ce
6 changed files with 81 additions and 31 deletions

View File

@ -10,7 +10,7 @@ use std::{
use crate::{
error::FinalError,
extension::{build_archive_file_suggestion, Extension},
extension::{build_archive_file_suggestion, Extension, PRETTY_SUPPORTED_ALIASES, PRETTY_SUPPORTED_EXTENSIONS},
info,
utils::{pretty_format_list_of_paths, try_infer_extension, user_wants_to_continue, EscapedPathDisplay},
warning, QuestionAction, QuestionPolicy, Result,
@ -127,32 +127,55 @@ pub fn check_archive_formats_position(formats: &[Extension], output_path: &Path)
/// Check if all provided files have formats to decompress.
pub fn check_missing_formats_when_decompressing(files: &[PathBuf], formats: &[Vec<Extension>]) -> Result<()> {
let files_missing_format: Vec<PathBuf> = files
let files_with_broken_extension: Vec<&PathBuf> = files
.iter()
.zip(formats)
.filter(|(_, format)| format.is_empty())
.map(|(input_path, _)| PathBuf::from(input_path))
.map(|(input_path, _)| input_path)
.collect();
if let Some(path) = files_missing_format.first() {
let error = FinalError::with_title("Cannot decompress files without extensions")
.detail(format!(
"Files without supported extensions: {}",
pretty_format_list_of_paths(&files_missing_format)
))
.detail("Decompression formats are detected automatically by the file extension")
.hint("Provide a file with a supported extension:")
.hint(" ouch decompress example.tar.gz")
if files_with_broken_extension.is_empty() {
return Ok(());
}
let (files_with_unsupported_extensions, files_missing_extension): (Vec<&PathBuf>, Vec<&PathBuf>) =
files_with_broken_extension
.iter()
.partition(|path| path.extension().is_some());
let mut error = FinalError::with_title("Cannot decompress files");
if !files_with_unsupported_extensions.is_empty() {
error = error.detail(format!(
"Files with unsupported extensions: {}",
pretty_format_list_of_paths(&files_with_unsupported_extensions)
));
}
if !files_missing_extension.is_empty() {
error = error.detail(format!(
"Files with missing extensions: {}",
pretty_format_list_of_paths(&files_missing_extension)
));
}
error = error
.detail("Decompression formats are detected automatically from file extension")
.hint(format!("Supported extensions are: {}", PRETTY_SUPPORTED_EXTENSIONS))
.hint(format!("Supported aliases are: {}", PRETTY_SUPPORTED_ALIASES));
// If there's exactly one file, give a suggestion to use `--format`
if let &[path] = files_with_broken_extension.as_slice() {
error = error
.hint("")
.hint("Or overwrite this option with the '--format' flag:")
.hint("Alternatively, you can pass an extension to the '--format' flag:")
.hint(format!(
" ouch decompress {} --format tar.gz",
EscapedPathDisplay::new(path),
));
return Err(error.into());
}
Ok(())
Err(error.into())
}
/// Check if there is a first format when compressing, and returns it.

View File

@ -7,6 +7,11 @@ use bstr::ByteSlice;
use self::CompressionFormat::*;
use crate::{error::Error, warning};
pub const SUPPORTED_EXTENSIONS: &[&str] = &["tar", "zip", "bz", "bz2", "gz", "lz4", "xz", "lzma", "sz", "zst"];
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";
pub const PRETTY_SUPPORTED_ALIASES: &str = "tgz, tbz, tlz4, txz, tzlma, tsz, tzst";
/// A wrapper around `CompressionFormat` that allows combinations like `tgz`
#[derive(Debug, Clone, Eq)]
#[non_exhaustive]
@ -85,11 +90,6 @@ impl CompressionFormat {
}
}
pub const SUPPORTED_EXTENSIONS: &[&str] = &[
"tar", "tgz", "tbz", "tlz4", "txz", "tzlma", "tsz", "tzst", "zip", "bz", "bz2", "gz", "lz4", "xz", "lzma", "sz",
"zst",
];
fn to_extension(ext: &[u8]) -> Option<Extension> {
Some(Extension::new(
match ext {
@ -156,7 +156,7 @@ pub fn separate_known_extensions_from_name(path: &Path) -> (&Path, Vec<Extension
if let Ok(name) = name.to_str() {
let file_stem = name.trim_matches('.');
if SUPPORTED_EXTENSIONS.contains(&file_stem) {
if SUPPORTED_EXTENSIONS.contains(&file_stem) || SUPPORTED_ALIASES.contains(&file_stem) {
warning!("Received a file with name '{file_stem}', but {file_stem} was expected as the extension.");
}
}
@ -208,7 +208,7 @@ pub fn build_archive_file_suggestion(path: &Path, suggested_extension: &str) ->
// If the extension we got is a supported extension, generate the suggestion
// at the position we found
if SUPPORTED_EXTENSIONS.contains(&maybe_extension) {
if SUPPORTED_EXTENSIONS.contains(&maybe_extension) || SUPPORTED_ALIASES.contains(&maybe_extension) {
let mut path = path.to_string();
path.insert_str(position_to_insert - 1, suggested_extension);
@ -227,7 +227,6 @@ mod tests {
#[test]
fn test_extensions_from_path() {
use CompressionFormat::*;
let path = Path::new("bolovo.tar.gz");
let extensions: Vec<Extension> = extensions_from_path(path);

View File

@ -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: <FOLDER>/b.unknown
- Files with missing extensions: <FOLDER>/a
- Decompression formats are detected automatically from file extension
hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst

View File

@ -0,0 +1,14 @@
---
source: tests/ui.rs
expression: "run_ouch(\"ouch decompress b.unknown\", dir)"
---
[ERROR] Cannot decompress files
- Files with unsupported extensions: <FOLDER>/b.unknown
- Decompression formats are detected automatically from file extension
hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst
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 <FOLDER>/b.unknown --format tar.gz

View File

@ -2,13 +2,13 @@
source: tests/ui.rs
expression: "run_ouch(\"ouch decompress a\", dir)"
---
[ERROR] Cannot decompress files without extensions
- Files without supported extensions: <FOLDER>/a
- Decompression formats are detected automatically by the file extension
[ERROR] Cannot decompress files
- Files with missing extensions: <FOLDER>/a
- Decompression formats are detected automatically from file extension
hint: Provide a file with a supported extension:
hint: ouch decompress example.tar.gz
hint: Supported extensions are: tar, zip, bz, bz2, gz, lz4, xz, lzma, sz, zst
hint: Supported aliases are: tgz, tbz, tlz4, txz, tzlma, tsz, tzst
hint:
hint: Or overwrite this option with the '--format' flag:
hint: Alternatively, you can pass an extension to the '--format' flag:
hint: ouch decompress <FOLDER>/a --format tar.gz

View File

@ -71,9 +71,11 @@ fn ui_test_err_compress_missing_extension() {
fn ui_test_err_decompress_missing_extension() {
let (_dropper, dir) = testdir().unwrap();
run_in(dir, "touch", "a").unwrap();
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));
}
#[test]