##// END OF EJS Templates
rhg: Fall back to Python if unsupported extensions are enabled...
Simon Sapin -
r47467:1bac7764 default
parent child Browse files
Show More
@@ -1,1084 +1,1084 b''
1 # This file is automatically @generated by Cargo.
1 # This file is automatically @generated by Cargo.
2 # It is not intended for manual editing.
2 # It is not intended for manual editing.
3 [[package]]
3 [[package]]
4 name = "adler"
4 name = "adler"
5 version = "0.2.3"
5 version = "0.2.3"
6 source = "registry+https://github.com/rust-lang/crates.io-index"
6 source = "registry+https://github.com/rust-lang/crates.io-index"
7 checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
7 checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
8
8
9 [[package]]
9 [[package]]
10 name = "aho-corasick"
10 name = "aho-corasick"
11 version = "0.7.15"
11 version = "0.7.15"
12 source = "registry+https://github.com/rust-lang/crates.io-index"
12 source = "registry+https://github.com/rust-lang/crates.io-index"
13 checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
13 checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
14 dependencies = [
14 dependencies = [
15 "memchr",
15 "memchr",
16 ]
16 ]
17
17
18 [[package]]
18 [[package]]
19 name = "ansi_term"
19 name = "ansi_term"
20 version = "0.11.0"
20 version = "0.11.0"
21 source = "registry+https://github.com/rust-lang/crates.io-index"
21 source = "registry+https://github.com/rust-lang/crates.io-index"
22 checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
22 checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
23 dependencies = [
23 dependencies = [
24 "winapi",
24 "winapi",
25 ]
25 ]
26
26
27 [[package]]
27 [[package]]
28 name = "atty"
28 name = "atty"
29 version = "0.2.14"
29 version = "0.2.14"
30 source = "registry+https://github.com/rust-lang/crates.io-index"
30 source = "registry+https://github.com/rust-lang/crates.io-index"
31 checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
31 checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
32 dependencies = [
32 dependencies = [
33 "hermit-abi",
33 "hermit-abi",
34 "libc",
34 "libc",
35 "winapi",
35 "winapi",
36 ]
36 ]
37
37
38 [[package]]
38 [[package]]
39 name = "autocfg"
39 name = "autocfg"
40 version = "1.0.1"
40 version = "1.0.1"
41 source = "registry+https://github.com/rust-lang/crates.io-index"
41 source = "registry+https://github.com/rust-lang/crates.io-index"
42 checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
42 checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
43
43
44 [[package]]
44 [[package]]
45 name = "bitflags"
45 name = "bitflags"
46 version = "1.2.1"
46 version = "1.2.1"
47 source = "registry+https://github.com/rust-lang/crates.io-index"
47 source = "registry+https://github.com/rust-lang/crates.io-index"
48 checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
48 checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
49
49
50 [[package]]
50 [[package]]
51 name = "bitmaps"
51 name = "bitmaps"
52 version = "2.1.0"
52 version = "2.1.0"
53 source = "registry+https://github.com/rust-lang/crates.io-index"
53 source = "registry+https://github.com/rust-lang/crates.io-index"
54 checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2"
54 checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2"
55 dependencies = [
55 dependencies = [
56 "typenum",
56 "typenum",
57 ]
57 ]
58
58
59 [[package]]
59 [[package]]
60 name = "byteorder"
60 name = "byteorder"
61 version = "1.3.4"
61 version = "1.3.4"
62 source = "registry+https://github.com/rust-lang/crates.io-index"
62 source = "registry+https://github.com/rust-lang/crates.io-index"
63 checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
63 checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
64
64
65 [[package]]
65 [[package]]
66 name = "bytes-cast"
66 name = "bytes-cast"
67 version = "0.1.0"
67 version = "0.1.0"
68 source = "registry+https://github.com/rust-lang/crates.io-index"
68 source = "registry+https://github.com/rust-lang/crates.io-index"
69 checksum = "3196ba300c7bc9282a4331e878496cb3e9603a898a8f1446601317163e16ca52"
69 checksum = "3196ba300c7bc9282a4331e878496cb3e9603a898a8f1446601317163e16ca52"
70 dependencies = [
70 dependencies = [
71 "bytes-cast-derive",
71 "bytes-cast-derive",
72 ]
72 ]
73
73
74 [[package]]
74 [[package]]
75 name = "bytes-cast-derive"
75 name = "bytes-cast-derive"
76 version = "0.1.0"
76 version = "0.1.0"
77 source = "registry+https://github.com/rust-lang/crates.io-index"
77 source = "registry+https://github.com/rust-lang/crates.io-index"
78 checksum = "cb936af9de38476664d6b58e529aff30d482e4ce1c5e150293d00730b0d81fdb"
78 checksum = "cb936af9de38476664d6b58e529aff30d482e4ce1c5e150293d00730b0d81fdb"
79 dependencies = [
79 dependencies = [
80 "proc-macro2",
80 "proc-macro2",
81 "quote",
81 "quote",
82 "syn",
82 "syn",
83 ]
83 ]
84
84
85 [[package]]
85 [[package]]
86 name = "cc"
86 name = "cc"
87 version = "1.0.66"
87 version = "1.0.66"
88 source = "registry+https://github.com/rust-lang/crates.io-index"
88 source = "registry+https://github.com/rust-lang/crates.io-index"
89 checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
89 checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
90 dependencies = [
90 dependencies = [
91 "jobserver",
91 "jobserver",
92 ]
92 ]
93
93
94 [[package]]
94 [[package]]
95 name = "cfg-if"
95 name = "cfg-if"
96 version = "0.1.10"
96 version = "0.1.10"
97 source = "registry+https://github.com/rust-lang/crates.io-index"
97 source = "registry+https://github.com/rust-lang/crates.io-index"
98 checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
98 checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
99
99
100 [[package]]
100 [[package]]
101 name = "cfg-if"
101 name = "cfg-if"
102 version = "1.0.0"
102 version = "1.0.0"
103 source = "registry+https://github.com/rust-lang/crates.io-index"
103 source = "registry+https://github.com/rust-lang/crates.io-index"
104 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
104 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
105
105
106 [[package]]
106 [[package]]
107 name = "chrono"
107 name = "chrono"
108 version = "0.4.19"
108 version = "0.4.19"
109 source = "registry+https://github.com/rust-lang/crates.io-index"
109 source = "registry+https://github.com/rust-lang/crates.io-index"
110 checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
110 checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
111 dependencies = [
111 dependencies = [
112 "libc",
112 "libc",
113 "num-integer",
113 "num-integer",
114 "num-traits",
114 "num-traits",
115 "time",
115 "time",
116 "winapi",
116 "winapi",
117 ]
117 ]
118
118
119 [[package]]
119 [[package]]
120 name = "clap"
120 name = "clap"
121 version = "2.33.3"
121 version = "2.33.3"
122 source = "registry+https://github.com/rust-lang/crates.io-index"
122 source = "registry+https://github.com/rust-lang/crates.io-index"
123 checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
123 checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
124 dependencies = [
124 dependencies = [
125 "ansi_term",
125 "ansi_term",
126 "atty",
126 "atty",
127 "bitflags",
127 "bitflags",
128 "strsim",
128 "strsim",
129 "textwrap",
129 "textwrap",
130 "unicode-width",
130 "unicode-width",
131 "vec_map",
131 "vec_map",
132 ]
132 ]
133
133
134 [[package]]
134 [[package]]
135 name = "const_fn"
135 name = "const_fn"
136 version = "0.4.4"
136 version = "0.4.4"
137 source = "registry+https://github.com/rust-lang/crates.io-index"
137 source = "registry+https://github.com/rust-lang/crates.io-index"
138 checksum = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826"
138 checksum = "cd51eab21ab4fd6a3bf889e2d0958c0a6e3a61ad04260325e919e652a2a62826"
139
139
140 [[package]]
140 [[package]]
141 name = "cpython"
141 name = "cpython"
142 version = "0.4.1"
142 version = "0.4.1"
143 source = "registry+https://github.com/rust-lang/crates.io-index"
143 source = "registry+https://github.com/rust-lang/crates.io-index"
144 checksum = "bfaf3847ab963e40c4f6dd8d6be279bdf74007ae2413786a0dcbb28c52139a95"
144 checksum = "bfaf3847ab963e40c4f6dd8d6be279bdf74007ae2413786a0dcbb28c52139a95"
145 dependencies = [
145 dependencies = [
146 "libc",
146 "libc",
147 "num-traits",
147 "num-traits",
148 "python27-sys",
148 "python27-sys",
149 "python3-sys",
149 "python3-sys",
150 ]
150 ]
151
151
152 [[package]]
152 [[package]]
153 name = "crc32fast"
153 name = "crc32fast"
154 version = "1.2.1"
154 version = "1.2.1"
155 source = "registry+https://github.com/rust-lang/crates.io-index"
155 source = "registry+https://github.com/rust-lang/crates.io-index"
156 checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
156 checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
157 dependencies = [
157 dependencies = [
158 "cfg-if 1.0.0",
158 "cfg-if 1.0.0",
159 ]
159 ]
160
160
161 [[package]]
161 [[package]]
162 name = "crossbeam-channel"
162 name = "crossbeam-channel"
163 version = "0.4.4"
163 version = "0.4.4"
164 source = "registry+https://github.com/rust-lang/crates.io-index"
164 source = "registry+https://github.com/rust-lang/crates.io-index"
165 checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
165 checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
166 dependencies = [
166 dependencies = [
167 "crossbeam-utils 0.7.2",
167 "crossbeam-utils 0.7.2",
168 "maybe-uninit",
168 "maybe-uninit",
169 ]
169 ]
170
170
171 [[package]]
171 [[package]]
172 name = "crossbeam-channel"
172 name = "crossbeam-channel"
173 version = "0.5.0"
173 version = "0.5.0"
174 source = "registry+https://github.com/rust-lang/crates.io-index"
174 source = "registry+https://github.com/rust-lang/crates.io-index"
175 checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
175 checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
176 dependencies = [
176 dependencies = [
177 "cfg-if 1.0.0",
177 "cfg-if 1.0.0",
178 "crossbeam-utils 0.8.1",
178 "crossbeam-utils 0.8.1",
179 ]
179 ]
180
180
181 [[package]]
181 [[package]]
182 name = "crossbeam-deque"
182 name = "crossbeam-deque"
183 version = "0.8.0"
183 version = "0.8.0"
184 source = "registry+https://github.com/rust-lang/crates.io-index"
184 source = "registry+https://github.com/rust-lang/crates.io-index"
185 checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
185 checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
186 dependencies = [
186 dependencies = [
187 "cfg-if 1.0.0",
187 "cfg-if 1.0.0",
188 "crossbeam-epoch",
188 "crossbeam-epoch",
189 "crossbeam-utils 0.8.1",
189 "crossbeam-utils 0.8.1",
190 ]
190 ]
191
191
192 [[package]]
192 [[package]]
193 name = "crossbeam-epoch"
193 name = "crossbeam-epoch"
194 version = "0.9.1"
194 version = "0.9.1"
195 source = "registry+https://github.com/rust-lang/crates.io-index"
195 source = "registry+https://github.com/rust-lang/crates.io-index"
196 checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
196 checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
197 dependencies = [
197 dependencies = [
198 "cfg-if 1.0.0",
198 "cfg-if 1.0.0",
199 "const_fn",
199 "const_fn",
200 "crossbeam-utils 0.8.1",
200 "crossbeam-utils 0.8.1",
201 "lazy_static",
201 "lazy_static",
202 "memoffset",
202 "memoffset",
203 "scopeguard",
203 "scopeguard",
204 ]
204 ]
205
205
206 [[package]]
206 [[package]]
207 name = "crossbeam-utils"
207 name = "crossbeam-utils"
208 version = "0.7.2"
208 version = "0.7.2"
209 source = "registry+https://github.com/rust-lang/crates.io-index"
209 source = "registry+https://github.com/rust-lang/crates.io-index"
210 checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
210 checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
211 dependencies = [
211 dependencies = [
212 "autocfg",
212 "autocfg",
213 "cfg-if 0.1.10",
213 "cfg-if 0.1.10",
214 "lazy_static",
214 "lazy_static",
215 ]
215 ]
216
216
217 [[package]]
217 [[package]]
218 name = "crossbeam-utils"
218 name = "crossbeam-utils"
219 version = "0.8.1"
219 version = "0.8.1"
220 source = "registry+https://github.com/rust-lang/crates.io-index"
220 source = "registry+https://github.com/rust-lang/crates.io-index"
221 checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
221 checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
222 dependencies = [
222 dependencies = [
223 "autocfg",
223 "autocfg",
224 "cfg-if 1.0.0",
224 "cfg-if 1.0.0",
225 "lazy_static",
225 "lazy_static",
226 ]
226 ]
227
227
228 [[package]]
228 [[package]]
229 name = "ctor"
229 name = "ctor"
230 version = "0.1.16"
230 version = "0.1.16"
231 source = "registry+https://github.com/rust-lang/crates.io-index"
231 source = "registry+https://github.com/rust-lang/crates.io-index"
232 checksum = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484"
232 checksum = "7fbaabec2c953050352311293be5c6aba8e141ba19d6811862b232d6fd020484"
233 dependencies = [
233 dependencies = [
234 "quote",
234 "quote",
235 "syn",
235 "syn",
236 ]
236 ]
237
237
238 [[package]]
238 [[package]]
239 name = "derive_more"
239 name = "derive_more"
240 version = "0.99.11"
240 version = "0.99.11"
241 source = "registry+https://github.com/rust-lang/crates.io-index"
241 source = "registry+https://github.com/rust-lang/crates.io-index"
242 checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c"
242 checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c"
243 dependencies = [
243 dependencies = [
244 "proc-macro2",
244 "proc-macro2",
245 "quote",
245 "quote",
246 "syn",
246 "syn",
247 ]
247 ]
248
248
249 [[package]]
249 [[package]]
250 name = "difference"
250 name = "difference"
251 version = "2.0.0"
251 version = "2.0.0"
252 source = "registry+https://github.com/rust-lang/crates.io-index"
252 source = "registry+https://github.com/rust-lang/crates.io-index"
253 checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
253 checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
254
254
255 [[package]]
255 [[package]]
256 name = "either"
256 name = "either"
257 version = "1.6.1"
257 version = "1.6.1"
258 source = "registry+https://github.com/rust-lang/crates.io-index"
258 source = "registry+https://github.com/rust-lang/crates.io-index"
259 checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
259 checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
260
260
261 [[package]]
261 [[package]]
262 name = "env_logger"
262 name = "env_logger"
263 version = "0.7.1"
263 version = "0.7.1"
264 source = "registry+https://github.com/rust-lang/crates.io-index"
264 source = "registry+https://github.com/rust-lang/crates.io-index"
265 checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
265 checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
266 dependencies = [
266 dependencies = [
267 "atty",
267 "atty",
268 "humantime",
268 "humantime",
269 "log",
269 "log",
270 "regex",
270 "regex",
271 "termcolor",
271 "termcolor",
272 ]
272 ]
273
273
274 [[package]]
274 [[package]]
275 name = "flate2"
275 name = "flate2"
276 version = "1.0.19"
276 version = "1.0.19"
277 source = "registry+https://github.com/rust-lang/crates.io-index"
277 source = "registry+https://github.com/rust-lang/crates.io-index"
278 checksum = "7411863d55df97a419aa64cb4d2f167103ea9d767e2c54a1868b7ac3f6b47129"
278 checksum = "7411863d55df97a419aa64cb4d2f167103ea9d767e2c54a1868b7ac3f6b47129"
279 dependencies = [
279 dependencies = [
280 "cfg-if 1.0.0",
280 "cfg-if 1.0.0",
281 "crc32fast",
281 "crc32fast",
282 "libc",
282 "libc",
283 "libz-sys",
283 "libz-sys",
284 "miniz_oxide",
284 "miniz_oxide",
285 ]
285 ]
286
286
287 [[package]]
287 [[package]]
288 name = "format-bytes"
288 name = "format-bytes"
289 version = "0.2.0"
289 version = "0.2.1"
290 source = "registry+https://github.com/rust-lang/crates.io-index"
290 source = "registry+https://github.com/rust-lang/crates.io-index"
291 checksum = "cc35f5e45d6b31053cea13078ffc6fa52fa8617aa54b7ac2011720d9c009e04f"
291 checksum = "8030ff4b04f0ca1c612d6fe49f2fc18caf56fb01497cb370b41cfd36d89b3b06"
292 dependencies = [
292 dependencies = [
293 "format-bytes-macros",
293 "format-bytes-macros",
294 "proc-macro-hack",
294 "proc-macro-hack",
295 ]
295 ]
296
296
297 [[package]]
297 [[package]]
298 name = "format-bytes-macros"
298 name = "format-bytes-macros"
299 version = "0.3.0"
299 version = "0.3.0"
300 source = "registry+https://github.com/rust-lang/crates.io-index"
300 source = "registry+https://github.com/rust-lang/crates.io-index"
301 checksum = "b05089e341a0460449e2210c3bf7b61597860b07f0deae58da38dbed0a4c6b6d"
301 checksum = "b05089e341a0460449e2210c3bf7b61597860b07f0deae58da38dbed0a4c6b6d"
302 dependencies = [
302 dependencies = [
303 "proc-macro-hack",
303 "proc-macro-hack",
304 "proc-macro2",
304 "proc-macro2",
305 "quote",
305 "quote",
306 "syn",
306 "syn",
307 ]
307 ]
308
308
309 [[package]]
309 [[package]]
310 name = "fuchsia-cprng"
310 name = "fuchsia-cprng"
311 version = "0.1.1"
311 version = "0.1.1"
312 source = "registry+https://github.com/rust-lang/crates.io-index"
312 source = "registry+https://github.com/rust-lang/crates.io-index"
313 checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
313 checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
314
314
315 [[package]]
315 [[package]]
316 name = "gcc"
316 name = "gcc"
317 version = "0.3.55"
317 version = "0.3.55"
318 source = "registry+https://github.com/rust-lang/crates.io-index"
318 source = "registry+https://github.com/rust-lang/crates.io-index"
319 checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
319 checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
320
320
321 [[package]]
321 [[package]]
322 name = "getrandom"
322 name = "getrandom"
323 version = "0.1.15"
323 version = "0.1.15"
324 source = "registry+https://github.com/rust-lang/crates.io-index"
324 source = "registry+https://github.com/rust-lang/crates.io-index"
325 checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
325 checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
326 dependencies = [
326 dependencies = [
327 "cfg-if 0.1.10",
327 "cfg-if 0.1.10",
328 "libc",
328 "libc",
329 "wasi 0.9.0+wasi-snapshot-preview1",
329 "wasi 0.9.0+wasi-snapshot-preview1",
330 ]
330 ]
331
331
332 [[package]]
332 [[package]]
333 name = "glob"
333 name = "glob"
334 version = "0.3.0"
334 version = "0.3.0"
335 source = "registry+https://github.com/rust-lang/crates.io-index"
335 source = "registry+https://github.com/rust-lang/crates.io-index"
336 checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
336 checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
337
337
338 [[package]]
338 [[package]]
339 name = "hermit-abi"
339 name = "hermit-abi"
340 version = "0.1.17"
340 version = "0.1.17"
341 source = "registry+https://github.com/rust-lang/crates.io-index"
341 source = "registry+https://github.com/rust-lang/crates.io-index"
342 checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
342 checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
343 dependencies = [
343 dependencies = [
344 "libc",
344 "libc",
345 ]
345 ]
346
346
347 [[package]]
347 [[package]]
348 name = "hg-core"
348 name = "hg-core"
349 version = "0.1.0"
349 version = "0.1.0"
350 dependencies = [
350 dependencies = [
351 "byteorder",
351 "byteorder",
352 "bytes-cast",
352 "bytes-cast",
353 "clap",
353 "clap",
354 "crossbeam-channel 0.4.4",
354 "crossbeam-channel 0.4.4",
355 "derive_more",
355 "derive_more",
356 "flate2",
356 "flate2",
357 "format-bytes",
357 "format-bytes",
358 "home",
358 "home",
359 "im-rc",
359 "im-rc",
360 "lazy_static",
360 "lazy_static",
361 "log",
361 "log",
362 "memmap",
362 "memmap",
363 "micro-timer",
363 "micro-timer",
364 "pretty_assertions",
364 "pretty_assertions",
365 "rand 0.7.3",
365 "rand 0.7.3",
366 "rand_distr",
366 "rand_distr",
367 "rand_pcg",
367 "rand_pcg",
368 "rayon",
368 "rayon",
369 "regex",
369 "regex",
370 "rust-crypto",
370 "rust-crypto",
371 "same-file",
371 "same-file",
372 "tempfile",
372 "tempfile",
373 "twox-hash",
373 "twox-hash",
374 "zstd",
374 "zstd",
375 ]
375 ]
376
376
377 [[package]]
377 [[package]]
378 name = "hg-cpython"
378 name = "hg-cpython"
379 version = "0.1.0"
379 version = "0.1.0"
380 dependencies = [
380 dependencies = [
381 "cpython",
381 "cpython",
382 "crossbeam-channel 0.4.4",
382 "crossbeam-channel 0.4.4",
383 "env_logger",
383 "env_logger",
384 "hg-core",
384 "hg-core",
385 "libc",
385 "libc",
386 "log",
386 "log",
387 ]
387 ]
388
388
389 [[package]]
389 [[package]]
390 name = "home"
390 name = "home"
391 version = "0.5.3"
391 version = "0.5.3"
392 source = "registry+https://github.com/rust-lang/crates.io-index"
392 source = "registry+https://github.com/rust-lang/crates.io-index"
393 checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
393 checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
394 dependencies = [
394 dependencies = [
395 "winapi",
395 "winapi",
396 ]
396 ]
397
397
398 [[package]]
398 [[package]]
399 name = "humantime"
399 name = "humantime"
400 version = "1.3.0"
400 version = "1.3.0"
401 source = "registry+https://github.com/rust-lang/crates.io-index"
401 source = "registry+https://github.com/rust-lang/crates.io-index"
402 checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
402 checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
403 dependencies = [
403 dependencies = [
404 "quick-error",
404 "quick-error",
405 ]
405 ]
406
406
407 [[package]]
407 [[package]]
408 name = "im-rc"
408 name = "im-rc"
409 version = "15.0.0"
409 version = "15.0.0"
410 source = "registry+https://github.com/rust-lang/crates.io-index"
410 source = "registry+https://github.com/rust-lang/crates.io-index"
411 checksum = "3ca8957e71f04a205cb162508f9326aea04676c8dfd0711220190d6b83664f3f"
411 checksum = "3ca8957e71f04a205cb162508f9326aea04676c8dfd0711220190d6b83664f3f"
412 dependencies = [
412 dependencies = [
413 "bitmaps",
413 "bitmaps",
414 "rand_core 0.5.1",
414 "rand_core 0.5.1",
415 "rand_xoshiro",
415 "rand_xoshiro",
416 "sized-chunks",
416 "sized-chunks",
417 "typenum",
417 "typenum",
418 "version_check",
418 "version_check",
419 ]
419 ]
420
420
421 [[package]]
421 [[package]]
422 name = "itertools"
422 name = "itertools"
423 version = "0.9.0"
423 version = "0.9.0"
424 source = "registry+https://github.com/rust-lang/crates.io-index"
424 source = "registry+https://github.com/rust-lang/crates.io-index"
425 checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
425 checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
426 dependencies = [
426 dependencies = [
427 "either",
427 "either",
428 ]
428 ]
429
429
430 [[package]]
430 [[package]]
431 name = "jobserver"
431 name = "jobserver"
432 version = "0.1.21"
432 version = "0.1.21"
433 source = "registry+https://github.com/rust-lang/crates.io-index"
433 source = "registry+https://github.com/rust-lang/crates.io-index"
434 checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2"
434 checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2"
435 dependencies = [
435 dependencies = [
436 "libc",
436 "libc",
437 ]
437 ]
438
438
439 [[package]]
439 [[package]]
440 name = "lazy_static"
440 name = "lazy_static"
441 version = "1.4.0"
441 version = "1.4.0"
442 source = "registry+https://github.com/rust-lang/crates.io-index"
442 source = "registry+https://github.com/rust-lang/crates.io-index"
443 checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
443 checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
444
444
445 [[package]]
445 [[package]]
446 name = "libc"
446 name = "libc"
447 version = "0.2.81"
447 version = "0.2.81"
448 source = "registry+https://github.com/rust-lang/crates.io-index"
448 source = "registry+https://github.com/rust-lang/crates.io-index"
449 checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
449 checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
450
450
451 [[package]]
451 [[package]]
452 name = "libz-sys"
452 name = "libz-sys"
453 version = "1.1.2"
453 version = "1.1.2"
454 source = "registry+https://github.com/rust-lang/crates.io-index"
454 source = "registry+https://github.com/rust-lang/crates.io-index"
455 checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655"
455 checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655"
456 dependencies = [
456 dependencies = [
457 "cc",
457 "cc",
458 "pkg-config",
458 "pkg-config",
459 "vcpkg",
459 "vcpkg",
460 ]
460 ]
461
461
462 [[package]]
462 [[package]]
463 name = "log"
463 name = "log"
464 version = "0.4.11"
464 version = "0.4.11"
465 source = "registry+https://github.com/rust-lang/crates.io-index"
465 source = "registry+https://github.com/rust-lang/crates.io-index"
466 checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
466 checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
467 dependencies = [
467 dependencies = [
468 "cfg-if 0.1.10",
468 "cfg-if 0.1.10",
469 ]
469 ]
470
470
471 [[package]]
471 [[package]]
472 name = "maybe-uninit"
472 name = "maybe-uninit"
473 version = "2.0.0"
473 version = "2.0.0"
474 source = "registry+https://github.com/rust-lang/crates.io-index"
474 source = "registry+https://github.com/rust-lang/crates.io-index"
475 checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
475 checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
476
476
477 [[package]]
477 [[package]]
478 name = "memchr"
478 name = "memchr"
479 version = "2.3.4"
479 version = "2.3.4"
480 source = "registry+https://github.com/rust-lang/crates.io-index"
480 source = "registry+https://github.com/rust-lang/crates.io-index"
481 checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
481 checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
482
482
483 [[package]]
483 [[package]]
484 name = "memmap"
484 name = "memmap"
485 version = "0.7.0"
485 version = "0.7.0"
486 source = "registry+https://github.com/rust-lang/crates.io-index"
486 source = "registry+https://github.com/rust-lang/crates.io-index"
487 checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
487 checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
488 dependencies = [
488 dependencies = [
489 "libc",
489 "libc",
490 "winapi",
490 "winapi",
491 ]
491 ]
492
492
493 [[package]]
493 [[package]]
494 name = "memoffset"
494 name = "memoffset"
495 version = "0.6.1"
495 version = "0.6.1"
496 source = "registry+https://github.com/rust-lang/crates.io-index"
496 source = "registry+https://github.com/rust-lang/crates.io-index"
497 checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
497 checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
498 dependencies = [
498 dependencies = [
499 "autocfg",
499 "autocfg",
500 ]
500 ]
501
501
502 [[package]]
502 [[package]]
503 name = "micro-timer"
503 name = "micro-timer"
504 version = "0.3.1"
504 version = "0.3.1"
505 source = "registry+https://github.com/rust-lang/crates.io-index"
505 source = "registry+https://github.com/rust-lang/crates.io-index"
506 checksum = "2620153e1d903d26b72b89f0e9c48d8c4756cba941c185461dddc234980c298c"
506 checksum = "2620153e1d903d26b72b89f0e9c48d8c4756cba941c185461dddc234980c298c"
507 dependencies = [
507 dependencies = [
508 "micro-timer-macros",
508 "micro-timer-macros",
509 "scopeguard",
509 "scopeguard",
510 ]
510 ]
511
511
512 [[package]]
512 [[package]]
513 name = "micro-timer-macros"
513 name = "micro-timer-macros"
514 version = "0.3.1"
514 version = "0.3.1"
515 source = "registry+https://github.com/rust-lang/crates.io-index"
515 source = "registry+https://github.com/rust-lang/crates.io-index"
516 checksum = "e28a3473e6abd6e9aab36aaeef32ad22ae0bd34e79f376643594c2b152ec1c5d"
516 checksum = "e28a3473e6abd6e9aab36aaeef32ad22ae0bd34e79f376643594c2b152ec1c5d"
517 dependencies = [
517 dependencies = [
518 "proc-macro2",
518 "proc-macro2",
519 "quote",
519 "quote",
520 "scopeguard",
520 "scopeguard",
521 "syn",
521 "syn",
522 ]
522 ]
523
523
524 [[package]]
524 [[package]]
525 name = "miniz_oxide"
525 name = "miniz_oxide"
526 version = "0.4.3"
526 version = "0.4.3"
527 source = "registry+https://github.com/rust-lang/crates.io-index"
527 source = "registry+https://github.com/rust-lang/crates.io-index"
528 checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
528 checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
529 dependencies = [
529 dependencies = [
530 "adler",
530 "adler",
531 "autocfg",
531 "autocfg",
532 ]
532 ]
533
533
534 [[package]]
534 [[package]]
535 name = "num-integer"
535 name = "num-integer"
536 version = "0.1.44"
536 version = "0.1.44"
537 source = "registry+https://github.com/rust-lang/crates.io-index"
537 source = "registry+https://github.com/rust-lang/crates.io-index"
538 checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
538 checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
539 dependencies = [
539 dependencies = [
540 "autocfg",
540 "autocfg",
541 "num-traits",
541 "num-traits",
542 ]
542 ]
543
543
544 [[package]]
544 [[package]]
545 name = "num-traits"
545 name = "num-traits"
546 version = "0.2.14"
546 version = "0.2.14"
547 source = "registry+https://github.com/rust-lang/crates.io-index"
547 source = "registry+https://github.com/rust-lang/crates.io-index"
548 checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
548 checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
549 dependencies = [
549 dependencies = [
550 "autocfg",
550 "autocfg",
551 ]
551 ]
552
552
553 [[package]]
553 [[package]]
554 name = "num_cpus"
554 name = "num_cpus"
555 version = "1.13.0"
555 version = "1.13.0"
556 source = "registry+https://github.com/rust-lang/crates.io-index"
556 source = "registry+https://github.com/rust-lang/crates.io-index"
557 checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
557 checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
558 dependencies = [
558 dependencies = [
559 "hermit-abi",
559 "hermit-abi",
560 "libc",
560 "libc",
561 ]
561 ]
562
562
563 [[package]]
563 [[package]]
564 name = "output_vt100"
564 name = "output_vt100"
565 version = "0.1.2"
565 version = "0.1.2"
566 source = "registry+https://github.com/rust-lang/crates.io-index"
566 source = "registry+https://github.com/rust-lang/crates.io-index"
567 checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
567 checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
568 dependencies = [
568 dependencies = [
569 "winapi",
569 "winapi",
570 ]
570 ]
571
571
572 [[package]]
572 [[package]]
573 name = "pkg-config"
573 name = "pkg-config"
574 version = "0.3.19"
574 version = "0.3.19"
575 source = "registry+https://github.com/rust-lang/crates.io-index"
575 source = "registry+https://github.com/rust-lang/crates.io-index"
576 checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
576 checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
577
577
578 [[package]]
578 [[package]]
579 name = "ppv-lite86"
579 name = "ppv-lite86"
580 version = "0.2.10"
580 version = "0.2.10"
581 source = "registry+https://github.com/rust-lang/crates.io-index"
581 source = "registry+https://github.com/rust-lang/crates.io-index"
582 checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
582 checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
583
583
584 [[package]]
584 [[package]]
585 name = "pretty_assertions"
585 name = "pretty_assertions"
586 version = "0.6.1"
586 version = "0.6.1"
587 source = "registry+https://github.com/rust-lang/crates.io-index"
587 source = "registry+https://github.com/rust-lang/crates.io-index"
588 checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
588 checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
589 dependencies = [
589 dependencies = [
590 "ansi_term",
590 "ansi_term",
591 "ctor",
591 "ctor",
592 "difference",
592 "difference",
593 "output_vt100",
593 "output_vt100",
594 ]
594 ]
595
595
596 [[package]]
596 [[package]]
597 name = "proc-macro-hack"
597 name = "proc-macro-hack"
598 version = "0.5.19"
598 version = "0.5.19"
599 source = "registry+https://github.com/rust-lang/crates.io-index"
599 source = "registry+https://github.com/rust-lang/crates.io-index"
600 checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
600 checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
601
601
602 [[package]]
602 [[package]]
603 name = "proc-macro2"
603 name = "proc-macro2"
604 version = "1.0.24"
604 version = "1.0.24"
605 source = "registry+https://github.com/rust-lang/crates.io-index"
605 source = "registry+https://github.com/rust-lang/crates.io-index"
606 checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
606 checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
607 dependencies = [
607 dependencies = [
608 "unicode-xid",
608 "unicode-xid",
609 ]
609 ]
610
610
611 [[package]]
611 [[package]]
612 name = "python27-sys"
612 name = "python27-sys"
613 version = "0.4.1"
613 version = "0.4.1"
614 source = "registry+https://github.com/rust-lang/crates.io-index"
614 source = "registry+https://github.com/rust-lang/crates.io-index"
615 checksum = "67cb041de8615111bf224dd75667af5f25c6e032118251426fed7f1b70ce4c8c"
615 checksum = "67cb041de8615111bf224dd75667af5f25c6e032118251426fed7f1b70ce4c8c"
616 dependencies = [
616 dependencies = [
617 "libc",
617 "libc",
618 "regex",
618 "regex",
619 ]
619 ]
620
620
621 [[package]]
621 [[package]]
622 name = "python3-sys"
622 name = "python3-sys"
623 version = "0.4.1"
623 version = "0.4.1"
624 source = "registry+https://github.com/rust-lang/crates.io-index"
624 source = "registry+https://github.com/rust-lang/crates.io-index"
625 checksum = "90af11779515a1e530af60782d273b59ac79d33b0e253c071a728563957c76d4"
625 checksum = "90af11779515a1e530af60782d273b59ac79d33b0e253c071a728563957c76d4"
626 dependencies = [
626 dependencies = [
627 "libc",
627 "libc",
628 "regex",
628 "regex",
629 ]
629 ]
630
630
631 [[package]]
631 [[package]]
632 name = "quick-error"
632 name = "quick-error"
633 version = "1.2.3"
633 version = "1.2.3"
634 source = "registry+https://github.com/rust-lang/crates.io-index"
634 source = "registry+https://github.com/rust-lang/crates.io-index"
635 checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
635 checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
636
636
637 [[package]]
637 [[package]]
638 name = "quote"
638 name = "quote"
639 version = "1.0.7"
639 version = "1.0.7"
640 source = "registry+https://github.com/rust-lang/crates.io-index"
640 source = "registry+https://github.com/rust-lang/crates.io-index"
641 checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
641 checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37"
642 dependencies = [
642 dependencies = [
643 "proc-macro2",
643 "proc-macro2",
644 ]
644 ]
645
645
646 [[package]]
646 [[package]]
647 name = "rand"
647 name = "rand"
648 version = "0.3.23"
648 version = "0.3.23"
649 source = "registry+https://github.com/rust-lang/crates.io-index"
649 source = "registry+https://github.com/rust-lang/crates.io-index"
650 checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
650 checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
651 dependencies = [
651 dependencies = [
652 "libc",
652 "libc",
653 "rand 0.4.6",
653 "rand 0.4.6",
654 ]
654 ]
655
655
656 [[package]]
656 [[package]]
657 name = "rand"
657 name = "rand"
658 version = "0.4.6"
658 version = "0.4.6"
659 source = "registry+https://github.com/rust-lang/crates.io-index"
659 source = "registry+https://github.com/rust-lang/crates.io-index"
660 checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
660 checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
661 dependencies = [
661 dependencies = [
662 "fuchsia-cprng",
662 "fuchsia-cprng",
663 "libc",
663 "libc",
664 "rand_core 0.3.1",
664 "rand_core 0.3.1",
665 "rdrand",
665 "rdrand",
666 "winapi",
666 "winapi",
667 ]
667 ]
668
668
669 [[package]]
669 [[package]]
670 name = "rand"
670 name = "rand"
671 version = "0.7.3"
671 version = "0.7.3"
672 source = "registry+https://github.com/rust-lang/crates.io-index"
672 source = "registry+https://github.com/rust-lang/crates.io-index"
673 checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
673 checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
674 dependencies = [
674 dependencies = [
675 "getrandom",
675 "getrandom",
676 "libc",
676 "libc",
677 "rand_chacha",
677 "rand_chacha",
678 "rand_core 0.5.1",
678 "rand_core 0.5.1",
679 "rand_hc",
679 "rand_hc",
680 ]
680 ]
681
681
682 [[package]]
682 [[package]]
683 name = "rand_chacha"
683 name = "rand_chacha"
684 version = "0.2.2"
684 version = "0.2.2"
685 source = "registry+https://github.com/rust-lang/crates.io-index"
685 source = "registry+https://github.com/rust-lang/crates.io-index"
686 checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
686 checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
687 dependencies = [
687 dependencies = [
688 "ppv-lite86",
688 "ppv-lite86",
689 "rand_core 0.5.1",
689 "rand_core 0.5.1",
690 ]
690 ]
691
691
692 [[package]]
692 [[package]]
693 name = "rand_core"
693 name = "rand_core"
694 version = "0.3.1"
694 version = "0.3.1"
695 source = "registry+https://github.com/rust-lang/crates.io-index"
695 source = "registry+https://github.com/rust-lang/crates.io-index"
696 checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
696 checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
697 dependencies = [
697 dependencies = [
698 "rand_core 0.4.2",
698 "rand_core 0.4.2",
699 ]
699 ]
700
700
701 [[package]]
701 [[package]]
702 name = "rand_core"
702 name = "rand_core"
703 version = "0.4.2"
703 version = "0.4.2"
704 source = "registry+https://github.com/rust-lang/crates.io-index"
704 source = "registry+https://github.com/rust-lang/crates.io-index"
705 checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
705 checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
706
706
707 [[package]]
707 [[package]]
708 name = "rand_core"
708 name = "rand_core"
709 version = "0.5.1"
709 version = "0.5.1"
710 source = "registry+https://github.com/rust-lang/crates.io-index"
710 source = "registry+https://github.com/rust-lang/crates.io-index"
711 checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
711 checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
712 dependencies = [
712 dependencies = [
713 "getrandom",
713 "getrandom",
714 ]
714 ]
715
715
716 [[package]]
716 [[package]]
717 name = "rand_distr"
717 name = "rand_distr"
718 version = "0.2.2"
718 version = "0.2.2"
719 source = "registry+https://github.com/rust-lang/crates.io-index"
719 source = "registry+https://github.com/rust-lang/crates.io-index"
720 checksum = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2"
720 checksum = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2"
721 dependencies = [
721 dependencies = [
722 "rand 0.7.3",
722 "rand 0.7.3",
723 ]
723 ]
724
724
725 [[package]]
725 [[package]]
726 name = "rand_hc"
726 name = "rand_hc"
727 version = "0.2.0"
727 version = "0.2.0"
728 source = "registry+https://github.com/rust-lang/crates.io-index"
728 source = "registry+https://github.com/rust-lang/crates.io-index"
729 checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
729 checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
730 dependencies = [
730 dependencies = [
731 "rand_core 0.5.1",
731 "rand_core 0.5.1",
732 ]
732 ]
733
733
734 [[package]]
734 [[package]]
735 name = "rand_pcg"
735 name = "rand_pcg"
736 version = "0.2.1"
736 version = "0.2.1"
737 source = "registry+https://github.com/rust-lang/crates.io-index"
737 source = "registry+https://github.com/rust-lang/crates.io-index"
738 checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
738 checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
739 dependencies = [
739 dependencies = [
740 "rand_core 0.5.1",
740 "rand_core 0.5.1",
741 ]
741 ]
742
742
743 [[package]]
743 [[package]]
744 name = "rand_xoshiro"
744 name = "rand_xoshiro"
745 version = "0.4.0"
745 version = "0.4.0"
746 source = "registry+https://github.com/rust-lang/crates.io-index"
746 source = "registry+https://github.com/rust-lang/crates.io-index"
747 checksum = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004"
747 checksum = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004"
748 dependencies = [
748 dependencies = [
749 "rand_core 0.5.1",
749 "rand_core 0.5.1",
750 ]
750 ]
751
751
752 [[package]]
752 [[package]]
753 name = "rayon"
753 name = "rayon"
754 version = "1.5.0"
754 version = "1.5.0"
755 source = "registry+https://github.com/rust-lang/crates.io-index"
755 source = "registry+https://github.com/rust-lang/crates.io-index"
756 checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
756 checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
757 dependencies = [
757 dependencies = [
758 "autocfg",
758 "autocfg",
759 "crossbeam-deque",
759 "crossbeam-deque",
760 "either",
760 "either",
761 "rayon-core",
761 "rayon-core",
762 ]
762 ]
763
763
764 [[package]]
764 [[package]]
765 name = "rayon-core"
765 name = "rayon-core"
766 version = "1.9.0"
766 version = "1.9.0"
767 source = "registry+https://github.com/rust-lang/crates.io-index"
767 source = "registry+https://github.com/rust-lang/crates.io-index"
768 checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
768 checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
769 dependencies = [
769 dependencies = [
770 "crossbeam-channel 0.5.0",
770 "crossbeam-channel 0.5.0",
771 "crossbeam-deque",
771 "crossbeam-deque",
772 "crossbeam-utils 0.8.1",
772 "crossbeam-utils 0.8.1",
773 "lazy_static",
773 "lazy_static",
774 "num_cpus",
774 "num_cpus",
775 ]
775 ]
776
776
777 [[package]]
777 [[package]]
778 name = "rdrand"
778 name = "rdrand"
779 version = "0.4.0"
779 version = "0.4.0"
780 source = "registry+https://github.com/rust-lang/crates.io-index"
780 source = "registry+https://github.com/rust-lang/crates.io-index"
781 checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
781 checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
782 dependencies = [
782 dependencies = [
783 "rand_core 0.3.1",
783 "rand_core 0.3.1",
784 ]
784 ]
785
785
786 [[package]]
786 [[package]]
787 name = "redox_syscall"
787 name = "redox_syscall"
788 version = "0.1.57"
788 version = "0.1.57"
789 source = "registry+https://github.com/rust-lang/crates.io-index"
789 source = "registry+https://github.com/rust-lang/crates.io-index"
790 checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
790 checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
791
791
792 [[package]]
792 [[package]]
793 name = "regex"
793 name = "regex"
794 version = "1.4.2"
794 version = "1.4.2"
795 source = "registry+https://github.com/rust-lang/crates.io-index"
795 source = "registry+https://github.com/rust-lang/crates.io-index"
796 checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
796 checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
797 dependencies = [
797 dependencies = [
798 "aho-corasick",
798 "aho-corasick",
799 "memchr",
799 "memchr",
800 "regex-syntax",
800 "regex-syntax",
801 "thread_local",
801 "thread_local",
802 ]
802 ]
803
803
804 [[package]]
804 [[package]]
805 name = "regex-syntax"
805 name = "regex-syntax"
806 version = "0.6.21"
806 version = "0.6.21"
807 source = "registry+https://github.com/rust-lang/crates.io-index"
807 source = "registry+https://github.com/rust-lang/crates.io-index"
808 checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
808 checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
809
809
810 [[package]]
810 [[package]]
811 name = "remove_dir_all"
811 name = "remove_dir_all"
812 version = "0.5.3"
812 version = "0.5.3"
813 source = "registry+https://github.com/rust-lang/crates.io-index"
813 source = "registry+https://github.com/rust-lang/crates.io-index"
814 checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
814 checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
815 dependencies = [
815 dependencies = [
816 "winapi",
816 "winapi",
817 ]
817 ]
818
818
819 [[package]]
819 [[package]]
820 name = "rhg"
820 name = "rhg"
821 version = "0.1.0"
821 version = "0.1.0"
822 dependencies = [
822 dependencies = [
823 "chrono",
823 "chrono",
824 "clap",
824 "clap",
825 "derive_more",
825 "derive_more",
826 "env_logger",
826 "env_logger",
827 "format-bytes",
827 "format-bytes",
828 "hg-core",
828 "hg-core",
829 "lazy_static",
829 "lazy_static",
830 "log",
830 "log",
831 "micro-timer",
831 "micro-timer",
832 "regex",
832 "regex",
833 "users",
833 "users",
834 ]
834 ]
835
835
836 [[package]]
836 [[package]]
837 name = "rust-crypto"
837 name = "rust-crypto"
838 version = "0.2.36"
838 version = "0.2.36"
839 source = "registry+https://github.com/rust-lang/crates.io-index"
839 source = "registry+https://github.com/rust-lang/crates.io-index"
840 checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
840 checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
841 dependencies = [
841 dependencies = [
842 "gcc",
842 "gcc",
843 "libc",
843 "libc",
844 "rand 0.3.23",
844 "rand 0.3.23",
845 "rustc-serialize",
845 "rustc-serialize",
846 "time",
846 "time",
847 ]
847 ]
848
848
849 [[package]]
849 [[package]]
850 name = "rustc-serialize"
850 name = "rustc-serialize"
851 version = "0.3.24"
851 version = "0.3.24"
852 source = "registry+https://github.com/rust-lang/crates.io-index"
852 source = "registry+https://github.com/rust-lang/crates.io-index"
853 checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
853 checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
854
854
855 [[package]]
855 [[package]]
856 name = "same-file"
856 name = "same-file"
857 version = "1.0.6"
857 version = "1.0.6"
858 source = "registry+https://github.com/rust-lang/crates.io-index"
858 source = "registry+https://github.com/rust-lang/crates.io-index"
859 checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
859 checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
860 dependencies = [
860 dependencies = [
861 "winapi-util",
861 "winapi-util",
862 ]
862 ]
863
863
864 [[package]]
864 [[package]]
865 name = "scopeguard"
865 name = "scopeguard"
866 version = "1.1.0"
866 version = "1.1.0"
867 source = "registry+https://github.com/rust-lang/crates.io-index"
867 source = "registry+https://github.com/rust-lang/crates.io-index"
868 checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
868 checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
869
869
870 [[package]]
870 [[package]]
871 name = "sized-chunks"
871 name = "sized-chunks"
872 version = "0.6.2"
872 version = "0.6.2"
873 source = "registry+https://github.com/rust-lang/crates.io-index"
873 source = "registry+https://github.com/rust-lang/crates.io-index"
874 checksum = "1ec31ceca5644fa6d444cc77548b88b67f46db6f7c71683b0f9336e671830d2f"
874 checksum = "1ec31ceca5644fa6d444cc77548b88b67f46db6f7c71683b0f9336e671830d2f"
875 dependencies = [
875 dependencies = [
876 "bitmaps",
876 "bitmaps",
877 "typenum",
877 "typenum",
878 ]
878 ]
879
879
880 [[package]]
880 [[package]]
881 name = "static_assertions"
881 name = "static_assertions"
882 version = "1.1.0"
882 version = "1.1.0"
883 source = "registry+https://github.com/rust-lang/crates.io-index"
883 source = "registry+https://github.com/rust-lang/crates.io-index"
884 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
884 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
885
885
886 [[package]]
886 [[package]]
887 name = "strsim"
887 name = "strsim"
888 version = "0.8.0"
888 version = "0.8.0"
889 source = "registry+https://github.com/rust-lang/crates.io-index"
889 source = "registry+https://github.com/rust-lang/crates.io-index"
890 checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
890 checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
891
891
892 [[package]]
892 [[package]]
893 name = "syn"
893 name = "syn"
894 version = "1.0.54"
894 version = "1.0.54"
895 source = "registry+https://github.com/rust-lang/crates.io-index"
895 source = "registry+https://github.com/rust-lang/crates.io-index"
896 checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44"
896 checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44"
897 dependencies = [
897 dependencies = [
898 "proc-macro2",
898 "proc-macro2",
899 "quote",
899 "quote",
900 "unicode-xid",
900 "unicode-xid",
901 ]
901 ]
902
902
903 [[package]]
903 [[package]]
904 name = "tempfile"
904 name = "tempfile"
905 version = "3.1.0"
905 version = "3.1.0"
906 source = "registry+https://github.com/rust-lang/crates.io-index"
906 source = "registry+https://github.com/rust-lang/crates.io-index"
907 checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
907 checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
908 dependencies = [
908 dependencies = [
909 "cfg-if 0.1.10",
909 "cfg-if 0.1.10",
910 "libc",
910 "libc",
911 "rand 0.7.3",
911 "rand 0.7.3",
912 "redox_syscall",
912 "redox_syscall",
913 "remove_dir_all",
913 "remove_dir_all",
914 "winapi",
914 "winapi",
915 ]
915 ]
916
916
917 [[package]]
917 [[package]]
918 name = "termcolor"
918 name = "termcolor"
919 version = "1.1.2"
919 version = "1.1.2"
920 source = "registry+https://github.com/rust-lang/crates.io-index"
920 source = "registry+https://github.com/rust-lang/crates.io-index"
921 checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
921 checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
922 dependencies = [
922 dependencies = [
923 "winapi-util",
923 "winapi-util",
924 ]
924 ]
925
925
926 [[package]]
926 [[package]]
927 name = "textwrap"
927 name = "textwrap"
928 version = "0.11.0"
928 version = "0.11.0"
929 source = "registry+https://github.com/rust-lang/crates.io-index"
929 source = "registry+https://github.com/rust-lang/crates.io-index"
930 checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
930 checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
931 dependencies = [
931 dependencies = [
932 "unicode-width",
932 "unicode-width",
933 ]
933 ]
934
934
935 [[package]]
935 [[package]]
936 name = "thread_local"
936 name = "thread_local"
937 version = "1.0.1"
937 version = "1.0.1"
938 source = "registry+https://github.com/rust-lang/crates.io-index"
938 source = "registry+https://github.com/rust-lang/crates.io-index"
939 checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
939 checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
940 dependencies = [
940 dependencies = [
941 "lazy_static",
941 "lazy_static",
942 ]
942 ]
943
943
944 [[package]]
944 [[package]]
945 name = "time"
945 name = "time"
946 version = "0.1.44"
946 version = "0.1.44"
947 source = "registry+https://github.com/rust-lang/crates.io-index"
947 source = "registry+https://github.com/rust-lang/crates.io-index"
948 checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
948 checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
949 dependencies = [
949 dependencies = [
950 "libc",
950 "libc",
951 "wasi 0.10.0+wasi-snapshot-preview1",
951 "wasi 0.10.0+wasi-snapshot-preview1",
952 "winapi",
952 "winapi",
953 ]
953 ]
954
954
955 [[package]]
955 [[package]]
956 name = "twox-hash"
956 name = "twox-hash"
957 version = "1.6.0"
957 version = "1.6.0"
958 source = "registry+https://github.com/rust-lang/crates.io-index"
958 source = "registry+https://github.com/rust-lang/crates.io-index"
959 checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59"
959 checksum = "04f8ab788026715fa63b31960869617cba39117e520eb415b0139543e325ab59"
960 dependencies = [
960 dependencies = [
961 "cfg-if 0.1.10",
961 "cfg-if 0.1.10",
962 "rand 0.7.3",
962 "rand 0.7.3",
963 "static_assertions",
963 "static_assertions",
964 ]
964 ]
965
965
966 [[package]]
966 [[package]]
967 name = "typenum"
967 name = "typenum"
968 version = "1.12.0"
968 version = "1.12.0"
969 source = "registry+https://github.com/rust-lang/crates.io-index"
969 source = "registry+https://github.com/rust-lang/crates.io-index"
970 checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
970 checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
971
971
972 [[package]]
972 [[package]]
973 name = "unicode-width"
973 name = "unicode-width"
974 version = "0.1.8"
974 version = "0.1.8"
975 source = "registry+https://github.com/rust-lang/crates.io-index"
975 source = "registry+https://github.com/rust-lang/crates.io-index"
976 checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
976 checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
977
977
978 [[package]]
978 [[package]]
979 name = "unicode-xid"
979 name = "unicode-xid"
980 version = "0.2.1"
980 version = "0.2.1"
981 source = "registry+https://github.com/rust-lang/crates.io-index"
981 source = "registry+https://github.com/rust-lang/crates.io-index"
982 checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
982 checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
983
983
984 [[package]]
984 [[package]]
985 name = "users"
985 name = "users"
986 version = "0.11.0"
986 version = "0.11.0"
987 source = "registry+https://github.com/rust-lang/crates.io-index"
987 source = "registry+https://github.com/rust-lang/crates.io-index"
988 checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032"
988 checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032"
989 dependencies = [
989 dependencies = [
990 "libc",
990 "libc",
991 "log",
991 "log",
992 ]
992 ]
993
993
994 [[package]]
994 [[package]]
995 name = "vcpkg"
995 name = "vcpkg"
996 version = "0.2.11"
996 version = "0.2.11"
997 source = "registry+https://github.com/rust-lang/crates.io-index"
997 source = "registry+https://github.com/rust-lang/crates.io-index"
998 checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
998 checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb"
999
999
1000 [[package]]
1000 [[package]]
1001 name = "vec_map"
1001 name = "vec_map"
1002 version = "0.8.2"
1002 version = "0.8.2"
1003 source = "registry+https://github.com/rust-lang/crates.io-index"
1003 source = "registry+https://github.com/rust-lang/crates.io-index"
1004 checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
1004 checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
1005
1005
1006 [[package]]
1006 [[package]]
1007 name = "version_check"
1007 name = "version_check"
1008 version = "0.9.2"
1008 version = "0.9.2"
1009 source = "registry+https://github.com/rust-lang/crates.io-index"
1009 source = "registry+https://github.com/rust-lang/crates.io-index"
1010 checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
1010 checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
1011
1011
1012 [[package]]
1012 [[package]]
1013 name = "wasi"
1013 name = "wasi"
1014 version = "0.9.0+wasi-snapshot-preview1"
1014 version = "0.9.0+wasi-snapshot-preview1"
1015 source = "registry+https://github.com/rust-lang/crates.io-index"
1015 source = "registry+https://github.com/rust-lang/crates.io-index"
1016 checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
1016 checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
1017
1017
1018 [[package]]
1018 [[package]]
1019 name = "wasi"
1019 name = "wasi"
1020 version = "0.10.0+wasi-snapshot-preview1"
1020 version = "0.10.0+wasi-snapshot-preview1"
1021 source = "registry+https://github.com/rust-lang/crates.io-index"
1021 source = "registry+https://github.com/rust-lang/crates.io-index"
1022 checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
1022 checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
1023
1023
1024 [[package]]
1024 [[package]]
1025 name = "winapi"
1025 name = "winapi"
1026 version = "0.3.9"
1026 version = "0.3.9"
1027 source = "registry+https://github.com/rust-lang/crates.io-index"
1027 source = "registry+https://github.com/rust-lang/crates.io-index"
1028 checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1028 checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1029 dependencies = [
1029 dependencies = [
1030 "winapi-i686-pc-windows-gnu",
1030 "winapi-i686-pc-windows-gnu",
1031 "winapi-x86_64-pc-windows-gnu",
1031 "winapi-x86_64-pc-windows-gnu",
1032 ]
1032 ]
1033
1033
1034 [[package]]
1034 [[package]]
1035 name = "winapi-i686-pc-windows-gnu"
1035 name = "winapi-i686-pc-windows-gnu"
1036 version = "0.4.0"
1036 version = "0.4.0"
1037 source = "registry+https://github.com/rust-lang/crates.io-index"
1037 source = "registry+https://github.com/rust-lang/crates.io-index"
1038 checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1038 checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1039
1039
1040 [[package]]
1040 [[package]]
1041 name = "winapi-util"
1041 name = "winapi-util"
1042 version = "0.1.5"
1042 version = "0.1.5"
1043 source = "registry+https://github.com/rust-lang/crates.io-index"
1043 source = "registry+https://github.com/rust-lang/crates.io-index"
1044 checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
1044 checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
1045 dependencies = [
1045 dependencies = [
1046 "winapi",
1046 "winapi",
1047 ]
1047 ]
1048
1048
1049 [[package]]
1049 [[package]]
1050 name = "winapi-x86_64-pc-windows-gnu"
1050 name = "winapi-x86_64-pc-windows-gnu"
1051 version = "0.4.0"
1051 version = "0.4.0"
1052 source = "registry+https://github.com/rust-lang/crates.io-index"
1052 source = "registry+https://github.com/rust-lang/crates.io-index"
1053 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1053 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1054
1054
1055 [[package]]
1055 [[package]]
1056 name = "zstd"
1056 name = "zstd"
1057 version = "0.5.3+zstd.1.4.5"
1057 version = "0.5.3+zstd.1.4.5"
1058 source = "registry+https://github.com/rust-lang/crates.io-index"
1058 source = "registry+https://github.com/rust-lang/crates.io-index"
1059 checksum = "01b32eaf771efa709e8308605bbf9319bf485dc1503179ec0469b611937c0cd8"
1059 checksum = "01b32eaf771efa709e8308605bbf9319bf485dc1503179ec0469b611937c0cd8"
1060 dependencies = [
1060 dependencies = [
1061 "zstd-safe",
1061 "zstd-safe",
1062 ]
1062 ]
1063
1063
1064 [[package]]
1064 [[package]]
1065 name = "zstd-safe"
1065 name = "zstd-safe"
1066 version = "2.0.5+zstd.1.4.5"
1066 version = "2.0.5+zstd.1.4.5"
1067 source = "registry+https://github.com/rust-lang/crates.io-index"
1067 source = "registry+https://github.com/rust-lang/crates.io-index"
1068 checksum = "1cfb642e0d27f64729a639c52db457e0ae906e7bc6f5fe8f5c453230400f1055"
1068 checksum = "1cfb642e0d27f64729a639c52db457e0ae906e7bc6f5fe8f5c453230400f1055"
1069 dependencies = [
1069 dependencies = [
1070 "libc",
1070 "libc",
1071 "zstd-sys",
1071 "zstd-sys",
1072 ]
1072 ]
1073
1073
1074 [[package]]
1074 [[package]]
1075 name = "zstd-sys"
1075 name = "zstd-sys"
1076 version = "1.4.17+zstd.1.4.5"
1076 version = "1.4.17+zstd.1.4.5"
1077 source = "registry+https://github.com/rust-lang/crates.io-index"
1077 source = "registry+https://github.com/rust-lang/crates.io-index"
1078 checksum = "b89249644df056b522696b1bb9e7c18c87e8ffa3e2f0dc3b0155875d6498f01b"
1078 checksum = "b89249644df056b522696b1bb9e7c18c87e8ffa3e2f0dc3b0155875d6498f01b"
1079 dependencies = [
1079 dependencies = [
1080 "cc",
1080 "cc",
1081 "glob",
1081 "glob",
1082 "itertools",
1082 "itertools",
1083 "libc",
1083 "libc",
1084 ]
1084 ]
@@ -1,428 +1,437 b''
1 // config.rs
1 // config.rs
2 //
2 //
3 // Copyright 2020
3 // Copyright 2020
4 // Valentin Gatien-Baron,
4 // Valentin Gatien-Baron,
5 // Raphaël Gomès <rgomes@octobus.net>
5 // Raphaël Gomès <rgomes@octobus.net>
6 //
6 //
7 // This software may be used and distributed according to the terms of the
7 // This software may be used and distributed according to the terms of the
8 // GNU General Public License version 2 or any later version.
8 // GNU General Public License version 2 or any later version.
9
9
10 use super::layer;
10 use super::layer;
11 use super::values;
11 use super::values;
12 use crate::config::layer::{
12 use crate::config::layer::{
13 ConfigError, ConfigLayer, ConfigOrigin, ConfigValue,
13 ConfigError, ConfigLayer, ConfigOrigin, ConfigValue,
14 };
14 };
15 use crate::utils::files::get_bytes_from_os_str;
15 use crate::utils::files::get_bytes_from_os_str;
16 use format_bytes::{write_bytes, DisplayBytes};
16 use format_bytes::{write_bytes, DisplayBytes};
17 use std::collections::HashSet;
17 use std::env;
18 use std::env;
18 use std::path::{Path, PathBuf};
19 use std::path::{Path, PathBuf};
19 use std::str;
20 use std::str;
20
21
21 use crate::errors::{HgResultExt, IoResultExt};
22 use crate::errors::{HgResultExt, IoResultExt};
22
23
23 /// Holds the config values for the current repository
24 /// Holds the config values for the current repository
24 /// TODO update this docstring once we support more sources
25 /// TODO update this docstring once we support more sources
25 pub struct Config {
26 pub struct Config {
26 layers: Vec<layer::ConfigLayer>,
27 layers: Vec<layer::ConfigLayer>,
27 }
28 }
28
29
29 impl DisplayBytes for Config {
30 impl DisplayBytes for Config {
30 fn display_bytes(
31 fn display_bytes(
31 &self,
32 &self,
32 out: &mut dyn std::io::Write,
33 out: &mut dyn std::io::Write,
33 ) -> std::io::Result<()> {
34 ) -> std::io::Result<()> {
34 for (index, layer) in self.layers.iter().rev().enumerate() {
35 for (index, layer) in self.layers.iter().rev().enumerate() {
35 write_bytes!(
36 write_bytes!(
36 out,
37 out,
37 b"==== Layer {} (trusted: {}) ====\n{}",
38 b"==== Layer {} (trusted: {}) ====\n{}",
38 index,
39 index,
39 if layer.trusted {
40 if layer.trusted {
40 &b"yes"[..]
41 &b"yes"[..]
41 } else {
42 } else {
42 &b"no"[..]
43 &b"no"[..]
43 },
44 },
44 layer
45 layer
45 )?;
46 )?;
46 }
47 }
47 Ok(())
48 Ok(())
48 }
49 }
49 }
50 }
50
51
51 pub enum ConfigSource {
52 pub enum ConfigSource {
52 /// Absolute path to a config file
53 /// Absolute path to a config file
53 AbsPath(PathBuf),
54 AbsPath(PathBuf),
54 /// Already parsed (from the CLI, env, Python resources, etc.)
55 /// Already parsed (from the CLI, env, Python resources, etc.)
55 Parsed(layer::ConfigLayer),
56 Parsed(layer::ConfigLayer),
56 }
57 }
57
58
58 #[derive(Debug)]
59 #[derive(Debug)]
59 pub struct ConfigValueParseError {
60 pub struct ConfigValueParseError {
60 pub origin: ConfigOrigin,
61 pub origin: ConfigOrigin,
61 pub line: Option<usize>,
62 pub line: Option<usize>,
62 pub section: Vec<u8>,
63 pub section: Vec<u8>,
63 pub item: Vec<u8>,
64 pub item: Vec<u8>,
64 pub value: Vec<u8>,
65 pub value: Vec<u8>,
65 pub expected_type: &'static str,
66 pub expected_type: &'static str,
66 }
67 }
67
68
68 impl Config {
69 impl Config {
69 /// Load system and user configuration from various files.
70 /// Load system and user configuration from various files.
70 ///
71 ///
71 /// This is also affected by some environment variables.
72 /// This is also affected by some environment variables.
72 pub fn load(
73 pub fn load(
73 cli_config_args: impl IntoIterator<Item = impl AsRef<[u8]>>,
74 cli_config_args: impl IntoIterator<Item = impl AsRef<[u8]>>,
74 ) -> Result<Self, ConfigError> {
75 ) -> Result<Self, ConfigError> {
75 let mut config = Self { layers: Vec::new() };
76 let mut config = Self { layers: Vec::new() };
76 let opt_rc_path = env::var_os("HGRCPATH");
77 let opt_rc_path = env::var_os("HGRCPATH");
77 // HGRCPATH replaces system config
78 // HGRCPATH replaces system config
78 if opt_rc_path.is_none() {
79 if opt_rc_path.is_none() {
79 config.add_system_config()?
80 config.add_system_config()?
80 }
81 }
81
82
82 config.add_for_environment_variable("EDITOR", b"ui", b"editor");
83 config.add_for_environment_variable("EDITOR", b"ui", b"editor");
83 config.add_for_environment_variable("VISUAL", b"ui", b"editor");
84 config.add_for_environment_variable("VISUAL", b"ui", b"editor");
84 config.add_for_environment_variable("PAGER", b"pager", b"pager");
85 config.add_for_environment_variable("PAGER", b"pager", b"pager");
85
86
86 // These are set by `run-tests.py --rhg` to enable fallback for the
87 // These are set by `run-tests.py --rhg` to enable fallback for the
87 // entire test suite. Alternatives would be setting configuration
88 // entire test suite. Alternatives would be setting configuration
88 // through `$HGRCPATH` but some tests override that, or changing the
89 // through `$HGRCPATH` but some tests override that, or changing the
89 // `hg` shell alias to include `--config` but that disrupts tests that
90 // `hg` shell alias to include `--config` but that disrupts tests that
90 // print command lines and check expected output.
91 // print command lines and check expected output.
91 config.add_for_environment_variable(
92 config.add_for_environment_variable(
92 "RHG_ON_UNSUPPORTED",
93 "RHG_ON_UNSUPPORTED",
93 b"rhg",
94 b"rhg",
94 b"on-unsupported",
95 b"on-unsupported",
95 );
96 );
96 config.add_for_environment_variable(
97 config.add_for_environment_variable(
97 "RHG_FALLBACK_EXECUTABLE",
98 "RHG_FALLBACK_EXECUTABLE",
98 b"rhg",
99 b"rhg",
99 b"fallback-executable",
100 b"fallback-executable",
100 );
101 );
101
102
102 // HGRCPATH replaces user config
103 // HGRCPATH replaces user config
103 if opt_rc_path.is_none() {
104 if opt_rc_path.is_none() {
104 config.add_user_config()?
105 config.add_user_config()?
105 }
106 }
106 if let Some(rc_path) = &opt_rc_path {
107 if let Some(rc_path) = &opt_rc_path {
107 for path in env::split_paths(rc_path) {
108 for path in env::split_paths(rc_path) {
108 if !path.as_os_str().is_empty() {
109 if !path.as_os_str().is_empty() {
109 if path.is_dir() {
110 if path.is_dir() {
110 config.add_trusted_dir(&path)?
111 config.add_trusted_dir(&path)?
111 } else {
112 } else {
112 config.add_trusted_file(&path)?
113 config.add_trusted_file(&path)?
113 }
114 }
114 }
115 }
115 }
116 }
116 }
117 }
117 if let Some(layer) = ConfigLayer::parse_cli_args(cli_config_args)? {
118 if let Some(layer) = ConfigLayer::parse_cli_args(cli_config_args)? {
118 config.layers.push(layer)
119 config.layers.push(layer)
119 }
120 }
120 Ok(config)
121 Ok(config)
121 }
122 }
122
123
123 fn add_trusted_dir(&mut self, path: &Path) -> Result<(), ConfigError> {
124 fn add_trusted_dir(&mut self, path: &Path) -> Result<(), ConfigError> {
124 if let Some(entries) = std::fs::read_dir(path)
125 if let Some(entries) = std::fs::read_dir(path)
125 .when_reading_file(path)
126 .when_reading_file(path)
126 .io_not_found_as_none()?
127 .io_not_found_as_none()?
127 {
128 {
128 let mut file_paths = entries
129 let mut file_paths = entries
129 .map(|result| {
130 .map(|result| {
130 result.when_reading_file(path).map(|entry| entry.path())
131 result.when_reading_file(path).map(|entry| entry.path())
131 })
132 })
132 .collect::<Result<Vec<_>, _>>()?;
133 .collect::<Result<Vec<_>, _>>()?;
133 file_paths.sort();
134 file_paths.sort();
134 for file_path in &file_paths {
135 for file_path in &file_paths {
135 if file_path.extension() == Some(std::ffi::OsStr::new("rc")) {
136 if file_path.extension() == Some(std::ffi::OsStr::new("rc")) {
136 self.add_trusted_file(&file_path)?
137 self.add_trusted_file(&file_path)?
137 }
138 }
138 }
139 }
139 }
140 }
140 Ok(())
141 Ok(())
141 }
142 }
142
143
143 fn add_trusted_file(&mut self, path: &Path) -> Result<(), ConfigError> {
144 fn add_trusted_file(&mut self, path: &Path) -> Result<(), ConfigError> {
144 if let Some(data) = std::fs::read(path)
145 if let Some(data) = std::fs::read(path)
145 .when_reading_file(path)
146 .when_reading_file(path)
146 .io_not_found_as_none()?
147 .io_not_found_as_none()?
147 {
148 {
148 self.layers.extend(ConfigLayer::parse(path, &data)?)
149 self.layers.extend(ConfigLayer::parse(path, &data)?)
149 }
150 }
150 Ok(())
151 Ok(())
151 }
152 }
152
153
153 fn add_for_environment_variable(
154 fn add_for_environment_variable(
154 &mut self,
155 &mut self,
155 var: &str,
156 var: &str,
156 section: &[u8],
157 section: &[u8],
157 key: &[u8],
158 key: &[u8],
158 ) {
159 ) {
159 if let Some(value) = env::var_os(var) {
160 if let Some(value) = env::var_os(var) {
160 let origin = layer::ConfigOrigin::Environment(var.into());
161 let origin = layer::ConfigOrigin::Environment(var.into());
161 let mut layer = ConfigLayer::new(origin);
162 let mut layer = ConfigLayer::new(origin);
162 layer.add(
163 layer.add(
163 section.to_owned(),
164 section.to_owned(),
164 key.to_owned(),
165 key.to_owned(),
165 get_bytes_from_os_str(value),
166 get_bytes_from_os_str(value),
166 None,
167 None,
167 );
168 );
168 self.layers.push(layer)
169 self.layers.push(layer)
169 }
170 }
170 }
171 }
171
172
172 #[cfg(unix)] // TODO: other platforms
173 #[cfg(unix)] // TODO: other platforms
173 fn add_system_config(&mut self) -> Result<(), ConfigError> {
174 fn add_system_config(&mut self) -> Result<(), ConfigError> {
174 let mut add_for_prefix = |prefix: &Path| -> Result<(), ConfigError> {
175 let mut add_for_prefix = |prefix: &Path| -> Result<(), ConfigError> {
175 let etc = prefix.join("etc").join("mercurial");
176 let etc = prefix.join("etc").join("mercurial");
176 self.add_trusted_file(&etc.join("hgrc"))?;
177 self.add_trusted_file(&etc.join("hgrc"))?;
177 self.add_trusted_dir(&etc.join("hgrc.d"))
178 self.add_trusted_dir(&etc.join("hgrc.d"))
178 };
179 };
179 let root = Path::new("/");
180 let root = Path::new("/");
180 // TODO: use `std::env::args_os().next().unwrap()` a.k.a. argv[0]
181 // TODO: use `std::env::args_os().next().unwrap()` a.k.a. argv[0]
181 // instead? TODO: can this be a relative path?
182 // instead? TODO: can this be a relative path?
182 let hg = crate::utils::current_exe()?;
183 let hg = crate::utils::current_exe()?;
183 // TODO: this order (per-installation then per-system) matches
184 // TODO: this order (per-installation then per-system) matches
184 // `systemrcpath()` in `mercurial/scmposix.py`, but
185 // `systemrcpath()` in `mercurial/scmposix.py`, but
185 // `mercurial/helptext/config.txt` suggests it should be reversed
186 // `mercurial/helptext/config.txt` suggests it should be reversed
186 if let Some(installation_prefix) = hg.parent().and_then(Path::parent) {
187 if let Some(installation_prefix) = hg.parent().and_then(Path::parent) {
187 if installation_prefix != root {
188 if installation_prefix != root {
188 add_for_prefix(&installation_prefix)?
189 add_for_prefix(&installation_prefix)?
189 }
190 }
190 }
191 }
191 add_for_prefix(root)?;
192 add_for_prefix(root)?;
192 Ok(())
193 Ok(())
193 }
194 }
194
195
195 #[cfg(unix)] // TODO: other plateforms
196 #[cfg(unix)] // TODO: other plateforms
196 fn add_user_config(&mut self) -> Result<(), ConfigError> {
197 fn add_user_config(&mut self) -> Result<(), ConfigError> {
197 let opt_home = home::home_dir();
198 let opt_home = home::home_dir();
198 if let Some(home) = &opt_home {
199 if let Some(home) = &opt_home {
199 self.add_trusted_file(&home.join(".hgrc"))?
200 self.add_trusted_file(&home.join(".hgrc"))?
200 }
201 }
201 let darwin = cfg!(any(target_os = "macos", target_os = "ios"));
202 let darwin = cfg!(any(target_os = "macos", target_os = "ios"));
202 if !darwin {
203 if !darwin {
203 if let Some(config_home) = env::var_os("XDG_CONFIG_HOME")
204 if let Some(config_home) = env::var_os("XDG_CONFIG_HOME")
204 .map(PathBuf::from)
205 .map(PathBuf::from)
205 .or_else(|| opt_home.map(|home| home.join(".config")))
206 .or_else(|| opt_home.map(|home| home.join(".config")))
206 {
207 {
207 self.add_trusted_file(&config_home.join("hg").join("hgrc"))?
208 self.add_trusted_file(&config_home.join("hg").join("hgrc"))?
208 }
209 }
209 }
210 }
210 Ok(())
211 Ok(())
211 }
212 }
212
213
213 /// Loads in order, which means that the precedence is the same
214 /// Loads in order, which means that the precedence is the same
214 /// as the order of `sources`.
215 /// as the order of `sources`.
215 pub fn load_from_explicit_sources(
216 pub fn load_from_explicit_sources(
216 sources: Vec<ConfigSource>,
217 sources: Vec<ConfigSource>,
217 ) -> Result<Self, ConfigError> {
218 ) -> Result<Self, ConfigError> {
218 let mut layers = vec![];
219 let mut layers = vec![];
219
220
220 for source in sources.into_iter() {
221 for source in sources.into_iter() {
221 match source {
222 match source {
222 ConfigSource::Parsed(c) => layers.push(c),
223 ConfigSource::Parsed(c) => layers.push(c),
223 ConfigSource::AbsPath(c) => {
224 ConfigSource::AbsPath(c) => {
224 // TODO check if it should be trusted
225 // TODO check if it should be trusted
225 // mercurial/ui.py:427
226 // mercurial/ui.py:427
226 let data = match std::fs::read(&c) {
227 let data = match std::fs::read(&c) {
227 Err(_) => continue, // same as the python code
228 Err(_) => continue, // same as the python code
228 Ok(data) => data,
229 Ok(data) => data,
229 };
230 };
230 layers.extend(ConfigLayer::parse(&c, &data)?)
231 layers.extend(ConfigLayer::parse(&c, &data)?)
231 }
232 }
232 }
233 }
233 }
234 }
234
235
235 Ok(Config { layers })
236 Ok(Config { layers })
236 }
237 }
237
238
238 /// Loads the per-repository config into a new `Config` which is combined
239 /// Loads the per-repository config into a new `Config` which is combined
239 /// with `self`.
240 /// with `self`.
240 pub(crate) fn combine_with_repo(
241 pub(crate) fn combine_with_repo(
241 &self,
242 &self,
242 repo_config_files: &[PathBuf],
243 repo_config_files: &[PathBuf],
243 ) -> Result<Self, ConfigError> {
244 ) -> Result<Self, ConfigError> {
244 let (cli_layers, other_layers) = self
245 let (cli_layers, other_layers) = self
245 .layers
246 .layers
246 .iter()
247 .iter()
247 .cloned()
248 .cloned()
248 .partition(ConfigLayer::is_from_command_line);
249 .partition(ConfigLayer::is_from_command_line);
249
250
250 let mut repo_config = Self {
251 let mut repo_config = Self {
251 layers: other_layers,
252 layers: other_layers,
252 };
253 };
253 for path in repo_config_files {
254 for path in repo_config_files {
254 // TODO: check if this file should be trusted:
255 // TODO: check if this file should be trusted:
255 // `mercurial/ui.py:427`
256 // `mercurial/ui.py:427`
256 repo_config.add_trusted_file(path)?;
257 repo_config.add_trusted_file(path)?;
257 }
258 }
258 repo_config.layers.extend(cli_layers);
259 repo_config.layers.extend(cli_layers);
259 Ok(repo_config)
260 Ok(repo_config)
260 }
261 }
261
262
262 fn get_parse<'config, T: 'config>(
263 fn get_parse<'config, T: 'config>(
263 &'config self,
264 &'config self,
264 section: &[u8],
265 section: &[u8],
265 item: &[u8],
266 item: &[u8],
266 expected_type: &'static str,
267 expected_type: &'static str,
267 parse: impl Fn(&'config [u8]) -> Option<T>,
268 parse: impl Fn(&'config [u8]) -> Option<T>,
268 ) -> Result<Option<T>, ConfigValueParseError> {
269 ) -> Result<Option<T>, ConfigValueParseError> {
269 match self.get_inner(&section, &item) {
270 match self.get_inner(&section, &item) {
270 Some((layer, v)) => match parse(&v.bytes) {
271 Some((layer, v)) => match parse(&v.bytes) {
271 Some(b) => Ok(Some(b)),
272 Some(b) => Ok(Some(b)),
272 None => Err(ConfigValueParseError {
273 None => Err(ConfigValueParseError {
273 origin: layer.origin.to_owned(),
274 origin: layer.origin.to_owned(),
274 line: v.line,
275 line: v.line,
275 value: v.bytes.to_owned(),
276 value: v.bytes.to_owned(),
276 section: section.to_owned(),
277 section: section.to_owned(),
277 item: item.to_owned(),
278 item: item.to_owned(),
278 expected_type,
279 expected_type,
279 }),
280 }),
280 },
281 },
281 None => Ok(None),
282 None => Ok(None),
282 }
283 }
283 }
284 }
284
285
285 /// Returns an `Err` if the first value found is not a valid UTF-8 string.
286 /// Returns an `Err` if the first value found is not a valid UTF-8 string.
286 /// Otherwise, returns an `Ok(value)` if found, or `None`.
287 /// Otherwise, returns an `Ok(value)` if found, or `None`.
287 pub fn get_str(
288 pub fn get_str(
288 &self,
289 &self,
289 section: &[u8],
290 section: &[u8],
290 item: &[u8],
291 item: &[u8],
291 ) -> Result<Option<&str>, ConfigValueParseError> {
292 ) -> Result<Option<&str>, ConfigValueParseError> {
292 self.get_parse(section, item, "ASCII or UTF-8 string", |value| {
293 self.get_parse(section, item, "ASCII or UTF-8 string", |value| {
293 str::from_utf8(value).ok()
294 str::from_utf8(value).ok()
294 })
295 })
295 }
296 }
296
297
297 /// Returns an `Err` if the first value found is not a valid unsigned
298 /// Returns an `Err` if the first value found is not a valid unsigned
298 /// integer. Otherwise, returns an `Ok(value)` if found, or `None`.
299 /// integer. Otherwise, returns an `Ok(value)` if found, or `None`.
299 pub fn get_u32(
300 pub fn get_u32(
300 &self,
301 &self,
301 section: &[u8],
302 section: &[u8],
302 item: &[u8],
303 item: &[u8],
303 ) -> Result<Option<u32>, ConfigValueParseError> {
304 ) -> Result<Option<u32>, ConfigValueParseError> {
304 self.get_parse(section, item, "valid integer", |value| {
305 self.get_parse(section, item, "valid integer", |value| {
305 str::from_utf8(value).ok()?.parse().ok()
306 str::from_utf8(value).ok()?.parse().ok()
306 })
307 })
307 }
308 }
308
309
309 /// Returns an `Err` if the first value found is not a valid file size
310 /// Returns an `Err` if the first value found is not a valid file size
310 /// value such as `30` (default unit is bytes), `7 MB`, or `42.5 kb`.
311 /// value such as `30` (default unit is bytes), `7 MB`, or `42.5 kb`.
311 /// Otherwise, returns an `Ok(value_in_bytes)` if found, or `None`.
312 /// Otherwise, returns an `Ok(value_in_bytes)` if found, or `None`.
312 pub fn get_byte_size(
313 pub fn get_byte_size(
313 &self,
314 &self,
314 section: &[u8],
315 section: &[u8],
315 item: &[u8],
316 item: &[u8],
316 ) -> Result<Option<u64>, ConfigValueParseError> {
317 ) -> Result<Option<u64>, ConfigValueParseError> {
317 self.get_parse(section, item, "byte quantity", values::parse_byte_size)
318 self.get_parse(section, item, "byte quantity", values::parse_byte_size)
318 }
319 }
319
320
320 /// Returns an `Err` if the first value found is not a valid boolean.
321 /// Returns an `Err` if the first value found is not a valid boolean.
321 /// Otherwise, returns an `Ok(option)`, where `option` is the boolean if
322 /// Otherwise, returns an `Ok(option)`, where `option` is the boolean if
322 /// found, or `None`.
323 /// found, or `None`.
323 pub fn get_option(
324 pub fn get_option(
324 &self,
325 &self,
325 section: &[u8],
326 section: &[u8],
326 item: &[u8],
327 item: &[u8],
327 ) -> Result<Option<bool>, ConfigValueParseError> {
328 ) -> Result<Option<bool>, ConfigValueParseError> {
328 self.get_parse(section, item, "boolean", values::parse_bool)
329 self.get_parse(section, item, "boolean", values::parse_bool)
329 }
330 }
330
331
331 /// Returns the corresponding boolean in the config. Returns `Ok(false)`
332 /// Returns the corresponding boolean in the config. Returns `Ok(false)`
332 /// if the value is not found, an `Err` if it's not a valid boolean.
333 /// if the value is not found, an `Err` if it's not a valid boolean.
333 pub fn get_bool(
334 pub fn get_bool(
334 &self,
335 &self,
335 section: &[u8],
336 section: &[u8],
336 item: &[u8],
337 item: &[u8],
337 ) -> Result<bool, ConfigValueParseError> {
338 ) -> Result<bool, ConfigValueParseError> {
338 Ok(self.get_option(section, item)?.unwrap_or(false))
339 Ok(self.get_option(section, item)?.unwrap_or(false))
339 }
340 }
340
341
341 /// Returns the raw value bytes of the first one found, or `None`.
342 /// Returns the raw value bytes of the first one found, or `None`.
342 pub fn get(&self, section: &[u8], item: &[u8]) -> Option<&[u8]> {
343 pub fn get(&self, section: &[u8], item: &[u8]) -> Option<&[u8]> {
343 self.get_inner(section, item)
344 self.get_inner(section, item)
344 .map(|(_, value)| value.bytes.as_ref())
345 .map(|(_, value)| value.bytes.as_ref())
345 }
346 }
346
347
347 /// Returns the layer and the value of the first one found, or `None`.
348 /// Returns the layer and the value of the first one found, or `None`.
348 fn get_inner(
349 fn get_inner(
349 &self,
350 &self,
350 section: &[u8],
351 section: &[u8],
351 item: &[u8],
352 item: &[u8],
352 ) -> Option<(&ConfigLayer, &ConfigValue)> {
353 ) -> Option<(&ConfigLayer, &ConfigValue)> {
353 for layer in self.layers.iter().rev() {
354 for layer in self.layers.iter().rev() {
354 if !layer.trusted {
355 if !layer.trusted {
355 continue;
356 continue;
356 }
357 }
357 if let Some(v) = layer.get(&section, &item) {
358 if let Some(v) = layer.get(&section, &item) {
358 return Some((&layer, v));
359 return Some((&layer, v));
359 }
360 }
360 }
361 }
361 None
362 None
362 }
363 }
363
364
365 /// Return all keys defined for the given section
366 pub fn get_section_keys(&self, section: &[u8]) -> HashSet<&[u8]> {
367 self.layers
368 .iter()
369 .flat_map(|layer| layer.iter_keys(section))
370 .collect()
371 }
372
364 /// Get raw values bytes from all layers (even untrusted ones) in order
373 /// Get raw values bytes from all layers (even untrusted ones) in order
365 /// of precedence.
374 /// of precedence.
366 #[cfg(test)]
375 #[cfg(test)]
367 fn get_all(&self, section: &[u8], item: &[u8]) -> Vec<&[u8]> {
376 fn get_all(&self, section: &[u8], item: &[u8]) -> Vec<&[u8]> {
368 let mut res = vec![];
377 let mut res = vec![];
369 for layer in self.layers.iter().rev() {
378 for layer in self.layers.iter().rev() {
370 if let Some(v) = layer.get(&section, &item) {
379 if let Some(v) = layer.get(&section, &item) {
371 res.push(v.bytes.as_ref());
380 res.push(v.bytes.as_ref());
372 }
381 }
373 }
382 }
374 res
383 res
375 }
384 }
376 }
385 }
377
386
378 #[cfg(test)]
387 #[cfg(test)]
379 mod tests {
388 mod tests {
380 use super::*;
389 use super::*;
381 use pretty_assertions::assert_eq;
390 use pretty_assertions::assert_eq;
382 use std::fs::File;
391 use std::fs::File;
383 use std::io::Write;
392 use std::io::Write;
384
393
385 #[test]
394 #[test]
386 fn test_include_layer_ordering() {
395 fn test_include_layer_ordering() {
387 let tmpdir = tempfile::tempdir().unwrap();
396 let tmpdir = tempfile::tempdir().unwrap();
388 let tmpdir_path = tmpdir.path();
397 let tmpdir_path = tmpdir.path();
389 let mut included_file =
398 let mut included_file =
390 File::create(&tmpdir_path.join("included.rc")).unwrap();
399 File::create(&tmpdir_path.join("included.rc")).unwrap();
391
400
392 included_file.write_all(b"[section]\nitem=value1").unwrap();
401 included_file.write_all(b"[section]\nitem=value1").unwrap();
393 let base_config_path = tmpdir_path.join("base.rc");
402 let base_config_path = tmpdir_path.join("base.rc");
394 let mut config_file = File::create(&base_config_path).unwrap();
403 let mut config_file = File::create(&base_config_path).unwrap();
395 let data =
404 let data =
396 b"[section]\nitem=value0\n%include included.rc\nitem=value2\n\
405 b"[section]\nitem=value0\n%include included.rc\nitem=value2\n\
397 [section2]\ncount = 4\nsize = 1.5 KB\nnot-count = 1.5\nnot-size = 1 ub";
406 [section2]\ncount = 4\nsize = 1.5 KB\nnot-count = 1.5\nnot-size = 1 ub";
398 config_file.write_all(data).unwrap();
407 config_file.write_all(data).unwrap();
399
408
400 let sources = vec![ConfigSource::AbsPath(base_config_path)];
409 let sources = vec![ConfigSource::AbsPath(base_config_path)];
401 let config = Config::load_from_explicit_sources(sources)
410 let config = Config::load_from_explicit_sources(sources)
402 .expect("expected valid config");
411 .expect("expected valid config");
403
412
404 let (_, value) = config.get_inner(b"section", b"item").unwrap();
413 let (_, value) = config.get_inner(b"section", b"item").unwrap();
405 assert_eq!(
414 assert_eq!(
406 value,
415 value,
407 &ConfigValue {
416 &ConfigValue {
408 bytes: b"value2".to_vec(),
417 bytes: b"value2".to_vec(),
409 line: Some(4)
418 line: Some(4)
410 }
419 }
411 );
420 );
412
421
413 let value = config.get(b"section", b"item").unwrap();
422 let value = config.get(b"section", b"item").unwrap();
414 assert_eq!(value, b"value2",);
423 assert_eq!(value, b"value2",);
415 assert_eq!(
424 assert_eq!(
416 config.get_all(b"section", b"item"),
425 config.get_all(b"section", b"item"),
417 [b"value2", b"value1", b"value0"]
426 [b"value2", b"value1", b"value0"]
418 );
427 );
419
428
420 assert_eq!(config.get_u32(b"section2", b"count").unwrap(), Some(4));
429 assert_eq!(config.get_u32(b"section2", b"count").unwrap(), Some(4));
421 assert_eq!(
430 assert_eq!(
422 config.get_byte_size(b"section2", b"size").unwrap(),
431 config.get_byte_size(b"section2", b"size").unwrap(),
423 Some(1024 + 512)
432 Some(1024 + 512)
424 );
433 );
425 assert!(config.get_u32(b"section2", b"not-count").is_err());
434 assert!(config.get_u32(b"section2", b"not-count").is_err());
426 assert!(config.get_byte_size(b"section2", b"not-size").is_err());
435 assert!(config.get_byte_size(b"section2", b"not-size").is_err());
427 }
436 }
428 }
437 }
@@ -1,297 +1,305 b''
1 // layer.rs
1 // layer.rs
2 //
2 //
3 // Copyright 2020
3 // Copyright 2020
4 // Valentin Gatien-Baron,
4 // Valentin Gatien-Baron,
5 // Raphaël Gomès <rgomes@octobus.net>
5 // Raphaël Gomès <rgomes@octobus.net>
6 //
6 //
7 // This software may be used and distributed according to the terms of the
7 // This software may be used and distributed according to the terms of the
8 // GNU General Public License version 2 or any later version.
8 // GNU General Public License version 2 or any later version.
9
9
10 use crate::errors::{HgError, IoResultExt};
10 use crate::errors::{HgError, IoResultExt};
11 use crate::utils::files::{get_bytes_from_path, get_path_from_bytes};
11 use crate::utils::files::{get_bytes_from_path, get_path_from_bytes};
12 use format_bytes::{format_bytes, write_bytes, DisplayBytes};
12 use format_bytes::{format_bytes, write_bytes, DisplayBytes};
13 use lazy_static::lazy_static;
13 use lazy_static::lazy_static;
14 use regex::bytes::Regex;
14 use regex::bytes::Regex;
15 use std::collections::HashMap;
15 use std::collections::HashMap;
16 use std::path::{Path, PathBuf};
16 use std::path::{Path, PathBuf};
17
17
18 lazy_static! {
18 lazy_static! {
19 static ref SECTION_RE: Regex = make_regex(r"^\[([^\[]+)\]");
19 static ref SECTION_RE: Regex = make_regex(r"^\[([^\[]+)\]");
20 static ref ITEM_RE: Regex = make_regex(r"^([^=\s][^=]*?)\s*=\s*((.*\S)?)");
20 static ref ITEM_RE: Regex = make_regex(r"^([^=\s][^=]*?)\s*=\s*((.*\S)?)");
21 /// Continuation whitespace
21 /// Continuation whitespace
22 static ref CONT_RE: Regex = make_regex(r"^\s+(\S|\S.*\S)\s*$");
22 static ref CONT_RE: Regex = make_regex(r"^\s+(\S|\S.*\S)\s*$");
23 static ref EMPTY_RE: Regex = make_regex(r"^(;|#|\s*$)");
23 static ref EMPTY_RE: Regex = make_regex(r"^(;|#|\s*$)");
24 static ref COMMENT_RE: Regex = make_regex(r"^(;|#)");
24 static ref COMMENT_RE: Regex = make_regex(r"^(;|#)");
25 /// A directive that allows for removing previous entries
25 /// A directive that allows for removing previous entries
26 static ref UNSET_RE: Regex = make_regex(r"^%unset\s+(\S+)");
26 static ref UNSET_RE: Regex = make_regex(r"^%unset\s+(\S+)");
27 /// A directive that allows for including other config files
27 /// A directive that allows for including other config files
28 static ref INCLUDE_RE: Regex = make_regex(r"^%include\s+(\S|\S.*\S)\s*$");
28 static ref INCLUDE_RE: Regex = make_regex(r"^%include\s+(\S|\S.*\S)\s*$");
29 }
29 }
30
30
31 /// All config values separated by layers of precedence.
31 /// All config values separated by layers of precedence.
32 /// Each config source may be split in multiple layers if `%include` directives
32 /// Each config source may be split in multiple layers if `%include` directives
33 /// are used.
33 /// are used.
34 /// TODO detail the general precedence
34 /// TODO detail the general precedence
35 #[derive(Clone)]
35 #[derive(Clone)]
36 pub struct ConfigLayer {
36 pub struct ConfigLayer {
37 /// Mapping of the sections to their items
37 /// Mapping of the sections to their items
38 sections: HashMap<Vec<u8>, ConfigItem>,
38 sections: HashMap<Vec<u8>, ConfigItem>,
39 /// All sections (and their items/values) in a layer share the same origin
39 /// All sections (and their items/values) in a layer share the same origin
40 pub origin: ConfigOrigin,
40 pub origin: ConfigOrigin,
41 /// Whether this layer comes from a trusted user or group
41 /// Whether this layer comes from a trusted user or group
42 pub trusted: bool,
42 pub trusted: bool,
43 }
43 }
44
44
45 impl ConfigLayer {
45 impl ConfigLayer {
46 pub fn new(origin: ConfigOrigin) -> Self {
46 pub fn new(origin: ConfigOrigin) -> Self {
47 ConfigLayer {
47 ConfigLayer {
48 sections: HashMap::new(),
48 sections: HashMap::new(),
49 trusted: true, // TODO check
49 trusted: true, // TODO check
50 origin,
50 origin,
51 }
51 }
52 }
52 }
53
53
54 /// Parse `--config` CLI arguments and return a layer if there’s any
54 /// Parse `--config` CLI arguments and return a layer if there’s any
55 pub(crate) fn parse_cli_args(
55 pub(crate) fn parse_cli_args(
56 cli_config_args: impl IntoIterator<Item = impl AsRef<[u8]>>,
56 cli_config_args: impl IntoIterator<Item = impl AsRef<[u8]>>,
57 ) -> Result<Option<Self>, ConfigError> {
57 ) -> Result<Option<Self>, ConfigError> {
58 fn parse_one(arg: &[u8]) -> Option<(Vec<u8>, Vec<u8>, Vec<u8>)> {
58 fn parse_one(arg: &[u8]) -> Option<(Vec<u8>, Vec<u8>, Vec<u8>)> {
59 use crate::utils::SliceExt;
59 use crate::utils::SliceExt;
60
60
61 let (section_and_item, value) = arg.split_2(b'=')?;
61 let (section_and_item, value) = arg.split_2(b'=')?;
62 let (section, item) = section_and_item.trim().split_2(b'.')?;
62 let (section, item) = section_and_item.trim().split_2(b'.')?;
63 Some((
63 Some((
64 section.to_owned(),
64 section.to_owned(),
65 item.to_owned(),
65 item.to_owned(),
66 value.trim().to_owned(),
66 value.trim().to_owned(),
67 ))
67 ))
68 }
68 }
69
69
70 let mut layer = Self::new(ConfigOrigin::CommandLine);
70 let mut layer = Self::new(ConfigOrigin::CommandLine);
71 for arg in cli_config_args {
71 for arg in cli_config_args {
72 let arg = arg.as_ref();
72 let arg = arg.as_ref();
73 if let Some((section, item, value)) = parse_one(arg) {
73 if let Some((section, item, value)) = parse_one(arg) {
74 layer.add(section, item, value, None);
74 layer.add(section, item, value, None);
75 } else {
75 } else {
76 Err(HgError::abort(format!(
76 Err(HgError::abort(format!(
77 "malformed --config option: '{}' \
77 "malformed --config option: '{}' \
78 (use --config section.name=value)",
78 (use --config section.name=value)",
79 String::from_utf8_lossy(arg),
79 String::from_utf8_lossy(arg),
80 )))?
80 )))?
81 }
81 }
82 }
82 }
83 if layer.sections.is_empty() {
83 if layer.sections.is_empty() {
84 Ok(None)
84 Ok(None)
85 } else {
85 } else {
86 Ok(Some(layer))
86 Ok(Some(layer))
87 }
87 }
88 }
88 }
89
89
90 /// Returns whether this layer comes from `--config` CLI arguments
90 /// Returns whether this layer comes from `--config` CLI arguments
91 pub(crate) fn is_from_command_line(&self) -> bool {
91 pub(crate) fn is_from_command_line(&self) -> bool {
92 if let ConfigOrigin::CommandLine = self.origin {
92 if let ConfigOrigin::CommandLine = self.origin {
93 true
93 true
94 } else {
94 } else {
95 false
95 false
96 }
96 }
97 }
97 }
98
98
99 /// Add an entry to the config, overwriting the old one if already present.
99 /// Add an entry to the config, overwriting the old one if already present.
100 pub fn add(
100 pub fn add(
101 &mut self,
101 &mut self,
102 section: Vec<u8>,
102 section: Vec<u8>,
103 item: Vec<u8>,
103 item: Vec<u8>,
104 value: Vec<u8>,
104 value: Vec<u8>,
105 line: Option<usize>,
105 line: Option<usize>,
106 ) {
106 ) {
107 self.sections
107 self.sections
108 .entry(section)
108 .entry(section)
109 .or_insert_with(|| HashMap::new())
109 .or_insert_with(|| HashMap::new())
110 .insert(item, ConfigValue { bytes: value, line });
110 .insert(item, ConfigValue { bytes: value, line });
111 }
111 }
112
112
113 /// Returns the config value in `<section>.<item>` if it exists
113 /// Returns the config value in `<section>.<item>` if it exists
114 pub fn get(&self, section: &[u8], item: &[u8]) -> Option<&ConfigValue> {
114 pub fn get(&self, section: &[u8], item: &[u8]) -> Option<&ConfigValue> {
115 Some(self.sections.get(section)?.get(item)?)
115 Some(self.sections.get(section)?.get(item)?)
116 }
116 }
117
117
118 /// Returns the keys defined in the given section
119 pub fn iter_keys(&self, section: &[u8]) -> impl Iterator<Item = &[u8]> {
120 self.sections
121 .get(section)
122 .into_iter()
123 .flat_map(|section| section.keys().map(|vec| &**vec))
124 }
125
118 pub fn is_empty(&self) -> bool {
126 pub fn is_empty(&self) -> bool {
119 self.sections.is_empty()
127 self.sections.is_empty()
120 }
128 }
121
129
122 /// Returns a `Vec` of layers in order of precedence (so, in read order),
130 /// Returns a `Vec` of layers in order of precedence (so, in read order),
123 /// recursively parsing the `%include` directives if any.
131 /// recursively parsing the `%include` directives if any.
124 pub fn parse(src: &Path, data: &[u8]) -> Result<Vec<Self>, ConfigError> {
132 pub fn parse(src: &Path, data: &[u8]) -> Result<Vec<Self>, ConfigError> {
125 let mut layers = vec![];
133 let mut layers = vec![];
126
134
127 // Discard byte order mark if any
135 // Discard byte order mark if any
128 let data = if data.starts_with(b"\xef\xbb\xbf") {
136 let data = if data.starts_with(b"\xef\xbb\xbf") {
129 &data[3..]
137 &data[3..]
130 } else {
138 } else {
131 data
139 data
132 };
140 };
133
141
134 // TODO check if it's trusted
142 // TODO check if it's trusted
135 let mut current_layer = Self::new(ConfigOrigin::File(src.to_owned()));
143 let mut current_layer = Self::new(ConfigOrigin::File(src.to_owned()));
136
144
137 let mut lines_iter =
145 let mut lines_iter =
138 data.split(|b| *b == b'\n').enumerate().peekable();
146 data.split(|b| *b == b'\n').enumerate().peekable();
139 let mut section = b"".to_vec();
147 let mut section = b"".to_vec();
140
148
141 while let Some((index, bytes)) = lines_iter.next() {
149 while let Some((index, bytes)) = lines_iter.next() {
142 if let Some(m) = INCLUDE_RE.captures(&bytes) {
150 if let Some(m) = INCLUDE_RE.captures(&bytes) {
143 let filename_bytes = &m[1];
151 let filename_bytes = &m[1];
144 // `Path::parent` only fails for the root directory,
152 // `Path::parent` only fails for the root directory,
145 // which `src` can’t be since we’ve managed to open it as a
153 // which `src` can’t be since we’ve managed to open it as a
146 // file.
154 // file.
147 let dir = src
155 let dir = src
148 .parent()
156 .parent()
149 .expect("Path::parent fail on a file we’ve read");
157 .expect("Path::parent fail on a file we’ve read");
150 // `Path::join` with an absolute argument correctly ignores the
158 // `Path::join` with an absolute argument correctly ignores the
151 // base path
159 // base path
152 let filename = dir.join(&get_path_from_bytes(&filename_bytes));
160 let filename = dir.join(&get_path_from_bytes(&filename_bytes));
153 let data =
161 let data =
154 std::fs::read(&filename).when_reading_file(&filename)?;
162 std::fs::read(&filename).when_reading_file(&filename)?;
155 layers.push(current_layer);
163 layers.push(current_layer);
156 layers.extend(Self::parse(&filename, &data)?);
164 layers.extend(Self::parse(&filename, &data)?);
157 current_layer = Self::new(ConfigOrigin::File(src.to_owned()));
165 current_layer = Self::new(ConfigOrigin::File(src.to_owned()));
158 } else if let Some(_) = EMPTY_RE.captures(&bytes) {
166 } else if let Some(_) = EMPTY_RE.captures(&bytes) {
159 } else if let Some(m) = SECTION_RE.captures(&bytes) {
167 } else if let Some(m) = SECTION_RE.captures(&bytes) {
160 section = m[1].to_vec();
168 section = m[1].to_vec();
161 } else if let Some(m) = ITEM_RE.captures(&bytes) {
169 } else if let Some(m) = ITEM_RE.captures(&bytes) {
162 let item = m[1].to_vec();
170 let item = m[1].to_vec();
163 let mut value = m[2].to_vec();
171 let mut value = m[2].to_vec();
164 loop {
172 loop {
165 match lines_iter.peek() {
173 match lines_iter.peek() {
166 None => break,
174 None => break,
167 Some((_, v)) => {
175 Some((_, v)) => {
168 if let Some(_) = COMMENT_RE.captures(&v) {
176 if let Some(_) = COMMENT_RE.captures(&v) {
169 } else if let Some(_) = CONT_RE.captures(&v) {
177 } else if let Some(_) = CONT_RE.captures(&v) {
170 value.extend(b"\n");
178 value.extend(b"\n");
171 value.extend(&m[1]);
179 value.extend(&m[1]);
172 } else {
180 } else {
173 break;
181 break;
174 }
182 }
175 }
183 }
176 };
184 };
177 lines_iter.next();
185 lines_iter.next();
178 }
186 }
179 current_layer.add(
187 current_layer.add(
180 section.clone(),
188 section.clone(),
181 item,
189 item,
182 value,
190 value,
183 Some(index + 1),
191 Some(index + 1),
184 );
192 );
185 } else if let Some(m) = UNSET_RE.captures(&bytes) {
193 } else if let Some(m) = UNSET_RE.captures(&bytes) {
186 if let Some(map) = current_layer.sections.get_mut(&section) {
194 if let Some(map) = current_layer.sections.get_mut(&section) {
187 map.remove(&m[1]);
195 map.remove(&m[1]);
188 }
196 }
189 } else {
197 } else {
190 let message = if bytes.starts_with(b" ") {
198 let message = if bytes.starts_with(b" ") {
191 format_bytes!(b"unexpected leading whitespace: {}", bytes)
199 format_bytes!(b"unexpected leading whitespace: {}", bytes)
192 } else {
200 } else {
193 bytes.to_owned()
201 bytes.to_owned()
194 };
202 };
195 return Err(ConfigParseError {
203 return Err(ConfigParseError {
196 origin: ConfigOrigin::File(src.to_owned()),
204 origin: ConfigOrigin::File(src.to_owned()),
197 line: Some(index + 1),
205 line: Some(index + 1),
198 message,
206 message,
199 }
207 }
200 .into());
208 .into());
201 }
209 }
202 }
210 }
203 if !current_layer.is_empty() {
211 if !current_layer.is_empty() {
204 layers.push(current_layer);
212 layers.push(current_layer);
205 }
213 }
206 Ok(layers)
214 Ok(layers)
207 }
215 }
208 }
216 }
209
217
210 impl DisplayBytes for ConfigLayer {
218 impl DisplayBytes for ConfigLayer {
211 fn display_bytes(
219 fn display_bytes(
212 &self,
220 &self,
213 out: &mut dyn std::io::Write,
221 out: &mut dyn std::io::Write,
214 ) -> std::io::Result<()> {
222 ) -> std::io::Result<()> {
215 let mut sections: Vec<_> = self.sections.iter().collect();
223 let mut sections: Vec<_> = self.sections.iter().collect();
216 sections.sort_by(|e0, e1| e0.0.cmp(e1.0));
224 sections.sort_by(|e0, e1| e0.0.cmp(e1.0));
217
225
218 for (section, items) in sections.into_iter() {
226 for (section, items) in sections.into_iter() {
219 let mut items: Vec<_> = items.into_iter().collect();
227 let mut items: Vec<_> = items.into_iter().collect();
220 items.sort_by(|e0, e1| e0.0.cmp(e1.0));
228 items.sort_by(|e0, e1| e0.0.cmp(e1.0));
221
229
222 for (item, config_entry) in items {
230 for (item, config_entry) in items {
223 write_bytes!(
231 write_bytes!(
224 out,
232 out,
225 b"{}.{}={} # {}\n",
233 b"{}.{}={} # {}\n",
226 section,
234 section,
227 item,
235 item,
228 &config_entry.bytes,
236 &config_entry.bytes,
229 &self.origin,
237 &self.origin,
230 )?
238 )?
231 }
239 }
232 }
240 }
233 Ok(())
241 Ok(())
234 }
242 }
235 }
243 }
236
244
237 /// Mapping of section item to value.
245 /// Mapping of section item to value.
238 /// In the following:
246 /// In the following:
239 /// ```text
247 /// ```text
240 /// [ui]
248 /// [ui]
241 /// paginate=no
249 /// paginate=no
242 /// ```
250 /// ```
243 /// "paginate" is the section item and "no" the value.
251 /// "paginate" is the section item and "no" the value.
244 pub type ConfigItem = HashMap<Vec<u8>, ConfigValue>;
252 pub type ConfigItem = HashMap<Vec<u8>, ConfigValue>;
245
253
246 #[derive(Clone, Debug, PartialEq)]
254 #[derive(Clone, Debug, PartialEq)]
247 pub struct ConfigValue {
255 pub struct ConfigValue {
248 /// The raw bytes of the value (be it from the CLI, env or from a file)
256 /// The raw bytes of the value (be it from the CLI, env or from a file)
249 pub bytes: Vec<u8>,
257 pub bytes: Vec<u8>,
250 /// Only present if the value comes from a file, 1-indexed.
258 /// Only present if the value comes from a file, 1-indexed.
251 pub line: Option<usize>,
259 pub line: Option<usize>,
252 }
260 }
253
261
254 #[derive(Clone, Debug)]
262 #[derive(Clone, Debug)]
255 pub enum ConfigOrigin {
263 pub enum ConfigOrigin {
256 /// From a configuration file
264 /// From a configuration file
257 File(PathBuf),
265 File(PathBuf),
258 /// From a `--config` CLI argument
266 /// From a `--config` CLI argument
259 CommandLine,
267 CommandLine,
260 /// From environment variables like `$PAGER` or `$EDITOR`
268 /// From environment variables like `$PAGER` or `$EDITOR`
261 Environment(Vec<u8>),
269 Environment(Vec<u8>),
262 /* TODO cli
270 /* TODO cli
263 * TODO defaults (configitems.py)
271 * TODO defaults (configitems.py)
264 * TODO extensions
272 * TODO extensions
265 * TODO Python resources?
273 * TODO Python resources?
266 * Others? */
274 * Others? */
267 }
275 }
268
276
269 impl DisplayBytes for ConfigOrigin {
277 impl DisplayBytes for ConfigOrigin {
270 fn display_bytes(
278 fn display_bytes(
271 &self,
279 &self,
272 out: &mut dyn std::io::Write,
280 out: &mut dyn std::io::Write,
273 ) -> std::io::Result<()> {
281 ) -> std::io::Result<()> {
274 match self {
282 match self {
275 ConfigOrigin::File(p) => out.write_all(&get_bytes_from_path(p)),
283 ConfigOrigin::File(p) => out.write_all(&get_bytes_from_path(p)),
276 ConfigOrigin::CommandLine => out.write_all(b"--config"),
284 ConfigOrigin::CommandLine => out.write_all(b"--config"),
277 ConfigOrigin::Environment(e) => write_bytes!(out, b"${}", e),
285 ConfigOrigin::Environment(e) => write_bytes!(out, b"${}", e),
278 }
286 }
279 }
287 }
280 }
288 }
281
289
282 #[derive(Debug)]
290 #[derive(Debug)]
283 pub struct ConfigParseError {
291 pub struct ConfigParseError {
284 pub origin: ConfigOrigin,
292 pub origin: ConfigOrigin,
285 pub line: Option<usize>,
293 pub line: Option<usize>,
286 pub message: Vec<u8>,
294 pub message: Vec<u8>,
287 }
295 }
288
296
289 #[derive(Debug, derive_more::From)]
297 #[derive(Debug, derive_more::From)]
290 pub enum ConfigError {
298 pub enum ConfigError {
291 Parse(ConfigParseError),
299 Parse(ConfigParseError),
292 Other(HgError),
300 Other(HgError),
293 }
301 }
294
302
295 fn make_regex(pattern: &'static str) -> Regex {
303 fn make_regex(pattern: &'static str) -> Regex {
296 Regex::new(pattern).expect("expected a valid regex")
304 Regex::new(pattern).expect("expected a valid regex")
297 }
305 }
@@ -1,21 +1,21 b''
1 [package]
1 [package]
2 name = "rhg"
2 name = "rhg"
3 version = "0.1.0"
3 version = "0.1.0"
4 authors = [
4 authors = [
5 "Antoine Cezar <antoine.cezar@octobus.net>",
5 "Antoine Cezar <antoine.cezar@octobus.net>",
6 "Raphaël Gomès <raphael.gomes@octobus.net>",
6 "Raphaël Gomès <raphael.gomes@octobus.net>",
7 ]
7 ]
8 edition = "2018"
8 edition = "2018"
9
9
10 [dependencies]
10 [dependencies]
11 hg-core = { path = "../hg-core"}
11 hg-core = { path = "../hg-core"}
12 chrono = "0.4.19"
12 chrono = "0.4.19"
13 clap = "2.33.1"
13 clap = "2.33.1"
14 derive_more = "0.99"
14 derive_more = "0.99"
15 lazy_static = "1.4.0"
15 lazy_static = "1.4.0"
16 log = "0.4.11"
16 log = "0.4.11"
17 micro-timer = "0.3.1"
17 micro-timer = "0.3.1"
18 regex = "1.3.9"
18 regex = "1.3.9"
19 env_logger = "0.7.1"
19 env_logger = "0.7.1"
20 format-bytes = "0.2.0"
20 format-bytes = "0.2.1"
21 users = "0.11.0"
21 users = "0.11.0"
@@ -1,354 +1,378 b''
1 extern crate log;
1 extern crate log;
2 use crate::ui::Ui;
2 use crate::ui::Ui;
3 use clap::App;
3 use clap::App;
4 use clap::AppSettings;
4 use clap::AppSettings;
5 use clap::Arg;
5 use clap::Arg;
6 use clap::ArgMatches;
6 use clap::ArgMatches;
7 use format_bytes::format_bytes;
7 use format_bytes::{format_bytes, join};
8 use hg::config::Config;
8 use hg::config::Config;
9 use hg::repo::{Repo, RepoError};
9 use hg::repo::{Repo, RepoError};
10 use hg::utils::files::{get_bytes_from_os_str, get_path_from_bytes};
10 use hg::utils::files::{get_bytes_from_os_str, get_path_from_bytes};
11 use hg::utils::SliceExt;
11 use hg::utils::SliceExt;
12 use std::ffi::OsString;
12 use std::ffi::OsString;
13 use std::path::PathBuf;
13 use std::path::PathBuf;
14 use std::process::Command;
14 use std::process::Command;
15
15
16 mod blackbox;
16 mod blackbox;
17 mod error;
17 mod error;
18 mod exitcode;
18 mod exitcode;
19 mod ui;
19 mod ui;
20 use error::CommandError;
20 use error::CommandError;
21
21
22 fn main_with_result(
22 fn main_with_result(
23 process_start_time: &blackbox::ProcessStartTime,
23 process_start_time: &blackbox::ProcessStartTime,
24 ui: &ui::Ui,
24 ui: &ui::Ui,
25 repo: Result<&Repo, &NoRepoInCwdError>,
25 repo: Result<&Repo, &NoRepoInCwdError>,
26 config: &Config,
26 config: &Config,
27 ) -> Result<(), CommandError> {
27 ) -> Result<(), CommandError> {
28 check_extensions(config)?;
29
28 let app = App::new("rhg")
30 let app = App::new("rhg")
29 .global_setting(AppSettings::AllowInvalidUtf8)
31 .global_setting(AppSettings::AllowInvalidUtf8)
30 .setting(AppSettings::SubcommandRequired)
32 .setting(AppSettings::SubcommandRequired)
31 .setting(AppSettings::VersionlessSubcommands)
33 .setting(AppSettings::VersionlessSubcommands)
32 .arg(
34 .arg(
33 Arg::with_name("repository")
35 Arg::with_name("repository")
34 .help("repository root directory")
36 .help("repository root directory")
35 .short("-R")
37 .short("-R")
36 .long("--repository")
38 .long("--repository")
37 .value_name("REPO")
39 .value_name("REPO")
38 .takes_value(true)
40 .takes_value(true)
39 // Both ok: `hg -R ./foo log` or `hg log -R ./foo`
41 // Both ok: `hg -R ./foo log` or `hg log -R ./foo`
40 .global(true),
42 .global(true),
41 )
43 )
42 .arg(
44 .arg(
43 Arg::with_name("config")
45 Arg::with_name("config")
44 .help("set/override config option (use 'section.name=value')")
46 .help("set/override config option (use 'section.name=value')")
45 .long("--config")
47 .long("--config")
46 .value_name("CONFIG")
48 .value_name("CONFIG")
47 .takes_value(true)
49 .takes_value(true)
48 .global(true)
50 .global(true)
49 // Ok: `--config section.key1=val --config section.key2=val2`
51 // Ok: `--config section.key1=val --config section.key2=val2`
50 .multiple(true)
52 .multiple(true)
51 // Not ok: `--config section.key1=val section.key2=val2`
53 // Not ok: `--config section.key1=val section.key2=val2`
52 .number_of_values(1),
54 .number_of_values(1),
53 )
55 )
54 .version("0.0.1");
56 .version("0.0.1");
55 let app = add_subcommand_args(app);
57 let app = add_subcommand_args(app);
56
58
57 let matches = app.clone().get_matches_safe()?;
59 let matches = app.clone().get_matches_safe()?;
58
60
59 let (subcommand_name, subcommand_matches) = matches.subcommand();
61 let (subcommand_name, subcommand_matches) = matches.subcommand();
60 let run = subcommand_run_fn(subcommand_name)
62 let run = subcommand_run_fn(subcommand_name)
61 .expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired");
63 .expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired");
62 let subcommand_args = subcommand_matches
64 let subcommand_args = subcommand_matches
63 .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired");
65 .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired");
64
66
65 let invocation = CliInvocation {
67 let invocation = CliInvocation {
66 ui,
68 ui,
67 subcommand_args,
69 subcommand_args,
68 config,
70 config,
69 repo,
71 repo,
70 };
72 };
71 let blackbox = blackbox::Blackbox::new(&invocation, process_start_time)?;
73 let blackbox = blackbox::Blackbox::new(&invocation, process_start_time)?;
72 blackbox.log_command_start();
74 blackbox.log_command_start();
73 let result = run(&invocation);
75 let result = run(&invocation);
74 blackbox.log_command_end(exit_code(&result));
76 blackbox.log_command_end(exit_code(&result));
75 result
77 result
76 }
78 }
77
79
78 fn main() {
80 fn main() {
79 // Run this first, before we find out if the blackbox extension is even
81 // Run this first, before we find out if the blackbox extension is even
80 // enabled, in order to include everything in-between in the duration
82 // enabled, in order to include everything in-between in the duration
81 // measurements. Reading config files can be slow if they’re on NFS.
83 // measurements. Reading config files can be slow if they’re on NFS.
82 let process_start_time = blackbox::ProcessStartTime::now();
84 let process_start_time = blackbox::ProcessStartTime::now();
83
85
84 env_logger::init();
86 env_logger::init();
85 let ui = ui::Ui::new();
87 let ui = ui::Ui::new();
86
88
87 let early_args = EarlyArgs::parse(std::env::args_os());
89 let early_args = EarlyArgs::parse(std::env::args_os());
88 let non_repo_config =
90 let non_repo_config =
89 Config::load(early_args.config).unwrap_or_else(|error| {
91 Config::load(early_args.config).unwrap_or_else(|error| {
90 // Normally this is decided based on config, but we don’t have that
92 // Normally this is decided based on config, but we don’t have that
91 // available. As of this writing config loading never returns an
93 // available. As of this writing config loading never returns an
92 // "unsupported" error but that is not enforced by the type system.
94 // "unsupported" error but that is not enforced by the type system.
93 let on_unsupported = OnUnsupported::Abort;
95 let on_unsupported = OnUnsupported::Abort;
94
96
95 exit(&ui, on_unsupported, Err(error.into()))
97 exit(&ui, on_unsupported, Err(error.into()))
96 });
98 });
97
99
98 if let Some(repo_path_bytes) = &early_args.repo {
100 if let Some(repo_path_bytes) = &early_args.repo {
99 lazy_static::lazy_static! {
101 lazy_static::lazy_static! {
100 static ref SCHEME_RE: regex::bytes::Regex =
102 static ref SCHEME_RE: regex::bytes::Regex =
101 // Same as `_matchscheme` in `mercurial/util.py`
103 // Same as `_matchscheme` in `mercurial/util.py`
102 regex::bytes::Regex::new("^[a-zA-Z0-9+.\\-]+:").unwrap();
104 regex::bytes::Regex::new("^[a-zA-Z0-9+.\\-]+:").unwrap();
103 }
105 }
104 if SCHEME_RE.is_match(&repo_path_bytes) {
106 if SCHEME_RE.is_match(&repo_path_bytes) {
105 exit(
107 exit(
106 &ui,
108 &ui,
107 OnUnsupported::from_config(&non_repo_config),
109 OnUnsupported::from_config(&non_repo_config),
108 Err(CommandError::UnsupportedFeature {
110 Err(CommandError::UnsupportedFeature {
109 message: format_bytes!(
111 message: format_bytes!(
110 b"URL-like --repository {}",
112 b"URL-like --repository {}",
111 repo_path_bytes
113 repo_path_bytes
112 ),
114 ),
113 }),
115 }),
114 )
116 )
115 }
117 }
116 }
118 }
117 let repo_path = early_args.repo.as_deref().map(get_path_from_bytes);
119 let repo_path = early_args.repo.as_deref().map(get_path_from_bytes);
118 let repo_result = match Repo::find(&non_repo_config, repo_path) {
120 let repo_result = match Repo::find(&non_repo_config, repo_path) {
119 Ok(repo) => Ok(repo),
121 Ok(repo) => Ok(repo),
120 Err(RepoError::NotFound { at }) if repo_path.is_none() => {
122 Err(RepoError::NotFound { at }) if repo_path.is_none() => {
121 // Not finding a repo is not fatal yet, if `-R` was not given
123 // Not finding a repo is not fatal yet, if `-R` was not given
122 Err(NoRepoInCwdError { cwd: at })
124 Err(NoRepoInCwdError { cwd: at })
123 }
125 }
124 Err(error) => exit(
126 Err(error) => exit(
125 &ui,
127 &ui,
126 OnUnsupported::from_config(&non_repo_config),
128 OnUnsupported::from_config(&non_repo_config),
127 Err(error.into()),
129 Err(error.into()),
128 ),
130 ),
129 };
131 };
130
132
131 let config = if let Ok(repo) = &repo_result {
133 let config = if let Ok(repo) = &repo_result {
132 repo.config()
134 repo.config()
133 } else {
135 } else {
134 &non_repo_config
136 &non_repo_config
135 };
137 };
136
138
137 let result = main_with_result(
139 let result = main_with_result(
138 &process_start_time,
140 &process_start_time,
139 &ui,
141 &ui,
140 repo_result.as_ref(),
142 repo_result.as_ref(),
141 config,
143 config,
142 );
144 );
143 exit(&ui, OnUnsupported::from_config(config), result)
145 exit(&ui, OnUnsupported::from_config(config), result)
144 }
146 }
145
147
146 fn exit_code(result: &Result<(), CommandError>) -> i32 {
148 fn exit_code(result: &Result<(), CommandError>) -> i32 {
147 match result {
149 match result {
148 Ok(()) => exitcode::OK,
150 Ok(()) => exitcode::OK,
149 Err(CommandError::Abort { .. }) => exitcode::ABORT,
151 Err(CommandError::Abort { .. }) => exitcode::ABORT,
150
152
151 // Exit with a specific code and no error message to let a potential
153 // Exit with a specific code and no error message to let a potential
152 // wrapper script fallback to Python-based Mercurial.
154 // wrapper script fallback to Python-based Mercurial.
153 Err(CommandError::UnsupportedFeature { .. }) => {
155 Err(CommandError::UnsupportedFeature { .. }) => {
154 exitcode::UNIMPLEMENTED
156 exitcode::UNIMPLEMENTED
155 }
157 }
156 }
158 }
157 }
159 }
158
160
159 fn exit(
161 fn exit(
160 ui: &Ui,
162 ui: &Ui,
161 mut on_unsupported: OnUnsupported,
163 mut on_unsupported: OnUnsupported,
162 result: Result<(), CommandError>,
164 result: Result<(), CommandError>,
163 ) -> ! {
165 ) -> ! {
164 if let (
166 if let (
165 OnUnsupported::Fallback { executable },
167 OnUnsupported::Fallback { executable },
166 Err(CommandError::UnsupportedFeature { .. }),
168 Err(CommandError::UnsupportedFeature { .. }),
167 ) = (&on_unsupported, &result)
169 ) = (&on_unsupported, &result)
168 {
170 {
169 let mut args = std::env::args_os();
171 let mut args = std::env::args_os();
170 let executable_path = get_path_from_bytes(&executable);
172 let executable_path = get_path_from_bytes(&executable);
171 let this_executable = args.next().expect("exepcted argv[0] to exist");
173 let this_executable = args.next().expect("exepcted argv[0] to exist");
172 if executable_path == &PathBuf::from(this_executable) {
174 if executable_path == &PathBuf::from(this_executable) {
173 // Avoid spawning infinitely many processes until resource
175 // Avoid spawning infinitely many processes until resource
174 // exhaustion.
176 // exhaustion.
175 let _ = ui.write_stderr(&format_bytes!(
177 let _ = ui.write_stderr(&format_bytes!(
176 b"Blocking recursive fallback. The 'rhg.fallback-executable = {}' config \
178 b"Blocking recursive fallback. The 'rhg.fallback-executable = {}' config \
177 points to `rhg` itself.\n",
179 points to `rhg` itself.\n",
178 executable
180 executable
179 ));
181 ));
180 on_unsupported = OnUnsupported::Abort
182 on_unsupported = OnUnsupported::Abort
181 } else {
183 } else {
182 // `args` is now `argv[1..]` since we’ve already consumed `argv[0]`
184 // `args` is now `argv[1..]` since we’ve already consumed `argv[0]`
183 let result = Command::new(executable_path).args(args).status();
185 let result = Command::new(executable_path).args(args).status();
184 match result {
186 match result {
185 Ok(status) => std::process::exit(
187 Ok(status) => std::process::exit(
186 status.code().unwrap_or(exitcode::ABORT),
188 status.code().unwrap_or(exitcode::ABORT),
187 ),
189 ),
188 Err(error) => {
190 Err(error) => {
189 let _ = ui.write_stderr(&format_bytes!(
191 let _ = ui.write_stderr(&format_bytes!(
190 b"tried to fall back to a '{}' sub-process but got error {}\n",
192 b"tried to fall back to a '{}' sub-process but got error {}\n",
191 executable, format_bytes::Utf8(error)
193 executable, format_bytes::Utf8(error)
192 ));
194 ));
193 on_unsupported = OnUnsupported::Abort
195 on_unsupported = OnUnsupported::Abort
194 }
196 }
195 }
197 }
196 }
198 }
197 }
199 }
198 match &result {
200 match &result {
199 Ok(_) => {}
201 Ok(_) => {}
200 Err(CommandError::Abort { message }) => {
202 Err(CommandError::Abort { message }) => {
201 if !message.is_empty() {
203 if !message.is_empty() {
202 // Ignore errors when writing to stderr, we’re already exiting
204 // Ignore errors when writing to stderr, we’re already exiting
203 // with failure code so there’s not much more we can do.
205 // with failure code so there’s not much more we can do.
204 let _ = ui.write_stderr(&format_bytes!(b"{}\n", message));
206 let _ = ui.write_stderr(&format_bytes!(b"{}\n", message));
205 }
207 }
206 }
208 }
207 Err(CommandError::UnsupportedFeature { message }) => {
209 Err(CommandError::UnsupportedFeature { message }) => {
208 match on_unsupported {
210 match on_unsupported {
209 OnUnsupported::Abort => {
211 OnUnsupported::Abort => {
210 let _ = ui.write_stderr(&format_bytes!(
212 let _ = ui.write_stderr(&format_bytes!(
211 b"unsupported feature: {}\n",
213 b"unsupported feature: {}\n",
212 message
214 message
213 ));
215 ));
214 }
216 }
215 OnUnsupported::AbortSilent => {}
217 OnUnsupported::AbortSilent => {}
216 OnUnsupported::Fallback { .. } => unreachable!(),
218 OnUnsupported::Fallback { .. } => unreachable!(),
217 }
219 }
218 }
220 }
219 }
221 }
220 std::process::exit(exit_code(&result))
222 std::process::exit(exit_code(&result))
221 }
223 }
222
224
223 macro_rules! subcommands {
225 macro_rules! subcommands {
224 ($( $command: ident )+) => {
226 ($( $command: ident )+) => {
225 mod commands {
227 mod commands {
226 $(
228 $(
227 pub mod $command;
229 pub mod $command;
228 )+
230 )+
229 }
231 }
230
232
231 fn add_subcommand_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
233 fn add_subcommand_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
232 app
234 app
233 $(
235 $(
234 .subcommand(commands::$command::args())
236 .subcommand(commands::$command::args())
235 )+
237 )+
236 }
238 }
237
239
238 pub type RunFn = fn(&CliInvocation) -> Result<(), CommandError>;
240 pub type RunFn = fn(&CliInvocation) -> Result<(), CommandError>;
239
241
240 fn subcommand_run_fn(name: &str) -> Option<RunFn> {
242 fn subcommand_run_fn(name: &str) -> Option<RunFn> {
241 match name {
243 match name {
242 $(
244 $(
243 stringify!($command) => Some(commands::$command::run),
245 stringify!($command) => Some(commands::$command::run),
244 )+
246 )+
245 _ => None,
247 _ => None,
246 }
248 }
247 }
249 }
248 };
250 };
249 }
251 }
250
252
251 subcommands! {
253 subcommands! {
252 cat
254 cat
253 debugdata
255 debugdata
254 debugrequirements
256 debugrequirements
255 files
257 files
256 root
258 root
257 config
259 config
258 }
260 }
259 pub struct CliInvocation<'a> {
261 pub struct CliInvocation<'a> {
260 ui: &'a Ui,
262 ui: &'a Ui,
261 subcommand_args: &'a ArgMatches<'a>,
263 subcommand_args: &'a ArgMatches<'a>,
262 config: &'a Config,
264 config: &'a Config,
263 /// References inside `Result` is a bit peculiar but allow
265 /// References inside `Result` is a bit peculiar but allow
264 /// `invocation.repo?` to work out with `&CliInvocation` since this
266 /// `invocation.repo?` to work out with `&CliInvocation` since this
265 /// `Result` type is `Copy`.
267 /// `Result` type is `Copy`.
266 repo: Result<&'a Repo, &'a NoRepoInCwdError>,
268 repo: Result<&'a Repo, &'a NoRepoInCwdError>,
267 }
269 }
268
270
269 struct NoRepoInCwdError {
271 struct NoRepoInCwdError {
270 cwd: PathBuf,
272 cwd: PathBuf,
271 }
273 }
272
274
273 /// CLI arguments to be parsed "early" in order to be able to read
275 /// CLI arguments to be parsed "early" in order to be able to read
274 /// configuration before using Clap. Ideally we would also use Clap for this,
276 /// configuration before using Clap. Ideally we would also use Clap for this,
275 /// see <https://github.com/clap-rs/clap/discussions/2366>.
277 /// see <https://github.com/clap-rs/clap/discussions/2366>.
276 ///
278 ///
277 /// These arguments are still declared when we do use Clap later, so that Clap
279 /// These arguments are still declared when we do use Clap later, so that Clap
278 /// does not return an error for their presence.
280 /// does not return an error for their presence.
279 struct EarlyArgs {
281 struct EarlyArgs {
280 /// Values of all `--config` arguments. (Possibly none)
282 /// Values of all `--config` arguments. (Possibly none)
281 config: Vec<Vec<u8>>,
283 config: Vec<Vec<u8>>,
282 /// Value of the `-R` or `--repository` argument, if any.
284 /// Value of the `-R` or `--repository` argument, if any.
283 repo: Option<Vec<u8>>,
285 repo: Option<Vec<u8>>,
284 }
286 }
285
287
286 impl EarlyArgs {
288 impl EarlyArgs {
287 fn parse(args: impl IntoIterator<Item = OsString>) -> Self {
289 fn parse(args: impl IntoIterator<Item = OsString>) -> Self {
288 let mut args = args.into_iter().map(get_bytes_from_os_str);
290 let mut args = args.into_iter().map(get_bytes_from_os_str);
289 let mut config = Vec::new();
291 let mut config = Vec::new();
290 let mut repo = None;
292 let mut repo = None;
291 // Use `while let` instead of `for` so that we can also call
293 // Use `while let` instead of `for` so that we can also call
292 // `args.next()` inside the loop.
294 // `args.next()` inside the loop.
293 while let Some(arg) = args.next() {
295 while let Some(arg) = args.next() {
294 if arg == b"--config" {
296 if arg == b"--config" {
295 if let Some(value) = args.next() {
297 if let Some(value) = args.next() {
296 config.push(value)
298 config.push(value)
297 }
299 }
298 } else if let Some(value) = arg.drop_prefix(b"--config=") {
300 } else if let Some(value) = arg.drop_prefix(b"--config=") {
299 config.push(value.to_owned())
301 config.push(value.to_owned())
300 }
302 }
301
303
302 if arg == b"--repository" || arg == b"-R" {
304 if arg == b"--repository" || arg == b"-R" {
303 if let Some(value) = args.next() {
305 if let Some(value) = args.next() {
304 repo = Some(value)
306 repo = Some(value)
305 }
307 }
306 } else if let Some(value) = arg.drop_prefix(b"--repository=") {
308 } else if let Some(value) = arg.drop_prefix(b"--repository=") {
307 repo = Some(value.to_owned())
309 repo = Some(value.to_owned())
308 } else if let Some(value) = arg.drop_prefix(b"-R") {
310 } else if let Some(value) = arg.drop_prefix(b"-R") {
309 repo = Some(value.to_owned())
311 repo = Some(value.to_owned())
310 }
312 }
311 }
313 }
312 Self { config, repo }
314 Self { config, repo }
313 }
315 }
314 }
316 }
315
317
316 /// What to do when encountering some unsupported feature.
318 /// What to do when encountering some unsupported feature.
317 ///
319 ///
318 /// See `HgError::UnsupportedFeature` and `CommandError::UnsupportedFeature`.
320 /// See `HgError::UnsupportedFeature` and `CommandError::UnsupportedFeature`.
319 enum OnUnsupported {
321 enum OnUnsupported {
320 /// Print an error message describing what feature is not supported,
322 /// Print an error message describing what feature is not supported,
321 /// and exit with code 252.
323 /// and exit with code 252.
322 Abort,
324 Abort,
323 /// Silently exit with code 252.
325 /// Silently exit with code 252.
324 AbortSilent,
326 AbortSilent,
325 /// Try running a Python implementation
327 /// Try running a Python implementation
326 Fallback { executable: Vec<u8> },
328 Fallback { executable: Vec<u8> },
327 }
329 }
328
330
329 impl OnUnsupported {
331 impl OnUnsupported {
330 const DEFAULT: Self = OnUnsupported::Abort;
332 const DEFAULT: Self = OnUnsupported::Abort;
331 const DEFAULT_FALLBACK_EXECUTABLE: &'static [u8] = b"hg";
333 const DEFAULT_FALLBACK_EXECUTABLE: &'static [u8] = b"hg";
332
334
333 fn from_config(config: &Config) -> Self {
335 fn from_config(config: &Config) -> Self {
334 match config
336 match config
335 .get(b"rhg", b"on-unsupported")
337 .get(b"rhg", b"on-unsupported")
336 .map(|value| value.to_ascii_lowercase())
338 .map(|value| value.to_ascii_lowercase())
337 .as_deref()
339 .as_deref()
338 {
340 {
339 Some(b"abort") => OnUnsupported::Abort,
341 Some(b"abort") => OnUnsupported::Abort,
340 Some(b"abort-silent") => OnUnsupported::AbortSilent,
342 Some(b"abort-silent") => OnUnsupported::AbortSilent,
341 Some(b"fallback") => OnUnsupported::Fallback {
343 Some(b"fallback") => OnUnsupported::Fallback {
342 executable: config
344 executable: config
343 .get(b"rhg", b"fallback-executable")
345 .get(b"rhg", b"fallback-executable")
344 .unwrap_or(Self::DEFAULT_FALLBACK_EXECUTABLE)
346 .unwrap_or(Self::DEFAULT_FALLBACK_EXECUTABLE)
345 .to_owned(),
347 .to_owned(),
346 },
348 },
347 None => Self::DEFAULT,
349 None => Self::DEFAULT,
348 Some(_) => {
350 Some(_) => {
349 // TODO: warn about unknown config value
351 // TODO: warn about unknown config value
350 Self::DEFAULT
352 Self::DEFAULT
351 }
353 }
352 }
354 }
353 }
355 }
354 }
356 }
357
358 const SUPPORTED_EXTENSIONS: &[&[u8]] = &[b"blackbox", b"share"];
359
360 fn check_extensions(config: &Config) -> Result<(), CommandError> {
361 let enabled = config.get_section_keys(b"extensions");
362
363 let mut unsupported = enabled;
364 for supported in SUPPORTED_EXTENSIONS {
365 unsupported.remove(supported);
366 }
367
368 if unsupported.is_empty() {
369 Ok(())
370 } else {
371 Err(CommandError::UnsupportedFeature {
372 message: format_bytes!(
373 b"extensions: {}",
374 join(unsupported, b", ")
375 ),
376 })
377 }
378 }
General Comments 0
You need to be logged in to leave comments. Login now