@@ -5,9 +5,10 @@ use std::{
5
5
} ;
6
6
7
7
use anyhow:: Result ;
8
+ use git:: index:: { entry:: Mode , State } ;
8
9
use git:: objs:: tree:: EntryMode ;
9
- use git:: sec:: trust:: DefaultForLevel ;
10
- use git:: { Commit , ObjectId , Repository , ThreadSafeRepository , Tree } ;
10
+ use git:: { prelude :: FindExt , sec:: trust:: DefaultForLevel } ;
11
+ use git:: { Commit , ObjectId , Repository , ThreadSafeRepository } ;
11
12
use git_repository as git;
12
13
use ignore:: WalkBuilder ;
13
14
use sha1:: Digest ;
@@ -19,12 +20,6 @@ mod test;
19
20
20
21
pub struct Git ;
21
22
22
- struct GitFileMeta {
23
- entry_mode : FileEntryMode ,
24
- oid : ObjectId ,
25
- path : PathBuf ,
26
- }
27
-
28
23
/// A subset of `git_repository::objs::tree::EntryMode` that actually makes sense for tree nodes.
29
24
#[ derive( Hash , PartialEq , Eq ) ]
30
25
enum FileEntryMode {
@@ -118,65 +113,65 @@ impl Git {
118
113
119
114
// TODO: allow diffing against another ref
120
115
let head_tree = repo. head_commit ( ) ?. tree ( ) ?;
121
-
122
- let mut head_tree_files = vec ! [ ] ;
123
- let mut submodule_paths = vec ! [ PathBuf :: from( ".git" ) ] ;
124
- traverse_tree (
125
- & head_tree,
126
- repo,
127
- PathBuf :: new ( ) ,
128
- & mut head_tree_files,
129
- & mut submodule_paths,
130
- ) ?;
131
-
132
- submodule_paths
133
- . iter_mut ( )
134
- . for_each ( |path| * path = work_dir. join ( & path) ) ;
116
+ let head_state = State :: from_tree ( & head_tree. id , |oid, buf| {
117
+ repo. objects . find_tree_iter ( oid, buf) . ok ( )
118
+ } ) ?;
135
119
136
120
let mut head_tree_set = HashSet :: new ( ) ;
121
+ let mut submodule_paths = vec ! [ ] ;
137
122
138
123
let mut raw_changes = RawChanges :: default ( ) ;
139
124
140
- // Looks for modified & deleted files by walking the head tree and probing the fs
141
- for item in head_tree_files. into_iter ( ) {
142
- let full_path = work_dir. join ( & item. path ) ;
125
+ for item in head_state. entries ( ) {
126
+ let full_path = work_dir. join ( & PathBuf :: from ( item. path ( & head_state) . to_string ( ) ) ) ;
143
127
144
- match git_meta_from_path ( & full_path , autocrlf ) ? {
145
- Some ( ( new_entry_mode , new_oid ) ) => {
146
- // On Windows, physical files are _always_ inferred as `Blob`. We simply don't
147
- // compare the entry mode as it's pointless.
148
- let entry_mode_changed = {
149
- # [ cfg ( unix ) ]
150
- {
151
- new_entry_mode != item . entry_mode
152
- }
128
+ if item . mode == Mode :: COMMIT {
129
+ submodule_paths . push ( full_path ) ;
130
+ } else {
131
+ let old_entry_mode = match item . mode {
132
+ Mode :: FILE => FileEntryMode :: Blob ,
133
+ Mode :: FILE_EXECUTABLE => FileEntryMode :: BlobExecutable ,
134
+ Mode :: SYMLINK => FileEntryMode :: Link ,
135
+ _ => anyhow :: bail! ( "unexpected entry mode" ) ,
136
+ } ;
153
137
154
- #[ cfg( not( unix) ) ]
155
- {
156
- false
138
+ match git_meta_from_path ( & full_path, autocrlf) ? {
139
+ Some ( ( new_entry_mode, new_oid) ) => {
140
+ // On Windows, physical files are _always_ inferred as `Blob`. We simply don't
141
+ // compare the entry mode as it's pointless.
142
+ let entry_mode_changed = {
143
+ #[ cfg( unix) ]
144
+ {
145
+ new_entry_mode != old_entry_mode
146
+ }
147
+
148
+ #[ cfg( not( unix) ) ]
149
+ {
150
+ false
151
+ }
152
+ } ;
153
+
154
+ if entry_mode_changed || new_oid != item. id {
155
+ raw_changes. add_modification ( RawModification {
156
+ previous_entry_mode : old_entry_mode,
157
+ previous_oid : item. id ,
158
+ entry_mode : new_entry_mode,
159
+ oid : new_oid,
160
+ path : full_path. clone ( ) ,
161
+ } ) ;
157
162
}
158
- } ;
159
-
160
- if entry_mode_changed || new_oid != item. oid {
161
- raw_changes. add_modification ( RawModification {
162
- previous_entry_mode : item. entry_mode ,
163
- previous_oid : item. oid ,
164
- entry_mode : new_entry_mode,
165
- oid : new_oid,
163
+ }
164
+ None => {
165
+ raw_changes. add_deletion ( RawDeletion {
166
+ entry_mode : old_entry_mode,
167
+ oid : item. id ,
166
168
path : full_path. clone ( ) ,
167
169
} ) ;
168
170
}
169
171
}
170
- None => {
171
- raw_changes. add_deletion ( RawDeletion {
172
- entry_mode : item. entry_mode ,
173
- oid : item. oid ,
174
- path : full_path. clone ( ) ,
175
- } ) ;
176
- }
177
- }
178
172
179
- head_tree_set. insert ( full_path) ;
173
+ head_tree_set. insert ( full_path) ;
174
+ }
180
175
}
181
176
182
177
// Looks for untracked files by walking the fs and probing the (cached) head tree
@@ -346,58 +341,6 @@ fn find_file_in_commit(repo: &Repository, commit: &Commit, file: &Path) -> Optio
346
341
}
347
342
}
348
343
349
- /// Traverses a tree with recursion.
350
- fn traverse_tree (
351
- tree : & Tree ,
352
- repo : & Repository ,
353
- base : PathBuf ,
354
- all_files : & mut Vec < GitFileMeta > ,
355
- submodules : & mut Vec < PathBuf > ,
356
- ) -> Result < ( ) > {
357
- for entry in tree. iter ( ) {
358
- let entry = entry?;
359
- let mut new_base = base. clone ( ) ;
360
- new_base. push ( entry. filename ( ) . to_string ( ) ) ;
361
-
362
- match entry. mode ( ) {
363
- EntryMode :: Tree => {
364
- let obj = repo. find_object ( entry. id ( ) ) ?;
365
- let new_tree = obj. try_into_tree ( ) ?;
366
- traverse_tree ( & new_tree, repo, new_base, all_files, submodules) ?;
367
- }
368
- EntryMode :: Commit => {
369
- // Submodules not supported yet. We return the path so that the fs walk can ignore
370
- // them.
371
- // TODO: support option for recursively looking into submodules
372
- submodules. push ( new_base) ;
373
- }
374
- EntryMode :: Link => {
375
- all_files. push ( GitFileMeta {
376
- entry_mode : FileEntryMode :: Link ,
377
- oid : entry. oid ( ) ,
378
- path : new_base,
379
- } ) ;
380
- }
381
- EntryMode :: Blob => {
382
- all_files. push ( GitFileMeta {
383
- entry_mode : FileEntryMode :: Blob ,
384
- oid : entry. oid ( ) ,
385
- path : new_base,
386
- } ) ;
387
- }
388
- EntryMode :: BlobExecutable => {
389
- all_files. push ( GitFileMeta {
390
- entry_mode : FileEntryMode :: BlobExecutable ,
391
- oid : entry. oid ( ) ,
392
- path : new_base,
393
- } ) ;
394
- }
395
- }
396
- }
397
-
398
- Ok ( ( ) )
399
- }
400
-
401
344
fn git_meta_from_path (
402
345
path : & Path ,
403
346
autocrlf : bool ,
0 commit comments