From b2bfa4a51bf8513c5753bc9eba07edad4f2231ba Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Tue, 15 Oct 2024 14:08:24 +0200 Subject: [PATCH 1/2] Remove unused parameter and fix potential ignore bug --- gix-dir/src/walk/classify.rs | 2 +- gix-pathspec/src/search/matching.rs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/gix-dir/src/walk/classify.rs b/gix-dir/src/walk/classify.rs index b87c893e7c7..6c61eb53e23 100644 --- a/gix-dir/src/walk/classify.rs +++ b/gix-dir/src/walk/classify.rs @@ -180,7 +180,7 @@ pub fn path( } let pathspec_could_match = ctx .pathspec - .can_match_relative_path(rela_path.as_bstr(), disk_kind.map(|ft| ft.is_dir())); + .can_match_relative_path(rela_path.as_bstr(), disk_kind.map_or(false, |ft| ft.is_dir())); if !pathspec_could_match { return Ok(out.with_status(entry::Status::Pruned)); } diff --git a/gix-pathspec/src/search/matching.rs b/gix-pathspec/src/search/matching.rs index 69f62a91c6c..90956b128ec 100644 --- a/gix-pathspec/src/search/matching.rs +++ b/gix-pathspec/src/search/matching.rs @@ -136,10 +136,9 @@ impl Search { /// /// This is useful if `relative_path` is a directory leading up to the item that is going to be matched in full later. /// Note that it should not end with `/` to indicate it's a directory, rather, use `is_dir` to indicate this. - /// `is_dir` is `true` if `relative_path` is a directory. If `None`, the fact that a pathspec might demand a directory match - /// is ignored. + /// TODO /// Returns `false` if this pathspec has no chance of ever matching `relative_path`. - pub fn can_match_relative_path(&self, relative_path: &BStr, is_dir: Option) -> bool { + pub fn can_match_relative_path(&self, relative_path: &BStr, is_dir: bool) -> bool { if self.patterns.is_empty() || relative_path.is_empty() { return true; } @@ -178,8 +177,8 @@ impl Search { } else { is_match }; - if let Some(is_dir) = is_dir.filter(|_| pattern.signature.contains(MagicSignature::MUST_BE_DIR)) { - is_match = if is_dir { + if is_dir { + is_match = if pattern.signature.contains(MagicSignature::MUST_BE_DIR) { matches!(pattern.path.get(common_len), None | Some(&b'/')) } else { relative_path.get(common_len) == Some(&b'/') From fab6b303401a25b97813fb1779ebf3b60c767e1e Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sun, 13 Oct 2024 19:47:44 +0200 Subject: [PATCH 2/2] Ignore non-regular files (very much unfinished, I will probably finish it later this week). My "mkfifo fifo && cargo publish" hangs because cargo tries to tar the fifo as well. This is surprising because neither "git status" nor "git check-ignore -v fifo" list the untracked fifo. Fifo type files are completely ignored by Git since commit 8695c8bfe1 (Add "show-files" command to show the list of managed (or non-managed) files., 2005-04-11) which states the reason: > * [...] We currently ignore anything but > * directories and regular files. That's because git doesn't > * handle them at all yet. Maybe that will change some day. It didn't change yet[*]. Try to match Git to minimize surprise. Combined with some extra error handling, this enables some cleanup. [*] But the logic from read_directory() has moved into treat_path(). --- gitoxide-core/src/repository/clean.rs | 13 +--- gitoxide-core/src/repository/index/entries.rs | 42 +++++------ gitoxide-core/src/repository/status.rs | 6 +- gix-dir/src/entry.rs | 27 +++---- gix-dir/src/lib.rs | 5 +- gix-dir/src/walk/classify.rs | 70 ++++++++++--------- gix-dir/src/walk/function.rs | 8 +-- gix-dir/src/walk/readdir.rs | 26 +++++-- gix-pathspec/src/search/matching.rs | 3 +- gix-status/src/index_as_worktree/function.rs | 16 ++--- .../src/index_as_worktree_with_renames/mod.rs | 29 ++++---- gix-submodule/src/is_active_platform.rs | 2 +- gix/src/pathspec.rs | 10 +-- gix/tests/gix/repository/pathspec.rs | 2 +- 14 files changed, 126 insertions(+), 133 deletions(-) diff --git a/gitoxide-core/src/repository/clean.rs b/gitoxide-core/src/repository/clean.rs index b9bac90d9f3..0fa3ac34582 100644 --- a/gitoxide-core/src/repository/clean.rs +++ b/gitoxide-core/src/repository/clean.rs @@ -112,7 +112,7 @@ pub(crate) mod function { let mut pruned_entries = 0; let mut saw_ignored_directory = false; let mut saw_untracked_directory = false; - for (mut entry, dir_status) in entries.into_iter() { + for (entry, dir_status) in entries.into_iter() { if dir_status.is_some() { if debug { writeln!( @@ -130,7 +130,7 @@ pub(crate) mod function { .pathspec_match .map_or(false, |m| m != gix::dir::entry::PathspecMatch::Excluded), Some(pathspec) => pathspec - .pattern_matching_relative_path(entry.rela_path.as_bstr(), entry.disk_kind.map(|k| k.is_dir())) + .pattern_matching_relative_path(entry.rela_path.as_bstr(), entry.disk_kind.is_dir()) .map_or(false, |m| !m.is_excluded()), }; pruned_entries += usize::from(!pathspec_includes_entry); @@ -158,14 +158,7 @@ pub(crate) mod function { } Status::Untracked => true, }; - if entry.disk_kind.is_none() { - entry.disk_kind = workdir - .join(gix::path::from_bstr(entry.rela_path.as_bstr())) - .metadata() - .ok() - .map(|e| e.file_type().into()); - } - let mut disk_kind = entry.disk_kind.expect("present if not pruned"); + let mut disk_kind = entry.disk_kind; if !keep { if debug { writeln!(err, "DBG: prune '{}' as -x or -p is missing", entry.rela_path).ok(); diff --git a/gitoxide-core/src/repository/index/entries.rs b/gitoxide-core/src/repository/index/entries.rs index 5eaad0a1e56..a91ac478bbb 100644 --- a/gitoxide-core/src/repository/index/entries.rs +++ b/gitoxide-core/src/repository/index/entries.rs @@ -160,30 +160,26 @@ pub(crate) mod function { // Note that we intentionally ignore `_case` so that we act like git does, attribute matching case is determined // by the repository, not the pathspec. let entry_is_excluded = pathspec - .pattern_matching_relative_path( - entry.path(&index), - Some(false), - &mut |rela_path, _case, is_dir, out| { - cache - .as_mut() - .map(|(attrs, cache)| { - match last_match { - // The user wants the attributes for display, so the match happened already. - Some(matched) => { - attrs.copy_into(cache.attributes_collection(), out); - matched - } - // The user doesn't want attributes, so we set the cache position on demand only - None => cache - .at_entry(rela_path, Some(is_dir_to_mode(is_dir))) - .ok() - .map(|platform| platform.matching_attributes(out)) - .unwrap_or_default(), + .pattern_matching_relative_path(entry.path(&index), true, &mut |rela_path, _case, is_dir, out| { + cache + .as_mut() + .map(|(attrs, cache)| { + match last_match { + // The user wants the attributes for display, so the match happened already. + Some(matched) => { + attrs.copy_into(cache.attributes_collection(), out); + matched } - }) - .unwrap_or_default() - }, - ) + // The user doesn't want attributes, so we set the cache position on demand only + None => cache + .at_entry(rela_path, Some(is_dir_to_mode(is_dir))) + .ok() + .map(|platform| platform.matching_attributes(out)) + .unwrap_or_default(), + } + }) + .unwrap_or_default() + }) .map_or(true, |m| m.is_excluded()); let entry_is_submodule = entry.mode.is_submodule(); diff --git a/gitoxide-core/src/repository/status.rs b/gitoxide-core/src/repository/status.rs index e32cb7e23d0..5c9fa45289c 100644 --- a/gitoxide-core/src/repository/status.rs +++ b/gitoxide-core/src/repository/status.rs @@ -130,11 +130,7 @@ pub fn show( status = "?", rela_path = gix::path::relativize_with_prefix(&gix::path::from_bstr(entry.rela_path), prefix).display(), - slash = if entry.disk_kind.unwrap_or(gix::dir::entry::Kind::File).is_dir() { - "/" - } else { - "" - } + slash = if entry.disk_kind.is_dir() { "/" } else { "" } )?; } } diff --git a/gix-dir/src/entry.rs b/gix-dir/src/entry.rs index 4bfc02e02a4..6227abf0508 100644 --- a/gix-dir/src/entry.rs +++ b/gix-dir/src/entry.rs @@ -147,14 +147,17 @@ impl Entry { } } -impl From for Kind { - fn from(value: std::fs::FileType) -> Self { +impl TryFrom for Kind { + type Error = (); + fn try_from(value: std::fs::FileType) -> Result { if value.is_dir() { - Kind::Directory + Ok(Kind::Directory) } else if value.is_symlink() { - Kind::Symlink + Ok(Kind::Symlink) + } else if value.is_file() { + Ok(Kind::File) } else { - Kind::File + return Err(()); } } } @@ -175,18 +178,16 @@ impl Status { /// Use `pathspec_match` to determine if a pathspec matches in any way, affecting the decision to recurse. pub fn can_recurse( &self, - file_type: Option, + file_type: Kind, pathspec_match: Option, for_deletion: Option, worktree_root_is_repository: bool, ) -> bool { - let is_dir_on_disk = file_type.map_or(false, |ft| { - if worktree_root_is_repository { - ft.is_dir() - } else { - ft.is_recursable_dir() - } - }); + let is_dir_on_disk = if worktree_root_is_repository { + file_type.is_dir() + } else { + file_type.is_recursable_dir() + }; if !is_dir_on_disk { return false; } diff --git a/gix-dir/src/lib.rs b/gix-dir/src/lib.rs index 5c099a730d9..88fe7d64385 100644 --- a/gix-dir/src/lib.rs +++ b/gix-dir/src/lib.rs @@ -32,8 +32,7 @@ pub struct EntryRef<'a> { /// Additional properties of the entry. pub property: Option, /// Further specify what the entry is on disk, similar to a file mode. - /// This is `None` if we decided it's not worth it to exit early and avoid trying to obtain this information. - pub disk_kind: Option, + pub disk_kind: entry::Kind, /// The kind of entry according to the index, if tracked. *Usually* the same as `disk_kind`. pub index_kind: Option, /// Determines how the pathspec matched. @@ -51,7 +50,7 @@ pub struct Entry { /// Additional flags that further clarify properties of the entry. pub property: Option, /// Further specify what the entry is on disk, similar to a file mode. - pub disk_kind: Option, + pub disk_kind: entry::Kind, /// The kind of entry according to the index, if tracked. *Usually* the same as `disk_kind`. /// Note that even if tracked, this might be `None` which indicates this is a worktree placed /// within the parent repository. diff --git a/gix-dir/src/walk/classify.rs b/gix-dir/src/walk/classify.rs index 6c61eb53e23..f904635d196 100644 --- a/gix-dir/src/walk/classify.rs +++ b/gix-dir/src/walk/classify.rs @@ -1,7 +1,7 @@ use crate::{entry, Entry, EntryRef}; use std::borrow::Cow; -use crate::entry::PathspecMatch; +use crate::entry::{Kind, PathspecMatch}; use crate::walk::{Context, Error, ForDeletionMode, Options}; use bstr::{BStr, BString, ByteSlice}; use std::path::{Path, PathBuf}; @@ -20,11 +20,21 @@ 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 mut out = path(&mut path_buf, buf, 0, file_kind, || None, options, ctx)?; - let worktree_root_is_repository = out - .disk_kind - .map_or(false, |kind| matches!(kind, entry::Kind::Repository)); + let compute_file_kind = |path_buf: &mut PathBuf| { + let file_type = path_buf + .symlink_metadata() + .map_err(|err| Error::SymlinkMetadata { + source: err, + path: std::mem::take(path_buf), + })? + .file_type(); + Kind::try_from(file_type).map_err(|()| Error::WorktreeRootIsFile { + root: std::mem::take(path_buf), + }) + }; + let file_kind = compute_file_kind(&mut path_buf)?; + let mut out = path(&mut path_buf, buf, 0, file_kind, options, ctx)?; + let worktree_root_is_repository = out.disk_kind == entry::Kind::Repository; for component in worktree_relative_root.components() { if last_length.is_some() { @@ -32,14 +42,13 @@ 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 = compute_file_kind(&mut path_buf)?; out = path( &mut path_buf, buf, last_length.map(|l| l + 1 /* slash */).unwrap_or_default(), file_kind, - || None, options, ctx, )?; @@ -67,7 +76,7 @@ pub struct Outcome { /// /// Note that the index is used to avoid disk access provided its entries are marked uptodate /// (possibly by a prior call to update the status). - pub disk_kind: Option, + pub disk_kind: entry::Kind, /// What the entry looks like in the index, or `None` if we aborted early. pub index_kind: Option, /// If a pathspec matched, this is how it matched. Maybe `None` if computation didn't see the need to evaluate it. @@ -80,7 +89,7 @@ impl Outcome { self } - fn with_kind(mut self, disk_kind: Option, index_kind: Option) -> Self { + fn with_kind(mut self, disk_kind: entry::Kind, index_kind: Option) -> Self { self.disk_kind = disk_kind; self.index_kind = index_kind; self @@ -126,8 +135,7 @@ pub fn path( path: &mut PathBuf, rela_path: &mut BString, filename_start_idx: usize, - disk_kind: Option, - on_demand_disk_kind: impl FnOnce() -> Option, + disk_kind: entry::Kind, Options { ignore_case, recurse_repositories, @@ -150,11 +158,7 @@ pub fn path( if is_eq(rela_path[filename_start_idx..].as_bstr(), ".git", ignore_case) { out.pathspec_match = ctx .pathspec - .pattern_matching_relative_path( - rela_path.as_bstr(), - disk_kind.map(|ft| ft.is_dir()), - ctx.pathspec_attributes, - ) + .pattern_matching_relative_path(rela_path.as_bstr(), disk_kind.is_dir(), ctx.pathspec_attributes) .map(Into::into); if for_deletion.is_some() { if let Some(excluded) = ctx @@ -164,7 +168,7 @@ pub fn path( stack .at_entry( rela_path.as_bstr(), - disk_kind.map(|ft| is_dir_to_mode(ft.is_dir())), + Some(is_dir_to_mode(disk_kind.is_dir())), ctx.objects, ) .map(|platform| platform.excluded_kind()) @@ -180,9 +184,9 @@ pub fn path( } let pathspec_could_match = ctx .pathspec - .can_match_relative_path(rela_path.as_bstr(), disk_kind.map_or(false, |ft| ft.is_dir())); + .can_match_relative_path(rela_path.as_bstr(), disk_kind.is_dir()); if !pathspec_could_match { - return Ok(out.with_status(entry::Status::Pruned)); + return Ok(out); } let (uptodate_index_kind, index_kind, property) = resolve_file_type_with_index( @@ -190,22 +194,22 @@ pub fn path( ctx.index, ctx.ignore_case_index_lookup.filter(|_| ignore_case), ); - let mut kind = uptodate_index_kind.or(disk_kind).or_else(on_demand_disk_kind); + let mut kind = uptodate_index_kind.unwrap_or(disk_kind); // We always check the pathspec to have the value filled in reliably. out.pathspec_match = ctx .pathspec - .pattern_matching_relative_path(rela_path.as_bstr(), kind.map(|ft| ft.is_dir()), ctx.pathspec_attributes) + .pattern_matching_relative_path(rela_path.as_bstr(), kind.is_dir(), ctx.pathspec_attributes) .map(Into::into); if worktree_relative_worktree_dirs.map_or(false, |worktrees| worktrees.contains(&*rela_path)) { return Ok(out - .with_kind(Some(entry::Kind::Repository), None) + .with_kind(entry::Kind::Repository, None) .with_status(entry::Status::Tracked)); } let maybe_status = if property.is_none() { - (index_kind.map(|k| k.is_dir()) == kind.map(|k| k.is_dir())).then_some(entry::Status::Tracked) + (index_kind.map(|k| k.is_dir()) == Some(kind.is_dir())).then_some(entry::Status::Tracked) } else { out.property = property; Some(entry::Status::Pruned) @@ -213,11 +217,11 @@ pub fn path( let is_dir = if symlinks_to_directories_are_ignored_like_directories && ctx.excludes.is_some() - && kind.map_or(false, |ft| ft == entry::Kind::Symlink) + && kind == entry::Kind::Symlink { path.metadata().ok().map(|md| is_dir_to_mode(md.is_dir())) } else { - kind.map(|ft| is_dir_to_mode(ft.is_dir())) + Some(is_dir_to_mode(kind.is_dir())) }; let mut maybe_upgrade_to_repository = |current_kind, find_harder: bool| { @@ -231,7 +235,7 @@ pub fn path( ) }; if let Some(status) = maybe_status { - if kind == Some(entry::Kind::Directory) && index_kind == Some(entry::Kind::Repository) { + if kind == entry::Kind::Directory && index_kind == Some(entry::Kind::Repository) { kind = maybe_upgrade_to_repository(kind, false); } return Ok(out.with_status(status).with_kind(kind, index_kind)); @@ -265,7 +269,7 @@ pub fn path( ), ); } - if kind.map_or(false, |d| d.is_recursable_dir()) + if kind.is_recursable_dir() && (out.pathspec_match.is_none() || worktree_relative_worktree_dirs.map_or(false, |worktrees| { for_deletion.is_some() @@ -287,7 +291,7 @@ pub fn path( debug_assert!(maybe_status.is_none()); let mut status = entry::Status::Untracked; - if kind.map_or(false, |ft| ft.is_dir()) { + if kind.is_dir() { kind = maybe_upgrade_to_repository(kind, classify_untracked_bare_repositories); } else if out.pathspec_match.is_none() { status = entry::Status::Pruned; @@ -296,13 +300,13 @@ pub fn path( } pub fn maybe_upgrade_to_repository( - current_kind: Option, + current_kind: entry::Kind, find_harder: bool, recurse_repositories: bool, path: &mut PathBuf, current_dir: &Path, git_dir_realpath: &Path, -) -> Option { +) -> entry::Kind { if recurse_repositories { return current_kind; } @@ -315,7 +319,7 @@ pub fn maybe_upgrade_to_repository( is_nested_repo = !git_dir_is_our_own; } if is_nested_repo { - return Some(entry::Kind::Repository); + return entry::Kind::Repository; } } path.push(gix_discover::DOT_GIT_DIR); @@ -329,7 +333,7 @@ pub fn maybe_upgrade_to_repository( path.pop(); if is_nested_nonbare_repo { - Some(entry::Kind::Repository) + entry::Kind::Repository } else { current_kind } diff --git a/gix-dir/src/walk/function.rs b/gix-dir/src/walk/function.rs index 21600f93251..13f2f343ea3 100644 --- a/gix-dir/src/walk/function.rs +++ b/gix-dir/src/walk/function.rs @@ -70,9 +70,9 @@ pub fn walk( let can_recurse = can_recurse( buf.as_bstr(), - if root == worktree_root && root_info.disk_kind == Some(entry::Kind::Symlink) && current.is_dir() { + if root == worktree_root && root_info.disk_kind == entry::Kind::Symlink && current.is_dir() { classify::Outcome { - disk_kind: Some(entry::Kind::Directory), + disk_kind: entry::Kind::Directory, ..root_info } } else { @@ -83,7 +83,7 @@ pub fn walk( delegate, ); if !can_recurse { - if buf.is_empty() && !root_info.disk_kind.map_or(false, |kind| kind.is_dir()) { + if buf.is_empty() && !root_info.disk_kind.is_dir() { return Err(Error::WorktreeRootIsFile { root: root.to_owned() }); } if options.precompose_unicode { @@ -159,7 +159,7 @@ pub(super) fn can_recurse( worktree_root_is_repository: bool, delegate: &mut dyn Delegate, ) -> bool { - let is_dir = info.disk_kind.map_or(false, |k| k.is_dir()); + let is_dir = info.disk_kind.is_dir(); if !is_dir { return false; } diff --git a/gix-dir/src/walk/readdir.rs b/gix-dir/src/walk/readdir.rs index ab1e9370344..3a60d056d96 100644 --- a/gix-dir/src/walk/readdir.rs +++ b/gix-dir/src/walk/readdir.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use std::path::{Path, PathBuf}; use std::sync::atomic::Ordering; -use crate::entry::{PathspecMatch, Status}; +use crate::entry::{Kind, PathspecMatch, Status}; use crate::walk::function::{can_recurse, emit_entry}; use crate::walk::EmissionMode::CollapseDirectory; use crate::walk::{ @@ -59,12 +59,24 @@ pub(super) fn recursive( ); current.push(file_name); + let disk_kind = { + let m = current.metadata().map_err(|err| Error::DirEntryFileType { + path: std::mem::take(current), + source: err, + })?; + match Kind::try_from(m.file_type()) { + Ok(kind) => kind, + Err(_err) => { + continue; + } + } + }; + let mut info = classify::path( current, current_bstr, if prev_len == 0 { 0 } else { prev_len + 1 }, - None, - || entry.file_type().ok().map(Into::into), + disk_kind, opts, ctx, )?; @@ -94,7 +106,7 @@ pub(super) fn recursive( } } else { if opts.for_deletion == Some(ForDeletionMode::IgnoredDirectoriesCanHideNestedRepositories) - && info.disk_kind == Some(entry::Kind::Directory) + && info.disk_kind == entry::Kind::Directory && matches!(info.status, Status::Ignored(_)) { info.disk_kind = classify::maybe_upgrade_to_repository( @@ -227,7 +239,7 @@ impl Mark { property: { assert_ne!( dir_info.disk_kind, - Some(entry::Kind::Repository), + entry::Kind::Repository, "BUG: it shouldn't be possible to classify an empty dir as repository" ); if !state.may_collapse(dir_path) { @@ -241,7 +253,7 @@ impl Mark { }, pathspec_match: ctx .pathspec - .pattern_matching_relative_path(dir_rela_path, Some(true), ctx.pathspec_attributes) + .pattern_matching_relative_path(dir_rela_path, true, ctx.pathspec_attributes) .map(|m| m.kind.into()), ..dir_info }; @@ -300,7 +312,7 @@ impl Mark { .map(|e| (e.disk_kind, e.status, e.pathspec_match)) { entries += 1; - if kind == Some(entry::Kind::Repository) { + if kind == entry::Kind::Repository { return None; } if pathspec_match.map_or(false, |m| { diff --git a/gix-pathspec/src/search/matching.rs b/gix-pathspec/src/search/matching.rs index 90956b128ec..01219d1538c 100644 --- a/gix-pathspec/src/search/matching.rs +++ b/gix-pathspec/src/search/matching.rs @@ -28,7 +28,7 @@ impl Search { pub fn pattern_matching_relative_path( &mut self, relative_path: &BStr, - is_dir: Option, + is_dir: bool, attributes: &mut dyn FnMut(&BStr, Case, bool, &mut gix_attributes::search::Outcome) -> bool, ) -> Option> { static MATCH_ALL_STAND_IN: Pattern = Pattern { @@ -54,7 +54,6 @@ impl Search { return None; } - let is_dir = is_dir.unwrap_or(false); let patterns_len = self.patterns.len(); let res = self.patterns.iter_mut().find_map(|mapping| { let ignore_case = mapping.value.pattern.signature.contains(MagicSignature::ICASE); diff --git a/gix-status/src/index_as_worktree/function.rs b/gix-status/src/index_as_worktree/function.rs index 515da2568e1..6bd53e98c0c 100644 --- a/gix-status/src/index_as_worktree/function.rs +++ b/gix-status/src/index_as_worktree/function.rs @@ -270,16 +270,12 @@ impl<'index> State<'_, 'index> { } let path = entry.path_in(self.path_backing); let is_excluded = pathspec - .pattern_matching_relative_path( - path, - Some(entry.mode.is_submodule()), - &mut |relative_path, case, is_dir, out| { - self.attr_stack - .set_case(case) - .at_entry(relative_path, Some(is_dir_to_mode(is_dir)), objects) - .map_or(false, |platform| platform.matching_attributes(out)) - }, - ) + .pattern_matching_relative_path(path, true, &mut |relative_path, case, is_dir, out| { + self.attr_stack + .set_case(case) + .at_entry(relative_path, Some(is_dir_to_mode(is_dir)), objects) + .map_or(false, |platform| platform.matching_attributes(out)) + }) .map_or(true, |m| m.is_excluded()); if is_excluded { diff --git a/gix-status/src/index_as_worktree_with_renames/mod.rs b/gix-status/src/index_as_worktree_with_renames/mod.rs index f2202ea0869..e149e0b3292 100644 --- a/gix-status/src/index_as_worktree_with_renames/mod.rs +++ b/gix-status/src/index_as_worktree_with_renames/mod.rs @@ -463,17 +463,18 @@ pub(super) mod function { fn entry_mode(&self) -> EntryMode { match self { - ModificationOrDirwalkEntry::Modification(c) => c.entry.mode.to_tree_entry_mode(), - ModificationOrDirwalkEntry::DirwalkEntry { entry, .. } => entry.disk_kind.map(|kind| { - match kind { - Kind::File => gix_object::tree::EntryKind::Blob, - Kind::Symlink => gix_object::tree::EntryKind::Link, - Kind::Repository | Kind::Directory => gix_object::tree::EntryKind::Tree, - } - .into() - }), + ModificationOrDirwalkEntry::Modification(c) => c + .entry + .mode + .to_tree_entry_mode() + .unwrap_or(gix_object::tree::EntryKind::Blob.into()), + ModificationOrDirwalkEntry::DirwalkEntry { entry, .. } => match entry.disk_kind { + Kind::File => gix_object::tree::EntryKind::Blob, + Kind::Symlink => gix_object::tree::EntryKind::Link, + Kind::Repository | Kind::Directory => gix_object::tree::EntryKind::Tree, + } + .into(), } - .unwrap_or(gix_object::tree::EntryKind::Blob.into()) } fn id_and_entry_mode(&self) -> (&oid, EntryMode) { @@ -487,7 +488,7 @@ pub(super) mod function { pub(super) fn calculate_worktree_id( object_hash: gix_hash::Kind, worktree_root: &Path, - disk_kind: Option, + disk_kind: gix_dir::entry::Kind, rela_path: &BStr, filter: &mut gix_filter::Pipeline, attrs: &mut gix_worktree::Stack, @@ -495,11 +496,7 @@ pub(super) mod function { buf: &mut Vec, should_interrupt: &std::sync::atomic::AtomicBool, ) -> Result { - let Some(kind) = disk_kind else { - return Ok(object_hash.null()); - }; - - Ok(match kind { + Ok(match disk_kind { Kind::File => { let platform = attrs .at_entry(rela_path, None, objects) diff --git a/gix-submodule/src/is_active_platform.rs b/gix-submodule/src/is_active_platform.rs index 85f4b9353b7..588443472a9 100644 --- a/gix-submodule/src/is_active_platform.rs +++ b/gix-submodule/src/is_active_platform.rs @@ -39,7 +39,7 @@ impl IsActivePlatform { }; if let Some(val) = self.search.as_mut().map(|search| { search - .pattern_matching_relative_path(name, Some(true), attributes) + .pattern_matching_relative_path(name, true, attributes) .map_or(false, |m| !m.is_excluded()) }) { return Ok(val); diff --git a/gix/src/pathspec.rs b/gix/src/pathspec.rs index be69ad0321e..dde28cb235d 100644 --- a/gix/src/pathspec.rs +++ b/gix/src/pathspec.rs @@ -125,7 +125,7 @@ impl<'repo> Pathspec<'repo> { pub fn pattern_matching_relative_path<'a>( &mut self, relative_path: impl Into<&'a BStr>, - is_dir: Option, + is_dir: bool, ) -> Option> { self.search.pattern_matching_relative_path( relative_path.into(), @@ -142,7 +142,7 @@ impl<'repo> Pathspec<'repo> { /// The simplified version of [`pattern_matching_relative_path()`](Self::pattern_matching_relative_path()) which returns /// `true` if `relative_path` is included in the set of positive pathspecs, while not being excluded. - pub fn is_included<'a>(&mut self, relative_path: impl Into<&'a BStr>, is_dir: Option) -> bool { + pub fn is_included<'a>(&mut self, relative_path: impl Into<&'a BStr>, is_dir: bool) -> bool { self.pattern_matching_relative_path(relative_path, is_dir) .map_or(false, |m| !m.is_excluded()) } @@ -157,7 +157,7 @@ impl<'repo> Pathspec<'repo> { index.prefixed_entries(self.search.common_prefix()).map(|entries| { entries.iter().filter_map(move |entry| { let path = entry.path(index); - self.is_included(path, Some(false)).then_some((path, entry)) + self.is_included(path, true).then_some((path, entry)) }) }) } @@ -179,7 +179,7 @@ impl PathspecDetached { pub fn pattern_matching_relative_path<'a>( &mut self, relative_path: impl Into<&'a BStr>, - is_dir: Option, + is_dir: bool, ) -> Option> { self.search.pattern_matching_relative_path( relative_path.into(), @@ -196,7 +196,7 @@ impl PathspecDetached { /// The simplified version of [`pattern_matching_relative_path()`](Self::pattern_matching_relative_path()) which returns /// `true` if `relative_path` is included in the set of positive pathspecs, while not being excluded. - pub fn is_included<'a>(&mut self, relative_path: impl Into<&'a BStr>, is_dir: Option) -> bool { + pub fn is_included<'a>(&mut self, relative_path: impl Into<&'a BStr>, is_dir: bool) -> bool { self.pattern_matching_relative_path(relative_path, is_dir) .map_or(false, |m| !m.is_excluded()) } diff --git a/gix/tests/gix/repository/pathspec.rs b/gix/tests/gix/repository/pathspec.rs index d4b61235ce6..7fcd19d48ca 100644 --- a/gix/tests/gix/repository/pathspec.rs +++ b/gix/tests/gix/repository/pathspec.rs @@ -29,7 +29,7 @@ fn defaults_are_taken_from_repo_config() -> crate::Result { assert!(!pathspec.is_included("ho", Some(false))); assert!(!pathspec.is_included("hip", Some(false))); assert!(pathspec - .pattern_matching_relative_path("hip", Some(false)) + .pattern_matching_relative_path("hip", true) .expect("match") .is_excluded());