Skip to content

Commit

Permalink
feat: allow ignoring hidden files and files matched by .gitignore files
Browse files Browse the repository at this point in the history
  • Loading branch information
vrmiguel committed Jan 17, 2022
1 parent 7a7c6b6 commit d6ff90a
Show file tree
Hide file tree
Showing 11 changed files with 252 additions and 81 deletions.
191 changes: 129 additions & 62 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ lzzzz = "0.8.0"
once_cell = "1.8.0"
snap = "1.0.5"
tar = "0.4.37"
walkdir = "2.3.2"
xz2 = "0.1.6"
zip = { version = "0.5.13", default-features = false }
zstd = { version = "0.9.0", default-features = false }
tempfile = "3.2.0"
ignore = "0.4.18"
indicatif = "0.16.2"

[build-dependencies]
Expand Down
12 changes: 8 additions & 4 deletions src/archive/tar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ use std::{

use fs_err as fs;
use tar;
use walkdir::WalkDir;

use crate::{
error::FinalError,
info,
list::FileInArchive,
utils::{self, Bytes},
utils::{self, Bytes, FileVisibilityPolicy},
};

/// Unpacks the archive given by `archive` into the folder given by `into`.
Expand Down Expand Up @@ -79,7 +78,12 @@ pub fn list_archive(
}

/// Compresses the archives given by `input_filenames` into the file given previously to `writer`.
pub fn build_archive_from_paths<W, D>(input_filenames: &[PathBuf], writer: W, mut display_handle: D) -> crate::Result<W>
pub fn build_archive_from_paths<W, D>(
input_filenames: &[PathBuf],
writer: W,
file_visibility_policy: FileVisibilityPolicy,
mut display_handle: D,
) -> crate::Result<W>
where
W: Write,
D: Write,
Expand All @@ -92,7 +96,7 @@ where
// Safe unwrap, input shall be treated before
let filename = filename.file_name().unwrap();

for entry in WalkDir::new(&filename) {
for entry in file_visibility_policy.build_walker(filename) {
let entry = entry?;
let path = entry.path();

Expand Down
15 changes: 11 additions & 4 deletions src/archive/zip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ use std::{
};

use fs_err as fs;
use walkdir::WalkDir;
use zip::{self, read::ZipFile, ZipArchive};

use crate::{
error::FinalError,
info,
list::FileInArchive,
utils::{self, cd_into_same_dir_as, concatenate_os_str_list, get_invalid_utf8_paths, strip_cur_dir, to_utf, Bytes},
utils::{
self, cd_into_same_dir_as, concatenate_os_str_list, get_invalid_utf8_paths, strip_cur_dir, to_utf, Bytes,
FileVisibilityPolicy,
},
};

/// Unpacks the archive given by `archive` into the folder given by `output_folder`.
Expand Down Expand Up @@ -119,7 +121,12 @@ where
}

/// Compresses the archives given by `input_filenames` into the file given previously to `writer`.
pub fn build_archive_from_paths<W, D>(input_filenames: &[PathBuf], writer: W, mut display_handle: D) -> crate::Result<W>
pub fn build_archive_from_paths<W, D>(
input_filenames: &[PathBuf],
writer: W,
file_visibility_policy: FileVisibilityPolicy,
mut display_handle: D,
) -> crate::Result<W>
where
W: Write + Seek,
D: Write,
Expand All @@ -144,7 +151,7 @@ where
// Safe unwrap, input shall be treated before
let filename = filename.file_name().unwrap();

for entry in WalkDir::new(filename) {
for entry in file_visibility_policy.build_walker(filename) {
let entry = entry?;
let path = entry.path();

Expand Down
13 changes: 10 additions & 3 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use clap::Parser;
use fs_err as fs;
use once_cell::sync::OnceCell;

use crate::{Opts, QuestionPolicy, Subcommand};
use crate::{utils::FileVisibilityPolicy, Opts, QuestionPolicy, Subcommand};

/// Whether to enable accessible output (removes info output and reduces other
/// output, removes visual markers like '[' and ']').
Expand All @@ -23,7 +23,7 @@ impl Opts {
/// And:
/// 1. Make paths absolute.
/// 2. Checks the QuestionPolicy.
pub fn parse_args() -> crate::Result<(Self, QuestionPolicy)> {
pub fn parse_args() -> crate::Result<(Self, QuestionPolicy, FileVisibilityPolicy)> {
let mut opts = Self::parse();

ACCESSIBLE.set(opts.accessible).unwrap();
Expand All @@ -40,7 +40,14 @@ impl Opts {
(true, true) => unreachable!(),
};

Ok((opts, skip_questions_positively))
// TODO: change this to be just a single function call?
let file_visibility_policy = FileVisibilityPolicy::new()
.read_git_exclude(opts.gitignore)
.read_ignore(opts.gitignore)
.read_git_ignore(opts.gitignore)
.read_hidden(opts.hidden);

Ok((opts, skip_questions_positively, file_visibility_policy))
}
}

Expand Down
14 changes: 11 additions & 3 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
progress::Progress,
utils::{
self, concatenate_os_str_list, dir_is_empty, nice_directory_display, to_utf, try_infer_extension,
user_wants_to_continue,
user_wants_to_continue, FileVisibilityPolicy,
},
warning, Opts, QuestionAction, QuestionPolicy, Subcommand,
};
Expand All @@ -43,7 +43,11 @@ fn represents_several_files(files: &[PathBuf]) -> bool {
}

/// Entrypoint of ouch, receives cli options and matches Subcommand to decide what to do
pub fn run(args: Opts, question_policy: QuestionPolicy) -> crate::Result<()> {
pub fn run(
args: Opts,
question_policy: QuestionPolicy,
file_visibility_policy: FileVisibilityPolicy,
) -> crate::Result<()> {
match args.cmd {
Subcommand::Compress { mut files, output: output_path } => {
// If the output_path file exists and is the same as some of the input files, warn the user and skip those inputs (in order to avoid compression recursion)
Expand Down Expand Up @@ -156,7 +160,8 @@ pub fn run(args: Opts, question_policy: QuestionPolicy) -> crate::Result<()> {
formats = new_formats;
}
}
let compress_result = compress_files(files, formats, output_file, &output_path, question_policy);
let compress_result =
compress_files(files, formats, output_file, &output_path, question_policy, file_visibility_policy);

// If any error occurred, delete incomplete file
if compress_result.is_err() {
Expand Down Expand Up @@ -285,6 +290,7 @@ fn compress_files(
output_file: fs::File,
output_dir: &Path,
question_policy: QuestionPolicy,
file_visibility_policy: FileVisibilityPolicy,
) -> crate::Result<()> {
// The next lines are for displaying the progress bar
// If the input files contain a directory, then the total size will be underestimated
Expand Down Expand Up @@ -348,6 +354,7 @@ fn compress_files(
archive::tar::build_archive_from_paths(
&files,
&mut writer,
file_visibility_policy,
progress.as_mut().map(Progress::display_handle).unwrap_or(&mut io::stdout()),
)?;
writer.flush()?;
Expand Down Expand Up @@ -385,6 +392,7 @@ fn compress_files(
archive::zip::build_archive_from_paths(
&files,
&mut vec_buffer,
file_visibility_policy,
progress.as_mut().map(Progress::display_handle).unwrap_or(&mut io::stdout()),
)?;
let vec_buffer = vec_buffer.into_inner();
Expand Down
4 changes: 2 additions & 2 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,8 +172,8 @@ impl From<zip::result::ZipError> for Error {
}
}

impl From<walkdir::Error> for Error {
fn from(err: walkdir::Error) -> Self {
impl From<ignore::Error> for Error {
fn from(err: ignore::Error) -> Self {
Self::WalkdirError { reason: err.to_string() }
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ fn main() {
}

fn run() -> Result<()> {
let (args, skip_questions_positively) = Opts::parse_args()?;
commands::run(args, skip_questions_positively)
let (args, skip_questions_positively, file_visibility_policy) = Opts::parse_args()?;
commands::run(args, skip_questions_positively, file_visibility_policy)
}
8 changes: 8 additions & 0 deletions src/opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ pub struct Opts {
#[clap(short = 'A', long, env = "ACCESSIBLE", global = true)]
pub accessible: bool,

/// Ignores hidden files
#[clap(short = 'H', long)]
pub hidden: bool,

/// Ignores files matched by git's ignore files
#[clap(short = 'g', long)]
pub gitignore: bool,

/// Ouch and claps subcommands
#[clap(subcommand)]
pub cmd: Subcommand,
Expand Down
68 changes: 68 additions & 0 deletions src/utils/file_visibility.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use std::path::Path;

/// Determines which files should be read or ignored during directory walking
pub struct FileVisibilityPolicy {
/// Enables reading .ignore files.
///
/// Disabled by default.
pub read_ignore: bool,

/// If enabled, ignores hidden files.
///
/// Disabled by default
pub read_hidden: bool,

/// Enables reading .gitignore files.
///
/// This is enabled by default.
pub read_git_ignore: bool,

/// Enables reading `.git/info/exclude` files.
pub read_git_exclude: bool,
}

impl Default for FileVisibilityPolicy {
fn default() -> Self {
Self { read_ignore: false, read_hidden: true, read_git_ignore: false, read_git_exclude: false }
}
}

impl FileVisibilityPolicy {
pub fn new() -> Self {
Self::default()
}

#[must_use]
/// Enables reading .ignore files.
pub fn read_ignore(self, read_ignore: bool) -> Self {
Self { read_ignore, ..self }
}

#[must_use]
/// Enables reading .gitignore files.
pub fn read_git_ignore(self, read_git_ignore: bool) -> Self {
Self { read_git_ignore, ..self }
}

#[must_use]
/// Enables reading `.git/info/exclude` files.
pub fn read_git_exclude(self, read_git_exclude: bool) -> Self {
Self { read_git_exclude, ..self }
}

#[must_use]
/// Enables reading `.git/info/exclude` files.
pub fn read_hidden(self, read_hidden: bool) -> Self {
Self { read_hidden, ..self }
}

/// Walks through a directory using [`ignore::Walk`]
pub fn build_walker(&self, path: impl AsRef<Path>) -> ignore::Walk {
ignore::WalkBuilder::new(path)
.git_exclude(self.read_git_exclude)
.git_ignore(self.read_git_ignore)
.ignore(self.read_ignore)
.hidden(self.read_hidden)
.build()
}
}
2 changes: 2 additions & 0 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
//! stdin interaction helpers.

pub mod colors;
mod file_visibility;
mod formatting;
mod fs;
mod question;

pub use file_visibility::FileVisibilityPolicy;
pub use formatting::{concatenate_os_str_list, nice_directory_display, strip_cur_dir, to_utf, Bytes};
pub use fs::{
cd_into_same_dir_as, clear_path, create_dir_if_non_existent, dir_is_empty, is_symlink, try_infer_extension,
Expand Down

0 comments on commit d6ff90a

Please sign in to comment.