Skip to content

Commit

Permalink
in progress more closesly follow walkdir
Browse files Browse the repository at this point in the history
  • Loading branch information
jessegrosjean committed Nov 9, 2019
1 parent 7ee0cb3 commit 66d46ac
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 42 deletions.
79 changes: 73 additions & 6 deletions src/core/dir_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ pub struct DirEntry<C: ClientState> {
pub depth: usize,
/// File name of this entry without leading path component.
pub file_name: OsString,
/// File type result for the file/directory that this entry points at.
pub file_type_result: Result<FileType>,
/// File type for the file/directory that this entry points at.
pub file_type: FileType,
/// Metadata result for the file/directory that this entry points at. Defaults
/// to `None`. Filled in by the walk process when the
/// [`preload_metadata`](struct.WalkDir.html#method.preload_metadata) option
Expand All @@ -42,13 +42,75 @@ pub struct DirEntry<C: ClientState> {
/// If `read_children_path` is set and resulting `fs::read_dir` generates an error
/// then that error is stored here.
pub read_children_error: Option<Error>,

follow_link: bool,
}

impl<C: ClientState> DirEntry<C> {
pub(crate) fn from_entry(
depth: usize,
parent_path: Arc<PathBuf>,
fs_dir_entry: &fs::DirEntry,
) -> Result<Self> {
let file_type = fs_dir_entry.file_type()?;
let file_name = fs_dir_entry.file_name();
let read_children_path = if file_type.is_dir() {
Some(Arc::new(parent_path.join(&file_name)))
} else {
None
};

Ok(DirEntry {
depth,
file_name,
file_type,
follow_link: false,
metadata_result: None,
parent_path,
read_children_path,
read_children_error: None,
client_state: C::default(),
})
}

pub(crate) fn from_path(
depth: usize,
path: &Path,
follow: bool,
) -> Result<Self> {
let metadata = if follow {
fs::metadata(&path)?
} else {
fs::symlink_metadata(&path)?
};

let root_name = OsString::from("/");
let file_name = path.file_name().unwrap_or(&root_name);
let parent_path = Arc::new(path.parent().map(Path::to_path_buf).unwrap_or_default());
let read_children_path = if metadata.file_type().is_dir() {
Some(Arc::new(path.into()))
} else {
None
};

Ok(DirEntry {
depth,
file_name: file_name.to_owned(),
file_type: metadata.file_type(),
follow_link: false,
metadata_result: Some(Ok(metadata)),
parent_path,
read_children_path,
read_children_error: None,
client_state: C::default(),
})
}

/*
pub(crate) fn new(
depth: usize,
file_name: OsString,
file_type_result: Result<FileType>,
file_type: FileType,
metadata_result: Option<Result<Metadata>>,
parent_path: Arc<PathBuf>,
read_children_path: Option<Arc<PathBuf>>,
Expand All @@ -57,12 +119,13 @@ impl<C: ClientState> DirEntry<C> {
DirEntry {
depth,
file_name,
file_type_result,
file_type,
parent_path,
metadata_result,
read_children_path,
read_children_error: None,
client_state,
follow_link: false,
}
}
Expand All @@ -80,13 +143,13 @@ impl<C: ClientState> DirEntry<C> {
Ok(DirEntry::new(
0,
file_name.to_owned(),
Ok(metadata.file_type()),
metadata.file_type(),
Some(Ok(metadata)),
parent_path,
read_children_path,
C::default(),
))
}
}*/

/// Path to the file/directory represented by this entry.
///
Expand All @@ -95,6 +158,10 @@ impl<C: ClientState> DirEntry<C> {
self.parent_path.join(&self.file_name)
}

pub fn path_is_symlink(&self) -> bool {
self.file_type.is_symlink() || self.follow_link
}

/// Reference to the path of the directory containing this entry.
pub fn parent_path(&self) -> &Path {
&self.parent_path
Expand Down
73 changes: 37 additions & 36 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,9 @@ struct WalkDirOptions<C: ClientState> {
sort: bool,
max_depth: usize,
skip_hidden: bool,
parallelism: Parallelism,
follow_links: bool,
preload_metadata: bool,
parallelism: Parallelism,
process_entries: Option<Arc<ProcessEntriesFunction<C>>>,
}

Expand All @@ -163,8 +164,9 @@ impl<C: ClientState> WalkDirGeneric<C> {
options: WalkDirOptions {
sort: false,
max_depth: ::std::usize::MAX,
parallelism: Parallelism::RayonDefaultPool,
skip_hidden: true,
follow_links: false,
parallelism: Parallelism::RayonDefaultPool,
preload_metadata: false,
process_entries: None,
},
Expand All @@ -190,6 +192,22 @@ impl<C: ClientState> WalkDirGeneric<C> {
self
}

/// Follow symbolic links. By default, this is disabled.
///
/// When `yes` is `true`, symbolic links are followed as if they were normal
/// directories and files. If a symbolic link is broken or is involved in a
/// loop, an error is yielded.
///
/// When enabled, the yielded [`DirEntry`] values represent the target of
/// the link while the path corresponds to the link. See the [`DirEntry`]
/// type for more details.
///
/// [`DirEntry`]: struct.DirEntry.html
pub fn follow_links(mut self, follow_links: bool) -> Self {
self.options.follow_links = follow_links;
self
}

/// Preload metadata before yielding entries. When running in parrallel the
/// metadata is loaded in rayon's thread pool.
pub fn preload_metadata(mut self, preload_metadata: bool) -> Self {
Expand Down Expand Up @@ -241,17 +259,18 @@ impl<C: ClientState> IntoIterator for WalkDirGeneric<C> {

fn into_iter(self) -> DirEntryIter<C> {
let sort = self.options.sort;
let max_depth = self.options.max_depth;
let parallelism = self.options.parallelism;
let skip_hidden = self.options.skip_hidden;
let max_depth = self.options.max_depth;
let follow_links = self.options.follow_links;
let preload_metadata = self.options.preload_metadata;
let process_entries = self.options.process_entries.clone();
let root_entry_results = if let Some(process_entries) = process_entries.as_ref() {
let mut root_entry_results = vec![DirEntry::new_root_with_path(&self.root)];
let mut root_entry_results = vec![DirEntry::from_path(0, &self.root, follow_links)];
process_entries(&mut C::default(), &mut root_entry_results);
root_entry_results
} else {
vec![DirEntry::new_root_with_path(&self.root)]
vec![DirEntry::from_path(0, &self.root, follow_links)]
};

DirEntryIter::new(
Expand All @@ -272,44 +291,25 @@ impl<C: ClientState> IntoIterator for WalkDirGeneric<C> {

let mut dir_entry_results: Vec<_> = fs::read_dir(path.as_ref())?
.filter_map(|dir_entry_result| {
let dir_entry = match dir_entry_result {
let fs_dir_entry = match dir_entry_result {
Ok(fs_dir_entry) => fs_dir_entry,
Err(err) => return Some(Err(err)),
};

let mut dir_entry = match DirEntry::from_entry(depth, path.clone(), &fs_dir_entry) {
Ok(dir_entry) => dir_entry,
Err(err) => return Some(Err(err)),
};

let file_name = dir_entry.file_name();
if skip_hidden && is_hidden(&file_name) {
if skip_hidden && is_hidden(&dir_entry.file_name) {
return None;
}

let file_type = dir_entry.file_type();
let metadata = if preload_metadata {
Some(dir_entry.metadata())
} else {
None
};

let read_children_path = match file_type {
Ok(file_type) => {
let l = file_type.is_symlink();
if file_type.is_dir() && depth < max_depth {
Some(Arc::new(path.as_ref().join(dir_entry.file_name())))
} else {
None
}
}
Err(_) => None,
};
if preload_metadata {
dir_entry.metadata_result = Some(fs_dir_entry.metadata());
}

Some(Ok(DirEntry::new(
depth,
file_name,
file_type,
metadata,
path.clone(),
read_children_path,
C::default(),
)))
Some(Ok(dir_entry))
})
.collect();

Expand Down Expand Up @@ -337,8 +337,9 @@ impl<C: ClientState> Clone for WalkDirOptions<C> {
WalkDirOptions {
sort: false,
max_depth: self.max_depth,
parallelism: self.parallelism.clone(),
skip_hidden: self.skip_hidden,
follow_links: self.follow_links,
parallelism: self.parallelism.clone(),
preload_metadata: self.preload_metadata,
process_entries: self.process_entries.clone(),
}
Expand Down

0 comments on commit 66d46ac

Please sign in to comment.