##// END OF EJS Templates
rust: create wrapper struct to reduce `regex` contention issues...
Raphaël Gomès -
r50476:04f1dba5 6.3 stable
parent child Browse files
Show More
@@ -1,1284 +1,1294 b''
1 1 # This file is automatically @generated by Cargo.
2 2 # It is not intended for manual editing.
3 3 version = 3
4 4
5 5 [[package]]
6 6 name = "Inflector"
7 7 version = "0.11.4"
8 8 source = "registry+https://github.com/rust-lang/crates.io-index"
9 9 checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
10 10
11 11 [[package]]
12 12 name = "adler"
13 13 version = "0.2.3"
14 14 source = "registry+https://github.com/rust-lang/crates.io-index"
15 15 checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
16 16
17 17 [[package]]
18 18 name = "ahash"
19 19 version = "0.4.7"
20 20 source = "registry+https://github.com/rust-lang/crates.io-index"
21 21 checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e"
22 22
23 23 [[package]]
24 24 name = "aho-corasick"
25 25 version = "0.7.18"
26 26 source = "registry+https://github.com/rust-lang/crates.io-index"
27 27 checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
28 28 dependencies = [
29 29 "memchr",
30 30 ]
31 31
32 32 [[package]]
33 33 name = "aliasable"
34 34 version = "0.1.3"
35 35 source = "registry+https://github.com/rust-lang/crates.io-index"
36 36 checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
37 37
38 38 [[package]]
39 39 name = "ansi_term"
40 40 version = "0.12.1"
41 41 source = "registry+https://github.com/rust-lang/crates.io-index"
42 42 checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
43 43 dependencies = [
44 44 "winapi",
45 45 ]
46 46
47 47 [[package]]
48 48 name = "atty"
49 49 version = "0.2.14"
50 50 source = "registry+https://github.com/rust-lang/crates.io-index"
51 51 checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
52 52 dependencies = [
53 53 "hermit-abi",
54 54 "libc",
55 55 "winapi",
56 56 ]
57 57
58 58 [[package]]
59 59 name = "autocfg"
60 60 version = "1.0.1"
61 61 source = "registry+https://github.com/rust-lang/crates.io-index"
62 62 checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
63 63
64 64 [[package]]
65 65 name = "bitflags"
66 66 version = "1.3.2"
67 67 source = "registry+https://github.com/rust-lang/crates.io-index"
68 68 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
69 69
70 70 [[package]]
71 71 name = "bitmaps"
72 72 version = "2.1.0"
73 73 source = "registry+https://github.com/rust-lang/crates.io-index"
74 74 checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2"
75 75 dependencies = [
76 76 "typenum",
77 77 ]
78 78
79 79 [[package]]
80 80 name = "block-buffer"
81 81 version = "0.9.0"
82 82 source = "registry+https://github.com/rust-lang/crates.io-index"
83 83 checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
84 84 dependencies = [
85 85 "generic-array",
86 86 ]
87 87
88 88 [[package]]
89 89 name = "block-buffer"
90 90 version = "0.10.2"
91 91 source = "registry+https://github.com/rust-lang/crates.io-index"
92 92 checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
93 93 dependencies = [
94 94 "generic-array",
95 95 ]
96 96
97 97 [[package]]
98 98 name = "byteorder"
99 99 version = "1.4.3"
100 100 source = "registry+https://github.com/rust-lang/crates.io-index"
101 101 checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
102 102
103 103 [[package]]
104 104 name = "bytes-cast"
105 105 version = "0.2.0"
106 106 source = "registry+https://github.com/rust-lang/crates.io-index"
107 107 checksum = "0d434f9a4ecbe987e7ccfda7274b6f82ea52c9b63742565a65cb5e8ba0f2c452"
108 108 dependencies = [
109 109 "bytes-cast-derive",
110 110 ]
111 111
112 112 [[package]]
113 113 name = "bytes-cast-derive"
114 114 version = "0.1.0"
115 115 source = "registry+https://github.com/rust-lang/crates.io-index"
116 116 checksum = "cb936af9de38476664d6b58e529aff30d482e4ce1c5e150293d00730b0d81fdb"
117 117 dependencies = [
118 118 "proc-macro2",
119 119 "quote",
120 120 "syn",
121 121 ]
122 122
123 123 [[package]]
124 124 name = "cc"
125 125 version = "1.0.66"
126 126 source = "registry+https://github.com/rust-lang/crates.io-index"
127 127 checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
128 128 dependencies = [
129 129 "jobserver",
130 130 ]
131 131
132 132 [[package]]
133 133 name = "cfg-if"
134 134 version = "0.1.10"
135 135 source = "registry+https://github.com/rust-lang/crates.io-index"
136 136 checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
137 137
138 138 [[package]]
139 139 name = "cfg-if"
140 140 version = "1.0.0"
141 141 source = "registry+https://github.com/rust-lang/crates.io-index"
142 142 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
143 143
144 144 [[package]]
145 145 name = "chrono"
146 146 version = "0.4.19"
147 147 source = "registry+https://github.com/rust-lang/crates.io-index"
148 148 checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
149 149 dependencies = [
150 150 "libc",
151 151 "num-integer",
152 152 "num-traits",
153 153 "time",
154 154 "winapi",
155 155 ]
156 156
157 157 [[package]]
158 158 name = "clap"
159 159 version = "2.34.0"
160 160 source = "registry+https://github.com/rust-lang/crates.io-index"
161 161 checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
162 162 dependencies = [
163 163 "ansi_term",
164 164 "atty",
165 165 "bitflags",
166 166 "strsim",
167 167 "textwrap",
168 168 "unicode-width",
169 169 "vec_map",
170 170 ]
171 171
172 172 [[package]]
173 173 name = "const_fn"
174 174 version = "0.4.4"
175 175 source = "registry+https://github.com/rust-lang/crates.io-index"
176 176 checksum = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826"
177 177
178 178 [[package]]
179 179 name = "convert_case"
180 180 version = "0.4.0"
181 181 source = "registry+https://github.com/rust-lang/crates.io-index"
182 182 checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
183 183
184 184 [[package]]
185 185 name = "cpufeatures"
186 186 version = "0.1.4"
187 187 source = "registry+https://github.com/rust-lang/crates.io-index"
188 188 checksum = "ed00c67cb5d0a7d64a44f6ad2668db7e7530311dd53ea79bcd4fb022c64911c8"
189 189 dependencies = [
190 190 "libc",
191 191 ]
192 192
193 193 [[package]]
194 194 name = "cpufeatures"
195 195 version = "0.2.1"
196 196 source = "registry+https://github.com/rust-lang/crates.io-index"
197 197 checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
198 198 dependencies = [
199 199 "libc",
200 200 ]
201 201
202 202 [[package]]
203 203 name = "cpython"
204 204 version = "0.7.0"
205 205 source = "registry+https://github.com/rust-lang/crates.io-index"
206 206 checksum = "b7d46ba8ace7f3a1d204ac5060a706d0a68de6b42eafb6a586cc08bebcffe664"
207 207 dependencies = [
208 208 "libc",
209 209 "num-traits",
210 210 "paste",
211 211 "python3-sys",
212 212 ]
213 213
214 214 [[package]]
215 215 name = "crc32fast"
216 216 version = "1.2.1"
217 217 source = "registry+https://github.com/rust-lang/crates.io-index"
218 218 checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
219 219 dependencies = [
220 220 "cfg-if 1.0.0",
221 221 ]
222 222
223 223 [[package]]
224 224 name = "crossbeam-channel"
225 225 version = "0.5.2"
226 226 source = "registry+https://github.com/rust-lang/crates.io-index"
227 227 checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
228 228 dependencies = [
229 229 "cfg-if 1.0.0",
230 230 "crossbeam-utils",
231 231 ]
232 232
233 233 [[package]]
234 234 name = "crossbeam-deque"
235 235 version = "0.8.0"
236 236 source = "registry+https://github.com/rust-lang/crates.io-index"
237 237 checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
238 238 dependencies = [
239 239 "cfg-if 1.0.0",
240 240 "crossbeam-epoch",
241 241 "crossbeam-utils",
242 242 ]
243 243
244 244 [[package]]
245 245 name = "crossbeam-epoch"
246 246 version = "0.9.1"
247 247 source = "registry+https://github.com/rust-lang/crates.io-index"
248 248 checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
249 249 dependencies = [
250 250 "cfg-if 1.0.0",
251 251 "const_fn",
252 252 "crossbeam-utils",
253 253 "lazy_static",
254 254 "memoffset",
255 255 "scopeguard",
256 256 ]
257 257
258 258 [[package]]
259 259 name = "crossbeam-utils"
260 260 version = "0.8.1"
261 261 source = "registry+https://github.com/rust-lang/crates.io-index"
262 262 checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
263 263 dependencies = [
264 264 "autocfg",
265 265 "cfg-if 1.0.0",
266 266 "lazy_static",
267 267 ]
268 268
269 269 [[package]]
270 270 name = "crypto-common"
271 271 version = "0.1.2"
272 272 source = "registry+https://github.com/rust-lang/crates.io-index"
273 273 checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06"
274 274 dependencies = [
275 275 "generic-array",
276 276 ]
277 277
278 278 [[package]]
279 279 name = "ctor"
280 280 version = "0.1.16"
281 281 source = "registry+https://github.com/rust-lang/crates.io-index"
282 282 checksum = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484"
283 283 dependencies = [
284 284 "quote",
285 285 "syn",
286 286 ]
287 287
288 288 [[package]]
289 289 name = "derive_more"
290 290 version = "0.99.17"
291 291 source = "registry+https://github.com/rust-lang/crates.io-index"
292 292 checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
293 293 dependencies = [
294 294 "convert_case",
295 295 "proc-macro2",
296 296 "quote",
297 297 "rustc_version",
298 298 "syn",
299 299 ]
300 300
301 301 [[package]]
302 302 name = "diff"
303 303 version = "0.1.12"
304 304 source = "registry+https://github.com/rust-lang/crates.io-index"
305 305 checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
306 306
307 307 [[package]]
308 308 name = "digest"
309 309 version = "0.9.0"
310 310 source = "registry+https://github.com/rust-lang/crates.io-index"
311 311 checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
312 312 dependencies = [
313 313 "generic-array",
314 314 ]
315 315
316 316 [[package]]
317 317 name = "digest"
318 318 version = "0.10.2"
319 319 source = "registry+https://github.com/rust-lang/crates.io-index"
320 320 checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837"
321 321 dependencies = [
322 322 "block-buffer 0.10.2",
323 323 "crypto-common",
324 324 ]
325 325
326 326 [[package]]
327 327 name = "either"
328 328 version = "1.6.1"
329 329 source = "registry+https://github.com/rust-lang/crates.io-index"
330 330 checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
331 331
332 332 [[package]]
333 333 name = "env_logger"
334 334 version = "0.9.0"
335 335 source = "registry+https://github.com/rust-lang/crates.io-index"
336 336 checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
337 337 dependencies = [
338 338 "atty",
339 339 "humantime",
340 340 "log",
341 341 "regex",
342 342 "termcolor",
343 343 ]
344 344
345 345 [[package]]
346 346 name = "fastrand"
347 347 version = "1.7.0"
348 348 source = "registry+https://github.com/rust-lang/crates.io-index"
349 349 checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
350 350 dependencies = [
351 351 "instant",
352 352 ]
353 353
354 354 [[package]]
355 355 name = "flate2"
356 356 version = "1.0.22"
357 357 source = "registry+https://github.com/rust-lang/crates.io-index"
358 358 checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f"
359 359 dependencies = [
360 360 "cfg-if 1.0.0",
361 361 "crc32fast",
362 362 "libc",
363 363 "libz-sys",
364 364 "miniz_oxide",
365 365 ]
366 366
367 367 [[package]]
368 368 name = "format-bytes"
369 369 version = "0.3.0"
370 370 source = "registry+https://github.com/rust-lang/crates.io-index"
371 371 checksum = "48942366ef93975da38e175ac9e10068c6fc08ca9e85930d4f098f4d5b14c2fd"
372 372 dependencies = [
373 373 "format-bytes-macros",
374 374 ]
375 375
376 376 [[package]]
377 377 name = "format-bytes-macros"
378 378 version = "0.4.0"
379 379 source = "registry+https://github.com/rust-lang/crates.io-index"
380 380 checksum = "203aadebefcc73d12038296c228eabf830f99cba991b0032adf20e9fa6ce7e4f"
381 381 dependencies = [
382 382 "proc-macro2",
383 383 "quote",
384 384 "syn",
385 385 ]
386 386
387 387 [[package]]
388 388 name = "generic-array"
389 389 version = "0.14.4"
390 390 source = "registry+https://github.com/rust-lang/crates.io-index"
391 391 checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
392 392 dependencies = [
393 393 "typenum",
394 394 "version_check",
395 395 ]
396 396
397 397 [[package]]
398 398 name = "getrandom"
399 399 version = "0.1.15"
400 400 source = "registry+https://github.com/rust-lang/crates.io-index"
401 401 checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
402 402 dependencies = [
403 403 "cfg-if 0.1.10",
404 404 "libc",
405 405 "wasi 0.9.0+wasi-snapshot-preview1",
406 406 ]
407 407
408 408 [[package]]
409 409 name = "getrandom"
410 410 version = "0.2.4"
411 411 source = "registry+https://github.com/rust-lang/crates.io-index"
412 412 checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
413 413 dependencies = [
414 414 "cfg-if 1.0.0",
415 415 "libc",
416 416 "wasi 0.10.0+wasi-snapshot-preview1",
417 417 ]
418 418
419 419 [[package]]
420 420 name = "glob"
421 421 version = "0.3.0"
422 422 source = "registry+https://github.com/rust-lang/crates.io-index"
423 423 checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
424 424
425 425 [[package]]
426 426 name = "hashbrown"
427 427 version = "0.9.1"
428 428 source = "registry+https://github.com/rust-lang/crates.io-index"
429 429 checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04"
430 430 dependencies = [
431 431 "ahash",
432 432 "rayon",
433 433 ]
434 434
435 435 [[package]]
436 436 name = "hermit-abi"
437 437 version = "0.1.17"
438 438 source = "registry+https://github.com/rust-lang/crates.io-index"
439 439 checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
440 440 dependencies = [
441 441 "libc",
442 442 ]
443 443
444 444 [[package]]
445 445 name = "hex"
446 446 version = "0.4.3"
447 447 source = "registry+https://github.com/rust-lang/crates.io-index"
448 448 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
449 449
450 450 [[package]]
451 451 name = "hg-core"
452 452 version = "0.1.0"
453 453 dependencies = [
454 454 "bitflags",
455 455 "byteorder",
456 456 "bytes-cast",
457 457 "clap",
458 458 "crossbeam-channel",
459 459 "derive_more",
460 460 "flate2",
461 461 "format-bytes",
462 462 "hashbrown",
463 463 "home",
464 464 "im-rc",
465 465 "itertools 0.10.3",
466 466 "lazy_static",
467 467 "libc",
468 468 "log",
469 469 "memmap2",
470 470 "micro-timer",
471 471 "once_cell",
472 472 "ouroboros",
473 473 "pretty_assertions",
474 474 "rand 0.8.5",
475 475 "rand_distr",
476 476 "rand_pcg",
477 477 "rayon",
478 478 "regex",
479 479 "same-file",
480 480 "sha-1 0.10.0",
481 481 "tempfile",
482 "thread_local",
482 483 "twox-hash",
483 484 "zstd",
484 485 ]
485 486
486 487 [[package]]
487 488 name = "hg-cpython"
488 489 version = "0.1.0"
489 490 dependencies = [
490 491 "cpython",
491 492 "crossbeam-channel",
492 493 "env_logger",
493 494 "hg-core",
494 495 "libc",
495 496 "log",
496 497 "stable_deref_trait",
497 498 "vcsgraph",
498 499 ]
499 500
500 501 [[package]]
501 502 name = "home"
502 503 version = "0.5.3"
503 504 source = "registry+https://github.com/rust-lang/crates.io-index"
504 505 checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
505 506 dependencies = [
506 507 "winapi",
507 508 ]
508 509
509 510 [[package]]
510 511 name = "humantime"
511 512 version = "2.1.0"
512 513 source = "registry+https://github.com/rust-lang/crates.io-index"
513 514 checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
514 515
515 516 [[package]]
516 517 name = "im-rc"
517 518 version = "15.0.0"
518 519 source = "registry+https://github.com/rust-lang/crates.io-index"
519 520 checksum = "3ca8957e71f04a205cb162508f9326aea04676c8dfd0711220190d6b83664f3f"
520 521 dependencies = [
521 522 "bitmaps",
522 523 "rand_core 0.5.1",
523 524 "rand_xoshiro",
524 525 "sized-chunks",
525 526 "typenum",
526 527 "version_check",
527 528 ]
528 529
529 530 [[package]]
530 531 name = "instant"
531 532 version = "0.1.12"
532 533 source = "registry+https://github.com/rust-lang/crates.io-index"
533 534 checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
534 535 dependencies = [
535 536 "cfg-if 1.0.0",
536 537 ]
537 538
538 539 [[package]]
539 540 name = "itertools"
540 541 version = "0.9.0"
541 542 source = "registry+https://github.com/rust-lang/crates.io-index"
542 543 checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
543 544 dependencies = [
544 545 "either",
545 546 ]
546 547
547 548 [[package]]
548 549 name = "itertools"
549 550 version = "0.10.3"
550 551 source = "registry+https://github.com/rust-lang/crates.io-index"
551 552 checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
552 553 dependencies = [
553 554 "either",
554 555 ]
555 556
556 557 [[package]]
557 558 name = "jobserver"
558 559 version = "0.1.21"
559 560 source = "registry+https://github.com/rust-lang/crates.io-index"
560 561 checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2"
561 562 dependencies = [
562 563 "libc",
563 564 ]
564 565
565 566 [[package]]
566 567 name = "lazy_static"
567 568 version = "1.4.0"
568 569 source = "registry+https://github.com/rust-lang/crates.io-index"
569 570 checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
570 571
571 572 [[package]]
572 573 name = "libc"
573 574 version = "0.2.124"
574 575 source = "registry+https://github.com/rust-lang/crates.io-index"
575 576 checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50"
576 577
577 578 [[package]]
578 579 name = "libm"
579 580 version = "0.2.1"
580 581 source = "registry+https://github.com/rust-lang/crates.io-index"
581 582 checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
582 583
583 584 [[package]]
584 585 name = "libz-sys"
585 586 version = "1.1.2"
586 587 source = "registry+https://github.com/rust-lang/crates.io-index"
587 588 checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655"
588 589 dependencies = [
589 590 "cc",
590 591 "pkg-config",
591 592 "vcpkg",
592 593 ]
593 594
594 595 [[package]]
595 596 name = "log"
596 597 version = "0.4.14"
597 598 source = "registry+https://github.com/rust-lang/crates.io-index"
598 599 checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
599 600 dependencies = [
600 601 "cfg-if 1.0.0",
601 602 ]
602 603
603 604 [[package]]
604 605 name = "memchr"
605 606 version = "2.4.1"
606 607 source = "registry+https://github.com/rust-lang/crates.io-index"
607 608 checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
608 609
609 610 [[package]]
610 611 name = "memmap2"
611 612 version = "0.5.7"
612 613 source = "registry+https://github.com/rust-lang/crates.io-index"
613 614 checksum = "95af15f345b17af2efc8ead6080fb8bc376f8cec1b35277b935637595fe77498"
614 615 dependencies = [
615 616 "libc",
616 617 "stable_deref_trait",
617 618 ]
618 619
619 620 [[package]]
620 621 name = "memoffset"
621 622 version = "0.6.1"
622 623 source = "registry+https://github.com/rust-lang/crates.io-index"
623 624 checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
624 625 dependencies = [
625 626 "autocfg",
626 627 ]
627 628
628 629 [[package]]
629 630 name = "micro-timer"
630 631 version = "0.4.0"
631 632 source = "registry+https://github.com/rust-lang/crates.io-index"
632 633 checksum = "5de32cb59a062672560d6f0842c4aa7714727457b9fe2daf8987d995a176a405"
633 634 dependencies = [
634 635 "micro-timer-macros",
635 636 "scopeguard",
636 637 ]
637 638
638 639 [[package]]
639 640 name = "micro-timer-macros"
640 641 version = "0.4.0"
641 642 source = "registry+https://github.com/rust-lang/crates.io-index"
642 643 checksum = "cee948b94700125b52dfb68dd17c19f6326696c1df57f92c05ee857463c93ba1"
643 644 dependencies = [
644 645 "proc-macro2",
645 646 "quote",
646 647 "scopeguard",
647 648 "syn",
648 649 ]
649 650
650 651 [[package]]
651 652 name = "miniz_oxide"
652 653 version = "0.4.3"
653 654 source = "registry+https://github.com/rust-lang/crates.io-index"
654 655 checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
655 656 dependencies = [
656 657 "adler",
657 658 "autocfg",
658 659 ]
659 660
660 661 [[package]]
661 662 name = "num-integer"
662 663 version = "0.1.44"
663 664 source = "registry+https://github.com/rust-lang/crates.io-index"
664 665 checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
665 666 dependencies = [
666 667 "autocfg",
667 668 "num-traits",
668 669 ]
669 670
670 671 [[package]]
671 672 name = "num-traits"
672 673 version = "0.2.14"
673 674 source = "registry+https://github.com/rust-lang/crates.io-index"
674 675 checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
675 676 dependencies = [
676 677 "autocfg",
677 678 "libm",
678 679 ]
679 680
680 681 [[package]]
681 682 name = "num_cpus"
682 683 version = "1.13.0"
683 684 source = "registry+https://github.com/rust-lang/crates.io-index"
684 685 checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
685 686 dependencies = [
686 687 "hermit-abi",
687 688 "libc",
688 689 ]
689 690
690 691 [[package]]
691 692 name = "once_cell"
692 693 version = "1.14.0"
693 694 source = "registry+https://github.com/rust-lang/crates.io-index"
694 695 checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
695 696
696 697 [[package]]
697 698 name = "opaque-debug"
698 699 version = "0.3.0"
699 700 source = "registry+https://github.com/rust-lang/crates.io-index"
700 701 checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
701 702
702 703 [[package]]
703 704 name = "ouroboros"
704 705 version = "0.15.0"
705 706 source = "registry+https://github.com/rust-lang/crates.io-index"
706 707 checksum = "9f31a3b678685b150cba82b702dcdc5e155893f63610cf388d30cd988d4ca2bf"
707 708 dependencies = [
708 709 "aliasable",
709 710 "ouroboros_macro",
710 711 "stable_deref_trait",
711 712 ]
712 713
713 714 [[package]]
714 715 name = "ouroboros_macro"
715 716 version = "0.15.0"
716 717 source = "registry+https://github.com/rust-lang/crates.io-index"
717 718 checksum = "084fd65d5dd8b3772edccb5ffd1e4b7eba43897ecd0f9401e330e8c542959408"
718 719 dependencies = [
719 720 "Inflector",
720 721 "proc-macro-error",
721 722 "proc-macro2",
722 723 "quote",
723 724 "syn",
724 725 ]
725 726
726 727 [[package]]
727 728 name = "output_vt100"
728 729 version = "0.1.2"
729 730 source = "registry+https://github.com/rust-lang/crates.io-index"
730 731 checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
731 732 dependencies = [
732 733 "winapi",
733 734 ]
734 735
735 736 [[package]]
736 737 name = "paste"
737 738 version = "1.0.5"
738 739 source = "registry+https://github.com/rust-lang/crates.io-index"
739 740 checksum = "acbf547ad0c65e31259204bd90935776d1c693cec2f4ff7abb7a1bbbd40dfe58"
740 741
741 742 [[package]]
742 743 name = "pkg-config"
743 744 version = "0.3.19"
744 745 source = "registry+https://github.com/rust-lang/crates.io-index"
745 746 checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
746 747
747 748 [[package]]
748 749 name = "ppv-lite86"
749 750 version = "0.2.10"
750 751 source = "registry+https://github.com/rust-lang/crates.io-index"
751 752 checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
752 753
753 754 [[package]]
754 755 name = "pretty_assertions"
755 756 version = "1.1.0"
756 757 source = "registry+https://github.com/rust-lang/crates.io-index"
757 758 checksum = "76d5b548b725018ab5496482b45cb8bef21e9fed1858a6d674e3a8a0f0bb5d50"
758 759 dependencies = [
759 760 "ansi_term",
760 761 "ctor",
761 762 "diff",
762 763 "output_vt100",
763 764 ]
764 765
765 766 [[package]]
766 767 name = "proc-macro-error"
767 768 version = "1.0.4"
768 769 source = "registry+https://github.com/rust-lang/crates.io-index"
769 770 checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
770 771 dependencies = [
771 772 "proc-macro-error-attr",
772 773 "proc-macro2",
773 774 "quote",
774 775 "syn",
775 776 "version_check",
776 777 ]
777 778
778 779 [[package]]
779 780 name = "proc-macro-error-attr"
780 781 version = "1.0.4"
781 782 source = "registry+https://github.com/rust-lang/crates.io-index"
782 783 checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
783 784 dependencies = [
784 785 "proc-macro2",
785 786 "quote",
786 787 "version_check",
787 788 ]
788 789
789 790 [[package]]
790 791 name = "proc-macro2"
791 792 version = "1.0.24"
792 793 source = "registry+https://github.com/rust-lang/crates.io-index"
793 794 checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
794 795 dependencies = [
795 796 "unicode-xid",
796 797 ]
797 798
798 799 [[package]]
799 800 name = "python3-sys"
800 801 version = "0.7.0"
801 802 source = "registry+https://github.com/rust-lang/crates.io-index"
802 803 checksum = "b18b32e64c103d5045f44644d7ddddd65336f7a0521f6fde673240a9ecceb77e"
803 804 dependencies = [
804 805 "libc",
805 806 "regex",
806 807 ]
807 808
808 809 [[package]]
809 810 name = "quote"
810 811 version = "1.0.7"
811 812 source = "registry+https://github.com/rust-lang/crates.io-index"
812 813 checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
813 814 dependencies = [
814 815 "proc-macro2",
815 816 ]
816 817
817 818 [[package]]
818 819 name = "rand"
819 820 version = "0.7.3"
820 821 source = "registry+https://github.com/rust-lang/crates.io-index"
821 822 checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
822 823 dependencies = [
823 824 "getrandom 0.1.15",
824 825 "libc",
825 826 "rand_chacha 0.2.2",
826 827 "rand_core 0.5.1",
827 828 "rand_hc",
828 829 ]
829 830
830 831 [[package]]
831 832 name = "rand"
832 833 version = "0.8.5"
833 834 source = "registry+https://github.com/rust-lang/crates.io-index"
834 835 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
835 836 dependencies = [
836 837 "libc",
837 838 "rand_chacha 0.3.1",
838 839 "rand_core 0.6.3",
839 840 ]
840 841
841 842 [[package]]
842 843 name = "rand_chacha"
843 844 version = "0.2.2"
844 845 source = "registry+https://github.com/rust-lang/crates.io-index"
845 846 checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
846 847 dependencies = [
847 848 "ppv-lite86",
848 849 "rand_core 0.5.1",
849 850 ]
850 851
851 852 [[package]]
852 853 name = "rand_chacha"
853 854 version = "0.3.1"
854 855 source = "registry+https://github.com/rust-lang/crates.io-index"
855 856 checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
856 857 dependencies = [
857 858 "ppv-lite86",
858 859 "rand_core 0.6.3",
859 860 ]
860 861
861 862 [[package]]
862 863 name = "rand_core"
863 864 version = "0.5.1"
864 865 source = "registry+https://github.com/rust-lang/crates.io-index"
865 866 checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
866 867 dependencies = [
867 868 "getrandom 0.1.15",
868 869 ]
869 870
870 871 [[package]]
871 872 name = "rand_core"
872 873 version = "0.6.3"
873 874 source = "registry+https://github.com/rust-lang/crates.io-index"
874 875 checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
875 876 dependencies = [
876 877 "getrandom 0.2.4",
877 878 ]
878 879
879 880 [[package]]
880 881 name = "rand_distr"
881 882 version = "0.4.3"
882 883 source = "registry+https://github.com/rust-lang/crates.io-index"
883 884 checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31"
884 885 dependencies = [
885 886 "num-traits",
886 887 "rand 0.8.5",
887 888 ]
888 889
889 890 [[package]]
890 891 name = "rand_hc"
891 892 version = "0.2.0"
892 893 source = "registry+https://github.com/rust-lang/crates.io-index"
893 894 checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
894 895 dependencies = [
895 896 "rand_core 0.5.1",
896 897 ]
897 898
898 899 [[package]]
899 900 name = "rand_pcg"
900 901 version = "0.3.1"
901 902 source = "registry+https://github.com/rust-lang/crates.io-index"
902 903 checksum = "59cad018caf63deb318e5a4586d99a24424a364f40f1e5778c29aca23f4fc73e"
903 904 dependencies = [
904 905 "rand_core 0.6.3",
905 906 ]
906 907
907 908 [[package]]
908 909 name = "rand_xoshiro"
909 910 version = "0.4.0"
910 911 source = "registry+https://github.com/rust-lang/crates.io-index"
911 912 checksum = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004"
912 913 dependencies = [
913 914 "rand_core 0.5.1",
914 915 ]
915 916
916 917 [[package]]
917 918 name = "rayon"
918 919 version = "1.5.1"
919 920 source = "registry+https://github.com/rust-lang/crates.io-index"
920 921 checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
921 922 dependencies = [
922 923 "autocfg",
923 924 "crossbeam-deque",
924 925 "either",
925 926 "rayon-core",
926 927 ]
927 928
928 929 [[package]]
929 930 name = "rayon-core"
930 931 version = "1.9.1"
931 932 source = "registry+https://github.com/rust-lang/crates.io-index"
932 933 checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
933 934 dependencies = [
934 935 "crossbeam-channel",
935 936 "crossbeam-deque",
936 937 "crossbeam-utils",
937 938 "lazy_static",
938 939 "num_cpus",
939 940 ]
940 941
941 942 [[package]]
942 943 name = "redox_syscall"
943 944 version = "0.2.11"
944 945 source = "registry+https://github.com/rust-lang/crates.io-index"
945 946 checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
946 947 dependencies = [
947 948 "bitflags",
948 949 ]
949 950
950 951 [[package]]
951 952 name = "regex"
952 953 version = "1.5.5"
953 954 source = "registry+https://github.com/rust-lang/crates.io-index"
954 955 checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
955 956 dependencies = [
956 957 "aho-corasick",
957 958 "memchr",
958 959 "regex-syntax",
959 960 ]
960 961
961 962 [[package]]
962 963 name = "regex-syntax"
963 964 version = "0.6.25"
964 965 source = "registry+https://github.com/rust-lang/crates.io-index"
965 966 checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
966 967
967 968 [[package]]
968 969 name = "remove_dir_all"
969 970 version = "0.5.3"
970 971 source = "registry+https://github.com/rust-lang/crates.io-index"
971 972 checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
972 973 dependencies = [
973 974 "winapi",
974 975 ]
975 976
976 977 [[package]]
977 978 name = "rhg"
978 979 version = "0.1.0"
979 980 dependencies = [
980 981 "atty",
981 982 "chrono",
982 983 "clap",
983 984 "derive_more",
984 985 "env_logger",
985 986 "format-bytes",
986 987 "hg-core",
987 988 "home",
988 989 "lazy_static",
989 990 "log",
990 991 "micro-timer",
991 992 "rayon",
992 993 "regex",
993 994 "users",
994 995 "which",
995 996 ]
996 997
997 998 [[package]]
998 999 name = "rustc_version"
999 1000 version = "0.4.0"
1000 1001 source = "registry+https://github.com/rust-lang/crates.io-index"
1001 1002 checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
1002 1003 dependencies = [
1003 1004 "semver",
1004 1005 ]
1005 1006
1006 1007 [[package]]
1007 1008 name = "same-file"
1008 1009 version = "1.0.6"
1009 1010 source = "registry+https://github.com/rust-lang/crates.io-index"
1010 1011 checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
1011 1012 dependencies = [
1012 1013 "winapi-util",
1013 1014 ]
1014 1015
1015 1016 [[package]]
1016 1017 name = "scopeguard"
1017 1018 version = "1.1.0"
1018 1019 source = "registry+https://github.com/rust-lang/crates.io-index"
1019 1020 checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
1020 1021
1021 1022 [[package]]
1022 1023 name = "semver"
1023 1024 version = "1.0.6"
1024 1025 source = "registry+https://github.com/rust-lang/crates.io-index"
1025 1026 checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d"
1026 1027
1027 1028 [[package]]
1028 1029 name = "sha-1"
1029 1030 version = "0.9.6"
1030 1031 source = "registry+https://github.com/rust-lang/crates.io-index"
1031 1032 checksum = "8c4cfa741c5832d0ef7fab46cabed29c2aae926db0b11bb2069edd8db5e64e16"
1032 1033 dependencies = [
1033 1034 "block-buffer 0.9.0",
1034 1035 "cfg-if 1.0.0",
1035 1036 "cpufeatures 0.1.4",
1036 1037 "digest 0.9.0",
1037 1038 "opaque-debug",
1038 1039 ]
1039 1040
1040 1041 [[package]]
1041 1042 name = "sha-1"
1042 1043 version = "0.10.0"
1043 1044 source = "registry+https://github.com/rust-lang/crates.io-index"
1044 1045 checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
1045 1046 dependencies = [
1046 1047 "cfg-if 1.0.0",
1047 1048 "cpufeatures 0.2.1",
1048 1049 "digest 0.10.2",
1049 1050 ]
1050 1051
1051 1052 [[package]]
1052 1053 name = "sized-chunks"
1053 1054 version = "0.6.2"
1054 1055 source = "registry+https://github.com/rust-lang/crates.io-index"
1055 1056 checksum = "1ec31ceca5644fa6d444cc77548b88b67f46db6f7c71683b0f9336e671830d2f"
1056 1057 dependencies = [
1057 1058 "bitmaps",
1058 1059 "typenum",
1059 1060 ]
1060 1061
1061 1062 [[package]]
1062 1063 name = "stable_deref_trait"
1063 1064 version = "1.2.0"
1064 1065 source = "registry+https://github.com/rust-lang/crates.io-index"
1065 1066 checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
1066 1067
1067 1068 [[package]]
1068 1069 name = "static_assertions"
1069 1070 version = "1.1.0"
1070 1071 source = "registry+https://github.com/rust-lang/crates.io-index"
1071 1072 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
1072 1073
1073 1074 [[package]]
1074 1075 name = "strsim"
1075 1076 version = "0.8.0"
1076 1077 source = "registry+https://github.com/rust-lang/crates.io-index"
1077 1078 checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
1078 1079
1079 1080 [[package]]
1080 1081 name = "syn"
1081 1082 version = "1.0.54"
1082 1083 source = "registry+https://github.com/rust-lang/crates.io-index"
1083 1084 checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44"
1084 1085 dependencies = [
1085 1086 "proc-macro2",
1086 1087 "quote",
1087 1088 "unicode-xid",
1088 1089 ]
1089 1090
1090 1091 [[package]]
1091 1092 name = "tempfile"
1092 1093 version = "3.3.0"
1093 1094 source = "registry+https://github.com/rust-lang/crates.io-index"
1094 1095 checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
1095 1096 dependencies = [
1096 1097 "cfg-if 1.0.0",
1097 1098 "fastrand",
1098 1099 "libc",
1099 1100 "redox_syscall",
1100 1101 "remove_dir_all",
1101 1102 "winapi",
1102 1103 ]
1103 1104
1104 1105 [[package]]
1105 1106 name = "termcolor"
1106 1107 version = "1.1.2"
1107 1108 source = "registry+https://github.com/rust-lang/crates.io-index"
1108 1109 checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
1109 1110 dependencies = [
1110 1111 "winapi-util",
1111 1112 ]
1112 1113
1113 1114 [[package]]
1114 1115 name = "textwrap"
1115 1116 version = "0.11.0"
1116 1117 source = "registry+https://github.com/rust-lang/crates.io-index"
1117 1118 checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
1118 1119 dependencies = [
1119 1120 "unicode-width",
1120 1121 ]
1121 1122
1122 1123 [[package]]
1124 name = "thread_local"
1125 version = "1.1.4"
1126 source = "registry+https://github.com/rust-lang/crates.io-index"
1127 checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
1128 dependencies = [
1129 "once_cell",
1130 ]
1131
1132 [[package]]
1123 1133 name = "time"
1124 1134 version = "0.1.44"
1125 1135 source = "registry+https://github.com/rust-lang/crates.io-index"
1126 1136 checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
1127 1137 dependencies = [
1128 1138 "libc",
1129 1139 "wasi 0.10.0+wasi-snapshot-preview1",
1130 1140 "winapi",
1131 1141 ]
1132 1142
1133 1143 [[package]]
1134 1144 name = "twox-hash"
1135 1145 version = "1.6.2"
1136 1146 source = "registry+https://github.com/rust-lang/crates.io-index"
1137 1147 checksum = "4ee73e6e4924fe940354b8d4d98cad5231175d615cd855b758adc658c0aac6a0"
1138 1148 dependencies = [
1139 1149 "cfg-if 1.0.0",
1140 1150 "rand 0.8.5",
1141 1151 "static_assertions",
1142 1152 ]
1143 1153
1144 1154 [[package]]
1145 1155 name = "typenum"
1146 1156 version = "1.12.0"
1147 1157 source = "registry+https://github.com/rust-lang/crates.io-index"
1148 1158 checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
1149 1159
1150 1160 [[package]]
1151 1161 name = "unicode-width"
1152 1162 version = "0.1.9"
1153 1163 source = "registry+https://github.com/rust-lang/crates.io-index"
1154 1164 checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
1155 1165
1156 1166 [[package]]
1157 1167 name = "unicode-xid"
1158 1168 version = "0.2.1"
1159 1169 source = "registry+https://github.com/rust-lang/crates.io-index"
1160 1170 checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
1161 1171
1162 1172 [[package]]
1163 1173 name = "users"
1164 1174 version = "0.11.0"
1165 1175 source = "registry+https://github.com/rust-lang/crates.io-index"
1166 1176 checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032"
1167 1177 dependencies = [
1168 1178 "libc",
1169 1179 "log",
1170 1180 ]
1171 1181
1172 1182 [[package]]
1173 1183 name = "vcpkg"
1174 1184 version = "0.2.11"
1175 1185 source = "registry+https://github.com/rust-lang/crates.io-index"
1176 1186 checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
1177 1187
1178 1188 [[package]]
1179 1189 name = "vcsgraph"
1180 1190 version = "0.2.0"
1181 1191 source = "registry+https://github.com/rust-lang/crates.io-index"
1182 1192 checksum = "4cb68c231e2575f7503a7c19213875f9d4ec2e84e963a56ce3de4b6bee351ef7"
1183 1193 dependencies = [
1184 1194 "hex",
1185 1195 "rand 0.7.3",
1186 1196 "sha-1 0.9.6",
1187 1197 ]
1188 1198
1189 1199 [[package]]
1190 1200 name = "vec_map"
1191 1201 version = "0.8.2"
1192 1202 source = "registry+https://github.com/rust-lang/crates.io-index"
1193 1203 checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
1194 1204
1195 1205 [[package]]
1196 1206 name = "version_check"
1197 1207 version = "0.9.2"
1198 1208 source = "registry+https://github.com/rust-lang/crates.io-index"
1199 1209 checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
1200 1210
1201 1211 [[package]]
1202 1212 name = "wasi"
1203 1213 version = "0.9.0+wasi-snapshot-preview1"
1204 1214 source = "registry+https://github.com/rust-lang/crates.io-index"
1205 1215 checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
1206 1216
1207 1217 [[package]]
1208 1218 name = "wasi"
1209 1219 version = "0.10.0+wasi-snapshot-preview1"
1210 1220 source = "registry+https://github.com/rust-lang/crates.io-index"
1211 1221 checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
1212 1222
1213 1223 [[package]]
1214 1224 name = "which"
1215 1225 version = "4.2.5"
1216 1226 source = "registry+https://github.com/rust-lang/crates.io-index"
1217 1227 checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae"
1218 1228 dependencies = [
1219 1229 "either",
1220 1230 "lazy_static",
1221 1231 "libc",
1222 1232 ]
1223 1233
1224 1234 [[package]]
1225 1235 name = "winapi"
1226 1236 version = "0.3.9"
1227 1237 source = "registry+https://github.com/rust-lang/crates.io-index"
1228 1238 checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1229 1239 dependencies = [
1230 1240 "winapi-i686-pc-windows-gnu",
1231 1241 "winapi-x86_64-pc-windows-gnu",
1232 1242 ]
1233 1243
1234 1244 [[package]]
1235 1245 name = "winapi-i686-pc-windows-gnu"
1236 1246 version = "0.4.0"
1237 1247 source = "registry+https://github.com/rust-lang/crates.io-index"
1238 1248 checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1239 1249
1240 1250 [[package]]
1241 1251 name = "winapi-util"
1242 1252 version = "0.1.5"
1243 1253 source = "registry+https://github.com/rust-lang/crates.io-index"
1244 1254 checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
1245 1255 dependencies = [
1246 1256 "winapi",
1247 1257 ]
1248 1258
1249 1259 [[package]]
1250 1260 name = "winapi-x86_64-pc-windows-gnu"
1251 1261 version = "0.4.0"
1252 1262 source = "registry+https://github.com/rust-lang/crates.io-index"
1253 1263 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1254 1264
1255 1265 [[package]]
1256 1266 name = "zstd"
1257 1267 version = "0.5.4+zstd.1.4.7"
1258 1268 source = "registry+https://github.com/rust-lang/crates.io-index"
1259 1269 checksum = "69996ebdb1ba8b1517f61387a883857818a66c8a295f487b1ffd8fd9d2c82910"
1260 1270 dependencies = [
1261 1271 "zstd-safe",
1262 1272 ]
1263 1273
1264 1274 [[package]]
1265 1275 name = "zstd-safe"
1266 1276 version = "2.0.6+zstd.1.4.7"
1267 1277 source = "registry+https://github.com/rust-lang/crates.io-index"
1268 1278 checksum = "98aa931fb69ecee256d44589d19754e61851ae4769bf963b385119b1cc37a49e"
1269 1279 dependencies = [
1270 1280 "libc",
1271 1281 "zstd-sys",
1272 1282 ]
1273 1283
1274 1284 [[package]]
1275 1285 name = "zstd-sys"
1276 1286 version = "1.4.18+zstd.1.4.7"
1277 1287 source = "registry+https://github.com/rust-lang/crates.io-index"
1278 1288 checksum = "a1e6e8778706838f43f771d80d37787cb2fe06dafe89dd3aebaf6721b9eaec81"
1279 1289 dependencies = [
1280 1290 "cc",
1281 1291 "glob",
1282 1292 "itertools 0.9.0",
1283 1293 "libc",
1284 1294 ]
@@ -1,51 +1,52 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 bitflags = "1.3.2"
13 13 bytes-cast = "0.2.0"
14 14 byteorder = "1.4.3"
15 15 derive_more = "0.99.17"
16 16 hashbrown = { version = "0.9.1", features = ["rayon"] }
17 17 home = "0.5.3"
18 18 im-rc = "15.0"
19 19 itertools = "0.10.3"
20 20 lazy_static = "1.4.0"
21 21 libc = "0.2"
22 22 ouroboros = "0.15.0"
23 23 rand = "0.8.4"
24 24 rand_pcg = "0.3.1"
25 25 rand_distr = "0.4.3"
26 26 rayon = "1.5.1"
27 27 regex = "1.5.5"
28 28 sha-1 = "0.10.0"
29 29 twox-hash = "1.6.2"
30 30 same-file = "1.0.6"
31 31 tempfile = "3.1.0"
32 thread_local = "1.1.4"
32 33 crossbeam-channel = "0.5.0"
33 34 micro-timer = "0.4.0"
34 35 log = "0.4.8"
35 36 memmap2 = { version = "0.5.3", features = ["stable_deref_trait"] }
36 37 zstd = "0.5.3"
37 38 format-bytes = "0.3.0"
38 # once_cell 1.15 uses edition 2021, while the heptapod CI
39 # once_cell 1.15 uses edition 2021, while the heptapod CI
39 40 # uses an old version of Cargo that doesn't support it.
40 41 once_cell = "=1.14.0"
41 42
42 43 # We don't use the `miniz-oxide` backend to not change rhg benchmarks and until
43 44 # we have a clearer view of which backend is the fastest.
44 45 [dependencies.flate2]
45 46 version = "1.0.22"
46 47 features = ["zlib"]
47 48 default-features = false
48 49
49 50 [dev-dependencies]
50 51 clap = "2.34.0"
51 52 pretty_assertions = "1.1.0"
@@ -1,1688 +1,1722 b''
1 1 // matchers.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 8 //! Structs and types for matching files and directories.
9 9
10 10 use crate::{
11 11 dirstate::dirs_multiset::DirsChildrenMultiset,
12 12 filepatterns::{
13 13 build_single_regex, filter_subincludes, get_patterns_from_file,
14 14 PatternFileWarning, PatternResult,
15 15 },
16 16 utils::{
17 17 files::find_dirs,
18 18 hg_path::{HgPath, HgPathBuf},
19 19 Escaped,
20 20 },
21 21 DirsMultiset, DirstateMapError, FastHashMap, IgnorePattern, PatternError,
22 22 PatternSyntax,
23 23 };
24 24
25 25 use crate::dirstate::status::IgnoreFnType;
26 26 use crate::filepatterns::normalize_path_bytes;
27 27 use std::borrow::ToOwned;
28 28 use std::collections::HashSet;
29 29 use std::fmt::{Display, Error, Formatter};
30 30 use std::iter::FromIterator;
31 31 use std::ops::Deref;
32 32 use std::path::{Path, PathBuf};
33 33
34 34 use micro_timer::timed;
35 35
36 36 #[derive(Debug, PartialEq)]
37 37 pub enum VisitChildrenSet {
38 38 /// Don't visit anything
39 39 Empty,
40 40 /// Only visit this directory
41 41 This,
42 42 /// Visit this directory and these subdirectories
43 43 /// TODO Should we implement a `NonEmptyHashSet`?
44 44 Set(HashSet<HgPathBuf>),
45 45 /// Visit this directory and all subdirectories
46 46 Recursive,
47 47 }
48 48
49 49 pub trait Matcher: core::fmt::Debug {
50 50 /// Explicitly listed files
51 51 fn file_set(&self) -> Option<&HashSet<HgPathBuf>>;
52 52 /// Returns whether `filename` is in `file_set`
53 53 fn exact_match(&self, filename: &HgPath) -> bool;
54 54 /// Returns whether `filename` is matched by this matcher
55 55 fn matches(&self, filename: &HgPath) -> bool;
56 56 /// Decides whether a directory should be visited based on whether it
57 57 /// has potential matches in it or one of its subdirectories, and
58 58 /// potentially lists which subdirectories of that directory should be
59 59 /// visited. This is based on the match's primary, included, and excluded
60 60 /// patterns.
61 61 ///
62 62 /// # Example
63 63 ///
64 64 /// Assume matchers `['path:foo/bar', 'rootfilesin:qux']`, we would
65 65 /// return the following values (assuming the implementation of
66 66 /// visit_children_set is capable of recognizing this; some implementations
67 67 /// are not).
68 68 ///
69 69 /// ```text
70 70 /// ```ignore
71 71 /// '' -> {'foo', 'qux'}
72 72 /// 'baz' -> set()
73 73 /// 'foo' -> {'bar'}
74 74 /// // Ideally this would be `Recursive`, but since the prefix nature of
75 75 /// // matchers is applied to the entire matcher, we have to downgrade this
76 76 /// // to `This` due to the (yet to be implemented in Rust) non-prefix
77 77 /// // `RootFilesIn'-kind matcher being mixed in.
78 78 /// 'foo/bar' -> 'this'
79 79 /// 'qux' -> 'this'
80 80 /// ```
81 81 /// # Important
82 82 ///
83 83 /// Most matchers do not know if they're representing files or
84 84 /// directories. They see `['path:dir/f']` and don't know whether `f` is a
85 85 /// file or a directory, so `visit_children_set('dir')` for most matchers
86 86 /// will return `HashSet{ HgPath { "f" } }`, but if the matcher knows it's
87 87 /// a file (like the yet to be implemented in Rust `ExactMatcher` does),
88 88 /// it may return `VisitChildrenSet::This`.
89 89 /// Do not rely on the return being a `HashSet` indicating that there are
90 90 /// no files in this dir to investigate (or equivalently that if there are
91 91 /// files to investigate in 'dir' that it will always return
92 92 /// `VisitChildrenSet::This`).
93 93 fn visit_children_set(&self, directory: &HgPath) -> VisitChildrenSet;
94 94 /// Matcher will match everything and `files_set()` will be empty:
95 95 /// optimization might be possible.
96 96 fn matches_everything(&self) -> bool;
97 97 /// Matcher will match exactly the files in `files_set()`: optimization
98 98 /// might be possible.
99 99 fn is_exact(&self) -> bool;
100 100 }
101 101
102 102 /// Matches everything.
103 103 ///```
104 104 /// use hg::{ matchers::{Matcher, AlwaysMatcher}, utils::hg_path::HgPath };
105 105 ///
106 106 /// let matcher = AlwaysMatcher;
107 107 ///
108 108 /// assert_eq!(matcher.matches(HgPath::new(b"whatever")), true);
109 109 /// assert_eq!(matcher.matches(HgPath::new(b"b.txt")), true);
110 110 /// assert_eq!(matcher.matches(HgPath::new(b"main.c")), true);
111 111 /// assert_eq!(matcher.matches(HgPath::new(br"re:.*\.c$")), true);
112 112 /// ```
113 113 #[derive(Debug)]
114 114 pub struct AlwaysMatcher;
115 115
116 116 impl Matcher for AlwaysMatcher {
117 117 fn file_set(&self) -> Option<&HashSet<HgPathBuf>> {
118 118 None
119 119 }
120 120 fn exact_match(&self, _filename: &HgPath) -> bool {
121 121 false
122 122 }
123 123 fn matches(&self, _filename: &HgPath) -> bool {
124 124 true
125 125 }
126 126 fn visit_children_set(&self, _directory: &HgPath) -> VisitChildrenSet {
127 127 VisitChildrenSet::Recursive
128 128 }
129 129 fn matches_everything(&self) -> bool {
130 130 true
131 131 }
132 132 fn is_exact(&self) -> bool {
133 133 false
134 134 }
135 135 }
136 136
137 137 /// Matches nothing.
138 138 #[derive(Debug)]
139 139 pub struct NeverMatcher;
140 140
141 141 impl Matcher for NeverMatcher {
142 142 fn file_set(&self) -> Option<&HashSet<HgPathBuf>> {
143 143 None
144 144 }
145 145 fn exact_match(&self, _filename: &HgPath) -> bool {
146 146 false
147 147 }
148 148 fn matches(&self, _filename: &HgPath) -> bool {
149 149 false
150 150 }
151 151 fn visit_children_set(&self, _directory: &HgPath) -> VisitChildrenSet {
152 152 VisitChildrenSet::Empty
153 153 }
154 154 fn matches_everything(&self) -> bool {
155 155 false
156 156 }
157 157 fn is_exact(&self) -> bool {
158 158 true
159 159 }
160 160 }
161 161
162 162 /// Matches the input files exactly. They are interpreted as paths, not
163 163 /// patterns.
164 164 ///
165 165 ///```
166 166 /// use hg::{ matchers::{Matcher, FileMatcher}, utils::hg_path::{HgPath, HgPathBuf} };
167 167 ///
168 168 /// let files = vec![HgPathBuf::from_bytes(b"a.txt"), HgPathBuf::from_bytes(br"re:.*\.c$")];
169 169 /// let matcher = FileMatcher::new(files).unwrap();
170 170 ///
171 171 /// assert_eq!(matcher.matches(HgPath::new(b"a.txt")), true);
172 172 /// assert_eq!(matcher.matches(HgPath::new(b"b.txt")), false);
173 173 /// assert_eq!(matcher.matches(HgPath::new(b"main.c")), false);
174 174 /// assert_eq!(matcher.matches(HgPath::new(br"re:.*\.c$")), true);
175 175 /// ```
176 176 #[derive(Debug)]
177 177 pub struct FileMatcher {
178 178 files: HashSet<HgPathBuf>,
179 179 dirs: DirsMultiset,
180 180 }
181 181
182 182 impl FileMatcher {
183 183 pub fn new(files: Vec<HgPathBuf>) -> Result<Self, DirstateMapError> {
184 184 let dirs = DirsMultiset::from_manifest(&files)?;
185 185 Ok(Self {
186 186 files: HashSet::from_iter(files.into_iter()),
187 187 dirs,
188 188 })
189 189 }
190 190 fn inner_matches(&self, filename: &HgPath) -> bool {
191 191 self.files.contains(filename.as_ref())
192 192 }
193 193 }
194 194
195 195 impl Matcher for FileMatcher {
196 196 fn file_set(&self) -> Option<&HashSet<HgPathBuf>> {
197 197 Some(&self.files)
198 198 }
199 199 fn exact_match(&self, filename: &HgPath) -> bool {
200 200 self.inner_matches(filename)
201 201 }
202 202 fn matches(&self, filename: &HgPath) -> bool {
203 203 self.inner_matches(filename)
204 204 }
205 205 fn visit_children_set(&self, directory: &HgPath) -> VisitChildrenSet {
206 206 if self.files.is_empty() || !self.dirs.contains(&directory) {
207 207 return VisitChildrenSet::Empty;
208 208 }
209 209 let mut candidates: HashSet<HgPathBuf> =
210 210 self.dirs.iter().cloned().collect();
211 211
212 212 candidates.extend(self.files.iter().cloned());
213 213 candidates.remove(HgPath::new(b""));
214 214
215 215 if !directory.as_ref().is_empty() {
216 216 let directory = [directory.as_ref().as_bytes(), b"/"].concat();
217 217 candidates = candidates
218 218 .iter()
219 219 .filter_map(|c| {
220 220 if c.as_bytes().starts_with(&directory) {
221 221 Some(HgPathBuf::from_bytes(
222 222 &c.as_bytes()[directory.len()..],
223 223 ))
224 224 } else {
225 225 None
226 226 }
227 227 })
228 228 .collect();
229 229 }
230 230
231 231 // `self.dirs` includes all of the directories, recursively, so if
232 232 // we're attempting to match 'foo/bar/baz.txt', it'll have '', 'foo',
233 233 // 'foo/bar' in it. Thus we can safely ignore a candidate that has a
234 234 // '/' in it, indicating it's for a subdir-of-a-subdir; the immediate
235 235 // subdir will be in there without a slash.
236 236 VisitChildrenSet::Set(
237 237 candidates
238 238 .into_iter()
239 239 .filter_map(|c| {
240 240 if c.bytes().all(|b| *b != b'/') {
241 241 Some(c)
242 242 } else {
243 243 None
244 244 }
245 245 })
246 246 .collect(),
247 247 )
248 248 }
249 249 fn matches_everything(&self) -> bool {
250 250 false
251 251 }
252 252 fn is_exact(&self) -> bool {
253 253 true
254 254 }
255 255 }
256 256
257 257 /// Matches files that are included in the ignore rules.
258 258 /// ```
259 259 /// use hg::{
260 260 /// matchers::{IncludeMatcher, Matcher},
261 261 /// IgnorePattern,
262 262 /// PatternSyntax,
263 263 /// utils::hg_path::HgPath
264 264 /// };
265 265 /// use std::path::Path;
266 266 /// ///
267 267 /// let ignore_patterns =
268 268 /// vec![IgnorePattern::new(PatternSyntax::RootGlob, b"this*", Path::new(""))];
269 269 /// let matcher = IncludeMatcher::new(ignore_patterns).unwrap();
270 270 /// ///
271 271 /// assert_eq!(matcher.matches(HgPath::new(b"testing")), false);
272 272 /// assert_eq!(matcher.matches(HgPath::new(b"this should work")), true);
273 273 /// assert_eq!(matcher.matches(HgPath::new(b"this also")), true);
274 274 /// assert_eq!(matcher.matches(HgPath::new(b"but not this")), false);
275 275 /// ```
276 276 pub struct IncludeMatcher<'a> {
277 277 patterns: Vec<u8>,
278 278 match_fn: IgnoreFnType<'a>,
279 279 /// Whether all the patterns match a prefix (i.e. recursively)
280 280 prefix: bool,
281 281 roots: HashSet<HgPathBuf>,
282 282 dirs: HashSet<HgPathBuf>,
283 283 parents: HashSet<HgPathBuf>,
284 284 }
285 285
286 286 impl core::fmt::Debug for IncludeMatcher<'_> {
287 287 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
288 288 f.debug_struct("IncludeMatcher")
289 289 .field("patterns", &String::from_utf8_lossy(&self.patterns))
290 290 .field("prefix", &self.prefix)
291 291 .field("roots", &self.roots)
292 292 .field("dirs", &self.dirs)
293 293 .field("parents", &self.parents)
294 294 .finish()
295 295 }
296 296 }
297 297
298 298 impl<'a> Matcher for IncludeMatcher<'a> {
299 299 fn file_set(&self) -> Option<&HashSet<HgPathBuf>> {
300 300 None
301 301 }
302 302
303 303 fn exact_match(&self, _filename: &HgPath) -> bool {
304 304 false
305 305 }
306 306
307 307 fn matches(&self, filename: &HgPath) -> bool {
308 308 (self.match_fn)(filename.as_ref())
309 309 }
310 310
311 311 fn visit_children_set(&self, directory: &HgPath) -> VisitChildrenSet {
312 312 let dir = directory.as_ref();
313 313 if self.prefix && self.roots.contains(dir) {
314 314 return VisitChildrenSet::Recursive;
315 315 }
316 316 if self.roots.contains(HgPath::new(b""))
317 317 || self.roots.contains(dir)
318 318 || self.dirs.contains(dir)
319 319 || find_dirs(dir).any(|parent_dir| self.roots.contains(parent_dir))
320 320 {
321 321 return VisitChildrenSet::This;
322 322 }
323 323
324 324 if self.parents.contains(directory.as_ref()) {
325 325 let multiset = self.get_all_parents_children();
326 326 if let Some(children) = multiset.get(dir) {
327 327 return VisitChildrenSet::Set(
328 328 children.into_iter().map(HgPathBuf::from).collect(),
329 329 );
330 330 }
331 331 }
332 332 VisitChildrenSet::Empty
333 333 }
334 334
335 335 fn matches_everything(&self) -> bool {
336 336 false
337 337 }
338 338
339 339 fn is_exact(&self) -> bool {
340 340 false
341 341 }
342 342 }
343 343
344 344 /// The union of multiple matchers. Will match if any of the matchers match.
345 345 #[derive(Debug)]
346 346 pub struct UnionMatcher {
347 347 matchers: Vec<Box<dyn Matcher + Sync>>,
348 348 }
349 349
350 350 impl Matcher for UnionMatcher {
351 351 fn file_set(&self) -> Option<&HashSet<HgPathBuf>> {
352 352 None
353 353 }
354 354
355 355 fn exact_match(&self, _filename: &HgPath) -> bool {
356 356 false
357 357 }
358 358
359 359 fn matches(&self, filename: &HgPath) -> bool {
360 360 self.matchers.iter().any(|m| m.matches(filename))
361 361 }
362 362
363 363 fn visit_children_set(&self, directory: &HgPath) -> VisitChildrenSet {
364 364 let mut result = HashSet::new();
365 365 let mut this = false;
366 366 for matcher in self.matchers.iter() {
367 367 let visit = matcher.visit_children_set(directory);
368 368 match visit {
369 369 VisitChildrenSet::Empty => continue,
370 370 VisitChildrenSet::This => {
371 371 this = true;
372 372 // Don't break, we might have an 'all' in here.
373 373 continue;
374 374 }
375 375 VisitChildrenSet::Set(set) => {
376 376 result.extend(set);
377 377 }
378 378 VisitChildrenSet::Recursive => {
379 379 return visit;
380 380 }
381 381 }
382 382 }
383 383 if this {
384 384 return VisitChildrenSet::This;
385 385 }
386 386 if result.is_empty() {
387 387 VisitChildrenSet::Empty
388 388 } else {
389 389 VisitChildrenSet::Set(result)
390 390 }
391 391 }
392 392
393 393 fn matches_everything(&self) -> bool {
394 394 // TODO Maybe if all are AlwaysMatcher?
395 395 false
396 396 }
397 397
398 398 fn is_exact(&self) -> bool {
399 399 false
400 400 }
401 401 }
402 402
403 403 impl UnionMatcher {
404 404 pub fn new(matchers: Vec<Box<dyn Matcher + Sync>>) -> Self {
405 405 Self { matchers }
406 406 }
407 407 }
408 408
409 409 #[derive(Debug)]
410 410 pub struct IntersectionMatcher {
411 411 m1: Box<dyn Matcher + Sync>,
412 412 m2: Box<dyn Matcher + Sync>,
413 413 files: Option<HashSet<HgPathBuf>>,
414 414 }
415 415
416 416 impl Matcher for IntersectionMatcher {
417 417 fn file_set(&self) -> Option<&HashSet<HgPathBuf>> {
418 418 self.files.as_ref()
419 419 }
420 420
421 421 fn exact_match(&self, filename: &HgPath) -> bool {
422 422 self.files.as_ref().map_or(false, |f| f.contains(filename))
423 423 }
424 424
425 425 fn matches(&self, filename: &HgPath) -> bool {
426 426 self.m1.matches(filename) && self.m2.matches(filename)
427 427 }
428 428
429 429 fn visit_children_set(&self, directory: &HgPath) -> VisitChildrenSet {
430 430 let m1_set = self.m1.visit_children_set(directory);
431 431 if m1_set == VisitChildrenSet::Empty {
432 432 return VisitChildrenSet::Empty;
433 433 }
434 434 let m2_set = self.m2.visit_children_set(directory);
435 435 if m2_set == VisitChildrenSet::Empty {
436 436 return VisitChildrenSet::Empty;
437 437 }
438 438
439 439 if m1_set == VisitChildrenSet::Recursive {
440 440 return m2_set;
441 441 } else if m2_set == VisitChildrenSet::Recursive {
442 442 return m1_set;
443 443 }
444 444
445 445 match (&m1_set, &m2_set) {
446 446 (VisitChildrenSet::Recursive, _) => m2_set,
447 447 (_, VisitChildrenSet::Recursive) => m1_set,
448 448 (VisitChildrenSet::This, _) | (_, VisitChildrenSet::This) => {
449 449 VisitChildrenSet::This
450 450 }
451 451 (VisitChildrenSet::Set(m1), VisitChildrenSet::Set(m2)) => {
452 452 let set: HashSet<_> = m1.intersection(&m2).cloned().collect();
453 453 if set.is_empty() {
454 454 VisitChildrenSet::Empty
455 455 } else {
456 456 VisitChildrenSet::Set(set)
457 457 }
458 458 }
459 459 _ => unreachable!(),
460 460 }
461 461 }
462 462
463 463 fn matches_everything(&self) -> bool {
464 464 self.m1.matches_everything() && self.m2.matches_everything()
465 465 }
466 466
467 467 fn is_exact(&self) -> bool {
468 468 self.m1.is_exact() || self.m2.is_exact()
469 469 }
470 470 }
471 471
472 472 impl IntersectionMatcher {
473 473 pub fn new(
474 474 mut m1: Box<dyn Matcher + Sync>,
475 475 mut m2: Box<dyn Matcher + Sync>,
476 476 ) -> Self {
477 477 let files = if m1.is_exact() || m2.is_exact() {
478 478 if !m1.is_exact() {
479 479 std::mem::swap(&mut m1, &mut m2);
480 480 }
481 481 m1.file_set().map(|m1_files| {
482 482 m1_files.iter().cloned().filter(|f| m2.matches(f)).collect()
483 483 })
484 484 } else {
485 485 None
486 486 };
487 487 Self { m1, m2, files }
488 488 }
489 489 }
490 490
491 491 #[derive(Debug)]
492 492 pub struct DifferenceMatcher {
493 493 base: Box<dyn Matcher + Sync>,
494 494 excluded: Box<dyn Matcher + Sync>,
495 495 files: Option<HashSet<HgPathBuf>>,
496 496 }
497 497
498 498 impl Matcher for DifferenceMatcher {
499 499 fn file_set(&self) -> Option<&HashSet<HgPathBuf>> {
500 500 self.files.as_ref()
501 501 }
502 502
503 503 fn exact_match(&self, filename: &HgPath) -> bool {
504 504 self.files.as_ref().map_or(false, |f| f.contains(filename))
505 505 }
506 506
507 507 fn matches(&self, filename: &HgPath) -> bool {
508 508 self.base.matches(filename) && !self.excluded.matches(filename)
509 509 }
510 510
511 511 fn visit_children_set(&self, directory: &HgPath) -> VisitChildrenSet {
512 512 let excluded_set = self.excluded.visit_children_set(directory);
513 513 if excluded_set == VisitChildrenSet::Recursive {
514 514 return VisitChildrenSet::Empty;
515 515 }
516 516 let base_set = self.base.visit_children_set(directory);
517 517 // Possible values for base: 'recursive', 'this', set(...), set()
518 518 // Possible values for excluded: 'this', set(...), set()
519 519 // If excluded has nothing under here that we care about, return base,
520 520 // even if it's 'recursive'.
521 521 if excluded_set == VisitChildrenSet::Empty {
522 522 return base_set;
523 523 }
524 524 match base_set {
525 525 VisitChildrenSet::This | VisitChildrenSet::Recursive => {
526 526 // Never return 'recursive' here if excluded_set is any kind of
527 527 // non-empty (either 'this' or set(foo)), since excluded might
528 528 // return set() for a subdirectory.
529 529 VisitChildrenSet::This
530 530 }
531 531 set => {
532 532 // Possible values for base: set(...), set()
533 533 // Possible values for excluded: 'this', set(...)
534 534 // We ignore excluded set results. They're possibly incorrect:
535 535 // base = path:dir/subdir
536 536 // excluded=rootfilesin:dir,
537 537 // visit_children_set(''):
538 538 // base returns {'dir'}, excluded returns {'dir'}, if we
539 539 // subtracted we'd return set(), which is *not* correct, we
540 540 // still need to visit 'dir'!
541 541 set
542 542 }
543 543 }
544 544 }
545 545
546 546 fn matches_everything(&self) -> bool {
547 547 false
548 548 }
549 549
550 550 fn is_exact(&self) -> bool {
551 551 self.base.is_exact()
552 552 }
553 553 }
554 554
555 555 impl DifferenceMatcher {
556 556 pub fn new(
557 557 base: Box<dyn Matcher + Sync>,
558 558 excluded: Box<dyn Matcher + Sync>,
559 559 ) -> Self {
560 560 let base_is_exact = base.is_exact();
561 561 let base_files = base.file_set().map(ToOwned::to_owned);
562 562 let mut new = Self {
563 563 base,
564 564 excluded,
565 565 files: None,
566 566 };
567 567 if base_is_exact {
568 568 new.files = base_files.map(|files| {
569 569 files.iter().cloned().filter(|f| new.matches(f)).collect()
570 570 });
571 571 }
572 572 new
573 573 }
574 574 }
575 575
576 /// Wraps [`regex::bytes::Regex`] to improve performance in multithreaded
577 /// contexts.
578 ///
579 /// The `status` algorithm makes heavy use of threads, and calling `is_match`
580 /// from many threads at once is prone to contention, probably within the
581 /// scratch space needed as the regex DFA is built lazily.
582 ///
583 /// We are in the process of raising the issue upstream, but for now
584 /// the workaround used here is to store the `Regex` in a lazily populated
585 /// thread-local variable, sharing the initial read-only compilation, but
586 /// not the lazy dfa scratch space mentioned above.
587 ///
588 /// This reduces the contention observed with 16+ threads, but does not
589 /// completely remove it. Hopefully this can be addressed upstream.
590 struct RegexMatcher {
591 /// Compiled at the start of the status algorithm, used as a base for
592 /// cloning in each thread-local `self.local`, thus sharing the expensive
593 /// first compilation.
594 base: regex::bytes::Regex,
595 /// Thread-local variable that holds the `Regex` that is actually queried
596 /// from each thread.
597 local: thread_local::ThreadLocal<regex::bytes::Regex>,
598 }
599
600 impl RegexMatcher {
601 /// Returns whether the path matches the stored `Regex`.
602 pub fn is_match(&self, path: &HgPath) -> bool {
603 self.local
604 .get_or(|| self.base.clone())
605 .is_match(path.as_bytes())
606 }
607 }
608
576 609 /// Returns a function that matches an `HgPath` against the given regex
577 610 /// pattern.
578 611 ///
579 612 /// This can fail when the pattern is invalid or not supported by the
580 613 /// underlying engine (the `regex` crate), for instance anything with
581 614 /// back-references.
582 615 #[timed]
583 fn re_matcher(
584 pattern: &[u8],
585 ) -> PatternResult<impl Fn(&HgPath) -> bool + Sync> {
616 fn re_matcher(pattern: &[u8]) -> PatternResult<RegexMatcher> {
586 617 use std::io::Write;
587 618
588 619 // The `regex` crate adds `.*` to the start and end of expressions if there
589 620 // are no anchors, so add the start anchor.
590 621 let mut escaped_bytes = vec![b'^', b'(', b'?', b':'];
591 622 for byte in pattern {
592 623 if *byte > 127 {
593 624 write!(escaped_bytes, "\\x{:x}", *byte).unwrap();
594 625 } else {
595 626 escaped_bytes.push(*byte);
596 627 }
597 628 }
598 629 escaped_bytes.push(b')');
599 630
600 631 // Avoid the cost of UTF8 checking
601 632 //
602 633 // # Safety
603 634 // This is safe because we escaped all non-ASCII bytes.
604 635 let pattern_string = unsafe { String::from_utf8_unchecked(escaped_bytes) };
605 636 let re = regex::bytes::RegexBuilder::new(&pattern_string)
606 637 .unicode(false)
607 638 // Big repos with big `.hgignore` will hit the default limit and
608 639 // incur a significant performance hit. One repo's `hg status` hit
609 640 // multiple *minutes*.
610 641 .dfa_size_limit(50 * (1 << 20))
611 642 .build()
612 643 .map_err(|e| PatternError::UnsupportedSyntax(e.to_string()))?;
613 644
614 Ok(move |path: &HgPath| re.is_match(path.as_bytes()))
645 Ok(RegexMatcher {
646 base: re,
647 local: Default::default(),
648 })
615 649 }
616 650
617 651 /// Returns the regex pattern and a function that matches an `HgPath` against
618 652 /// said regex formed by the given ignore patterns.
619 653 fn build_regex_match<'a, 'b>(
620 654 ignore_patterns: &'a [IgnorePattern],
621 655 ) -> PatternResult<(Vec<u8>, IgnoreFnType<'b>)> {
622 656 let mut regexps = vec![];
623 657 let mut exact_set = HashSet::new();
624 658
625 659 for pattern in ignore_patterns {
626 660 if let Some(re) = build_single_regex(pattern)? {
627 661 regexps.push(re);
628 662 } else {
629 663 let exact = normalize_path_bytes(&pattern.pattern);
630 664 exact_set.insert(HgPathBuf::from_bytes(&exact));
631 665 }
632 666 }
633 667
634 668 let full_regex = regexps.join(&b'|');
635 669
636 670 // An empty pattern would cause the regex engine to incorrectly match the
637 671 // (empty) root directory
638 672 let func = if !(regexps.is_empty()) {
639 673 let matcher = re_matcher(&full_regex)?;
640 674 let func = move |filename: &HgPath| {
641 exact_set.contains(filename) || matcher(filename)
675 exact_set.contains(filename) || matcher.is_match(filename)
642 676 };
643 677 Box::new(func) as IgnoreFnType
644 678 } else {
645 679 let func = move |filename: &HgPath| exact_set.contains(filename);
646 680 Box::new(func) as IgnoreFnType
647 681 };
648 682
649 683 Ok((full_regex, func))
650 684 }
651 685
652 686 /// Returns roots and directories corresponding to each pattern.
653 687 ///
654 688 /// This calculates the roots and directories exactly matching the patterns and
655 689 /// returns a tuple of (roots, dirs). It does not return other directories
656 690 /// which may also need to be considered, like the parent directories.
657 691 fn roots_and_dirs(
658 692 ignore_patterns: &[IgnorePattern],
659 693 ) -> (Vec<HgPathBuf>, Vec<HgPathBuf>) {
660 694 let mut roots = Vec::new();
661 695 let mut dirs = Vec::new();
662 696
663 697 for ignore_pattern in ignore_patterns {
664 698 let IgnorePattern {
665 699 syntax, pattern, ..
666 700 } = ignore_pattern;
667 701 match syntax {
668 702 PatternSyntax::RootGlob | PatternSyntax::Glob => {
669 703 let mut root = HgPathBuf::new();
670 704 for p in pattern.split(|c| *c == b'/') {
671 705 if p.iter().any(|c| match *c {
672 706 b'[' | b'{' | b'*' | b'?' => true,
673 707 _ => false,
674 708 }) {
675 709 break;
676 710 }
677 711 root.push(HgPathBuf::from_bytes(p).as_ref());
678 712 }
679 713 roots.push(root);
680 714 }
681 715 PatternSyntax::Path | PatternSyntax::RelPath => {
682 716 let pat = HgPath::new(if pattern == b"." {
683 717 &[] as &[u8]
684 718 } else {
685 719 pattern
686 720 });
687 721 roots.push(pat.to_owned());
688 722 }
689 723 PatternSyntax::RootFiles => {
690 724 let pat = if pattern == b"." {
691 725 &[] as &[u8]
692 726 } else {
693 727 pattern
694 728 };
695 729 dirs.push(HgPathBuf::from_bytes(pat));
696 730 }
697 731 _ => {
698 732 roots.push(HgPathBuf::new());
699 733 }
700 734 }
701 735 }
702 736 (roots, dirs)
703 737 }
704 738
705 739 /// Paths extracted from patterns
706 740 #[derive(Debug, PartialEq)]
707 741 struct RootsDirsAndParents {
708 742 /// Directories to match recursively
709 743 pub roots: HashSet<HgPathBuf>,
710 744 /// Directories to match non-recursively
711 745 pub dirs: HashSet<HgPathBuf>,
712 746 /// Implicitly required directories to go to items in either roots or dirs
713 747 pub parents: HashSet<HgPathBuf>,
714 748 }
715 749
716 750 /// Extract roots, dirs and parents from patterns.
717 751 fn roots_dirs_and_parents(
718 752 ignore_patterns: &[IgnorePattern],
719 753 ) -> PatternResult<RootsDirsAndParents> {
720 754 let (roots, dirs) = roots_and_dirs(ignore_patterns);
721 755
722 756 let mut parents = HashSet::new();
723 757
724 758 parents.extend(
725 759 DirsMultiset::from_manifest(&dirs)
726 760 .map_err(|e| match e {
727 761 DirstateMapError::InvalidPath(e) => e,
728 762 _ => unreachable!(),
729 763 })?
730 764 .iter()
731 765 .map(ToOwned::to_owned),
732 766 );
733 767 parents.extend(
734 768 DirsMultiset::from_manifest(&roots)
735 769 .map_err(|e| match e {
736 770 DirstateMapError::InvalidPath(e) => e,
737 771 _ => unreachable!(),
738 772 })?
739 773 .iter()
740 774 .map(ToOwned::to_owned),
741 775 );
742 776
743 777 Ok(RootsDirsAndParents {
744 778 roots: HashSet::from_iter(roots),
745 779 dirs: HashSet::from_iter(dirs),
746 780 parents,
747 781 })
748 782 }
749 783
750 784 /// Returns a function that checks whether a given file (in the general sense)
751 785 /// should be matched.
752 786 fn build_match<'a, 'b>(
753 787 ignore_patterns: Vec<IgnorePattern>,
754 788 ) -> PatternResult<(Vec<u8>, IgnoreFnType<'b>)> {
755 789 let mut match_funcs: Vec<IgnoreFnType<'b>> = vec![];
756 790 // For debugging and printing
757 791 let mut patterns = vec![];
758 792
759 793 let (subincludes, ignore_patterns) = filter_subincludes(ignore_patterns)?;
760 794
761 795 if !subincludes.is_empty() {
762 796 // Build prefix-based matcher functions for subincludes
763 797 let mut submatchers = FastHashMap::default();
764 798 let mut prefixes = vec![];
765 799
766 800 for sub_include in subincludes {
767 801 let matcher = IncludeMatcher::new(sub_include.included_patterns)?;
768 802 let match_fn =
769 803 Box::new(move |path: &HgPath| matcher.matches(path));
770 804 prefixes.push(sub_include.prefix.clone());
771 805 submatchers.insert(sub_include.prefix.clone(), match_fn);
772 806 }
773 807
774 808 let match_subinclude = move |filename: &HgPath| {
775 809 for prefix in prefixes.iter() {
776 810 if let Some(rel) = filename.relative_to(prefix) {
777 811 if (submatchers[prefix])(rel) {
778 812 return true;
779 813 }
780 814 }
781 815 }
782 816 false
783 817 };
784 818
785 819 match_funcs.push(Box::new(match_subinclude));
786 820 }
787 821
788 822 if !ignore_patterns.is_empty() {
789 823 // Either do dumb matching if all patterns are rootfiles, or match
790 824 // with a regex.
791 825 if ignore_patterns
792 826 .iter()
793 827 .all(|k| k.syntax == PatternSyntax::RootFiles)
794 828 {
795 829 let dirs: HashSet<_> = ignore_patterns
796 830 .iter()
797 831 .map(|k| k.pattern.to_owned())
798 832 .collect();
799 833 let mut dirs_vec: Vec<_> = dirs.iter().cloned().collect();
800 834
801 835 let match_func = move |path: &HgPath| -> bool {
802 836 let path = path.as_bytes();
803 837 let i = path.iter().rfind(|a| **a == b'/');
804 838 let dir = if let Some(i) = i {
805 839 &path[..*i as usize]
806 840 } else {
807 841 b"."
808 842 };
809 843 dirs.contains(dir.deref())
810 844 };
811 845 match_funcs.push(Box::new(match_func));
812 846
813 847 patterns.extend(b"rootfilesin: ");
814 848 dirs_vec.sort();
815 849 patterns.extend(dirs_vec.escaped_bytes());
816 850 } else {
817 851 let (new_re, match_func) = build_regex_match(&ignore_patterns)?;
818 852 patterns = new_re;
819 853 match_funcs.push(match_func)
820 854 }
821 855 }
822 856
823 857 Ok(if match_funcs.len() == 1 {
824 858 (patterns, match_funcs.remove(0))
825 859 } else {
826 860 (
827 861 patterns,
828 862 Box::new(move |f: &HgPath| -> bool {
829 863 match_funcs.iter().any(|match_func| match_func(f))
830 864 }),
831 865 )
832 866 })
833 867 }
834 868
835 869 /// Parses all "ignore" files with their recursive includes and returns a
836 870 /// function that checks whether a given file (in the general sense) should be
837 871 /// ignored.
838 872 pub fn get_ignore_matcher<'a>(
839 873 mut all_pattern_files: Vec<PathBuf>,
840 874 root_dir: &Path,
841 875 inspect_pattern_bytes: &mut impl FnMut(&Path, &[u8]),
842 876 ) -> PatternResult<(IncludeMatcher<'a>, Vec<PatternFileWarning>)> {
843 877 let mut all_patterns = vec![];
844 878 let mut all_warnings = vec![];
845 879
846 880 // Sort to make the ordering of calls to `inspect_pattern_bytes`
847 881 // deterministic even if the ordering of `all_pattern_files` is not (such
848 882 // as when a iteration order of a Python dict or Rust HashMap is involved).
849 883 // Sort by "string" representation instead of the default by component
850 884 // (with a Rust-specific definition of a component)
851 885 all_pattern_files
852 886 .sort_unstable_by(|a, b| a.as_os_str().cmp(b.as_os_str()));
853 887
854 888 for pattern_file in &all_pattern_files {
855 889 let (patterns, warnings) = get_patterns_from_file(
856 890 pattern_file,
857 891 root_dir,
858 892 inspect_pattern_bytes,
859 893 )?;
860 894
861 895 all_patterns.extend(patterns.to_owned());
862 896 all_warnings.extend(warnings);
863 897 }
864 898 let matcher = IncludeMatcher::new(all_patterns)?;
865 899 Ok((matcher, all_warnings))
866 900 }
867 901
868 902 /// Parses all "ignore" files with their recursive includes and returns a
869 903 /// function that checks whether a given file (in the general sense) should be
870 904 /// ignored.
871 905 pub fn get_ignore_function<'a>(
872 906 all_pattern_files: Vec<PathBuf>,
873 907 root_dir: &Path,
874 908 inspect_pattern_bytes: &mut impl FnMut(&Path, &[u8]),
875 909 ) -> PatternResult<(IgnoreFnType<'a>, Vec<PatternFileWarning>)> {
876 910 let res =
877 911 get_ignore_matcher(all_pattern_files, root_dir, inspect_pattern_bytes);
878 912 res.map(|(matcher, all_warnings)| {
879 913 let res: IgnoreFnType<'a> =
880 914 Box::new(move |path: &HgPath| matcher.matches(path));
881 915
882 916 (res, all_warnings)
883 917 })
884 918 }
885 919
886 920 impl<'a> IncludeMatcher<'a> {
887 921 pub fn new(ignore_patterns: Vec<IgnorePattern>) -> PatternResult<Self> {
888 922 let RootsDirsAndParents {
889 923 roots,
890 924 dirs,
891 925 parents,
892 926 } = roots_dirs_and_parents(&ignore_patterns)?;
893 927 let prefix = ignore_patterns.iter().all(|k| match k.syntax {
894 928 PatternSyntax::Path | PatternSyntax::RelPath => true,
895 929 _ => false,
896 930 });
897 931 let (patterns, match_fn) = build_match(ignore_patterns)?;
898 932
899 933 Ok(Self {
900 934 patterns,
901 935 match_fn,
902 936 prefix,
903 937 roots,
904 938 dirs,
905 939 parents,
906 940 })
907 941 }
908 942
909 943 fn get_all_parents_children(&self) -> DirsChildrenMultiset {
910 944 // TODO cache
911 945 let thing = self
912 946 .dirs
913 947 .iter()
914 948 .chain(self.roots.iter())
915 949 .chain(self.parents.iter());
916 950 DirsChildrenMultiset::new(thing, Some(&self.parents))
917 951 }
918 952
919 953 pub fn debug_get_patterns(&self) -> &[u8] {
920 954 self.patterns.as_ref()
921 955 }
922 956 }
923 957
924 958 impl<'a> Display for IncludeMatcher<'a> {
925 959 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
926 960 // XXX What about exact matches?
927 961 // I'm not sure it's worth it to clone the HashSet and keep it
928 962 // around just in case someone wants to display the matcher, plus
929 963 // it's going to be unreadable after a few entries, but we need to
930 964 // inform in this display that exact matches are being used and are
931 965 // (on purpose) missing from the `includes`.
932 966 write!(
933 967 f,
934 968 "IncludeMatcher(includes='{}')",
935 969 String::from_utf8_lossy(&self.patterns.escaped_bytes())
936 970 )
937 971 }
938 972 }
939 973
940 974 #[cfg(test)]
941 975 mod tests {
942 976 use super::*;
943 977 use pretty_assertions::assert_eq;
944 978 use std::path::Path;
945 979
946 980 #[test]
947 981 fn test_roots_and_dirs() {
948 982 let pats = vec![
949 983 IgnorePattern::new(PatternSyntax::Glob, b"g/h/*", Path::new("")),
950 984 IgnorePattern::new(PatternSyntax::Glob, b"g/h", Path::new("")),
951 985 IgnorePattern::new(PatternSyntax::Glob, b"g*", Path::new("")),
952 986 ];
953 987 let (roots, dirs) = roots_and_dirs(&pats);
954 988
955 989 assert_eq!(
956 990 roots,
957 991 vec!(
958 992 HgPathBuf::from_bytes(b"g/h"),
959 993 HgPathBuf::from_bytes(b"g/h"),
960 994 HgPathBuf::new()
961 995 ),
962 996 );
963 997 assert_eq!(dirs, vec!());
964 998 }
965 999
966 1000 #[test]
967 1001 fn test_roots_dirs_and_parents() {
968 1002 let pats = vec![
969 1003 IgnorePattern::new(PatternSyntax::Glob, b"g/h/*", Path::new("")),
970 1004 IgnorePattern::new(PatternSyntax::Glob, b"g/h", Path::new("")),
971 1005 IgnorePattern::new(PatternSyntax::Glob, b"g*", Path::new("")),
972 1006 ];
973 1007
974 1008 let mut roots = HashSet::new();
975 1009 roots.insert(HgPathBuf::from_bytes(b"g/h"));
976 1010 roots.insert(HgPathBuf::new());
977 1011
978 1012 let dirs = HashSet::new();
979 1013
980 1014 let mut parents = HashSet::new();
981 1015 parents.insert(HgPathBuf::new());
982 1016 parents.insert(HgPathBuf::from_bytes(b"g"));
983 1017
984 1018 assert_eq!(
985 1019 roots_dirs_and_parents(&pats).unwrap(),
986 1020 RootsDirsAndParents {
987 1021 roots,
988 1022 dirs,
989 1023 parents
990 1024 }
991 1025 );
992 1026 }
993 1027
994 1028 #[test]
995 1029 fn test_filematcher_visit_children_set() {
996 1030 // Visitchildrenset
997 1031 let files = vec![HgPathBuf::from_bytes(b"dir/subdir/foo.txt")];
998 1032 let matcher = FileMatcher::new(files).unwrap();
999 1033
1000 1034 let mut set = HashSet::new();
1001 1035 set.insert(HgPathBuf::from_bytes(b"dir"));
1002 1036 assert_eq!(
1003 1037 matcher.visit_children_set(HgPath::new(b"")),
1004 1038 VisitChildrenSet::Set(set)
1005 1039 );
1006 1040
1007 1041 let mut set = HashSet::new();
1008 1042 set.insert(HgPathBuf::from_bytes(b"subdir"));
1009 1043 assert_eq!(
1010 1044 matcher.visit_children_set(HgPath::new(b"dir")),
1011 1045 VisitChildrenSet::Set(set)
1012 1046 );
1013 1047
1014 1048 let mut set = HashSet::new();
1015 1049 set.insert(HgPathBuf::from_bytes(b"foo.txt"));
1016 1050 assert_eq!(
1017 1051 matcher.visit_children_set(HgPath::new(b"dir/subdir")),
1018 1052 VisitChildrenSet::Set(set)
1019 1053 );
1020 1054
1021 1055 assert_eq!(
1022 1056 matcher.visit_children_set(HgPath::new(b"dir/subdir/x")),
1023 1057 VisitChildrenSet::Empty
1024 1058 );
1025 1059 assert_eq!(
1026 1060 matcher.visit_children_set(HgPath::new(b"dir/subdir/foo.txt")),
1027 1061 VisitChildrenSet::Empty
1028 1062 );
1029 1063 assert_eq!(
1030 1064 matcher.visit_children_set(HgPath::new(b"folder")),
1031 1065 VisitChildrenSet::Empty
1032 1066 );
1033 1067 }
1034 1068
1035 1069 #[test]
1036 1070 fn test_filematcher_visit_children_set_files_and_dirs() {
1037 1071 let files = vec![
1038 1072 HgPathBuf::from_bytes(b"rootfile.txt"),
1039 1073 HgPathBuf::from_bytes(b"a/file1.txt"),
1040 1074 HgPathBuf::from_bytes(b"a/b/file2.txt"),
1041 1075 // No file in a/b/c
1042 1076 HgPathBuf::from_bytes(b"a/b/c/d/file4.txt"),
1043 1077 ];
1044 1078 let matcher = FileMatcher::new(files).unwrap();
1045 1079
1046 1080 let mut set = HashSet::new();
1047 1081 set.insert(HgPathBuf::from_bytes(b"a"));
1048 1082 set.insert(HgPathBuf::from_bytes(b"rootfile.txt"));
1049 1083 assert_eq!(
1050 1084 matcher.visit_children_set(HgPath::new(b"")),
1051 1085 VisitChildrenSet::Set(set)
1052 1086 );
1053 1087
1054 1088 let mut set = HashSet::new();
1055 1089 set.insert(HgPathBuf::from_bytes(b"b"));
1056 1090 set.insert(HgPathBuf::from_bytes(b"file1.txt"));
1057 1091 assert_eq!(
1058 1092 matcher.visit_children_set(HgPath::new(b"a")),
1059 1093 VisitChildrenSet::Set(set)
1060 1094 );
1061 1095
1062 1096 let mut set = HashSet::new();
1063 1097 set.insert(HgPathBuf::from_bytes(b"c"));
1064 1098 set.insert(HgPathBuf::from_bytes(b"file2.txt"));
1065 1099 assert_eq!(
1066 1100 matcher.visit_children_set(HgPath::new(b"a/b")),
1067 1101 VisitChildrenSet::Set(set)
1068 1102 );
1069 1103
1070 1104 let mut set = HashSet::new();
1071 1105 set.insert(HgPathBuf::from_bytes(b"d"));
1072 1106 assert_eq!(
1073 1107 matcher.visit_children_set(HgPath::new(b"a/b/c")),
1074 1108 VisitChildrenSet::Set(set)
1075 1109 );
1076 1110 let mut set = HashSet::new();
1077 1111 set.insert(HgPathBuf::from_bytes(b"file4.txt"));
1078 1112 assert_eq!(
1079 1113 matcher.visit_children_set(HgPath::new(b"a/b/c/d")),
1080 1114 VisitChildrenSet::Set(set)
1081 1115 );
1082 1116
1083 1117 assert_eq!(
1084 1118 matcher.visit_children_set(HgPath::new(b"a/b/c/d/e")),
1085 1119 VisitChildrenSet::Empty
1086 1120 );
1087 1121 assert_eq!(
1088 1122 matcher.visit_children_set(HgPath::new(b"folder")),
1089 1123 VisitChildrenSet::Empty
1090 1124 );
1091 1125 }
1092 1126
1093 1127 #[test]
1094 1128 fn test_includematcher() {
1095 1129 // VisitchildrensetPrefix
1096 1130 let matcher = IncludeMatcher::new(vec![IgnorePattern::new(
1097 1131 PatternSyntax::RelPath,
1098 1132 b"dir/subdir",
1099 1133 Path::new(""),
1100 1134 )])
1101 1135 .unwrap();
1102 1136
1103 1137 let mut set = HashSet::new();
1104 1138 set.insert(HgPathBuf::from_bytes(b"dir"));
1105 1139 assert_eq!(
1106 1140 matcher.visit_children_set(HgPath::new(b"")),
1107 1141 VisitChildrenSet::Set(set)
1108 1142 );
1109 1143
1110 1144 let mut set = HashSet::new();
1111 1145 set.insert(HgPathBuf::from_bytes(b"subdir"));
1112 1146 assert_eq!(
1113 1147 matcher.visit_children_set(HgPath::new(b"dir")),
1114 1148 VisitChildrenSet::Set(set)
1115 1149 );
1116 1150 assert_eq!(
1117 1151 matcher.visit_children_set(HgPath::new(b"dir/subdir")),
1118 1152 VisitChildrenSet::Recursive
1119 1153 );
1120 1154 // OPT: This should probably be 'all' if its parent is?
1121 1155 assert_eq!(
1122 1156 matcher.visit_children_set(HgPath::new(b"dir/subdir/x")),
1123 1157 VisitChildrenSet::This
1124 1158 );
1125 1159 assert_eq!(
1126 1160 matcher.visit_children_set(HgPath::new(b"folder")),
1127 1161 VisitChildrenSet::Empty
1128 1162 );
1129 1163
1130 1164 // VisitchildrensetRootfilesin
1131 1165 let matcher = IncludeMatcher::new(vec![IgnorePattern::new(
1132 1166 PatternSyntax::RootFiles,
1133 1167 b"dir/subdir",
1134 1168 Path::new(""),
1135 1169 )])
1136 1170 .unwrap();
1137 1171
1138 1172 let mut set = HashSet::new();
1139 1173 set.insert(HgPathBuf::from_bytes(b"dir"));
1140 1174 assert_eq!(
1141 1175 matcher.visit_children_set(HgPath::new(b"")),
1142 1176 VisitChildrenSet::Set(set)
1143 1177 );
1144 1178
1145 1179 let mut set = HashSet::new();
1146 1180 set.insert(HgPathBuf::from_bytes(b"subdir"));
1147 1181 assert_eq!(
1148 1182 matcher.visit_children_set(HgPath::new(b"dir")),
1149 1183 VisitChildrenSet::Set(set)
1150 1184 );
1151 1185
1152 1186 assert_eq!(
1153 1187 matcher.visit_children_set(HgPath::new(b"dir/subdir")),
1154 1188 VisitChildrenSet::This
1155 1189 );
1156 1190 assert_eq!(
1157 1191 matcher.visit_children_set(HgPath::new(b"dir/subdir/x")),
1158 1192 VisitChildrenSet::Empty
1159 1193 );
1160 1194 assert_eq!(
1161 1195 matcher.visit_children_set(HgPath::new(b"folder")),
1162 1196 VisitChildrenSet::Empty
1163 1197 );
1164 1198
1165 1199 // VisitchildrensetGlob
1166 1200 let matcher = IncludeMatcher::new(vec![IgnorePattern::new(
1167 1201 PatternSyntax::Glob,
1168 1202 b"dir/z*",
1169 1203 Path::new(""),
1170 1204 )])
1171 1205 .unwrap();
1172 1206
1173 1207 let mut set = HashSet::new();
1174 1208 set.insert(HgPathBuf::from_bytes(b"dir"));
1175 1209 assert_eq!(
1176 1210 matcher.visit_children_set(HgPath::new(b"")),
1177 1211 VisitChildrenSet::Set(set)
1178 1212 );
1179 1213 assert_eq!(
1180 1214 matcher.visit_children_set(HgPath::new(b"folder")),
1181 1215 VisitChildrenSet::Empty
1182 1216 );
1183 1217 assert_eq!(
1184 1218 matcher.visit_children_set(HgPath::new(b"dir")),
1185 1219 VisitChildrenSet::This
1186 1220 );
1187 1221 // OPT: these should probably be set().
1188 1222 assert_eq!(
1189 1223 matcher.visit_children_set(HgPath::new(b"dir/subdir")),
1190 1224 VisitChildrenSet::This
1191 1225 );
1192 1226 assert_eq!(
1193 1227 matcher.visit_children_set(HgPath::new(b"dir/subdir/x")),
1194 1228 VisitChildrenSet::This
1195 1229 );
1196 1230
1197 1231 // Test multiple patterns
1198 1232 let matcher = IncludeMatcher::new(vec![
1199 1233 IgnorePattern::new(PatternSyntax::RelPath, b"foo", Path::new("")),
1200 1234 IgnorePattern::new(PatternSyntax::Glob, b"g*", Path::new("")),
1201 1235 ])
1202 1236 .unwrap();
1203 1237
1204 1238 assert_eq!(
1205 1239 matcher.visit_children_set(HgPath::new(b"")),
1206 1240 VisitChildrenSet::This
1207 1241 );
1208 1242
1209 1243 // Test multiple patterns
1210 1244 let matcher = IncludeMatcher::new(vec![IgnorePattern::new(
1211 1245 PatternSyntax::Glob,
1212 1246 b"**/*.exe",
1213 1247 Path::new(""),
1214 1248 )])
1215 1249 .unwrap();
1216 1250
1217 1251 assert_eq!(
1218 1252 matcher.visit_children_set(HgPath::new(b"")),
1219 1253 VisitChildrenSet::This
1220 1254 );
1221 1255 }
1222 1256
1223 1257 #[test]
1224 1258 fn test_unionmatcher() {
1225 1259 // Path + Rootfiles
1226 1260 let m1 = IncludeMatcher::new(vec![IgnorePattern::new(
1227 1261 PatternSyntax::RelPath,
1228 1262 b"dir/subdir",
1229 1263 Path::new(""),
1230 1264 )])
1231 1265 .unwrap();
1232 1266 let m2 = IncludeMatcher::new(vec![IgnorePattern::new(
1233 1267 PatternSyntax::RootFiles,
1234 1268 b"dir",
1235 1269 Path::new(""),
1236 1270 )])
1237 1271 .unwrap();
1238 1272 let matcher = UnionMatcher::new(vec![Box::new(m1), Box::new(m2)]);
1239 1273
1240 1274 let mut set = HashSet::new();
1241 1275 set.insert(HgPathBuf::from_bytes(b"dir"));
1242 1276 assert_eq!(
1243 1277 matcher.visit_children_set(HgPath::new(b"")),
1244 1278 VisitChildrenSet::Set(set)
1245 1279 );
1246 1280 assert_eq!(
1247 1281 matcher.visit_children_set(HgPath::new(b"dir")),
1248 1282 VisitChildrenSet::This
1249 1283 );
1250 1284 assert_eq!(
1251 1285 matcher.visit_children_set(HgPath::new(b"dir/subdir")),
1252 1286 VisitChildrenSet::Recursive
1253 1287 );
1254 1288 assert_eq!(
1255 1289 matcher.visit_children_set(HgPath::new(b"dir/foo")),
1256 1290 VisitChildrenSet::Empty
1257 1291 );
1258 1292 assert_eq!(
1259 1293 matcher.visit_children_set(HgPath::new(b"folder")),
1260 1294 VisitChildrenSet::Empty
1261 1295 );
1262 1296 assert_eq!(
1263 1297 matcher.visit_children_set(HgPath::new(b"folder")),
1264 1298 VisitChildrenSet::Empty
1265 1299 );
1266 1300
1267 1301 // OPT: These next two could be 'all' instead of 'this'.
1268 1302 assert_eq!(
1269 1303 matcher.visit_children_set(HgPath::new(b"dir/subdir/z")),
1270 1304 VisitChildrenSet::This
1271 1305 );
1272 1306 assert_eq!(
1273 1307 matcher.visit_children_set(HgPath::new(b"dir/subdir/x")),
1274 1308 VisitChildrenSet::This
1275 1309 );
1276 1310
1277 1311 // Path + unrelated Path
1278 1312 let m1 = IncludeMatcher::new(vec![IgnorePattern::new(
1279 1313 PatternSyntax::RelPath,
1280 1314 b"dir/subdir",
1281 1315 Path::new(""),
1282 1316 )])
1283 1317 .unwrap();
1284 1318 let m2 = IncludeMatcher::new(vec![IgnorePattern::new(
1285 1319 PatternSyntax::RelPath,
1286 1320 b"folder",
1287 1321 Path::new(""),
1288 1322 )])
1289 1323 .unwrap();
1290 1324 let matcher = UnionMatcher::new(vec![Box::new(m1), Box::new(m2)]);
1291 1325
1292 1326 let mut set = HashSet::new();
1293 1327 set.insert(HgPathBuf::from_bytes(b"folder"));
1294 1328 set.insert(HgPathBuf::from_bytes(b"dir"));
1295 1329 assert_eq!(
1296 1330 matcher.visit_children_set(HgPath::new(b"")),
1297 1331 VisitChildrenSet::Set(set)
1298 1332 );
1299 1333 let mut set = HashSet::new();
1300 1334 set.insert(HgPathBuf::from_bytes(b"subdir"));
1301 1335 assert_eq!(
1302 1336 matcher.visit_children_set(HgPath::new(b"dir")),
1303 1337 VisitChildrenSet::Set(set)
1304 1338 );
1305 1339
1306 1340 assert_eq!(
1307 1341 matcher.visit_children_set(HgPath::new(b"dir/subdir")),
1308 1342 VisitChildrenSet::Recursive
1309 1343 );
1310 1344 assert_eq!(
1311 1345 matcher.visit_children_set(HgPath::new(b"dir/foo")),
1312 1346 VisitChildrenSet::Empty
1313 1347 );
1314 1348
1315 1349 assert_eq!(
1316 1350 matcher.visit_children_set(HgPath::new(b"folder")),
1317 1351 VisitChildrenSet::Recursive
1318 1352 );
1319 1353 // OPT: These next two could be 'all' instead of 'this'.
1320 1354 assert_eq!(
1321 1355 matcher.visit_children_set(HgPath::new(b"dir/subdir/z")),
1322 1356 VisitChildrenSet::This
1323 1357 );
1324 1358 assert_eq!(
1325 1359 matcher.visit_children_set(HgPath::new(b"dir/subdir/x")),
1326 1360 VisitChildrenSet::This
1327 1361 );
1328 1362
1329 1363 // Path + subpath
1330 1364 let m1 = IncludeMatcher::new(vec![IgnorePattern::new(
1331 1365 PatternSyntax::RelPath,
1332 1366 b"dir/subdir/x",
1333 1367 Path::new(""),
1334 1368 )])
1335 1369 .unwrap();
1336 1370 let m2 = IncludeMatcher::new(vec![IgnorePattern::new(
1337 1371 PatternSyntax::RelPath,
1338 1372 b"dir/subdir",
1339 1373 Path::new(""),
1340 1374 )])
1341 1375 .unwrap();
1342 1376 let matcher = UnionMatcher::new(vec![Box::new(m1), Box::new(m2)]);
1343 1377
1344 1378 let mut set = HashSet::new();
1345 1379 set.insert(HgPathBuf::from_bytes(b"dir"));
1346 1380 assert_eq!(
1347 1381 matcher.visit_children_set(HgPath::new(b"")),
1348 1382 VisitChildrenSet::Set(set)
1349 1383 );
1350 1384 let mut set = HashSet::new();
1351 1385 set.insert(HgPathBuf::from_bytes(b"subdir"));
1352 1386 assert_eq!(
1353 1387 matcher.visit_children_set(HgPath::new(b"dir")),
1354 1388 VisitChildrenSet::Set(set)
1355 1389 );
1356 1390
1357 1391 assert_eq!(
1358 1392 matcher.visit_children_set(HgPath::new(b"dir/subdir")),
1359 1393 VisitChildrenSet::Recursive
1360 1394 );
1361 1395 assert_eq!(
1362 1396 matcher.visit_children_set(HgPath::new(b"dir/foo")),
1363 1397 VisitChildrenSet::Empty
1364 1398 );
1365 1399
1366 1400 assert_eq!(
1367 1401 matcher.visit_children_set(HgPath::new(b"folder")),
1368 1402 VisitChildrenSet::Empty
1369 1403 );
1370 1404 assert_eq!(
1371 1405 matcher.visit_children_set(HgPath::new(b"dir/subdir/x")),
1372 1406 VisitChildrenSet::Recursive
1373 1407 );
1374 1408 // OPT: this should probably be 'all' not 'this'.
1375 1409 assert_eq!(
1376 1410 matcher.visit_children_set(HgPath::new(b"dir/subdir/z")),
1377 1411 VisitChildrenSet::This
1378 1412 );
1379 1413 }
1380 1414
1381 1415 #[test]
1382 1416 fn test_intersectionmatcher() {
1383 1417 // Include path + Include rootfiles
1384 1418 let m1 = Box::new(
1385 1419 IncludeMatcher::new(vec![IgnorePattern::new(
1386 1420 PatternSyntax::RelPath,
1387 1421 b"dir/subdir",
1388 1422 Path::new(""),
1389 1423 )])
1390 1424 .unwrap(),
1391 1425 );
1392 1426 let m2 = Box::new(
1393 1427 IncludeMatcher::new(vec![IgnorePattern::new(
1394 1428 PatternSyntax::RootFiles,
1395 1429 b"dir",
1396 1430 Path::new(""),
1397 1431 )])
1398 1432 .unwrap(),
1399 1433 );
1400 1434 let matcher = IntersectionMatcher::new(m1, m2);
1401 1435
1402 1436 let mut set = HashSet::new();
1403 1437 set.insert(HgPathBuf::from_bytes(b"dir"));
1404 1438 assert_eq!(
1405 1439 matcher.visit_children_set(HgPath::new(b"")),
1406 1440 VisitChildrenSet::Set(set)
1407 1441 );
1408 1442 assert_eq!(
1409 1443 matcher.visit_children_set(HgPath::new(b"dir")),
1410 1444 VisitChildrenSet::This
1411 1445 );
1412 1446 assert_eq!(
1413 1447 matcher.visit_children_set(HgPath::new(b"dir/subdir")),
1414 1448 VisitChildrenSet::Empty
1415 1449 );
1416 1450 assert_eq!(
1417 1451 matcher.visit_children_set(HgPath::new(b"dir/foo")),
1418 1452 VisitChildrenSet::Empty
1419 1453 );
1420 1454 assert_eq!(
1421 1455 matcher.visit_children_set(HgPath::new(b"folder")),
1422 1456 VisitChildrenSet::Empty
1423 1457 );
1424 1458 assert_eq!(
1425 1459 matcher.visit_children_set(HgPath::new(b"dir/subdir/z")),
1426 1460 VisitChildrenSet::Empty
1427 1461 );
1428 1462 assert_eq!(
1429 1463 matcher.visit_children_set(HgPath::new(b"dir/subdir/x")),
1430 1464 VisitChildrenSet::Empty
1431 1465 );
1432 1466
1433 1467 // Non intersecting paths
1434 1468 let m1 = Box::new(
1435 1469 IncludeMatcher::new(vec![IgnorePattern::new(
1436 1470 PatternSyntax::RelPath,
1437 1471 b"dir/subdir",
1438 1472 Path::new(""),
1439 1473 )])
1440 1474 .unwrap(),
1441 1475 );
1442 1476 let m2 = Box::new(
1443 1477 IncludeMatcher::new(vec![IgnorePattern::new(
1444 1478 PatternSyntax::RelPath,
1445 1479 b"folder",
1446 1480 Path::new(""),
1447 1481 )])
1448 1482 .unwrap(),
1449 1483 );
1450 1484 let matcher = IntersectionMatcher::new(m1, m2);
1451 1485
1452 1486 assert_eq!(
1453 1487 matcher.visit_children_set(HgPath::new(b"")),
1454 1488 VisitChildrenSet::Empty
1455 1489 );
1456 1490 assert_eq!(
1457 1491 matcher.visit_children_set(HgPath::new(b"dir")),
1458 1492 VisitChildrenSet::Empty
1459 1493 );
1460 1494 assert_eq!(
1461 1495 matcher.visit_children_set(HgPath::new(b"dir/subdir")),
1462 1496 VisitChildrenSet::Empty
1463 1497 );
1464 1498 assert_eq!(
1465 1499 matcher.visit_children_set(HgPath::new(b"dir/foo")),
1466 1500 VisitChildrenSet::Empty
1467 1501 );
1468 1502 assert_eq!(
1469 1503 matcher.visit_children_set(HgPath::new(b"folder")),
1470 1504 VisitChildrenSet::Empty
1471 1505 );
1472 1506 assert_eq!(
1473 1507 matcher.visit_children_set(HgPath::new(b"dir/subdir/z")),
1474 1508 VisitChildrenSet::Empty
1475 1509 );
1476 1510 assert_eq!(
1477 1511 matcher.visit_children_set(HgPath::new(b"dir/subdir/x")),
1478 1512 VisitChildrenSet::Empty
1479 1513 );
1480 1514
1481 1515 // Nested paths
1482 1516 let m1 = Box::new(
1483 1517 IncludeMatcher::new(vec![IgnorePattern::new(
1484 1518 PatternSyntax::RelPath,
1485 1519 b"dir/subdir/x",
1486 1520 Path::new(""),
1487 1521 )])
1488 1522 .unwrap(),
1489 1523 );
1490 1524 let m2 = Box::new(
1491 1525 IncludeMatcher::new(vec![IgnorePattern::new(
1492 1526 PatternSyntax::RelPath,
1493 1527 b"dir/subdir",
1494 1528 Path::new(""),
1495 1529 )])
1496 1530 .unwrap(),
1497 1531 );
1498 1532 let matcher = IntersectionMatcher::new(m1, m2);
1499 1533
1500 1534 let mut set = HashSet::new();
1501 1535 set.insert(HgPathBuf::from_bytes(b"dir"));
1502 1536 assert_eq!(
1503 1537 matcher.visit_children_set(HgPath::new(b"")),
1504 1538 VisitChildrenSet::Set(set)
1505 1539 );
1506 1540
1507 1541 let mut set = HashSet::new();
1508 1542 set.insert(HgPathBuf::from_bytes(b"subdir"));
1509 1543 assert_eq!(
1510 1544 matcher.visit_children_set(HgPath::new(b"dir")),
1511 1545 VisitChildrenSet::Set(set)
1512 1546 );
1513 1547 let mut set = HashSet::new();
1514 1548 set.insert(HgPathBuf::from_bytes(b"x"));
1515 1549 assert_eq!(
1516 1550 matcher.visit_children_set(HgPath::new(b"dir/subdir")),
1517 1551 VisitChildrenSet::Set(set)
1518 1552 );
1519 1553 assert_eq!(
1520 1554 matcher.visit_children_set(HgPath::new(b"dir/foo")),
1521 1555 VisitChildrenSet::Empty
1522 1556 );
1523 1557 assert_eq!(
1524 1558 matcher.visit_children_set(HgPath::new(b"folder")),
1525 1559 VisitChildrenSet::Empty
1526 1560 );
1527 1561 assert_eq!(
1528 1562 matcher.visit_children_set(HgPath::new(b"dir/subdir/z")),
1529 1563 VisitChildrenSet::Empty
1530 1564 );
1531 1565 // OPT: this should probably be 'all' not 'this'.
1532 1566 assert_eq!(
1533 1567 matcher.visit_children_set(HgPath::new(b"dir/subdir/x")),
1534 1568 VisitChildrenSet::This
1535 1569 );
1536 1570
1537 1571 // Diverging paths
1538 1572 let m1 = Box::new(
1539 1573 IncludeMatcher::new(vec![IgnorePattern::new(
1540 1574 PatternSyntax::RelPath,
1541 1575 b"dir/subdir/x",
1542 1576 Path::new(""),
1543 1577 )])
1544 1578 .unwrap(),
1545 1579 );
1546 1580 let m2 = Box::new(
1547 1581 IncludeMatcher::new(vec![IgnorePattern::new(
1548 1582 PatternSyntax::RelPath,
1549 1583 b"dir/subdir/z",
1550 1584 Path::new(""),
1551 1585 )])
1552 1586 .unwrap(),
1553 1587 );
1554 1588 let matcher = IntersectionMatcher::new(m1, m2);
1555 1589
1556 1590 // OPT: these next two could probably be Empty as well.
1557 1591 let mut set = HashSet::new();
1558 1592 set.insert(HgPathBuf::from_bytes(b"dir"));
1559 1593 assert_eq!(
1560 1594 matcher.visit_children_set(HgPath::new(b"")),
1561 1595 VisitChildrenSet::Set(set)
1562 1596 );
1563 1597 // OPT: these next two could probably be Empty as well.
1564 1598 let mut set = HashSet::new();
1565 1599 set.insert(HgPathBuf::from_bytes(b"subdir"));
1566 1600 assert_eq!(
1567 1601 matcher.visit_children_set(HgPath::new(b"dir")),
1568 1602 VisitChildrenSet::Set(set)
1569 1603 );
1570 1604 assert_eq!(
1571 1605 matcher.visit_children_set(HgPath::new(b"dir/subdir")),
1572 1606 VisitChildrenSet::Empty
1573 1607 );
1574 1608 assert_eq!(
1575 1609 matcher.visit_children_set(HgPath::new(b"dir/foo")),
1576 1610 VisitChildrenSet::Empty
1577 1611 );
1578 1612 assert_eq!(
1579 1613 matcher.visit_children_set(HgPath::new(b"folder")),
1580 1614 VisitChildrenSet::Empty
1581 1615 );
1582 1616 assert_eq!(
1583 1617 matcher.visit_children_set(HgPath::new(b"dir/subdir/z")),
1584 1618 VisitChildrenSet::Empty
1585 1619 );
1586 1620 assert_eq!(
1587 1621 matcher.visit_children_set(HgPath::new(b"dir/subdir/x")),
1588 1622 VisitChildrenSet::Empty
1589 1623 );
1590 1624 }
1591 1625
1592 1626 #[test]
1593 1627 fn test_differencematcher() {
1594 1628 // Two alwaysmatchers should function like a nevermatcher
1595 1629 let m1 = AlwaysMatcher;
1596 1630 let m2 = AlwaysMatcher;
1597 1631 let matcher = DifferenceMatcher::new(Box::new(m1), Box::new(m2));
1598 1632
1599 1633 for case in &[
1600 1634 &b""[..],
1601 1635 b"dir",
1602 1636 b"dir/subdir",
1603 1637 b"dir/subdir/z",
1604 1638 b"dir/foo",
1605 1639 b"dir/subdir/x",
1606 1640 b"folder",
1607 1641 ] {
1608 1642 assert_eq!(
1609 1643 matcher.visit_children_set(HgPath::new(case)),
1610 1644 VisitChildrenSet::Empty
1611 1645 );
1612 1646 }
1613 1647
1614 1648 // One always and one never should behave the same as an always
1615 1649 let m1 = AlwaysMatcher;
1616 1650 let m2 = NeverMatcher;
1617 1651 let matcher = DifferenceMatcher::new(Box::new(m1), Box::new(m2));
1618 1652
1619 1653 for case in &[
1620 1654 &b""[..],
1621 1655 b"dir",
1622 1656 b"dir/subdir",
1623 1657 b"dir/subdir/z",
1624 1658 b"dir/foo",
1625 1659 b"dir/subdir/x",
1626 1660 b"folder",
1627 1661 ] {
1628 1662 assert_eq!(
1629 1663 matcher.visit_children_set(HgPath::new(case)),
1630 1664 VisitChildrenSet::Recursive
1631 1665 );
1632 1666 }
1633 1667
1634 1668 // Two include matchers
1635 1669 let m1 = Box::new(
1636 1670 IncludeMatcher::new(vec![IgnorePattern::new(
1637 1671 PatternSyntax::RelPath,
1638 1672 b"dir/subdir",
1639 1673 Path::new("/repo"),
1640 1674 )])
1641 1675 .unwrap(),
1642 1676 );
1643 1677 let m2 = Box::new(
1644 1678 IncludeMatcher::new(vec![IgnorePattern::new(
1645 1679 PatternSyntax::RootFiles,
1646 1680 b"dir",
1647 1681 Path::new("/repo"),
1648 1682 )])
1649 1683 .unwrap(),
1650 1684 );
1651 1685
1652 1686 let matcher = DifferenceMatcher::new(m1, m2);
1653 1687
1654 1688 let mut set = HashSet::new();
1655 1689 set.insert(HgPathBuf::from_bytes(b"dir"));
1656 1690 assert_eq!(
1657 1691 matcher.visit_children_set(HgPath::new(b"")),
1658 1692 VisitChildrenSet::Set(set)
1659 1693 );
1660 1694
1661 1695 let mut set = HashSet::new();
1662 1696 set.insert(HgPathBuf::from_bytes(b"subdir"));
1663 1697 assert_eq!(
1664 1698 matcher.visit_children_set(HgPath::new(b"dir")),
1665 1699 VisitChildrenSet::Set(set)
1666 1700 );
1667 1701 assert_eq!(
1668 1702 matcher.visit_children_set(HgPath::new(b"dir/subdir")),
1669 1703 VisitChildrenSet::Recursive
1670 1704 );
1671 1705 assert_eq!(
1672 1706 matcher.visit_children_set(HgPath::new(b"dir/foo")),
1673 1707 VisitChildrenSet::Empty
1674 1708 );
1675 1709 assert_eq!(
1676 1710 matcher.visit_children_set(HgPath::new(b"folder")),
1677 1711 VisitChildrenSet::Empty
1678 1712 );
1679 1713 assert_eq!(
1680 1714 matcher.visit_children_set(HgPath::new(b"dir/subdir/z")),
1681 1715 VisitChildrenSet::This
1682 1716 );
1683 1717 assert_eq!(
1684 1718 matcher.visit_children_set(HgPath::new(b"dir/subdir/x")),
1685 1719 VisitChildrenSet::This
1686 1720 );
1687 1721 }
1688 1722 }
General Comments 0
You need to be logged in to leave comments. Login now