@@ -2,7 +2,10 @@ use super::{utils::bytes2string, CommitId};
2
2
use crate :: { error:: Result , sync:: utils:: repo} ;
3
3
use git2:: { Oid , Repository , Tree } ;
4
4
use scopetime:: scope_time;
5
- use std:: path:: { Path , PathBuf } ;
5
+ use std:: {
6
+ cmp:: Ordering ,
7
+ path:: { Path , PathBuf } ,
8
+ } ;
6
9
7
10
/// `tree_files` returns a list of `FileTree`
8
11
#[ derive( Debug , PartialEq ) ]
@@ -15,7 +18,7 @@ pub struct TreeFile {
15
18
id : Oid ,
16
19
}
17
20
18
- ///
21
+ /// guarantees sorting the result
19
22
pub fn tree_files (
20
23
repo_path : & str ,
21
24
commit : CommitId ,
@@ -31,9 +34,40 @@ pub fn tree_files(
31
34
32
35
tree_recurse ( & repo, & PathBuf :: from ( "./" ) , & tree, & mut files) ?;
33
36
37
+ sort_file_list ( & mut files) ;
38
+
34
39
Ok ( files)
35
40
}
36
41
42
+ fn sort_file_list ( files : & mut Vec < TreeFile > ) {
43
+ files. sort_by ( |a, b| path_cmp ( & a. path , & b. path ) ) ;
44
+ }
45
+
46
+ // applies topologically order on paths sorting
47
+ fn path_cmp ( a : & Path , b : & Path ) -> Ordering {
48
+ let mut comp_a = a. components ( ) . into_iter ( ) . peekable ( ) ;
49
+ let mut comp_b = b. components ( ) . into_iter ( ) . peekable ( ) ;
50
+
51
+ loop {
52
+ let a = comp_a. next ( ) ;
53
+ let b = comp_b. next ( ) ;
54
+
55
+ let a_is_file = comp_a. peek ( ) . is_none ( ) ;
56
+ let b_is_file = comp_b. peek ( ) . is_none ( ) ;
57
+
58
+ if a_is_file && !b_is_file {
59
+ return Ordering :: Greater ;
60
+ } else if !a_is_file && b_is_file {
61
+ return Ordering :: Less ;
62
+ }
63
+
64
+ let cmp = a. cmp ( & b) ;
65
+ if cmp != Ordering :: Equal {
66
+ return cmp;
67
+ }
68
+ }
69
+ }
70
+
37
71
///
38
72
pub fn tree_file_content (
39
73
repo_path : & str ,
@@ -109,4 +143,99 @@ mod tests {
109
143
assert_eq ! ( files_c2. len( ) , 1 ) ;
110
144
assert_ne ! ( files_c2[ 0 ] , files[ 0 ] ) ;
111
145
}
146
+
147
+ #[ test]
148
+ fn test_sorting ( ) {
149
+ let mut list = vec ! [ "file" , "folder/file" , "folder/afile" ]
150
+ . iter ( )
151
+ . map ( |f| TreeFile {
152
+ path : PathBuf :: from ( f) ,
153
+ filemode : 0 ,
154
+ id : Oid :: zero ( ) ,
155
+ } )
156
+ . collect ( ) ;
157
+
158
+ sort_file_list ( & mut list) ;
159
+
160
+ assert_eq ! (
161
+ list. iter( )
162
+ . map( |f| f. path. to_string_lossy( ) )
163
+ . collect:: <Vec <_>>( ) ,
164
+ vec![
165
+ String :: from( "folder/afile" ) ,
166
+ String :: from( "folder/file" ) ,
167
+ String :: from( "file" )
168
+ ]
169
+ ) ;
170
+ }
171
+
172
+ #[ test]
173
+ fn test_sorting_folders ( ) {
174
+ let mut list = vec ! [ "bfolder/file" , "afolder/file" ]
175
+ . iter ( )
176
+ . map ( |f| TreeFile {
177
+ path : PathBuf :: from ( f) ,
178
+ filemode : 0 ,
179
+ id : Oid :: zero ( ) ,
180
+ } )
181
+ . collect ( ) ;
182
+
183
+ sort_file_list ( & mut list) ;
184
+
185
+ assert_eq ! (
186
+ list. iter( )
187
+ . map( |f| f. path. to_string_lossy( ) )
188
+ . collect:: <Vec <_>>( ) ,
189
+ vec![
190
+ String :: from( "afolder/file" ) ,
191
+ String :: from( "bfolder/file" ) ,
192
+ ]
193
+ ) ;
194
+ }
195
+
196
+ #[ test]
197
+ fn test_sorting_folders2 ( ) {
198
+ let mut list = vec ! [ "bfolder/sub/file" , "afolder/file" ]
199
+ . iter ( )
200
+ . map ( |f| TreeFile {
201
+ path : PathBuf :: from ( f) ,
202
+ filemode : 0 ,
203
+ id : Oid :: zero ( ) ,
204
+ } )
205
+ . collect ( ) ;
206
+
207
+ sort_file_list ( & mut list) ;
208
+
209
+ assert_eq ! (
210
+ list. iter( )
211
+ . map( |f| f. path. to_string_lossy( ) )
212
+ . collect:: <Vec <_>>( ) ,
213
+ vec![
214
+ String :: from( "afolder/file" ) ,
215
+ String :: from( "bfolder/sub/file" ) ,
216
+ ]
217
+ ) ;
218
+ }
219
+
220
+ #[ test]
221
+ fn test_path_cmp ( ) {
222
+ assert_eq ! (
223
+ path_cmp(
224
+ & PathBuf :: from( "bfolder/sub/file" ) ,
225
+ & PathBuf :: from( "afolder/file" )
226
+ ) ,
227
+ Ordering :: Greater
228
+ ) ;
229
+ }
230
+
231
+ #[ test]
232
+ fn test_path_file_cmp ( ) {
233
+ assert_eq ! (
234
+ path_cmp(
235
+ & PathBuf :: from( "a" ) ,
236
+ & PathBuf :: from( "afolder/file" )
237
+ ) ,
238
+ Ordering :: Greater
239
+ ) ;
240
+ }
112
241
}
0 commit comments