Skip to content

dirwalk ignores non-regular files #1727

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading