##// END OF EJS Templates
hg-core: check data integrity in `Revlog`...
Antoine Cezar -
r46102:b0d6309f default
parent child Browse files
Show More
@@ -1,816 +1,895 b''
1 1 # This file is automatically @generated by Cargo.
2 2 # It is not intended for manual editing.
3 3 [[package]]
4 4 name = "adler"
5 5 version = "0.2.3"
6 6 source = "registry+https://github.com/rust-lang/crates.io-index"
7 7
8 8 [[package]]
9 9 name = "aho-corasick"
10 10 version = "0.7.13"
11 11 source = "registry+https://github.com/rust-lang/crates.io-index"
12 12 dependencies = [
13 13 "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
14 14 ]
15 15
16 16 [[package]]
17 17 name = "ansi_term"
18 18 version = "0.11.0"
19 19 source = "registry+https://github.com/rust-lang/crates.io-index"
20 20 dependencies = [
21 21 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
22 22 ]
23 23
24 24 [[package]]
25 25 name = "atty"
26 26 version = "0.2.14"
27 27 source = "registry+https://github.com/rust-lang/crates.io-index"
28 28 dependencies = [
29 29 "hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
30 30 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
31 31 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
32 32 ]
33 33
34 34 [[package]]
35 35 name = "autocfg"
36 36 version = "1.0.1"
37 37 source = "registry+https://github.com/rust-lang/crates.io-index"
38 38
39 39 [[package]]
40 40 name = "bitflags"
41 41 version = "1.2.1"
42 42 source = "registry+https://github.com/rust-lang/crates.io-index"
43 43
44 44 [[package]]
45 45 name = "byteorder"
46 46 version = "1.3.4"
47 47 source = "registry+https://github.com/rust-lang/crates.io-index"
48 48
49 49 [[package]]
50 50 name = "cc"
51 51 version = "1.0.60"
52 52 source = "registry+https://github.com/rust-lang/crates.io-index"
53 53 dependencies = [
54 54 "jobserver 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
55 55 ]
56 56
57 57 [[package]]
58 58 name = "cfg-if"
59 59 version = "0.1.10"
60 60 source = "registry+https://github.com/rust-lang/crates.io-index"
61 61
62 62 [[package]]
63 63 name = "clap"
64 64 version = "2.33.3"
65 65 source = "registry+https://github.com/rust-lang/crates.io-index"
66 66 dependencies = [
67 67 "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
68 68 "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
69 69 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
70 70 "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
71 71 "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
72 72 "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
73 73 "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
74 74 ]
75 75
76 76 [[package]]
77 77 name = "cpython"
78 78 version = "0.4.1"
79 79 source = "registry+https://github.com/rust-lang/crates.io-index"
80 80 dependencies = [
81 81 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
82 82 "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
83 83 "python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
84 84 "python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
85 85 ]
86 86
87 87 [[package]]
88 88 name = "crc32fast"
89 89 version = "1.2.0"
90 90 source = "registry+https://github.com/rust-lang/crates.io-index"
91 91 dependencies = [
92 92 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
93 93 ]
94 94
95 95 [[package]]
96 96 name = "crossbeam"
97 97 version = "0.7.3"
98 98 source = "registry+https://github.com/rust-lang/crates.io-index"
99 99 dependencies = [
100 100 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
101 101 "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
102 102 "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
103 103 "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
104 104 "crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
105 105 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
106 106 ]
107 107
108 108 [[package]]
109 109 name = "crossbeam-channel"
110 110 version = "0.4.4"
111 111 source = "registry+https://github.com/rust-lang/crates.io-index"
112 112 dependencies = [
113 113 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
114 114 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
115 115 ]
116 116
117 117 [[package]]
118 118 name = "crossbeam-deque"
119 119 version = "0.7.3"
120 120 source = "registry+https://github.com/rust-lang/crates.io-index"
121 121 dependencies = [
122 122 "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
123 123 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
124 124 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
125 125 ]
126 126
127 127 [[package]]
128 128 name = "crossbeam-epoch"
129 129 version = "0.8.2"
130 130 source = "registry+https://github.com/rust-lang/crates.io-index"
131 131 dependencies = [
132 132 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
133 133 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
134 134 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
135 135 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
136 136 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
137 137 "memoffset 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
138 138 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
139 139 ]
140 140
141 141 [[package]]
142 142 name = "crossbeam-queue"
143 143 version = "0.2.3"
144 144 source = "registry+https://github.com/rust-lang/crates.io-index"
145 145 dependencies = [
146 146 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
147 147 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
148 148 "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
149 149 ]
150 150
151 151 [[package]]
152 152 name = "crossbeam-utils"
153 153 version = "0.7.2"
154 154 source = "registry+https://github.com/rust-lang/crates.io-index"
155 155 dependencies = [
156 156 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
157 157 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
158 158 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
159 159 ]
160 160
161 161 [[package]]
162 162 name = "ctor"
163 163 version = "0.1.16"
164 164 source = "registry+https://github.com/rust-lang/crates.io-index"
165 165 dependencies = [
166 166 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
167 167 "syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
168 168 ]
169 169
170 170 [[package]]
171 171 name = "difference"
172 172 version = "2.0.0"
173 173 source = "registry+https://github.com/rust-lang/crates.io-index"
174 174
175 175 [[package]]
176 176 name = "either"
177 177 version = "1.6.1"
178 178 source = "registry+https://github.com/rust-lang/crates.io-index"
179 179
180 180 [[package]]
181 181 name = "env_logger"
182 182 version = "0.7.1"
183 183 source = "registry+https://github.com/rust-lang/crates.io-index"
184 184 dependencies = [
185 185 "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
186 186 "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
187 187 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
188 188 "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
189 189 "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
190 190 ]
191 191
192 192 [[package]]
193 193 name = "flate2"
194 194 version = "1.0.17"
195 195 source = "registry+https://github.com/rust-lang/crates.io-index"
196 196 dependencies = [
197 197 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
198 198 "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
199 199 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
200 200 "libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
201 201 "miniz_oxide 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
202 202 ]
203 203
204 204 [[package]]
205 name = "fuchsia-cprng"
206 version = "0.1.1"
207 source = "registry+https://github.com/rust-lang/crates.io-index"
208
209 [[package]]
210 name = "gcc"
211 version = "0.3.55"
212 source = "registry+https://github.com/rust-lang/crates.io-index"
213
214 [[package]]
205 215 name = "getrandom"
206 216 version = "0.1.15"
207 217 source = "registry+https://github.com/rust-lang/crates.io-index"
208 218 dependencies = [
209 219 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
210 220 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
211 221 "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
212 222 ]
213 223
214 224 [[package]]
215 225 name = "glob"
216 226 version = "0.3.0"
217 227 source = "registry+https://github.com/rust-lang/crates.io-index"
218 228
219 229 [[package]]
220 230 name = "hermit-abi"
221 231 version = "0.1.16"
222 232 source = "registry+https://github.com/rust-lang/crates.io-index"
223 233 dependencies = [
224 234 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
225 235 ]
226 236
227 237 [[package]]
228 238 name = "hex"
229 239 version = "0.4.2"
230 240 source = "registry+https://github.com/rust-lang/crates.io-index"
231 241
232 242 [[package]]
233 243 name = "hg-core"
234 244 version = "0.1.0"
235 245 dependencies = [
236 246 "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
237 247 "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
238 248 "crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
239 249 "flate2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)",
240 250 "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
241 251 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
242 252 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
243 253 "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
244 254 "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
245 255 "micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
246 256 "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
247 257 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
248 258 "rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
249 259 "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
250 260 "rayon 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
251 261 "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
262 "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
252 263 "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
253 264 "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
254 265 "twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
255 266 "zstd 0.5.3+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
256 267 ]
257 268
258 269 [[package]]
259 270 name = "hg-cpython"
260 271 version = "0.1.0"
261 272 dependencies = [
262 273 "cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
263 274 "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
264 275 "hg-core 0.1.0",
265 276 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
266 277 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
267 278 ]
268 279
269 280 [[package]]
270 281 name = "humantime"
271 282 version = "1.3.0"
272 283 source = "registry+https://github.com/rust-lang/crates.io-index"
273 284 dependencies = [
274 285 "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
275 286 ]
276 287
277 288 [[package]]
278 289 name = "itertools"
279 290 version = "0.9.0"
280 291 source = "registry+https://github.com/rust-lang/crates.io-index"
281 292 dependencies = [
282 293 "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
283 294 ]
284 295
285 296 [[package]]
286 297 name = "jobserver"
287 298 version = "0.1.21"
288 299 source = "registry+https://github.com/rust-lang/crates.io-index"
289 300 dependencies = [
290 301 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
291 302 ]
292 303
293 304 [[package]]
294 305 name = "lazy_static"
295 306 version = "1.4.0"
296 307 source = "registry+https://github.com/rust-lang/crates.io-index"
297 308
298 309 [[package]]
299 310 name = "libc"
300 311 version = "0.2.77"
301 312 source = "registry+https://github.com/rust-lang/crates.io-index"
302 313
303 314 [[package]]
304 315 name = "libz-sys"
305 316 version = "1.1.2"
306 317 source = "registry+https://github.com/rust-lang/crates.io-index"
307 318 dependencies = [
308 319 "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)",
309 320 "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
310 321 "vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
311 322 ]
312 323
313 324 [[package]]
314 325 name = "log"
315 326 version = "0.4.11"
316 327 source = "registry+https://github.com/rust-lang/crates.io-index"
317 328 dependencies = [
318 329 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
319 330 ]
320 331
321 332 [[package]]
322 333 name = "maybe-uninit"
323 334 version = "2.0.0"
324 335 source = "registry+https://github.com/rust-lang/crates.io-index"
325 336
326 337 [[package]]
327 338 name = "memchr"
328 339 version = "2.3.3"
329 340 source = "registry+https://github.com/rust-lang/crates.io-index"
330 341
331 342 [[package]]
332 343 name = "memmap"
333 344 version = "0.7.0"
334 345 source = "registry+https://github.com/rust-lang/crates.io-index"
335 346 dependencies = [
336 347 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
337 348 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
338 349 ]
339 350
340 351 [[package]]
341 352 name = "memoffset"
342 353 version = "0.5.6"
343 354 source = "registry+https://github.com/rust-lang/crates.io-index"
344 355 dependencies = [
345 356 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
346 357 ]
347 358
348 359 [[package]]
349 360 name = "micro-timer"
350 361 version = "0.3.1"
351 362 source = "registry+https://github.com/rust-lang/crates.io-index"
352 363 dependencies = [
353 364 "micro-timer-macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
354 365 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
355 366 ]
356 367
357 368 [[package]]
358 369 name = "micro-timer-macros"
359 370 version = "0.3.1"
360 371 source = "registry+https://github.com/rust-lang/crates.io-index"
361 372 dependencies = [
362 373 "proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
363 374 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
364 375 "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
365 376 "syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
366 377 ]
367 378
368 379 [[package]]
369 380 name = "miniz_oxide"
370 381 version = "0.4.2"
371 382 source = "registry+https://github.com/rust-lang/crates.io-index"
372 383 dependencies = [
373 384 "adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
374 385 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
375 386 ]
376 387
377 388 [[package]]
378 389 name = "num-traits"
379 390 version = "0.2.12"
380 391 source = "registry+https://github.com/rust-lang/crates.io-index"
381 392 dependencies = [
382 393 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
383 394 ]
384 395
385 396 [[package]]
386 397 name = "num_cpus"
387 398 version = "1.13.0"
388 399 source = "registry+https://github.com/rust-lang/crates.io-index"
389 400 dependencies = [
390 401 "hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
391 402 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
392 403 ]
393 404
394 405 [[package]]
395 406 name = "output_vt100"
396 407 version = "0.1.2"
397 408 source = "registry+https://github.com/rust-lang/crates.io-index"
398 409 dependencies = [
399 410 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
400 411 ]
401 412
402 413 [[package]]
403 414 name = "pkg-config"
404 415 version = "0.3.18"
405 416 source = "registry+https://github.com/rust-lang/crates.io-index"
406 417
407 418 [[package]]
408 419 name = "ppv-lite86"
409 420 version = "0.2.9"
410 421 source = "registry+https://github.com/rust-lang/crates.io-index"
411 422
412 423 [[package]]
413 424 name = "pretty_assertions"
414 425 version = "0.6.1"
415 426 source = "registry+https://github.com/rust-lang/crates.io-index"
416 427 dependencies = [
417 428 "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
418 429 "ctor 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
419 430 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
420 431 "output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
421 432 ]
422 433
423 434 [[package]]
424 435 name = "proc-macro2"
425 436 version = "1.0.21"
426 437 source = "registry+https://github.com/rust-lang/crates.io-index"
427 438 dependencies = [
428 439 "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
429 440 ]
430 441
431 442 [[package]]
432 443 name = "python27-sys"
433 444 version = "0.4.1"
434 445 source = "registry+https://github.com/rust-lang/crates.io-index"
435 446 dependencies = [
436 447 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
437 448 "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
438 449 ]
439 450
440 451 [[package]]
441 452 name = "python3-sys"
442 453 version = "0.4.1"
443 454 source = "registry+https://github.com/rust-lang/crates.io-index"
444 455 dependencies = [
445 456 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
446 457 "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
447 458 ]
448 459
449 460 [[package]]
450 461 name = "quick-error"
451 462 version = "1.2.3"
452 463 source = "registry+https://github.com/rust-lang/crates.io-index"
453 464
454 465 [[package]]
455 466 name = "quote"
456 467 version = "1.0.7"
457 468 source = "registry+https://github.com/rust-lang/crates.io-index"
458 469 dependencies = [
459 470 "proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
460 471 ]
461 472
462 473 [[package]]
463 474 name = "rand"
475 version = "0.3.23"
476 source = "registry+https://github.com/rust-lang/crates.io-index"
477 dependencies = [
478 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
479 "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
480 ]
481
482 [[package]]
483 name = "rand"
484 version = "0.4.6"
485 source = "registry+https://github.com/rust-lang/crates.io-index"
486 dependencies = [
487 "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
488 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
489 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
490 "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
491 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
492 ]
493
494 [[package]]
495 name = "rand"
464 496 version = "0.7.3"
465 497 source = "registry+https://github.com/rust-lang/crates.io-index"
466 498 dependencies = [
467 499 "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
468 500 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
469 501 "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
470 502 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
471 503 "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
472 504 ]
473 505
474 506 [[package]]
475 507 name = "rand_chacha"
476 508 version = "0.2.2"
477 509 source = "registry+https://github.com/rust-lang/crates.io-index"
478 510 dependencies = [
479 511 "ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
480 512 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
481 513 ]
482 514
483 515 [[package]]
484 516 name = "rand_core"
517 version = "0.3.1"
518 source = "registry+https://github.com/rust-lang/crates.io-index"
519 dependencies = [
520 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
521 ]
522
523 [[package]]
524 name = "rand_core"
525 version = "0.4.2"
526 source = "registry+https://github.com/rust-lang/crates.io-index"
527
528 [[package]]
529 name = "rand_core"
485 530 version = "0.5.1"
486 531 source = "registry+https://github.com/rust-lang/crates.io-index"
487 532 dependencies = [
488 533 "getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
489 534 ]
490 535
491 536 [[package]]
492 537 name = "rand_distr"
493 538 version = "0.2.2"
494 539 source = "registry+https://github.com/rust-lang/crates.io-index"
495 540 dependencies = [
496 541 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
497 542 ]
498 543
499 544 [[package]]
500 545 name = "rand_hc"
501 546 version = "0.2.0"
502 547 source = "registry+https://github.com/rust-lang/crates.io-index"
503 548 dependencies = [
504 549 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
505 550 ]
506 551
507 552 [[package]]
508 553 name = "rand_pcg"
509 554 version = "0.2.1"
510 555 source = "registry+https://github.com/rust-lang/crates.io-index"
511 556 dependencies = [
512 557 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
513 558 ]
514 559
515 560 [[package]]
516 561 name = "rayon"
517 562 version = "1.4.0"
518 563 source = "registry+https://github.com/rust-lang/crates.io-index"
519 564 dependencies = [
520 565 "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
521 566 "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
522 567 "either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
523 568 "rayon-core 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
524 569 ]
525 570
526 571 [[package]]
527 572 name = "rayon-core"
528 573 version = "1.8.1"
529 574 source = "registry+https://github.com/rust-lang/crates.io-index"
530 575 dependencies = [
531 576 "crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
532 577 "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
533 578 "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
534 579 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
535 580 "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
536 581 ]
537 582
538 583 [[package]]
584 name = "rdrand"
585 version = "0.4.0"
586 source = "registry+https://github.com/rust-lang/crates.io-index"
587 dependencies = [
588 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
589 ]
590
591 [[package]]
539 592 name = "redox_syscall"
540 593 version = "0.1.57"
541 594 source = "registry+https://github.com/rust-lang/crates.io-index"
542 595
543 596 [[package]]
544 597 name = "regex"
545 598 version = "1.3.9"
546 599 source = "registry+https://github.com/rust-lang/crates.io-index"
547 600 dependencies = [
548 601 "aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)",
549 602 "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
550 603 "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
551 604 "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
552 605 ]
553 606
554 607 [[package]]
555 608 name = "regex-syntax"
556 609 version = "0.6.18"
557 610 source = "registry+https://github.com/rust-lang/crates.io-index"
558 611
559 612 [[package]]
560 613 name = "remove_dir_all"
561 614 version = "0.5.3"
562 615 source = "registry+https://github.com/rust-lang/crates.io-index"
563 616 dependencies = [
564 617 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
565 618 ]
566 619
567 620 [[package]]
568 621 name = "rhg"
569 622 version = "0.1.0"
570 623 dependencies = [
571 624 "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
572 625 "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
573 626 "hg-core 0.1.0",
574 627 "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
575 628 "micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
576 629 ]
577 630
578 631 [[package]]
632 name = "rust-crypto"
633 version = "0.2.36"
634 source = "registry+https://github.com/rust-lang/crates.io-index"
635 dependencies = [
636 "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)",
637 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
638 "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
639 "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
640 "time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)",
641 ]
642
643 [[package]]
644 name = "rustc-serialize"
645 version = "0.3.24"
646 source = "registry+https://github.com/rust-lang/crates.io-index"
647
648 [[package]]
579 649 name = "same-file"
580 650 version = "1.0.6"
581 651 source = "registry+https://github.com/rust-lang/crates.io-index"
582 652 dependencies = [
583 653 "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
584 654 ]
585 655
586 656 [[package]]
587 657 name = "scopeguard"
588 658 version = "1.1.0"
589 659 source = "registry+https://github.com/rust-lang/crates.io-index"
590 660
591 661 [[package]]
592 662 name = "strsim"
593 663 version = "0.8.0"
594 664 source = "registry+https://github.com/rust-lang/crates.io-index"
595 665
596 666 [[package]]
597 667 name = "syn"
598 668 version = "1.0.41"
599 669 source = "registry+https://github.com/rust-lang/crates.io-index"
600 670 dependencies = [
601 671 "proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)",
602 672 "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
603 673 "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
604 674 ]
605 675
606 676 [[package]]
607 677 name = "tempfile"
608 678 version = "3.1.0"
609 679 source = "registry+https://github.com/rust-lang/crates.io-index"
610 680 dependencies = [
611 681 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
612 682 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
613 683 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
614 684 "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)",
615 685 "remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
616 686 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
617 687 ]
618 688
619 689 [[package]]
620 690 name = "termcolor"
621 691 version = "1.1.0"
622 692 source = "registry+https://github.com/rust-lang/crates.io-index"
623 693 dependencies = [
624 694 "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
625 695 ]
626 696
627 697 [[package]]
628 698 name = "textwrap"
629 699 version = "0.11.0"
630 700 source = "registry+https://github.com/rust-lang/crates.io-index"
631 701 dependencies = [
632 702 "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
633 703 ]
634 704
635 705 [[package]]
636 706 name = "thread_local"
637 707 version = "1.0.1"
638 708 source = "registry+https://github.com/rust-lang/crates.io-index"
639 709 dependencies = [
640 710 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
641 711 ]
642 712
643 713 [[package]]
644 714 name = "twox-hash"
645 715 version = "1.5.0"
646 716 source = "registry+https://github.com/rust-lang/crates.io-index"
647 717 dependencies = [
648 718 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
649 719 ]
650 720
651 721 [[package]]
652 722 name = "unicode-width"
653 723 version = "0.1.8"
654 724 source = "registry+https://github.com/rust-lang/crates.io-index"
655 725
656 726 [[package]]
657 727 name = "unicode-xid"
658 728 version = "0.2.1"
659 729 source = "registry+https://github.com/rust-lang/crates.io-index"
660 730
661 731 [[package]]
662 732 name = "vcpkg"
663 733 version = "0.2.10"
664 734 source = "registry+https://github.com/rust-lang/crates.io-index"
665 735
666 736 [[package]]
667 737 name = "vec_map"
668 738 version = "0.8.2"
669 739 source = "registry+https://github.com/rust-lang/crates.io-index"
670 740
671 741 [[package]]
672 742 name = "wasi"
673 743 version = "0.9.0+wasi-snapshot-preview1"
674 744 source = "registry+https://github.com/rust-lang/crates.io-index"
675 745
676 746 [[package]]
677 747 name = "winapi"
678 748 version = "0.3.9"
679 749 source = "registry+https://github.com/rust-lang/crates.io-index"
680 750 dependencies = [
681 751 "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
682 752 "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
683 753 ]
684 754
685 755 [[package]]
686 756 name = "winapi-i686-pc-windows-gnu"
687 757 version = "0.4.0"
688 758 source = "registry+https://github.com/rust-lang/crates.io-index"
689 759
690 760 [[package]]
691 761 name = "winapi-util"
692 762 version = "0.1.5"
693 763 source = "registry+https://github.com/rust-lang/crates.io-index"
694 764 dependencies = [
695 765 "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
696 766 ]
697 767
698 768 [[package]]
699 769 name = "winapi-x86_64-pc-windows-gnu"
700 770 version = "0.4.0"
701 771 source = "registry+https://github.com/rust-lang/crates.io-index"
702 772
703 773 [[package]]
704 774 name = "zstd"
705 775 version = "0.5.3+zstd.1.4.5"
706 776 source = "registry+https://github.com/rust-lang/crates.io-index"
707 777 dependencies = [
708 778 "zstd-safe 2.0.5+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
709 779 ]
710 780
711 781 [[package]]
712 782 name = "zstd-safe"
713 783 version = "2.0.5+zstd.1.4.5"
714 784 source = "registry+https://github.com/rust-lang/crates.io-index"
715 785 dependencies = [
716 786 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
717 787 "zstd-sys 1.4.17+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
718 788 ]
719 789
720 790 [[package]]
721 791 name = "zstd-sys"
722 792 version = "1.4.17+zstd.1.4.5"
723 793 source = "registry+https://github.com/rust-lang/crates.io-index"
724 794 dependencies = [
725 795 "cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)",
726 796 "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
727 797 "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
728 798 "libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)",
729 799 ]
730 800
731 801 [metadata]
732 802 "checksum adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
733 803 "checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
734 804 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
735 805 "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
736 806 "checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
737 807 "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
738 808 "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
739 809 "checksum cc 1.0.60 (registry+https://github.com/rust-lang/crates.io-index)" = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c"
740 810 "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
741 811 "checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
742 812 "checksum cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaf3847ab963e40c4f6dd8d6be279bdf74007ae2413786a0dcbb28c52139a95"
743 813 "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
744 814 "checksum crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e"
745 815 "checksum crossbeam-channel 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
746 816 "checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285"
747 817 "checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
748 818 "checksum crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
749 819 "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
750 820 "checksum ctor 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484"
751 821 "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
752 822 "checksum either 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
753 823 "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
754 824 "checksum flate2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "766d0e77a2c1502169d4a93ff3b8c15a71fd946cd0126309752104e5f3c46d94"
825 "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
826 "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
755 827 "checksum getrandom 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
756 828 "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
757 829 "checksum hermit-abi 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c30f6d0bc6b00693347368a67d41b58f2fb851215ff1da49e90fe2c5c667151"
758 830 "checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
759 831 "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
760 832 "checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
761 833 "checksum jobserver 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2"
762 834 "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
763 835 "checksum libc 0.2.77 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
764 836 "checksum libz-sys 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655"
765 837 "checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
766 838 "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
767 839 "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
768 840 "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
769 841 "checksum memoffset 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"
770 842 "checksum micro-timer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2620153e1d903d26b72b89f0e9c48d8c4756cba941c185461dddc234980c298c"
771 843 "checksum micro-timer-macros 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e28a3473e6abd6e9aab36aaeef32ad22ae0bd34e79f376643594c2b152ec1c5d"
772 844 "checksum miniz_oxide 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c60c0dfe32c10b43a144bad8fc83538c52f58302c92300ea7ec7bf7b38d5a7b9"
773 845 "checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
774 846 "checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
775 847 "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
776 848 "checksum pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33"
777 849 "checksum ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20"
778 850 "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
779 851 "checksum proc-macro2 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c"
780 852 "checksum python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67cb041de8615111bf224dd75667af5f25c6e032118251426fed7f1b70ce4c8c"
781 853 "checksum python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90af11779515a1e530af60782d273b59ac79d33b0e253c071a728563957c76d4"
782 854 "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
783 855 "checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
856 "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
857 "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
784 858 "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
785 859 "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
860 "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
861 "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
786 862 "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
787 863 "checksum rand_distr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2"
788 864 "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
789 865 "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
790 866 "checksum rayon 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270"
791 867 "checksum rayon-core 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e8c4fec834fb6e6d2dd5eece3c7b432a52f0ba887cf40e595190c4107edc08bf"
868 "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
792 869 "checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
793 870 "checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
794 871 "checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
795 872 "checksum remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
873 "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
874 "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
796 875 "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
797 876 "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
798 877 "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
799 878 "checksum syn 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b"
800 879 "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
801 880 "checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f"
802 881 "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
803 882 "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
804 883 "checksum twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56"
805 884 "checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
806 885 "checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
807 886 "checksum vcpkg 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c"
808 887 "checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
809 888 "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
810 889 "checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
811 890 "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
812 891 "checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
813 892 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
814 893 "checksum zstd 0.5.3+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01b32eaf771efa709e8308605bbf9319bf485dc1503179ec0469b611937c0cd8"
815 894 "checksum zstd-safe 2.0.5+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cfb642e0d27f64729a639c52db457e0ae906e7bc6f5fe8f5c453230400f1055"
816 895 "checksum zstd-sys 1.4.17+zstd.1.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b89249644df056b522696b1bb9e7c18c87e8ffa3e2f0dc3b0155875d6498f01b"
@@ -1,41 +1,42 b''
1 1 [package]
2 2 name = "hg-core"
3 3 version = "0.1.0"
4 4 authors = ["Georges Racinet <gracinet@anybox.fr>"]
5 5 description = "Mercurial pure Rust core library, with no assumption on Python bindings (FFI)"
6 6 edition = "2018"
7 7
8 8 [lib]
9 9 name = "hg"
10 10
11 11 [dependencies]
12 12 byteorder = "1.3.4"
13 13 hex = "0.4.2"
14 14 lazy_static = "1.4.0"
15 15 memchr = "2.3.3"
16 16 rand = "0.7.3"
17 17 rand_pcg = "0.2.1"
18 18 rand_distr = "0.2.2"
19 19 rayon = "1.3.0"
20 20 regex = "1.3.9"
21 21 twox-hash = "1.5.0"
22 22 same-file = "1.0.6"
23 23 crossbeam = "0.7.3"
24 24 micro-timer = "0.3.0"
25 25 log = "0.4.8"
26 26 memmap = "0.7.0"
27 27 zstd = "0.5.3"
28 rust-crypto = "0.2.36"
28 29
29 30 # We don't use the `miniz-oxide` backend because its minimum Rust version is
30 31 # `1.36`. However, this PR (https://github.com/Frommi/miniz_oxide/pull/84/files)
31 32 # introduces a flag `no_extern_crate_alloc` to bring the requirement back down
32 33 # to `1.34`.
33 34 [dependencies.flate2]
34 35 version = "1.0.16"
35 36 features = ["zlib"]
36 37 default-features = false
37 38
38 39 [dev-dependencies]
39 40 clap = "*"
40 41 pretty_assertions = "0.6.1"
41 42 tempfile = "3.1.0"
@@ -1,503 +1,503 b''
1 1 // dirstate_map.rs
2 2 //
3 3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 4 //
5 5 // This software may be used and distributed according to the terms of the
6 6 // GNU General Public License version 2 or any later version.
7 7
8 use crate::revlog::node::NULL_NODE_ID;
8 9 use crate::{
9 10 dirstate::{parsers::PARENT_SIZE, EntryState, SIZE_FROM_OTHER_PARENT},
10 11 pack_dirstate, parse_dirstate,
11 12 utils::{
12 13 files::normalize_case,
13 14 hg_path::{HgPath, HgPathBuf},
14 15 },
15 16 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError,
16 17 DirstateParents, DirstateParseError, FastHashMap, StateMap,
17 18 };
18 19 use core::borrow::Borrow;
19 20 use std::collections::HashSet;
20 21 use std::convert::TryInto;
21 22 use std::iter::FromIterator;
22 23 use std::ops::Deref;
23 24 use std::time::Duration;
24 25
25 26 pub type FileFoldMap = FastHashMap<HgPathBuf, HgPathBuf>;
26 27
27 const NULL_ID: [u8; 20] = [0; 20];
28 28 const MTIME_UNSET: i32 = -1;
29 29
30 30 #[derive(Default)]
31 31 pub struct DirstateMap {
32 32 state_map: StateMap,
33 33 pub copy_map: CopyMap,
34 34 file_fold_map: Option<FileFoldMap>,
35 35 pub dirs: Option<DirsMultiset>,
36 36 pub all_dirs: Option<DirsMultiset>,
37 37 non_normal_set: Option<HashSet<HgPathBuf>>,
38 38 other_parent_set: Option<HashSet<HgPathBuf>>,
39 39 parents: Option<DirstateParents>,
40 40 dirty_parents: bool,
41 41 }
42 42
43 43 /// Should only really be used in python interface code, for clarity
44 44 impl Deref for DirstateMap {
45 45 type Target = StateMap;
46 46
47 47 fn deref(&self) -> &Self::Target {
48 48 &self.state_map
49 49 }
50 50 }
51 51
52 52 impl FromIterator<(HgPathBuf, DirstateEntry)> for DirstateMap {
53 53 fn from_iter<I: IntoIterator<Item = (HgPathBuf, DirstateEntry)>>(
54 54 iter: I,
55 55 ) -> Self {
56 56 Self {
57 57 state_map: iter.into_iter().collect(),
58 58 ..Self::default()
59 59 }
60 60 }
61 61 }
62 62
63 63 impl DirstateMap {
64 64 pub fn new() -> Self {
65 65 Self::default()
66 66 }
67 67
68 68 pub fn clear(&mut self) {
69 69 self.state_map.clear();
70 70 self.copy_map.clear();
71 71 self.file_fold_map = None;
72 72 self.non_normal_set = None;
73 73 self.other_parent_set = None;
74 74 self.set_parents(&DirstateParents {
75 p1: NULL_ID,
76 p2: NULL_ID,
75 p1: NULL_NODE_ID,
76 p2: NULL_NODE_ID,
77 77 })
78 78 }
79 79
80 80 /// Add a tracked file to the dirstate
81 81 pub fn add_file(
82 82 &mut self,
83 83 filename: &HgPath,
84 84 old_state: EntryState,
85 85 entry: DirstateEntry,
86 86 ) -> Result<(), DirstateMapError> {
87 87 if old_state == EntryState::Unknown || old_state == EntryState::Removed
88 88 {
89 89 if let Some(ref mut dirs) = self.dirs {
90 90 dirs.add_path(filename)?;
91 91 }
92 92 }
93 93 if old_state == EntryState::Unknown {
94 94 if let Some(ref mut all_dirs) = self.all_dirs {
95 95 all_dirs.add_path(filename)?;
96 96 }
97 97 }
98 98 self.state_map.insert(filename.to_owned(), entry.to_owned());
99 99
100 100 if entry.state != EntryState::Normal || entry.mtime == MTIME_UNSET {
101 101 self.get_non_normal_other_parent_entries()
102 102 .0
103 103 .insert(filename.to_owned());
104 104 }
105 105
106 106 if entry.size == SIZE_FROM_OTHER_PARENT {
107 107 self.get_non_normal_other_parent_entries()
108 108 .1
109 109 .insert(filename.to_owned());
110 110 }
111 111 Ok(())
112 112 }
113 113
114 114 /// Mark a file as removed in the dirstate.
115 115 ///
116 116 /// The `size` parameter is used to store sentinel values that indicate
117 117 /// the file's previous state. In the future, we should refactor this
118 118 /// to be more explicit about what that state is.
119 119 pub fn remove_file(
120 120 &mut self,
121 121 filename: &HgPath,
122 122 old_state: EntryState,
123 123 size: i32,
124 124 ) -> Result<(), DirstateMapError> {
125 125 if old_state != EntryState::Unknown && old_state != EntryState::Removed
126 126 {
127 127 if let Some(ref mut dirs) = self.dirs {
128 128 dirs.delete_path(filename)?;
129 129 }
130 130 }
131 131 if old_state == EntryState::Unknown {
132 132 if let Some(ref mut all_dirs) = self.all_dirs {
133 133 all_dirs.add_path(filename)?;
134 134 }
135 135 }
136 136
137 137 if let Some(ref mut file_fold_map) = self.file_fold_map {
138 138 file_fold_map.remove(&normalize_case(filename));
139 139 }
140 140 self.state_map.insert(
141 141 filename.to_owned(),
142 142 DirstateEntry {
143 143 state: EntryState::Removed,
144 144 mode: 0,
145 145 size,
146 146 mtime: 0,
147 147 },
148 148 );
149 149 self.get_non_normal_other_parent_entries()
150 150 .0
151 151 .insert(filename.to_owned());
152 152 Ok(())
153 153 }
154 154
155 155 /// Remove a file from the dirstate.
156 156 /// Returns `true` if the file was previously recorded.
157 157 pub fn drop_file(
158 158 &mut self,
159 159 filename: &HgPath,
160 160 old_state: EntryState,
161 161 ) -> Result<bool, DirstateMapError> {
162 162 let exists = self.state_map.remove(filename).is_some();
163 163
164 164 if exists {
165 165 if old_state != EntryState::Removed {
166 166 if let Some(ref mut dirs) = self.dirs {
167 167 dirs.delete_path(filename)?;
168 168 }
169 169 }
170 170 if let Some(ref mut all_dirs) = self.all_dirs {
171 171 all_dirs.delete_path(filename)?;
172 172 }
173 173 }
174 174 if let Some(ref mut file_fold_map) = self.file_fold_map {
175 175 file_fold_map.remove(&normalize_case(filename));
176 176 }
177 177 self.get_non_normal_other_parent_entries()
178 178 .0
179 179 .remove(filename);
180 180
181 181 Ok(exists)
182 182 }
183 183
184 184 pub fn clear_ambiguous_times(
185 185 &mut self,
186 186 filenames: Vec<HgPathBuf>,
187 187 now: i32,
188 188 ) {
189 189 for filename in filenames {
190 190 let mut changed = false;
191 191 self.state_map
192 192 .entry(filename.to_owned())
193 193 .and_modify(|entry| {
194 194 if entry.state == EntryState::Normal && entry.mtime == now
195 195 {
196 196 changed = true;
197 197 *entry = DirstateEntry {
198 198 mtime: MTIME_UNSET,
199 199 ..*entry
200 200 };
201 201 }
202 202 });
203 203 if changed {
204 204 self.get_non_normal_other_parent_entries()
205 205 .0
206 206 .insert(filename.to_owned());
207 207 }
208 208 }
209 209 }
210 210
211 211 pub fn non_normal_entries_remove(
212 212 &mut self,
213 213 key: impl AsRef<HgPath>,
214 214 ) -> bool {
215 215 self.get_non_normal_other_parent_entries()
216 216 .0
217 217 .remove(key.as_ref())
218 218 }
219 219 pub fn non_normal_entries_union(
220 220 &mut self,
221 221 other: HashSet<HgPathBuf>,
222 222 ) -> Vec<HgPathBuf> {
223 223 self.get_non_normal_other_parent_entries()
224 224 .0
225 225 .union(&other)
226 226 .map(ToOwned::to_owned)
227 227 .collect()
228 228 }
229 229
230 230 pub fn get_non_normal_other_parent_entries(
231 231 &mut self,
232 232 ) -> (&mut HashSet<HgPathBuf>, &mut HashSet<HgPathBuf>) {
233 233 self.set_non_normal_other_parent_entries(false);
234 234 (
235 235 self.non_normal_set.as_mut().unwrap(),
236 236 self.other_parent_set.as_mut().unwrap(),
237 237 )
238 238 }
239 239
240 240 /// Useful to get immutable references to those sets in contexts where
241 241 /// you only have an immutable reference to the `DirstateMap`, like when
242 242 /// sharing references with Python.
243 243 ///
244 244 /// TODO, get rid of this along with the other "setter/getter" stuff when
245 245 /// a nice typestate plan is defined.
246 246 ///
247 247 /// # Panics
248 248 ///
249 249 /// Will panic if either set is `None`.
250 250 pub fn get_non_normal_other_parent_entries_panic(
251 251 &self,
252 252 ) -> (&HashSet<HgPathBuf>, &HashSet<HgPathBuf>) {
253 253 (
254 254 self.non_normal_set.as_ref().unwrap(),
255 255 self.other_parent_set.as_ref().unwrap(),
256 256 )
257 257 }
258 258
259 259 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
260 260 if !force
261 261 && self.non_normal_set.is_some()
262 262 && self.other_parent_set.is_some()
263 263 {
264 264 return;
265 265 }
266 266 let mut non_normal = HashSet::new();
267 267 let mut other_parent = HashSet::new();
268 268
269 269 for (
270 270 filename,
271 271 DirstateEntry {
272 272 state, size, mtime, ..
273 273 },
274 274 ) in self.state_map.iter()
275 275 {
276 276 if *state != EntryState::Normal || *mtime == MTIME_UNSET {
277 277 non_normal.insert(filename.to_owned());
278 278 }
279 279 if *state == EntryState::Normal && *size == SIZE_FROM_OTHER_PARENT
280 280 {
281 281 other_parent.insert(filename.to_owned());
282 282 }
283 283 }
284 284 self.non_normal_set = Some(non_normal);
285 285 self.other_parent_set = Some(other_parent);
286 286 }
287 287
288 288 /// Both of these setters and their uses appear to be the simplest way to
289 289 /// emulate a Python lazy property, but it is ugly and unidiomatic.
290 290 /// TODO One day, rewriting this struct using the typestate might be a
291 291 /// good idea.
292 292 pub fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
293 293 if self.all_dirs.is_none() {
294 294 self.all_dirs =
295 295 Some(DirsMultiset::from_dirstate(&self.state_map, None)?);
296 296 }
297 297 Ok(())
298 298 }
299 299
300 300 pub fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
301 301 if self.dirs.is_none() {
302 302 self.dirs = Some(DirsMultiset::from_dirstate(
303 303 &self.state_map,
304 304 Some(EntryState::Removed),
305 305 )?);
306 306 }
307 307 Ok(())
308 308 }
309 309
310 310 pub fn has_tracked_dir(
311 311 &mut self,
312 312 directory: &HgPath,
313 313 ) -> Result<bool, DirstateMapError> {
314 314 self.set_dirs()?;
315 315 Ok(self.dirs.as_ref().unwrap().contains(directory))
316 316 }
317 317
318 318 pub fn has_dir(
319 319 &mut self,
320 320 directory: &HgPath,
321 321 ) -> Result<bool, DirstateMapError> {
322 322 self.set_all_dirs()?;
323 323 Ok(self.all_dirs.as_ref().unwrap().contains(directory))
324 324 }
325 325
326 326 pub fn parents(
327 327 &mut self,
328 328 file_contents: &[u8],
329 329 ) -> Result<&DirstateParents, DirstateError> {
330 330 if let Some(ref parents) = self.parents {
331 331 return Ok(parents);
332 332 }
333 333 let parents;
334 334 if file_contents.len() == PARENT_SIZE * 2 {
335 335 parents = DirstateParents {
336 336 p1: file_contents[..PARENT_SIZE].try_into().unwrap(),
337 337 p2: file_contents[PARENT_SIZE..PARENT_SIZE * 2]
338 338 .try_into()
339 339 .unwrap(),
340 340 };
341 341 } else if file_contents.is_empty() {
342 342 parents = DirstateParents {
343 p1: NULL_ID,
344 p2: NULL_ID,
343 p1: NULL_NODE_ID,
344 p2: NULL_NODE_ID,
345 345 };
346 346 } else {
347 347 return Err(DirstateError::Parse(DirstateParseError::Damaged));
348 348 }
349 349
350 350 self.parents = Some(parents);
351 351 Ok(self.parents.as_ref().unwrap())
352 352 }
353 353
354 354 pub fn set_parents(&mut self, parents: &DirstateParents) {
355 355 self.parents = Some(parents.clone());
356 356 self.dirty_parents = true;
357 357 }
358 358
359 359 pub fn read(
360 360 &mut self,
361 361 file_contents: &[u8],
362 362 ) -> Result<Option<DirstateParents>, DirstateError> {
363 363 if file_contents.is_empty() {
364 364 return Ok(None);
365 365 }
366 366
367 367 let (parents, entries, copies) = parse_dirstate(file_contents)?;
368 368 self.state_map.extend(
369 369 entries
370 370 .into_iter()
371 371 .map(|(path, entry)| (path.to_owned(), entry)),
372 372 );
373 373 self.copy_map.extend(
374 374 copies
375 375 .into_iter()
376 376 .map(|(path, copy)| (path.to_owned(), copy.to_owned())),
377 377 );
378 378
379 379 if !self.dirty_parents {
380 380 self.set_parents(&parents);
381 381 }
382 382
383 383 Ok(Some(parents))
384 384 }
385 385
386 386 pub fn pack(
387 387 &mut self,
388 388 parents: DirstateParents,
389 389 now: Duration,
390 390 ) -> Result<Vec<u8>, DirstateError> {
391 391 let packed =
392 392 pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
393 393
394 394 self.dirty_parents = false;
395 395
396 396 self.set_non_normal_other_parent_entries(true);
397 397 Ok(packed)
398 398 }
399 399
400 400 pub fn build_file_fold_map(&mut self) -> &FileFoldMap {
401 401 if let Some(ref file_fold_map) = self.file_fold_map {
402 402 return file_fold_map;
403 403 }
404 404 let mut new_file_fold_map = FileFoldMap::default();
405 405 for (filename, DirstateEntry { state, .. }) in self.state_map.borrow()
406 406 {
407 407 if *state == EntryState::Removed {
408 408 new_file_fold_map
409 409 .insert(normalize_case(filename), filename.to_owned());
410 410 }
411 411 }
412 412 self.file_fold_map = Some(new_file_fold_map);
413 413 self.file_fold_map.as_ref().unwrap()
414 414 }
415 415 }
416 416
417 417 #[cfg(test)]
418 418 mod tests {
419 419 use super::*;
420 420
421 421 #[test]
422 422 fn test_dirs_multiset() {
423 423 let mut map = DirstateMap::new();
424 424 assert!(map.dirs.is_none());
425 425 assert!(map.all_dirs.is_none());
426 426
427 427 assert_eq!(map.has_dir(HgPath::new(b"nope")).unwrap(), false);
428 428 assert!(map.all_dirs.is_some());
429 429 assert!(map.dirs.is_none());
430 430
431 431 assert_eq!(map.has_tracked_dir(HgPath::new(b"nope")).unwrap(), false);
432 432 assert!(map.dirs.is_some());
433 433 }
434 434
435 435 #[test]
436 436 fn test_add_file() {
437 437 let mut map = DirstateMap::new();
438 438
439 439 assert_eq!(0, map.len());
440 440
441 441 map.add_file(
442 442 HgPath::new(b"meh"),
443 443 EntryState::Normal,
444 444 DirstateEntry {
445 445 state: EntryState::Normal,
446 446 mode: 1337,
447 447 mtime: 1337,
448 448 size: 1337,
449 449 },
450 450 )
451 451 .unwrap();
452 452
453 453 assert_eq!(1, map.len());
454 454 assert_eq!(0, map.get_non_normal_other_parent_entries().0.len());
455 455 assert_eq!(0, map.get_non_normal_other_parent_entries().1.len());
456 456 }
457 457
458 458 #[test]
459 459 fn test_non_normal_other_parent_entries() {
460 460 let mut map: DirstateMap = [
461 461 (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
462 462 (b"f2", (EntryState::Normal, 1337, 1337, -1)),
463 463 (b"f3", (EntryState::Normal, 1337, 1337, 1337)),
464 464 (b"f4", (EntryState::Normal, 1337, -2, 1337)),
465 465 (b"f5", (EntryState::Added, 1337, 1337, 1337)),
466 466 (b"f6", (EntryState::Added, 1337, 1337, -1)),
467 467 (b"f7", (EntryState::Merged, 1337, 1337, -1)),
468 468 (b"f8", (EntryState::Merged, 1337, 1337, 1337)),
469 469 (b"f9", (EntryState::Merged, 1337, -2, 1337)),
470 470 (b"fa", (EntryState::Added, 1337, -2, 1337)),
471 471 (b"fb", (EntryState::Removed, 1337, -2, 1337)),
472 472 ]
473 473 .iter()
474 474 .map(|(fname, (state, mode, size, mtime))| {
475 475 (
476 476 HgPathBuf::from_bytes(fname.as_ref()),
477 477 DirstateEntry {
478 478 state: *state,
479 479 mode: *mode,
480 480 size: *size,
481 481 mtime: *mtime,
482 482 },
483 483 )
484 484 })
485 485 .collect();
486 486
487 487 let mut non_normal = [
488 488 b"f1", b"f2", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb",
489 489 ]
490 490 .iter()
491 491 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
492 492 .collect();
493 493
494 494 let mut other_parent = HashSet::new();
495 495 other_parent.insert(HgPathBuf::from_bytes(b"f4"));
496 496 let entries = map.get_non_normal_other_parent_entries();
497 497
498 498 assert_eq!(
499 499 (&mut non_normal, &mut other_parent),
500 500 (entries.0, entries.1)
501 501 );
502 502 }
503 503 }
@@ -1,299 +1,316 b''
1 use byteorder::{BigEndian, ByteOrder};
2
1 3 use crate::revlog::{Revision, NULL_REVISION};
2 use byteorder::{BigEndian, ByteOrder};
3 4
4 5 pub const INDEX_ENTRY_SIZE: usize = 64;
5 6
6 7 /// A Revlog index
7 8 #[derive(Debug)]
8 9 pub struct Index<'a> {
9 10 bytes: &'a [u8],
10 11 /// Offsets of starts of index blocks.
11 12 /// Only needed when the index is interleaved with data.
12 13 offsets: Option<Vec<usize>>,
13 14 }
14 15
15 16 impl<'a> Index<'a> {
16 17 /// Create an index from bytes.
17 18 /// Calculate the start of each entry when is_inline is true.
18 19 pub fn new(bytes: &'a [u8], is_inline: bool) -> Self {
19 20 if is_inline {
20 21 let mut offset: usize = 0;
21 22 let mut offsets = Vec::new();
22 23
23 24 while (bytes.len() - offset) >= INDEX_ENTRY_SIZE {
24 25 offsets.push(offset);
25 26 let end = offset + INDEX_ENTRY_SIZE;
26 27 let entry = IndexEntry {
27 28 bytes: &bytes[offset..end],
28 29 offset_override: None,
29 30 };
30 31
31 32 offset += INDEX_ENTRY_SIZE + entry.compressed_len();
32 33 }
33 34
34 35 Self {
35 36 bytes,
36 37 offsets: Some(offsets),
37 38 }
38 39 } else {
39 40 Self {
40 41 bytes,
41 42 offsets: None,
42 43 }
43 44 }
44 45 }
45 46
46 47 /// Return the index entry corresponding to the given revision if it
47 48 /// exists.
48 49 pub fn get_entry(&self, rev: Revision) -> Option<IndexEntry> {
49 50 if rev == NULL_REVISION {
50 51 return None;
51 52 }
52 53 if let Some(offsets) = &self.offsets {
53 54 self.get_entry_inline(rev, offsets)
54 55 } else {
55 56 self.get_entry_separated(rev)
56 57 }
57 58 }
58 59
59 60 fn get_entry_inline(
60 61 &self,
61 62 rev: Revision,
62 63 offsets: &[usize],
63 64 ) -> Option<IndexEntry> {
64 65 let start = *offsets.get(rev as usize)?;
65 66 let end = start.checked_add(INDEX_ENTRY_SIZE)?;
66 67 let bytes = &self.bytes[start..end];
67 68
68 69 // See IndexEntry for an explanation of this override.
69 70 let offset_override = Some(end);
70 71
71 72 Some(IndexEntry {
72 73 bytes,
73 74 offset_override,
74 75 })
75 76 }
76 77
77 78 fn get_entry_separated(&self, rev: Revision) -> Option<IndexEntry> {
78 79 let max_rev = self.bytes.len() / INDEX_ENTRY_SIZE;
79 80 if rev as usize >= max_rev {
80 81 return None;
81 82 }
82 83 let start = rev as usize * INDEX_ENTRY_SIZE;
83 84 let end = start + INDEX_ENTRY_SIZE;
84 85 let bytes = &self.bytes[start..end];
85 86
86 87 // See IndexEntry for an explanation of this override.
87 88 let offset_override = match rev {
88 89 0 => Some(0),
89 90 _ => None,
90 91 };
91 92
92 93 Some(IndexEntry {
93 94 bytes,
94 95 offset_override,
95 96 })
96 97 }
97 98 }
98 99
99 100 #[derive(Debug)]
100 101 pub struct IndexEntry<'a> {
101 102 bytes: &'a [u8],
102 103 /// Allows to override the offset value of the entry.
103 104 ///
104 105 /// For interleaved index and data, the offset stored in the index
105 106 /// corresponds to the separated data offset.
106 107 /// It has to be overridden with the actual offset in the interleaved
107 108 /// index which is just after the index block.
108 109 ///
109 110 /// For separated index and data, the offset stored in the first index
110 111 /// entry is mixed with the index headers.
111 112 /// It has to be overridden with 0.
112 113 offset_override: Option<usize>,
113 114 }
114 115
115 116 impl<'a> IndexEntry<'a> {
116 117 /// Return the offset of the data if not overridden by offset_override.
117 118 pub fn offset(&self) -> usize {
118 119 if let Some(offset_override) = self.offset_override {
119 120 offset_override
120 121 } else {
121 122 let mut bytes = [0; 8];
122 123 bytes[2..8].copy_from_slice(&self.bytes[0..=5]);
123 124 BigEndian::read_u64(&bytes[..]) as usize
124 125 }
125 126 }
126 127
127 128 /// Return the compressed length of the data.
128 129 pub fn compressed_len(&self) -> usize {
129 130 BigEndian::read_u32(&self.bytes[8..=11]) as usize
130 131 }
131 132
132 133 /// Return the uncompressed length of the data.
133 134 pub fn uncompressed_len(&self) -> usize {
134 135 BigEndian::read_u32(&self.bytes[12..=15]) as usize
135 136 }
136 137
137 138 /// Return the revision upon which the data has been derived.
138 139 pub fn base_revision(&self) -> Revision {
139 140 // TODO Maybe return an Option when base_revision == rev?
140 141 // Requires to add rev to IndexEntry
141 142
142 143 BigEndian::read_i32(&self.bytes[16..])
143 144 }
145
146 pub fn p1(&self) -> Revision {
147 BigEndian::read_i32(&self.bytes[24..])
148 }
149
150 pub fn p2(&self) -> Revision {
151 BigEndian::read_i32(&self.bytes[28..])
152 }
153
154 /// Return the hash of revision's full text.
155 ///
156 /// Currently, SHA-1 is used and only the first 20 bytes of this field
157 /// are used.
158 pub fn hash(&self) -> &[u8] {
159 &self.bytes[32..52]
160 }
144 161 }
145 162
146 163 #[cfg(test)]
147 164 mod tests {
148 165 use super::*;
149 166
150 167 #[cfg(test)]
151 168 #[derive(Debug, Copy, Clone)]
152 169 pub struct IndexEntryBuilder {
153 170 is_first: bool,
154 171 is_inline: bool,
155 172 is_general_delta: bool,
156 173 version: u16,
157 174 offset: usize,
158 175 compressed_len: usize,
159 176 uncompressed_len: usize,
160 177 base_revision: Revision,
161 178 }
162 179
163 180 #[cfg(test)]
164 181 impl IndexEntryBuilder {
165 182 pub fn new() -> Self {
166 183 Self {
167 184 is_first: false,
168 185 is_inline: false,
169 186 is_general_delta: true,
170 187 version: 2,
171 188 offset: 0,
172 189 compressed_len: 0,
173 190 uncompressed_len: 0,
174 191 base_revision: 0,
175 192 }
176 193 }
177 194
178 195 pub fn is_first(&mut self, value: bool) -> &mut Self {
179 196 self.is_first = value;
180 197 self
181 198 }
182 199
183 200 pub fn with_inline(&mut self, value: bool) -> &mut Self {
184 201 self.is_inline = value;
185 202 self
186 203 }
187 204
188 205 pub fn with_general_delta(&mut self, value: bool) -> &mut Self {
189 206 self.is_general_delta = value;
190 207 self
191 208 }
192 209
193 210 pub fn with_version(&mut self, value: u16) -> &mut Self {
194 211 self.version = value;
195 212 self
196 213 }
197 214
198 215 pub fn with_offset(&mut self, value: usize) -> &mut Self {
199 216 self.offset = value;
200 217 self
201 218 }
202 219
203 220 pub fn with_compressed_len(&mut self, value: usize) -> &mut Self {
204 221 self.compressed_len = value;
205 222 self
206 223 }
207 224
208 225 pub fn with_uncompressed_len(&mut self, value: usize) -> &mut Self {
209 226 self.uncompressed_len = value;
210 227 self
211 228 }
212 229
213 230 pub fn with_base_revision(&mut self, value: Revision) -> &mut Self {
214 231 self.base_revision = value;
215 232 self
216 233 }
217 234
218 235 pub fn build(&self) -> Vec<u8> {
219 236 let mut bytes = Vec::with_capacity(INDEX_ENTRY_SIZE);
220 237 if self.is_first {
221 238 bytes.extend(&match (self.is_general_delta, self.is_inline) {
222 239 (false, false) => [0u8, 0],
223 240 (false, true) => [0u8, 1],
224 241 (true, false) => [0u8, 2],
225 242 (true, true) => [0u8, 3],
226 243 });
227 244 bytes.extend(&self.version.to_be_bytes());
228 245 // Remaining offset bytes.
229 246 bytes.extend(&[0u8; 2]);
230 247 } else {
231 248 // Offset is only 6 bytes will usize is 8.
232 249 bytes.extend(&self.offset.to_be_bytes()[2..]);
233 250 }
234 251 bytes.extend(&[0u8; 2]); // Revision flags.
235 252 bytes.extend(&self.compressed_len.to_be_bytes()[4..]);
236 253 bytes.extend(&self.uncompressed_len.to_be_bytes()[4..]);
237 254 bytes.extend(&self.base_revision.to_be_bytes());
238 255 bytes
239 256 }
240 257 }
241 258
242 259 #[test]
243 260 fn test_offset() {
244 261 let bytes = IndexEntryBuilder::new().with_offset(1).build();
245 262 let entry = IndexEntry {
246 263 bytes: &bytes,
247 264 offset_override: None,
248 265 };
249 266
250 267 assert_eq!(entry.offset(), 1)
251 268 }
252 269
253 270 #[test]
254 271 fn test_with_overridden_offset() {
255 272 let bytes = IndexEntryBuilder::new().with_offset(1).build();
256 273 let entry = IndexEntry {
257 274 bytes: &bytes,
258 275 offset_override: Some(2),
259 276 };
260 277
261 278 assert_eq!(entry.offset(), 2)
262 279 }
263 280
264 281 #[test]
265 282 fn test_compressed_len() {
266 283 let bytes = IndexEntryBuilder::new().with_compressed_len(1).build();
267 284 let entry = IndexEntry {
268 285 bytes: &bytes,
269 286 offset_override: None,
270 287 };
271 288
272 289 assert_eq!(entry.compressed_len(), 1)
273 290 }
274 291
275 292 #[test]
276 293 fn test_uncompressed_len() {
277 294 let bytes = IndexEntryBuilder::new().with_uncompressed_len(1).build();
278 295 let entry = IndexEntry {
279 296 bytes: &bytes,
280 297 offset_override: None,
281 298 };
282 299
283 300 assert_eq!(entry.uncompressed_len(), 1)
284 301 }
285 302
286 303 #[test]
287 304 fn test_base_revision() {
288 305 let bytes = IndexEntryBuilder::new().with_base_revision(1).build();
289 306 let entry = IndexEntry {
290 307 bytes: &bytes,
291 308 offset_override: None,
292 309 };
293 310
294 311 assert_eq!(entry.base_revision(), 1)
295 312 }
296 313 }
297 314
298 315 #[cfg(test)]
299 316 pub use tests::IndexEntryBuilder;
@@ -1,433 +1,438 b''
1 1 // Copyright 2019-2020 Georges Racinet <georges.racinet@octobus.net>
2 2 //
3 3 // This software may be used and distributed according to the terms of the
4 4 // GNU General Public License version 2 or any later version.
5 5
6 6 //! Definitions and utilities for Revision nodes
7 7 //!
8 8 //! In Mercurial code base, it is customary to call "a node" the binary SHA
9 9 //! of a revision.
10 10
11 11 use hex::{self, FromHex, FromHexError};
12 12
13 13 /// The length in bytes of a `Node`
14 14 ///
15 15 /// This constant is meant to ease refactors of this module, and
16 16 /// are private so that calling code does not expect all nodes have
17 17 /// the same size, should we support several formats concurrently in
18 18 /// the future.
19 const NODE_BYTES_LENGTH: usize = 20;
19 pub const NODE_BYTES_LENGTH: usize = 20;
20
21 /// Id of the null node.
22 ///
23 /// Used to indicate the absence of node.
24 pub const NULL_NODE_ID: [u8; NODE_BYTES_LENGTH] = [0u8; NODE_BYTES_LENGTH];
20 25
21 26 /// The length in bytes of a `Node`
22 27 ///
23 28 /// see also `NODES_BYTES_LENGTH` about it being private.
24 29 const NODE_NYBBLES_LENGTH: usize = 2 * NODE_BYTES_LENGTH;
25 30
26 31 /// Private alias for readability and to ease future change
27 32 type NodeData = [u8; NODE_BYTES_LENGTH];
28 33
29 34 /// Binary revision SHA
30 35 ///
31 36 /// ## Future changes of hash size
32 37 ///
33 38 /// To accomodate future changes of hash size, Rust callers
34 39 /// should use the conversion methods at the boundaries (FFI, actual
35 40 /// computation of hashes and I/O) only, and only if required.
36 41 ///
37 42 /// All other callers outside of unit tests should just handle `Node` values
38 43 /// and never make any assumption on the actual length, using [`nybbles_len`]
39 44 /// if they need a loop boundary.
40 45 ///
41 46 /// All methods that create a `Node` either take a type that enforces
42 47 /// the size or fail immediately at runtime with [`ExactLengthRequired`].
43 48 ///
44 49 /// [`nybbles_len`]: #method.nybbles_len
45 50 /// [`ExactLengthRequired`]: struct.NodeError#variant.ExactLengthRequired
46 51 #[derive(Clone, Debug, PartialEq)]
47 52 #[repr(transparent)]
48 53 pub struct Node {
49 54 data: NodeData,
50 55 }
51 56
52 57 /// The node value for NULL_REVISION
53 58 pub const NULL_NODE: Node = Node {
54 59 data: [0; NODE_BYTES_LENGTH],
55 60 };
56 61
57 62 impl From<NodeData> for Node {
58 63 fn from(data: NodeData) -> Node {
59 64 Node { data }
60 65 }
61 66 }
62 67
63 68 #[derive(Debug, PartialEq)]
64 69 pub enum NodeError {
65 70 ExactLengthRequired(usize, String),
66 71 PrefixTooLong(String),
67 72 HexError(FromHexError, String),
68 73 }
69 74
70 75 /// Low level utility function, also for prefixes
71 76 fn get_nybble(s: &[u8], i: usize) -> u8 {
72 77 if i % 2 == 0 {
73 78 s[i / 2] >> 4
74 79 } else {
75 80 s[i / 2] & 0x0f
76 81 }
77 82 }
78 83
79 84 impl Node {
80 85 /// Retrieve the `i`th half-byte of the binary data.
81 86 ///
82 87 /// This is also the `i`th hexadecimal digit in numeric form,
83 88 /// also called a [nybble](https://en.wikipedia.org/wiki/Nibble).
84 89 pub fn get_nybble(&self, i: usize) -> u8 {
85 90 get_nybble(&self.data, i)
86 91 }
87 92
88 93 /// Length of the data, in nybbles
89 94 pub fn nybbles_len(&self) -> usize {
90 95 // public exposure as an instance method only, so that we can
91 96 // easily support several sizes of hashes if needed in the future.
92 97 NODE_NYBBLES_LENGTH
93 98 }
94 99
95 100 /// Convert from hexadecimal string representation
96 101 ///
97 102 /// Exact length is required.
98 103 ///
99 104 /// To be used in FFI and I/O only, in order to facilitate future
100 105 /// changes of hash format.
101 106 pub fn from_hex(hex: &str) -> Result<Node, NodeError> {
102 107 Ok(NodeData::from_hex(hex)
103 108 .map_err(|e| NodeError::from((e, hex)))?
104 109 .into())
105 110 }
106 111
107 112 /// Convert to hexadecimal string representation
108 113 ///
109 114 /// To be used in FFI and I/O only, in order to facilitate future
110 115 /// changes of hash format.
111 116 pub fn encode_hex(&self) -> String {
112 117 hex::encode(self.data)
113 118 }
114 119
115 120 /// Provide access to binary data
116 121 ///
117 122 /// This is needed by FFI layers, for instance to return expected
118 123 /// binary values to Python.
119 124 pub fn as_bytes(&self) -> &[u8] {
120 125 &self.data
121 126 }
122 127 }
123 128
124 129 impl<T: AsRef<str>> From<(FromHexError, T)> for NodeError {
125 130 fn from(err_offender: (FromHexError, T)) -> Self {
126 131 let (err, offender) = err_offender;
127 132 match err {
128 133 FromHexError::InvalidStringLength => {
129 134 NodeError::ExactLengthRequired(
130 135 NODE_NYBBLES_LENGTH,
131 136 offender.as_ref().to_owned(),
132 137 )
133 138 }
134 139 _ => NodeError::HexError(err, offender.as_ref().to_owned()),
135 140 }
136 141 }
137 142 }
138 143
139 144 /// The beginning of a binary revision SHA.
140 145 ///
141 146 /// Since it can potentially come from an hexadecimal representation with
142 147 /// odd length, it needs to carry around whether the last 4 bits are relevant
143 148 /// or not.
144 149 #[derive(Debug, PartialEq)]
145 150 pub struct NodePrefix {
146 151 buf: Vec<u8>,
147 152 is_odd: bool,
148 153 }
149 154
150 155 impl NodePrefix {
151 156 /// Convert from hexadecimal string representation
152 157 ///
153 158 /// Similarly to `hex::decode`, can be used with Unicode string types
154 159 /// (`String`, `&str`) as well as bytes.
155 160 ///
156 161 /// To be used in FFI and I/O only, in order to facilitate future
157 162 /// changes of hash format.
158 163 pub fn from_hex(hex: impl AsRef<[u8]>) -> Result<Self, NodeError> {
159 164 let hex = hex.as_ref();
160 165 let len = hex.len();
161 166 if len > NODE_NYBBLES_LENGTH {
162 167 return Err(NodeError::PrefixTooLong(
163 168 String::from_utf8_lossy(hex).to_owned().to_string(),
164 169 ));
165 170 }
166 171
167 172 let is_odd = len % 2 == 1;
168 173 let even_part = if is_odd { &hex[..len - 1] } else { hex };
169 174 let mut buf: Vec<u8> = Vec::from_hex(&even_part)
170 175 .map_err(|e| (e, String::from_utf8_lossy(hex)))?;
171 176
172 177 if is_odd {
173 178 let latest_char = char::from(hex[len - 1]);
174 179 let latest_nybble = latest_char.to_digit(16).ok_or_else(|| {
175 180 (
176 181 FromHexError::InvalidHexCharacter {
177 182 c: latest_char,
178 183 index: len - 1,
179 184 },
180 185 String::from_utf8_lossy(hex),
181 186 )
182 187 })? as u8;
183 188 buf.push(latest_nybble << 4);
184 189 }
185 190 Ok(NodePrefix { buf, is_odd })
186 191 }
187 192
188 193 pub fn borrow(&self) -> NodePrefixRef {
189 194 NodePrefixRef {
190 195 buf: &self.buf,
191 196 is_odd: self.is_odd,
192 197 }
193 198 }
194 199 }
195 200
196 201 #[derive(Clone, Debug, PartialEq)]
197 202 pub struct NodePrefixRef<'a> {
198 203 buf: &'a [u8],
199 204 is_odd: bool,
200 205 }
201 206
202 207 impl<'a> NodePrefixRef<'a> {
203 208 pub fn len(&self) -> usize {
204 209 if self.is_odd {
205 210 self.buf.len() * 2 - 1
206 211 } else {
207 212 self.buf.len() * 2
208 213 }
209 214 }
210 215
211 216 pub fn is_empty(&self) -> bool {
212 217 self.len() == 0
213 218 }
214 219
215 220 pub fn is_prefix_of(&self, node: &Node) -> bool {
216 221 if self.is_odd {
217 222 let buf = self.buf;
218 223 let last_pos = buf.len() - 1;
219 224 node.data.starts_with(buf.split_at(last_pos).0)
220 225 && node.data[last_pos] >> 4 == buf[last_pos] >> 4
221 226 } else {
222 227 node.data.starts_with(self.buf)
223 228 }
224 229 }
225 230
226 231 /// Retrieve the `i`th half-byte from the prefix.
227 232 ///
228 233 /// This is also the `i`th hexadecimal digit in numeric form,
229 234 /// also called a [nybble](https://en.wikipedia.org/wiki/Nibble).
230 235 pub fn get_nybble(&self, i: usize) -> u8 {
231 236 assert!(i < self.len());
232 237 get_nybble(self.buf, i)
233 238 }
234 239
235 240 /// Return the index first nybble that's different from `node`
236 241 ///
237 242 /// If the return value is `None` that means that `self` is
238 243 /// a prefix of `node`, but the current method is a bit slower
239 244 /// than `is_prefix_of`.
240 245 ///
241 246 /// Returned index is as in `get_nybble`, i.e., starting at 0.
242 247 pub fn first_different_nybble(&self, node: &Node) -> Option<usize> {
243 248 let buf = self.buf;
244 249 let until = if self.is_odd {
245 250 buf.len() - 1
246 251 } else {
247 252 buf.len()
248 253 };
249 254 for (i, item) in buf.iter().enumerate().take(until) {
250 255 if *item != node.data[i] {
251 256 return if *item & 0xf0 == node.data[i] & 0xf0 {
252 257 Some(2 * i + 1)
253 258 } else {
254 259 Some(2 * i)
255 260 };
256 261 }
257 262 }
258 263 if self.is_odd && buf[until] & 0xf0 != node.data[until] & 0xf0 {
259 264 Some(until * 2)
260 265 } else {
261 266 None
262 267 }
263 268 }
264 269 }
265 270
266 271 /// A shortcut for full `Node` references
267 272 impl<'a> From<&'a Node> for NodePrefixRef<'a> {
268 273 fn from(node: &'a Node) -> Self {
269 274 NodePrefixRef {
270 275 buf: &node.data,
271 276 is_odd: false,
272 277 }
273 278 }
274 279 }
275 280
276 281 #[cfg(test)]
277 282 mod tests {
278 283 use super::*;
279 284
280 285 fn sample_node() -> Node {
281 286 let mut data = [0; NODE_BYTES_LENGTH];
282 287 data.copy_from_slice(&[
283 288 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba,
284 289 0x98, 0x76, 0x54, 0x32, 0x10, 0xde, 0xad, 0xbe, 0xef,
285 290 ]);
286 291 data.into()
287 292 }
288 293
289 294 /// Pad an hexadecimal string to reach `NODE_NYBBLES_LENGTH`
290 295 ///
291 296 /// The padding is made with zeros
292 297 pub fn hex_pad_right(hex: &str) -> String {
293 298 let mut res = hex.to_string();
294 299 while res.len() < NODE_NYBBLES_LENGTH {
295 300 res.push('0');
296 301 }
297 302 res
298 303 }
299 304
300 305 fn sample_node_hex() -> String {
301 306 hex_pad_right("0123456789abcdeffedcba9876543210deadbeef")
302 307 }
303 308
304 309 #[test]
305 310 fn test_node_from_hex() {
306 311 assert_eq!(Node::from_hex(&sample_node_hex()), Ok(sample_node()));
307 312
308 313 let mut short = hex_pad_right("0123");
309 314 short.pop();
310 315 short.pop();
311 316 assert_eq!(
312 317 Node::from_hex(&short),
313 318 Err(NodeError::ExactLengthRequired(NODE_NYBBLES_LENGTH, short)),
314 319 );
315 320
316 321 let not_hex = hex_pad_right("012... oops");
317 322 assert_eq!(
318 323 Node::from_hex(&not_hex),
319 324 Err(NodeError::HexError(
320 325 FromHexError::InvalidHexCharacter { c: '.', index: 3 },
321 326 not_hex,
322 327 )),
323 328 );
324 329 }
325 330
326 331 #[test]
327 332 fn test_node_encode_hex() {
328 333 assert_eq!(sample_node().encode_hex(), sample_node_hex());
329 334 }
330 335
331 336 #[test]
332 337 fn test_prefix_from_hex() -> Result<(), NodeError> {
333 338 assert_eq!(
334 339 NodePrefix::from_hex("0e1")?,
335 340 NodePrefix {
336 341 buf: vec![14, 16],
337 342 is_odd: true
338 343 }
339 344 );
340 345 assert_eq!(
341 346 NodePrefix::from_hex("0e1a")?,
342 347 NodePrefix {
343 348 buf: vec![14, 26],
344 349 is_odd: false
345 350 }
346 351 );
347 352
348 353 // checking limit case
349 354 let node_as_vec = sample_node().data.iter().cloned().collect();
350 355 assert_eq!(
351 356 NodePrefix::from_hex(sample_node_hex())?,
352 357 NodePrefix {
353 358 buf: node_as_vec,
354 359 is_odd: false
355 360 }
356 361 );
357 362
358 363 Ok(())
359 364 }
360 365
361 366 #[test]
362 367 fn test_prefix_from_hex_errors() {
363 368 assert_eq!(
364 369 NodePrefix::from_hex("testgr"),
365 370 Err(NodeError::HexError(
366 371 FromHexError::InvalidHexCharacter { c: 't', index: 0 },
367 372 "testgr".to_string()
368 373 ))
369 374 );
370 375 let mut long = NULL_NODE.encode_hex();
371 376 long.push('c');
372 377 match NodePrefix::from_hex(&long)
373 378 .expect_err("should be refused as too long")
374 379 {
375 380 NodeError::PrefixTooLong(s) => assert_eq!(s, long),
376 381 err => panic!(format!("Should have been TooLong, got {:?}", err)),
377 382 }
378 383 }
379 384
380 385 #[test]
381 386 fn test_is_prefix_of() -> Result<(), NodeError> {
382 387 let mut node_data = [0; NODE_BYTES_LENGTH];
383 388 node_data[0] = 0x12;
384 389 node_data[1] = 0xca;
385 390 let node = Node::from(node_data);
386 391 assert!(NodePrefix::from_hex("12")?.borrow().is_prefix_of(&node));
387 392 assert!(!NodePrefix::from_hex("1a")?.borrow().is_prefix_of(&node));
388 393 assert!(NodePrefix::from_hex("12c")?.borrow().is_prefix_of(&node));
389 394 assert!(!NodePrefix::from_hex("12d")?.borrow().is_prefix_of(&node));
390 395 Ok(())
391 396 }
392 397
393 398 #[test]
394 399 fn test_get_nybble() -> Result<(), NodeError> {
395 400 let prefix = NodePrefix::from_hex("dead6789cafe")?;
396 401 assert_eq!(prefix.borrow().get_nybble(0), 13);
397 402 assert_eq!(prefix.borrow().get_nybble(7), 9);
398 403 Ok(())
399 404 }
400 405
401 406 #[test]
402 407 fn test_first_different_nybble_even_prefix() {
403 408 let prefix = NodePrefix::from_hex("12ca").unwrap();
404 409 let prefref = prefix.borrow();
405 410 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
406 411 assert_eq!(prefref.first_different_nybble(&node), Some(0));
407 412 node.data[0] = 0x13;
408 413 assert_eq!(prefref.first_different_nybble(&node), Some(1));
409 414 node.data[0] = 0x12;
410 415 assert_eq!(prefref.first_different_nybble(&node), Some(2));
411 416 node.data[1] = 0xca;
412 417 // now it is a prefix
413 418 assert_eq!(prefref.first_different_nybble(&node), None);
414 419 }
415 420
416 421 #[test]
417 422 fn test_first_different_nybble_odd_prefix() {
418 423 let prefix = NodePrefix::from_hex("12c").unwrap();
419 424 let prefref = prefix.borrow();
420 425 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
421 426 assert_eq!(prefref.first_different_nybble(&node), Some(0));
422 427 node.data[0] = 0x13;
423 428 assert_eq!(prefref.first_different_nybble(&node), Some(1));
424 429 node.data[0] = 0x12;
425 430 assert_eq!(prefref.first_different_nybble(&node), Some(2));
426 431 node.data[1] = 0xca;
427 432 // now it is a prefix
428 433 assert_eq!(prefref.first_different_nybble(&node), None);
429 434 }
430 435 }
431 436
432 437 #[cfg(test)]
433 438 pub use tests::hex_pad_right;
@@ -1,353 +1,412 b''
1 1 use std::borrow::Cow;
2 2 use std::fs::File;
3 3 use std::io::Read;
4 4 use std::ops::Deref;
5 5 use std::path::Path;
6 6
7 7 use byteorder::{BigEndian, ByteOrder};
8 use crypto::digest::Digest;
9 use crypto::sha1::Sha1;
8 10 use flate2::read::ZlibDecoder;
9 11 use memmap::{Mmap, MmapOptions};
10 12 use micro_timer::timed;
11 13 use zstd;
12 14
13 15 use super::index::Index;
16 use super::node::{NODE_BYTES_LENGTH, NULL_NODE_ID};
14 17 use super::patch;
15 18 use crate::revlog::Revision;
16 19
17 20 pub enum RevlogError {
18 21 IoError(std::io::Error),
19 22 UnsuportedVersion(u16),
20 23 InvalidRevision,
21 24 Corrupted,
22 25 UnknowDataFormat(u8),
23 26 }
24 27
25 28 fn mmap_open(path: &Path) -> Result<Mmap, std::io::Error> {
26 29 let file = File::open(path)?;
27 30 let mmap = unsafe { MmapOptions::new().map(&file) }?;
28 31 Ok(mmap)
29 32 }
30 33
31 34 /// Read only implementation of revlog.
32 35 pub struct Revlog {
33 36 /// When index and data are not interleaved: bytes of the revlog index.
34 37 /// When index and data are interleaved: bytes of the revlog index and
35 38 /// data.
36 39 index_bytes: Box<dyn Deref<Target = [u8]> + Send>,
37 40 /// When index and data are not interleaved: bytes of the revlog data
38 41 data_bytes: Option<Box<dyn Deref<Target = [u8]> + Send>>,
39 42 }
40 43
41 44 impl Revlog {
42 45 /// Open a revlog index file.
43 46 ///
44 47 /// It will also open the associated data file if index and data are not
45 48 /// interleaved.
46 49 #[timed]
47 50 pub fn open(index_path: &Path) -> Result<Self, RevlogError> {
48 51 let index_mmap =
49 52 mmap_open(&index_path).map_err(RevlogError::IoError)?;
50 53
51 54 let version = get_version(&index_mmap);
52 55 if version != 1 {
53 56 return Err(RevlogError::UnsuportedVersion(version));
54 57 }
55 58
56 59 let is_inline = is_inline(&index_mmap);
57 60
58 61 let index_bytes = Box::new(index_mmap);
59 62
60 63 // TODO load data only when needed //
61 64 // type annotation required
62 65 // won't recognize Mmap as Deref<Target = [u8]>
63 66 let data_bytes: Option<Box<dyn Deref<Target = [u8]> + Send>> =
64 67 if is_inline {
65 68 None
66 69 } else {
67 70 let data_path = index_path.with_extension("d");
68 71 let data_mmap =
69 72 mmap_open(&data_path).map_err(RevlogError::IoError)?;
70 73 Some(Box::new(data_mmap))
71 74 };
72 75
73 76 Ok(Revlog {
74 77 index_bytes,
75 78 data_bytes,
76 79 })
77 80 }
78 81
79 82 /// Return the full data associated to a revision.
80 83 ///
81 84 /// All entries required to build the final data out of deltas will be
82 85 /// retrieved as needed, and the deltas will be applied to the inital
83 86 /// snapshot to rebuild the final data.
84 87 #[timed]
85 88 pub fn get_rev_data(&self, rev: Revision) -> Result<Vec<u8>, RevlogError> {
86 89 // Todo return -> Cow
87 90 let mut entry = self.get_entry(rev)?;
88 91 let mut delta_chain = vec![];
89 92 while let Some(base_rev) = entry.base_rev {
90 93 delta_chain.push(entry);
91 94 entry = self
92 95 .get_entry(base_rev)
93 96 .map_err(|_| RevlogError::Corrupted)?;
94 97 }
95 98
96 if delta_chain.is_empty() {
97 Ok(entry.data()?.into())
99 // TODO do not look twice in the index
100 let index = self.index();
101 let index_entry =
102 index.get_entry(rev).ok_or(RevlogError::InvalidRevision)?;
103
104 let data: Vec<u8> = if delta_chain.is_empty() {
105 entry.data()?.into()
106 } else {
107 Revlog::build_data_from_deltas(entry, &delta_chain)?
108 };
109
110 if self.check_hash(
111 index_entry.p1(),
112 index_entry.p2(),
113 index_entry.hash(),
114 &data,
115 ) {
116 Ok(data)
98 117 } else {
99 Revlog::build_data_from_deltas(entry, &delta_chain)
118 Err(RevlogError::Corrupted)
100 119 }
101 120 }
102 121
122 /// Check the hash of some given data against the recorded hash.
123 pub fn check_hash(
124 &self,
125 p1: Revision,
126 p2: Revision,
127 expected: &[u8],
128 data: &[u8],
129 ) -> bool {
130 let index = self.index();
131 let e1 = index.get_entry(p1);
132 let h1 = match e1 {
133 Some(ref entry) => entry.hash(),
134 None => &NULL_NODE_ID,
135 };
136 let e2 = index.get_entry(p2);
137 let h2 = match e2 {
138 Some(ref entry) => entry.hash(),
139 None => &NULL_NODE_ID,
140 };
141
142 hash(data, &h1, &h2).as_slice() == expected
143 }
144
103 145 /// Build the full data of a revision out its snapshot
104 146 /// and its deltas.
105 147 #[timed]
106 148 fn build_data_from_deltas(
107 149 snapshot: RevlogEntry,
108 150 deltas: &[RevlogEntry],
109 151 ) -> Result<Vec<u8>, RevlogError> {
110 152 let snapshot = snapshot.data()?;
111 153 let deltas = deltas
112 154 .iter()
113 155 .rev()
114 156 .map(RevlogEntry::data)
115 157 .collect::<Result<Vec<Cow<'_, [u8]>>, RevlogError>>()?;
116 158 let patches: Vec<_> =
117 159 deltas.iter().map(|d| patch::PatchList::new(d)).collect();
118 160 let patch = patch::fold_patch_lists(&patches);
119 161 Ok(patch.apply(&snapshot))
120 162 }
121 163
122 164 /// Return the revlog index.
123 165 fn index(&self) -> Index {
124 166 let is_inline = self.data_bytes.is_none();
125 167 Index::new(&self.index_bytes, is_inline)
126 168 }
127 169
128 170 /// Return the revlog data.
129 171 fn data(&self) -> &[u8] {
130 172 match self.data_bytes {
131 173 Some(ref data_bytes) => &data_bytes,
132 174 None => &self.index_bytes,
133 175 }
134 176 }
135 177
136 178 /// Get an entry of the revlog.
137 179 fn get_entry(&self, rev: Revision) -> Result<RevlogEntry, RevlogError> {
138 180 let index = self.index();
139 181 let index_entry =
140 182 index.get_entry(rev).ok_or(RevlogError::InvalidRevision)?;
141 183 let start = index_entry.offset();
142 184 let end = start + index_entry.compressed_len();
143 185 let entry = RevlogEntry {
144 186 rev,
145 187 bytes: &self.data()[start..end],
146 188 compressed_len: index_entry.compressed_len(),
147 189 uncompressed_len: index_entry.uncompressed_len(),
148 190 base_rev: if index_entry.base_revision() == rev {
149 191 None
150 192 } else {
151 193 Some(index_entry.base_revision())
152 194 },
153 195 };
154 196 Ok(entry)
155 197 }
156 198 }
157 199
158 200 /// The revlog entry's bytes and the necessary informations to extract
159 201 /// the entry's data.
160 202 #[derive(Debug)]
161 203 pub struct RevlogEntry<'a> {
162 204 rev: Revision,
163 205 bytes: &'a [u8],
164 206 compressed_len: usize,
165 207 uncompressed_len: usize,
166 208 base_rev: Option<Revision>,
167 209 }
168 210
169 211 impl<'a> RevlogEntry<'a> {
170 212 /// Extract the data contained in the entry.
171 213 pub fn data(&self) -> Result<Cow<'_, [u8]>, RevlogError> {
172 214 if self.bytes.is_empty() {
173 215 return Ok(Cow::Borrowed(&[]));
174 216 }
175 217 match self.bytes[0] {
176 218 // Revision data is the entirety of the entry, including this
177 219 // header.
178 220 b'\0' => Ok(Cow::Borrowed(self.bytes)),
179 221 // Raw revision data follows.
180 222 b'u' => Ok(Cow::Borrowed(&self.bytes[1..])),
181 223 // zlib (RFC 1950) data.
182 224 b'x' => Ok(Cow::Owned(self.uncompressed_zlib_data())),
183 225 // zstd data.
184 226 b'\x28' => Ok(Cow::Owned(self.uncompressed_zstd_data())),
185 227 format_type => Err(RevlogError::UnknowDataFormat(format_type)),
186 228 }
187 229 }
188 230
189 231 fn uncompressed_zlib_data(&self) -> Vec<u8> {
190 232 let mut decoder = ZlibDecoder::new(self.bytes);
191 233 if self.is_delta() {
192 234 let mut buf = Vec::with_capacity(self.compressed_len);
193 235 decoder.read_to_end(&mut buf).expect("corrupted zlib data");
194 236 buf
195 237 } else {
196 238 let mut buf = vec![0; self.uncompressed_len];
197 239 decoder.read_exact(&mut buf).expect("corrupted zlib data");
198 240 buf
199 241 }
200 242 }
201 243
202 244 fn uncompressed_zstd_data(&self) -> Vec<u8> {
203 245 if self.is_delta() {
204 246 let mut buf = Vec::with_capacity(self.compressed_len);
205 247 zstd::stream::copy_decode(self.bytes, &mut buf)
206 248 .expect("corrupted zstd data");
207 249 buf
208 250 } else {
209 251 let mut buf = vec![0; self.uncompressed_len];
210 252 let len = zstd::block::decompress_to_buffer(self.bytes, &mut buf)
211 253 .expect("corrupted zstd data");
212 254 assert_eq!(len, self.uncompressed_len, "corrupted zstd data");
213 255 buf
214 256 }
215 257 }
216 258
217 259 /// Tell if the entry is a snapshot or a delta
218 260 /// (influences on decompression).
219 261 fn is_delta(&self) -> bool {
220 262 self.base_rev.is_some()
221 263 }
222 264 }
223 265
224 266 /// Value of the inline flag.
225 267 pub fn is_inline(index_bytes: &[u8]) -> bool {
226 268 match &index_bytes[0..=1] {
227 269 [0, 0] | [0, 2] => false,
228 270 _ => true,
229 271 }
230 272 }
231 273
232 274 /// Format version of the revlog.
233 275 pub fn get_version(index_bytes: &[u8]) -> u16 {
234 276 BigEndian::read_u16(&index_bytes[2..=3])
235 277 }
236 278
279 /// Calculate the hash of a revision given its data and its parents.
280 fn hash(data: &[u8], p1_hash: &[u8], p2_hash: &[u8]) -> Vec<u8> {
281 let mut hasher = Sha1::new();
282 let (a, b) = (p1_hash, p2_hash);
283 if a > b {
284 hasher.input(b);
285 hasher.input(a);
286 } else {
287 hasher.input(a);
288 hasher.input(b);
289 }
290 hasher.input(data);
291 let mut hash = vec![0; NODE_BYTES_LENGTH];
292 hasher.result(&mut hash);
293 hash
294 }
295
237 296 #[cfg(test)]
238 297 mod tests {
239 298 use super::*;
240 299
241 300 use super::super::index::IndexEntryBuilder;
242 301
243 302 #[cfg(test)]
244 303 pub struct RevlogBuilder {
245 304 version: u16,
246 305 is_general_delta: bool,
247 306 is_inline: bool,
248 307 offset: usize,
249 308 index: Vec<Vec<u8>>,
250 309 data: Vec<Vec<u8>>,
251 310 }
252 311
253 312 #[cfg(test)]
254 313 impl RevlogBuilder {
255 314 pub fn new() -> Self {
256 315 Self {
257 316 version: 2,
258 317 is_inline: false,
259 318 is_general_delta: true,
260 319 offset: 0,
261 320 index: vec![],
262 321 data: vec![],
263 322 }
264 323 }
265 324
266 325 pub fn with_inline(&mut self, value: bool) -> &mut Self {
267 326 self.is_inline = value;
268 327 self
269 328 }
270 329
271 330 pub fn with_general_delta(&mut self, value: bool) -> &mut Self {
272 331 self.is_general_delta = value;
273 332 self
274 333 }
275 334
276 335 pub fn with_version(&mut self, value: u16) -> &mut Self {
277 336 self.version = value;
278 337 self
279 338 }
280 339
281 340 pub fn push(
282 341 &mut self,
283 342 mut index: IndexEntryBuilder,
284 343 data: Vec<u8>,
285 344 ) -> &mut Self {
286 345 if self.index.is_empty() {
287 346 index.is_first(true);
288 347 index.with_general_delta(self.is_general_delta);
289 348 index.with_inline(self.is_inline);
290 349 index.with_version(self.version);
291 350 } else {
292 351 index.with_offset(self.offset);
293 352 }
294 353 self.index.push(index.build());
295 354 self.offset += data.len();
296 355 self.data.push(data);
297 356 self
298 357 }
299 358
300 359 pub fn build_inline(&self) -> Vec<u8> {
301 360 let mut bytes =
302 361 Vec::with_capacity(self.index.len() + self.data.len());
303 362 for (index, data) in self.index.iter().zip(self.data.iter()) {
304 363 bytes.extend(index);
305 364 bytes.extend(data);
306 365 }
307 366 bytes
308 367 }
309 368 }
310 369
311 370 #[test]
312 371 fn is_not_inline_when_no_inline_flag_test() {
313 372 let bytes = RevlogBuilder::new()
314 373 .with_general_delta(false)
315 374 .with_inline(false)
316 375 .push(IndexEntryBuilder::new(), vec![])
317 376 .build_inline();
318 377
319 378 assert_eq!(is_inline(&bytes), false)
320 379 }
321 380
322 381 #[test]
323 382 fn is_inline_when_inline_flag_test() {
324 383 let bytes = RevlogBuilder::new()
325 384 .with_general_delta(false)
326 385 .with_inline(true)
327 386 .push(IndexEntryBuilder::new(), vec![])
328 387 .build_inline();
329 388
330 389 assert_eq!(is_inline(&bytes), true)
331 390 }
332 391
333 392 #[test]
334 393 fn is_inline_when_inline_and_generaldelta_flags_test() {
335 394 let bytes = RevlogBuilder::new()
336 395 .with_general_delta(true)
337 396 .with_inline(true)
338 397 .push(IndexEntryBuilder::new(), vec![])
339 398 .build_inline();
340 399
341 400 assert_eq!(is_inline(&bytes), true)
342 401 }
343 402
344 403 #[test]
345 404 fn version_test() {
346 405 let bytes = RevlogBuilder::new()
347 406 .with_version(1)
348 407 .push(IndexEntryBuilder::new(), vec![])
349 408 .build_inline();
350 409
351 410 assert_eq!(get_version(&bytes), 1)
352 411 }
353 412 }
General Comments 0
You need to be logged in to leave comments. Login now