1
1
use std:: collections:: HashMap ;
2
- use std:: { ffi:: CString , fs} ;
2
+ use std:: vec;
3
+ use std:: ffi:: CString ;
3
4
use std:: path:: { Path , PathBuf } ;
4
5
use libc:: { self , stat} ;
5
6
use mercury:: hash:: SHA1 ;
@@ -8,12 +9,12 @@ use mercury::internal::object::tree::{Tree, TreeItem, TreeItemMode};
8
9
use mercury:: internal:: object:: types:: ObjectType ;
9
10
10
11
use crate :: manager:: store:: TreeStore ;
11
- use crate :: util :: GPath ;
12
+
12
13
13
14
fn collect_paths < P : AsRef < Path > > ( path : P ) -> Vec < PathBuf > {
14
15
let mut paths = Vec :: new ( ) ;
15
16
16
- if let Ok ( entries) = fs:: read_dir ( path) {
17
+ if let Ok ( entries) = std :: fs:: read_dir ( path) {
17
18
for entry in entries. filter_map ( Result :: ok) {
18
19
let path = entry. path ( ) ;
19
20
if path. is_dir ( ) {
@@ -43,74 +44,177 @@ fn is_whiteout_inode<P: AsRef<Path>>(path: P)-> bool {
43
44
44
45
false
45
46
}
47
+ /// the output tree in hashmap , which hash value is not computed.
46
48
#[ allow( unused) ]
47
- fn diff ( lower : PathBuf , upper : PathBuf , dbpath : & str ) ->( HashMap < PathBuf , Tree > , Vec < Blob > ) {
49
+ pub fn diff ( lower : PathBuf , upper : PathBuf , dbpath : & str , monopath : PathBuf ) ->( HashMap < PathBuf , Tree > , Vec < Blob > ) {
48
50
let db = sled:: open ( dbpath) . unwrap ( ) ;
49
51
let upper_changes = collect_paths ( & lower) ;
50
52
let _root_len = lower. clone ( ) ;
51
53
let mut map = HashMap :: < PathBuf , Tree > :: new ( ) ;
52
- let root_tree = db. get_bypath ( GPath :: from ( String :: from ( lower. to_str ( ) . unwrap ( ) ) ) ) . unwrap ( ) ;
54
+ let root_tree = db. get_bypath ( monopath. clone ( ) ) . unwrap ( ) ; // BUG: wrong path :"lower". the store in db is not real path .
55
+ // dont forget get tree below
53
56
map. insert ( lower. clone ( ) , root_tree) ;
54
57
let mut blobs=Vec :: < Blob > :: new ( ) ;
58
+
55
59
for node in upper_changes {
56
- let p = node. parent ( ) . unwrap ( ) . to_path_buf ( ) ;
57
- let t = map. get_mut ( & p) . unwrap ( ) ;
58
-
59
- let mut is_new_file = true ;
60
- // look up the older version to delete/change .
61
- let mut i =0 ;
62
- while i<t. tree_items . len ( ) {
63
- let item = & mut t. tree_items [ i] ;
64
- if item. name . eq ( node. file_name ( ) . unwrap ( ) . to_string_lossy ( ) . as_ref ( ) ) {
65
- is_new_file = false ;
66
- //delete .
67
- if is_whiteout_inode ( & node) {
68
- t. tree_items . remove ( i) ;
69
- } else {
70
- // changed
71
- // node is a changed ()blob.
72
- // just compute the NEW hash first.
73
- let content = std:: fs:: read ( & node) . unwrap ( ) ;
74
- item. id = SHA1 :: from_type_and_data ( ObjectType :: Blob , & content) ;
75
- blobs. push ( Blob { id : item. id , data : content } ) ;
60
+ if node. is_dir ( ) {
61
+ let new_path = monopath. clone ( ) . join ( node. strip_prefix ( & lower) . unwrap ( ) ) ;
62
+ let node_tree = db. get_bypath ( new_path) . unwrap ( ) ;
63
+ map. insert ( node. clone ( ) , node_tree) ;
64
+ //db.get_bypath(path);
65
+ //ap.insert(node.clone(), node_tree);
66
+ }
67
+ let p = node. parent ( ) . unwrap ( ) . to_path_buf ( ) ;
68
+ let t = map. get_mut ( & p) . unwrap ( ) ;
69
+
70
+ let mut is_new_file = true ;
71
+ // look up the parent tree node to delete/change .
72
+ let mut i =0 ;
73
+ while i<t. tree_items . len ( ) {
74
+ let item = & mut t. tree_items [ i] ;
75
+ if item. name . eq ( node. file_name ( ) . unwrap ( ) . to_string_lossy ( ) . as_ref ( ) ) {
76
+ is_new_file = false ;
77
+ //delete .
78
+ if is_whiteout_inode ( & node) {
79
+ t. tree_items . remove ( i) ;
80
+ }
81
+ else if node. is_dir ( ) {
82
+ //pass
83
+ }
84
+ else {
85
+ // changed
86
+ // node is a changed ()blob.
87
+ // just compute the NEW hash first.
88
+ let content = std:: fs:: read ( & node) . unwrap ( ) ;
89
+ item. id = SHA1 :: from_type_and_data ( ObjectType :: Blob , & content) ;
90
+ blobs. push ( Blob { id : item. id , data : content } ) ;
91
+ }
92
+ break ;
93
+ }
94
+ i+=1 ;
95
+ }
96
+ // if new file add item.
97
+ let new_name =node. file_name ( ) . unwrap ( ) . to_string_lossy ( ) . as_ref ( ) . to_owned ( ) ;
98
+ if is_new_file{
99
+ //is a fiel or a dictionary?
100
+ if node. is_dir ( ) {
101
+ // is dictionary.
102
+ t. tree_items . push ( TreeItem {
103
+ mode : TreeItemMode :: Tree ,
104
+ id : SHA1 :: default ( ) ,
105
+ name : new_name,
106
+ } ) ;
107
+ } else {
108
+ //is a file.
109
+ let content = std:: fs:: read ( & node) . unwrap ( ) ;
110
+ let hash = SHA1 :: from_type_and_data ( ObjectType :: Blob , & content) ;
111
+ blobs. push ( Blob { id : hash, data : content } ) ;
112
+ t. tree_items . push ( TreeItem {
113
+ mode : TreeItemMode :: Blob ,
114
+ id : hash,
115
+ name : new_name,
116
+ } ) ;
117
+ }
118
+
119
+ }
120
+ }
121
+ ( map, blobs)
122
+ }
123
+
124
+ pub fn change (
125
+ real_path : PathBuf ,
126
+ tree_path : PathBuf ,
127
+ trees : & mut Vec < Tree > ,
128
+ blobs : & mut Vec < Blob > ,
129
+ db : & sled:: Db ) -> Tree {
130
+ let mut tree;
131
+ let root_tree = db. get_bypath ( tree_path. clone ( ) ) ;
132
+ if let Ok ( root_tree) = root_tree{ // exit dictionry
133
+ println ! ( "exit tree:{:?}" , tree_path) ;
134
+ tree = root_tree;
135
+ } else { // there is a new dictionary.
136
+ println ! ( "new tree:{:?}" , tree_path) ;
137
+ tree = Tree { id : SHA1 :: default ( ) , tree_items : vec ! [ ] } ;
138
+ }
139
+
140
+ let entries = std:: fs:: read_dir ( real_path) . unwrap ( ) ;
141
+ for entry in entries {
142
+ let entry = entry. unwrap ( ) ;
143
+ let path = entry. path ( ) ;
144
+ let name = path. file_name ( ) . unwrap ( ) . to_string_lossy ( ) . into_owned ( ) . to_string ( ) ;
145
+ let mut new = true ;
146
+ let mut i =0 ;
147
+ while i<tree. tree_items . len ( ) {
148
+ let item: & mut TreeItem = tree. tree_items . get_mut ( i) . unwrap ( ) ;
149
+ if item. name . eq ( & name) {
150
+ if is_whiteout_inode ( & path) {
151
+ println ! ( "change: delete {}" , item. name) ;
152
+ // delete..
153
+ let _ = item; //drop
154
+ tree. tree_items . remove ( i) ;
155
+ }
156
+ else if path. is_dir ( ) {
157
+ let new_tree_path = tree_path. join ( path. file_name ( ) . unwrap ( ) ) ;
158
+ let new_tree = change ( path. clone ( ) , new_tree_path, trees, blobs, db) ;
159
+
160
+ // change the hash value & push tree .
161
+ item. id = new_tree. id ;
162
+ trees. push ( new_tree) ;
163
+ println ! ( "change: changed tree {}" , item. name) ;
164
+ } else {
165
+ println ! ( "change: changed file {}" , item. name) ;
166
+ let content = std:: fs:: read ( & path) . unwrap ( ) ;
167
+ let hash = SHA1 :: from_type_and_data ( ObjectType :: Blob , & content) ;
168
+ blobs. push ( Blob { id : hash, data : content } ) ;
169
+ item. id = hash; // change fiel hash .
76
170
}
171
+ new = false ;
77
172
break ;
78
173
}
79
174
i+=1 ;
80
175
}
81
- // if new file add item.
82
- let new_name =node. file_name ( ) . unwrap ( ) . to_string_lossy ( ) . as_ref ( ) . to_owned ( ) ;
83
- if is_new_file{
84
- //is a fiel or a dictionary?
85
- if node. is_dir ( ) {
86
- // is dictionary.
87
- t. tree_items . push ( TreeItem {
88
- mode : TreeItemMode :: Tree ,
89
- id : SHA1 :: default ( ) ,
90
- name : new_name,
176
+ if new{ // a new file or dictionary
177
+ if path. is_dir ( ) {
178
+ println ! ( "change: new tree {:?}" , name) ;
179
+ let new_tree_path = tree_path. join ( path. file_name ( ) . unwrap ( ) ) ;
180
+ let new_tree = change ( path. clone ( ) , new_tree_path, trees, blobs, db) ;
181
+
182
+ //add a new item for this tree. and push tree.
183
+ tree. tree_items . push ( TreeItem {
184
+ mode : TreeItemMode :: Tree ,
185
+ id : new_tree. id ,
186
+ name ,
91
187
} ) ;
92
- } else {
93
- //is a file.
94
- let content = std:: fs:: read ( & node) . unwrap ( ) ;
188
+ trees. push ( new_tree) ;
189
+ } else {
190
+ println ! ( "change: new file {}" , name) ;
191
+ let content = std:: fs:: read ( & path) . unwrap ( ) ;
95
192
let hash = SHA1 :: from_type_and_data ( ObjectType :: Blob , & content) ;
96
193
blobs. push ( Blob { id : hash, data : content } ) ;
97
- t . tree_items . push ( TreeItem {
98
- mode : TreeItemMode :: Blob ,
99
- id : hash,
100
- name : new_name ,
194
+ tree . tree_items . push ( TreeItem {
195
+ mode : TreeItemMode :: Blob ,
196
+ id : hash,
197
+ name ,
101
198
} ) ;
102
199
}
103
-
104
200
}
105
- }
106
- ( map, blobs)
201
+
202
+
203
+
204
+ }
205
+ tree. rehash ( ) ; //Re compute the hash value .
206
+ tree
207
+
107
208
}
209
+
108
210
#[ cfg( test) ]
109
211
mod tests {
110
- use fs:: File ;
212
+
213
+ use std:: fs:: File ;
111
214
112
215
use super :: * ;
113
216
217
+
114
218
#[ test]
115
219
fn test_collect_paths_nested_directories ( ) {
116
220
let temp_dir = "/home/luxian/code/mega/scorpio/src" ;
0 commit comments