Skip to content

Commit

Permalink
Merge pull request #1727 from GitoxideLabs/dirwalk-ignore-non-regulars
Browse files Browse the repository at this point in the history
dirwalk ignores non-regular files
  • Loading branch information
Byron authored Dec 18, 2024
2 parents a542775 + a49c960 commit 69ee6a3
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 11 deletions.
2 changes: 1 addition & 1 deletion gitoxide-core/src/repository/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ pub(crate) mod function {
.join(gix::path::from_bstr(entry.rela_path.as_bstr()))
.metadata()
.ok()
.map(|e| e.file_type().into());
.and_then(|e| gix::dir::entry::Kind::try_from_file_type(e.file_type()));
}
let mut disk_kind = entry.disk_kind.expect("present if not pruned");
if !keep {
Expand Down
1 change: 1 addition & 0 deletions gix-dir/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ rust-version = "1.65"

[lib]
doctest = false
test = false

[dependencies]
gix-trace = { version = "^0.1.11", path = "../gix-trace" }
Expand Down
17 changes: 11 additions & 6 deletions gix-dir/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,20 @@ impl Entry {
}
}

impl From<std::fs::FileType> for Kind {
fn from(value: std::fs::FileType) -> Self {
if value.is_dir() {
impl Kind {
/// Try to represent the file type `t` as `Entry`, or return `None` if it cannot be represented.
///
/// The latter can happen if it's a `pipe` for instance.
pub fn try_from_file_type(t: std::fs::FileType) -> Option<Self> {
Some(if t.is_dir() {
Kind::Directory
} else if value.is_symlink() {
} else if t.is_symlink() {
Kind::Symlink
} else {
} else if t.is_file() {
Kind::File
}
} else {
return None;
})
}
}

Expand Down
12 changes: 10 additions & 2 deletions gix-dir/src/walk/classify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ pub fn root(
let mut last_length = None;
let mut path_buf = worktree_root.to_owned();
// These initial values kick in if worktree_relative_root.is_empty();
let file_kind = path_buf.symlink_metadata().map(|m| m.file_type().into()).ok();
let file_kind = path_buf
.symlink_metadata()
.ok()
.and_then(|m| entry::Kind::try_from_file_type(m.file_type()));
let mut out = path(&mut path_buf, buf, 0, file_kind, || None, options, ctx)?;
let worktree_root_is_repository = out
.disk_kind
Expand All @@ -32,7 +35,10 @@ pub fn root(
}
path_buf.push(component);
buf.extend_from_slice(gix_path::os_str_into_bstr(component.as_os_str()).expect("no illformed UTF8"));
let file_kind = path_buf.symlink_metadata().map(|m| m.file_type().into()).ok();
let file_kind = path_buf
.symlink_metadata()
.ok()
.and_then(|m| entry::Kind::try_from_file_type(m.file_type()));

out = path(
&mut path_buf,
Expand Down Expand Up @@ -122,6 +128,8 @@ impl<'a> EntryRef<'a> {
///
/// Returns `(status, file_kind, pathspec_matches_how)` to identify the `status` on disk, along with a classification `file_kind`,
/// and if `file_kind` is not a directory, the way the pathspec matched with `pathspec_matches_how`.
///
/// Note that non-files are pruned by default.
pub fn path(
path: &mut PathBuf,
rela_path: &mut BString,
Expand Down
2 changes: 1 addition & 1 deletion gix-dir/src/walk/readdir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ pub(super) fn recursive(
current_bstr,
if prev_len == 0 { 0 } else { prev_len + 1 },
None,
|| entry.file_type().ok().map(Into::into),
|| entry.file_type().ok().and_then(entry::Kind::try_from_file_type),
opts,
ctx,
)?;
Expand Down
1 change: 1 addition & 0 deletions gix-dir/tests/dir.rs → gix-dir/tests/dir/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub use gix_testtools::Result;

mod walk;
#[path = "../walk_utils/mod.rs"]
pub mod walk_utils;
88 changes: 88 additions & 0 deletions gix-dir/tests/walk/mod.rs → gix-dir/tests/dir/walk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,94 @@ use gix_dir::walk::EmissionMode::*;
use gix_dir::walk::ForDeletionMode;
use gix_ignore::Kind::*;

#[test]
#[cfg(unix)]
fn root_is_fifo() {
let root = fixture_in("fifo", "top-level");

let err = try_collect(&root, None, |keep, ctx| {
walk(
&root,
ctx,
gix_dir::walk::Options {
emit_ignored: Some(Matching),
..options()
},
keep,
)
})
.unwrap_err();
assert!(
matches!(err, gix_dir::walk::Error::WorktreeRootIsFile { .. }),
"roots simply need to be directories to work"
);
}

#[test]
#[cfg(unix)]
fn one_top_level_fifo() {
let root = fixture_in("fifo", "single-top-level-fifo");

let ((out, _root), entries) = collect(&root, None, |keep, ctx| {
walk(
&root,
ctx,
gix_dir::walk::Options {
emit_pruned: false,
..options()
},
keep,
)
});
assert_eq!(
out,
walk::Outcome {
read_dir_calls: 1,
returned_entries: entries.len(),
seen_entries: 2,
}
);

assert_eq!(entries, &[], "Non-files are simply pruned by default");
}

#[test]
#[cfg(unix)]
fn fifo_in_traversal() {
let root = fixture_in("fifo", "two-fifos-two-files");

let ((out, _root), entries) = collect(&root, None, |keep, ctx| {
walk(
&root,
ctx,
gix_dir::walk::Options {
emit_pruned: true,
..options()
},
keep,
)
});
assert_eq!(
out,
walk::Outcome {
read_dir_calls: 3,
returned_entries: entries.len(),
seen_entries: 5,
}
);

assert_eq!(
entries,
&[
entry_nokind(".git", Pruned).with_property(DotGit).with_match(Always),
entry("dir-with-file/nested-file", Untracked, File),
entry("file", Untracked, File),
],
"Non-files are not even pruned, they are ignored entirely.\
If one day this isn't what we want, we can create an own filetype for them"
);
}

#[test]
fn symlink_to_dir_can_be_excluded() -> crate::Result {
let root = fixture_in("many-symlinks", "excluded-symlinks-to-dir");
Expand Down
File renamed without changes.
18 changes: 18 additions & 0 deletions gix-dir/tests/fixtures/fifo.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -eu -o pipefail

mkfifo top-level

git init single-top-level-fifo
(cd single-top-level-fifo
mkfifo top
)

git init two-fifos-two-files
(cd two-fifos-two-files
mkdir dir dir-with-file
touch file dir-with-file/nested-file

mkfifo top
mkfifo dir/nested
)
3 changes: 2 additions & 1 deletion gix-dir/tests/fixtures/generated-archives/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
many.tar
many-symlinks.tar
many-symlinks.tar
fifo.tar

0 comments on commit 69ee6a3

Please sign in to comment.