mirror of https://github.com/sharkdp/fd.git
Merge pull request #812 from yyogo/master
Append trailing path separators to directories
This commit is contained in:
commit
de27835264
|
@ -14,6 +14,7 @@
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
- Changed `-u` flag to be equivalent to `-HI`. Multiple `-u` flags still allowed but do nothing, see #840 (@jacksontheel)
|
- Changed `-u` flag to be equivalent to `-HI`. Multiple `-u` flags still allowed but do nothing, see #840 (@jacksontheel)
|
||||||
|
- Directories are now printed with an additional path separator at the end: `foo/bar/`, see #436 and #812 (@yyogo)
|
||||||
|
|
||||||
## Other
|
## Other
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,9 @@ pub struct Config {
|
||||||
/// The separator used to print file paths.
|
/// The separator used to print file paths.
|
||||||
pub path_separator: Option<String>,
|
pub path_separator: Option<String>,
|
||||||
|
|
||||||
|
/// The actual separator, either the system default separator or `path_separator`
|
||||||
|
pub actual_path_separator: String,
|
||||||
|
|
||||||
/// The maximum number of search results
|
/// The maximum number of search results
|
||||||
pub max_results: Option<usize>,
|
pub max_results: Option<usize>,
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
use std::{
|
||||||
|
fs::{FileType, Metadata},
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
|
use once_cell::unsync::OnceCell;
|
||||||
|
|
||||||
|
enum DirEntryInner {
|
||||||
|
Normal(ignore::DirEntry),
|
||||||
|
BrokenSymlink(PathBuf),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DirEntry {
|
||||||
|
inner: DirEntryInner,
|
||||||
|
metadata: OnceCell<Option<Metadata>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirEntry {
|
||||||
|
#[inline]
|
||||||
|
pub fn normal(e: ignore::DirEntry) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: DirEntryInner::Normal(e),
|
||||||
|
metadata: OnceCell::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn broken_symlink(path: PathBuf) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: DirEntryInner::BrokenSymlink(path),
|
||||||
|
metadata: OnceCell::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path(&self) -> &Path {
|
||||||
|
match &self.inner {
|
||||||
|
DirEntryInner::Normal(e) => e.path(),
|
||||||
|
DirEntryInner::BrokenSymlink(pathbuf) => pathbuf.as_path(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_path(self) -> PathBuf {
|
||||||
|
match self.inner {
|
||||||
|
DirEntryInner::Normal(e) => e.into_path(),
|
||||||
|
DirEntryInner::BrokenSymlink(p) => p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file_type(&self) -> Option<FileType> {
|
||||||
|
match &self.inner {
|
||||||
|
DirEntryInner::Normal(e) => e.file_type(),
|
||||||
|
DirEntryInner::BrokenSymlink(_) => self.metadata().map(|m| m.file_type()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn metadata(&self) -> Option<&Metadata> {
|
||||||
|
self.metadata
|
||||||
|
.get_or_init(|| match &self.inner {
|
||||||
|
DirEntryInner::Normal(e) => e.metadata().ok(),
|
||||||
|
DirEntryInner::BrokenSymlink(path) => path.symlink_metadata().ok(),
|
||||||
|
})
|
||||||
|
.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn depth(&self) -> Option<usize> {
|
||||||
|
match &self.inner {
|
||||||
|
DirEntryInner::Normal(e) => Some(e.depth()),
|
||||||
|
DirEntryInner::BrokenSymlink(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for DirEntry {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.path() == other.path()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Eq for DirEntry {}
|
||||||
|
|
||||||
|
impl PartialOrd for DirEntry {
|
||||||
|
#[inline]
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
self.path().partial_cmp(other.path())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for DirEntry {
|
||||||
|
#[inline]
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
self.path().cmp(other.path())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::sync::mpsc::Receiver;
|
use std::sync::mpsc::Receiver;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use crate::dir_entry::DirEntry;
|
||||||
use crate::error::print_error;
|
use crate::error::print_error;
|
||||||
use crate::exit_codes::{merge_exitcodes, ExitCode};
|
use crate::exit_codes::{merge_exitcodes, ExitCode};
|
||||||
use crate::walk::WorkerResult;
|
use crate::walk::WorkerResult;
|
||||||
|
@ -25,8 +25,8 @@ pub fn job(
|
||||||
|
|
||||||
// Obtain the next result from the receiver, else if the channel
|
// Obtain the next result from the receiver, else if the channel
|
||||||
// has closed, exit from the loop
|
// has closed, exit from the loop
|
||||||
let value: PathBuf = match lock.recv() {
|
let dir_entry: DirEntry = match lock.recv() {
|
||||||
Ok(WorkerResult::Entry(path)) => path,
|
Ok(WorkerResult::Entry(dir_entry)) => dir_entry,
|
||||||
Ok(WorkerResult::Error(err)) => {
|
Ok(WorkerResult::Error(err)) => {
|
||||||
if show_filesystem_errors {
|
if show_filesystem_errors {
|
||||||
print_error(err.to_string());
|
print_error(err.to_string());
|
||||||
|
@ -39,7 +39,7 @@ pub fn job(
|
||||||
// Drop the lock so that other threads can read from the receiver.
|
// Drop the lock so that other threads can read from the receiver.
|
||||||
drop(lock);
|
drop(lock);
|
||||||
// Generate a command, execute it and store its exit code.
|
// Generate a command, execute it and store its exit code.
|
||||||
results.push(cmd.execute(&value, Arc::clone(&out_perm), buffer_output))
|
results.push(cmd.execute(dir_entry.path(), Arc::clone(&out_perm), buffer_output))
|
||||||
}
|
}
|
||||||
// Returns error in case of any error.
|
// Returns error in case of any error.
|
||||||
merge_exitcodes(results)
|
merge_exitcodes(results)
|
||||||
|
@ -51,8 +51,10 @@ pub fn batch(
|
||||||
show_filesystem_errors: bool,
|
show_filesystem_errors: bool,
|
||||||
limit: usize,
|
limit: usize,
|
||||||
) -> ExitCode {
|
) -> ExitCode {
|
||||||
let paths = rx.iter().filter_map(|value| match value {
|
let paths = rx
|
||||||
WorkerResult::Entry(path) => Some(path),
|
.into_iter()
|
||||||
|
.filter_map(|worker_result| match worker_result {
|
||||||
|
WorkerResult::Entry(dir_entry) => Some(dir_entry.into_path()),
|
||||||
WorkerResult::Error(err) => {
|
WorkerResult::Error(err) => {
|
||||||
if show_filesystem_errors {
|
if show_filesystem_errors {
|
||||||
print_error(err.to_string());
|
print_error(err.to_string());
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use normpath::PathExt;
|
use normpath::PathExt;
|
||||||
|
|
||||||
use crate::walk;
|
use crate::dir_entry;
|
||||||
|
|
||||||
pub fn path_absolute_form(path: &Path) -> io::Result<PathBuf> {
|
pub fn path_absolute_form(path: &Path) -> io::Result<PathBuf> {
|
||||||
if path.is_absolute() {
|
if path.is_absolute() {
|
||||||
|
@ -51,7 +51,7 @@ pub fn is_executable(_: &fs::Metadata) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(entry: &walk::DirEntry) -> bool {
|
pub fn is_empty(entry: &dir_entry::DirEntry) -> bool {
|
||||||
if let Some(file_type) = entry.file_type() {
|
if let Some(file_type) = entry.file_type() {
|
||||||
if file_type.is_dir() {
|
if file_type.is_dir() {
|
||||||
if let Ok(mut entries) = fs::read_dir(entry.path()) {
|
if let Ok(mut entries) = fs::read_dir(entry.path()) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
use crate::dir_entry;
|
||||||
use crate::filesystem;
|
use crate::filesystem;
|
||||||
use crate::walk;
|
|
||||||
|
|
||||||
/// Whether or not to show
|
/// Whether or not to show
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -14,7 +14,7 @@ pub struct FileTypes {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileTypes {
|
impl FileTypes {
|
||||||
pub fn should_ignore(&self, entry: &walk::DirEntry) -> bool {
|
pub fn should_ignore(&self, entry: &dir_entry::DirEntry) -> bool {
|
||||||
if let Some(ref entry_type) = entry.file_type() {
|
if let Some(ref entry_type) = entry.file_type() {
|
||||||
(!self.files && entry_type.is_file())
|
(!self.files && entry_type.is_file())
|
||||||
|| (!self.directories && entry_type.is_dir())
|
|| (!self.directories && entry_type.is_dir())
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
mod app;
|
mod app;
|
||||||
mod config;
|
mod config;
|
||||||
|
mod dir_entry;
|
||||||
mod error;
|
mod error;
|
||||||
mod exec;
|
mod exec;
|
||||||
mod exit_codes;
|
mod exit_codes;
|
||||||
|
@ -221,6 +222,9 @@ fn construct_config(matches: clap::ArgMatches, pattern_regex: &str) -> Result<Co
|
||||||
let path_separator = matches
|
let path_separator = matches
|
||||||
.value_of("path-separator")
|
.value_of("path-separator")
|
||||||
.map_or_else(filesystem::default_path_separator, |s| Some(s.to_owned()));
|
.map_or_else(filesystem::default_path_separator, |s| Some(s.to_owned()));
|
||||||
|
let actual_path_separator = path_separator
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| std::path::MAIN_SEPARATOR.to_string());
|
||||||
check_path_separator_length(path_separator.as_deref())?;
|
check_path_separator_length(path_separator.as_deref())?;
|
||||||
|
|
||||||
let size_limits = extract_size_limits(&matches)?;
|
let size_limits = extract_size_limits(&matches)?;
|
||||||
|
@ -367,6 +371,7 @@ fn construct_config(matches: clap::ArgMatches, pattern_regex: &str) -> Result<Co
|
||||||
owner_constraint,
|
owner_constraint,
|
||||||
show_filesystem_errors: matches.is_present("show-errors"),
|
show_filesystem_errors: matches.is_present("show-errors"),
|
||||||
path_separator,
|
path_separator,
|
||||||
|
actual_path_separator,
|
||||||
max_results: matches
|
max_results: matches
|
||||||
.value_of("max-results")
|
.value_of("max-results")
|
||||||
.map(|n| n.parse::<usize>())
|
.map(|n| n.parse::<usize>())
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::path::Path;
|
||||||
use lscolors::{Indicator, LsColors, Style};
|
use lscolors::{Indicator, LsColors, Style};
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
use crate::dir_entry::DirEntry;
|
||||||
use crate::error::print_error;
|
use crate::error::print_error;
|
||||||
use crate::exit_codes::ExitCode;
|
use crate::exit_codes::ExitCode;
|
||||||
use crate::filesystem::strip_current_dir;
|
use crate::filesystem::strip_current_dir;
|
||||||
|
@ -13,18 +14,21 @@ fn replace_path_separator(path: &str, new_path_separator: &str) -> String {
|
||||||
path.replace(std::path::MAIN_SEPARATOR, new_path_separator)
|
path.replace(std::path::MAIN_SEPARATOR, new_path_separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this function is performance critical and can probably be optimized
|
fn stripped_path<'a>(entry: &'a DirEntry, config: &Config) -> &'a Path {
|
||||||
pub fn print_entry<W: Write>(stdout: &mut W, entry: &Path, config: &Config) {
|
let path = entry.path();
|
||||||
let path = if config.strip_cwd_prefix {
|
if config.strip_cwd_prefix {
|
||||||
strip_current_dir(entry)
|
strip_current_dir(path)
|
||||||
} else {
|
} else {
|
||||||
entry
|
path
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: this function is performance critical and can probably be optimized
|
||||||
|
pub fn print_entry<W: Write>(stdout: &mut W, entry: &DirEntry, config: &Config) {
|
||||||
let r = if let Some(ref ls_colors) = config.ls_colors {
|
let r = if let Some(ref ls_colors) = config.ls_colors {
|
||||||
print_entry_colorized(stdout, path, config, ls_colors)
|
print_entry_colorized(stdout, entry, config, ls_colors)
|
||||||
} else {
|
} else {
|
||||||
print_entry_uncolorized(stdout, path, config)
|
print_entry_uncolorized(stdout, entry, config)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = r {
|
if let Err(e) = r {
|
||||||
|
@ -38,15 +42,39 @@ pub fn print_entry<W: Write>(stdout: &mut W, entry: &Path, config: &Config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Display a trailing slash if the path is a directory and the config option is enabled.
|
||||||
|
// If the path_separator option is set, display that instead.
|
||||||
|
// The trailing slash will not be colored.
|
||||||
|
#[inline]
|
||||||
|
fn print_trailing_slash<W: Write>(
|
||||||
|
stdout: &mut W,
|
||||||
|
entry: &DirEntry,
|
||||||
|
config: &Config,
|
||||||
|
style: Option<&Style>,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
if entry.file_type().map_or(false, |ft| ft.is_dir()) {
|
||||||
|
write!(
|
||||||
|
stdout,
|
||||||
|
"{}",
|
||||||
|
style
|
||||||
|
.map(Style::to_ansi_term_style)
|
||||||
|
.unwrap_or_default()
|
||||||
|
.paint(&config.actual_path_separator)
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: this function is performance critical and can probably be optimized
|
// TODO: this function is performance critical and can probably be optimized
|
||||||
fn print_entry_colorized<W: Write>(
|
fn print_entry_colorized<W: Write>(
|
||||||
stdout: &mut W,
|
stdout: &mut W,
|
||||||
path: &Path,
|
entry: &DirEntry,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
ls_colors: &LsColors,
|
ls_colors: &LsColors,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
// Split the path between the parent and the last component
|
// Split the path between the parent and the last component
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
|
let path = stripped_path(entry, config);
|
||||||
let path_str = path.to_string_lossy();
|
let path_str = path.to_string_lossy();
|
||||||
|
|
||||||
if let Some(parent) = path.parent() {
|
if let Some(parent) = path.parent() {
|
||||||
|
@ -74,11 +102,18 @@ fn print_entry_colorized<W: Write>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let style = ls_colors
|
let style = ls_colors
|
||||||
.style_for_path(path)
|
.style_for_path_with_metadata(path, entry.metadata())
|
||||||
.map(Style::to_ansi_term_style)
|
.map(Style::to_ansi_term_style)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
write!(stdout, "{}", style.paint(&path_str[offset..]))?;
|
write!(stdout, "{}", style.paint(&path_str[offset..]))?;
|
||||||
|
|
||||||
|
print_trailing_slash(
|
||||||
|
stdout,
|
||||||
|
entry,
|
||||||
|
config,
|
||||||
|
ls_colors.style_for_indicator(Indicator::Directory),
|
||||||
|
)?;
|
||||||
|
|
||||||
if config.null_separator {
|
if config.null_separator {
|
||||||
write!(stdout, "\0")?;
|
write!(stdout, "\0")?;
|
||||||
} else {
|
} else {
|
||||||
|
@ -91,42 +126,46 @@ fn print_entry_colorized<W: Write>(
|
||||||
// TODO: this function is performance critical and can probably be optimized
|
// TODO: this function is performance critical and can probably be optimized
|
||||||
fn print_entry_uncolorized_base<W: Write>(
|
fn print_entry_uncolorized_base<W: Write>(
|
||||||
stdout: &mut W,
|
stdout: &mut W,
|
||||||
path: &Path,
|
entry: &DirEntry,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let separator = if config.null_separator { "\0" } else { "\n" };
|
let separator = if config.null_separator { "\0" } else { "\n" };
|
||||||
|
let path = stripped_path(entry, config);
|
||||||
|
|
||||||
let mut path_string = path.to_string_lossy();
|
let mut path_string = path.to_string_lossy();
|
||||||
if let Some(ref separator) = config.path_separator {
|
if let Some(ref separator) = config.path_separator {
|
||||||
*path_string.to_mut() = replace_path_separator(&path_string, separator);
|
*path_string.to_mut() = replace_path_separator(&path_string, separator);
|
||||||
}
|
}
|
||||||
write!(stdout, "{}{}", path_string, separator)
|
write!(stdout, "{}", path_string)?;
|
||||||
|
print_trailing_slash(stdout, entry, config, None)?;
|
||||||
|
write!(stdout, "{}", separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
fn print_entry_uncolorized<W: Write>(
|
fn print_entry_uncolorized<W: Write>(
|
||||||
stdout: &mut W,
|
stdout: &mut W,
|
||||||
path: &Path,
|
entry: &DirEntry,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
print_entry_uncolorized_base(stdout, path, config)
|
print_entry_uncolorized_base(stdout, entry, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn print_entry_uncolorized<W: Write>(
|
fn print_entry_uncolorized<W: Write>(
|
||||||
stdout: &mut W,
|
stdout: &mut W,
|
||||||
path: &Path,
|
entry: &DirEntry,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
|
||||||
if config.interactive_terminal || config.path_separator.is_some() {
|
if config.interactive_terminal || config.path_separator.is_some() {
|
||||||
// Fall back to the base implementation
|
// Fall back to the base implementation
|
||||||
print_entry_uncolorized_base(stdout, path, config)
|
print_entry_uncolorized_base(stdout, entry, config)
|
||||||
} else {
|
} else {
|
||||||
// Print path as raw bytes, allowing invalid UTF-8 filenames to be passed to other processes
|
// Print path as raw bytes, allowing invalid UTF-8 filenames to be passed to other processes
|
||||||
let separator = if config.null_separator { b"\0" } else { b"\n" };
|
let separator = if config.null_separator { b"\0" } else { b"\n" };
|
||||||
stdout.write_all(path.as_os_str().as_bytes())?;
|
stdout.write_all(stripped_path(entry, config).as_os_str().as_bytes())?;
|
||||||
|
print_trailing_slash(stdout, entry, config, None)?;
|
||||||
stdout.write_all(separator)
|
stdout.write_all(separator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
77
src/walk.rs
77
src/walk.rs
|
@ -1,8 +1,7 @@
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fs::{FileType, Metadata};
|
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::mpsc::{channel, Receiver, RecvTimeoutError, Sender};
|
use std::sync::mpsc::{channel, Receiver, RecvTimeoutError, Sender};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
@ -13,10 +12,10 @@ use std::{borrow::Cow, io::Write};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use ignore::overrides::OverrideBuilder;
|
use ignore::overrides::OverrideBuilder;
|
||||||
use ignore::{self, WalkBuilder};
|
use ignore::{self, WalkBuilder};
|
||||||
use once_cell::unsync::OnceCell;
|
|
||||||
use regex::bytes::Regex;
|
use regex::bytes::Regex;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
use crate::dir_entry::DirEntry;
|
||||||
use crate::error::print_error;
|
use crate::error::print_error;
|
||||||
use crate::exec;
|
use crate::exec;
|
||||||
use crate::exit_codes::{merge_exitcodes, ExitCode};
|
use crate::exit_codes::{merge_exitcodes, ExitCode};
|
||||||
|
@ -36,7 +35,7 @@ enum ReceiverMode {
|
||||||
|
|
||||||
/// The Worker threads can result in a valid entry having PathBuf or an error.
|
/// The Worker threads can result in a valid entry having PathBuf or an error.
|
||||||
pub enum WorkerResult {
|
pub enum WorkerResult {
|
||||||
Entry(PathBuf),
|
Entry(DirEntry),
|
||||||
Error(ignore::Error),
|
Error(ignore::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,7 +180,7 @@ struct ReceiverBuffer<W> {
|
||||||
/// The deadline to switch to streaming mode.
|
/// The deadline to switch to streaming mode.
|
||||||
deadline: Instant,
|
deadline: Instant,
|
||||||
/// The buffer of quickly received paths.
|
/// The buffer of quickly received paths.
|
||||||
buffer: Vec<PathBuf>,
|
buffer: Vec<DirEntry>,
|
||||||
/// Result count.
|
/// Result count.
|
||||||
num_results: usize,
|
num_results: usize,
|
||||||
}
|
}
|
||||||
|
@ -242,20 +241,20 @@ impl<W: Write> ReceiverBuffer<W> {
|
||||||
/// Wait for a result or state change.
|
/// Wait for a result or state change.
|
||||||
fn poll(&mut self) -> Result<(), ExitCode> {
|
fn poll(&mut self) -> Result<(), ExitCode> {
|
||||||
match self.recv() {
|
match self.recv() {
|
||||||
Ok(WorkerResult::Entry(path)) => {
|
Ok(WorkerResult::Entry(dir_entry)) => {
|
||||||
if self.config.quiet {
|
if self.config.quiet {
|
||||||
return Err(ExitCode::HasResults(true));
|
return Err(ExitCode::HasResults(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
match self.mode {
|
match self.mode {
|
||||||
ReceiverMode::Buffering => {
|
ReceiverMode::Buffering => {
|
||||||
self.buffer.push(path);
|
self.buffer.push(dir_entry);
|
||||||
if self.buffer.len() > MAX_BUFFER_LENGTH {
|
if self.buffer.len() > MAX_BUFFER_LENGTH {
|
||||||
self.stream()?;
|
self.stream()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ReceiverMode::Streaming => {
|
ReceiverMode::Streaming => {
|
||||||
self.print(&path)?;
|
self.print(&dir_entry)?;
|
||||||
self.flush()?;
|
self.flush()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,8 +283,8 @@ impl<W: Write> ReceiverBuffer<W> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Output a path.
|
/// Output a path.
|
||||||
fn print(&mut self, path: &Path) -> Result<(), ExitCode> {
|
fn print(&mut self, entry: &DirEntry) -> Result<(), ExitCode> {
|
||||||
output::print_entry(&mut self.stdout, path, &self.config);
|
output::print_entry(&mut self.stdout, entry, &self.config);
|
||||||
|
|
||||||
if self.interrupt_flag.load(Ordering::Relaxed) {
|
if self.interrupt_flag.load(Ordering::Relaxed) {
|
||||||
// Ignore any errors on flush, because we're about to exit anyway
|
// Ignore any errors on flush, because we're about to exit anyway
|
||||||
|
@ -396,62 +395,6 @@ fn spawn_receiver(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
enum DirEntryInner {
|
|
||||||
Normal(ignore::DirEntry),
|
|
||||||
BrokenSymlink(PathBuf),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DirEntry {
|
|
||||||
inner: DirEntryInner,
|
|
||||||
metadata: OnceCell<Option<Metadata>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DirEntry {
|
|
||||||
fn normal(e: ignore::DirEntry) -> Self {
|
|
||||||
Self {
|
|
||||||
inner: DirEntryInner::Normal(e),
|
|
||||||
metadata: OnceCell::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn broken_symlink(path: PathBuf) -> Self {
|
|
||||||
Self {
|
|
||||||
inner: DirEntryInner::BrokenSymlink(path),
|
|
||||||
metadata: OnceCell::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path(&self) -> &Path {
|
|
||||||
match &self.inner {
|
|
||||||
DirEntryInner::Normal(e) => e.path(),
|
|
||||||
DirEntryInner::BrokenSymlink(pathbuf) => pathbuf.as_path(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn file_type(&self) -> Option<FileType> {
|
|
||||||
match &self.inner {
|
|
||||||
DirEntryInner::Normal(e) => e.file_type(),
|
|
||||||
DirEntryInner::BrokenSymlink(_) => self.metadata().map(|m| m.file_type()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn metadata(&self) -> Option<&Metadata> {
|
|
||||||
self.metadata
|
|
||||||
.get_or_init(|| match &self.inner {
|
|
||||||
DirEntryInner::Normal(e) => e.metadata().ok(),
|
|
||||||
DirEntryInner::BrokenSymlink(path) => path.symlink_metadata().ok(),
|
|
||||||
})
|
|
||||||
.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn depth(&self) -> Option<usize> {
|
|
||||||
match &self.inner {
|
|
||||||
DirEntryInner::Normal(e) => Some(e.depth()),
|
|
||||||
DirEntryInner::BrokenSymlink(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn spawn_senders(
|
fn spawn_senders(
|
||||||
config: &Arc<Config>,
|
config: &Arc<Config>,
|
||||||
quit_flag: &Arc<AtomicBool>,
|
quit_flag: &Arc<AtomicBool>,
|
||||||
|
@ -602,7 +545,7 @@ fn spawn_senders(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let send_result = tx_thread.send(WorkerResult::Entry(entry_path.to_owned()));
|
let send_result = tx_thread.send(WorkerResult::Entry(entry));
|
||||||
|
|
||||||
if send_result.is_err() {
|
if send_result.is_err() {
|
||||||
return ignore::WalkState::Quit;
|
return ignore::WalkState::Quit;
|
||||||
|
|
194
tests/tests.rs
194
tests/tests.rs
|
@ -72,7 +72,7 @@ fn test_simple() {
|
||||||
./one/two/c.foo
|
./one/two/c.foo
|
||||||
./one/two/C.Foo2
|
./one/two/C.Foo2
|
||||||
./one/two/three/d.foo
|
./one/two/three/d.foo
|
||||||
./one/two/three/directory_foo",
|
./one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,14 +82,14 @@ fn test_empty_pattern() {
|
||||||
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
|
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
|
||||||
let expected = "./a.foo
|
let expected = "./a.foo
|
||||||
./e1 e2
|
./e1 e2
|
||||||
./one
|
./one/
|
||||||
./one/b.foo
|
./one/b.foo
|
||||||
./one/two
|
./one/two/
|
||||||
./one/two/c.foo
|
./one/two/c.foo
|
||||||
./one/two/C.Foo2
|
./one/two/C.Foo2
|
||||||
./one/two/three
|
./one/two/three/
|
||||||
./one/two/three/d.foo
|
./one/two/three/d.foo
|
||||||
./one/two/three/directory_foo
|
./one/two/three/directory_foo/
|
||||||
./symlink";
|
./symlink";
|
||||||
|
|
||||||
te.assert_output(&["--regex"], expected);
|
te.assert_output(&["--regex"], expected);
|
||||||
|
@ -171,24 +171,24 @@ fn test_explicit_root_path() {
|
||||||
one/two/c.foo
|
one/two/c.foo
|
||||||
one/two/C.Foo2
|
one/two/C.Foo2
|
||||||
one/two/three/d.foo
|
one/two/three/d.foo
|
||||||
one/two/three/directory_foo",
|
one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
|
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["foo", "one/two/three"],
|
&["foo", "one/two/three"],
|
||||||
"one/two/three/d.foo
|
"one/two/three/d.foo
|
||||||
one/two/three/directory_foo",
|
one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
|
|
||||||
te.assert_output_subdirectory(
|
te.assert_output_subdirectory(
|
||||||
"one/two",
|
"one/two/",
|
||||||
&["foo", "../../"],
|
&["foo", "../../"],
|
||||||
"../../a.foo
|
"../../a.foo
|
||||||
../../one/b.foo
|
../../one/b.foo
|
||||||
../../one/two/c.foo
|
../../one/two/c.foo
|
||||||
../../one/two/C.Foo2
|
../../one/two/C.Foo2
|
||||||
../../one/two/three/d.foo
|
../../one/two/three/d.foo
|
||||||
../../one/two/three/directory_foo",
|
../../one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
|
|
||||||
te.assert_output_subdirectory(
|
te.assert_output_subdirectory(
|
||||||
|
@ -196,9 +196,9 @@ fn test_explicit_root_path() {
|
||||||
&["", ".."],
|
&["", ".."],
|
||||||
"../c.foo
|
"../c.foo
|
||||||
../C.Foo2
|
../C.Foo2
|
||||||
../three
|
../three/
|
||||||
../three/d.foo
|
../three/d.foo
|
||||||
../three/directory_foo",
|
../three/directory_foo/",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,7 +387,7 @@ fn test_full_path() {
|
||||||
&format!("^{prefix}.*three.*foo$", prefix = prefix),
|
&format!("^{prefix}.*three.*foo$", prefix = prefix),
|
||||||
],
|
],
|
||||||
"./one/two/three/d.foo
|
"./one/two/three/d.foo
|
||||||
./one/two/three/directory_foo",
|
./one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,7 +404,7 @@ fn test_hidden() {
|
||||||
./one/two/c.foo
|
./one/two/c.foo
|
||||||
./one/two/C.Foo2
|
./one/two/C.Foo2
|
||||||
./one/two/three/d.foo
|
./one/two/three/d.foo
|
||||||
./one/two/three/directory_foo",
|
./one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,7 +444,7 @@ fn test_no_ignore() {
|
||||||
./one/two/c.foo
|
./one/two/c.foo
|
||||||
./one/two/C.Foo2
|
./one/two/C.Foo2
|
||||||
./one/two/three/d.foo
|
./one/two/three/d.foo
|
||||||
./one/two/three/directory_foo",
|
./one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
|
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
|
@ -457,7 +457,7 @@ fn test_no_ignore() {
|
||||||
./one/two/c.foo
|
./one/two/c.foo
|
||||||
./one/two/C.Foo2
|
./one/two/C.Foo2
|
||||||
./one/two/three/d.foo
|
./one/two/three/d.foo
|
||||||
./one/two/three/directory_foo",
|
./one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,7 +610,7 @@ fn test_no_ignore_vcs() {
|
||||||
./one/two/c.foo
|
./one/two/c.foo
|
||||||
./one/two/C.Foo2
|
./one/two/C.Foo2
|
||||||
./one/two/three/d.foo
|
./one/two/three/d.foo
|
||||||
./one/two/three/directory_foo",
|
./one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,7 +664,7 @@ fn test_no_ignore_aliases() {
|
||||||
./one/two/c.foo
|
./one/two/c.foo
|
||||||
./one/two/C.Foo2
|
./one/two/C.Foo2
|
||||||
./one/two/three/d.foo
|
./one/two/three/d.foo
|
||||||
./one/two/three/directory_foo",
|
./one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,7 +763,7 @@ fn test_print0() {
|
||||||
./one/two/C.Foo2NULL
|
./one/two/C.Foo2NULL
|
||||||
./one/two/c.fooNULL
|
./one/two/c.fooNULL
|
||||||
./one/two/three/d.fooNULL
|
./one/two/three/d.fooNULL
|
||||||
./one/two/three/directory_fooNULL",
|
./one/two/three/directory_foo/NULL",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -776,12 +776,12 @@ fn test_max_depth() {
|
||||||
&["--max-depth", "3"],
|
&["--max-depth", "3"],
|
||||||
"./a.foo
|
"./a.foo
|
||||||
./e1 e2
|
./e1 e2
|
||||||
./one
|
./one/
|
||||||
./one/b.foo
|
./one/b.foo
|
||||||
./one/two
|
./one/two/
|
||||||
./one/two/c.foo
|
./one/two/c.foo
|
||||||
./one/two/C.Foo2
|
./one/two/C.Foo2
|
||||||
./one/two/three
|
./one/two/three/
|
||||||
./symlink",
|
./symlink",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -789,9 +789,9 @@ fn test_max_depth() {
|
||||||
&["--max-depth", "2"],
|
&["--max-depth", "2"],
|
||||||
"./a.foo
|
"./a.foo
|
||||||
./e1 e2
|
./e1 e2
|
||||||
./one
|
./one/
|
||||||
./one/b.foo
|
./one/b.foo
|
||||||
./one/two
|
./one/two/
|
||||||
./symlink",
|
./symlink",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -799,7 +799,7 @@ fn test_max_depth() {
|
||||||
&["--max-depth", "1"],
|
&["--max-depth", "1"],
|
||||||
"./a.foo
|
"./a.foo
|
||||||
./e1 e2
|
./e1 e2
|
||||||
./one
|
./one/
|
||||||
./symlink",
|
./symlink",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -813,15 +813,15 @@ fn test_min_depth() {
|
||||||
&["--min-depth", "3"],
|
&["--min-depth", "3"],
|
||||||
"./one/two/c.foo
|
"./one/two/c.foo
|
||||||
./one/two/C.Foo2
|
./one/two/C.Foo2
|
||||||
./one/two/three
|
./one/two/three/
|
||||||
./one/two/three/d.foo
|
./one/two/three/d.foo
|
||||||
./one/two/three/directory_foo",
|
./one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
|
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--min-depth", "4"],
|
&["--min-depth", "4"],
|
||||||
"./one/two/three/d.foo
|
"./one/two/three/d.foo
|
||||||
./one/two/three/directory_foo",
|
./one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,7 +834,7 @@ fn test_exact_depth() {
|
||||||
&["--exact-depth", "3"],
|
&["--exact-depth", "3"],
|
||||||
"./one/two/c.foo
|
"./one/two/c.foo
|
||||||
./one/two/C.Foo2
|
./one/two/C.Foo2
|
||||||
./one/two/three",
|
./one/two/three/",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,19 +854,19 @@ fn test_prune() {
|
||||||
|
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["foo"],
|
&["foo"],
|
||||||
"./foo
|
"./foo/
|
||||||
./foo/foo.file
|
./foo/foo.file
|
||||||
./foo/bar/foo.file
|
./foo/bar/foo.file
|
||||||
./bar/foo.file
|
./bar/foo.file
|
||||||
./bar/foo
|
./bar/foo/
|
||||||
./bar/foo/foo.file
|
./bar/foo/foo.file
|
||||||
./baz/foo.file",
|
./baz/foo.file",
|
||||||
);
|
);
|
||||||
|
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--prune", "foo"],
|
&["--prune", "foo"],
|
||||||
"./foo
|
"./foo/
|
||||||
./bar/foo
|
./bar/foo/
|
||||||
./bar/foo.file
|
./bar/foo.file
|
||||||
./baz/foo.file",
|
./baz/foo.file",
|
||||||
);
|
);
|
||||||
|
@ -882,14 +882,14 @@ fn test_absolute_path() {
|
||||||
&format!(
|
&format!(
|
||||||
"{abs_path}/a.foo
|
"{abs_path}/a.foo
|
||||||
{abs_path}/e1 e2
|
{abs_path}/e1 e2
|
||||||
{abs_path}/one
|
{abs_path}/one/
|
||||||
{abs_path}/one/b.foo
|
{abs_path}/one/b.foo
|
||||||
{abs_path}/one/two
|
{abs_path}/one/two/
|
||||||
{abs_path}/one/two/c.foo
|
{abs_path}/one/two/c.foo
|
||||||
{abs_path}/one/two/C.Foo2
|
{abs_path}/one/two/C.Foo2
|
||||||
{abs_path}/one/two/three
|
{abs_path}/one/two/three/
|
||||||
{abs_path}/one/two/three/d.foo
|
{abs_path}/one/two/three/d.foo
|
||||||
{abs_path}/one/two/three/directory_foo
|
{abs_path}/one/two/three/directory_foo/
|
||||||
{abs_path}/symlink",
|
{abs_path}/symlink",
|
||||||
abs_path = &abs_path
|
abs_path = &abs_path
|
||||||
),
|
),
|
||||||
|
@ -903,7 +903,7 @@ fn test_absolute_path() {
|
||||||
{abs_path}/one/two/c.foo
|
{abs_path}/one/two/c.foo
|
||||||
{abs_path}/one/two/C.Foo2
|
{abs_path}/one/two/C.Foo2
|
||||||
{abs_path}/one/two/three/d.foo
|
{abs_path}/one/two/three/d.foo
|
||||||
{abs_path}/one/two/three/directory_foo",
|
{abs_path}/one/two/three/directory_foo/",
|
||||||
abs_path = &abs_path
|
abs_path = &abs_path
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -922,7 +922,7 @@ fn test_implicit_absolute_path() {
|
||||||
{abs_path}/one/two/c.foo
|
{abs_path}/one/two/c.foo
|
||||||
{abs_path}/one/two/C.Foo2
|
{abs_path}/one/two/C.Foo2
|
||||||
{abs_path}/one/two/three/d.foo
|
{abs_path}/one/two/three/d.foo
|
||||||
{abs_path}/one/two/three/directory_foo",
|
{abs_path}/one/two/three/directory_foo/",
|
||||||
abs_path = &abs_path
|
abs_path = &abs_path
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -942,7 +942,7 @@ fn test_normalized_absolute_path() {
|
||||||
{abs_path}/one/two/c.foo
|
{abs_path}/one/two/c.foo
|
||||||
{abs_path}/one/two/C.Foo2
|
{abs_path}/one/two/C.Foo2
|
||||||
{abs_path}/one/two/three/d.foo
|
{abs_path}/one/two/three/d.foo
|
||||||
{abs_path}/one/two/three/directory_foo",
|
{abs_path}/one/two/three/directory_foo/",
|
||||||
abs_path = &abs_path
|
abs_path = &abs_path
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -967,18 +967,18 @@ fn test_type() {
|
||||||
|
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--type", "d"],
|
&["--type", "d"],
|
||||||
"./one
|
"./one/
|
||||||
./one/two
|
./one/two/
|
||||||
./one/two/three
|
./one/two/three/
|
||||||
./one/two/three/directory_foo",
|
./one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
|
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--type", "d", "--type", "l"],
|
&["--type", "d", "--type", "l"],
|
||||||
"./one
|
"./one/
|
||||||
./one/two
|
./one/two/
|
||||||
./one/two/three
|
./one/two/three/
|
||||||
./one/two/three/directory_foo
|
./one/two/three/directory_foo/
|
||||||
./symlink",
|
./symlink",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1005,10 +1005,10 @@ fn test_type_executable() {
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--type", "executable", "--type", "directory"],
|
&["--type", "executable", "--type", "directory"],
|
||||||
"./executable-file.sh
|
"./executable-file.sh
|
||||||
./one
|
./one/
|
||||||
./one/two
|
./one/two/
|
||||||
./one/two/three
|
./one/two/three/
|
||||||
./one/two/three/directory_foo",
|
./one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1025,18 +1025,18 @@ fn test_type_empty() {
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--type", "empty"],
|
&["--type", "empty"],
|
||||||
"./0_bytes.foo
|
"./0_bytes.foo
|
||||||
./dir_empty",
|
./dir_empty/",
|
||||||
);
|
);
|
||||||
|
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--type", "empty", "--type", "file", "--type", "directory"],
|
&["--type", "empty", "--type", "file", "--type", "directory"],
|
||||||
"./0_bytes.foo
|
"./0_bytes.foo
|
||||||
./dir_empty",
|
./dir_empty/",
|
||||||
);
|
);
|
||||||
|
|
||||||
te.assert_output(&["--type", "empty", "--type", "file"], "./0_bytes.foo");
|
te.assert_output(&["--type", "empty", "--type", "file"], "./0_bytes.foo");
|
||||||
|
|
||||||
te.assert_output(&["--type", "empty", "--type", "directory"], "./dir_empty");
|
te.assert_output(&["--type", "empty", "--type", "directory"], "./dir_empty/");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// File extension (--extension)
|
/// File extension (--extension)
|
||||||
|
@ -1107,12 +1107,12 @@ fn test_no_extension() {
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["^[^.]+$"],
|
&["^[^.]+$"],
|
||||||
"./aa
|
"./aa
|
||||||
./one
|
./one/
|
||||||
./one/bb
|
./one/bb
|
||||||
./one/two
|
./one/two/
|
||||||
./one/two/three
|
./one/two/three/
|
||||||
./one/two/three/d
|
./one/two/three/d
|
||||||
./one/two/three/directory_foo
|
./one/two/three/directory_foo/
|
||||||
./symlink",
|
./symlink",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1152,14 +1152,14 @@ fn test_symlink_as_root() {
|
||||||
"{dir}/a.foo
|
"{dir}/a.foo
|
||||||
{dir}/broken_symlink
|
{dir}/broken_symlink
|
||||||
{dir}/e1 e2
|
{dir}/e1 e2
|
||||||
{dir}/one
|
{dir}/one/
|
||||||
{dir}/one/b.foo
|
{dir}/one/b.foo
|
||||||
{dir}/one/two
|
{dir}/one/two/
|
||||||
{dir}/one/two/c.foo
|
{dir}/one/two/c.foo
|
||||||
{dir}/one/two/C.Foo2
|
{dir}/one/two/C.Foo2
|
||||||
{dir}/one/two/three
|
{dir}/one/two/three/
|
||||||
{dir}/one/two/three/d.foo
|
{dir}/one/two/three/d.foo
|
||||||
{dir}/one/two/three/directory_foo
|
{dir}/one/two/three/directory_foo/
|
||||||
{dir}/symlink",
|
{dir}/symlink",
|
||||||
dir = &parent_parent
|
dir = &parent_parent
|
||||||
),
|
),
|
||||||
|
@ -1178,9 +1178,9 @@ fn test_symlink_and_absolute_path() {
|
||||||
&format!(
|
&format!(
|
||||||
"{abs_path}/{expected_path}/c.foo
|
"{abs_path}/{expected_path}/c.foo
|
||||||
{abs_path}/{expected_path}/C.Foo2
|
{abs_path}/{expected_path}/C.Foo2
|
||||||
{abs_path}/{expected_path}/three
|
{abs_path}/{expected_path}/three/
|
||||||
{abs_path}/{expected_path}/three/d.foo
|
{abs_path}/{expected_path}/three/d.foo
|
||||||
{abs_path}/{expected_path}/three/directory_foo",
|
{abs_path}/{expected_path}/three/directory_foo/",
|
||||||
abs_path = &abs_path,
|
abs_path = &abs_path,
|
||||||
expected_path = expected_path
|
expected_path = expected_path
|
||||||
),
|
),
|
||||||
|
@ -1196,9 +1196,9 @@ fn test_symlink_as_absolute_root() {
|
||||||
&format!(
|
&format!(
|
||||||
"{abs_path}/symlink/c.foo
|
"{abs_path}/symlink/c.foo
|
||||||
{abs_path}/symlink/C.Foo2
|
{abs_path}/symlink/C.Foo2
|
||||||
{abs_path}/symlink/three
|
{abs_path}/symlink/three/
|
||||||
{abs_path}/symlink/three/d.foo
|
{abs_path}/symlink/three/d.foo
|
||||||
{abs_path}/symlink/three/directory_foo",
|
{abs_path}/symlink/three/directory_foo/",
|
||||||
abs_path = &abs_path
|
abs_path = &abs_path
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1220,9 +1220,9 @@ fn test_symlink_and_full_path() {
|
||||||
&format!("^{prefix}.*three", prefix = prefix),
|
&format!("^{prefix}.*three", prefix = prefix),
|
||||||
],
|
],
|
||||||
&format!(
|
&format!(
|
||||||
"{abs_path}/{expected_path}/three
|
"{abs_path}/{expected_path}/three/
|
||||||
{abs_path}/{expected_path}/three/d.foo
|
{abs_path}/{expected_path}/three/d.foo
|
||||||
{abs_path}/{expected_path}/three/directory_foo",
|
{abs_path}/{expected_path}/three/directory_foo/",
|
||||||
abs_path = &abs_path,
|
abs_path = &abs_path,
|
||||||
expected_path = expected_path
|
expected_path = expected_path
|
||||||
),
|
),
|
||||||
|
@ -1241,9 +1241,9 @@ fn test_symlink_and_full_path_abs_path() {
|
||||||
&format!("{abs_path}/symlink", abs_path = abs_path),
|
&format!("{abs_path}/symlink", abs_path = abs_path),
|
||||||
],
|
],
|
||||||
&format!(
|
&format!(
|
||||||
"{abs_path}/symlink/three
|
"{abs_path}/symlink/three/
|
||||||
{abs_path}/symlink/three/d.foo
|
{abs_path}/symlink/three/d.foo
|
||||||
{abs_path}/symlink/three/directory_foo",
|
{abs_path}/symlink/three/directory_foo/",
|
||||||
abs_path = &abs_path
|
abs_path = &abs_path
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1255,32 +1255,32 @@ fn test_excludes() {
|
||||||
|
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--exclude", "*.foo"],
|
&["--exclude", "*.foo"],
|
||||||
"./one
|
"./one/
|
||||||
./one/two
|
./one/two/
|
||||||
./one/two/C.Foo2
|
./one/two/C.Foo2
|
||||||
./one/two/three
|
./one/two/three/
|
||||||
./one/two/three/directory_foo
|
./one/two/three/directory_foo/
|
||||||
./e1 e2
|
./e1 e2
|
||||||
./symlink",
|
./symlink",
|
||||||
);
|
);
|
||||||
|
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--exclude", "*.foo", "--exclude", "*.Foo2"],
|
&["--exclude", "*.foo", "--exclude", "*.Foo2"],
|
||||||
"./one
|
"./one/
|
||||||
./one/two
|
./one/two/
|
||||||
./one/two/three
|
./one/two/three/
|
||||||
./one/two/three/directory_foo
|
./one/two/three/directory_foo/
|
||||||
./e1 e2
|
./e1 e2
|
||||||
./symlink",
|
./symlink",
|
||||||
);
|
);
|
||||||
|
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--exclude", "*.foo", "--exclude", "*.Foo2", "foo"],
|
&["--exclude", "*.foo", "--exclude", "*.Foo2", "foo"],
|
||||||
"./one/two/three/directory_foo",
|
"./one/two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
|
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--exclude", "one/two", "foo"],
|
&["--exclude", "one/two/", "foo"],
|
||||||
"./a.foo
|
"./a.foo
|
||||||
./one/b.foo",
|
./one/b.foo",
|
||||||
);
|
);
|
||||||
|
@ -1289,11 +1289,11 @@ fn test_excludes() {
|
||||||
&["--exclude", "one/**/*.foo"],
|
&["--exclude", "one/**/*.foo"],
|
||||||
"./a.foo
|
"./a.foo
|
||||||
./e1 e2
|
./e1 e2
|
||||||
./one
|
./one/
|
||||||
./one/two
|
./one/two/
|
||||||
./one/two/C.Foo2
|
./one/two/C.Foo2
|
||||||
./one/two/three
|
./one/two/three/
|
||||||
./one/two/three/directory_foo
|
./one/two/three/directory_foo/
|
||||||
./symlink",
|
./symlink",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1866,7 +1866,7 @@ fn test_custom_path_separator() {
|
||||||
one=two=c.foo
|
one=two=c.foo
|
||||||
one=two=C.Foo2
|
one=two=C.Foo2
|
||||||
one=two=three=d.foo
|
one=two=three=d.foo
|
||||||
one=two=three=directory_foo",
|
one=two=three=directory_foo=",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1877,20 +1877,20 @@ fn test_base_directory() {
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--base-directory", "one"],
|
&["--base-directory", "one"],
|
||||||
"./b.foo
|
"./b.foo
|
||||||
./two
|
./two/
|
||||||
./two/c.foo
|
./two/c.foo
|
||||||
./two/C.Foo2
|
./two/C.Foo2
|
||||||
./two/three
|
./two/three/
|
||||||
./two/three/d.foo
|
./two/three/d.foo
|
||||||
./two/three/directory_foo",
|
./two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
|
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--base-directory", "one/two", "foo"],
|
&["--base-directory", "one/two/", "foo"],
|
||||||
"./c.foo
|
"./c.foo
|
||||||
./C.Foo2
|
./C.Foo2
|
||||||
./three/d.foo
|
./three/d.foo
|
||||||
./three/directory_foo",
|
./three/directory_foo/",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Explicit root path
|
// Explicit root path
|
||||||
|
@ -1899,12 +1899,12 @@ fn test_base_directory() {
|
||||||
"two/c.foo
|
"two/c.foo
|
||||||
two/C.Foo2
|
two/C.Foo2
|
||||||
two/three/d.foo
|
two/three/d.foo
|
||||||
two/three/directory_foo",
|
two/three/directory_foo/",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ignore base directory when absolute path is used
|
// Ignore base directory when absolute path is used
|
||||||
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
|
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
|
||||||
let abs_base_dir = &format!("{abs_path}/one/two", abs_path = &abs_path);
|
let abs_base_dir = &format!("{abs_path}/one/two/", abs_path = &abs_path);
|
||||||
te.assert_output(
|
te.assert_output(
|
||||||
&["--base-directory", abs_base_dir, "foo", &abs_path],
|
&["--base-directory", abs_base_dir, "foo", &abs_path],
|
||||||
&format!(
|
&format!(
|
||||||
|
@ -1913,7 +1913,7 @@ fn test_base_directory() {
|
||||||
{abs_path}/one/two/c.foo
|
{abs_path}/one/two/c.foo
|
||||||
{abs_path}/one/two/C.Foo2
|
{abs_path}/one/two/C.Foo2
|
||||||
{abs_path}/one/two/three/d.foo
|
{abs_path}/one/two/three/d.foo
|
||||||
{abs_path}/one/two/three/directory_foo",
|
{abs_path}/one/two/three/directory_foo/",
|
||||||
abs_path = &abs_path
|
abs_path = &abs_path
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -2069,14 +2069,14 @@ fn test_strip_cwd_prefix() {
|
||||||
&["--strip-cwd-prefix", "."],
|
&["--strip-cwd-prefix", "."],
|
||||||
"a.foo
|
"a.foo
|
||||||
e1 e2
|
e1 e2
|
||||||
one
|
one/
|
||||||
one/b.foo
|
one/b.foo
|
||||||
one/two
|
one/two/
|
||||||
one/two/c.foo
|
one/two/c.foo
|
||||||
one/two/C.Foo2
|
one/two/C.Foo2
|
||||||
one/two/three
|
one/two/three/
|
||||||
one/two/three/d.foo
|
one/two/three/d.foo
|
||||||
one/two/three/directory_foo
|
one/two/three/directory_foo/
|
||||||
symlink",
|
symlink",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue