Show More
@@ -1,1096 +1,1102 b'' | |||||
1 | from __future__ import absolute_import, print_function |
|
1 | from __future__ import absolute_import, print_function | |
2 |
|
2 | |||
3 | import distutils.version |
|
3 | import distutils.version | |
4 | import os |
|
4 | import os | |
5 | import re |
|
5 | import re | |
6 | import socket |
|
6 | import socket | |
7 | import stat |
|
7 | import stat | |
8 | import subprocess |
|
8 | import subprocess | |
9 | import sys |
|
9 | import sys | |
10 | import tempfile |
|
10 | import tempfile | |
11 |
|
11 | |||
12 | tempprefix = 'hg-hghave-' |
|
12 | tempprefix = 'hg-hghave-' | |
13 |
|
13 | |||
14 | checks = { |
|
14 | checks = { | |
15 | "true": (lambda: True, "yak shaving"), |
|
15 | "true": (lambda: True, "yak shaving"), | |
16 | "false": (lambda: False, "nail clipper"), |
|
16 | "false": (lambda: False, "nail clipper"), | |
17 | "known-bad-output": (lambda: True, "use for currently known bad output"), |
|
17 | "known-bad-output": (lambda: True, "use for currently known bad output"), | |
18 | "missing-correct-output": (lambda: False, "use for missing good output"), |
|
18 | "missing-correct-output": (lambda: False, "use for missing good output"), | |
19 | } |
|
19 | } | |
20 |
|
20 | |||
21 | try: |
|
21 | try: | |
22 | import msvcrt |
|
22 | import msvcrt | |
23 |
|
23 | |||
24 | msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) |
|
24 | msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) | |
25 | msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY) |
|
25 | msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY) | |
26 | except ImportError: |
|
26 | except ImportError: | |
27 | pass |
|
27 | pass | |
28 |
|
28 | |||
29 | stdout = getattr(sys.stdout, 'buffer', sys.stdout) |
|
29 | stdout = getattr(sys.stdout, 'buffer', sys.stdout) | |
30 | stderr = getattr(sys.stderr, 'buffer', sys.stderr) |
|
30 | stderr = getattr(sys.stderr, 'buffer', sys.stderr) | |
31 |
|
31 | |||
32 | if sys.version_info[0] >= 3: |
|
32 | if sys.version_info[0] >= 3: | |
33 |
|
33 | |||
34 | def _sys2bytes(p): |
|
34 | def _sys2bytes(p): | |
35 | if p is None: |
|
35 | if p is None: | |
36 | return p |
|
36 | return p | |
37 | return p.encode('utf-8') |
|
37 | return p.encode('utf-8') | |
38 |
|
38 | |||
39 | def _bytes2sys(p): |
|
39 | def _bytes2sys(p): | |
40 | if p is None: |
|
40 | if p is None: | |
41 | return p |
|
41 | return p | |
42 | return p.decode('utf-8') |
|
42 | return p.decode('utf-8') | |
43 |
|
43 | |||
44 |
|
44 | |||
45 | else: |
|
45 | else: | |
46 |
|
46 | |||
47 | def _sys2bytes(p): |
|
47 | def _sys2bytes(p): | |
48 | return p |
|
48 | return p | |
49 |
|
49 | |||
50 | _bytes2sys = _sys2bytes |
|
50 | _bytes2sys = _sys2bytes | |
51 |
|
51 | |||
52 |
|
52 | |||
53 | def check(name, desc): |
|
53 | def check(name, desc): | |
54 | """Registers a check function for a feature.""" |
|
54 | """Registers a check function for a feature.""" | |
55 |
|
55 | |||
56 | def decorator(func): |
|
56 | def decorator(func): | |
57 | checks[name] = (func, desc) |
|
57 | checks[name] = (func, desc) | |
58 | return func |
|
58 | return func | |
59 |
|
59 | |||
60 | return decorator |
|
60 | return decorator | |
61 |
|
61 | |||
62 |
|
62 | |||
63 | def checkvers(name, desc, vers): |
|
63 | def checkvers(name, desc, vers): | |
64 | """Registers a check function for each of a series of versions. |
|
64 | """Registers a check function for each of a series of versions. | |
65 |
|
65 | |||
66 | vers can be a list or an iterator. |
|
66 | vers can be a list or an iterator. | |
67 |
|
67 | |||
68 | Produces a series of feature checks that have the form <name><vers> without |
|
68 | Produces a series of feature checks that have the form <name><vers> without | |
69 | any punctuation (even if there's punctuation in 'vers'; i.e. this produces |
|
69 | any punctuation (even if there's punctuation in 'vers'; i.e. this produces | |
70 | 'py38', not 'py3.8' or 'py-38').""" |
|
70 | 'py38', not 'py3.8' or 'py-38').""" | |
71 |
|
71 | |||
72 | def decorator(func): |
|
72 | def decorator(func): | |
73 | def funcv(v): |
|
73 | def funcv(v): | |
74 | def f(): |
|
74 | def f(): | |
75 | return func(v) |
|
75 | return func(v) | |
76 |
|
76 | |||
77 | return f |
|
77 | return f | |
78 |
|
78 | |||
79 | for v in vers: |
|
79 | for v in vers: | |
80 | v = str(v) |
|
80 | v = str(v) | |
81 | f = funcv(v) |
|
81 | f = funcv(v) | |
82 | checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v) |
|
82 | checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v) | |
83 | return func |
|
83 | return func | |
84 |
|
84 | |||
85 | return decorator |
|
85 | return decorator | |
86 |
|
86 | |||
87 |
|
87 | |||
88 | def checkfeatures(features): |
|
88 | def checkfeatures(features): | |
89 | result = { |
|
89 | result = { | |
90 | 'error': [], |
|
90 | 'error': [], | |
91 | 'missing': [], |
|
91 | 'missing': [], | |
92 | 'skipped': [], |
|
92 | 'skipped': [], | |
93 | } |
|
93 | } | |
94 |
|
94 | |||
95 | for feature in features: |
|
95 | for feature in features: | |
96 | negate = feature.startswith('no-') |
|
96 | negate = feature.startswith('no-') | |
97 | if negate: |
|
97 | if negate: | |
98 | feature = feature[3:] |
|
98 | feature = feature[3:] | |
99 |
|
99 | |||
100 | if feature not in checks: |
|
100 | if feature not in checks: | |
101 | result['missing'].append(feature) |
|
101 | result['missing'].append(feature) | |
102 | continue |
|
102 | continue | |
103 |
|
103 | |||
104 | check, desc = checks[feature] |
|
104 | check, desc = checks[feature] | |
105 | try: |
|
105 | try: | |
106 | available = check() |
|
106 | available = check() | |
107 | except Exception: |
|
107 | except Exception: | |
108 | result['error'].append('hghave check failed: %s' % feature) |
|
108 | result['error'].append('hghave check failed: %s' % feature) | |
109 | continue |
|
109 | continue | |
110 |
|
110 | |||
111 | if not negate and not available: |
|
111 | if not negate and not available: | |
112 | result['skipped'].append('missing feature: %s' % desc) |
|
112 | result['skipped'].append('missing feature: %s' % desc) | |
113 | elif negate and available: |
|
113 | elif negate and available: | |
114 | result['skipped'].append('system supports %s' % desc) |
|
114 | result['skipped'].append('system supports %s' % desc) | |
115 |
|
115 | |||
116 | return result |
|
116 | return result | |
117 |
|
117 | |||
118 |
|
118 | |||
119 | def require(features): |
|
119 | def require(features): | |
120 | """Require that features are available, exiting if not.""" |
|
120 | """Require that features are available, exiting if not.""" | |
121 | result = checkfeatures(features) |
|
121 | result = checkfeatures(features) | |
122 |
|
122 | |||
123 | for missing in result['missing']: |
|
123 | for missing in result['missing']: | |
124 | stderr.write( |
|
124 | stderr.write( | |
125 | ('skipped: unknown feature: %s\n' % missing).encode('utf-8') |
|
125 | ('skipped: unknown feature: %s\n' % missing).encode('utf-8') | |
126 | ) |
|
126 | ) | |
127 | for msg in result['skipped']: |
|
127 | for msg in result['skipped']: | |
128 | stderr.write(('skipped: %s\n' % msg).encode('utf-8')) |
|
128 | stderr.write(('skipped: %s\n' % msg).encode('utf-8')) | |
129 | for msg in result['error']: |
|
129 | for msg in result['error']: | |
130 | stderr.write(('%s\n' % msg).encode('utf-8')) |
|
130 | stderr.write(('%s\n' % msg).encode('utf-8')) | |
131 |
|
131 | |||
132 | if result['missing']: |
|
132 | if result['missing']: | |
133 | sys.exit(2) |
|
133 | sys.exit(2) | |
134 |
|
134 | |||
135 | if result['skipped'] or result['error']: |
|
135 | if result['skipped'] or result['error']: | |
136 | sys.exit(1) |
|
136 | sys.exit(1) | |
137 |
|
137 | |||
138 |
|
138 | |||
139 | def matchoutput(cmd, regexp, ignorestatus=False): |
|
139 | def matchoutput(cmd, regexp, ignorestatus=False): | |
140 | """Return the match object if cmd executes successfully and its output |
|
140 | """Return the match object if cmd executes successfully and its output | |
141 | is matched by the supplied regular expression. |
|
141 | is matched by the supplied regular expression. | |
142 | """ |
|
142 | """ | |
143 | r = re.compile(regexp) |
|
143 | r = re.compile(regexp) | |
144 | p = subprocess.Popen( |
|
144 | p = subprocess.Popen( | |
145 | cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT |
|
145 | cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT | |
146 | ) |
|
146 | ) | |
147 | s = p.communicate()[0] |
|
147 | s = p.communicate()[0] | |
148 | ret = p.returncode |
|
148 | ret = p.returncode | |
149 | return (ignorestatus or not ret) and r.search(s) |
|
149 | return (ignorestatus or not ret) and r.search(s) | |
150 |
|
150 | |||
151 |
|
151 | |||
152 | @check("baz", "GNU Arch baz client") |
|
152 | @check("baz", "GNU Arch baz client") | |
153 | def has_baz(): |
|
153 | def has_baz(): | |
154 | return matchoutput('baz --version 2>&1', br'baz Bazaar version') |
|
154 | return matchoutput('baz --version 2>&1', br'baz Bazaar version') | |
155 |
|
155 | |||
156 |
|
156 | |||
157 | @check("bzr", "Canonical's Bazaar client") |
|
157 | @check("bzr", "Canonical's Bazaar client") | |
158 | def has_bzr(): |
|
158 | def has_bzr(): | |
159 | try: |
|
159 | try: | |
160 | import bzrlib |
|
160 | import bzrlib | |
161 | import bzrlib.bzrdir |
|
161 | import bzrlib.bzrdir | |
162 | import bzrlib.errors |
|
162 | import bzrlib.errors | |
163 | import bzrlib.revision |
|
163 | import bzrlib.revision | |
164 | import bzrlib.revisionspec |
|
164 | import bzrlib.revisionspec | |
165 |
|
165 | |||
166 | bzrlib.revisionspec.RevisionSpec |
|
166 | bzrlib.revisionspec.RevisionSpec | |
167 | return bzrlib.__doc__ is not None |
|
167 | return bzrlib.__doc__ is not None | |
168 | except (AttributeError, ImportError): |
|
168 | except (AttributeError, ImportError): | |
169 | return False |
|
169 | return False | |
170 |
|
170 | |||
171 |
|
171 | |||
172 | @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,)) |
|
172 | @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,)) | |
173 | def has_bzr_range(v): |
|
173 | def has_bzr_range(v): | |
174 | major, minor = v.split('rc')[0].split('.')[0:2] |
|
174 | major, minor = v.split('rc')[0].split('.')[0:2] | |
175 | try: |
|
175 | try: | |
176 | import bzrlib |
|
176 | import bzrlib | |
177 |
|
177 | |||
178 | return bzrlib.__doc__ is not None and bzrlib.version_info[:2] >= ( |
|
178 | return bzrlib.__doc__ is not None and bzrlib.version_info[:2] >= ( | |
179 | int(major), |
|
179 | int(major), | |
180 | int(minor), |
|
180 | int(minor), | |
181 | ) |
|
181 | ) | |
182 | except ImportError: |
|
182 | except ImportError: | |
183 | return False |
|
183 | return False | |
184 |
|
184 | |||
185 |
|
185 | |||
186 | @check("chg", "running with chg") |
|
186 | @check("chg", "running with chg") | |
187 | def has_chg(): |
|
187 | def has_chg(): | |
188 | return 'CHGHG' in os.environ |
|
188 | return 'CHGHG' in os.environ | |
189 |
|
189 | |||
190 |
|
190 | |||
191 | @check("cvs", "cvs client/server") |
|
191 | @check("cvs", "cvs client/server") | |
192 | def has_cvs(): |
|
192 | def has_cvs(): | |
193 | re = br'Concurrent Versions System.*?server' |
|
193 | re = br'Concurrent Versions System.*?server' | |
194 | return matchoutput('cvs --version 2>&1', re) and not has_msys() |
|
194 | return matchoutput('cvs --version 2>&1', re) and not has_msys() | |
195 |
|
195 | |||
196 |
|
196 | |||
197 | @check("cvs112", "cvs client/server 1.12.* (not cvsnt)") |
|
197 | @check("cvs112", "cvs client/server 1.12.* (not cvsnt)") | |
198 | def has_cvs112(): |
|
198 | def has_cvs112(): | |
199 | re = br'Concurrent Versions System \(CVS\) 1.12.*?server' |
|
199 | re = br'Concurrent Versions System \(CVS\) 1.12.*?server' | |
200 | return matchoutput('cvs --version 2>&1', re) and not has_msys() |
|
200 | return matchoutput('cvs --version 2>&1', re) and not has_msys() | |
201 |
|
201 | |||
202 |
|
202 | |||
203 | @check("cvsnt", "cvsnt client/server") |
|
203 | @check("cvsnt", "cvsnt client/server") | |
204 | def has_cvsnt(): |
|
204 | def has_cvsnt(): | |
205 | re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)' |
|
205 | re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)' | |
206 | return matchoutput('cvsnt --version 2>&1', re) |
|
206 | return matchoutput('cvsnt --version 2>&1', re) | |
207 |
|
207 | |||
208 |
|
208 | |||
209 | @check("darcs", "darcs client") |
|
209 | @check("darcs", "darcs client") | |
210 | def has_darcs(): |
|
210 | def has_darcs(): | |
211 | return matchoutput('darcs --version', br'\b2\.([2-9]|\d{2})', True) |
|
211 | return matchoutput('darcs --version', br'\b2\.([2-9]|\d{2})', True) | |
212 |
|
212 | |||
213 |
|
213 | |||
214 | @check("mtn", "monotone client (>= 1.0)") |
|
214 | @check("mtn", "monotone client (>= 1.0)") | |
215 | def has_mtn(): |
|
215 | def has_mtn(): | |
216 | return matchoutput('mtn --version', br'monotone', True) and not matchoutput( |
|
216 | return matchoutput('mtn --version', br'monotone', True) and not matchoutput( | |
217 | 'mtn --version', br'monotone 0\.', True |
|
217 | 'mtn --version', br'monotone 0\.', True | |
218 | ) |
|
218 | ) | |
219 |
|
219 | |||
220 |
|
220 | |||
221 | @check("eol-in-paths", "end-of-lines in paths") |
|
221 | @check("eol-in-paths", "end-of-lines in paths") | |
222 | def has_eol_in_paths(): |
|
222 | def has_eol_in_paths(): | |
223 | try: |
|
223 | try: | |
224 | fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r') |
|
224 | fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r') | |
225 | os.close(fd) |
|
225 | os.close(fd) | |
226 | os.remove(path) |
|
226 | os.remove(path) | |
227 | return True |
|
227 | return True | |
228 | except (IOError, OSError): |
|
228 | except (IOError, OSError): | |
229 | return False |
|
229 | return False | |
230 |
|
230 | |||
231 |
|
231 | |||
232 | @check("execbit", "executable bit") |
|
232 | @check("execbit", "executable bit") | |
233 | def has_executablebit(): |
|
233 | def has_executablebit(): | |
234 | try: |
|
234 | try: | |
235 | EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH |
|
235 | EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH | |
236 | fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix) |
|
236 | fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix) | |
237 | try: |
|
237 | try: | |
238 | os.close(fh) |
|
238 | os.close(fh) | |
239 | m = os.stat(fn).st_mode & 0o777 |
|
239 | m = os.stat(fn).st_mode & 0o777 | |
240 | new_file_has_exec = m & EXECFLAGS |
|
240 | new_file_has_exec = m & EXECFLAGS | |
241 | os.chmod(fn, m ^ EXECFLAGS) |
|
241 | os.chmod(fn, m ^ EXECFLAGS) | |
242 | exec_flags_cannot_flip = (os.stat(fn).st_mode & 0o777) == m |
|
242 | exec_flags_cannot_flip = (os.stat(fn).st_mode & 0o777) == m | |
243 | finally: |
|
243 | finally: | |
244 | os.unlink(fn) |
|
244 | os.unlink(fn) | |
245 | except (IOError, OSError): |
|
245 | except (IOError, OSError): | |
246 | # we don't care, the user probably won't be able to commit anyway |
|
246 | # we don't care, the user probably won't be able to commit anyway | |
247 | return False |
|
247 | return False | |
248 | return not (new_file_has_exec or exec_flags_cannot_flip) |
|
248 | return not (new_file_has_exec or exec_flags_cannot_flip) | |
249 |
|
249 | |||
250 |
|
250 | |||
251 | @check("icasefs", "case insensitive file system") |
|
251 | @check("icasefs", "case insensitive file system") | |
252 | def has_icasefs(): |
|
252 | def has_icasefs(): | |
253 | # Stolen from mercurial.util |
|
253 | # Stolen from mercurial.util | |
254 | fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix) |
|
254 | fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix) | |
255 | os.close(fd) |
|
255 | os.close(fd) | |
256 | try: |
|
256 | try: | |
257 | s1 = os.stat(path) |
|
257 | s1 = os.stat(path) | |
258 | d, b = os.path.split(path) |
|
258 | d, b = os.path.split(path) | |
259 | p2 = os.path.join(d, b.upper()) |
|
259 | p2 = os.path.join(d, b.upper()) | |
260 | if path == p2: |
|
260 | if path == p2: | |
261 | p2 = os.path.join(d, b.lower()) |
|
261 | p2 = os.path.join(d, b.lower()) | |
262 | try: |
|
262 | try: | |
263 | s2 = os.stat(p2) |
|
263 | s2 = os.stat(p2) | |
264 | return s2 == s1 |
|
264 | return s2 == s1 | |
265 | except OSError: |
|
265 | except OSError: | |
266 | return False |
|
266 | return False | |
267 | finally: |
|
267 | finally: | |
268 | os.remove(path) |
|
268 | os.remove(path) | |
269 |
|
269 | |||
270 |
|
270 | |||
271 | @check("fifo", "named pipes") |
|
271 | @check("fifo", "named pipes") | |
272 | def has_fifo(): |
|
272 | def has_fifo(): | |
273 | if getattr(os, "mkfifo", None) is None: |
|
273 | if getattr(os, "mkfifo", None) is None: | |
274 | return False |
|
274 | return False | |
275 | name = tempfile.mktemp(dir='.', prefix=tempprefix) |
|
275 | name = tempfile.mktemp(dir='.', prefix=tempprefix) | |
276 | try: |
|
276 | try: | |
277 | os.mkfifo(name) |
|
277 | os.mkfifo(name) | |
278 | os.unlink(name) |
|
278 | os.unlink(name) | |
279 | return True |
|
279 | return True | |
280 | except OSError: |
|
280 | except OSError: | |
281 | return False |
|
281 | return False | |
282 |
|
282 | |||
283 |
|
283 | |||
284 | @check("killdaemons", 'killdaemons.py support') |
|
284 | @check("killdaemons", 'killdaemons.py support') | |
285 | def has_killdaemons(): |
|
285 | def has_killdaemons(): | |
286 | return True |
|
286 | return True | |
287 |
|
287 | |||
288 |
|
288 | |||
289 | @check("cacheable", "cacheable filesystem") |
|
289 | @check("cacheable", "cacheable filesystem") | |
290 | def has_cacheable_fs(): |
|
290 | def has_cacheable_fs(): | |
291 | from mercurial import util |
|
291 | from mercurial import util | |
292 |
|
292 | |||
293 | fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix) |
|
293 | fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix) | |
294 | os.close(fd) |
|
294 | os.close(fd) | |
295 | try: |
|
295 | try: | |
296 | return util.cachestat(path).cacheable() |
|
296 | return util.cachestat(path).cacheable() | |
297 | finally: |
|
297 | finally: | |
298 | os.remove(path) |
|
298 | os.remove(path) | |
299 |
|
299 | |||
300 |
|
300 | |||
301 | @check("lsprof", "python lsprof module") |
|
301 | @check("lsprof", "python lsprof module") | |
302 | def has_lsprof(): |
|
302 | def has_lsprof(): | |
303 | try: |
|
303 | try: | |
304 | import _lsprof |
|
304 | import _lsprof | |
305 |
|
305 | |||
306 | _lsprof.Profiler # silence unused import warning |
|
306 | _lsprof.Profiler # silence unused import warning | |
307 | return True |
|
307 | return True | |
308 | except ImportError: |
|
308 | except ImportError: | |
309 | return False |
|
309 | return False | |
310 |
|
310 | |||
311 |
|
311 | |||
312 | def _gethgversion(): |
|
312 | def _gethgversion(): | |
313 | m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)') |
|
313 | m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)') | |
314 | if not m: |
|
314 | if not m: | |
315 | return (0, 0) |
|
315 | return (0, 0) | |
316 | return (int(m.group(1)), int(m.group(2))) |
|
316 | return (int(m.group(1)), int(m.group(2))) | |
317 |
|
317 | |||
318 |
|
318 | |||
319 | _hgversion = None |
|
319 | _hgversion = None | |
320 |
|
320 | |||
321 |
|
321 | |||
322 | def gethgversion(): |
|
322 | def gethgversion(): | |
323 | global _hgversion |
|
323 | global _hgversion | |
324 | if _hgversion is None: |
|
324 | if _hgversion is None: | |
325 | _hgversion = _gethgversion() |
|
325 | _hgversion = _gethgversion() | |
326 | return _hgversion |
|
326 | return _hgversion | |
327 |
|
327 | |||
328 |
|
328 | |||
329 | @checkvers( |
|
329 | @checkvers( | |
330 | "hg", "Mercurial >= %s", list([(1.0 * x) / 10 for x in range(9, 99)]) |
|
330 | "hg", "Mercurial >= %s", list([(1.0 * x) / 10 for x in range(9, 99)]) | |
331 | ) |
|
331 | ) | |
332 | def has_hg_range(v): |
|
332 | def has_hg_range(v): | |
333 | major, minor = v.split('.')[0:2] |
|
333 | major, minor = v.split('.')[0:2] | |
334 | return gethgversion() >= (int(major), int(minor)) |
|
334 | return gethgversion() >= (int(major), int(minor)) | |
335 |
|
335 | |||
336 |
|
336 | |||
337 | @check("rust", "Using the Rust extensions") |
|
337 | @check("rust", "Using the Rust extensions") | |
338 | def has_rust(): |
|
338 | def has_rust(): | |
339 | """Check is the mercurial currently running is using some rust code""" |
|
339 | """Check is the mercurial currently running is using some rust code""" | |
340 | cmd = 'hg debuginstall --quiet 2>&1' |
|
340 | cmd = 'hg debuginstall --quiet 2>&1' | |
341 | match = br'checking module policy \(([^)]+)\)' |
|
341 | match = br'checking module policy \(([^)]+)\)' | |
342 | policy = matchoutput(cmd, match) |
|
342 | policy = matchoutput(cmd, match) | |
343 | if not policy: |
|
343 | if not policy: | |
344 | return False |
|
344 | return False | |
345 | return b'rust' in policy.group(1) |
|
345 | return b'rust' in policy.group(1) | |
346 |
|
346 | |||
347 |
|
347 | |||
348 | @check("hg08", "Mercurial >= 0.8") |
|
348 | @check("hg08", "Mercurial >= 0.8") | |
349 | def has_hg08(): |
|
349 | def has_hg08(): | |
350 | if checks["hg09"][0](): |
|
350 | if checks["hg09"][0](): | |
351 | return True |
|
351 | return True | |
352 | return matchoutput('hg help annotate 2>&1', '--date') |
|
352 | return matchoutput('hg help annotate 2>&1', '--date') | |
353 |
|
353 | |||
354 |
|
354 | |||
355 | @check("hg07", "Mercurial >= 0.7") |
|
355 | @check("hg07", "Mercurial >= 0.7") | |
356 | def has_hg07(): |
|
356 | def has_hg07(): | |
357 | if checks["hg08"][0](): |
|
357 | if checks["hg08"][0](): | |
358 | return True |
|
358 | return True | |
359 | return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM') |
|
359 | return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM') | |
360 |
|
360 | |||
361 |
|
361 | |||
362 | @check("hg06", "Mercurial >= 0.6") |
|
362 | @check("hg06", "Mercurial >= 0.6") | |
363 | def has_hg06(): |
|
363 | def has_hg06(): | |
364 | if checks["hg07"][0](): |
|
364 | if checks["hg07"][0](): | |
365 | return True |
|
365 | return True | |
366 | return matchoutput('hg --version --quiet 2>&1', 'Mercurial version') |
|
366 | return matchoutput('hg --version --quiet 2>&1', 'Mercurial version') | |
367 |
|
367 | |||
368 |
|
368 | |||
369 | @check("gettext", "GNU Gettext (msgfmt)") |
|
369 | @check("gettext", "GNU Gettext (msgfmt)") | |
370 | def has_gettext(): |
|
370 | def has_gettext(): | |
371 | return matchoutput('msgfmt --version', br'GNU gettext-tools') |
|
371 | return matchoutput('msgfmt --version', br'GNU gettext-tools') | |
372 |
|
372 | |||
373 |
|
373 | |||
374 | @check("git", "git command line client") |
|
374 | @check("git", "git command line client") | |
375 | def has_git(): |
|
375 | def has_git(): | |
376 | return matchoutput('git --version 2>&1', br'^git version') |
|
376 | return matchoutput('git --version 2>&1', br'^git version') | |
377 |
|
377 | |||
378 |
|
378 | |||
379 | def getgitversion(): |
|
379 | def getgitversion(): | |
380 | m = matchoutput('git --version 2>&1', br'git version (\d+)\.(\d+)') |
|
380 | m = matchoutput('git --version 2>&1', br'git version (\d+)\.(\d+)') | |
381 | if not m: |
|
381 | if not m: | |
382 | return (0, 0) |
|
382 | return (0, 0) | |
383 | return (int(m.group(1)), int(m.group(2))) |
|
383 | return (int(m.group(1)), int(m.group(2))) | |
384 |
|
384 | |||
385 |
|
385 | |||
386 | @check("pygit2", "pygit2 Python library") |
|
386 | @check("pygit2", "pygit2 Python library") | |
387 | def has_git(): |
|
387 | def has_git(): | |
388 | try: |
|
388 | try: | |
389 | import pygit2 |
|
389 | import pygit2 | |
390 |
|
390 | |||
391 | pygit2.Oid # silence unused import |
|
391 | pygit2.Oid # silence unused import | |
392 | return True |
|
392 | return True | |
393 | except ImportError: |
|
393 | except ImportError: | |
394 | return False |
|
394 | return False | |
395 |
|
395 | |||
396 |
|
396 | |||
397 | # https://github.com/git-lfs/lfs-test-server |
|
397 | # https://github.com/git-lfs/lfs-test-server | |
398 | @check("lfs-test-server", "git-lfs test server") |
|
398 | @check("lfs-test-server", "git-lfs test server") | |
399 | def has_lfsserver(): |
|
399 | def has_lfsserver(): | |
400 | exe = 'lfs-test-server' |
|
400 | exe = 'lfs-test-server' | |
401 | if has_windows(): |
|
401 | if has_windows(): | |
402 | exe = 'lfs-test-server.exe' |
|
402 | exe = 'lfs-test-server.exe' | |
403 | return any( |
|
403 | return any( | |
404 | os.access(os.path.join(path, exe), os.X_OK) |
|
404 | os.access(os.path.join(path, exe), os.X_OK) | |
405 | for path in os.environ["PATH"].split(os.pathsep) |
|
405 | for path in os.environ["PATH"].split(os.pathsep) | |
406 | ) |
|
406 | ) | |
407 |
|
407 | |||
408 |
|
408 | |||
409 | @checkvers("git", "git client (with ext::sh support) version >= %s", (1.9,)) |
|
409 | @checkvers("git", "git client (with ext::sh support) version >= %s", (1.9,)) | |
410 | def has_git_range(v): |
|
410 | def has_git_range(v): | |
411 | major, minor = v.split('.')[0:2] |
|
411 | major, minor = v.split('.')[0:2] | |
412 | return getgitversion() >= (int(major), int(minor)) |
|
412 | return getgitversion() >= (int(major), int(minor)) | |
413 |
|
413 | |||
414 |
|
414 | |||
415 | @check("docutils", "Docutils text processing library") |
|
415 | @check("docutils", "Docutils text processing library") | |
416 | def has_docutils(): |
|
416 | def has_docutils(): | |
417 | try: |
|
417 | try: | |
418 | import docutils.core |
|
418 | import docutils.core | |
419 |
|
419 | |||
420 | docutils.core.publish_cmdline # silence unused import |
|
420 | docutils.core.publish_cmdline # silence unused import | |
421 | return True |
|
421 | return True | |
422 | except ImportError: |
|
422 | except ImportError: | |
423 | return False |
|
423 | return False | |
424 |
|
424 | |||
425 |
|
425 | |||
426 | def getsvnversion(): |
|
426 | def getsvnversion(): | |
427 | m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)') |
|
427 | m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)') | |
428 | if not m: |
|
428 | if not m: | |
429 | return (0, 0) |
|
429 | return (0, 0) | |
430 | return (int(m.group(1)), int(m.group(2))) |
|
430 | return (int(m.group(1)), int(m.group(2))) | |
431 |
|
431 | |||
432 |
|
432 | |||
433 | @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5)) |
|
433 | @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5)) | |
434 | def has_svn_range(v): |
|
434 | def has_svn_range(v): | |
435 | major, minor = v.split('.')[0:2] |
|
435 | major, minor = v.split('.')[0:2] | |
436 | return getsvnversion() >= (int(major), int(minor)) |
|
436 | return getsvnversion() >= (int(major), int(minor)) | |
437 |
|
437 | |||
438 |
|
438 | |||
439 | @check("svn", "subversion client and admin tools") |
|
439 | @check("svn", "subversion client and admin tools") | |
440 | def has_svn(): |
|
440 | def has_svn(): | |
441 | return matchoutput('svn --version 2>&1', br'^svn, version') and matchoutput( |
|
441 | return matchoutput('svn --version 2>&1', br'^svn, version') and matchoutput( | |
442 | 'svnadmin --version 2>&1', br'^svnadmin, version' |
|
442 | 'svnadmin --version 2>&1', br'^svnadmin, version' | |
443 | ) |
|
443 | ) | |
444 |
|
444 | |||
445 |
|
445 | |||
446 | @check("svn-bindings", "subversion python bindings") |
|
446 | @check("svn-bindings", "subversion python bindings") | |
447 | def has_svn_bindings(): |
|
447 | def has_svn_bindings(): | |
448 | try: |
|
448 | try: | |
449 | import svn.core |
|
449 | import svn.core | |
450 |
|
450 | |||
451 | version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR |
|
451 | version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR | |
452 | if version < (1, 4): |
|
452 | if version < (1, 4): | |
453 | return False |
|
453 | return False | |
454 | return True |
|
454 | return True | |
455 | except ImportError: |
|
455 | except ImportError: | |
456 | return False |
|
456 | return False | |
457 |
|
457 | |||
458 |
|
458 | |||
459 | @check("p4", "Perforce server and client") |
|
459 | @check("p4", "Perforce server and client") | |
460 | def has_p4(): |
|
460 | def has_p4(): | |
461 | return matchoutput('p4 -V', br'Rev\. P4/') and matchoutput( |
|
461 | return matchoutput('p4 -V', br'Rev\. P4/') and matchoutput( | |
462 | 'p4d -V', br'Rev\. P4D/' |
|
462 | 'p4d -V', br'Rev\. P4D/' | |
463 | ) |
|
463 | ) | |
464 |
|
464 | |||
465 |
|
465 | |||
466 | @check("symlink", "symbolic links") |
|
466 | @check("symlink", "symbolic links") | |
467 | def has_symlink(): |
|
467 | def has_symlink(): | |
468 | # mercurial.windows.checklink() is a hard 'no' at the moment |
|
468 | # mercurial.windows.checklink() is a hard 'no' at the moment | |
469 | if os.name == 'nt' or getattr(os, "symlink", None) is None: |
|
469 | if os.name == 'nt' or getattr(os, "symlink", None) is None: | |
470 | return False |
|
470 | return False | |
471 | name = tempfile.mktemp(dir='.', prefix=tempprefix) |
|
471 | name = tempfile.mktemp(dir='.', prefix=tempprefix) | |
472 | try: |
|
472 | try: | |
473 | os.symlink(".", name) |
|
473 | os.symlink(".", name) | |
474 | os.unlink(name) |
|
474 | os.unlink(name) | |
475 | return True |
|
475 | return True | |
476 | except (OSError, AttributeError): |
|
476 | except (OSError, AttributeError): | |
477 | return False |
|
477 | return False | |
478 |
|
478 | |||
479 |
|
479 | |||
480 | @check("hardlink", "hardlinks") |
|
480 | @check("hardlink", "hardlinks") | |
481 | def has_hardlink(): |
|
481 | def has_hardlink(): | |
482 | from mercurial import util |
|
482 | from mercurial import util | |
483 |
|
483 | |||
484 | fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix) |
|
484 | fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix) | |
485 | os.close(fh) |
|
485 | os.close(fh) | |
486 | name = tempfile.mktemp(dir='.', prefix=tempprefix) |
|
486 | name = tempfile.mktemp(dir='.', prefix=tempprefix) | |
487 | try: |
|
487 | try: | |
488 | util.oslink(_sys2bytes(fn), _sys2bytes(name)) |
|
488 | util.oslink(_sys2bytes(fn), _sys2bytes(name)) | |
489 | os.unlink(name) |
|
489 | os.unlink(name) | |
490 | return True |
|
490 | return True | |
491 | except OSError: |
|
491 | except OSError: | |
492 | return False |
|
492 | return False | |
493 | finally: |
|
493 | finally: | |
494 | os.unlink(fn) |
|
494 | os.unlink(fn) | |
495 |
|
495 | |||
496 |
|
496 | |||
497 | @check("hardlink-whitelisted", "hardlinks on whitelisted filesystems") |
|
497 | @check("hardlink-whitelisted", "hardlinks on whitelisted filesystems") | |
498 | def has_hardlink_whitelisted(): |
|
498 | def has_hardlink_whitelisted(): | |
499 | from mercurial import util |
|
499 | from mercurial import util | |
500 |
|
500 | |||
501 | try: |
|
501 | try: | |
502 | fstype = util.getfstype(b'.') |
|
502 | fstype = util.getfstype(b'.') | |
503 | except OSError: |
|
503 | except OSError: | |
504 | return False |
|
504 | return False | |
505 | return fstype in util._hardlinkfswhitelist |
|
505 | return fstype in util._hardlinkfswhitelist | |
506 |
|
506 | |||
507 |
|
507 | |||
508 | @check("rmcwd", "can remove current working directory") |
|
508 | @check("rmcwd", "can remove current working directory") | |
509 | def has_rmcwd(): |
|
509 | def has_rmcwd(): | |
510 | ocwd = os.getcwd() |
|
510 | ocwd = os.getcwd() | |
511 | temp = tempfile.mkdtemp(dir='.', prefix=tempprefix) |
|
511 | temp = tempfile.mkdtemp(dir='.', prefix=tempprefix) | |
512 | try: |
|
512 | try: | |
513 | os.chdir(temp) |
|
513 | os.chdir(temp) | |
514 | # On Linux, 'rmdir .' isn't allowed, but the other names are okay. |
|
514 | # On Linux, 'rmdir .' isn't allowed, but the other names are okay. | |
515 | # On Solaris and Windows, the cwd can't be removed by any names. |
|
515 | # On Solaris and Windows, the cwd can't be removed by any names. | |
516 | os.rmdir(os.getcwd()) |
|
516 | os.rmdir(os.getcwd()) | |
517 | return True |
|
517 | return True | |
518 | except OSError: |
|
518 | except OSError: | |
519 | return False |
|
519 | return False | |
520 | finally: |
|
520 | finally: | |
521 | os.chdir(ocwd) |
|
521 | os.chdir(ocwd) | |
522 | # clean up temp dir on platforms where cwd can't be removed |
|
522 | # clean up temp dir on platforms where cwd can't be removed | |
523 | try: |
|
523 | try: | |
524 | os.rmdir(temp) |
|
524 | os.rmdir(temp) | |
525 | except OSError: |
|
525 | except OSError: | |
526 | pass |
|
526 | pass | |
527 |
|
527 | |||
528 |
|
528 | |||
529 | @check("tla", "GNU Arch tla client") |
|
529 | @check("tla", "GNU Arch tla client") | |
530 | def has_tla(): |
|
530 | def has_tla(): | |
531 | return matchoutput('tla --version 2>&1', br'The GNU Arch Revision') |
|
531 | return matchoutput('tla --version 2>&1', br'The GNU Arch Revision') | |
532 |
|
532 | |||
533 |
|
533 | |||
534 | @check("gpg", "gpg client") |
|
534 | @check("gpg", "gpg client") | |
535 | def has_gpg(): |
|
535 | def has_gpg(): | |
536 | return matchoutput('gpg --version 2>&1', br'GnuPG') |
|
536 | return matchoutput('gpg --version 2>&1', br'GnuPG') | |
537 |
|
537 | |||
538 |
|
538 | |||
539 | @check("gpg2", "gpg client v2") |
|
539 | @check("gpg2", "gpg client v2") | |
540 | def has_gpg2(): |
|
540 | def has_gpg2(): | |
541 | return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.') |
|
541 | return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.') | |
542 |
|
542 | |||
543 |
|
543 | |||
544 | @check("gpg21", "gpg client v2.1+") |
|
544 | @check("gpg21", "gpg client v2.1+") | |
545 | def has_gpg21(): |
|
545 | def has_gpg21(): | |
546 | return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.(?!0)') |
|
546 | return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.(?!0)') | |
547 |
|
547 | |||
548 |
|
548 | |||
549 | @check("unix-permissions", "unix-style permissions") |
|
549 | @check("unix-permissions", "unix-style permissions") | |
550 | def has_unix_permissions(): |
|
550 | def has_unix_permissions(): | |
551 | d = tempfile.mkdtemp(dir='.', prefix=tempprefix) |
|
551 | d = tempfile.mkdtemp(dir='.', prefix=tempprefix) | |
552 | try: |
|
552 | try: | |
553 | fname = os.path.join(d, 'foo') |
|
553 | fname = os.path.join(d, 'foo') | |
554 | for umask in (0o77, 0o07, 0o22): |
|
554 | for umask in (0o77, 0o07, 0o22): | |
555 | os.umask(umask) |
|
555 | os.umask(umask) | |
556 | f = open(fname, 'w') |
|
556 | f = open(fname, 'w') | |
557 | f.close() |
|
557 | f.close() | |
558 | mode = os.stat(fname).st_mode |
|
558 | mode = os.stat(fname).st_mode | |
559 | os.unlink(fname) |
|
559 | os.unlink(fname) | |
560 | if mode & 0o777 != ~umask & 0o666: |
|
560 | if mode & 0o777 != ~umask & 0o666: | |
561 | return False |
|
561 | return False | |
562 | return True |
|
562 | return True | |
563 | finally: |
|
563 | finally: | |
564 | os.rmdir(d) |
|
564 | os.rmdir(d) | |
565 |
|
565 | |||
566 |
|
566 | |||
567 | @check("unix-socket", "AF_UNIX socket family") |
|
567 | @check("unix-socket", "AF_UNIX socket family") | |
568 | def has_unix_socket(): |
|
568 | def has_unix_socket(): | |
569 | return getattr(socket, 'AF_UNIX', None) is not None |
|
569 | return getattr(socket, 'AF_UNIX', None) is not None | |
570 |
|
570 | |||
571 |
|
571 | |||
572 | @check("root", "root permissions") |
|
572 | @check("root", "root permissions") | |
573 | def has_root(): |
|
573 | def has_root(): | |
574 | return getattr(os, 'geteuid', None) and os.geteuid() == 0 |
|
574 | return getattr(os, 'geteuid', None) and os.geteuid() == 0 | |
575 |
|
575 | |||
576 |
|
576 | |||
577 | @check("pyflakes", "Pyflakes python linter") |
|
577 | @check("pyflakes", "Pyflakes python linter") | |
578 | def has_pyflakes(): |
|
578 | def has_pyflakes(): | |
579 | try: |
|
579 | try: | |
580 | import pyflakes |
|
580 | import pyflakes | |
581 |
|
581 | |||
582 | pyflakes.__version__ |
|
582 | pyflakes.__version__ | |
583 | except ImportError: |
|
583 | except ImportError: | |
584 | return False |
|
584 | return False | |
585 | else: |
|
585 | else: | |
586 | return True |
|
586 | return True | |
587 |
|
587 | |||
588 |
|
588 | |||
589 | @check("pylint", "Pylint python linter") |
|
589 | @check("pylint", "Pylint python linter") | |
590 | def has_pylint(): |
|
590 | def has_pylint(): | |
591 | return matchoutput("pylint --help", br"Usage:[ ]+pylint", True) |
|
591 | return matchoutput("pylint --help", br"Usage:[ ]+pylint", True) | |
592 |
|
592 | |||
593 |
|
593 | |||
594 | @check("clang-format", "clang-format C code formatter (>= 11)") |
|
594 | @check("clang-format", "clang-format C code formatter (>= 11)") | |
595 | def has_clang_format(): |
|
595 | def has_clang_format(): | |
596 | m = matchoutput('clang-format --version', br'clang-format version (\d+)') |
|
596 | m = matchoutput('clang-format --version', br'clang-format version (\d+)') | |
597 | # style changed somewhere between 10.x and 11.x |
|
597 | # style changed somewhere between 10.x and 11.x | |
598 | return m and int(m.group(1)) >= 11 |
|
598 | return m and int(m.group(1)) >= 11 | |
599 |
|
599 | |||
600 |
|
600 | |||
601 | @check("jshint", "JSHint static code analysis tool") |
|
601 | @check("jshint", "JSHint static code analysis tool") | |
602 | def has_jshint(): |
|
602 | def has_jshint(): | |
603 | return matchoutput("jshint --version 2>&1", br"jshint v") |
|
603 | return matchoutput("jshint --version 2>&1", br"jshint v") | |
604 |
|
604 | |||
605 |
|
605 | |||
606 | @check("pygments", "Pygments source highlighting library") |
|
606 | @check("pygments", "Pygments source highlighting library") | |
607 | def has_pygments(): |
|
607 | def has_pygments(): | |
608 | try: |
|
608 | try: | |
609 | import pygments |
|
609 | import pygments | |
610 |
|
610 | |||
611 | pygments.highlight # silence unused import warning |
|
611 | pygments.highlight # silence unused import warning | |
612 | return True |
|
612 | return True | |
613 | except ImportError: |
|
613 | except ImportError: | |
614 | return False |
|
614 | return False | |
615 |
|
615 | |||
616 |
|
616 | |||
617 | @check("pygments25", "Pygments version >= 2.5") |
|
617 | @check("pygments25", "Pygments version >= 2.5") | |
618 | def pygments25(): |
|
618 | def pygments25(): | |
619 | try: |
|
619 | try: | |
620 | import pygments |
|
620 | import pygments | |
621 |
|
621 | |||
622 | v = pygments.__version__ |
|
622 | v = pygments.__version__ | |
623 | except ImportError: |
|
623 | except ImportError: | |
624 | return False |
|
624 | return False | |
625 |
|
625 | |||
626 | parts = v.split(".") |
|
626 | parts = v.split(".") | |
627 | major = int(parts[0]) |
|
627 | major = int(parts[0]) | |
628 | minor = int(parts[1]) |
|
628 | minor = int(parts[1]) | |
629 |
|
629 | |||
630 | return (major, minor) >= (2, 5) |
|
630 | return (major, minor) >= (2, 5) | |
631 |
|
631 | |||
632 |
|
632 | |||
633 | @check("outer-repo", "outer repo") |
|
633 | @check("outer-repo", "outer repo") | |
634 | def has_outer_repo(): |
|
634 | def has_outer_repo(): | |
635 | # failing for other reasons than 'no repo' imply that there is a repo |
|
635 | # failing for other reasons than 'no repo' imply that there is a repo | |
636 | return not matchoutput('hg root 2>&1', br'abort: no repository found', True) |
|
636 | return not matchoutput('hg root 2>&1', br'abort: no repository found', True) | |
637 |
|
637 | |||
638 |
|
638 | |||
639 | @check("ssl", "ssl module available") |
|
639 | @check("ssl", "ssl module available") | |
640 | def has_ssl(): |
|
640 | def has_ssl(): | |
641 | try: |
|
641 | try: | |
642 | import ssl |
|
642 | import ssl | |
643 |
|
643 | |||
644 | ssl.CERT_NONE |
|
644 | ssl.CERT_NONE | |
645 | return True |
|
645 | return True | |
646 | except ImportError: |
|
646 | except ImportError: | |
647 | return False |
|
647 | return False | |
648 |
|
648 | |||
649 |
|
649 | |||
650 | @check("defaultcacertsloaded", "detected presence of loaded system CA certs") |
|
650 | @check("defaultcacertsloaded", "detected presence of loaded system CA certs") | |
651 | def has_defaultcacertsloaded(): |
|
651 | def has_defaultcacertsloaded(): | |
652 | import ssl |
|
652 | import ssl | |
653 | from mercurial import sslutil, ui as uimod |
|
653 | from mercurial import sslutil, ui as uimod | |
654 |
|
654 | |||
655 | ui = uimod.ui.load() |
|
655 | ui = uimod.ui.load() | |
656 | cafile = sslutil._defaultcacerts(ui) |
|
656 | cafile = sslutil._defaultcacerts(ui) | |
657 | ctx = ssl.create_default_context() |
|
657 | ctx = ssl.create_default_context() | |
658 | if cafile: |
|
658 | if cafile: | |
659 | ctx.load_verify_locations(cafile=cafile) |
|
659 | ctx.load_verify_locations(cafile=cafile) | |
660 | else: |
|
660 | else: | |
661 | ctx.load_default_certs() |
|
661 | ctx.load_default_certs() | |
662 |
|
662 | |||
663 | return len(ctx.get_ca_certs()) > 0 |
|
663 | return len(ctx.get_ca_certs()) > 0 | |
664 |
|
664 | |||
665 |
|
665 | |||
666 | @check("tls1.2", "TLS 1.2 protocol support") |
|
666 | @check("tls1.2", "TLS 1.2 protocol support") | |
667 | def has_tls1_2(): |
|
667 | def has_tls1_2(): | |
668 | from mercurial import sslutil |
|
668 | from mercurial import sslutil | |
669 |
|
669 | |||
670 | return b'tls1.2' in sslutil.supportedprotocols |
|
670 | return b'tls1.2' in sslutil.supportedprotocols | |
671 |
|
671 | |||
672 |
|
672 | |||
673 | @check("windows", "Windows") |
|
673 | @check("windows", "Windows") | |
674 | def has_windows(): |
|
674 | def has_windows(): | |
675 | return os.name == 'nt' |
|
675 | return os.name == 'nt' | |
676 |
|
676 | |||
677 |
|
677 | |||
678 | @check("system-sh", "system() uses sh") |
|
678 | @check("system-sh", "system() uses sh") | |
679 | def has_system_sh(): |
|
679 | def has_system_sh(): | |
680 | return os.name != 'nt' |
|
680 | return os.name != 'nt' | |
681 |
|
681 | |||
682 |
|
682 | |||
683 | @check("serve", "platform and python can manage 'hg serve -d'") |
|
683 | @check("serve", "platform and python can manage 'hg serve -d'") | |
684 | def has_serve(): |
|
684 | def has_serve(): | |
685 | return True |
|
685 | return True | |
686 |
|
686 | |||
687 |
|
687 | |||
688 | @check("setprocname", "whether osutil.setprocname is available or not") |
|
688 | @check("setprocname", "whether osutil.setprocname is available or not") | |
689 | def has_setprocname(): |
|
689 | def has_setprocname(): | |
690 | try: |
|
690 | try: | |
691 | from mercurial.utils import procutil |
|
691 | from mercurial.utils import procutil | |
692 |
|
692 | |||
693 | procutil.setprocname |
|
693 | procutil.setprocname | |
694 | return True |
|
694 | return True | |
695 | except AttributeError: |
|
695 | except AttributeError: | |
696 | return False |
|
696 | return False | |
697 |
|
697 | |||
698 |
|
698 | |||
699 | @check("test-repo", "running tests from repository") |
|
699 | @check("test-repo", "running tests from repository") | |
700 | def has_test_repo(): |
|
700 | def has_test_repo(): | |
701 | t = os.environ["TESTDIR"] |
|
701 | t = os.environ["TESTDIR"] | |
702 | return os.path.isdir(os.path.join(t, "..", ".hg")) |
|
702 | return os.path.isdir(os.path.join(t, "..", ".hg")) | |
703 |
|
703 | |||
704 |
|
704 | |||
|
705 | @check("network-io", "whether tests are allowed to access 3rd party services") | |||
|
706 | def has_test_repo(): | |||
|
707 | t = os.environ.get("HGTESTS_ALLOW_NETIO") | |||
|
708 | return t == "1" | |||
|
709 | ||||
|
710 | ||||
705 | @check("curses", "terminfo compiler and curses module") |
|
711 | @check("curses", "terminfo compiler and curses module") | |
706 | def has_curses(): |
|
712 | def has_curses(): | |
707 | try: |
|
713 | try: | |
708 | import curses |
|
714 | import curses | |
709 |
|
715 | |||
710 | curses.COLOR_BLUE |
|
716 | curses.COLOR_BLUE | |
711 |
|
717 | |||
712 | # Windows doesn't have a `tic` executable, but the windows_curses |
|
718 | # Windows doesn't have a `tic` executable, but the windows_curses | |
713 | # package is sufficient to run the tests without it. |
|
719 | # package is sufficient to run the tests without it. | |
714 | if os.name == 'nt': |
|
720 | if os.name == 'nt': | |
715 | return True |
|
721 | return True | |
716 |
|
722 | |||
717 | return has_tic() |
|
723 | return has_tic() | |
718 |
|
724 | |||
719 | except (ImportError, AttributeError): |
|
725 | except (ImportError, AttributeError): | |
720 | return False |
|
726 | return False | |
721 |
|
727 | |||
722 |
|
728 | |||
723 | @check("tic", "terminfo compiler") |
|
729 | @check("tic", "terminfo compiler") | |
724 | def has_tic(): |
|
730 | def has_tic(): | |
725 | return matchoutput('test -x "`which tic`"', br'') |
|
731 | return matchoutput('test -x "`which tic`"', br'') | |
726 |
|
732 | |||
727 |
|
733 | |||
728 | @check("xz", "xz compression utility") |
|
734 | @check("xz", "xz compression utility") | |
729 | def has_xz(): |
|
735 | def has_xz(): | |
730 | # When Windows invokes a subprocess in shell mode, it uses `cmd.exe`, which |
|
736 | # When Windows invokes a subprocess in shell mode, it uses `cmd.exe`, which | |
731 | # only knows `where`, not `which`. So invoke MSYS shell explicitly. |
|
737 | # only knows `where`, not `which`. So invoke MSYS shell explicitly. | |
732 | return matchoutput("sh -c 'test -x \"`which xz`\"'", b'') |
|
738 | return matchoutput("sh -c 'test -x \"`which xz`\"'", b'') | |
733 |
|
739 | |||
734 |
|
740 | |||
735 | @check("msys", "Windows with MSYS") |
|
741 | @check("msys", "Windows with MSYS") | |
736 | def has_msys(): |
|
742 | def has_msys(): | |
737 | return os.getenv('MSYSTEM') |
|
743 | return os.getenv('MSYSTEM') | |
738 |
|
744 | |||
739 |
|
745 | |||
740 | @check("aix", "AIX") |
|
746 | @check("aix", "AIX") | |
741 | def has_aix(): |
|
747 | def has_aix(): | |
742 | return sys.platform.startswith("aix") |
|
748 | return sys.platform.startswith("aix") | |
743 |
|
749 | |||
744 |
|
750 | |||
745 | @check("osx", "OS X") |
|
751 | @check("osx", "OS X") | |
746 | def has_osx(): |
|
752 | def has_osx(): | |
747 | return sys.platform == 'darwin' |
|
753 | return sys.platform == 'darwin' | |
748 |
|
754 | |||
749 |
|
755 | |||
750 | @check("osxpackaging", "OS X packaging tools") |
|
756 | @check("osxpackaging", "OS X packaging tools") | |
751 | def has_osxpackaging(): |
|
757 | def has_osxpackaging(): | |
752 | try: |
|
758 | try: | |
753 | return ( |
|
759 | return ( | |
754 | matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1) |
|
760 | matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1) | |
755 | and matchoutput( |
|
761 | and matchoutput( | |
756 | 'productbuild', br'Usage: productbuild ', ignorestatus=1 |
|
762 | 'productbuild', br'Usage: productbuild ', ignorestatus=1 | |
757 | ) |
|
763 | ) | |
758 | and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1) |
|
764 | and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1) | |
759 | and matchoutput('xar --help', br'Usage: xar', ignorestatus=1) |
|
765 | and matchoutput('xar --help', br'Usage: xar', ignorestatus=1) | |
760 | ) |
|
766 | ) | |
761 | except ImportError: |
|
767 | except ImportError: | |
762 | return False |
|
768 | return False | |
763 |
|
769 | |||
764 |
|
770 | |||
765 | @check('linuxormacos', 'Linux or MacOS') |
|
771 | @check('linuxormacos', 'Linux or MacOS') | |
766 | def has_linuxormacos(): |
|
772 | def has_linuxormacos(): | |
767 | # This isn't a perfect test for MacOS. But it is sufficient for our needs. |
|
773 | # This isn't a perfect test for MacOS. But it is sufficient for our needs. | |
768 | return sys.platform.startswith(('linux', 'darwin')) |
|
774 | return sys.platform.startswith(('linux', 'darwin')) | |
769 |
|
775 | |||
770 |
|
776 | |||
771 | @check("docker", "docker support") |
|
777 | @check("docker", "docker support") | |
772 | def has_docker(): |
|
778 | def has_docker(): | |
773 | pat = br'A self-sufficient runtime for' |
|
779 | pat = br'A self-sufficient runtime for' | |
774 | if matchoutput('docker --help', pat): |
|
780 | if matchoutput('docker --help', pat): | |
775 | if 'linux' not in sys.platform: |
|
781 | if 'linux' not in sys.platform: | |
776 | # TODO: in theory we should be able to test docker-based |
|
782 | # TODO: in theory we should be able to test docker-based | |
777 | # package creation on non-linux using boot2docker, but in |
|
783 | # package creation on non-linux using boot2docker, but in | |
778 | # practice that requires extra coordination to make sure |
|
784 | # practice that requires extra coordination to make sure | |
779 | # $TESTTEMP is going to be visible at the same path to the |
|
785 | # $TESTTEMP is going to be visible at the same path to the | |
780 | # boot2docker VM. If we figure out how to verify that, we |
|
786 | # boot2docker VM. If we figure out how to verify that, we | |
781 | # can use the following instead of just saying False: |
|
787 | # can use the following instead of just saying False: | |
782 | # return 'DOCKER_HOST' in os.environ |
|
788 | # return 'DOCKER_HOST' in os.environ | |
783 | return False |
|
789 | return False | |
784 |
|
790 | |||
785 | return True |
|
791 | return True | |
786 | return False |
|
792 | return False | |
787 |
|
793 | |||
788 |
|
794 | |||
789 | @check("debhelper", "debian packaging tools") |
|
795 | @check("debhelper", "debian packaging tools") | |
790 | def has_debhelper(): |
|
796 | def has_debhelper(): | |
791 | # Some versions of dpkg say `dpkg', some say 'dpkg' (` vs ' on the first |
|
797 | # Some versions of dpkg say `dpkg', some say 'dpkg' (` vs ' on the first | |
792 | # quote), so just accept anything in that spot. |
|
798 | # quote), so just accept anything in that spot. | |
793 | dpkg = matchoutput( |
|
799 | dpkg = matchoutput( | |
794 | 'dpkg --version', br"Debian .dpkg' package management program" |
|
800 | 'dpkg --version', br"Debian .dpkg' package management program" | |
795 | ) |
|
801 | ) | |
796 | dh = matchoutput( |
|
802 | dh = matchoutput( | |
797 | 'dh --help', br'dh is a part of debhelper.', ignorestatus=True |
|
803 | 'dh --help', br'dh is a part of debhelper.', ignorestatus=True | |
798 | ) |
|
804 | ) | |
799 | dh_py2 = matchoutput( |
|
805 | dh_py2 = matchoutput( | |
800 | 'dh_python2 --help', br'other supported Python versions' |
|
806 | 'dh_python2 --help', br'other supported Python versions' | |
801 | ) |
|
807 | ) | |
802 | # debuild comes from the 'devscripts' package, though you might want |
|
808 | # debuild comes from the 'devscripts' package, though you might want | |
803 | # the 'build-debs' package instead, which has a dependency on devscripts. |
|
809 | # the 'build-debs' package instead, which has a dependency on devscripts. | |
804 | debuild = matchoutput( |
|
810 | debuild = matchoutput( | |
805 | 'debuild --help', br'to run debian/rules with given parameter' |
|
811 | 'debuild --help', br'to run debian/rules with given parameter' | |
806 | ) |
|
812 | ) | |
807 | return dpkg and dh and dh_py2 and debuild |
|
813 | return dpkg and dh and dh_py2 and debuild | |
808 |
|
814 | |||
809 |
|
815 | |||
810 | @check( |
|
816 | @check( | |
811 | "debdeps", "debian build dependencies (run dpkg-checkbuilddeps in contrib/)" |
|
817 | "debdeps", "debian build dependencies (run dpkg-checkbuilddeps in contrib/)" | |
812 | ) |
|
818 | ) | |
813 | def has_debdeps(): |
|
819 | def has_debdeps(): | |
814 | # just check exit status (ignoring output) |
|
820 | # just check exit status (ignoring output) | |
815 | path = '%s/../contrib/packaging/debian/control' % os.environ['TESTDIR'] |
|
821 | path = '%s/../contrib/packaging/debian/control' % os.environ['TESTDIR'] | |
816 | return matchoutput('dpkg-checkbuilddeps %s' % path, br'') |
|
822 | return matchoutput('dpkg-checkbuilddeps %s' % path, br'') | |
817 |
|
823 | |||
818 |
|
824 | |||
819 | @check("demandimport", "demandimport enabled") |
|
825 | @check("demandimport", "demandimport enabled") | |
820 | def has_demandimport(): |
|
826 | def has_demandimport(): | |
821 | # chg disables demandimport intentionally for performance wins. |
|
827 | # chg disables demandimport intentionally for performance wins. | |
822 | return (not has_chg()) and os.environ.get('HGDEMANDIMPORT') != 'disable' |
|
828 | return (not has_chg()) and os.environ.get('HGDEMANDIMPORT') != 'disable' | |
823 |
|
829 | |||
824 |
|
830 | |||
825 | # Add "py27", "py35", ... as possible feature checks. Note that there's no |
|
831 | # Add "py27", "py35", ... as possible feature checks. Note that there's no | |
826 | # punctuation here. |
|
832 | # punctuation here. | |
827 | @checkvers("py", "Python >= %s", (2.7, 3.5, 3.6, 3.7, 3.8, 3.9)) |
|
833 | @checkvers("py", "Python >= %s", (2.7, 3.5, 3.6, 3.7, 3.8, 3.9)) | |
828 | def has_python_range(v): |
|
834 | def has_python_range(v): | |
829 | major, minor = v.split('.')[0:2] |
|
835 | major, minor = v.split('.')[0:2] | |
830 | py_major, py_minor = sys.version_info.major, sys.version_info.minor |
|
836 | py_major, py_minor = sys.version_info.major, sys.version_info.minor | |
831 |
|
837 | |||
832 | return (py_major, py_minor) >= (int(major), int(minor)) |
|
838 | return (py_major, py_minor) >= (int(major), int(minor)) | |
833 |
|
839 | |||
834 |
|
840 | |||
835 | @check("py3", "running with Python 3.x") |
|
841 | @check("py3", "running with Python 3.x") | |
836 | def has_py3(): |
|
842 | def has_py3(): | |
837 | return 3 == sys.version_info[0] |
|
843 | return 3 == sys.version_info[0] | |
838 |
|
844 | |||
839 |
|
845 | |||
840 | @check("py3exe", "a Python 3.x interpreter is available") |
|
846 | @check("py3exe", "a Python 3.x interpreter is available") | |
841 | def has_python3exe(): |
|
847 | def has_python3exe(): | |
842 | return matchoutput('python3 -V', br'^Python 3.(5|6|7|8|9)') |
|
848 | return matchoutput('python3 -V', br'^Python 3.(5|6|7|8|9)') | |
843 |
|
849 | |||
844 |
|
850 | |||
845 | @check("pure", "running with pure Python code") |
|
851 | @check("pure", "running with pure Python code") | |
846 | def has_pure(): |
|
852 | def has_pure(): | |
847 | return any( |
|
853 | return any( | |
848 | [ |
|
854 | [ | |
849 | os.environ.get("HGMODULEPOLICY") == "py", |
|
855 | os.environ.get("HGMODULEPOLICY") == "py", | |
850 | os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure", |
|
856 | os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure", | |
851 | ] |
|
857 | ] | |
852 | ) |
|
858 | ) | |
853 |
|
859 | |||
854 |
|
860 | |||
855 | @check("slow", "allow slow tests (use --allow-slow-tests)") |
|
861 | @check("slow", "allow slow tests (use --allow-slow-tests)") | |
856 | def has_slow(): |
|
862 | def has_slow(): | |
857 | return os.environ.get('HGTEST_SLOW') == 'slow' |
|
863 | return os.environ.get('HGTEST_SLOW') == 'slow' | |
858 |
|
864 | |||
859 |
|
865 | |||
860 | @check("hypothesis", "Hypothesis automated test generation") |
|
866 | @check("hypothesis", "Hypothesis automated test generation") | |
861 | def has_hypothesis(): |
|
867 | def has_hypothesis(): | |
862 | try: |
|
868 | try: | |
863 | import hypothesis |
|
869 | import hypothesis | |
864 |
|
870 | |||
865 | hypothesis.given |
|
871 | hypothesis.given | |
866 | return True |
|
872 | return True | |
867 | except ImportError: |
|
873 | except ImportError: | |
868 | return False |
|
874 | return False | |
869 |
|
875 | |||
870 |
|
876 | |||
871 | @check("unziplinks", "unzip(1) understands and extracts symlinks") |
|
877 | @check("unziplinks", "unzip(1) understands and extracts symlinks") | |
872 | def unzip_understands_symlinks(): |
|
878 | def unzip_understands_symlinks(): | |
873 | return matchoutput('unzip --help', br'Info-ZIP') |
|
879 | return matchoutput('unzip --help', br'Info-ZIP') | |
874 |
|
880 | |||
875 |
|
881 | |||
876 | @check("zstd", "zstd Python module available") |
|
882 | @check("zstd", "zstd Python module available") | |
877 | def has_zstd(): |
|
883 | def has_zstd(): | |
878 | try: |
|
884 | try: | |
879 | import mercurial.zstd |
|
885 | import mercurial.zstd | |
880 |
|
886 | |||
881 | mercurial.zstd.__version__ |
|
887 | mercurial.zstd.__version__ | |
882 | return True |
|
888 | return True | |
883 | except ImportError: |
|
889 | except ImportError: | |
884 | return False |
|
890 | return False | |
885 |
|
891 | |||
886 |
|
892 | |||
887 | @check("devfull", "/dev/full special file") |
|
893 | @check("devfull", "/dev/full special file") | |
888 | def has_dev_full(): |
|
894 | def has_dev_full(): | |
889 | return os.path.exists('/dev/full') |
|
895 | return os.path.exists('/dev/full') | |
890 |
|
896 | |||
891 |
|
897 | |||
892 | @check("ensurepip", "ensurepip module") |
|
898 | @check("ensurepip", "ensurepip module") | |
893 | def has_ensurepip(): |
|
899 | def has_ensurepip(): | |
894 | try: |
|
900 | try: | |
895 | import ensurepip |
|
901 | import ensurepip | |
896 |
|
902 | |||
897 | ensurepip.bootstrap |
|
903 | ensurepip.bootstrap | |
898 | return True |
|
904 | return True | |
899 | except ImportError: |
|
905 | except ImportError: | |
900 | return False |
|
906 | return False | |
901 |
|
907 | |||
902 |
|
908 | |||
903 | @check("virtualenv", "virtualenv support") |
|
909 | @check("virtualenv", "virtualenv support") | |
904 | def has_virtualenv(): |
|
910 | def has_virtualenv(): | |
905 | try: |
|
911 | try: | |
906 | import virtualenv |
|
912 | import virtualenv | |
907 |
|
913 | |||
908 | # --no-site-package became the default in 1.7 (Nov 2011), and the |
|
914 | # --no-site-package became the default in 1.7 (Nov 2011), and the | |
909 | # argument was removed in 20.0 (Feb 2020). Rather than make the |
|
915 | # argument was removed in 20.0 (Feb 2020). Rather than make the | |
910 | # script complicated, just ignore ancient versions. |
|
916 | # script complicated, just ignore ancient versions. | |
911 | return int(virtualenv.__version__.split('.')[0]) > 1 |
|
917 | return int(virtualenv.__version__.split('.')[0]) > 1 | |
912 | except (AttributeError, ImportError, IndexError): |
|
918 | except (AttributeError, ImportError, IndexError): | |
913 | return False |
|
919 | return False | |
914 |
|
920 | |||
915 |
|
921 | |||
916 | @check("fsmonitor", "running tests with fsmonitor") |
|
922 | @check("fsmonitor", "running tests with fsmonitor") | |
917 | def has_fsmonitor(): |
|
923 | def has_fsmonitor(): | |
918 | return 'HGFSMONITOR_TESTS' in os.environ |
|
924 | return 'HGFSMONITOR_TESTS' in os.environ | |
919 |
|
925 | |||
920 |
|
926 | |||
921 | @check("fuzzywuzzy", "Fuzzy string matching library") |
|
927 | @check("fuzzywuzzy", "Fuzzy string matching library") | |
922 | def has_fuzzywuzzy(): |
|
928 | def has_fuzzywuzzy(): | |
923 | try: |
|
929 | try: | |
924 | import fuzzywuzzy |
|
930 | import fuzzywuzzy | |
925 |
|
931 | |||
926 | fuzzywuzzy.__version__ |
|
932 | fuzzywuzzy.__version__ | |
927 | return True |
|
933 | return True | |
928 | except ImportError: |
|
934 | except ImportError: | |
929 | return False |
|
935 | return False | |
930 |
|
936 | |||
931 |
|
937 | |||
932 | @check("clang-libfuzzer", "clang new enough to include libfuzzer") |
|
938 | @check("clang-libfuzzer", "clang new enough to include libfuzzer") | |
933 | def has_clang_libfuzzer(): |
|
939 | def has_clang_libfuzzer(): | |
934 | mat = matchoutput('clang --version', br'clang version (\d)') |
|
940 | mat = matchoutput('clang --version', br'clang version (\d)') | |
935 | if mat: |
|
941 | if mat: | |
936 | # libfuzzer is new in clang 6 |
|
942 | # libfuzzer is new in clang 6 | |
937 | return int(mat.group(1)) > 5 |
|
943 | return int(mat.group(1)) > 5 | |
938 | return False |
|
944 | return False | |
939 |
|
945 | |||
940 |
|
946 | |||
941 | @check("clang-6.0", "clang 6.0 with version suffix (libfuzzer included)") |
|
947 | @check("clang-6.0", "clang 6.0 with version suffix (libfuzzer included)") | |
942 | def has_clang60(): |
|
948 | def has_clang60(): | |
943 | return matchoutput('clang-6.0 --version', br'clang version 6\.') |
|
949 | return matchoutput('clang-6.0 --version', br'clang version 6\.') | |
944 |
|
950 | |||
945 |
|
951 | |||
946 | @check("xdiff", "xdiff algorithm") |
|
952 | @check("xdiff", "xdiff algorithm") | |
947 | def has_xdiff(): |
|
953 | def has_xdiff(): | |
948 | try: |
|
954 | try: | |
949 | from mercurial import policy |
|
955 | from mercurial import policy | |
950 |
|
956 | |||
951 | bdiff = policy.importmod('bdiff') |
|
957 | bdiff = policy.importmod('bdiff') | |
952 | return bdiff.xdiffblocks(b'', b'') == [(0, 0, 0, 0)] |
|
958 | return bdiff.xdiffblocks(b'', b'') == [(0, 0, 0, 0)] | |
953 | except (ImportError, AttributeError): |
|
959 | except (ImportError, AttributeError): | |
954 | return False |
|
960 | return False | |
955 |
|
961 | |||
956 |
|
962 | |||
957 | @check('extraextensions', 'whether tests are running with extra extensions') |
|
963 | @check('extraextensions', 'whether tests are running with extra extensions') | |
958 | def has_extraextensions(): |
|
964 | def has_extraextensions(): | |
959 | return 'HGTESTEXTRAEXTENSIONS' in os.environ |
|
965 | return 'HGTESTEXTRAEXTENSIONS' in os.environ | |
960 |
|
966 | |||
961 |
|
967 | |||
962 | def getrepofeatures(): |
|
968 | def getrepofeatures(): | |
963 | """Obtain set of repository features in use. |
|
969 | """Obtain set of repository features in use. | |
964 |
|
970 | |||
965 | HGREPOFEATURES can be used to define or remove features. It contains |
|
971 | HGREPOFEATURES can be used to define or remove features. It contains | |
966 | a space-delimited list of feature strings. Strings beginning with ``-`` |
|
972 | a space-delimited list of feature strings. Strings beginning with ``-`` | |
967 | mean to remove. |
|
973 | mean to remove. | |
968 | """ |
|
974 | """ | |
969 | # Default list provided by core. |
|
975 | # Default list provided by core. | |
970 | features = { |
|
976 | features = { | |
971 | 'bundlerepo', |
|
977 | 'bundlerepo', | |
972 | 'revlogstore', |
|
978 | 'revlogstore', | |
973 | 'fncache', |
|
979 | 'fncache', | |
974 | } |
|
980 | } | |
975 |
|
981 | |||
976 | # Features that imply other features. |
|
982 | # Features that imply other features. | |
977 | implies = { |
|
983 | implies = { | |
978 | 'simplestore': ['-revlogstore', '-bundlerepo', '-fncache'], |
|
984 | 'simplestore': ['-revlogstore', '-bundlerepo', '-fncache'], | |
979 | } |
|
985 | } | |
980 |
|
986 | |||
981 | for override in os.environ.get('HGREPOFEATURES', '').split(' '): |
|
987 | for override in os.environ.get('HGREPOFEATURES', '').split(' '): | |
982 | if not override: |
|
988 | if not override: | |
983 | continue |
|
989 | continue | |
984 |
|
990 | |||
985 | if override.startswith('-'): |
|
991 | if override.startswith('-'): | |
986 | if override[1:] in features: |
|
992 | if override[1:] in features: | |
987 | features.remove(override[1:]) |
|
993 | features.remove(override[1:]) | |
988 | else: |
|
994 | else: | |
989 | features.add(override) |
|
995 | features.add(override) | |
990 |
|
996 | |||
991 | for imply in implies.get(override, []): |
|
997 | for imply in implies.get(override, []): | |
992 | if imply.startswith('-'): |
|
998 | if imply.startswith('-'): | |
993 | if imply[1:] in features: |
|
999 | if imply[1:] in features: | |
994 | features.remove(imply[1:]) |
|
1000 | features.remove(imply[1:]) | |
995 | else: |
|
1001 | else: | |
996 | features.add(imply) |
|
1002 | features.add(imply) | |
997 |
|
1003 | |||
998 | return features |
|
1004 | return features | |
999 |
|
1005 | |||
1000 |
|
1006 | |||
1001 | @check('reporevlogstore', 'repository using the default revlog store') |
|
1007 | @check('reporevlogstore', 'repository using the default revlog store') | |
1002 | def has_reporevlogstore(): |
|
1008 | def has_reporevlogstore(): | |
1003 | return 'revlogstore' in getrepofeatures() |
|
1009 | return 'revlogstore' in getrepofeatures() | |
1004 |
|
1010 | |||
1005 |
|
1011 | |||
1006 | @check('reposimplestore', 'repository using simple storage extension') |
|
1012 | @check('reposimplestore', 'repository using simple storage extension') | |
1007 | def has_reposimplestore(): |
|
1013 | def has_reposimplestore(): | |
1008 | return 'simplestore' in getrepofeatures() |
|
1014 | return 'simplestore' in getrepofeatures() | |
1009 |
|
1015 | |||
1010 |
|
1016 | |||
1011 | @check('repobundlerepo', 'whether we can open bundle files as repos') |
|
1017 | @check('repobundlerepo', 'whether we can open bundle files as repos') | |
1012 | def has_repobundlerepo(): |
|
1018 | def has_repobundlerepo(): | |
1013 | return 'bundlerepo' in getrepofeatures() |
|
1019 | return 'bundlerepo' in getrepofeatures() | |
1014 |
|
1020 | |||
1015 |
|
1021 | |||
1016 | @check('repofncache', 'repository has an fncache') |
|
1022 | @check('repofncache', 'repository has an fncache') | |
1017 | def has_repofncache(): |
|
1023 | def has_repofncache(): | |
1018 | return 'fncache' in getrepofeatures() |
|
1024 | return 'fncache' in getrepofeatures() | |
1019 |
|
1025 | |||
1020 |
|
1026 | |||
1021 | @check('sqlite', 'sqlite3 module and matching cli is available') |
|
1027 | @check('sqlite', 'sqlite3 module and matching cli is available') | |
1022 | def has_sqlite(): |
|
1028 | def has_sqlite(): | |
1023 | try: |
|
1029 | try: | |
1024 | import sqlite3 |
|
1030 | import sqlite3 | |
1025 |
|
1031 | |||
1026 | version = sqlite3.sqlite_version_info |
|
1032 | version = sqlite3.sqlite_version_info | |
1027 | except ImportError: |
|
1033 | except ImportError: | |
1028 | return False |
|
1034 | return False | |
1029 |
|
1035 | |||
1030 | if version < (3, 8, 3): |
|
1036 | if version < (3, 8, 3): | |
1031 | # WITH clause not supported |
|
1037 | # WITH clause not supported | |
1032 | return False |
|
1038 | return False | |
1033 |
|
1039 | |||
1034 | return matchoutput('sqlite3 -version', br'^3\.\d+') |
|
1040 | return matchoutput('sqlite3 -version', br'^3\.\d+') | |
1035 |
|
1041 | |||
1036 |
|
1042 | |||
1037 | @check('vcr', 'vcr http mocking library (pytest-vcr)') |
|
1043 | @check('vcr', 'vcr http mocking library (pytest-vcr)') | |
1038 | def has_vcr(): |
|
1044 | def has_vcr(): | |
1039 | try: |
|
1045 | try: | |
1040 | import vcr |
|
1046 | import vcr | |
1041 |
|
1047 | |||
1042 | vcr.VCR |
|
1048 | vcr.VCR | |
1043 | return True |
|
1049 | return True | |
1044 | except (ImportError, AttributeError): |
|
1050 | except (ImportError, AttributeError): | |
1045 | pass |
|
1051 | pass | |
1046 | return False |
|
1052 | return False | |
1047 |
|
1053 | |||
1048 |
|
1054 | |||
1049 | @check('emacs', 'GNU Emacs') |
|
1055 | @check('emacs', 'GNU Emacs') | |
1050 | def has_emacs(): |
|
1056 | def has_emacs(): | |
1051 | # Our emacs lisp uses `with-eval-after-load` which is new in emacs |
|
1057 | # Our emacs lisp uses `with-eval-after-load` which is new in emacs | |
1052 | # 24.4, so we allow emacs 24.4, 24.5, and 25+ (24.5 was the last |
|
1058 | # 24.4, so we allow emacs 24.4, 24.5, and 25+ (24.5 was the last | |
1053 | # 24 release) |
|
1059 | # 24 release) | |
1054 | return matchoutput('emacs --version', b'GNU Emacs 2(4.4|4.5|5|6|7|8|9)') |
|
1060 | return matchoutput('emacs --version', b'GNU Emacs 2(4.4|4.5|5|6|7|8|9)') | |
1055 |
|
1061 | |||
1056 |
|
1062 | |||
1057 | @check('black', 'the black formatter for python (>= 20.8b1)') |
|
1063 | @check('black', 'the black formatter for python (>= 20.8b1)') | |
1058 | def has_black(): |
|
1064 | def has_black(): | |
1059 | blackcmd = 'black --version' |
|
1065 | blackcmd = 'black --version' | |
1060 | version_regex = b'black, version ([0-9a-b.]+)' |
|
1066 | version_regex = b'black, version ([0-9a-b.]+)' | |
1061 | version = matchoutput(blackcmd, version_regex) |
|
1067 | version = matchoutput(blackcmd, version_regex) | |
1062 | sv = distutils.version.StrictVersion |
|
1068 | sv = distutils.version.StrictVersion | |
1063 | return version and sv(_bytes2sys(version.group(1))) >= sv('20.8b1') |
|
1069 | return version and sv(_bytes2sys(version.group(1))) >= sv('20.8b1') | |
1064 |
|
1070 | |||
1065 |
|
1071 | |||
1066 | @check('pytype', 'the pytype type checker') |
|
1072 | @check('pytype', 'the pytype type checker') | |
1067 | def has_pytype(): |
|
1073 | def has_pytype(): | |
1068 | pytypecmd = 'pytype --version' |
|
1074 | pytypecmd = 'pytype --version' | |
1069 | version = matchoutput(pytypecmd, b'[0-9a-b.]+') |
|
1075 | version = matchoutput(pytypecmd, b'[0-9a-b.]+') | |
1070 | sv = distutils.version.StrictVersion |
|
1076 | sv = distutils.version.StrictVersion | |
1071 | return version and sv(_bytes2sys(version.group(0))) >= sv('2019.10.17') |
|
1077 | return version and sv(_bytes2sys(version.group(0))) >= sv('2019.10.17') | |
1072 |
|
1078 | |||
1073 |
|
1079 | |||
1074 | @check("rustfmt", "rustfmt tool at version nightly-2020-10-04") |
|
1080 | @check("rustfmt", "rustfmt tool at version nightly-2020-10-04") | |
1075 | def has_rustfmt(): |
|
1081 | def has_rustfmt(): | |
1076 | # We use Nightly's rustfmt due to current unstable config options. |
|
1082 | # We use Nightly's rustfmt due to current unstable config options. | |
1077 | return matchoutput( |
|
1083 | return matchoutput( | |
1078 | '`rustup which --toolchain nightly-2020-10-04 rustfmt` --version', |
|
1084 | '`rustup which --toolchain nightly-2020-10-04 rustfmt` --version', | |
1079 | b'rustfmt', |
|
1085 | b'rustfmt', | |
1080 | ) |
|
1086 | ) | |
1081 |
|
1087 | |||
1082 |
|
1088 | |||
1083 | @check("cargo", "cargo tool") |
|
1089 | @check("cargo", "cargo tool") | |
1084 | def has_cargo(): |
|
1090 | def has_cargo(): | |
1085 | return matchoutput('`rustup which cargo` --version', b'cargo') |
|
1091 | return matchoutput('`rustup which cargo` --version', b'cargo') | |
1086 |
|
1092 | |||
1087 |
|
1093 | |||
1088 | @check("lzma", "python lzma module") |
|
1094 | @check("lzma", "python lzma module") | |
1089 | def has_lzma(): |
|
1095 | def has_lzma(): | |
1090 | try: |
|
1096 | try: | |
1091 | import _lzma |
|
1097 | import _lzma | |
1092 |
|
1098 | |||
1093 | _lzma.FORMAT_XZ |
|
1099 | _lzma.FORMAT_XZ | |
1094 | return True |
|
1100 | return True | |
1095 | except ImportError: |
|
1101 | except ImportError: | |
1096 | return False |
|
1102 | return False |
@@ -1,262 +1,264 b'' | |||||
1 | hg debuginstall |
|
1 | hg debuginstall | |
2 | $ hg debuginstall |
|
2 | $ hg debuginstall | |
3 | checking encoding (ascii)... |
|
3 | checking encoding (ascii)... | |
4 | checking Python executable (*) (glob) |
|
4 | checking Python executable (*) (glob) | |
5 | checking Python implementation (*) (glob) |
|
5 | checking Python implementation (*) (glob) | |
6 | checking Python version (2.*) (glob) (no-py3 !) |
|
6 | checking Python version (2.*) (glob) (no-py3 !) | |
7 | checking Python version (3.*) (glob) (py3 !) |
|
7 | checking Python version (3.*) (glob) (py3 !) | |
8 | checking Python lib (.*[Ll]ib.*)... (re) |
|
8 | checking Python lib (.*[Ll]ib.*)... (re) | |
9 | checking Python security support (*) (glob) |
|
9 | checking Python security support (*) (glob) | |
10 | TLS 1.2 not supported by Python install; network connections lack modern security (?) |
|
10 | TLS 1.2 not supported by Python install; network connections lack modern security (?) | |
11 | SNI not supported by Python install; may have connectivity issues with some servers (?) |
|
11 | SNI not supported by Python install; may have connectivity issues with some servers (?) | |
12 | checking Rust extensions \((installed|missing)\) (re) |
|
12 | checking Rust extensions \((installed|missing)\) (re) | |
13 | checking Mercurial version (*) (glob) |
|
13 | checking Mercurial version (*) (glob) | |
14 | checking Mercurial custom build (*) (glob) |
|
14 | checking Mercurial custom build (*) (glob) | |
15 | checking module policy (*) (glob) |
|
15 | checking module policy (*) (glob) | |
16 | checking installed modules (*mercurial)... (glob) |
|
16 | checking installed modules (*mercurial)... (glob) | |
17 | checking registered compression engines (*zlib*) (glob) |
|
17 | checking registered compression engines (*zlib*) (glob) | |
18 | checking available compression engines (*zlib*) (glob) |
|
18 | checking available compression engines (*zlib*) (glob) | |
19 | checking available compression engines for wire protocol (*zlib*) (glob) |
|
19 | checking available compression engines for wire protocol (*zlib*) (glob) | |
20 | checking "re2" regexp engine \((available|missing)\) (re) |
|
20 | checking "re2" regexp engine \((available|missing)\) (re) | |
21 | checking templates (*mercurial?templates)... (glob) |
|
21 | checking templates (*mercurial?templates)... (glob) | |
22 | checking default template (*mercurial?templates?map-cmdline.default) (glob) |
|
22 | checking default template (*mercurial?templates?map-cmdline.default) (glob) | |
23 | checking commit editor... (*) (glob) |
|
23 | checking commit editor... (*) (glob) | |
24 | checking username (test) |
|
24 | checking username (test) | |
25 | no problems detected |
|
25 | no problems detected | |
26 |
|
26 | |||
27 | hg debuginstall JSON |
|
27 | hg debuginstall JSON | |
28 | $ hg debuginstall -Tjson | sed 's|\\\\|\\|g' |
|
28 | $ hg debuginstall -Tjson | sed 's|\\\\|\\|g' | |
29 | [ |
|
29 | [ | |
30 | { |
|
30 | { | |
31 | "compengines": ["bz2", "bz2truncated", "none", "zlib"*], (glob) |
|
31 | "compengines": ["bz2", "bz2truncated", "none", "zlib"*], (glob) | |
32 | "compenginesavail": ["bz2", "bz2truncated", "none", "zlib"*], (glob) |
|
32 | "compenginesavail": ["bz2", "bz2truncated", "none", "zlib"*], (glob) | |
33 | "compenginesserver": [*"zlib"*], (glob) |
|
33 | "compenginesserver": [*"zlib"*], (glob) | |
34 | "defaulttemplate": "*mercurial?templates?map-cmdline.default", (glob) |
|
34 | "defaulttemplate": "*mercurial?templates?map-cmdline.default", (glob) | |
35 | "defaulttemplateerror": null, |
|
35 | "defaulttemplateerror": null, | |
36 | "defaulttemplatenotfound": "default", |
|
36 | "defaulttemplatenotfound": "default", | |
37 | "editor": "*", (glob) |
|
37 | "editor": "*", (glob) | |
38 | "editornotfound": false, |
|
38 | "editornotfound": false, | |
39 | "encoding": "ascii", |
|
39 | "encoding": "ascii", | |
40 | "encodingerror": null, |
|
40 | "encodingerror": null, | |
41 | "extensionserror": null, (no-pure !) |
|
41 | "extensionserror": null, (no-pure !) | |
42 | "hgmodulepolicy": "*", (glob) |
|
42 | "hgmodulepolicy": "*", (glob) | |
43 | "hgmodules": "*mercurial", (glob) |
|
43 | "hgmodules": "*mercurial", (glob) | |
44 | "hgver": "*", (glob) |
|
44 | "hgver": "*", (glob) | |
45 | "hgverextra": "*", (glob) |
|
45 | "hgverextra": "*", (glob) | |
46 | "problems": 0, |
|
46 | "problems": 0, | |
47 | "pythonexe": "*", (glob) |
|
47 | "pythonexe": "*", (glob) | |
48 | "pythonimplementation": "*", (glob) |
|
48 | "pythonimplementation": "*", (glob) | |
49 | "pythonlib": "*", (glob) |
|
49 | "pythonlib": "*", (glob) | |
50 | "pythonsecurity": [*], (glob) |
|
50 | "pythonsecurity": [*], (glob) | |
51 | "pythonver": "*.*.*", (glob) |
|
51 | "pythonver": "*.*.*", (glob) | |
52 | "re2": (true|false), (re) |
|
52 | "re2": (true|false), (re) | |
53 | "templatedirs": "*mercurial?templates", (glob) |
|
53 | "templatedirs": "*mercurial?templates", (glob) | |
54 | "username": "test", |
|
54 | "username": "test", | |
55 | "usernameerror": null, |
|
55 | "usernameerror": null, | |
56 | "vinotfound": false |
|
56 | "vinotfound": false | |
57 | } |
|
57 | } | |
58 | ] |
|
58 | ] | |
59 |
|
59 | |||
60 | hg debuginstall with no username |
|
60 | hg debuginstall with no username | |
61 | $ HGUSER= hg debuginstall |
|
61 | $ HGUSER= hg debuginstall | |
62 | checking encoding (ascii)... |
|
62 | checking encoding (ascii)... | |
63 | checking Python executable (*) (glob) |
|
63 | checking Python executable (*) (glob) | |
64 | checking Python implementation (*) (glob) |
|
64 | checking Python implementation (*) (glob) | |
65 | checking Python version (2.*) (glob) (no-py3 !) |
|
65 | checking Python version (2.*) (glob) (no-py3 !) | |
66 | checking Python version (3.*) (glob) (py3 !) |
|
66 | checking Python version (3.*) (glob) (py3 !) | |
67 | checking Python lib (.*[Ll]ib.*)... (re) |
|
67 | checking Python lib (.*[Ll]ib.*)... (re) | |
68 | checking Python security support (*) (glob) |
|
68 | checking Python security support (*) (glob) | |
69 | TLS 1.2 not supported by Python install; network connections lack modern security (?) |
|
69 | TLS 1.2 not supported by Python install; network connections lack modern security (?) | |
70 | SNI not supported by Python install; may have connectivity issues with some servers (?) |
|
70 | SNI not supported by Python install; may have connectivity issues with some servers (?) | |
71 | checking Rust extensions \((installed|missing)\) (re) |
|
71 | checking Rust extensions \((installed|missing)\) (re) | |
72 | checking Mercurial version (*) (glob) |
|
72 | checking Mercurial version (*) (glob) | |
73 | checking Mercurial custom build (*) (glob) |
|
73 | checking Mercurial custom build (*) (glob) | |
74 | checking module policy (*) (glob) |
|
74 | checking module policy (*) (glob) | |
75 | checking installed modules (*mercurial)... (glob) |
|
75 | checking installed modules (*mercurial)... (glob) | |
76 | checking registered compression engines (*zlib*) (glob) |
|
76 | checking registered compression engines (*zlib*) (glob) | |
77 | checking available compression engines (*zlib*) (glob) |
|
77 | checking available compression engines (*zlib*) (glob) | |
78 | checking available compression engines for wire protocol (*zlib*) (glob) |
|
78 | checking available compression engines for wire protocol (*zlib*) (glob) | |
79 | checking "re2" regexp engine \((available|missing)\) (re) |
|
79 | checking "re2" regexp engine \((available|missing)\) (re) | |
80 | checking templates (*mercurial?templates)... (glob) |
|
80 | checking templates (*mercurial?templates)... (glob) | |
81 | checking default template (*mercurial?templates?map-cmdline.default) (glob) |
|
81 | checking default template (*mercurial?templates?map-cmdline.default) (glob) | |
82 | checking commit editor... (*) (glob) |
|
82 | checking commit editor... (*) (glob) | |
83 | checking username... |
|
83 | checking username... | |
84 | no username supplied |
|
84 | no username supplied | |
85 | (specify a username in your configuration file) |
|
85 | (specify a username in your configuration file) | |
86 | 1 problems detected, please check your install! |
|
86 | 1 problems detected, please check your install! | |
87 | [1] |
|
87 | [1] | |
88 |
|
88 | |||
89 | hg debuginstall with invalid encoding |
|
89 | hg debuginstall with invalid encoding | |
90 | $ HGENCODING=invalidenc hg debuginstall | grep encoding |
|
90 | $ HGENCODING=invalidenc hg debuginstall | grep encoding | |
91 | checking encoding (invalidenc)... |
|
91 | checking encoding (invalidenc)... | |
92 | unknown encoding: invalidenc |
|
92 | unknown encoding: invalidenc | |
93 |
|
93 | |||
94 | exception message in JSON |
|
94 | exception message in JSON | |
95 |
|
95 | |||
96 | $ HGENCODING=invalidenc HGUSER= hg debuginstall -Tjson | grep error |
|
96 | $ HGENCODING=invalidenc HGUSER= hg debuginstall -Tjson | grep error | |
97 | "defaulttemplateerror": null, |
|
97 | "defaulttemplateerror": null, | |
98 | "encodingerror": "unknown encoding: invalidenc", |
|
98 | "encodingerror": "unknown encoding: invalidenc", | |
99 | "extensionserror": null, (no-pure !) |
|
99 | "extensionserror": null, (no-pure !) | |
100 | "usernameerror": "no username supplied", |
|
100 | "usernameerror": "no username supplied", | |
101 |
|
101 | |||
102 | path variables are expanded (~ is the same as $TESTTMP) |
|
102 | path variables are expanded (~ is the same as $TESTTMP) | |
103 | $ mkdir tools |
|
103 | $ mkdir tools | |
104 | $ touch tools/testeditor.exe |
|
104 | $ touch tools/testeditor.exe | |
105 | #if execbit |
|
105 | #if execbit | |
106 | $ chmod 755 tools/testeditor.exe |
|
106 | $ chmod 755 tools/testeditor.exe | |
107 | #endif |
|
107 | #endif | |
108 | $ HGEDITOR="~/tools/testeditor.exe" hg debuginstall |
|
108 | $ HGEDITOR="~/tools/testeditor.exe" hg debuginstall | |
109 | checking encoding (ascii)... |
|
109 | checking encoding (ascii)... | |
110 | checking Python executable (*) (glob) |
|
110 | checking Python executable (*) (glob) | |
111 | checking Python implementation (*) (glob) |
|
111 | checking Python implementation (*) (glob) | |
112 | checking Python version (2.*) (glob) (no-py3 !) |
|
112 | checking Python version (2.*) (glob) (no-py3 !) | |
113 | checking Python version (3.*) (glob) (py3 !) |
|
113 | checking Python version (3.*) (glob) (py3 !) | |
114 | checking Python lib (.*[Ll]ib.*)... (re) |
|
114 | checking Python lib (.*[Ll]ib.*)... (re) | |
115 | checking Python security support (*) (glob) |
|
115 | checking Python security support (*) (glob) | |
116 | TLS 1.2 not supported by Python install; network connections lack modern security (?) |
|
116 | TLS 1.2 not supported by Python install; network connections lack modern security (?) | |
117 | SNI not supported by Python install; may have connectivity issues with some servers (?) |
|
117 | SNI not supported by Python install; may have connectivity issues with some servers (?) | |
118 | checking Rust extensions \((installed|missing)\) (re) |
|
118 | checking Rust extensions \((installed|missing)\) (re) | |
119 | checking Mercurial version (*) (glob) |
|
119 | checking Mercurial version (*) (glob) | |
120 | checking Mercurial custom build (*) (glob) |
|
120 | checking Mercurial custom build (*) (glob) | |
121 | checking module policy (*) (glob) |
|
121 | checking module policy (*) (glob) | |
122 | checking installed modules (*mercurial)... (glob) |
|
122 | checking installed modules (*mercurial)... (glob) | |
123 | checking registered compression engines (*zlib*) (glob) |
|
123 | checking registered compression engines (*zlib*) (glob) | |
124 | checking available compression engines (*zlib*) (glob) |
|
124 | checking available compression engines (*zlib*) (glob) | |
125 | checking available compression engines for wire protocol (*zlib*) (glob) |
|
125 | checking available compression engines for wire protocol (*zlib*) (glob) | |
126 | checking "re2" regexp engine \((available|missing)\) (re) |
|
126 | checking "re2" regexp engine \((available|missing)\) (re) | |
127 | checking templates (*mercurial?templates)... (glob) |
|
127 | checking templates (*mercurial?templates)... (glob) | |
128 | checking default template (*mercurial?templates?map-cmdline.default) (glob) |
|
128 | checking default template (*mercurial?templates?map-cmdline.default) (glob) | |
129 | checking commit editor... ($TESTTMP/tools/testeditor.exe) |
|
129 | checking commit editor... ($TESTTMP/tools/testeditor.exe) | |
130 | checking username (test) |
|
130 | checking username (test) | |
131 | no problems detected |
|
131 | no problems detected | |
132 |
|
132 | |||
133 | print out the binary post-shlexsplit in the error message when commit editor is |
|
133 | print out the binary post-shlexsplit in the error message when commit editor is | |
134 | not found (this is intentionally using backslashes to mimic a windows usecase). |
|
134 | not found (this is intentionally using backslashes to mimic a windows usecase). | |
135 | $ HGEDITOR="c:\foo\bar\baz.exe -y -z" hg debuginstall |
|
135 | $ HGEDITOR="c:\foo\bar\baz.exe -y -z" hg debuginstall | |
136 | checking encoding (ascii)... |
|
136 | checking encoding (ascii)... | |
137 | checking Python executable (*) (glob) |
|
137 | checking Python executable (*) (glob) | |
138 | checking Python implementation (*) (glob) |
|
138 | checking Python implementation (*) (glob) | |
139 | checking Python version (2.*) (glob) (no-py3 !) |
|
139 | checking Python version (2.*) (glob) (no-py3 !) | |
140 | checking Python version (3.*) (glob) (py3 !) |
|
140 | checking Python version (3.*) (glob) (py3 !) | |
141 | checking Python lib (.*[Ll]ib.*)... (re) |
|
141 | checking Python lib (.*[Ll]ib.*)... (re) | |
142 | checking Python security support (*) (glob) |
|
142 | checking Python security support (*) (glob) | |
143 | TLS 1.2 not supported by Python install; network connections lack modern security (?) |
|
143 | TLS 1.2 not supported by Python install; network connections lack modern security (?) | |
144 | SNI not supported by Python install; may have connectivity issues with some servers (?) |
|
144 | SNI not supported by Python install; may have connectivity issues with some servers (?) | |
145 | checking Rust extensions \((installed|missing)\) (re) |
|
145 | checking Rust extensions \((installed|missing)\) (re) | |
146 | checking Mercurial version (*) (glob) |
|
146 | checking Mercurial version (*) (glob) | |
147 | checking Mercurial custom build (*) (glob) |
|
147 | checking Mercurial custom build (*) (glob) | |
148 | checking module policy (*) (glob) |
|
148 | checking module policy (*) (glob) | |
149 | checking installed modules (*mercurial)... (glob) |
|
149 | checking installed modules (*mercurial)... (glob) | |
150 | checking registered compression engines (*zlib*) (glob) |
|
150 | checking registered compression engines (*zlib*) (glob) | |
151 | checking available compression engines (*zlib*) (glob) |
|
151 | checking available compression engines (*zlib*) (glob) | |
152 | checking available compression engines for wire protocol (*zlib*) (glob) |
|
152 | checking available compression engines for wire protocol (*zlib*) (glob) | |
153 | checking "re2" regexp engine \((available|missing)\) (re) |
|
153 | checking "re2" regexp engine \((available|missing)\) (re) | |
154 | checking templates (*mercurial?templates)... (glob) |
|
154 | checking templates (*mercurial?templates)... (glob) | |
155 | checking default template (*mercurial?templates?map-cmdline.default) (glob) |
|
155 | checking default template (*mercurial?templates?map-cmdline.default) (glob) | |
156 | checking commit editor... (c:\foo\bar\baz.exe) (windows !) |
|
156 | checking commit editor... (c:\foo\bar\baz.exe) (windows !) | |
157 | Can't find editor 'c:\foo\bar\baz.exe' in PATH (windows !) |
|
157 | Can't find editor 'c:\foo\bar\baz.exe' in PATH (windows !) | |
158 | checking commit editor... (c:foobarbaz.exe) (no-windows !) |
|
158 | checking commit editor... (c:foobarbaz.exe) (no-windows !) | |
159 | Can't find editor 'c:foobarbaz.exe' in PATH (no-windows !) |
|
159 | Can't find editor 'c:foobarbaz.exe' in PATH (no-windows !) | |
160 | (specify a commit editor in your configuration file) |
|
160 | (specify a commit editor in your configuration file) | |
161 | checking username (test) |
|
161 | checking username (test) | |
162 | 1 problems detected, please check your install! |
|
162 | 1 problems detected, please check your install! | |
163 | [1] |
|
163 | [1] | |
164 |
|
164 | |||
165 | debuginstall extension support |
|
165 | debuginstall extension support | |
166 | $ hg debuginstall --config extensions.fsmonitor= --config fsmonitor.watchman_exe=false | grep atchman |
|
166 | $ hg debuginstall --config extensions.fsmonitor= --config fsmonitor.watchman_exe=false | grep atchman | |
167 | fsmonitor checking for watchman binary... (false) |
|
167 | fsmonitor checking for watchman binary... (false) | |
168 | watchman binary missing or broken: warning: Watchman unavailable: watchman exited with code 1 |
|
168 | watchman binary missing or broken: warning: Watchman unavailable: watchman exited with code 1 | |
169 | Verify the json works too: |
|
169 | Verify the json works too: | |
170 | $ hg debuginstall --config extensions.fsmonitor= --config fsmonitor.watchman_exe=false -Tjson | grep atchman |
|
170 | $ hg debuginstall --config extensions.fsmonitor= --config fsmonitor.watchman_exe=false -Tjson | grep atchman | |
171 | "fsmonitor-watchman": "false", |
|
171 | "fsmonitor-watchman": "false", | |
172 | "fsmonitor-watchman-error": "warning: Watchman unavailable: watchman exited with code 1", |
|
172 | "fsmonitor-watchman-error": "warning: Watchman unavailable: watchman exited with code 1", | |
173 |
|
173 | |||
174 | Verify that Mercurial is installable with pip. Note that this MUST be |
|
174 | Verify that Mercurial is installable with pip. Note that this MUST be | |
175 | the last test in this file, because we do some nasty things to the |
|
175 | the last test in this file, because we do some nasty things to the | |
176 | shell environment in order to make the virtualenv work reliably. |
|
176 | shell environment in order to make the virtualenv work reliably. | |
177 |
|
177 | |||
178 | On Python 3, we use the venv module, which is part of the standard library. |
|
178 | On Python 3, we use the venv module, which is part of the standard library. | |
179 | But some Linux distros strip out this module's functionality involving pip, |
|
179 | But some Linux distros strip out this module's functionality involving pip, | |
180 | so we have to look for the ensurepip module, which these distros strip out |
|
180 | so we have to look for the ensurepip module, which these distros strip out | |
181 | completely. |
|
181 | completely. | |
182 | On Python 2, we use the 3rd party virtualenv module, if available. |
|
182 | On Python 2, we use the 3rd party virtualenv module, if available. | |
183 |
|
183 | |||
184 | $ cd $TESTTMP |
|
184 | $ cd $TESTTMP | |
185 | $ unset PYTHONPATH |
|
185 | $ unset PYTHONPATH | |
186 |
|
186 | |||
187 | #if py3 ensurepip |
|
187 | #if py3 ensurepip network-io | |
188 | $ "$PYTHON" -m venv installenv >> pip.log |
|
188 | $ "$PYTHON" -m venv installenv >> pip.log | |
189 |
|
189 | |||
190 | Hack: Debian does something a bit different in ensurepip.bootstrap. This makes |
|
190 | Hack: Debian does something a bit different in ensurepip.bootstrap. This makes | |
191 | it so that pip thinks the 'wheel' wheel is installed so it can build wheels; |
|
191 | it so that pip thinks the 'wheel' wheel is installed so it can build wheels; | |
192 | when it goes to try, however, it shells out to run `python3 -u <setup.py>`, |
|
192 | when it goes to try, however, it shells out to run `python3 -u <setup.py>`, | |
193 | that *doesn't* get the 'wheel' wheel, and it fails with an invalid command |
|
193 | that *doesn't* get the 'wheel' wheel, and it fails with an invalid command | |
194 | 'bdist_wheel'. To fix this, we just delete the wheel from where Debian put it in |
|
194 | 'bdist_wheel'. To fix this, we just delete the wheel from where Debian put it in | |
195 | our virtual env. Then pip doesn't think it's installed and doesn't try to build. |
|
195 | our virtual env. Then pip doesn't think it's installed and doesn't try to build. | |
196 | $ rm installenv/share/python-wheels/wheel-*.whl >/dev/null 2>&1 || true |
|
196 | $ rm installenv/share/python-wheels/wheel-*.whl >/dev/null 2>&1 || true | |
197 |
|
197 | |||
198 | Note: we use this weird path to run pip and hg to avoid platform differences, |
|
198 | Note: we use this weird path to run pip and hg to avoid platform differences, | |
199 | since it's bin on most platforms but Scripts on Windows. |
|
199 | since it's bin on most platforms but Scripts on Windows. | |
200 |
$ ./installenv/*/pip install |
|
200 | $ ./installenv/*/pip install $TESTDIR/.. >> pip.log | |
201 | Failed building wheel for mercurial (?) |
|
201 | Failed building wheel for mercurial (?) | |
|
202 | WARNING: You are using pip version *; however, version * is available. (glob) (?) | |||
|
203 | You should consider upgrading via the '$TESTTMP/installenv/bin/python* -m pip install --upgrade pip' command. (glob) (?) | |||
202 | $ ./installenv/*/hg debuginstall || cat pip.log |
|
204 | $ ./installenv/*/hg debuginstall || cat pip.log | |
203 | checking encoding (ascii)... |
|
205 | checking encoding (ascii)... | |
204 | checking Python executable (*) (glob) |
|
206 | checking Python executable (*) (glob) | |
205 | checking Python implementation (*) (glob) |
|
207 | checking Python implementation (*) (glob) | |
206 | checking Python version (3.*) (glob) |
|
208 | checking Python version (3.*) (glob) | |
207 | checking Python lib (*)... (glob) |
|
209 | checking Python lib (*)... (glob) | |
208 | checking Python security support (*) (glob) |
|
210 | checking Python security support (*) (glob) | |
209 | checking Rust extensions \((installed|missing)\) (re) |
|
211 | checking Rust extensions \((installed|missing)\) (re) | |
210 | checking Mercurial version (*) (glob) |
|
212 | checking Mercurial version (*) (glob) | |
211 | checking Mercurial custom build (*) (glob) |
|
213 | checking Mercurial custom build (*) (glob) | |
212 | checking module policy (*) (glob) |
|
214 | checking module policy (*) (glob) | |
213 | checking installed modules (*/mercurial)... (glob) |
|
215 | checking installed modules (*/mercurial)... (glob) | |
214 | checking registered compression engines (*) (glob) |
|
216 | checking registered compression engines (*) (glob) | |
215 | checking available compression engines (*) (glob) |
|
217 | checking available compression engines (*) (glob) | |
216 | checking available compression engines for wire protocol (*) (glob) |
|
218 | checking available compression engines for wire protocol (*) (glob) | |
217 | checking "re2" regexp engine \((available|missing)\) (re) |
|
219 | checking "re2" regexp engine \((available|missing)\) (re) | |
218 | checking templates ($TESTTMP/installenv/*/site-packages/mercurial/templates)... (glob) |
|
220 | checking templates ($TESTTMP/installenv/*/site-packages/mercurial/templates)... (glob) | |
219 | checking default template ($TESTTMP/installenv/*/site-packages/mercurial/templates/map-cmdline.default) (glob) |
|
221 | checking default template ($TESTTMP/installenv/*/site-packages/mercurial/templates/map-cmdline.default) (glob) | |
220 | checking commit editor... (*) (glob) |
|
222 | checking commit editor... (*) (glob) | |
221 | checking username (test) |
|
223 | checking username (test) | |
222 | no problems detected |
|
224 | no problems detected | |
223 | #endif |
|
225 | #endif | |
224 |
|
226 | |||
225 | #if virtualenv no-py3 |
|
227 | #if virtualenv no-py3 network-io | |
226 |
|
228 | |||
227 | Note: --no-site-packages is the default for all versions enabled by hghave |
|
229 | Note: --no-site-packages is the default for all versions enabled by hghave | |
228 |
|
230 | |||
229 |
$ "$PYTHON" -m virtualenv |
|
231 | $ "$PYTHON" -m virtualenv installenv >> pip.log | |
230 | DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. (?) |
|
232 | DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. (?) | |
231 | DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support (?) |
|
233 | DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support (?) | |
232 |
|
234 | |||
233 | Note: we use this weird path to run pip and hg to avoid platform differences, |
|
235 | Note: we use this weird path to run pip and hg to avoid platform differences, | |
234 | since it's bin on most platforms but Scripts on Windows. |
|
236 | since it's bin on most platforms but Scripts on Windows. | |
235 |
$ ./installenv/*/pip install |
|
237 | $ ./installenv/*/pip install $TESTDIR/.. >> pip.log | |
236 | DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. (?) |
|
238 | DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. (?) | |
237 | DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support (?) |
|
239 | DEPRECATION: Python 2.7 will reach the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 won't be maintained after that date. A future version of pip will drop support for Python 2.7. More details about Python 2 support in pip, can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support (?) | |
238 | DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality. (?) |
|
240 | DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality. (?) | |
239 | $ ./installenv/*/hg debuginstall || cat pip.log |
|
241 | $ ./installenv/*/hg debuginstall || cat pip.log | |
240 | checking encoding (ascii)... |
|
242 | checking encoding (ascii)... | |
241 | checking Python executable (*) (glob) |
|
243 | checking Python executable (*) (glob) | |
242 | checking Python implementation (*) (glob) |
|
244 | checking Python implementation (*) (glob) | |
243 | checking Python version (2.*) (glob) |
|
245 | checking Python version (2.*) (glob) | |
244 | checking Python lib (*)... (glob) |
|
246 | checking Python lib (*)... (glob) | |
245 | checking Python security support (*) (glob) |
|
247 | checking Python security support (*) (glob) | |
246 | TLS 1.2 not supported by Python install; network connections lack modern security (?) |
|
248 | TLS 1.2 not supported by Python install; network connections lack modern security (?) | |
247 | SNI not supported by Python install; may have connectivity issues with some servers (?) |
|
249 | SNI not supported by Python install; may have connectivity issues with some servers (?) | |
248 | checking Rust extensions \((installed|missing)\) (re) |
|
250 | checking Rust extensions \((installed|missing)\) (re) | |
249 | checking Mercurial version (*) (glob) |
|
251 | checking Mercurial version (*) (glob) | |
250 | checking Mercurial custom build (*) (glob) |
|
252 | checking Mercurial custom build (*) (glob) | |
251 | checking module policy (*) (glob) |
|
253 | checking module policy (*) (glob) | |
252 | checking installed modules (*/mercurial)... (glob) |
|
254 | checking installed modules (*/mercurial)... (glob) | |
253 | checking registered compression engines (*) (glob) |
|
255 | checking registered compression engines (*) (glob) | |
254 | checking available compression engines (*) (glob) |
|
256 | checking available compression engines (*) (glob) | |
255 | checking available compression engines for wire protocol (*) (glob) |
|
257 | checking available compression engines for wire protocol (*) (glob) | |
256 | checking "re2" regexp engine \((available|missing)\) (re) |
|
258 | checking "re2" regexp engine \((available|missing)\) (re) | |
257 | checking templates ($TESTTMP/installenv/*/site-packages/mercurial/templates)... (glob) |
|
259 | checking templates ($TESTTMP/installenv/*/site-packages/mercurial/templates)... (glob) | |
258 | checking default template ($TESTTMP/installenv/*/site-packages/mercurial/templates/map-cmdline.default) (glob) |
|
260 | checking default template ($TESTTMP/installenv/*/site-packages/mercurial/templates/map-cmdline.default) (glob) | |
259 | checking commit editor... (*) (glob) |
|
261 | checking commit editor... (*) (glob) | |
260 | checking username (test) |
|
262 | checking username (test) | |
261 | no problems detected |
|
263 | no problems detected | |
262 | #endif |
|
264 | #endif |
General Comments 0
You need to be logged in to leave comments.
Login now