Docs improvements

+ Removed some dead code
This commit is contained in:
João M. Bezerra 2021-11-02 04:57:26 -03:00
parent ebe3918478
commit d2d4a929e1
10 changed files with 122 additions and 82 deletions

View File

@ -71,7 +71,6 @@ where
FinalError::with_title("Could not create archive")
.detail("Unexpected error while trying to read file")
.detail(format!("Error: {}.", err))
.into_owned()
})?;
}
}

View File

@ -1,6 +1,4 @@
//! CLI configuration step, uses definitions from `opts.rs`.
//!
//! Also used to treat some inputs.
//! CLI related functions, uses the clap argparsing definitions from `opts.rs`.
use std::{
path::{Path, PathBuf},
@ -13,8 +11,11 @@ use fs_err as fs;
use crate::{Error, Opts, QuestionPolicy, Subcommand};
impl Opts {
/// A helper method that calls `clap::Parser::parse` and then translates relative paths to absolute.
/// Also determines if the user wants to skip questions or not
/// A helper method that calls `clap::Parser::parse`.
///
/// And:
/// 1. Make paths absolute.
/// 2. Checks the QuestionPolicy.
pub fn parse_args() -> crate::Result<(Self, QuestionPolicy)> {
let mut opts: Self = Self::parse();

View File

@ -37,7 +37,7 @@ fn represents_several_files(files: &[PathBuf]) -> bool {
}
/// Entrypoint of ouch, receives cli options and matches Subcommand
/// to decide current operation
/// to decide what to do
pub fn run(args: Opts, question_policy: QuestionPolicy) -> crate::Result<()> {
match args.cmd {
Subcommand::Compress { files, output: output_path } => {

View File

@ -1,7 +1,7 @@
//! Pretty (and colored) dialog for asking [Y/n] for the end user.
//!
//! Example:
//! "Do you want to overwrite 'archive.targz'? [Y/n]"
//! "Do you want to overwrite 'archive.tar.gz'? [Y/n]"
use std::{
borrow::Cow,
@ -10,19 +10,21 @@ use std::{
use crate::utils::colors;
/// Represents a confirmation dialog
/// Confirmation dialog for end user with [Y/n] question.
///
/// If the placeholder is found in the prompt text, it will be replaced to form the final message.
pub struct Confirmation<'a> {
/// Represents the message to the displayed
/// The message to be displayed with the placeholder text in it.
/// e.g.: "Do you want to overwrite 'FILE'?"
pub prompt: &'a str,
/// Represents a placeholder to be changed at runtime
/// The placeholder text that will be replaced in the `ask` function:
/// e.g.: Some("FILE")
pub placeholder: Option<&'a str>,
}
impl<'a> Confirmation<'a> {
/// New Confirmation
/// Creates a new Confirmation.
pub const fn new(prompt: &'a str, pattern: Option<&'a str>) -> Self {
Self { prompt, placeholder: pattern }
}
@ -35,20 +37,17 @@ impl<'a> Confirmation<'a> {
(Some(placeholder), Some(subs)) => Cow::Owned(self.prompt.replace(placeholder, subs)),
};
// Ask the same question to end while no valid answers are given
loop {
print!("{} [{}Y{}/{}n{}] ", message, *colors::GREEN, *colors::RESET, *colors::RED, *colors::RESET);
io::stdout().flush()?;
let mut answer = String::new();
io::stdin().read_line(&mut answer)?;
let trimmed_answer = answer.trim();
if trimmed_answer.is_empty() {
return Ok(true);
}
match trimmed_answer.to_ascii_lowercase().as_ref() {
"y" | "yes" => return Ok(true),
answer.make_ascii_lowercase();
match answer.trim() {
"" | "y" | "yes" => return Ok(true),
"n" | "no" => return Ok(false),
_ => continue, // Try again
}

View File

@ -1,12 +1,6 @@
//! Error type definitions.
//! Error types definitions.
//!
//! All the unexpected user-side errors should be treated in this file, that does not include
//! errors made by devs in our implementation.
//!
//! TODO: wrap `FinalError` in a variant to keep all `FinalError::display_and_crash()` function
//! calls inside of this module.
#![allow(missing_docs)]
//! All usage errors will pass throught the Error enum, a lot of them in the Error::Custom.
use std::{
fmt::{self, Display},
@ -15,32 +9,64 @@ use std::{
use crate::utils::colors::*;
/// Custom Ouch Errors
/// All errors that can be generated by `ouch`
#[derive(Debug, PartialEq)]
pub enum Error {
/// Extension found is not supported and known to ouch
UnknownExtensionError(String),
/// TO BE REMOVED
MissingExtensionError(PathBuf),
IoError { reason: String },
/// Not every IoError, some of them get filtered by `From<io::Error>` into other variants
IoError {
/// TODO
reason: String,
},
/// Detected from io::Error if .kind() is io::ErrorKind::NotFound
FileNotFound(PathBuf),
/// TO BE REMOVED
AlreadyExists,
/// TO BE REMOVED
InvalidZipArchive(&'static str),
PermissionDenied { error_title: String },
/// Detected from io::Error if .kind() is io::ErrorKind::PermissionDenied
PermissionDenied {
/// TODO
error_title: String,
},
/// TO BE REMOVED
UnsupportedZipArchive(&'static str),
/// TO BE REMOVED
InternalError,
/// TO BE REMOVED
CompressingRootFolder,
/// TO BE REMOVED
MissingArgumentsForCompression,
/// TO BE REMOVED
MissingArgumentsForDecompression,
/// TO BE REMOVED
CompressionTypo,
WalkdirError { reason: String },
Custom { reason: FinalError },
/// Specialized walkdir's io::Error wrapper with additional information on the error
WalkdirError {
/// TODO
reason: String,
},
/// Custom and unique errors are reported in this variant
Custom {
/// TODO
reason: FinalError,
},
}
/// Alias to std's Result with ouch's Error
pub type Result<T> = std::result::Result<T, Error>;
/// Pretty final error message for end users, crashing the program after display.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct FinalError {
/// Should be made of just one line, appears after the "[ERROR]" part
title: String,
/// Shown as a unnumbered list in yellow
details: Vec<String>,
/// Shown as green at the end to give hints on how to work around this error, if it's fixable
hints: Vec<String>,
}
@ -68,23 +94,22 @@ impl Display for FinalError {
}
impl FinalError {
/// Only constructor
pub fn with_title(title: impl ToString) -> Self {
Self { title: title.to_string(), details: vec![], hints: vec![] }
}
/// Add one detail line, can have multiple
pub fn detail(mut self, detail: impl ToString) -> Self {
self.details.push(detail.to_string());
self
}
/// Add one hint line, can have multiple
pub fn hint(mut self, hint: impl ToString) -> Self {
self.hints.push(hint.to_string());
self
}
pub fn into_owned(&mut self) -> Self {
std::mem::take(self)
}
}
impl fmt::Display for Error {
@ -151,6 +176,7 @@ impl fmt::Display for Error {
}
impl Error {
/// TO BE REMOVED
pub fn with_reason(reason: FinalError) -> Self {
Self::Custom { reason }
}

View File

@ -7,7 +7,9 @@ use self::CompressionFormat::*;
/// A wrapper around `CompressionFormat` that allows combinations like `tgz`
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Extension {
/// One extension like "tgz" can be made of multiple CompressionFormats ([Tar, Gz])
pub compression_formats: Vec<CompressionFormat>,
/// The input text for this extension, like "tgz", "tar" or "xz"
pub display_text: String,
}
@ -26,6 +28,7 @@ impl Extension {
self.compression_formats[0].is_archive_format()
}
/// Iteration to inner compression formats, useful for flat_mapping
pub fn iter(&self) -> impl Iterator<Item = &CompressionFormat> {
self.compression_formats.iter()
}
@ -37,16 +40,21 @@ impl fmt::Display for Extension {
}
}
#[allow(missing_docs)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
/// Accepted extensions for input and output
pub enum CompressionFormat {
Gzip, // .gz
Bzip, // .bz
Lzma, // .lzma
Tar, // .tar (technically not a compression extension, but will do for now)
Zstd, // .zst
Zip, // .zip
/// .gz
Gzip,
/// .bz .bz2
Bzip,
/// .xz .lzma .lz
Lzma,
/// tar, tgz, tbz, tbz2, txz, tlz, tlzma, tzst
Tar,
/// .zst
Zstd,
/// .zip
Zip,
}
impl CompressionFormat {

View File

@ -1,8 +1,4 @@
//! This library is meant to be published, just used internally by our binary crate at `main.rs`.
//!
//! A module shall be public only if:
//! 1. It's required by `main.rs`, or
//! 2. It's required by some integration tests at tests/ folder.
//! This library isn't meant to be published, but used internally by our binary crate `main.rs`.
#![warn(missing_docs)]
@ -17,12 +13,12 @@ pub mod error;
pub mod extension;
pub mod utils;
/// CLI configuration step, uses definitions from `opts.rs`, also used to treat some inputs.
/// CLI argparsing definitions, using `clap`.
pub mod opts;
pub use error::{Error, Result};
pub use opts::{Opts, Subcommand};
pub use utils::QuestionPolicy;
/// The status code ouch has when an error is encountered
/// The status code returned from `ouch` on error
pub const EXIT_FAILURE: i32 = libc::EXIT_FAILURE;

View File

@ -1,6 +1,6 @@
//! Macros used on ouch.
/// Macro that prints message in INFO mode
/// Macro that prints [INFO] messages, wraps [`println`].
#[macro_export]
macro_rules! info {
($($arg:tt)*) => {
@ -9,7 +9,7 @@ macro_rules! info {
};
}
/// Prints the `[Info]` tag
/// Helper to display "[INFO]", colored yellow
pub fn _info_helper() {
use crate::utils::colors::{RESET, YELLOW};

View File

@ -6,41 +6,51 @@ use std::path::PathBuf;
#[derive(Parser, Debug)]
#[clap(version, about)]
pub struct Opts {
/// Skip overwrite questions positively.
/// Skip [Y/n] questions positively.
#[clap(short, long, conflicts_with = "no")]
pub yes: bool,
/// Skip overwrite questions negatively.
/// Skip [Y/n] questions negatively.
#[clap(short, long)]
pub no: bool,
/// Action to take
/// Ouch and claps subcommands
#[clap(subcommand)]
pub cmd: Subcommand,
}
/// Actions to take
// CAREFUL: this docs can accidentally become part of the --help message if they get too long
// this was tested in clap 3.0.0-beta5.
/// Repository: https://github.com/ouch-org/ouch
//
// Ouch commands:
// - `compress`
// - `decompress`
// - `list`
//
// Clap commands:
// - `help`
#[derive(Parser, PartialEq, Eq, Debug)]
pub enum Subcommand {
/// Compress files. Alias: c
/// Compress one or more files into one output file.
#[clap(alias = "c")]
Compress {
/// Files to be compressed
/// Files to be compressed.
#[clap(required = true, min_values = 1)]
files: Vec<PathBuf>,
/// The resulting file. Its extensions specify how the files will be compressed and they need to be supported
/// The resulting file. It's extensions can be used to specify the compression formats.
#[clap(required = true, value_hint = ValueHint::FilePath)]
output: PathBuf,
},
/// Compress files. Alias: d
/// Decompresses one or more files, optionally into another folder.
#[clap(alias = "d")]
Decompress {
/// Files to be decompressed
/// Files to be decompressed.
#[clap(required = true, min_values = 1)]
files: Vec<PathBuf>,
/// Decompress files in a directory other than the current
/// Choose to files in a directory other than the current
#[clap(short, long = "dir", value_hint = ValueHint::DirPath)]
output_dir: Option<PathBuf>,
},

View File

@ -1,4 +1,4 @@
//! Utils used on ouch.
//! Random stuff used on ouch.
use std::{
cmp, env,
@ -11,7 +11,7 @@ use fs_err as fs;
use crate::{dialogs::Confirmation, info};
/// Checks if the given path represents an empty directory.
/// Checks given path points to an empty directory.
pub fn dir_is_empty(dir_path: &Path) -> bool {
let is_empty = |mut rd: std::fs::ReadDir| rd.next().is_none();
@ -37,21 +37,18 @@ pub fn strip_cur_dir(source_path: &Path) -> PathBuf {
.unwrap_or_else(|_| source_path.to_path_buf())
}
/// Changes the process' current directory to the directory that contains the
/// file pointed to by `filename` and returns the directory that the process
/// was in before this function was called.
/// Returns current directory, but before change the process' directory to the
/// one that contains the file pointed to by `filename`.
pub fn cd_into_same_dir_as(filename: &Path) -> crate::Result<PathBuf> {
let previous_location = env::current_dir()?;
let parent = filename.parent().ok_or(crate::Error::CompressingRootFolder)?;
env::set_current_dir(parent)?;
Ok(previous_location)
}
/// Centralizes the decision of overwriting a file or not,
/// whether the user has already passed a question_policy or not.
/// Check if QuestionPolicy flags were set, otherwise, ask user if they want to overwrite.
pub fn user_wants_to_overwrite(path: &Path, question_policy: QuestionPolicy) -> crate::Result<bool> {
match question_policy {
QuestionPolicy::AlwaysYes => Ok(true),
@ -65,13 +62,17 @@ pub fn user_wants_to_overwrite(path: &Path, question_policy: QuestionPolicy) ->
}
}
/// Converts an OsStr to utf8.
/// Converts an OsStr to utf8 with custom formatting.
///
/// This is different from [`Path::display`].
///
/// See https://gist.github.com/marcospb19/ebce5572be26397cf08bbd0fd3b65ac1 for a comparison.
pub fn to_utf(os_str: impl AsRef<OsStr>) -> String {
let text = format!("{:?}", os_str.as_ref());
text.trim_matches('"').to_string()
}
/// Treats weird paths for better user messages.
/// Display the directory name, but change to "current directory" when necessary.
pub fn nice_directory_display(os_str: impl AsRef<OsStr>) -> String {
let text = to_utf(os_str);
if text == "." {
@ -81,11 +82,6 @@ pub fn nice_directory_display(os_str: impl AsRef<OsStr>) -> String {
}
}
/// Struct used to overload functionality onto Byte presentation.
pub struct Bytes {
bytes: f64,
}
/// Module with a list of bright colors.
#[allow(dead_code)]
pub mod colors {
@ -116,10 +112,15 @@ pub mod colors {
color!(YELLOW = "\u{1b}[38;5;11m");
}
/// Struct useful to printing bytes as kB, MB, GB, etc.
pub struct Bytes {
bytes: f64,
}
impl Bytes {
const UNIT_PREFIXES: [&'static str; 6] = ["", "k", "M", "G", "T", "P"];
/// New Byte structure
/// Create a new Bytes.
pub fn new(bytes: u64) -> Self {
Self { bytes: bytes as f64 }
}
@ -141,13 +142,13 @@ impl std::fmt::Display for Bytes {
}
#[derive(Debug, PartialEq, Clone, Copy)]
/// How overwrite questions should be handled
/// Determines if overwrite questions should be skipped or asked to the user
pub enum QuestionPolicy {
/// Ask everytime
/// Ask the user every time
Ask,
/// Skip overwrite questions positively
/// Set by `--yes`, will say 'Y' to all overwrite questions
AlwaysYes,
/// Skip overwrite questions negatively
/// Set by `--no`, will say 'N' to all overwrite questions
AlwaysNo,
}