1
- use crate :: { entry, Entry } ;
1
+ use crate :: { entry, Entry , EntryRef } ;
2
+ use std:: borrow:: Cow ;
2
3
3
4
use crate :: entry:: PathspecMatch ;
4
5
use crate :: walk:: { Context , Error , ForDeletionMode , Options } ;
@@ -61,7 +62,10 @@ pub fn root(
61
62
pub struct Outcome {
62
63
/// The computed status of an entry. It can be seen as aggregate of things we know about an entry.
63
64
pub status : entry:: Status ,
64
- /// What the entry is on disk, or `None` if we aborted the classification early.
65
+ /// Additional properties.
66
+ pub flags : entry:: Flags ,
67
+ /// What the entry is on disk, or `None` if we aborted the classification early or an IO-error occurred
68
+ /// when querying the disk.
65
69
///
66
70
/// Note that the index is used to avoid disk access provided its entries are marked uptodate
67
71
/// (possibly by a prior call to update the status).
@@ -89,13 +93,27 @@ impl From<&Entry> for Outcome {
89
93
fn from ( e : & Entry ) -> Self {
90
94
Outcome {
91
95
status : e. status ,
96
+ flags : e. flags ,
92
97
disk_kind : e. disk_kind ,
93
98
index_kind : e. index_kind ,
94
99
pathspec_match : e. pathspec_match ,
95
100
}
96
101
}
97
102
}
98
103
104
+ impl < ' a > EntryRef < ' a > {
105
+ pub ( super ) fn from_outcome ( rela_path : Cow < ' a , BStr > , info : crate :: walk:: classify:: Outcome ) -> Self {
106
+ EntryRef {
107
+ rela_path,
108
+ flags : info. flags ,
109
+ status : info. status ,
110
+ disk_kind : info. disk_kind ,
111
+ index_kind : info. index_kind ,
112
+ pathspec_match : info. pathspec_match ,
113
+ }
114
+ }
115
+ }
116
+
99
117
/// Figure out what to do with `rela_path`, provided as worktree-relative path, with `disk_file_type` if it is known already
100
118
/// as it helps to match pathspecs correctly, which can be different for directories.
101
119
/// `path` is a disk-accessible variant of `rela_path` which is within the `worktree_root`, and will be modified temporarily but remain unchanged.
@@ -123,12 +141,34 @@ pub fn path(
123
141
ctx : & mut Context < ' _ > ,
124
142
) -> Result < Outcome , Error > {
125
143
let mut out = Outcome {
126
- status : entry:: Status :: DotGit ,
144
+ status : entry:: Status :: Pruned ,
145
+ flags : entry:: Flags :: empty ( ) ,
127
146
disk_kind,
128
147
index_kind : None ,
129
148
pathspec_match : None ,
130
149
} ;
131
150
if is_eq ( rela_path[ filename_start_idx..] . as_bstr ( ) , ".git" , ignore_case) {
151
+ out. pathspec_match = ctx
152
+ . pathspec
153
+ . pattern_matching_relative_path (
154
+ rela_path. as_bstr ( ) ,
155
+ disk_kind. map ( |ft| ft. is_dir ( ) ) ,
156
+ ctx. pathspec_attributes ,
157
+ )
158
+ . map ( Into :: into) ;
159
+ if let Some ( excluded) = ctx
160
+ . excludes
161
+ . as_mut ( )
162
+ . map_or ( Ok ( None ) , |stack| {
163
+ stack
164
+ . at_entry ( rela_path. as_bstr ( ) , disk_kind. map ( |ft| ft. is_dir ( ) ) , ctx. objects )
165
+ . map ( |platform| platform. excluded_kind ( ) )
166
+ } )
167
+ . map_err ( Error :: ExcludesAccess ) ?
168
+ {
169
+ out. status = entry:: Status :: Ignored ( excluded) ;
170
+ }
171
+ out. flags = entry:: Flags :: DOT_GIT ;
132
172
return Ok ( out) ;
133
173
}
134
174
let pathspec_could_match = rela_path. is_empty ( )
@@ -139,31 +179,25 @@ pub fn path(
139
179
return Ok ( out. with_status ( entry:: Status :: Pruned ) ) ;
140
180
}
141
181
142
- let ( uptodate_index_kind, index_kind, mut maybe_status ) = resolve_file_type_with_index (
182
+ let ( uptodate_index_kind, index_kind, extra_flags ) = resolve_file_type_with_index (
143
183
rela_path,
144
184
ctx. index ,
145
185
ctx. ignore_case_index_lookup . filter ( |_| ignore_case) ,
146
186
) ;
147
187
let mut kind = uptodate_index_kind. or ( disk_kind) . or_else ( on_demand_disk_kind) ;
148
188
149
- maybe_status = maybe_status
150
- . or_else ( || ( index_kind. map ( |k| k. is_dir ( ) ) == kind. map ( |k| k. is_dir ( ) ) ) . then_some ( entry:: Status :: Tracked ) ) ;
189
+ let maybe_status = if extra_flags. is_empty ( ) {
190
+ ( index_kind. map ( |k| k. is_dir ( ) ) == kind. map ( |k| k. is_dir ( ) ) ) . then_some ( entry:: Status :: Tracked )
191
+ } else {
192
+ out. flags |= extra_flags;
193
+ Some ( entry:: Status :: Pruned )
194
+ } ;
151
195
152
196
// We always check the pathspec to have the value filled in reliably.
153
197
out. pathspec_match = ctx
154
198
. pathspec
155
- . pattern_matching_relative_path (
156
- rela_path. as_bstr ( ) ,
157
- disk_kind. map ( |ft| ft. is_dir ( ) ) ,
158
- ctx. pathspec_attributes ,
159
- )
160
- . map ( |m| {
161
- if m. is_excluded ( ) {
162
- PathspecMatch :: Excluded
163
- } else {
164
- m. kind . into ( )
165
- }
166
- } ) ;
199
+ . pattern_matching_relative_path ( rela_path. as_bstr ( ) , kind. map ( |ft| ft. is_dir ( ) ) , ctx. pathspec_attributes )
200
+ . map ( Into :: into) ;
167
201
168
202
let mut maybe_upgrade_to_repository = |current_kind, find_harder : bool | {
169
203
if recurse_repositories {
@@ -258,8 +292,7 @@ pub fn path(
258
292
259
293
/// Note that `rela_path` is used as buffer for convenience, but will be left as is when this function returns.
260
294
/// Also note `maybe_file_type` will be `None` for entries that aren't up-to-date and files, for directories at least one entry must be uptodate.
261
- /// Returns `(maybe_file_type, Option<index_file_type>, Option(TrackedExcluded)`, with the last option being set only for sparse directories.
262
- /// `tracked_exclued` indicates it's a sparse directory was found.
295
+ /// Returns `(maybe_file_type, Option<index_file_type>, flags)`, with the last option being a flag set only for sparse directories in the index.
263
296
/// `index_file_type` is the type of `rela_path` as available in the index.
264
297
///
265
298
/// ### Shortcoming
@@ -271,9 +304,9 @@ fn resolve_file_type_with_index(
271
304
rela_path : & mut BString ,
272
305
index : & gix_index:: State ,
273
306
ignore_case : Option < & gix_index:: AccelerateLookup < ' _ > > ,
274
- ) -> ( Option < entry:: Kind > , Option < entry:: Kind > , Option < entry:: Status > ) {
307
+ ) -> ( Option < entry:: Kind > , Option < entry:: Kind > , entry:: Flags ) {
275
308
// TODO: either get this to work for icase as well, or remove the need for it. Logic is different in both branches.
276
- let mut special_status = None ;
309
+ let mut special_status = entry :: Flags :: empty ( ) ;
277
310
278
311
fn entry_to_kinds ( entry : & gix_index:: Entry ) -> ( Option < entry:: Kind > , Option < entry:: Kind > ) {
279
312
let kind = if entry. mode . is_submodule ( ) {
@@ -352,7 +385,7 @@ fn resolve_file_type_with_index(
352
385
. filter ( |_| kind. is_none ( ) )
353
386
. map_or ( false , |idx| index. entries ( ) [ idx] . mode . is_sparse ( ) )
354
387
{
355
- special_status = Some ( entry:: Status :: TrackedExcluded ) ;
388
+ special_status |= entry:: Flags :: TRACKED_EXCLUDED ;
356
389
}
357
390
( kind, is_tracked. then_some ( entry:: Kind :: Directory ) )
358
391
}
0 commit comments