#[cfg(feature = "walkdir")]
mod shared {
pub enum Parallelism {
Serial,
ThreadPoolPerTraversal {
thread_name: &'static str,
},
}
}
#[cfg(any(feature = "walkdir", feature = "fs-read-dir"))]
mod walkdir_precompose {
use std::{borrow::Cow, ffi::OsStr, path::Path};
#[derive(Debug)]
pub struct DirEntry<T: std::fmt::Debug> {
inner: T,
precompose_unicode: bool,
}
impl<T: std::fmt::Debug> DirEntry<T> {
pub fn new(inner: T, precompose_unicode: bool) -> Self {
Self {
inner,
precompose_unicode,
}
}
}
pub trait DirEntryApi {
fn path(&self) -> Cow<'_, Path>;
fn file_name(&self) -> Cow<'_, OsStr>;
fn file_type(&self) -> std::io::Result<std::fs::FileType>;
}
impl<T: DirEntryApi + std::fmt::Debug> DirEntry<T> {
pub fn path(&self) -> Cow<'_, Path> {
let path = self.inner.path();
if self.precompose_unicode {
gix_utils::str::precompose_path(path)
} else {
path
}
}
pub fn file_name(&self) -> Cow<'_, OsStr> {
let name = self.inner.file_name();
if self.precompose_unicode {
gix_utils::str::precompose_os_string(name)
} else {
name
}
}
pub fn file_type(&self) -> std::io::Result<std::fs::FileType> {
self.inner.file_type()
}
}
#[cfg(feature = "walkdir")]
pub struct WalkDir<T> {
pub(crate) inner: Option<T>,
pub(crate) precompose_unicode: bool,
}
#[cfg(feature = "walkdir")]
pub struct WalkDirIter<T, I, E>
where
T: Iterator<Item = Result<I, E>>,
I: DirEntryApi,
{
pub(crate) inner: T,
pub(crate) precompose_unicode: bool,
}
#[cfg(feature = "walkdir")]
impl<T, I, E> Iterator for WalkDirIter<T, I, E>
where
T: Iterator<Item = Result<I, E>>,
I: DirEntryApi + std::fmt::Debug,
{
type Item = Result<DirEntry<I>, E>;
fn next(&mut self) -> Option<Self::Item> {
self.inner
.next()
.map(|res| res.map(|entry| DirEntry::new(entry, self.precompose_unicode)))
}
}
}
#[cfg(feature = "fs-read-dir")]
pub mod read_dir {
use std::{borrow::Cow, ffi::OsStr, fs::FileType, path::Path};
pub type DirEntry = super::walkdir_precompose::DirEntry<std::fs::DirEntry>;
impl super::walkdir_precompose::DirEntryApi for std::fs::DirEntry {
fn path(&self) -> Cow<'_, Path> {
self.path().into()
}
fn file_name(&self) -> Cow<'_, OsStr> {
self.file_name().into()
}
fn file_type(&self) -> std::io::Result<FileType> {
self.file_type()
}
}
}
#[cfg(feature = "walkdir")]
pub mod walkdir {
use std::{borrow::Cow, ffi::OsStr, fs::FileType, path::Path};
pub use walkdir::Error;
use walkdir::{DirEntry as DirEntryImpl, WalkDir as WalkDirImpl};
pub type DirEntry = super::walkdir_precompose::DirEntry<DirEntryImpl>;
pub type WalkDir = super::walkdir_precompose::WalkDir<WalkDirImpl>;
pub use super::shared::Parallelism;
impl super::walkdir_precompose::DirEntryApi for DirEntryImpl {
fn path(&self) -> Cow<'_, Path> {
self.path().into()
}
fn file_name(&self) -> Cow<'_, OsStr> {
self.file_name().into()
}
fn file_type(&self) -> std::io::Result<FileType> {
Ok(self.file_type())
}
}
impl IntoIterator for WalkDir {
type Item = Result<DirEntry, walkdir::Error>;
type IntoIter = DirEntryIter;
fn into_iter(self) -> Self::IntoIter {
DirEntryIter {
inner: self.inner.expect("always set (builder fix)").into_iter(),
precompose_unicode: self.precompose_unicode,
}
}
}
impl WalkDir {
pub fn min_depth(mut self, min: usize) -> Self {
self.inner = Some(self.inner.take().expect("always set").min_depth(min));
self
}
pub fn max_depth(mut self, max: usize) -> Self {
self.inner = Some(self.inner.take().expect("always set").max_depth(max));
self
}
pub fn follow_links(mut self, toggle: bool) -> Self {
self.inner = Some(self.inner.take().expect("always set").follow_links(toggle));
self
}
}
pub fn walkdir_new(root: &Path, _: Parallelism, precompose_unicode: bool) -> WalkDir {
WalkDir {
inner: WalkDirImpl::new(root).into(),
precompose_unicode,
}
}
pub fn walkdir_sorted_new(root: &Path, _: Parallelism, precompose_unicode: bool) -> WalkDir {
WalkDir {
inner: WalkDirImpl::new(root)
.sort_by(|a, b| {
let storage_a;
let storage_b;
let a_name = match gix_path::os_str_into_bstr(a.file_name()) {
Ok(f) => f,
Err(_) => {
storage_a = a.file_name().to_string_lossy();
storage_a.as_ref().into()
}
};
let b_name = match gix_path::os_str_into_bstr(b.file_name()) {
Ok(f) => f,
Err(_) => {
storage_b = b.file_name().to_string_lossy();
storage_b.as_ref().into()
}
};
let common = a_name.len().min(b_name.len());
a_name[..common].cmp(&b_name[..common]).then_with(|| {
let a = a_name.get(common).or_else(|| a.file_type().is_dir().then_some(&b'/'));
let b = b_name.get(common).or_else(|| b.file_type().is_dir().then_some(&b'/'));
a.cmp(&b)
})
})
.into(),
precompose_unicode,
}
}
pub type DirEntryIter = super::walkdir_precompose::WalkDirIter<walkdir::IntoIter, DirEntryImpl, walkdir::Error>;
}
#[cfg(feature = "walkdir")]
pub use self::walkdir::{walkdir_new, walkdir_sorted_new, WalkDir};
pub fn open_options_no_follow() -> std::fs::OpenOptions {
#[cfg_attr(not(unix), allow(unused_mut))]
let mut options = std::fs::OpenOptions::new();
#[cfg(unix)]
{
use std::os::unix::fs::OpenOptionsExt;
options.custom_flags(libc::O_NOFOLLOW);
}
options
}