mirror of
https://github.com/ouch-org/ouch.git
synced 2025-06-07 03:55:28 +00:00

Fixes #687. If "-" is passed as a filename, decompress data from stdin. Currently `--format` must be passed as well, but as a next step, we could try to infer the format from magic numbers. As stdin is not connected to the terminal, we cannot prompt for Y/N when warning about decompression in memory, for e.g. zip. Just default to No, and require passing "-y" in these cases. For zip, we have to buffer the whole stream in memory to seek into it, just as we do with a chained decoder like `.zip.bz`. The rar format requires an actual file (not an `impl Read`), so we write a temp file that it can decode. When decoding a single-file archive (e.g. file.bz), the output filename is just `-`, since we don't know the original filename. I had to add a bit of a hack to the tests to work around this. Another option would be to interpret "-d" as a destination filename in this case. When decoding a multi-file archive, I decided to unpack directly into the destination directory, as this seemed like a better experience than adding a top-level "-" folder inside the destination.
65 lines
1.8 KiB
Rust
65 lines
1.8 KiB
Rust
//! CLI related functions, uses the clap argparsing definitions from `args.rs`.
|
|
|
|
mod args;
|
|
|
|
use std::{
|
|
io,
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
use clap::Parser;
|
|
use fs_err as fs;
|
|
|
|
pub use self::args::{CliArgs, Subcommand};
|
|
use crate::{
|
|
accessible::set_accessible,
|
|
utils::{is_path_stdin, FileVisibilityPolicy},
|
|
QuestionPolicy,
|
|
};
|
|
|
|
impl CliArgs {
|
|
/// A helper method that calls `clap::Parser::parse`.
|
|
///
|
|
/// And:
|
|
/// 1. Make paths absolute.
|
|
/// 2. Checks the QuestionPolicy.
|
|
pub fn parse_and_validate_args() -> crate::Result<(Self, QuestionPolicy, FileVisibilityPolicy)> {
|
|
let mut args = Self::parse();
|
|
|
|
set_accessible(args.accessible);
|
|
|
|
let (Subcommand::Compress { files, .. }
|
|
| Subcommand::Decompress { files, .. }
|
|
| Subcommand::List { archives: files, .. }) = &mut args.cmd;
|
|
*files = canonicalize_files(files)?;
|
|
|
|
let skip_questions_positively = match (args.yes, args.no) {
|
|
(false, false) => QuestionPolicy::Ask,
|
|
(true, false) => QuestionPolicy::AlwaysYes,
|
|
(false, true) => QuestionPolicy::AlwaysNo,
|
|
(true, true) => unreachable!(),
|
|
};
|
|
|
|
let file_visibility_policy = FileVisibilityPolicy::new()
|
|
.read_git_exclude(args.gitignore)
|
|
.read_ignore(args.gitignore)
|
|
.read_git_ignore(args.gitignore)
|
|
.read_hidden(args.hidden);
|
|
|
|
Ok((args, skip_questions_positively, file_visibility_policy))
|
|
}
|
|
}
|
|
|
|
fn canonicalize_files(files: &[impl AsRef<Path>]) -> io::Result<Vec<PathBuf>> {
|
|
files
|
|
.iter()
|
|
.map(|f| {
|
|
if is_path_stdin(f.as_ref()) {
|
|
Ok(f.as_ref().to_path_buf())
|
|
} else {
|
|
fs::canonicalize(f)
|
|
}
|
|
})
|
|
.collect()
|
|
}
|