ignore: add sort_by_file_path builder method

This permits callers to sort entries by their full file path, which makes
it easy to query for various file statistics.

It would have been better to provide a comparator on DirEntry itself,
similar to how walkdir does it, but this seems to require quite a bit of
work to make the types work out, assuming we want to continue to use
walkdir's sorting support (we do).
This commit is contained in:
Andrew Gallant 2018-08-25 22:52:24 -04:00
parent f9ce7a84a8
commit 510f15f4da

View File

@ -453,12 +453,16 @@ pub struct WalkBuilder {
max_filesize: Option<u64>, max_filesize: Option<u64>,
follow_links: bool, follow_links: bool,
same_file_system: bool, same_file_system: bool,
sorter: Option<Arc< sorter: Option<Sorter>,
Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static
>>,
threads: usize, threads: usize,
} }
#[derive(Clone)]
enum Sorter {
ByName(Arc<Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static>),
ByPath(Arc<Fn(&Path, &Path) -> cmp::Ordering + Send + Sync + 'static>),
}
impl fmt::Debug for WalkBuilder { impl fmt::Debug for WalkBuilder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("WalkBuilder") f.debug_struct("WalkBuilder")
@ -496,7 +500,7 @@ impl WalkBuilder {
pub fn build(&self) -> Walk { pub fn build(&self) -> Walk {
let follow_links = self.follow_links; let follow_links = self.follow_links;
let max_depth = self.max_depth; let max_depth = self.max_depth;
let cmp = self.sorter.clone(); let sorter = self.sorter.clone();
let its = self.paths.iter().map(move |p| { let its = self.paths.iter().map(move |p| {
if p == Path::new("-") { if p == Path::new("-") {
(p.to_path_buf(), None) (p.to_path_buf(), None)
@ -507,11 +511,19 @@ impl WalkBuilder {
if let Some(max_depth) = max_depth { if let Some(max_depth) = max_depth {
wd = wd.max_depth(max_depth); wd = wd.max_depth(max_depth);
} }
if let Some(ref cmp) = cmp { if let Some(ref sorter) = sorter {
let cmp = cmp.clone(); match sorter.clone() {
wd = wd.sort_by(move |a, b| { Sorter::ByName(cmp) => {
cmp(a.file_name(), b.file_name()) wd = wd.sort_by(move |a, b| {
}); cmp(a.file_name(), b.file_name())
});
}
Sorter::ByPath(cmp) => {
wd = wd.sort_by(move |a, b| {
cmp(a.path(), b.path())
});
}
}
} }
(p.to_path_buf(), Some(WalkEventIter::from(wd))) (p.to_path_buf(), Some(WalkEventIter::from(wd)))
} }
@ -726,6 +738,30 @@ impl WalkBuilder {
self self
} }
/// Set a function for sorting directory entries by their path.
///
/// If a compare function is set, the resulting iterator will return all
/// paths in sorted order. The compare function will be called to compare
/// entries from the same directory.
///
/// This is like `sort_by_file_name`, except the comparator accepts
/// a `&Path` instead of the base file name, which permits it to sort by
/// more criteria.
///
/// This method will override any previous sorter set by this method or
/// by `sort_by_file_name`.
///
/// Note that this is not used in the parallel iterator.
pub fn sort_by_file_path<F>(
&mut self,
cmp: F,
) -> &mut WalkBuilder
where F: Fn(&Path, &Path) -> cmp::Ordering + Send + Sync + 'static
{
self.sorter = Some(Sorter::ByPath(Arc::new(cmp)));
self
}
/// Set a function for sorting directory entries by file name. /// Set a function for sorting directory entries by file name.
/// ///
/// If a compare function is set, the resulting iterator will return all /// If a compare function is set, the resulting iterator will return all
@ -733,11 +769,14 @@ impl WalkBuilder {
/// names from entries from the same directory using only the name of the /// names from entries from the same directory using only the name of the
/// entry. /// entry.
/// ///
/// This method will override any previous sorter set by this method or
/// by `sort_by_file_path`.
///
/// Note that this is not used in the parallel iterator. /// Note that this is not used in the parallel iterator.
pub fn sort_by_file_name<F>(&mut self, cmp: F) -> &mut WalkBuilder pub fn sort_by_file_name<F>(&mut self, cmp: F) -> &mut WalkBuilder
where F: Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static where F: Fn(&OsStr, &OsStr) -> cmp::Ordering + Send + Sync + 'static
{ {
self.sorter = Some(Arc::new(cmp)); self.sorter = Some(Sorter::ByName(Arc::new(cmp)));
self self
} }