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