Skip to content

Commit

Permalink
Merge branch 'master' into command_list
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonHermann committed Nov 1, 2021
2 parents cabb4f0 + 272b306 commit 9919c72
Show file tree
Hide file tree
Showing 13 changed files with 89 additions and 15 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.2.0"
authors = ["Vinícius Rodrigues Miguel <vrmiguel99@gmail.com>", "João M. Bezerra <marcospb19@hotmail.com>"]
edition = "2018"
readme = "README.md"
repository = "https://github.com/vrmiguel/ouch"
repository = "https://github.com/ouch-org/ouch"
license = "MIT"
keywords = ["decompression", "compression", "zip", "tar", "gzip"]
categories = ["command-line-utilities", "compression", "encoding"]
Expand Down
2 changes: 2 additions & 0 deletions src/archive/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
//! Archive compression algorithms

pub mod tar;
pub mod zip;
2 changes: 2 additions & 0 deletions src/archive/tar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::{
QuestionPolicy,
};

/// Unpacks the archive given by `archive` into the folder given by `into`.
pub fn unpack_archive(
reader: Box<dyn Read>,
output_folder: &Path,
Expand Down Expand Up @@ -59,6 +60,7 @@ pub fn list_archive(reader: Box<dyn Read>) -> crate::Result<Vec<FileInArchive>>
Ok(files)
}

/// Compresses the archives given by `input_filenames` into the file given previously to `writer`.
pub fn build_archive_from_paths<W>(input_filenames: &[PathBuf], writer: W) -> crate::Result<W>
where
W: Write,
Expand Down
2 changes: 2 additions & 0 deletions src/archive/zip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ where
Ok(unpacked_files)
}

/// List contents of `archive`, returning a vector of archive entries
pub fn list_archive<R>(mut archive: ZipArchive<R>) -> crate::Result<Vec<FileInArchive>>
where
R: Read + Seek,
Expand All @@ -93,6 +94,7 @@ where
Ok(files)
}

/// Compresses the archives given by `input_filenames` into the file given previously to `writer`.
pub fn build_archive_from_paths<W>(input_filenames: &[PathBuf], writer: W) -> crate::Result<W>
where
W: Write + Seek,
Expand Down
4 changes: 3 additions & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
//! CLI arg parser configuration, command detection and input treatment.
//! CLI configuration step, uses definitions from `opts.rs`.
//!
//! Also used to treat some inputs.

use std::{
path::{Path, PathBuf},
Expand Down
9 changes: 9 additions & 0 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ fn represents_several_files(files: &[PathBuf]) -> bool {
files.iter().any(is_non_empty_dir) || files.len() > 1
}

/// Entrypoint of ouch, receives cli options and matches Subcommand
/// to decide current operation
pub fn run(args: Opts, question_policy: QuestionPolicy) -> crate::Result<()> {
match args.cmd {
Subcommand::Compress { files, output: output_path } => {
Expand Down Expand Up @@ -220,6 +222,11 @@ pub fn run(args: Opts, question_policy: QuestionPolicy) -> crate::Result<()> {
Ok(())
}

// Compress files into an `output_file`
//
// files are the list of paths to be compressed: ["dir/file1.txt", "dir/file2.txt"]
// formats contains each format necessary for compression, example: [Tar, Gz] (in compression order)
// output_file is the resulting compressed file name, example: "compressed.tar.gz"
fn compress_files(files: Vec<PathBuf>, formats: Vec<CompressionFormat>, output_file: fs::File) -> crate::Result<()> {
let file_writer = BufWriter::with_capacity(BUFFER_CAPACITY, output_file);

Expand Down Expand Up @@ -297,6 +304,8 @@ fn compress_files(files: Vec<PathBuf>, formats: Vec<CompressionFormat>, output_f
Ok(())
}

// Decompress a file
//
// File at input_file_path is opened for reading, example: "archive.tar.gz"
// formats contains each format necessary for decompression, example: [Gz, Tar] (in decompression order)
// output_dir it's where the file will be decompressed to
Expand Down
7 changes: 7 additions & 0 deletions src/dialogs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,22 @@ use crate::utils::colors;

/// Represents a confirmation dialog
pub struct Confirmation<'a> {
/// Represents the message to the displayed
/// e.g.: "Do you want to overwrite 'FILE'?"
pub prompt: &'a str,

/// Represents a placeholder to be changed at runtime
/// e.g.: Some("FILE")
pub placeholder: Option<&'a str>,
}

impl<'a> Confirmation<'a> {
/// New Confirmation
pub const fn new(prompt: &'a str, pattern: Option<&'a str>) -> Self {
Self { prompt, placeholder: pattern }
}

/// Creates user message and receives a boolean input to be used on the program
pub fn ask(&self, substitute: Option<&'a str>) -> crate::Result<bool> {
let message = match (self.placeholder, substitute) {
(None, _) => Cow::Borrowed(self.prompt),
Expand Down
7 changes: 5 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
//! TODO: wrap `FinalError` in a variant to keep all `FinalError::display_and_crash()` function
//! calls inside of this module.

#![allow(missing_docs)]

use std::{
fmt::{self, Display},
path::{Path, PathBuf},
};

use crate::utils::colors::*;

/// Custom Ouch Errors
#[derive(Debug, PartialEq)]
pub enum Error {
UnknownExtensionError(String),
Expand Down Expand Up @@ -91,7 +94,7 @@ impl fmt::Display for Error {
FinalError::with_title(format!("Cannot compress to {:?}", filename))
.detail("Ouch could not detect the compression format")
.hint("Use a supported format extension, like '.zip' or '.tar.gz'")
.hint("Check https://github.com/vrmiguel/ouch for a full list of supported formats")
.hint("Check https://github.com/ouch-org/ouch for a full list of supported formats")
}
Error::WalkdirError { reason } => FinalError::with_title(reason),
Error::FileNotFound(file) => {
Expand Down Expand Up @@ -128,7 +131,7 @@ impl fmt::Display for Error {
.detail("This should not have happened")
.detail("It's probably our fault")
.detail("Please help us improve by reporting the issue at:")
.detail(format!(" {}https://github.com/vrmiguel/ouch/issues ", *CYAN))
.detail(format!(" {}https://github.com/ouch-org/ouch/issues ", *CYAN))
}
Error::IoError { reason } => FinalError::with_title(reason),
Error::CompressionTypo => {
Expand Down
24 changes: 24 additions & 0 deletions src/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::{ffi::OsStr, fmt, path::Path};

use self::CompressionFormat::*;

#[allow(missing_docs)]
#[derive(Clone, PartialEq, Eq, Debug)]
/// Accepted extensions for input and output
pub enum CompressionFormat {
Expand All @@ -20,6 +21,7 @@ pub enum CompressionFormat {
}

impl CompressionFormat {
/// Currently supported archive formats are .tar (and aliases to it) and .zip
pub fn is_archive_format(&self) -> bool {
matches!(self, Tar | Tgz | Tbz | Tlzma | Tzst | Zip)
}
Expand Down Expand Up @@ -51,6 +53,19 @@ impl CompressionFormat {
}
}

// use crate::extension::CompressionFormat::*;
//

/// Extracts extensions from a path,
/// return both the remaining path and the list of extension objects
///
/// ```rust
/// use ouch::extension::{separate_known_extensions_from_name, CompressionFormat};
/// use std::path::Path;
///
/// let mut path = Path::new("bolovo.tar.gz");
/// assert_eq!(separate_known_extensions_from_name(&path), (Path::new("bolovo"), vec![CompressionFormat::Tar, CompressionFormat::Gzip]));
/// ```
pub fn separate_known_extensions_from_name(mut path: &Path) -> (&Path, Vec<CompressionFormat>) {
// // TODO: check for file names with the name of an extension
// // TODO2: warn the user that currently .tar.gz is a .gz file named .tar
Expand Down Expand Up @@ -87,6 +102,15 @@ pub fn separate_known_extensions_from_name(mut path: &Path) -> (&Path, Vec<Compr
(path, extensions)
}

/// Extracts extensions from a path, return only the list of extension objects
///
/// ```rust
/// use ouch::extension::{extensions_from_path, CompressionFormat};
/// use std::path::Path;
///
/// let mut path = Path::new("bolovo.tar.gz");
/// assert_eq!(extensions_from_path(&path), vec![CompressionFormat::Tar, CompressionFormat::Gzip]);
/// ```
pub fn extensions_from_path(path: &Path) -> Vec<CompressionFormat> {
let (_, extensions) = separate_known_extensions_from_name(path);
extensions
Expand Down
23 changes: 13 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@
//! 1. It's required by `main.rs`, or
//! 2. It's required by some integration tests at tests/ folder.

// Public modules
#![warn(missing_docs)]

// Macros should be declared before
pub mod macros;

pub mod archive;
pub mod cli;
pub mod commands;
pub mod dialogs;
pub mod error;
pub mod extension;
pub mod list;
pub mod utils;

// Private modules
mod cli;
mod dialogs;
mod error;
mod extension;
mod list;
mod macros;
mod opts;
mod utils;
/// CLI configuration step, uses definitions from `opts.rs`, also used to treat some inputs.
pub mod opts;

pub use error::{Error, Result};
pub use opts::{Opts, Subcommand};
Expand Down
4 changes: 4 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//! Macros used on ouch.

/// Macro that prints message in INFO mode
#[macro_export]
macro_rules! info {
($($arg:tt)*) => {
Expand All @@ -6,6 +9,7 @@ macro_rules! info {
};
}

/// Prints the `[Info]` tag
pub fn _info_helper() {
use crate::utils::colors::{RESET, YELLOW};

Expand Down
3 changes: 3 additions & 0 deletions src/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use clap::{Parser, ValueHint};

use std::path::PathBuf;

/// Command line options
#[derive(Parser, Debug)]
#[clap(version, about)]
pub struct Opts {
Expand All @@ -13,10 +14,12 @@ pub struct Opts {
#[clap(short, long)]
pub no: bool,

/// Action to take
#[clap(subcommand)]
pub cmd: Subcommand,
}

/// Actions to take
#[derive(Parser, PartialEq, Eq, Debug)]
pub enum Subcommand {
/// Compress files. Alias: c
Expand Down
15 changes: 14 additions & 1 deletion src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Utils used on ouch.

use std::{
cmp, env,
ffi::OsStr,
Expand All @@ -16,6 +18,7 @@ pub fn dir_is_empty(dir_path: &Path) -> bool {
dir_path.read_dir().map(is_empty).unwrap_or_default()
}

/// Creates the dir if non existent.
pub fn create_dir_if_non_existent(path: &Path) -> crate::Result<()> {
if !path.exists() {
fs::create_dir_all(path)?;
Expand All @@ -24,6 +27,9 @@ pub fn create_dir_if_non_existent(path: &Path) -> crate::Result<()> {
Ok(())
}

/// Removes the current dir from the beginning of a path
/// normally used for presentation sake.
/// If this function fails, it will return source path as a PathBuf.
pub fn strip_cur_dir(source_path: &Path) -> PathBuf {
source_path
.strip_prefix(Component::CurDir)
Expand All @@ -44,6 +50,8 @@ pub fn cd_into_same_dir_as(filename: &Path) -> crate::Result<PathBuf> {
Ok(previous_location)
}

/// Centralizes the decision of overwriting a file or not,
/// whether the user has already passed a question_policy or not.
pub fn user_wants_to_overwrite(path: &Path, question_policy: QuestionPolicy) -> crate::Result<bool> {
match question_policy {
QuestionPolicy::AlwaysYes => Ok(true),
Expand All @@ -57,11 +65,13 @@ pub fn user_wants_to_overwrite(path: &Path, question_policy: QuestionPolicy) ->
}
}

/// Converts an OsStr to utf8.
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.
pub fn nice_directory_display(os_str: impl AsRef<OsStr>) -> String {
let text = to_utf(os_str);
if text == "." {
Expand All @@ -71,6 +81,7 @@ pub fn nice_directory_display(os_str: impl AsRef<OsStr>) -> String {
}
}

/// Struct used to overload functionality onto Byte presentation.
pub struct Bytes {
bytes: f64,
}
Expand All @@ -87,6 +98,7 @@ pub mod colors {
macro_rules! color {
($name:ident = $value:literal) => {
#[cfg(target_family = "unix")]
/// Inserts color onto text based on configuration
pub static $name: Lazy<&str> = Lazy::new(|| if *DISABLE_COLORED_TEXT { "" } else { $value });
#[cfg(not(target_family = "unix"))]
pub static $name: &&str = &"";
Expand All @@ -110,6 +122,7 @@ pub mod colors {
impl Bytes {
const UNIT_PREFIXES: [&'static str; 6] = ["", "k", "M", "G", "T", "P"];

/// New Byte structure
pub fn new(bytes: u64) -> Self {
Self { bytes: bytes as f64 }
}
Expand All @@ -133,7 +146,7 @@ impl std::fmt::Display for Bytes {
#[derive(Debug, PartialEq, Clone, Copy)]
/// How overwrite questions should be handled
pub enum QuestionPolicy {
/// Ask ever time
/// Ask everytime
Ask,
/// Skip overwrite questions positively
AlwaysYes,
Expand Down

0 comments on commit 9919c72

Please sign in to comment.