##// END OF EJS Templates
rust-re2: add wrapper for calling Re2 from Rust...
Raphaël Gomès -
r44786:d8d4fa9a default
parent child Browse files
Show More
@@ -0,0 +1,25 b''
1 // build.rs
2 //
3 // Copyright 2020 Raphaël Gomès <rgomes@octobus.net>
4 //
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
7
8 #[cfg(feature = "with-re2")]
9 use cc;
10
11 #[cfg(feature = "with-re2")]
12 fn compile_re2() {
13 cc::Build::new()
14 .cpp(true)
15 .flag("-std=c++11")
16 .file("src/re2/rust_re2.cpp")
17 .compile("librustre.a");
18
19 println!("cargo:rustc-link-lib=re2");
20 }
21
22 fn main() {
23 #[cfg(feature = "with-re2")]
24 compile_re2();
25 }
@@ -0,0 +1,21 b''
1 /// re2 module
2 ///
3 /// The Python implementation of Mercurial uses the Re2 regex engine when
4 /// possible and if the bindings are installed, falling back to Python's `re`
5 /// in case of unsupported syntax (Re2 is a non-backtracking engine).
6 ///
7 /// Using it from Rust is not ideal. We need C++ bindings, a C++ compiler,
8 /// Re2 needs to be installed... why not just use the `regex` crate?
9 ///
10 /// Using Re2 from the Rust implementation guarantees backwards compatibility.
11 /// We know it will work out of the box without needing to figure out the
12 /// subtle differences in syntax. For example, `regex` currently does not
13 /// support empty alternations (regex like `a||b`) which happens more often
14 /// than we might think. Old benchmarks also showed worse performance from
15 /// regex than with Re2, but the methodology and results were lost, so take
16 /// this with a grain of salt.
17 ///
18 /// The idea is to use Re2 for now as a temporary phase and then investigate
19 /// how much work would be needed to use `regex`.
20 mod re2;
21 pub use re2::Re2;
@@ -0,0 +1,66 b''
1 /*
2 re2.rs
3
4 Rust FFI bindings to Re2.
5
6 Copyright 2020 Valentin Gatien-Baron
7
8 This software may be used and distributed according to the terms of the
9 GNU General Public License version 2 or any later version.
10 */
11 use libc::{c_int, c_void};
12
13 type Re2Ptr = *const c_void;
14
15 pub struct Re2(Re2Ptr);
16
17 /// `re2.h` says:
18 /// "An "RE2" object is safe for concurrent use by multiple threads."
19 unsafe impl Sync for Re2 {}
20
21 /// These bind to the C ABI in `rust_re2.cpp`.
22 extern "C" {
23 fn rust_re2_create(data: *const u8, len: usize) -> Re2Ptr;
24 fn rust_re2_destroy(re2: Re2Ptr);
25 fn rust_re2_ok(re2: Re2Ptr) -> bool;
26 fn rust_re2_error(
27 re2: Re2Ptr,
28 outdata: *mut *const u8,
29 outlen: *mut usize,
30 ) -> bool;
31 fn rust_re2_match(
32 re2: Re2Ptr,
33 data: *const u8,
34 len: usize,
35 anchor: c_int,
36 ) -> bool;
37 }
38
39 impl Re2 {
40 pub fn new(pattern: &[u8]) -> Result<Re2, String> {
41 unsafe {
42 let re2 = rust_re2_create(pattern.as_ptr(), pattern.len());
43 if rust_re2_ok(re2) {
44 Ok(Re2(re2))
45 } else {
46 let mut data: *const u8 = std::ptr::null();
47 let mut len: usize = 0;
48 rust_re2_error(re2, &mut data, &mut len);
49 Err(String::from_utf8_lossy(std::slice::from_raw_parts(
50 data, len,
51 ))
52 .to_string())
53 }
54 }
55 }
56
57 pub fn is_match(&self, data: &[u8]) -> bool {
58 unsafe { rust_re2_match(self.0, data.as_ptr(), data.len(), 1) }
59 }
60 }
61
62 impl Drop for Re2 {
63 fn drop(&mut self) {
64 unsafe { rust_re2_destroy(self.0) }
65 }
66 }
@@ -0,0 +1,49 b''
1 /*
2 rust_re2.cpp
3
4 C ABI export of Re2's C++ interface for Rust FFI.
5
6 Copyright 2020 Valentin Gatien-Baron
7
8 This software may be used and distributed according to the terms of the
9 GNU General Public License version 2 or any later version.
10 */
11
12 #include <re2/re2.h>
13 using namespace re2;
14
15 extern "C" {
16 RE2* rust_re2_create(const char* data, size_t len) {
17 RE2::Options o;
18 o.set_encoding(RE2::Options::Encoding::EncodingLatin1);
19 o.set_log_errors(false);
20 o.set_max_mem(50000000);
21
22 return new RE2(StringPiece(data, len), o);
23 }
24
25 void rust_re2_destroy(RE2* re) {
26 delete re;
27 }
28
29 bool rust_re2_ok(RE2* re) {
30 return re->ok();
31 }
32
33 void rust_re2_error(RE2* re, const char** outdata, size_t* outlen) {
34 const std::string& e = re->error();
35 *outdata = e.data();
36 *outlen = e.length();
37 }
38
39 bool rust_re2_match(RE2* re, char* data, size_t len, int ianchor) {
40 const StringPiece sp = StringPiece(data, len);
41
42 RE2::Anchor anchor =
43 ianchor == 0 ? RE2::Anchor::UNANCHORED :
44 (ianchor == 1 ? RE2::Anchor::ANCHOR_START :
45 RE2::Anchor::ANCHOR_BOTH);
46
47 return re->Match(sp, 0, len, anchor, NULL, 0);
48 }
49 }
@@ -1,664 +1,672 b''
1 1 # This file is automatically @generated by Cargo.
2 2 # It is not intended for manual editing.
3 3 [[package]]
4 4 name = "aho-corasick"
5 5 version = "0.7.8"
6 6 source = "registry+https://github.com/rust-lang/crates.io-index"
7 7 dependencies = [
8 8 "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
9 9 ]
10 10
11 11 [[package]]
12 12 name = "ansi_term"
13 13 version = "0.11.0"
14 14 source = "registry+https://github.com/rust-lang/crates.io-index"
15 15 dependencies = [
16 16 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
17 17 ]
18 18
19 19 [[package]]
20 20 name = "autocfg"
21 21 version = "0.1.7"
22 22 source = "registry+https://github.com/rust-lang/crates.io-index"
23 23
24 24 [[package]]
25 25 name = "autocfg"
26 26 version = "1.0.0"
27 27 source = "registry+https://github.com/rust-lang/crates.io-index"
28 28
29 29 [[package]]
30 30 name = "bitflags"
31 31 version = "1.2.1"
32 32 source = "registry+https://github.com/rust-lang/crates.io-index"
33 33
34 34 [[package]]
35 35 name = "byteorder"
36 36 version = "1.3.2"
37 37 source = "registry+https://github.com/rust-lang/crates.io-index"
38 38
39 39 [[package]]
40 40 name = "c2-chacha"
41 41 version = "0.2.3"
42 42 source = "registry+https://github.com/rust-lang/crates.io-index"
43 43 dependencies = [
44 44 "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
45 45 ]
46 46
47 47 [[package]]
48 name = "cc"
49 version = "1.0.50"
50 source = "registry+https://github.com/rust-lang/crates.io-index"
51
52 [[package]]
48 53 name = "cfg-if"
49 54 version = "0.1.10"
50 55 source = "registry+https://github.com/rust-lang/crates.io-index"
51 56
52 57 [[package]]
53 58 name = "cloudabi"
54 59 version = "0.0.3"
55 60 source = "registry+https://github.com/rust-lang/crates.io-index"
56 61 dependencies = [
57 62 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
58 63 ]
59 64
60 65 [[package]]
61 66 name = "cpython"
62 67 version = "0.4.1"
63 68 source = "registry+https://github.com/rust-lang/crates.io-index"
64 69 dependencies = [
65 70 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
66 71 "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
67 72 "python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
68 73 "python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
69 74 ]
70 75
71 76 [[package]]
72 77 name = "crossbeam-deque"
73 78 version = "0.7.2"
74 79 source = "registry+https://github.com/rust-lang/crates.io-index"
75 80 dependencies = [
76 81 "crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
77 82 "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
78 83 ]
79 84
80 85 [[package]]
81 86 name = "crossbeam-epoch"
82 87 version = "0.8.0"
83 88 source = "registry+https://github.com/rust-lang/crates.io-index"
84 89 dependencies = [
85 90 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
86 91 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
87 92 "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
88 93 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
89 94 "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
90 95 "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
91 96 ]
92 97
93 98 [[package]]
94 99 name = "crossbeam-queue"
95 100 version = "0.2.1"
96 101 source = "registry+https://github.com/rust-lang/crates.io-index"
97 102 dependencies = [
98 103 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
99 104 "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
100 105 ]
101 106
102 107 [[package]]
103 108 name = "crossbeam-utils"
104 109 version = "0.7.0"
105 110 source = "registry+https://github.com/rust-lang/crates.io-index"
106 111 dependencies = [
107 112 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
108 113 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
109 114 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
110 115 ]
111 116
112 117 [[package]]
113 118 name = "ctor"
114 119 version = "0.1.12"
115 120 source = "registry+https://github.com/rust-lang/crates.io-index"
116 121 dependencies = [
117 122 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
118 123 "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
119 124 ]
120 125
121 126 [[package]]
122 127 name = "difference"
123 128 version = "2.0.0"
124 129 source = "registry+https://github.com/rust-lang/crates.io-index"
125 130
126 131 [[package]]
127 132 name = "either"
128 133 version = "1.5.3"
129 134 source = "registry+https://github.com/rust-lang/crates.io-index"
130 135
131 136 [[package]]
132 137 name = "fuchsia-cprng"
133 138 version = "0.1.1"
134 139 source = "registry+https://github.com/rust-lang/crates.io-index"
135 140
136 141 [[package]]
137 142 name = "getrandom"
138 143 version = "0.1.14"
139 144 source = "registry+https://github.com/rust-lang/crates.io-index"
140 145 dependencies = [
141 146 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
142 147 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
143 148 "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
144 149 ]
145 150
146 151 [[package]]
147 152 name = "hermit-abi"
148 153 version = "0.1.6"
149 154 source = "registry+https://github.com/rust-lang/crates.io-index"
150 155 dependencies = [
151 156 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
152 157 ]
153 158
154 159 [[package]]
155 160 name = "hex"
156 161 version = "0.4.0"
157 162 source = "registry+https://github.com/rust-lang/crates.io-index"
158 163
159 164 [[package]]
160 165 name = "hg-core"
161 166 version = "0.1.0"
162 167 dependencies = [
163 168 "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
169 "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
164 170 "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
165 171 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
172 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
166 173 "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
167 174 "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
168 175 "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
169 176 "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
170 177 "rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
171 178 "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
172 179 "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
173 180 "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
174 181 "twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
175 182 ]
176 183
177 184 [[package]]
178 185 name = "hg-cpython"
179 186 version = "0.1.0"
180 187 dependencies = [
181 188 "cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
182 189 "hg-core 0.1.0",
183 190 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
184 191 ]
185 192
186 193 [[package]]
187 194 name = "hgdirectffi"
188 195 version = "0.1.0"
189 196 dependencies = [
190 197 "hg-core 0.1.0",
191 198 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
192 199 ]
193 200
194 201 [[package]]
195 202 name = "lazy_static"
196 203 version = "1.4.0"
197 204 source = "registry+https://github.com/rust-lang/crates.io-index"
198 205
199 206 [[package]]
200 207 name = "libc"
201 208 version = "0.2.66"
202 209 source = "registry+https://github.com/rust-lang/crates.io-index"
203 210
204 211 [[package]]
205 212 name = "memchr"
206 213 version = "2.3.0"
207 214 source = "registry+https://github.com/rust-lang/crates.io-index"
208 215
209 216 [[package]]
210 217 name = "memoffset"
211 218 version = "0.5.3"
212 219 source = "registry+https://github.com/rust-lang/crates.io-index"
213 220 dependencies = [
214 221 "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
215 222 ]
216 223
217 224 [[package]]
218 225 name = "num-traits"
219 226 version = "0.2.11"
220 227 source = "registry+https://github.com/rust-lang/crates.io-index"
221 228 dependencies = [
222 229 "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
223 230 ]
224 231
225 232 [[package]]
226 233 name = "num_cpus"
227 234 version = "1.12.0"
228 235 source = "registry+https://github.com/rust-lang/crates.io-index"
229 236 dependencies = [
230 237 "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
231 238 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
232 239 ]
233 240
234 241 [[package]]
235 242 name = "output_vt100"
236 243 version = "0.1.2"
237 244 source = "registry+https://github.com/rust-lang/crates.io-index"
238 245 dependencies = [
239 246 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
240 247 ]
241 248
242 249 [[package]]
243 250 name = "ppv-lite86"
244 251 version = "0.2.6"
245 252 source = "registry+https://github.com/rust-lang/crates.io-index"
246 253
247 254 [[package]]
248 255 name = "pretty_assertions"
249 256 version = "0.6.1"
250 257 source = "registry+https://github.com/rust-lang/crates.io-index"
251 258 dependencies = [
252 259 "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
253 260 "ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
254 261 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
255 262 "output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
256 263 ]
257 264
258 265 [[package]]
259 266 name = "proc-macro2"
260 267 version = "1.0.8"
261 268 source = "registry+https://github.com/rust-lang/crates.io-index"
262 269 dependencies = [
263 270 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
264 271 ]
265 272
266 273 [[package]]
267 274 name = "python27-sys"
268 275 version = "0.4.1"
269 276 source = "registry+https://github.com/rust-lang/crates.io-index"
270 277 dependencies = [
271 278 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
272 279 "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
273 280 ]
274 281
275 282 [[package]]
276 283 name = "python3-sys"
277 284 version = "0.4.1"
278 285 source = "registry+https://github.com/rust-lang/crates.io-index"
279 286 dependencies = [
280 287 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
281 288 "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
282 289 ]
283 290
284 291 [[package]]
285 292 name = "quote"
286 293 version = "1.0.2"
287 294 source = "registry+https://github.com/rust-lang/crates.io-index"
288 295 dependencies = [
289 296 "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
290 297 ]
291 298
292 299 [[package]]
293 300 name = "rand"
294 301 version = "0.6.5"
295 302 source = "registry+https://github.com/rust-lang/crates.io-index"
296 303 dependencies = [
297 304 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
298 305 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
299 306 "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
300 307 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
301 308 "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
302 309 "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
303 310 "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
304 311 "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
305 312 "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
306 313 "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
307 314 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
308 315 ]
309 316
310 317 [[package]]
311 318 name = "rand"
312 319 version = "0.7.3"
313 320 source = "registry+https://github.com/rust-lang/crates.io-index"
314 321 dependencies = [
315 322 "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
316 323 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
317 324 "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
318 325 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
319 326 "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
320 327 ]
321 328
322 329 [[package]]
323 330 name = "rand_chacha"
324 331 version = "0.1.1"
325 332 source = "registry+https://github.com/rust-lang/crates.io-index"
326 333 dependencies = [
327 334 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
328 335 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
329 336 ]
330 337
331 338 [[package]]
332 339 name = "rand_chacha"
333 340 version = "0.2.1"
334 341 source = "registry+https://github.com/rust-lang/crates.io-index"
335 342 dependencies = [
336 343 "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
337 344 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
338 345 ]
339 346
340 347 [[package]]
341 348 name = "rand_core"
342 349 version = "0.3.1"
343 350 source = "registry+https://github.com/rust-lang/crates.io-index"
344 351 dependencies = [
345 352 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
346 353 ]
347 354
348 355 [[package]]
349 356 name = "rand_core"
350 357 version = "0.4.2"
351 358 source = "registry+https://github.com/rust-lang/crates.io-index"
352 359
353 360 [[package]]
354 361 name = "rand_core"
355 362 version = "0.5.1"
356 363 source = "registry+https://github.com/rust-lang/crates.io-index"
357 364 dependencies = [
358 365 "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
359 366 ]
360 367
361 368 [[package]]
362 369 name = "rand_hc"
363 370 version = "0.1.0"
364 371 source = "registry+https://github.com/rust-lang/crates.io-index"
365 372 dependencies = [
366 373 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
367 374 ]
368 375
369 376 [[package]]
370 377 name = "rand_hc"
371 378 version = "0.2.0"
372 379 source = "registry+https://github.com/rust-lang/crates.io-index"
373 380 dependencies = [
374 381 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
375 382 ]
376 383
377 384 [[package]]
378 385 name = "rand_isaac"
379 386 version = "0.1.1"
380 387 source = "registry+https://github.com/rust-lang/crates.io-index"
381 388 dependencies = [
382 389 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
383 390 ]
384 391
385 392 [[package]]
386 393 name = "rand_jitter"
387 394 version = "0.1.4"
388 395 source = "registry+https://github.com/rust-lang/crates.io-index"
389 396 dependencies = [
390 397 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
391 398 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
392 399 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
393 400 ]
394 401
395 402 [[package]]
396 403 name = "rand_os"
397 404 version = "0.1.3"
398 405 source = "registry+https://github.com/rust-lang/crates.io-index"
399 406 dependencies = [
400 407 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
401 408 "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
402 409 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
403 410 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
404 411 "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
405 412 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
406 413 ]
407 414
408 415 [[package]]
409 416 name = "rand_pcg"
410 417 version = "0.1.2"
411 418 source = "registry+https://github.com/rust-lang/crates.io-index"
412 419 dependencies = [
413 420 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
414 421 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
415 422 ]
416 423
417 424 [[package]]
418 425 name = "rand_xorshift"
419 426 version = "0.1.1"
420 427 source = "registry+https://github.com/rust-lang/crates.io-index"
421 428 dependencies = [
422 429 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
423 430 ]
424 431
425 432 [[package]]
426 433 name = "rayon"
427 434 version = "1.3.0"
428 435 source = "registry+https://github.com/rust-lang/crates.io-index"
429 436 dependencies = [
430 437 "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
431 438 "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
432 439 "rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
433 440 ]
434 441
435 442 [[package]]
436 443 name = "rayon-core"
437 444 version = "1.7.0"
438 445 source = "registry+https://github.com/rust-lang/crates.io-index"
439 446 dependencies = [
440 447 "crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
441 448 "crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
442 449 "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
443 450 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
444 451 "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
445 452 ]
446 453
447 454 [[package]]
448 455 name = "rdrand"
449 456 version = "0.4.0"
450 457 source = "registry+https://github.com/rust-lang/crates.io-index"
451 458 dependencies = [
452 459 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
453 460 ]
454 461
455 462 [[package]]
456 463 name = "redox_syscall"
457 464 version = "0.1.56"
458 465 source = "registry+https://github.com/rust-lang/crates.io-index"
459 466
460 467 [[package]]
461 468 name = "regex"
462 469 version = "1.3.4"
463 470 source = "registry+https://github.com/rust-lang/crates.io-index"
464 471 dependencies = [
465 472 "aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
466 473 "memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
467 474 "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)",
468 475 "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
469 476 ]
470 477
471 478 [[package]]
472 479 name = "regex-syntax"
473 480 version = "0.6.14"
474 481 source = "registry+https://github.com/rust-lang/crates.io-index"
475 482
476 483 [[package]]
477 484 name = "remove_dir_all"
478 485 version = "0.5.2"
479 486 source = "registry+https://github.com/rust-lang/crates.io-index"
480 487 dependencies = [
481 488 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
482 489 ]
483 490
484 491 [[package]]
485 492 name = "rustc_version"
486 493 version = "0.2.3"
487 494 source = "registry+https://github.com/rust-lang/crates.io-index"
488 495 dependencies = [
489 496 "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
490 497 ]
491 498
492 499 [[package]]
493 500 name = "same-file"
494 501 version = "1.0.6"
495 502 source = "registry+https://github.com/rust-lang/crates.io-index"
496 503 dependencies = [
497 504 "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
498 505 ]
499 506
500 507 [[package]]
501 508 name = "scopeguard"
502 509 version = "1.0.0"
503 510 source = "registry+https://github.com/rust-lang/crates.io-index"
504 511
505 512 [[package]]
506 513 name = "semver"
507 514 version = "0.9.0"
508 515 source = "registry+https://github.com/rust-lang/crates.io-index"
509 516 dependencies = [
510 517 "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
511 518 ]
512 519
513 520 [[package]]
514 521 name = "semver-parser"
515 522 version = "0.7.0"
516 523 source = "registry+https://github.com/rust-lang/crates.io-index"
517 524
518 525 [[package]]
519 526 name = "syn"
520 527 version = "1.0.14"
521 528 source = "registry+https://github.com/rust-lang/crates.io-index"
522 529 dependencies = [
523 530 "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
524 531 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
525 532 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
526 533 ]
527 534
528 535 [[package]]
529 536 name = "tempfile"
530 537 version = "3.1.0"
531 538 source = "registry+https://github.com/rust-lang/crates.io-index"
532 539 dependencies = [
533 540 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
534 541 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
535 542 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
536 543 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
537 544 "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
538 545 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
539 546 ]
540 547
541 548 [[package]]
542 549 name = "thread_local"
543 550 version = "1.0.1"
544 551 source = "registry+https://github.com/rust-lang/crates.io-index"
545 552 dependencies = [
546 553 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
547 554 ]
548 555
549 556 [[package]]
550 557 name = "twox-hash"
551 558 version = "1.5.0"
552 559 source = "registry+https://github.com/rust-lang/crates.io-index"
553 560 dependencies = [
554 561 "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
555 562 ]
556 563
557 564 [[package]]
558 565 name = "unicode-xid"
559 566 version = "0.2.0"
560 567 source = "registry+https://github.com/rust-lang/crates.io-index"
561 568
562 569 [[package]]
563 570 name = "wasi"
564 571 version = "0.9.0+wasi-snapshot-preview1"
565 572 source = "registry+https://github.com/rust-lang/crates.io-index"
566 573
567 574 [[package]]
568 575 name = "winapi"
569 576 version = "0.3.8"
570 577 source = "registry+https://github.com/rust-lang/crates.io-index"
571 578 dependencies = [
572 579 "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
573 580 "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
574 581 ]
575 582
576 583 [[package]]
577 584 name = "winapi-i686-pc-windows-gnu"
578 585 version = "0.4.0"
579 586 source = "registry+https://github.com/rust-lang/crates.io-index"
580 587
581 588 [[package]]
582 589 name = "winapi-util"
583 590 version = "0.1.3"
584 591 source = "registry+https://github.com/rust-lang/crates.io-index"
585 592 dependencies = [
586 593 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
587 594 ]
588 595
589 596 [[package]]
590 597 name = "winapi-x86_64-pc-windows-gnu"
591 598 version = "0.4.0"
592 599 source = "registry+https://github.com/rust-lang/crates.io-index"
593 600
594 601 [metadata]
595 602 "checksum aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811"
596 603 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
597 604 "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
598 605 "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
599 606 "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
600 607 "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
601 608 "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
609 "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
602 610 "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
603 611 "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
604 612 "checksum cpython 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfaf3847ab963e40c4f6dd8d6be279bdf74007ae2413786a0dcbb28c52139a95"
605 613 "checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
606 614 "checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
607 615 "checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
608 616 "checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
609 617 "checksum ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc"
610 618 "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
611 619 "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
612 620 "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
613 621 "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
614 622 "checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
615 623 "checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e"
616 624 "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
617 625 "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
618 626 "checksum memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223"
619 627 "checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
620 628 "checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096"
621 629 "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
622 630 "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
623 631 "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
624 632 "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
625 633 "checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548"
626 634 "checksum python27-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67cb041de8615111bf224dd75667af5f25c6e032118251426fed7f1b70ce4c8c"
627 635 "checksum python3-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90af11779515a1e530af60782d273b59ac79d33b0e253c071a728563957c76d4"
628 636 "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
629 637 "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
630 638 "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
631 639 "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
632 640 "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
633 641 "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
634 642 "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
635 643 "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
636 644 "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
637 645 "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
638 646 "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
639 647 "checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
640 648 "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
641 649 "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
642 650 "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
643 651 "checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
644 652 "checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
645 653 "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
646 654 "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
647 655 "checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8"
648 656 "checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06"
649 657 "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
650 658 "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
651 659 "checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
652 660 "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
653 661 "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
654 662 "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
655 663 "checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5"
656 664 "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
657 665 "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
658 666 "checksum twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56"
659 667 "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
660 668 "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
661 669 "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
662 670 "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
663 671 "checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80"
664 672 "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
@@ -1,25 +1,34 b''
1 1 [package]
2 2 name = "hg-core"
3 3 version = "0.1.0"
4 4 authors = ["Georges Racinet <gracinet@anybox.fr>"]
5 5 description = "Mercurial pure Rust core library, with no assumption on Python bindings (FFI)"
6 6 edition = "2018"
7 build = "build.rs"
7 8
8 9 [lib]
9 10 name = "hg"
10 11
11 12 [dependencies]
12 13 byteorder = "1.3.1"
13 14 hex = "0.4.0"
14 15 lazy_static = "1.3.0"
16 libc = { version = "0.2.66", optional = true }
15 17 memchr = "2.2.0"
16 18 rand = "0.6.5"
17 19 rand_pcg = "0.1.1"
18 20 rayon = "1.3.0"
19 21 regex = "1.1.0"
20 22 twox-hash = "1.5.0"
21 23 same-file = "1.0.6"
22 24
23 25 [dev-dependencies]
24 26 tempfile = "3.1.0"
25 pretty_assertions = "0.6.1" No newline at end of file
27 pretty_assertions = "0.6.1"
28
29 [build-dependencies]
30 cc = { version = "1.0.48", optional = true }
31
32 [features]
33 default = []
34 with-re2 = ["cc", "libc"]
@@ -1,175 +1,177 b''
1 1 // Copyright 2018-2020 Georges Racinet <georges.racinet@octobus.net>
2 2 // and Mercurial contributors
3 3 //
4 4 // This software may be used and distributed according to the terms of the
5 5 // GNU General Public License version 2 or any later version.
6 6 mod ancestors;
7 7 pub mod dagops;
8 8 pub use ancestors::{AncestorsIterator, LazyAncestors, MissingAncestors};
9 9 mod dirstate;
10 10 pub mod discovery;
11 11 pub mod testing; // unconditionally built, for use from integration tests
12 12 pub use dirstate::{
13 13 dirs_multiset::{DirsMultiset, DirsMultisetIter},
14 14 dirstate_map::DirstateMap,
15 15 parsers::{pack_dirstate, parse_dirstate, PARENT_SIZE},
16 16 status::{status, StatusResult},
17 17 CopyMap, CopyMapIter, DirstateEntry, DirstateParents, EntryState,
18 18 StateMap, StateMapIter,
19 19 };
20 20 mod filepatterns;
21 21 pub mod matchers;
22 22 pub mod revlog;
23 23 pub use revlog::*;
24 #[cfg(feature = "with-re2")]
25 pub mod re2;
24 26 pub mod utils;
25 27
26 28 use crate::utils::hg_path::{HgPathBuf, HgPathError};
27 29 pub use filepatterns::{
28 30 parse_pattern_syntax, read_pattern_file, IgnorePattern,
29 31 PatternFileWarning, PatternSyntax,
30 32 };
31 33 use std::collections::HashMap;
32 34 use twox_hash::RandomXxHashBuilder64;
33 35
34 36 pub type LineNumber = usize;
35 37
36 38 /// Rust's default hasher is too slow because it tries to prevent collision
37 39 /// attacks. We are not concerned about those: if an ill-minded person has
38 40 /// write access to your repository, you have other issues.
39 41 pub type FastHashMap<K, V> = HashMap<K, V, RandomXxHashBuilder64>;
40 42
41 43 #[derive(Clone, Debug, PartialEq)]
42 44 pub enum DirstateParseError {
43 45 TooLittleData,
44 46 Overflow,
45 47 CorruptedEntry(String),
46 48 Damaged,
47 49 }
48 50
49 51 impl From<std::io::Error> for DirstateParseError {
50 52 fn from(e: std::io::Error) -> Self {
51 53 DirstateParseError::CorruptedEntry(e.to_string())
52 54 }
53 55 }
54 56
55 57 impl ToString for DirstateParseError {
56 58 fn to_string(&self) -> String {
57 59 use crate::DirstateParseError::*;
58 60 match self {
59 61 TooLittleData => "Too little data for dirstate.".to_string(),
60 62 Overflow => "Overflow in dirstate.".to_string(),
61 63 CorruptedEntry(e) => format!("Corrupted entry: {:?}.", e),
62 64 Damaged => "Dirstate appears to be damaged.".to_string(),
63 65 }
64 66 }
65 67 }
66 68
67 69 #[derive(Debug, PartialEq)]
68 70 pub enum DirstatePackError {
69 71 CorruptedEntry(String),
70 72 CorruptedParent,
71 73 BadSize(usize, usize),
72 74 }
73 75
74 76 impl From<std::io::Error> for DirstatePackError {
75 77 fn from(e: std::io::Error) -> Self {
76 78 DirstatePackError::CorruptedEntry(e.to_string())
77 79 }
78 80 }
79 81 #[derive(Debug, PartialEq)]
80 82 pub enum DirstateMapError {
81 83 PathNotFound(HgPathBuf),
82 84 EmptyPath,
83 85 InvalidPath(HgPathError),
84 86 }
85 87
86 88 impl ToString for DirstateMapError {
87 89 fn to_string(&self) -> String {
88 90 match self {
89 91 DirstateMapError::PathNotFound(_) => {
90 92 "expected a value, found none".to_string()
91 93 }
92 94 DirstateMapError::EmptyPath => "Overflow in dirstate.".to_string(),
93 95 DirstateMapError::InvalidPath(e) => e.to_string(),
94 96 }
95 97 }
96 98 }
97 99
98 100 pub enum DirstateError {
99 101 Parse(DirstateParseError),
100 102 Pack(DirstatePackError),
101 103 Map(DirstateMapError),
102 104 IO(std::io::Error),
103 105 }
104 106
105 107 impl From<DirstateParseError> for DirstateError {
106 108 fn from(e: DirstateParseError) -> Self {
107 109 DirstateError::Parse(e)
108 110 }
109 111 }
110 112
111 113 impl From<DirstatePackError> for DirstateError {
112 114 fn from(e: DirstatePackError) -> Self {
113 115 DirstateError::Pack(e)
114 116 }
115 117 }
116 118
117 119 #[derive(Debug)]
118 120 pub enum PatternError {
119 121 Path(HgPathError),
120 122 UnsupportedSyntax(String),
121 123 UnsupportedSyntaxInFile(String, String, usize),
122 124 TooLong(usize),
123 125 IO(std::io::Error),
124 126 /// Needed a pattern that can be turned into a regex but got one that
125 127 /// can't. This should only happen through programmer error.
126 128 NonRegexPattern(IgnorePattern),
127 129 }
128 130
129 131 impl ToString for PatternError {
130 132 fn to_string(&self) -> String {
131 133 match self {
132 134 PatternError::UnsupportedSyntax(syntax) => {
133 135 format!("Unsupported syntax {}", syntax)
134 136 }
135 137 PatternError::UnsupportedSyntaxInFile(syntax, file_path, line) => {
136 138 format!(
137 139 "{}:{}: unsupported syntax {}",
138 140 file_path, line, syntax
139 141 )
140 142 }
141 143 PatternError::TooLong(size) => {
142 144 format!("matcher pattern is too long ({} bytes)", size)
143 145 }
144 146 PatternError::IO(e) => e.to_string(),
145 147 PatternError::Path(e) => e.to_string(),
146 148 PatternError::NonRegexPattern(pattern) => {
147 149 format!("'{:?}' cannot be turned into a regex", pattern)
148 150 }
149 151 }
150 152 }
151 153 }
152 154
153 155 impl From<DirstateMapError> for DirstateError {
154 156 fn from(e: DirstateMapError) -> Self {
155 157 DirstateError::Map(e)
156 158 }
157 159 }
158 160
159 161 impl From<std::io::Error> for DirstateError {
160 162 fn from(e: std::io::Error) -> Self {
161 163 DirstateError::IO(e)
162 164 }
163 165 }
164 166
165 167 impl From<std::io::Error> for PatternError {
166 168 fn from(e: std::io::Error) -> Self {
167 169 PatternError::IO(e)
168 170 }
169 171 }
170 172
171 173 impl From<HgPathError> for PatternError {
172 174 fn from(e: HgPathError) -> Self {
173 175 PatternError::Path(e)
174 176 }
175 177 }
@@ -1,29 +1,30 b''
1 1 [package]
2 2 name = "hg-cpython"
3 3 version = "0.1.0"
4 4 authors = ["Georges Racinet <gracinet@anybox.fr>"]
5 5 edition = "2018"
6 6
7 7 [lib]
8 8 name='rusthg'
9 9 crate-type = ["cdylib"]
10 10
11 11 [features]
12 12 default = ["python27"]
13 with-re2 = ["hg-core/with-re2"]
13 14
14 15 # Features to build an extension module:
15 16 python27 = ["cpython/python27-sys", "cpython/extension-module-2-7"]
16 17 python3 = ["cpython/python3-sys", "cpython/extension-module"]
17 18
18 19 # Enable one of these features to build a test executable linked to libpython:
19 20 # e.g. cargo test --no-default-features --features python27-bin
20 21 python27-bin = ["cpython/python27-sys"]
21 22 python3-bin = ["cpython/python3-sys"]
22 23
23 24 [dependencies]
24 hg-core = { path = "../hg-core" }
25 hg-core = { path = "../hg-core"}
25 26 libc = '*'
26 27
27 28 [dependencies.cpython]
28 29 version = "0.4"
29 30 default-features = false
@@ -1,1727 +1,1736 b''
1 1 #
2 2 # This is the mercurial setup script.
3 3 #
4 4 # 'python setup.py install', or
5 5 # 'python setup.py --help' for more options
6 6
7 7 import os
8 8
9 9 # Mercurial will never work on Python 3 before 3.5 due to a lack
10 10 # of % formatting on bytestrings, and can't work on 3.6.0 or 3.6.1
11 11 # due to a bug in % formatting in bytestrings.
12 12 # We cannot support Python 3.5.0, 3.5.1, 3.5.2 because of bug in
13 13 # codecs.escape_encode() where it raises SystemError on empty bytestring
14 14 # bug link: https://bugs.python.org/issue25270
15 15 supportedpy = ','.join(
16 16 [
17 17 '>=2.7',
18 18 '!=3.0.*',
19 19 '!=3.1.*',
20 20 '!=3.2.*',
21 21 '!=3.3.*',
22 22 '!=3.4.*',
23 23 '!=3.5.0',
24 24 '!=3.5.1',
25 25 '!=3.5.2',
26 26 '!=3.6.0',
27 27 '!=3.6.1',
28 28 ]
29 29 )
30 30
31 31 import sys, platform
32 32 import sysconfig
33 33
34 34 if sys.version_info[0] >= 3:
35 35 printf = eval('print')
36 36 libdir_escape = 'unicode_escape'
37 37
38 38 def sysstr(s):
39 39 return s.decode('latin-1')
40 40
41 41
42 42 else:
43 43 libdir_escape = 'string_escape'
44 44
45 45 def printf(*args, **kwargs):
46 46 f = kwargs.get('file', sys.stdout)
47 47 end = kwargs.get('end', '\n')
48 48 f.write(b' '.join(args) + end)
49 49
50 50 def sysstr(s):
51 51 return s
52 52
53 53
54 54 # Attempt to guide users to a modern pip - this means that 2.6 users
55 55 # should have a chance of getting a 4.2 release, and when we ratchet
56 56 # the version requirement forward again hopefully everyone will get
57 57 # something that works for them.
58 58 if sys.version_info < (2, 7, 0, 'final'):
59 59 pip_message = (
60 60 'This may be due to an out of date pip. '
61 61 'Make sure you have pip >= 9.0.1.'
62 62 )
63 63 try:
64 64 import pip
65 65
66 66 pip_version = tuple([int(x) for x in pip.__version__.split('.')[:3]])
67 67 if pip_version < (9, 0, 1):
68 68 pip_message = (
69 69 'Your pip version is out of date, please install '
70 70 'pip >= 9.0.1. pip {} detected.'.format(pip.__version__)
71 71 )
72 72 else:
73 73 # pip is new enough - it must be something else
74 74 pip_message = ''
75 75 except Exception:
76 76 pass
77 77 error = """
78 78 Mercurial does not support Python older than 2.7.
79 79 Python {py} detected.
80 80 {pip}
81 81 """.format(
82 82 py=sys.version_info, pip=pip_message
83 83 )
84 84 printf(error, file=sys.stderr)
85 85 sys.exit(1)
86 86
87 87 if sys.version_info[0] >= 3:
88 88 DYLIB_SUFFIX = sysconfig.get_config_vars()['EXT_SUFFIX']
89 89 else:
90 90 # deprecated in Python 3
91 91 DYLIB_SUFFIX = sysconfig.get_config_vars()['SO']
92 92
93 93 # Solaris Python packaging brain damage
94 94 try:
95 95 import hashlib
96 96
97 97 sha = hashlib.sha1()
98 98 except ImportError:
99 99 try:
100 100 import sha
101 101
102 102 sha.sha # silence unused import warning
103 103 except ImportError:
104 104 raise SystemExit(
105 105 "Couldn't import standard hashlib (incomplete Python install)."
106 106 )
107 107
108 108 try:
109 109 import zlib
110 110
111 111 zlib.compressobj # silence unused import warning
112 112 except ImportError:
113 113 raise SystemExit(
114 114 "Couldn't import standard zlib (incomplete Python install)."
115 115 )
116 116
117 117 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
118 118 isironpython = False
119 119 try:
120 120 isironpython = (
121 121 platform.python_implementation().lower().find("ironpython") != -1
122 122 )
123 123 except AttributeError:
124 124 pass
125 125
126 126 if isironpython:
127 127 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
128 128 else:
129 129 try:
130 130 import bz2
131 131
132 132 bz2.BZ2Compressor # silence unused import warning
133 133 except ImportError:
134 134 raise SystemExit(
135 135 "Couldn't import standard bz2 (incomplete Python install)."
136 136 )
137 137
138 138 ispypy = "PyPy" in sys.version
139 139
140 140 hgrustext = os.environ.get('HGWITHRUSTEXT')
141 141 # TODO record it for proper rebuild upon changes
142 142 # (see mercurial/__modulepolicy__.py)
143 143 if hgrustext != 'cpython' and hgrustext is not None:
144 144 hgrustext = 'direct-ffi'
145 145
146 146 import ctypes
147 147 import errno
148 148 import stat, subprocess, time
149 149 import re
150 150 import shutil
151 151 import tempfile
152 152 from distutils import log
153 153
154 154 # We have issues with setuptools on some platforms and builders. Until
155 155 # those are resolved, setuptools is opt-in except for platforms where
156 156 # we don't have issues.
157 157 issetuptools = os.name == 'nt' or 'FORCE_SETUPTOOLS' in os.environ
158 158 if issetuptools:
159 159 from setuptools import setup
160 160 else:
161 161 from distutils.core import setup
162 162 from distutils.ccompiler import new_compiler
163 163 from distutils.core import Command, Extension
164 164 from distutils.dist import Distribution
165 165 from distutils.command.build import build
166 166 from distutils.command.build_ext import build_ext
167 167 from distutils.command.build_py import build_py
168 168 from distutils.command.build_scripts import build_scripts
169 169 from distutils.command.install import install
170 170 from distutils.command.install_lib import install_lib
171 171 from distutils.command.install_scripts import install_scripts
172 172 from distutils.spawn import spawn, find_executable
173 173 from distutils import file_util
174 174 from distutils.errors import (
175 175 CCompilerError,
176 176 DistutilsError,
177 177 DistutilsExecError,
178 178 )
179 179 from distutils.sysconfig import get_python_inc, get_config_var
180 180 from distutils.version import StrictVersion
181 181
182 182 # Explain to distutils.StrictVersion how our release candidates are versionned
183 183 StrictVersion.version_re = re.compile(r'^(\d+)\.(\d+)(\.(\d+))?-?(rc(\d+))?$')
184 184
185 185
186 186 def write_if_changed(path, content):
187 187 """Write content to a file iff the content hasn't changed."""
188 188 if os.path.exists(path):
189 189 with open(path, 'rb') as fh:
190 190 current = fh.read()
191 191 else:
192 192 current = b''
193 193
194 194 if current != content:
195 195 with open(path, 'wb') as fh:
196 196 fh.write(content)
197 197
198 198
199 199 scripts = ['hg']
200 200 if os.name == 'nt':
201 201 # We remove hg.bat if we are able to build hg.exe.
202 202 scripts.append('contrib/win32/hg.bat')
203 203
204 204
205 205 def cancompile(cc, code):
206 206 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
207 207 devnull = oldstderr = None
208 208 try:
209 209 fname = os.path.join(tmpdir, 'testcomp.c')
210 210 f = open(fname, 'w')
211 211 f.write(code)
212 212 f.close()
213 213 # Redirect stderr to /dev/null to hide any error messages
214 214 # from the compiler.
215 215 # This will have to be changed if we ever have to check
216 216 # for a function on Windows.
217 217 devnull = open('/dev/null', 'w')
218 218 oldstderr = os.dup(sys.stderr.fileno())
219 219 os.dup2(devnull.fileno(), sys.stderr.fileno())
220 220 objects = cc.compile([fname], output_dir=tmpdir)
221 221 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
222 222 return True
223 223 except Exception:
224 224 return False
225 225 finally:
226 226 if oldstderr is not None:
227 227 os.dup2(oldstderr, sys.stderr.fileno())
228 228 if devnull is not None:
229 229 devnull.close()
230 230 shutil.rmtree(tmpdir)
231 231
232 232
233 233 # simplified version of distutils.ccompiler.CCompiler.has_function
234 234 # that actually removes its temporary files.
235 235 def hasfunction(cc, funcname):
236 236 code = 'int main(void) { %s(); }\n' % funcname
237 237 return cancompile(cc, code)
238 238
239 239
240 240 def hasheader(cc, headername):
241 241 code = '#include <%s>\nint main(void) { return 0; }\n' % headername
242 242 return cancompile(cc, code)
243 243
244 244
245 245 # py2exe needs to be installed to work
246 246 try:
247 247 import py2exe
248 248
249 249 py2exe.Distribution # silence unused import warning
250 250 py2exeloaded = True
251 251 # import py2exe's patched Distribution class
252 252 from distutils.core import Distribution
253 253 except ImportError:
254 254 py2exeloaded = False
255 255
256 256
257 257 def runcmd(cmd, env, cwd=None):
258 258 p = subprocess.Popen(
259 259 cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env, cwd=cwd
260 260 )
261 261 out, err = p.communicate()
262 262 return p.returncode, out, err
263 263
264 264
265 265 class hgcommand(object):
266 266 def __init__(self, cmd, env):
267 267 self.cmd = cmd
268 268 self.env = env
269 269
270 270 def run(self, args):
271 271 cmd = self.cmd + args
272 272 returncode, out, err = runcmd(cmd, self.env)
273 273 err = filterhgerr(err)
274 274 if err or returncode != 0:
275 275 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
276 276 printf(err, file=sys.stderr)
277 277 return ''
278 278 return out
279 279
280 280
281 281 def filterhgerr(err):
282 282 # If root is executing setup.py, but the repository is owned by
283 283 # another user (as in "sudo python setup.py install") we will get
284 284 # trust warnings since the .hg/hgrc file is untrusted. That is
285 285 # fine, we don't want to load it anyway. Python may warn about
286 286 # a missing __init__.py in mercurial/locale, we also ignore that.
287 287 err = [
288 288 e
289 289 for e in err.splitlines()
290 290 if (
291 291 not e.startswith(b'not trusting file')
292 292 and not e.startswith(b'warning: Not importing')
293 293 and not e.startswith(b'obsolete feature not enabled')
294 294 and not e.startswith(b'*** failed to import extension')
295 295 and not e.startswith(b'devel-warn:')
296 296 and not (
297 297 e.startswith(b'(third party extension')
298 298 and e.endswith(b'or newer of Mercurial; disabling)')
299 299 )
300 300 )
301 301 ]
302 302 return b'\n'.join(b' ' + e for e in err)
303 303
304 304
305 305 def findhg():
306 306 """Try to figure out how we should invoke hg for examining the local
307 307 repository contents.
308 308
309 309 Returns an hgcommand object."""
310 310 # By default, prefer the "hg" command in the user's path. This was
311 311 # presumably the hg command that the user used to create this repository.
312 312 #
313 313 # This repository may require extensions or other settings that would not
314 314 # be enabled by running the hg script directly from this local repository.
315 315 hgenv = os.environ.copy()
316 316 # Use HGPLAIN to disable hgrc settings that would change output formatting,
317 317 # and disable localization for the same reasons.
318 318 hgenv['HGPLAIN'] = '1'
319 319 hgenv['LANGUAGE'] = 'C'
320 320 hgcmd = ['hg']
321 321 # Run a simple "hg log" command just to see if using hg from the user's
322 322 # path works and can successfully interact with this repository. Windows
323 323 # gives precedence to hg.exe in the current directory, so fall back to the
324 324 # python invocation of local hg, where pythonXY.dll can always be found.
325 325 check_cmd = ['log', '-r.', '-Ttest']
326 326 if os.name != 'nt' or not os.path.exists("hg.exe"):
327 327 try:
328 328 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
329 329 except EnvironmentError:
330 330 retcode = -1
331 331 if retcode == 0 and not filterhgerr(err):
332 332 return hgcommand(hgcmd, hgenv)
333 333
334 334 # Fall back to trying the local hg installation.
335 335 hgenv = localhgenv()
336 336 hgcmd = [sys.executable, 'hg']
337 337 try:
338 338 retcode, out, err = runcmd(hgcmd + check_cmd, hgenv)
339 339 except EnvironmentError:
340 340 retcode = -1
341 341 if retcode == 0 and not filterhgerr(err):
342 342 return hgcommand(hgcmd, hgenv)
343 343
344 344 raise SystemExit(
345 345 'Unable to find a working hg binary to extract the '
346 346 'version from the repository tags'
347 347 )
348 348
349 349
350 350 def localhgenv():
351 351 """Get an environment dictionary to use for invoking or importing
352 352 mercurial from the local repository."""
353 353 # Execute hg out of this directory with a custom environment which takes
354 354 # care to not use any hgrc files and do no localization.
355 355 env = {
356 356 'HGMODULEPOLICY': 'py',
357 357 'HGRCPATH': '',
358 358 'LANGUAGE': 'C',
359 359 'PATH': '',
360 360 } # make pypi modules that use os.environ['PATH'] happy
361 361 if 'LD_LIBRARY_PATH' in os.environ:
362 362 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
363 363 if 'SystemRoot' in os.environ:
364 364 # SystemRoot is required by Windows to load various DLLs. See:
365 365 # https://bugs.python.org/issue13524#msg148850
366 366 env['SystemRoot'] = os.environ['SystemRoot']
367 367 return env
368 368
369 369
370 370 version = ''
371 371
372 372 if os.path.isdir('.hg'):
373 373 hg = findhg()
374 374 cmd = ['log', '-r', '.', '--template', '{tags}\n']
375 375 numerictags = [t for t in sysstr(hg.run(cmd)).split() if t[0:1].isdigit()]
376 376 hgid = sysstr(hg.run(['id', '-i'])).strip()
377 377 if not hgid:
378 378 # Bail out if hg is having problems interacting with this repository,
379 379 # rather than falling through and producing a bogus version number.
380 380 # Continuing with an invalid version number will break extensions
381 381 # that define minimumhgversion.
382 382 raise SystemExit('Unable to determine hg version from local repository')
383 383 if numerictags: # tag(s) found
384 384 version = numerictags[-1]
385 385 if hgid.endswith('+'): # propagate the dirty status to the tag
386 386 version += '+'
387 387 else: # no tag found
388 388 ltagcmd = ['parents', '--template', '{latesttag}']
389 389 ltag = sysstr(hg.run(ltagcmd))
390 390 changessincecmd = ['log', '-T', 'x\n', '-r', "only(.,'%s')" % ltag]
391 391 changessince = len(hg.run(changessincecmd).splitlines())
392 392 version = '%s+%s-%s' % (ltag, changessince, hgid)
393 393 if version.endswith('+'):
394 394 version += time.strftime('%Y%m%d')
395 395 elif os.path.exists('.hg_archival.txt'):
396 396 kw = dict(
397 397 [[t.strip() for t in l.split(':', 1)] for l in open('.hg_archival.txt')]
398 398 )
399 399 if 'tag' in kw:
400 400 version = kw['tag']
401 401 elif 'latesttag' in kw:
402 402 if 'changessincelatesttag' in kw:
403 403 version = '%(latesttag)s+%(changessincelatesttag)s-%(node).12s' % kw
404 404 else:
405 405 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
406 406 else:
407 407 version = kw.get('node', '')[:12]
408 408
409 409 if version:
410 410 versionb = version
411 411 if not isinstance(versionb, bytes):
412 412 versionb = versionb.encode('ascii')
413 413
414 414 write_if_changed(
415 415 'mercurial/__version__.py',
416 416 b''.join(
417 417 [
418 418 b'# this file is autogenerated by setup.py\n'
419 419 b'version = b"%s"\n' % versionb,
420 420 ]
421 421 ),
422 422 )
423 423
424 424 try:
425 425 oldpolicy = os.environ.get('HGMODULEPOLICY', None)
426 426 os.environ['HGMODULEPOLICY'] = 'py'
427 427 from mercurial import __version__
428 428
429 429 version = __version__.version
430 430 except ImportError:
431 431 version = b'unknown'
432 432 finally:
433 433 if oldpolicy is None:
434 434 del os.environ['HGMODULEPOLICY']
435 435 else:
436 436 os.environ['HGMODULEPOLICY'] = oldpolicy
437 437
438 438
439 439 class hgbuild(build):
440 440 # Insert hgbuildmo first so that files in mercurial/locale/ are found
441 441 # when build_py is run next.
442 442 sub_commands = [('build_mo', None)] + build.sub_commands
443 443
444 444
445 445 class hgbuildmo(build):
446 446
447 447 description = "build translations (.mo files)"
448 448
449 449 def run(self):
450 450 if not find_executable('msgfmt'):
451 451 self.warn(
452 452 "could not find msgfmt executable, no translations "
453 453 "will be built"
454 454 )
455 455 return
456 456
457 457 podir = 'i18n'
458 458 if not os.path.isdir(podir):
459 459 self.warn("could not find %s/ directory" % podir)
460 460 return
461 461
462 462 join = os.path.join
463 463 for po in os.listdir(podir):
464 464 if not po.endswith('.po'):
465 465 continue
466 466 pofile = join(podir, po)
467 467 modir = join('locale', po[:-3], 'LC_MESSAGES')
468 468 mofile = join(modir, 'hg.mo')
469 469 mobuildfile = join('mercurial', mofile)
470 470 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
471 471 if sys.platform != 'sunos5':
472 472 # msgfmt on Solaris does not know about -c
473 473 cmd.append('-c')
474 474 self.mkpath(join('mercurial', modir))
475 475 self.make_file([pofile], mobuildfile, spawn, (cmd,))
476 476
477 477
478 478 class hgdist(Distribution):
479 479 pure = False
480 480 rust = hgrustext is not None
481 481 cffi = ispypy
482 482
483 483 global_options = Distribution.global_options + [
484 484 ('pure', None, "use pure (slow) Python code instead of C extensions"),
485 485 ('rust', None, "use Rust extensions additionally to C extensions"),
486 486 ]
487 487
488 488 def has_ext_modules(self):
489 489 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
490 490 # too late for some cases
491 491 return not self.pure and Distribution.has_ext_modules(self)
492 492
493 493
494 494 # This is ugly as a one-liner. So use a variable.
495 495 buildextnegops = dict(getattr(build_ext, 'negative_options', {}))
496 496 buildextnegops['no-zstd'] = 'zstd'
497 497 buildextnegops['no-rust'] = 'rust'
498 498
499 499
500 500 class hgbuildext(build_ext):
501 501 user_options = build_ext.user_options + [
502 502 ('zstd', None, 'compile zstd bindings [default]'),
503 503 ('no-zstd', None, 'do not compile zstd bindings'),
504 504 (
505 505 'rust',
506 506 None,
507 507 'compile Rust extensions if they are in use '
508 508 '(requires Cargo) [default]',
509 509 ),
510 510 ('no-rust', None, 'do not compile Rust extensions'),
511 511 ]
512 512
513 513 boolean_options = build_ext.boolean_options + ['zstd', 'rust']
514 514 negative_opt = buildextnegops
515 515
516 516 def initialize_options(self):
517 517 self.zstd = True
518 518 self.rust = True
519 519
520 520 return build_ext.initialize_options(self)
521 521
522 522 def finalize_options(self):
523 523 # Unless overridden by the end user, build extensions in parallel.
524 524 # Only influences behavior on Python 3.5+.
525 525 if getattr(self, 'parallel', None) is None:
526 526 self.parallel = True
527 527
528 528 return build_ext.finalize_options(self)
529 529
530 530 def build_extensions(self):
531 531 ruststandalones = [
532 532 e for e in self.extensions if isinstance(e, RustStandaloneExtension)
533 533 ]
534 534 self.extensions = [
535 535 e for e in self.extensions if e not in ruststandalones
536 536 ]
537 537 # Filter out zstd if disabled via argument.
538 538 if not self.zstd:
539 539 self.extensions = [
540 540 e for e in self.extensions if e.name != 'mercurial.zstd'
541 541 ]
542 542
543 543 # Build Rust standalon extensions if it'll be used
544 544 # and its build is not explictely disabled (for external build
545 545 # as Linux distributions would do)
546 546 if self.distribution.rust and self.rust and hgrustext != 'direct-ffi':
547 547 for rustext in ruststandalones:
548 548 rustext.build('' if self.inplace else self.build_lib)
549 549
550 550 return build_ext.build_extensions(self)
551 551
552 552 def build_extension(self, ext):
553 553 if (
554 554 self.distribution.rust
555 555 and self.rust
556 556 and isinstance(ext, RustExtension)
557 557 ):
558 558 ext.rustbuild()
559 559 try:
560 560 build_ext.build_extension(self, ext)
561 561 except CCompilerError:
562 562 if not getattr(ext, 'optional', False):
563 563 raise
564 564 log.warn(
565 565 "Failed to build optional extension '%s' (skipping)", ext.name
566 566 )
567 567
568 568
569 569 class hgbuildscripts(build_scripts):
570 570 def run(self):
571 571 if os.name != 'nt' or self.distribution.pure:
572 572 return build_scripts.run(self)
573 573
574 574 exebuilt = False
575 575 try:
576 576 self.run_command('build_hgexe')
577 577 exebuilt = True
578 578 except (DistutilsError, CCompilerError):
579 579 log.warn('failed to build optional hg.exe')
580 580
581 581 if exebuilt:
582 582 # Copying hg.exe to the scripts build directory ensures it is
583 583 # installed by the install_scripts command.
584 584 hgexecommand = self.get_finalized_command('build_hgexe')
585 585 dest = os.path.join(self.build_dir, 'hg.exe')
586 586 self.mkpath(self.build_dir)
587 587 self.copy_file(hgexecommand.hgexepath, dest)
588 588
589 589 # Remove hg.bat because it is redundant with hg.exe.
590 590 self.scripts.remove('contrib/win32/hg.bat')
591 591
592 592 return build_scripts.run(self)
593 593
594 594
595 595 class hgbuildpy(build_py):
596 596 def finalize_options(self):
597 597 build_py.finalize_options(self)
598 598
599 599 if self.distribution.pure:
600 600 self.distribution.ext_modules = []
601 601 elif self.distribution.cffi:
602 602 from mercurial.cffi import (
603 603 bdiffbuild,
604 604 mpatchbuild,
605 605 )
606 606
607 607 exts = [
608 608 mpatchbuild.ffi.distutils_extension(),
609 609 bdiffbuild.ffi.distutils_extension(),
610 610 ]
611 611 # cffi modules go here
612 612 if sys.platform == 'darwin':
613 613 from mercurial.cffi import osutilbuild
614 614
615 615 exts.append(osutilbuild.ffi.distutils_extension())
616 616 self.distribution.ext_modules = exts
617 617 else:
618 618 h = os.path.join(get_python_inc(), 'Python.h')
619 619 if not os.path.exists(h):
620 620 raise SystemExit(
621 621 'Python headers are required to build '
622 622 'Mercurial but weren\'t found in %s' % h
623 623 )
624 624
625 625 def run(self):
626 626 basepath = os.path.join(self.build_lib, 'mercurial')
627 627 self.mkpath(basepath)
628 628
629 629 rust = self.distribution.rust
630 630 if self.distribution.pure:
631 631 modulepolicy = 'py'
632 632 elif self.build_lib == '.':
633 633 # in-place build should run without rebuilding and Rust extensions
634 634 modulepolicy = 'rust+c-allow' if rust else 'allow'
635 635 else:
636 636 modulepolicy = 'rust+c' if rust else 'c'
637 637
638 638 content = b''.join(
639 639 [
640 640 b'# this file is autogenerated by setup.py\n',
641 641 b'modulepolicy = b"%s"\n' % modulepolicy.encode('ascii'),
642 642 ]
643 643 )
644 644 write_if_changed(os.path.join(basepath, '__modulepolicy__.py'), content)
645 645
646 646 build_py.run(self)
647 647
648 648
649 649 class buildhgextindex(Command):
650 650 description = 'generate prebuilt index of hgext (for frozen package)'
651 651 user_options = []
652 652 _indexfilename = 'hgext/__index__.py'
653 653
654 654 def initialize_options(self):
655 655 pass
656 656
657 657 def finalize_options(self):
658 658 pass
659 659
660 660 def run(self):
661 661 if os.path.exists(self._indexfilename):
662 662 with open(self._indexfilename, 'w') as f:
663 663 f.write('# empty\n')
664 664
665 665 # here no extension enabled, disabled() lists up everything
666 666 code = (
667 667 'import pprint; from mercurial import extensions; '
668 668 'pprint.pprint(extensions.disabled())'
669 669 )
670 670 returncode, out, err = runcmd(
671 671 [sys.executable, '-c', code], localhgenv()
672 672 )
673 673 if err or returncode != 0:
674 674 raise DistutilsExecError(err)
675 675
676 676 with open(self._indexfilename, 'wb') as f:
677 677 f.write(b'# this file is autogenerated by setup.py\n')
678 678 f.write(b'docs = ')
679 679 f.write(out)
680 680
681 681
682 682 class buildhgexe(build_ext):
683 683 description = 'compile hg.exe from mercurial/exewrapper.c'
684 684 user_options = build_ext.user_options + [
685 685 (
686 686 'long-paths-support',
687 687 None,
688 688 'enable support for long paths on '
689 689 'Windows (off by default and '
690 690 'experimental)',
691 691 ),
692 692 ]
693 693
694 694 LONG_PATHS_MANIFEST = """
695 695 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
696 696 <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
697 697 <application>
698 698 <windowsSettings
699 699 xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
700 700 <ws2:longPathAware>true</ws2:longPathAware>
701 701 </windowsSettings>
702 702 </application>
703 703 </assembly>"""
704 704
705 705 def initialize_options(self):
706 706 build_ext.initialize_options(self)
707 707 self.long_paths_support = False
708 708
709 709 def build_extensions(self):
710 710 if os.name != 'nt':
711 711 return
712 712 if isinstance(self.compiler, HackedMingw32CCompiler):
713 713 self.compiler.compiler_so = self.compiler.compiler # no -mdll
714 714 self.compiler.dll_libraries = [] # no -lmsrvc90
715 715
716 716 pythonlib = None
717 717
718 718 if getattr(sys, 'dllhandle', None):
719 719 # Different Python installs can have different Python library
720 720 # names. e.g. the official CPython distribution uses pythonXY.dll
721 721 # and MinGW uses libpythonX.Y.dll.
722 722 _kernel32 = ctypes.windll.kernel32
723 723 _kernel32.GetModuleFileNameA.argtypes = [
724 724 ctypes.c_void_p,
725 725 ctypes.c_void_p,
726 726 ctypes.c_ulong,
727 727 ]
728 728 _kernel32.GetModuleFileNameA.restype = ctypes.c_ulong
729 729 size = 1000
730 730 buf = ctypes.create_string_buffer(size + 1)
731 731 filelen = _kernel32.GetModuleFileNameA(
732 732 sys.dllhandle, ctypes.byref(buf), size
733 733 )
734 734
735 735 if filelen > 0 and filelen != size:
736 736 dllbasename = os.path.basename(buf.value)
737 737 if not dllbasename.lower().endswith(b'.dll'):
738 738 raise SystemExit(
739 739 'Python DLL does not end with .dll: %s' % dllbasename
740 740 )
741 741 pythonlib = dllbasename[:-4]
742 742
743 743 if not pythonlib:
744 744 log.warn(
745 745 'could not determine Python DLL filename; assuming pythonXY'
746 746 )
747 747
748 748 hv = sys.hexversion
749 749 pythonlib = b'python%d%d' % (hv >> 24, (hv >> 16) & 0xFF)
750 750
751 751 log.info('using %s as Python library name' % pythonlib)
752 752 with open('mercurial/hgpythonlib.h', 'wb') as f:
753 753 f.write(b'/* this file is autogenerated by setup.py */\n')
754 754 f.write(b'#define HGPYTHONLIB "%s"\n' % pythonlib)
755 755
756 756 macros = None
757 757 if sys.version_info[0] >= 3:
758 758 macros = [('_UNICODE', None), ('UNICODE', None)]
759 759
760 760 objects = self.compiler.compile(
761 761 ['mercurial/exewrapper.c'],
762 762 output_dir=self.build_temp,
763 763 macros=macros,
764 764 )
765 765 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
766 766 self.hgtarget = os.path.join(dir, 'hg')
767 767 self.compiler.link_executable(
768 768 objects, self.hgtarget, libraries=[], output_dir=self.build_temp
769 769 )
770 770 if self.long_paths_support:
771 771 self.addlongpathsmanifest()
772 772
773 773 def addlongpathsmanifest(self):
774 774 r"""Add manifest pieces so that hg.exe understands long paths
775 775
776 776 This is an EXPERIMENTAL feature, use with care.
777 777 To enable long paths support, one needs to do two things:
778 778 - build Mercurial with --long-paths-support option
779 779 - change HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\
780 780 LongPathsEnabled to have value 1.
781 781
782 782 Please ignore 'warning 81010002: Unrecognized Element "longPathAware"';
783 783 it happens because Mercurial uses mt.exe circa 2008, which is not
784 784 yet aware of long paths support in the manifest (I think so at least).
785 785 This does not stop mt.exe from embedding/merging the XML properly.
786 786
787 787 Why resource #1 should be used for .exe manifests? I don't know and
788 788 wasn't able to find an explanation for mortals. But it seems to work.
789 789 """
790 790 exefname = self.compiler.executable_filename(self.hgtarget)
791 791 fdauto, manfname = tempfile.mkstemp(suffix='.hg.exe.manifest')
792 792 os.close(fdauto)
793 793 with open(manfname, 'w') as f:
794 794 f.write(self.LONG_PATHS_MANIFEST)
795 795 log.info("long paths manifest is written to '%s'" % manfname)
796 796 inputresource = '-inputresource:%s;#1' % exefname
797 797 outputresource = '-outputresource:%s;#1' % exefname
798 798 log.info("running mt.exe to update hg.exe's manifest in-place")
799 799 # supplying both -manifest and -inputresource to mt.exe makes
800 800 # it merge the embedded and supplied manifests in the -outputresource
801 801 self.spawn(
802 802 [
803 803 'mt.exe',
804 804 '-nologo',
805 805 '-manifest',
806 806 manfname,
807 807 inputresource,
808 808 outputresource,
809 809 ]
810 810 )
811 811 log.info("done updating hg.exe's manifest")
812 812 os.remove(manfname)
813 813
814 814 @property
815 815 def hgexepath(self):
816 816 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
817 817 return os.path.join(self.build_temp, dir, 'hg.exe')
818 818
819 819
820 820 class hgbuilddoc(Command):
821 821 description = 'build documentation'
822 822 user_options = [
823 823 ('man', None, 'generate man pages'),
824 824 ('html', None, 'generate html pages'),
825 825 ]
826 826
827 827 def initialize_options(self):
828 828 self.man = None
829 829 self.html = None
830 830
831 831 def finalize_options(self):
832 832 # If --man or --html are set, only generate what we're told to.
833 833 # Otherwise generate everything.
834 834 have_subset = self.man is not None or self.html is not None
835 835
836 836 if have_subset:
837 837 self.man = True if self.man else False
838 838 self.html = True if self.html else False
839 839 else:
840 840 self.man = True
841 841 self.html = True
842 842
843 843 def run(self):
844 844 def normalizecrlf(p):
845 845 with open(p, 'rb') as fh:
846 846 orig = fh.read()
847 847
848 848 if b'\r\n' not in orig:
849 849 return
850 850
851 851 log.info('normalizing %s to LF line endings' % p)
852 852 with open(p, 'wb') as fh:
853 853 fh.write(orig.replace(b'\r\n', b'\n'))
854 854
855 855 def gentxt(root):
856 856 txt = 'doc/%s.txt' % root
857 857 log.info('generating %s' % txt)
858 858 res, out, err = runcmd(
859 859 [sys.executable, 'gendoc.py', root], os.environ, cwd='doc'
860 860 )
861 861 if res:
862 862 raise SystemExit(
863 863 'error running gendoc.py: %s' % '\n'.join([out, err])
864 864 )
865 865
866 866 with open(txt, 'wb') as fh:
867 867 fh.write(out)
868 868
869 869 def gengendoc(root):
870 870 gendoc = 'doc/%s.gendoc.txt' % root
871 871
872 872 log.info('generating %s' % gendoc)
873 873 res, out, err = runcmd(
874 874 [sys.executable, 'gendoc.py', '%s.gendoc' % root],
875 875 os.environ,
876 876 cwd='doc',
877 877 )
878 878 if res:
879 879 raise SystemExit(
880 880 'error running gendoc: %s' % '\n'.join([out, err])
881 881 )
882 882
883 883 with open(gendoc, 'wb') as fh:
884 884 fh.write(out)
885 885
886 886 def genman(root):
887 887 log.info('generating doc/%s' % root)
888 888 res, out, err = runcmd(
889 889 [
890 890 sys.executable,
891 891 'runrst',
892 892 'hgmanpage',
893 893 '--halt',
894 894 'warning',
895 895 '--strip-elements-with-class',
896 896 'htmlonly',
897 897 '%s.txt' % root,
898 898 root,
899 899 ],
900 900 os.environ,
901 901 cwd='doc',
902 902 )
903 903 if res:
904 904 raise SystemExit(
905 905 'error running runrst: %s' % '\n'.join([out, err])
906 906 )
907 907
908 908 normalizecrlf('doc/%s' % root)
909 909
910 910 def genhtml(root):
911 911 log.info('generating doc/%s.html' % root)
912 912 res, out, err = runcmd(
913 913 [
914 914 sys.executable,
915 915 'runrst',
916 916 'html',
917 917 '--halt',
918 918 'warning',
919 919 '--link-stylesheet',
920 920 '--stylesheet-path',
921 921 'style.css',
922 922 '%s.txt' % root,
923 923 '%s.html' % root,
924 924 ],
925 925 os.environ,
926 926 cwd='doc',
927 927 )
928 928 if res:
929 929 raise SystemExit(
930 930 'error running runrst: %s' % '\n'.join([out, err])
931 931 )
932 932
933 933 normalizecrlf('doc/%s.html' % root)
934 934
935 935 # This logic is duplicated in doc/Makefile.
936 936 sources = set(
937 937 f
938 938 for f in os.listdir('mercurial/helptext')
939 939 if re.search(r'[0-9]\.txt$', f)
940 940 )
941 941
942 942 # common.txt is a one-off.
943 943 gentxt('common')
944 944
945 945 for source in sorted(sources):
946 946 assert source[-4:] == '.txt'
947 947 root = source[:-4]
948 948
949 949 gentxt(root)
950 950 gengendoc(root)
951 951
952 952 if self.man:
953 953 genman(root)
954 954 if self.html:
955 955 genhtml(root)
956 956
957 957
958 958 class hginstall(install):
959 959
960 960 user_options = install.user_options + [
961 961 (
962 962 'old-and-unmanageable',
963 963 None,
964 964 'noop, present for eggless setuptools compat',
965 965 ),
966 966 (
967 967 'single-version-externally-managed',
968 968 None,
969 969 'noop, present for eggless setuptools compat',
970 970 ),
971 971 ]
972 972
973 973 # Also helps setuptools not be sad while we refuse to create eggs.
974 974 single_version_externally_managed = True
975 975
976 976 def get_sub_commands(self):
977 977 # Screen out egg related commands to prevent egg generation. But allow
978 978 # mercurial.egg-info generation, since that is part of modern
979 979 # packaging.
980 980 excl = set(['bdist_egg'])
981 981 return filter(lambda x: x not in excl, install.get_sub_commands(self))
982 982
983 983
984 984 class hginstalllib(install_lib):
985 985 '''
986 986 This is a specialization of install_lib that replaces the copy_file used
987 987 there so that it supports setting the mode of files after copying them,
988 988 instead of just preserving the mode that the files originally had. If your
989 989 system has a umask of something like 027, preserving the permissions when
990 990 copying will lead to a broken install.
991 991
992 992 Note that just passing keep_permissions=False to copy_file would be
993 993 insufficient, as it might still be applying a umask.
994 994 '''
995 995
996 996 def run(self):
997 997 realcopyfile = file_util.copy_file
998 998
999 999 def copyfileandsetmode(*args, **kwargs):
1000 1000 src, dst = args[0], args[1]
1001 1001 dst, copied = realcopyfile(*args, **kwargs)
1002 1002 if copied:
1003 1003 st = os.stat(src)
1004 1004 # Persist executable bit (apply it to group and other if user
1005 1005 # has it)
1006 1006 if st[stat.ST_MODE] & stat.S_IXUSR:
1007 1007 setmode = int('0755', 8)
1008 1008 else:
1009 1009 setmode = int('0644', 8)
1010 1010 m = stat.S_IMODE(st[stat.ST_MODE])
1011 1011 m = (m & ~int('0777', 8)) | setmode
1012 1012 os.chmod(dst, m)
1013 1013
1014 1014 file_util.copy_file = copyfileandsetmode
1015 1015 try:
1016 1016 install_lib.run(self)
1017 1017 finally:
1018 1018 file_util.copy_file = realcopyfile
1019 1019
1020 1020
1021 1021 class hginstallscripts(install_scripts):
1022 1022 '''
1023 1023 This is a specialization of install_scripts that replaces the @LIBDIR@ with
1024 1024 the configured directory for modules. If possible, the path is made relative
1025 1025 to the directory for scripts.
1026 1026 '''
1027 1027
1028 1028 def initialize_options(self):
1029 1029 install_scripts.initialize_options(self)
1030 1030
1031 1031 self.install_lib = None
1032 1032
1033 1033 def finalize_options(self):
1034 1034 install_scripts.finalize_options(self)
1035 1035 self.set_undefined_options('install', ('install_lib', 'install_lib'))
1036 1036
1037 1037 def run(self):
1038 1038 install_scripts.run(self)
1039 1039
1040 1040 # It only makes sense to replace @LIBDIR@ with the install path if
1041 1041 # the install path is known. For wheels, the logic below calculates
1042 1042 # the libdir to be "../..". This is because the internal layout of a
1043 1043 # wheel archive looks like:
1044 1044 #
1045 1045 # mercurial-3.6.1.data/scripts/hg
1046 1046 # mercurial/__init__.py
1047 1047 #
1048 1048 # When installing wheels, the subdirectories of the "<pkg>.data"
1049 1049 # directory are translated to system local paths and files therein
1050 1050 # are copied in place. The mercurial/* files are installed into the
1051 1051 # site-packages directory. However, the site-packages directory
1052 1052 # isn't known until wheel install time. This means we have no clue
1053 1053 # at wheel generation time what the installed site-packages directory
1054 1054 # will be. And, wheels don't appear to provide the ability to register
1055 1055 # custom code to run during wheel installation. This all means that
1056 1056 # we can't reliably set the libdir in wheels: the default behavior
1057 1057 # of looking in sys.path must do.
1058 1058
1059 1059 if (
1060 1060 os.path.splitdrive(self.install_dir)[0]
1061 1061 != os.path.splitdrive(self.install_lib)[0]
1062 1062 ):
1063 1063 # can't make relative paths from one drive to another, so use an
1064 1064 # absolute path instead
1065 1065 libdir = self.install_lib
1066 1066 else:
1067 1067 libdir = os.path.relpath(self.install_lib, self.install_dir)
1068 1068
1069 1069 for outfile in self.outfiles:
1070 1070 with open(outfile, 'rb') as fp:
1071 1071 data = fp.read()
1072 1072
1073 1073 # skip binary files
1074 1074 if b'\0' in data:
1075 1075 continue
1076 1076
1077 1077 # During local installs, the shebang will be rewritten to the final
1078 1078 # install path. During wheel packaging, the shebang has a special
1079 1079 # value.
1080 1080 if data.startswith(b'#!python'):
1081 1081 log.info(
1082 1082 'not rewriting @LIBDIR@ in %s because install path '
1083 1083 'not known' % outfile
1084 1084 )
1085 1085 continue
1086 1086
1087 1087 data = data.replace(b'@LIBDIR@', libdir.encode(libdir_escape))
1088 1088 with open(outfile, 'wb') as fp:
1089 1089 fp.write(data)
1090 1090
1091 1091
1092 1092 # virtualenv installs custom distutils/__init__.py and
1093 1093 # distutils/distutils.cfg files which essentially proxy back to the
1094 1094 # "real" distutils in the main Python install. The presence of this
1095 1095 # directory causes py2exe to pick up the "hacked" distutils package
1096 1096 # from the virtualenv and "import distutils" will fail from the py2exe
1097 1097 # build because the "real" distutils files can't be located.
1098 1098 #
1099 1099 # We work around this by monkeypatching the py2exe code finding Python
1100 1100 # modules to replace the found virtualenv distutils modules with the
1101 1101 # original versions via filesystem scanning. This is a bit hacky. But
1102 1102 # it allows us to use virtualenvs for py2exe packaging, which is more
1103 1103 # deterministic and reproducible.
1104 1104 #
1105 1105 # It's worth noting that the common StackOverflow suggestions for this
1106 1106 # problem involve copying the original distutils files into the
1107 1107 # virtualenv or into the staging directory after setup() is invoked.
1108 1108 # The former is very brittle and can easily break setup(). Our hacking
1109 1109 # of the found modules routine has a similar result as copying the files
1110 1110 # manually. But it makes fewer assumptions about how py2exe works and
1111 1111 # is less brittle.
1112 1112
1113 1113 # This only catches virtualenvs made with virtualenv (as opposed to
1114 1114 # venv, which is likely what Python 3 uses).
1115 1115 py2exehacked = py2exeloaded and getattr(sys, 'real_prefix', None) is not None
1116 1116
1117 1117 if py2exehacked:
1118 1118 from distutils.command.py2exe import py2exe as buildpy2exe
1119 1119 from py2exe.mf import Module as py2exemodule
1120 1120
1121 1121 class hgbuildpy2exe(buildpy2exe):
1122 1122 def find_needed_modules(self, mf, files, modules):
1123 1123 res = buildpy2exe.find_needed_modules(self, mf, files, modules)
1124 1124
1125 1125 # Replace virtualenv's distutils modules with the real ones.
1126 1126 modules = {}
1127 1127 for k, v in res.modules.items():
1128 1128 if k != 'distutils' and not k.startswith('distutils.'):
1129 1129 modules[k] = v
1130 1130
1131 1131 res.modules = modules
1132 1132
1133 1133 import opcode
1134 1134
1135 1135 distutilsreal = os.path.join(
1136 1136 os.path.dirname(opcode.__file__), 'distutils'
1137 1137 )
1138 1138
1139 1139 for root, dirs, files in os.walk(distutilsreal):
1140 1140 for f in sorted(files):
1141 1141 if not f.endswith('.py'):
1142 1142 continue
1143 1143
1144 1144 full = os.path.join(root, f)
1145 1145
1146 1146 parents = ['distutils']
1147 1147
1148 1148 if root != distutilsreal:
1149 1149 rel = os.path.relpath(root, distutilsreal)
1150 1150 parents.extend(p for p in rel.split(os.sep))
1151 1151
1152 1152 modname = '%s.%s' % ('.'.join(parents), f[:-3])
1153 1153
1154 1154 if modname.startswith('distutils.tests.'):
1155 1155 continue
1156 1156
1157 1157 if modname.endswith('.__init__'):
1158 1158 modname = modname[: -len('.__init__')]
1159 1159 path = os.path.dirname(full)
1160 1160 else:
1161 1161 path = None
1162 1162
1163 1163 res.modules[modname] = py2exemodule(
1164 1164 modname, full, path=path
1165 1165 )
1166 1166
1167 1167 if 'distutils' not in res.modules:
1168 1168 raise SystemExit('could not find distutils modules')
1169 1169
1170 1170 return res
1171 1171
1172 1172
1173 1173 cmdclass = {
1174 1174 'build': hgbuild,
1175 1175 'build_doc': hgbuilddoc,
1176 1176 'build_mo': hgbuildmo,
1177 1177 'build_ext': hgbuildext,
1178 1178 'build_py': hgbuildpy,
1179 1179 'build_scripts': hgbuildscripts,
1180 1180 'build_hgextindex': buildhgextindex,
1181 1181 'install': hginstall,
1182 1182 'install_lib': hginstalllib,
1183 1183 'install_scripts': hginstallscripts,
1184 1184 'build_hgexe': buildhgexe,
1185 1185 }
1186 1186
1187 1187 if py2exehacked:
1188 1188 cmdclass['py2exe'] = hgbuildpy2exe
1189 1189
1190 1190 packages = [
1191 1191 'mercurial',
1192 1192 'mercurial.cext',
1193 1193 'mercurial.cffi',
1194 1194 'mercurial.defaultrc',
1195 1195 'mercurial.helptext',
1196 1196 'mercurial.helptext.internals',
1197 1197 'mercurial.hgweb',
1198 1198 'mercurial.interfaces',
1199 1199 'mercurial.pure',
1200 1200 'mercurial.thirdparty',
1201 1201 'mercurial.thirdparty.attr',
1202 1202 'mercurial.thirdparty.zope',
1203 1203 'mercurial.thirdparty.zope.interface',
1204 1204 'mercurial.utils',
1205 1205 'mercurial.revlogutils',
1206 1206 'mercurial.testing',
1207 1207 'hgext',
1208 1208 'hgext.convert',
1209 1209 'hgext.fsmonitor',
1210 1210 'hgext.fastannotate',
1211 1211 'hgext.fsmonitor.pywatchman',
1212 1212 'hgext.highlight',
1213 1213 'hgext.infinitepush',
1214 1214 'hgext.largefiles',
1215 1215 'hgext.lfs',
1216 1216 'hgext.narrow',
1217 1217 'hgext.remotefilelog',
1218 1218 'hgext.zeroconf',
1219 1219 'hgext3rd',
1220 1220 'hgdemandimport',
1221 1221 ]
1222 1222 if sys.version_info[0] == 2:
1223 1223 packages.extend(
1224 1224 [
1225 1225 'mercurial.thirdparty.concurrent',
1226 1226 'mercurial.thirdparty.concurrent.futures',
1227 1227 ]
1228 1228 )
1229 1229
1230 1230 if 'HG_PY2EXE_EXTRA_INSTALL_PACKAGES' in os.environ:
1231 1231 # py2exe can't cope with namespace packages very well, so we have to
1232 1232 # install any hgext3rd.* extensions that we want in the final py2exe
1233 1233 # image here. This is gross, but you gotta do what you gotta do.
1234 1234 packages.extend(os.environ['HG_PY2EXE_EXTRA_INSTALL_PACKAGES'].split(' '))
1235 1235
1236 1236 common_depends = [
1237 1237 'mercurial/bitmanipulation.h',
1238 1238 'mercurial/compat.h',
1239 1239 'mercurial/cext/util.h',
1240 1240 ]
1241 1241 common_include_dirs = ['mercurial']
1242 1242
1243 1243 osutil_cflags = []
1244 1244 osutil_ldflags = []
1245 1245
1246 1246 # platform specific macros
1247 1247 for plat, func in [('bsd', 'setproctitle')]:
1248 1248 if re.search(plat, sys.platform) and hasfunction(new_compiler(), func):
1249 1249 osutil_cflags.append('-DHAVE_%s' % func.upper())
1250 1250
1251 1251 for plat, macro, code in [
1252 1252 (
1253 1253 'bsd|darwin',
1254 1254 'BSD_STATFS',
1255 1255 '''
1256 1256 #include <sys/param.h>
1257 1257 #include <sys/mount.h>
1258 1258 int main() { struct statfs s; return sizeof(s.f_fstypename); }
1259 1259 ''',
1260 1260 ),
1261 1261 (
1262 1262 'linux',
1263 1263 'LINUX_STATFS',
1264 1264 '''
1265 1265 #include <linux/magic.h>
1266 1266 #include <sys/vfs.h>
1267 1267 int main() { struct statfs s; return sizeof(s.f_type); }
1268 1268 ''',
1269 1269 ),
1270 1270 ]:
1271 1271 if re.search(plat, sys.platform) and cancompile(new_compiler(), code):
1272 1272 osutil_cflags.append('-DHAVE_%s' % macro)
1273 1273
1274 1274 if sys.platform == 'darwin':
1275 1275 osutil_ldflags += ['-framework', 'ApplicationServices']
1276 1276
1277 1277 xdiff_srcs = [
1278 1278 'mercurial/thirdparty/xdiff/xdiffi.c',
1279 1279 'mercurial/thirdparty/xdiff/xprepare.c',
1280 1280 'mercurial/thirdparty/xdiff/xutils.c',
1281 1281 ]
1282 1282
1283 1283 xdiff_headers = [
1284 1284 'mercurial/thirdparty/xdiff/xdiff.h',
1285 1285 'mercurial/thirdparty/xdiff/xdiffi.h',
1286 1286 'mercurial/thirdparty/xdiff/xinclude.h',
1287 1287 'mercurial/thirdparty/xdiff/xmacros.h',
1288 1288 'mercurial/thirdparty/xdiff/xprepare.h',
1289 1289 'mercurial/thirdparty/xdiff/xtypes.h',
1290 1290 'mercurial/thirdparty/xdiff/xutils.h',
1291 1291 ]
1292 1292
1293 1293
1294 1294 class RustCompilationError(CCompilerError):
1295 1295 """Exception class for Rust compilation errors."""
1296 1296
1297 1297
1298 1298 class RustExtension(Extension):
1299 1299 """Base classes for concrete Rust Extension classes.
1300 1300 """
1301 1301
1302 1302 rusttargetdir = os.path.join('rust', 'target', 'release')
1303 1303
1304 1304 def __init__(
1305 1305 self, mpath, sources, rustlibname, subcrate, py3_features=None, **kw
1306 1306 ):
1307 1307 Extension.__init__(self, mpath, sources, **kw)
1308 1308 srcdir = self.rustsrcdir = os.path.join('rust', subcrate)
1309 1309 self.py3_features = py3_features
1310 1310
1311 1311 # adding Rust source and control files to depends so that the extension
1312 1312 # gets rebuilt if they've changed
1313 1313 self.depends.append(os.path.join(srcdir, 'Cargo.toml'))
1314 1314 cargo_lock = os.path.join(srcdir, 'Cargo.lock')
1315 1315 if os.path.exists(cargo_lock):
1316 1316 self.depends.append(cargo_lock)
1317 1317 for dirpath, subdir, fnames in os.walk(os.path.join(srcdir, 'src')):
1318 1318 self.depends.extend(
1319 1319 os.path.join(dirpath, fname)
1320 1320 for fname in fnames
1321 1321 if os.path.splitext(fname)[1] == '.rs'
1322 1322 )
1323 1323
1324 1324 @staticmethod
1325 1325 def rustdylibsuffix():
1326 1326 """Return the suffix for shared libraries produced by rustc.
1327 1327
1328 1328 See also: https://doc.rust-lang.org/reference/linkage.html
1329 1329 """
1330 1330 if sys.platform == 'darwin':
1331 1331 return '.dylib'
1332 1332 elif os.name == 'nt':
1333 1333 return '.dll'
1334 1334 else:
1335 1335 return '.so'
1336 1336
1337 1337 def rustbuild(self):
1338 1338 env = os.environ.copy()
1339 1339 if 'HGTEST_RESTOREENV' in env:
1340 1340 # Mercurial tests change HOME to a temporary directory,
1341 1341 # but, if installed with rustup, the Rust toolchain needs
1342 1342 # HOME to be correct (otherwise the 'no default toolchain'
1343 1343 # error message is issued and the build fails).
1344 1344 # This happens currently with test-hghave.t, which does
1345 1345 # invoke this build.
1346 1346
1347 1347 # Unix only fix (os.path.expanduser not really reliable if
1348 1348 # HOME is shadowed like this)
1349 1349 import pwd
1350 1350
1351 1351 env['HOME'] = pwd.getpwuid(os.getuid()).pw_dir
1352 1352
1353 1353 cargocmd = ['cargo', 'rustc', '-vv', '--release']
1354
1355 feature_flags = []
1356
1354 1357 if sys.version_info[0] == 3 and self.py3_features is not None:
1355 cargocmd.extend(
1356 ('--features', self.py3_features, '--no-default-features')
1357 )
1358 feature_flags.append(self.py3_features)
1359 cargocmd.append('--no-default-features')
1360
1361 rust_features = env.get("HG_RUST_FEATURES")
1362 if rust_features:
1363 feature_flags.append(rust_features)
1364
1365 cargocmd.extend(('--features', " ".join(feature_flags)))
1366
1358 1367 cargocmd.append('--')
1359 1368 if sys.platform == 'darwin':
1360 1369 cargocmd.extend(
1361 1370 ("-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup")
1362 1371 )
1363 1372 try:
1364 1373 subprocess.check_call(cargocmd, env=env, cwd=self.rustsrcdir)
1365 1374 except OSError as exc:
1366 1375 if exc.errno == errno.ENOENT:
1367 1376 raise RustCompilationError("Cargo not found")
1368 1377 elif exc.errno == errno.EACCES:
1369 1378 raise RustCompilationError(
1370 1379 "Cargo found, but permisssion to execute it is denied"
1371 1380 )
1372 1381 else:
1373 1382 raise
1374 1383 except subprocess.CalledProcessError:
1375 1384 raise RustCompilationError(
1376 1385 "Cargo failed. Working directory: %r, "
1377 1386 "command: %r, environment: %r"
1378 1387 % (self.rustsrcdir, cargocmd, env)
1379 1388 )
1380 1389
1381 1390
1382 1391 class RustEnhancedExtension(RustExtension):
1383 1392 """A C Extension, conditionally enhanced with Rust code.
1384 1393
1385 1394 If the HGWITHRUSTEXT environment variable is set to something else
1386 1395 than 'cpython', the Rust sources get compiled and linked within
1387 1396 the C target shared library object.
1388 1397 """
1389 1398
1390 1399 def __init__(self, mpath, sources, rustlibname, subcrate, **kw):
1391 1400 RustExtension.__init__(
1392 1401 self, mpath, sources, rustlibname, subcrate, **kw
1393 1402 )
1394 1403 if hgrustext != 'direct-ffi':
1395 1404 return
1396 1405 self.extra_compile_args.append('-DWITH_RUST')
1397 1406 self.libraries.append(rustlibname)
1398 1407 self.library_dirs.append(self.rusttargetdir)
1399 1408
1400 1409 def rustbuild(self):
1401 1410 if hgrustext == 'direct-ffi':
1402 1411 RustExtension.rustbuild(self)
1403 1412
1404 1413
1405 1414 class RustStandaloneExtension(RustExtension):
1406 1415 def __init__(self, pydottedname, rustcrate, dylibname, **kw):
1407 1416 RustExtension.__init__(
1408 1417 self, pydottedname, [], dylibname, rustcrate, **kw
1409 1418 )
1410 1419 self.dylibname = dylibname
1411 1420
1412 1421 def build(self, target_dir):
1413 1422 self.rustbuild()
1414 1423 target = [target_dir]
1415 1424 target.extend(self.name.split('.'))
1416 1425 target[-1] += DYLIB_SUFFIX
1417 1426 shutil.copy2(
1418 1427 os.path.join(
1419 1428 self.rusttargetdir, self.dylibname + self.rustdylibsuffix()
1420 1429 ),
1421 1430 os.path.join(*target),
1422 1431 )
1423 1432
1424 1433
1425 1434 extmodules = [
1426 1435 Extension(
1427 1436 'mercurial.cext.base85',
1428 1437 ['mercurial/cext/base85.c'],
1429 1438 include_dirs=common_include_dirs,
1430 1439 depends=common_depends,
1431 1440 ),
1432 1441 Extension(
1433 1442 'mercurial.cext.bdiff',
1434 1443 ['mercurial/bdiff.c', 'mercurial/cext/bdiff.c'] + xdiff_srcs,
1435 1444 include_dirs=common_include_dirs,
1436 1445 depends=common_depends + ['mercurial/bdiff.h'] + xdiff_headers,
1437 1446 ),
1438 1447 Extension(
1439 1448 'mercurial.cext.mpatch',
1440 1449 ['mercurial/mpatch.c', 'mercurial/cext/mpatch.c'],
1441 1450 include_dirs=common_include_dirs,
1442 1451 depends=common_depends,
1443 1452 ),
1444 1453 RustEnhancedExtension(
1445 1454 'mercurial.cext.parsers',
1446 1455 [
1447 1456 'mercurial/cext/charencode.c',
1448 1457 'mercurial/cext/dirs.c',
1449 1458 'mercurial/cext/manifest.c',
1450 1459 'mercurial/cext/parsers.c',
1451 1460 'mercurial/cext/pathencode.c',
1452 1461 'mercurial/cext/revlog.c',
1453 1462 ],
1454 1463 'hgdirectffi',
1455 1464 'hg-direct-ffi',
1456 1465 include_dirs=common_include_dirs,
1457 1466 depends=common_depends
1458 1467 + [
1459 1468 'mercurial/cext/charencode.h',
1460 1469 'mercurial/cext/revlog.h',
1461 1470 'rust/hg-core/src/ancestors.rs',
1462 1471 'rust/hg-core/src/lib.rs',
1463 1472 ],
1464 1473 ),
1465 1474 Extension(
1466 1475 'mercurial.cext.osutil',
1467 1476 ['mercurial/cext/osutil.c'],
1468 1477 include_dirs=common_include_dirs,
1469 1478 extra_compile_args=osutil_cflags,
1470 1479 extra_link_args=osutil_ldflags,
1471 1480 depends=common_depends,
1472 1481 ),
1473 1482 Extension(
1474 1483 'mercurial.thirdparty.zope.interface._zope_interface_coptimizations',
1475 1484 [
1476 1485 'mercurial/thirdparty/zope/interface/_zope_interface_coptimizations.c',
1477 1486 ],
1478 1487 ),
1479 1488 Extension(
1480 1489 'mercurial.thirdparty.sha1dc',
1481 1490 [
1482 1491 'mercurial/thirdparty/sha1dc/cext.c',
1483 1492 'mercurial/thirdparty/sha1dc/lib/sha1.c',
1484 1493 'mercurial/thirdparty/sha1dc/lib/ubc_check.c',
1485 1494 ],
1486 1495 ),
1487 1496 Extension(
1488 1497 'hgext.fsmonitor.pywatchman.bser', ['hgext/fsmonitor/pywatchman/bser.c']
1489 1498 ),
1490 1499 RustStandaloneExtension(
1491 1500 'mercurial.rustext', 'hg-cpython', 'librusthg', py3_features='python3'
1492 1501 ),
1493 1502 ]
1494 1503
1495 1504
1496 1505 sys.path.insert(0, 'contrib/python-zstandard')
1497 1506 import setup_zstd
1498 1507
1499 1508 extmodules.append(
1500 1509 setup_zstd.get_c_extension(
1501 1510 name='mercurial.zstd', root=os.path.abspath(os.path.dirname(__file__))
1502 1511 )
1503 1512 )
1504 1513
1505 1514 try:
1506 1515 from distutils import cygwinccompiler
1507 1516
1508 1517 # the -mno-cygwin option has been deprecated for years
1509 1518 mingw32compilerclass = cygwinccompiler.Mingw32CCompiler
1510 1519
1511 1520 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
1512 1521 def __init__(self, *args, **kwargs):
1513 1522 mingw32compilerclass.__init__(self, *args, **kwargs)
1514 1523 for i in 'compiler compiler_so linker_exe linker_so'.split():
1515 1524 try:
1516 1525 getattr(self, i).remove('-mno-cygwin')
1517 1526 except ValueError:
1518 1527 pass
1519 1528
1520 1529 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
1521 1530 except ImportError:
1522 1531 # the cygwinccompiler package is not available on some Python
1523 1532 # distributions like the ones from the optware project for Synology
1524 1533 # DiskStation boxes
1525 1534 class HackedMingw32CCompiler(object):
1526 1535 pass
1527 1536
1528 1537
1529 1538 if os.name == 'nt':
1530 1539 # Allow compiler/linker flags to be added to Visual Studio builds. Passing
1531 1540 # extra_link_args to distutils.extensions.Extension() doesn't have any
1532 1541 # effect.
1533 1542 from distutils import msvccompiler
1534 1543
1535 1544 msvccompilerclass = msvccompiler.MSVCCompiler
1536 1545
1537 1546 class HackedMSVCCompiler(msvccompiler.MSVCCompiler):
1538 1547 def initialize(self):
1539 1548 msvccompilerclass.initialize(self)
1540 1549 # "warning LNK4197: export 'func' specified multiple times"
1541 1550 self.ldflags_shared.append('/ignore:4197')
1542 1551 self.ldflags_shared_debug.append('/ignore:4197')
1543 1552
1544 1553 msvccompiler.MSVCCompiler = HackedMSVCCompiler
1545 1554
1546 1555 packagedata = {
1547 1556 'mercurial': [
1548 1557 'locale/*/LC_MESSAGES/hg.mo',
1549 1558 'defaultrc/*.rc',
1550 1559 'dummycert.pem',
1551 1560 ],
1552 1561 'mercurial.helptext': ['*.txt',],
1553 1562 'mercurial.helptext.internals': ['*.txt',],
1554 1563 }
1555 1564
1556 1565
1557 1566 def ordinarypath(p):
1558 1567 return p and p[0] != '.' and p[-1] != '~'
1559 1568
1560 1569
1561 1570 for root in ('templates',):
1562 1571 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
1563 1572 curdir = curdir.split(os.sep, 1)[1]
1564 1573 dirs[:] = filter(ordinarypath, dirs)
1565 1574 for f in filter(ordinarypath, files):
1566 1575 f = os.path.join(curdir, f)
1567 1576 packagedata['mercurial'].append(f)
1568 1577
1569 1578 datafiles = []
1570 1579
1571 1580 # distutils expects version to be str/unicode. Converting it to
1572 1581 # unicode on Python 2 still works because it won't contain any
1573 1582 # non-ascii bytes and will be implicitly converted back to bytes
1574 1583 # when operated on.
1575 1584 assert isinstance(version, bytes)
1576 1585 setupversion = version.decode('ascii')
1577 1586
1578 1587 extra = {}
1579 1588
1580 1589 py2exepackages = [
1581 1590 'hgdemandimport',
1582 1591 'hgext3rd',
1583 1592 'hgext',
1584 1593 'email',
1585 1594 # implicitly imported per module policy
1586 1595 # (cffi wouldn't be used as a frozen exe)
1587 1596 'mercurial.cext',
1588 1597 #'mercurial.cffi',
1589 1598 'mercurial.pure',
1590 1599 ]
1591 1600
1592 1601 py2exeexcludes = []
1593 1602 py2exedllexcludes = ['crypt32.dll']
1594 1603
1595 1604 if issetuptools:
1596 1605 extra['python_requires'] = supportedpy
1597 1606
1598 1607 if py2exeloaded:
1599 1608 extra['console'] = [
1600 1609 {
1601 1610 'script': 'hg',
1602 1611 'copyright': 'Copyright (C) 2005-2020 Matt Mackall and others',
1603 1612 'product_version': version,
1604 1613 }
1605 1614 ]
1606 1615 # Sub command of 'build' because 'py2exe' does not handle sub_commands.
1607 1616 # Need to override hgbuild because it has a private copy of
1608 1617 # build.sub_commands.
1609 1618 hgbuild.sub_commands.insert(0, ('build_hgextindex', None))
1610 1619 # put dlls in sub directory so that they won't pollute PATH
1611 1620 extra['zipfile'] = 'lib/library.zip'
1612 1621
1613 1622 # We allow some configuration to be supplemented via environment
1614 1623 # variables. This is better than setup.cfg files because it allows
1615 1624 # supplementing configs instead of replacing them.
1616 1625 extrapackages = os.environ.get('HG_PY2EXE_EXTRA_PACKAGES')
1617 1626 if extrapackages:
1618 1627 py2exepackages.extend(extrapackages.split(' '))
1619 1628
1620 1629 excludes = os.environ.get('HG_PY2EXE_EXTRA_EXCLUDES')
1621 1630 if excludes:
1622 1631 py2exeexcludes.extend(excludes.split(' '))
1623 1632
1624 1633 dllexcludes = os.environ.get('HG_PY2EXE_EXTRA_DLL_EXCLUDES')
1625 1634 if dllexcludes:
1626 1635 py2exedllexcludes.extend(dllexcludes.split(' '))
1627 1636
1628 1637 if os.name == 'nt':
1629 1638 # Windows binary file versions for exe/dll files must have the
1630 1639 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
1631 1640 setupversion = setupversion.split(r'+', 1)[0]
1632 1641
1633 1642 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
1634 1643 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[1].splitlines()
1635 1644 if version:
1636 1645 version = version[0]
1637 1646 if sys.version_info[0] == 3:
1638 1647 version = version.decode('utf-8')
1639 1648 xcode4 = version.startswith('Xcode') and StrictVersion(
1640 1649 version.split()[1]
1641 1650 ) >= StrictVersion('4.0')
1642 1651 xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
1643 1652 else:
1644 1653 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
1645 1654 # installed, but instead with only command-line tools. Assume
1646 1655 # that only happens on >= Lion, thus no PPC support.
1647 1656 xcode4 = True
1648 1657 xcode51 = False
1649 1658
1650 1659 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
1651 1660 # distutils.sysconfig
1652 1661 if xcode4:
1653 1662 os.environ['ARCHFLAGS'] = ''
1654 1663
1655 1664 # XCode 5.1 changes clang such that it now fails to compile if the
1656 1665 # -mno-fused-madd flag is passed, but the version of Python shipped with
1657 1666 # OS X 10.9 Mavericks includes this flag. This causes problems in all
1658 1667 # C extension modules, and a bug has been filed upstream at
1659 1668 # http://bugs.python.org/issue21244. We also need to patch this here
1660 1669 # so Mercurial can continue to compile in the meantime.
1661 1670 if xcode51:
1662 1671 cflags = get_config_var('CFLAGS')
1663 1672 if cflags and re.search(r'-mno-fused-madd\b', cflags) is not None:
1664 1673 os.environ['CFLAGS'] = (
1665 1674 os.environ.get('CFLAGS', '') + ' -Qunused-arguments'
1666 1675 )
1667 1676
1668 1677 setup(
1669 1678 name='mercurial',
1670 1679 version=setupversion,
1671 1680 author='Matt Mackall and many others',
1672 1681 author_email='mercurial@mercurial-scm.org',
1673 1682 url='https://mercurial-scm.org/',
1674 1683 download_url='https://mercurial-scm.org/release/',
1675 1684 description=(
1676 1685 'Fast scalable distributed SCM (revision control, version '
1677 1686 'control) system'
1678 1687 ),
1679 1688 long_description=(
1680 1689 'Mercurial is a distributed SCM tool written in Python.'
1681 1690 ' It is used by a number of large projects that require'
1682 1691 ' fast, reliable distributed revision control, such as '
1683 1692 'Mozilla.'
1684 1693 ),
1685 1694 license='GNU GPLv2 or any later version',
1686 1695 classifiers=[
1687 1696 'Development Status :: 6 - Mature',
1688 1697 'Environment :: Console',
1689 1698 'Intended Audience :: Developers',
1690 1699 'Intended Audience :: System Administrators',
1691 1700 'License :: OSI Approved :: GNU General Public License (GPL)',
1692 1701 'Natural Language :: Danish',
1693 1702 'Natural Language :: English',
1694 1703 'Natural Language :: German',
1695 1704 'Natural Language :: Italian',
1696 1705 'Natural Language :: Japanese',
1697 1706 'Natural Language :: Portuguese (Brazilian)',
1698 1707 'Operating System :: Microsoft :: Windows',
1699 1708 'Operating System :: OS Independent',
1700 1709 'Operating System :: POSIX',
1701 1710 'Programming Language :: C',
1702 1711 'Programming Language :: Python',
1703 1712 'Topic :: Software Development :: Version Control',
1704 1713 ],
1705 1714 scripts=scripts,
1706 1715 packages=packages,
1707 1716 ext_modules=extmodules,
1708 1717 data_files=datafiles,
1709 1718 package_data=packagedata,
1710 1719 cmdclass=cmdclass,
1711 1720 distclass=hgdist,
1712 1721 options={
1713 1722 'py2exe': {
1714 1723 'bundle_files': 3,
1715 1724 'dll_excludes': py2exedllexcludes,
1716 1725 'excludes': py2exeexcludes,
1717 1726 'packages': py2exepackages,
1718 1727 },
1719 1728 'bdist_mpkg': {
1720 1729 'zipdist': False,
1721 1730 'license': 'COPYING',
1722 1731 'readme': 'contrib/packaging/macosx/Readme.html',
1723 1732 'welcome': 'contrib/packaging/macosx/Welcome.html',
1724 1733 },
1725 1734 },
1726 1735 **extra
1727 1736 )
General Comments 0
You need to be logged in to leave comments. Login now