Mercurial > hg
comparison tests/hghave.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | 07e479ef7c96 |
children | fb41ea2ea076 |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
15 "false": (lambda: False, "nail clipper"), | 15 "false": (lambda: False, "nail clipper"), |
16 } | 16 } |
17 | 17 |
18 try: | 18 try: |
19 import msvcrt | 19 import msvcrt |
20 | |
20 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) | 21 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) |
21 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY) | 22 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY) |
22 except ImportError: | 23 except ImportError: |
23 pass | 24 pass |
24 | 25 |
25 stdout = getattr(sys.stdout, 'buffer', sys.stdout) | 26 stdout = getattr(sys.stdout, 'buffer', sys.stdout) |
26 stderr = getattr(sys.stderr, 'buffer', sys.stderr) | 27 stderr = getattr(sys.stderr, 'buffer', sys.stderr) |
27 | 28 |
28 if sys.version_info[0] >= 3: | 29 if sys.version_info[0] >= 3: |
30 | |
29 def _bytespath(p): | 31 def _bytespath(p): |
30 if p is None: | 32 if p is None: |
31 return p | 33 return p |
32 return p.encode('utf-8') | 34 return p.encode('utf-8') |
33 | 35 |
34 def _strpath(p): | 36 def _strpath(p): |
35 if p is None: | 37 if p is None: |
36 return p | 38 return p |
37 return p.decode('utf-8') | 39 return p.decode('utf-8') |
40 | |
41 | |
38 else: | 42 else: |
43 | |
39 def _bytespath(p): | 44 def _bytespath(p): |
40 return p | 45 return p |
41 | 46 |
42 _strpath = _bytespath | 47 _strpath = _bytespath |
43 | 48 |
49 | |
44 def check(name, desc): | 50 def check(name, desc): |
45 """Registers a check function for a feature.""" | 51 """Registers a check function for a feature.""" |
52 | |
46 def decorator(func): | 53 def decorator(func): |
47 checks[name] = (func, desc) | 54 checks[name] = (func, desc) |
48 return func | 55 return func |
56 | |
49 return decorator | 57 return decorator |
58 | |
50 | 59 |
51 def checkvers(name, desc, vers): | 60 def checkvers(name, desc, vers): |
52 """Registers a check function for each of a series of versions. | 61 """Registers a check function for each of a series of versions. |
53 | 62 |
54 vers can be a list or an iterator""" | 63 vers can be a list or an iterator""" |
64 | |
55 def decorator(func): | 65 def decorator(func): |
56 def funcv(v): | 66 def funcv(v): |
57 def f(): | 67 def f(): |
58 return func(v) | 68 return func(v) |
69 | |
59 return f | 70 return f |
71 | |
60 for v in vers: | 72 for v in vers: |
61 v = str(v) | 73 v = str(v) |
62 f = funcv(v) | 74 f = funcv(v) |
63 checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v) | 75 checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v) |
64 return func | 76 return func |
77 | |
65 return decorator | 78 return decorator |
79 | |
66 | 80 |
67 def checkfeatures(features): | 81 def checkfeatures(features): |
68 result = { | 82 result = { |
69 'error': [], | 83 'error': [], |
70 'missing': [], | 84 'missing': [], |
92 elif negate and available: | 106 elif negate and available: |
93 result['skipped'].append('system supports %s' % desc) | 107 result['skipped'].append('system supports %s' % desc) |
94 | 108 |
95 return result | 109 return result |
96 | 110 |
111 | |
97 def require(features): | 112 def require(features): |
98 """Require that features are available, exiting if not.""" | 113 """Require that features are available, exiting if not.""" |
99 result = checkfeatures(features) | 114 result = checkfeatures(features) |
100 | 115 |
101 for missing in result['missing']: | 116 for missing in result['missing']: |
102 stderr.write(('skipped: unknown feature: %s\n' | 117 stderr.write( |
103 % missing).encode('utf-8')) | 118 ('skipped: unknown feature: %s\n' % missing).encode('utf-8') |
119 ) | |
104 for msg in result['skipped']: | 120 for msg in result['skipped']: |
105 stderr.write(('skipped: %s\n' % msg).encode('utf-8')) | 121 stderr.write(('skipped: %s\n' % msg).encode('utf-8')) |
106 for msg in result['error']: | 122 for msg in result['error']: |
107 stderr.write(('%s\n' % msg).encode('utf-8')) | 123 stderr.write(('%s\n' % msg).encode('utf-8')) |
108 | 124 |
109 if result['missing']: | 125 if result['missing']: |
110 sys.exit(2) | 126 sys.exit(2) |
111 | 127 |
112 if result['skipped'] or result['error']: | 128 if result['skipped'] or result['error']: |
113 sys.exit(1) | 129 sys.exit(1) |
130 | |
114 | 131 |
115 def matchoutput(cmd, regexp, ignorestatus=False): | 132 def matchoutput(cmd, regexp, ignorestatus=False): |
116 """Return the match object if cmd executes successfully and its output | 133 """Return the match object if cmd executes successfully and its output |
117 is matched by the supplied regular expression. | 134 is matched by the supplied regular expression. |
118 """ | 135 """ |
119 r = re.compile(regexp) | 136 r = re.compile(regexp) |
120 p = subprocess.Popen( | 137 p = subprocess.Popen( |
121 cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) | 138 cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT |
139 ) | |
122 s = p.communicate()[0] | 140 s = p.communicate()[0] |
123 ret = p.returncode | 141 ret = p.returncode |
124 return (ignorestatus or not ret) and r.search(s) | 142 return (ignorestatus or not ret) and r.search(s) |
125 | 143 |
144 | |
126 @check("baz", "GNU Arch baz client") | 145 @check("baz", "GNU Arch baz client") |
127 def has_baz(): | 146 def has_baz(): |
128 return matchoutput('baz --version 2>&1', br'baz Bazaar version') | 147 return matchoutput('baz --version 2>&1', br'baz Bazaar version') |
148 | |
129 | 149 |
130 @check("bzr", "Canonical's Bazaar client") | 150 @check("bzr", "Canonical's Bazaar client") |
131 def has_bzr(): | 151 def has_bzr(): |
132 try: | 152 try: |
133 import bzrlib | 153 import bzrlib |
134 import bzrlib.bzrdir | 154 import bzrlib.bzrdir |
135 import bzrlib.errors | 155 import bzrlib.errors |
136 import bzrlib.revision | 156 import bzrlib.revision |
137 import bzrlib.revisionspec | 157 import bzrlib.revisionspec |
158 | |
138 bzrlib.revisionspec.RevisionSpec | 159 bzrlib.revisionspec.RevisionSpec |
139 return bzrlib.__doc__ is not None | 160 return bzrlib.__doc__ is not None |
140 except (AttributeError, ImportError): | 161 except (AttributeError, ImportError): |
141 return False | 162 return False |
142 | 163 |
164 | |
143 @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,)) | 165 @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,)) |
144 def has_bzr_range(v): | 166 def has_bzr_range(v): |
145 major, minor = v.split('rc')[0].split('.')[0:2] | 167 major, minor = v.split('rc')[0].split('.')[0:2] |
146 try: | 168 try: |
147 import bzrlib | 169 import bzrlib |
148 return (bzrlib.__doc__ is not None | 170 |
149 and bzrlib.version_info[:2] >= (int(major), int(minor))) | 171 return bzrlib.__doc__ is not None and bzrlib.version_info[:2] >= ( |
150 except ImportError: | 172 int(major), |
151 return False | 173 int(minor), |
174 ) | |
175 except ImportError: | |
176 return False | |
177 | |
152 | 178 |
153 @check("chg", "running with chg") | 179 @check("chg", "running with chg") |
154 def has_chg(): | 180 def has_chg(): |
155 return 'CHGHG' in os.environ | 181 return 'CHGHG' in os.environ |
182 | |
156 | 183 |
157 @check("cvs", "cvs client/server") | 184 @check("cvs", "cvs client/server") |
158 def has_cvs(): | 185 def has_cvs(): |
159 re = br'Concurrent Versions System.*?server' | 186 re = br'Concurrent Versions System.*?server' |
160 return matchoutput('cvs --version 2>&1', re) and not has_msys() | 187 return matchoutput('cvs --version 2>&1', re) and not has_msys() |
161 | 188 |
189 | |
162 @check("cvs112", "cvs client/server 1.12.* (not cvsnt)") | 190 @check("cvs112", "cvs client/server 1.12.* (not cvsnt)") |
163 def has_cvs112(): | 191 def has_cvs112(): |
164 re = br'Concurrent Versions System \(CVS\) 1.12.*?server' | 192 re = br'Concurrent Versions System \(CVS\) 1.12.*?server' |
165 return matchoutput('cvs --version 2>&1', re) and not has_msys() | 193 return matchoutput('cvs --version 2>&1', re) and not has_msys() |
166 | 194 |
195 | |
167 @check("cvsnt", "cvsnt client/server") | 196 @check("cvsnt", "cvsnt client/server") |
168 def has_cvsnt(): | 197 def has_cvsnt(): |
169 re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)' | 198 re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)' |
170 return matchoutput('cvsnt --version 2>&1', re) | 199 return matchoutput('cvsnt --version 2>&1', re) |
171 | 200 |
201 | |
172 @check("darcs", "darcs client") | 202 @check("darcs", "darcs client") |
173 def has_darcs(): | 203 def has_darcs(): |
174 return matchoutput('darcs --version', br'\b2\.([2-9]|\d{2})', True) | 204 return matchoutput('darcs --version', br'\b2\.([2-9]|\d{2})', True) |
175 | 205 |
206 | |
176 @check("mtn", "monotone client (>= 1.0)") | 207 @check("mtn", "monotone client (>= 1.0)") |
177 def has_mtn(): | 208 def has_mtn(): |
178 return matchoutput('mtn --version', br'monotone', True) and not matchoutput( | 209 return matchoutput('mtn --version', br'monotone', True) and not matchoutput( |
179 'mtn --version', br'monotone 0\.', True) | 210 'mtn --version', br'monotone 0\.', True |
211 ) | |
212 | |
180 | 213 |
181 @check("eol-in-paths", "end-of-lines in paths") | 214 @check("eol-in-paths", "end-of-lines in paths") |
182 def has_eol_in_paths(): | 215 def has_eol_in_paths(): |
183 try: | 216 try: |
184 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r') | 217 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r') |
185 os.close(fd) | 218 os.close(fd) |
186 os.remove(path) | 219 os.remove(path) |
187 return True | 220 return True |
188 except (IOError, OSError): | 221 except (IOError, OSError): |
189 return False | 222 return False |
223 | |
190 | 224 |
191 @check("execbit", "executable bit") | 225 @check("execbit", "executable bit") |
192 def has_executablebit(): | 226 def has_executablebit(): |
193 try: | 227 try: |
194 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH | 228 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH |
196 try: | 230 try: |
197 os.close(fh) | 231 os.close(fh) |
198 m = os.stat(fn).st_mode & 0o777 | 232 m = os.stat(fn).st_mode & 0o777 |
199 new_file_has_exec = m & EXECFLAGS | 233 new_file_has_exec = m & EXECFLAGS |
200 os.chmod(fn, m ^ EXECFLAGS) | 234 os.chmod(fn, m ^ EXECFLAGS) |
201 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0o777) == m) | 235 exec_flags_cannot_flip = (os.stat(fn).st_mode & 0o777) == m |
202 finally: | 236 finally: |
203 os.unlink(fn) | 237 os.unlink(fn) |
204 except (IOError, OSError): | 238 except (IOError, OSError): |
205 # we don't care, the user probably won't be able to commit anyway | 239 # we don't care, the user probably won't be able to commit anyway |
206 return False | 240 return False |
207 return not (new_file_has_exec or exec_flags_cannot_flip) | 241 return not (new_file_has_exec or exec_flags_cannot_flip) |
242 | |
208 | 243 |
209 @check("icasefs", "case insensitive file system") | 244 @check("icasefs", "case insensitive file system") |
210 def has_icasefs(): | 245 def has_icasefs(): |
211 # Stolen from mercurial.util | 246 # Stolen from mercurial.util |
212 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix) | 247 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix) |
223 except OSError: | 258 except OSError: |
224 return False | 259 return False |
225 finally: | 260 finally: |
226 os.remove(path) | 261 os.remove(path) |
227 | 262 |
263 | |
228 @check("fifo", "named pipes") | 264 @check("fifo", "named pipes") |
229 def has_fifo(): | 265 def has_fifo(): |
230 if getattr(os, "mkfifo", None) is None: | 266 if getattr(os, "mkfifo", None) is None: |
231 return False | 267 return False |
232 name = tempfile.mktemp(dir='.', prefix=tempprefix) | 268 name = tempfile.mktemp(dir='.', prefix=tempprefix) |
235 os.unlink(name) | 271 os.unlink(name) |
236 return True | 272 return True |
237 except OSError: | 273 except OSError: |
238 return False | 274 return False |
239 | 275 |
276 | |
240 @check("killdaemons", 'killdaemons.py support') | 277 @check("killdaemons", 'killdaemons.py support') |
241 def has_killdaemons(): | 278 def has_killdaemons(): |
242 return True | 279 return True |
243 | 280 |
281 | |
244 @check("cacheable", "cacheable filesystem") | 282 @check("cacheable", "cacheable filesystem") |
245 def has_cacheable_fs(): | 283 def has_cacheable_fs(): |
246 from mercurial import util | 284 from mercurial import util |
247 | 285 |
248 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix) | 286 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix) |
250 try: | 288 try: |
251 return util.cachestat(path).cacheable() | 289 return util.cachestat(path).cacheable() |
252 finally: | 290 finally: |
253 os.remove(path) | 291 os.remove(path) |
254 | 292 |
293 | |
255 @check("lsprof", "python lsprof module") | 294 @check("lsprof", "python lsprof module") |
256 def has_lsprof(): | 295 def has_lsprof(): |
257 try: | 296 try: |
258 import _lsprof | 297 import _lsprof |
259 _lsprof.Profiler # silence unused import warning | 298 |
260 return True | 299 _lsprof.Profiler # silence unused import warning |
261 except ImportError: | 300 return True |
262 return False | 301 except ImportError: |
302 return False | |
303 | |
263 | 304 |
264 def gethgversion(): | 305 def gethgversion(): |
265 m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)') | 306 m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)') |
266 if not m: | 307 if not m: |
267 return (0, 0) | 308 return (0, 0) |
268 return (int(m.group(1)), int(m.group(2))) | 309 return (int(m.group(1)), int(m.group(2))) |
269 | 310 |
270 @checkvers("hg", "Mercurial >= %s", | 311 |
271 list([(1.0 * x) / 10 for x in range(9, 99)])) | 312 @checkvers( |
313 "hg", "Mercurial >= %s", list([(1.0 * x) / 10 for x in range(9, 99)]) | |
314 ) | |
272 def has_hg_range(v): | 315 def has_hg_range(v): |
273 major, minor = v.split('.')[0:2] | 316 major, minor = v.split('.')[0:2] |
274 return gethgversion() >= (int(major), int(minor)) | 317 return gethgversion() >= (int(major), int(minor)) |
275 | 318 |
319 | |
276 @check("hg08", "Mercurial >= 0.8") | 320 @check("hg08", "Mercurial >= 0.8") |
277 def has_hg08(): | 321 def has_hg08(): |
278 if checks["hg09"][0](): | 322 if checks["hg09"][0](): |
279 return True | 323 return True |
280 return matchoutput('hg help annotate 2>&1', '--date') | 324 return matchoutput('hg help annotate 2>&1', '--date') |
281 | 325 |
326 | |
282 @check("hg07", "Mercurial >= 0.7") | 327 @check("hg07", "Mercurial >= 0.7") |
283 def has_hg07(): | 328 def has_hg07(): |
284 if checks["hg08"][0](): | 329 if checks["hg08"][0](): |
285 return True | 330 return True |
286 return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM') | 331 return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM') |
287 | 332 |
333 | |
288 @check("hg06", "Mercurial >= 0.6") | 334 @check("hg06", "Mercurial >= 0.6") |
289 def has_hg06(): | 335 def has_hg06(): |
290 if checks["hg07"][0](): | 336 if checks["hg07"][0](): |
291 return True | 337 return True |
292 return matchoutput('hg --version --quiet 2>&1', 'Mercurial version') | 338 return matchoutput('hg --version --quiet 2>&1', 'Mercurial version') |
293 | 339 |
340 | |
294 @check("gettext", "GNU Gettext (msgfmt)") | 341 @check("gettext", "GNU Gettext (msgfmt)") |
295 def has_gettext(): | 342 def has_gettext(): |
296 return matchoutput('msgfmt --version', br'GNU gettext-tools') | 343 return matchoutput('msgfmt --version', br'GNU gettext-tools') |
297 | 344 |
345 | |
298 @check("git", "git command line client") | 346 @check("git", "git command line client") |
299 def has_git(): | 347 def has_git(): |
300 return matchoutput('git --version 2>&1', br'^git version') | 348 return matchoutput('git --version 2>&1', br'^git version') |
349 | |
301 | 350 |
302 def getgitversion(): | 351 def getgitversion(): |
303 m = matchoutput('git --version 2>&1', br'git version (\d+)\.(\d+)') | 352 m = matchoutput('git --version 2>&1', br'git version (\d+)\.(\d+)') |
304 if not m: | 353 if not m: |
305 return (0, 0) | 354 return (0, 0) |
306 return (int(m.group(1)), int(m.group(2))) | 355 return (int(m.group(1)), int(m.group(2))) |
356 | |
307 | 357 |
308 # https://github.com/git-lfs/lfs-test-server | 358 # https://github.com/git-lfs/lfs-test-server |
309 @check("lfs-test-server", "git-lfs test server") | 359 @check("lfs-test-server", "git-lfs test server") |
310 def has_lfsserver(): | 360 def has_lfsserver(): |
311 exe = 'lfs-test-server' | 361 exe = 'lfs-test-server' |
314 return any( | 364 return any( |
315 os.access(os.path.join(path, exe), os.X_OK) | 365 os.access(os.path.join(path, exe), os.X_OK) |
316 for path in os.environ["PATH"].split(os.pathsep) | 366 for path in os.environ["PATH"].split(os.pathsep) |
317 ) | 367 ) |
318 | 368 |
369 | |
319 @checkvers("git", "git client (with ext::sh support) version >= %s", (1.9,)) | 370 @checkvers("git", "git client (with ext::sh support) version >= %s", (1.9,)) |
320 def has_git_range(v): | 371 def has_git_range(v): |
321 major, minor = v.split('.')[0:2] | 372 major, minor = v.split('.')[0:2] |
322 return getgitversion() >= (int(major), int(minor)) | 373 return getgitversion() >= (int(major), int(minor)) |
323 | 374 |
375 | |
324 @check("docutils", "Docutils text processing library") | 376 @check("docutils", "Docutils text processing library") |
325 def has_docutils(): | 377 def has_docutils(): |
326 try: | 378 try: |
327 import docutils.core | 379 import docutils.core |
328 docutils.core.publish_cmdline # silence unused import | 380 |
329 return True | 381 docutils.core.publish_cmdline # silence unused import |
330 except ImportError: | 382 return True |
331 return False | 383 except ImportError: |
384 return False | |
385 | |
332 | 386 |
333 def getsvnversion(): | 387 def getsvnversion(): |
334 m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)') | 388 m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)') |
335 if not m: | 389 if not m: |
336 return (0, 0) | 390 return (0, 0) |
337 return (int(m.group(1)), int(m.group(2))) | 391 return (int(m.group(1)), int(m.group(2))) |
338 | 392 |
393 | |
339 @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5)) | 394 @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5)) |
340 def has_svn_range(v): | 395 def has_svn_range(v): |
341 major, minor = v.split('.')[0:2] | 396 major, minor = v.split('.')[0:2] |
342 return getsvnversion() >= (int(major), int(minor)) | 397 return getsvnversion() >= (int(major), int(minor)) |
343 | 398 |
399 | |
344 @check("svn", "subversion client and admin tools") | 400 @check("svn", "subversion client and admin tools") |
345 def has_svn(): | 401 def has_svn(): |
346 return (matchoutput('svn --version 2>&1', br'^svn, version') and | 402 return matchoutput('svn --version 2>&1', br'^svn, version') and matchoutput( |
347 matchoutput('svnadmin --version 2>&1', br'^svnadmin, version')) | 403 'svnadmin --version 2>&1', br'^svnadmin, version' |
404 ) | |
405 | |
348 | 406 |
349 @check("svn-bindings", "subversion python bindings") | 407 @check("svn-bindings", "subversion python bindings") |
350 def has_svn_bindings(): | 408 def has_svn_bindings(): |
351 try: | 409 try: |
352 import svn.core | 410 import svn.core |
411 | |
353 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR | 412 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR |
354 if version < (1, 4): | 413 if version < (1, 4): |
355 return False | 414 return False |
356 return True | 415 return True |
357 except ImportError: | 416 except ImportError: |
358 return False | 417 return False |
359 | 418 |
419 | |
360 @check("p4", "Perforce server and client") | 420 @check("p4", "Perforce server and client") |
361 def has_p4(): | 421 def has_p4(): |
362 return (matchoutput('p4 -V', br'Rev\. P4/') and | 422 return matchoutput('p4 -V', br'Rev\. P4/') and matchoutput( |
363 matchoutput('p4d -V', br'Rev\. P4D/')) | 423 'p4d -V', br'Rev\. P4D/' |
424 ) | |
425 | |
364 | 426 |
365 @check("symlink", "symbolic links") | 427 @check("symlink", "symbolic links") |
366 def has_symlink(): | 428 def has_symlink(): |
367 if getattr(os, "symlink", None) is None: | 429 if getattr(os, "symlink", None) is None: |
368 return False | 430 return False |
372 os.unlink(name) | 434 os.unlink(name) |
373 return True | 435 return True |
374 except (OSError, AttributeError): | 436 except (OSError, AttributeError): |
375 return False | 437 return False |
376 | 438 |
439 | |
377 @check("hardlink", "hardlinks") | 440 @check("hardlink", "hardlinks") |
378 def has_hardlink(): | 441 def has_hardlink(): |
379 from mercurial import util | 442 from mercurial import util |
443 | |
380 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix) | 444 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix) |
381 os.close(fh) | 445 os.close(fh) |
382 name = tempfile.mktemp(dir='.', prefix=tempprefix) | 446 name = tempfile.mktemp(dir='.', prefix=tempprefix) |
383 try: | 447 try: |
384 util.oslink(_bytespath(fn), _bytespath(name)) | 448 util.oslink(_bytespath(fn), _bytespath(name)) |
387 except OSError: | 451 except OSError: |
388 return False | 452 return False |
389 finally: | 453 finally: |
390 os.unlink(fn) | 454 os.unlink(fn) |
391 | 455 |
456 | |
392 @check("hardlink-whitelisted", "hardlinks on whitelisted filesystems") | 457 @check("hardlink-whitelisted", "hardlinks on whitelisted filesystems") |
393 def has_hardlink_whitelisted(): | 458 def has_hardlink_whitelisted(): |
394 from mercurial import util | 459 from mercurial import util |
460 | |
395 try: | 461 try: |
396 fstype = util.getfstype(b'.') | 462 fstype = util.getfstype(b'.') |
397 except OSError: | 463 except OSError: |
398 return False | 464 return False |
399 return fstype in util._hardlinkfswhitelist | 465 return fstype in util._hardlinkfswhitelist |
466 | |
400 | 467 |
401 @check("rmcwd", "can remove current working directory") | 468 @check("rmcwd", "can remove current working directory") |
402 def has_rmcwd(): | 469 def has_rmcwd(): |
403 ocwd = os.getcwd() | 470 ocwd = os.getcwd() |
404 temp = tempfile.mkdtemp(dir='.', prefix=tempprefix) | 471 temp = tempfile.mkdtemp(dir='.', prefix=tempprefix) |
416 try: | 483 try: |
417 os.rmdir(temp) | 484 os.rmdir(temp) |
418 except OSError: | 485 except OSError: |
419 pass | 486 pass |
420 | 487 |
488 | |
421 @check("tla", "GNU Arch tla client") | 489 @check("tla", "GNU Arch tla client") |
422 def has_tla(): | 490 def has_tla(): |
423 return matchoutput('tla --version 2>&1', br'The GNU Arch Revision') | 491 return matchoutput('tla --version 2>&1', br'The GNU Arch Revision') |
424 | 492 |
493 | |
425 @check("gpg", "gpg client") | 494 @check("gpg", "gpg client") |
426 def has_gpg(): | 495 def has_gpg(): |
427 return matchoutput('gpg --version 2>&1', br'GnuPG') | 496 return matchoutput('gpg --version 2>&1', br'GnuPG') |
428 | 497 |
498 | |
429 @check("gpg2", "gpg client v2") | 499 @check("gpg2", "gpg client v2") |
430 def has_gpg2(): | 500 def has_gpg2(): |
431 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.') | 501 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.') |
432 | 502 |
503 | |
433 @check("gpg21", "gpg client v2.1+") | 504 @check("gpg21", "gpg client v2.1+") |
434 def has_gpg21(): | 505 def has_gpg21(): |
435 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.(?!0)') | 506 return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.(?!0)') |
507 | |
436 | 508 |
437 @check("unix-permissions", "unix-style permissions") | 509 @check("unix-permissions", "unix-style permissions") |
438 def has_unix_permissions(): | 510 def has_unix_permissions(): |
439 d = tempfile.mkdtemp(dir='.', prefix=tempprefix) | 511 d = tempfile.mkdtemp(dir='.', prefix=tempprefix) |
440 try: | 512 try: |
449 return False | 521 return False |
450 return True | 522 return True |
451 finally: | 523 finally: |
452 os.rmdir(d) | 524 os.rmdir(d) |
453 | 525 |
526 | |
454 @check("unix-socket", "AF_UNIX socket family") | 527 @check("unix-socket", "AF_UNIX socket family") |
455 def has_unix_socket(): | 528 def has_unix_socket(): |
456 return getattr(socket, 'AF_UNIX', None) is not None | 529 return getattr(socket, 'AF_UNIX', None) is not None |
457 | 530 |
531 | |
458 @check("root", "root permissions") | 532 @check("root", "root permissions") |
459 def has_root(): | 533 def has_root(): |
460 return getattr(os, 'geteuid', None) and os.geteuid() == 0 | 534 return getattr(os, 'geteuid', None) and os.geteuid() == 0 |
461 | 535 |
536 | |
462 @check("pyflakes", "Pyflakes python linter") | 537 @check("pyflakes", "Pyflakes python linter") |
463 def has_pyflakes(): | 538 def has_pyflakes(): |
464 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"", | 539 return matchoutput( |
465 br"<stdin>:1: 're' imported but unused", | 540 "sh -c \"echo 'import re' 2>&1 | pyflakes\"", |
466 True) | 541 br"<stdin>:1: 're' imported but unused", |
542 True, | |
543 ) | |
544 | |
467 | 545 |
468 @check("pylint", "Pylint python linter") | 546 @check("pylint", "Pylint python linter") |
469 def has_pylint(): | 547 def has_pylint(): |
470 return matchoutput("pylint --help", | 548 return matchoutput("pylint --help", br"Usage: pylint", True) |
471 br"Usage: pylint", | 549 |
472 True) | |
473 | 550 |
474 @check("clang-format", "clang-format C code formatter") | 551 @check("clang-format", "clang-format C code formatter") |
475 def has_clang_format(): | 552 def has_clang_format(): |
476 m = matchoutput('clang-format --version', br'clang-format version (\d)') | 553 m = matchoutput('clang-format --version', br'clang-format version (\d)') |
477 # style changed somewhere between 4.x and 6.x | 554 # style changed somewhere between 4.x and 6.x |
478 return m and int(m.group(1)) >= 6 | 555 return m and int(m.group(1)) >= 6 |
479 | 556 |
557 | |
480 @check("jshint", "JSHint static code analysis tool") | 558 @check("jshint", "JSHint static code analysis tool") |
481 def has_jshint(): | 559 def has_jshint(): |
482 return matchoutput("jshint --version 2>&1", br"jshint v") | 560 return matchoutput("jshint --version 2>&1", br"jshint v") |
483 | 561 |
562 | |
484 @check("pygments", "Pygments source highlighting library") | 563 @check("pygments", "Pygments source highlighting library") |
485 def has_pygments(): | 564 def has_pygments(): |
486 try: | 565 try: |
487 import pygments | 566 import pygments |
488 pygments.highlight # silence unused import warning | 567 |
489 return True | 568 pygments.highlight # silence unused import warning |
490 except ImportError: | 569 return True |
491 return False | 570 except ImportError: |
571 return False | |
572 | |
492 | 573 |
493 @check("outer-repo", "outer repo") | 574 @check("outer-repo", "outer repo") |
494 def has_outer_repo(): | 575 def has_outer_repo(): |
495 # failing for other reasons than 'no repo' imply that there is a repo | 576 # failing for other reasons than 'no repo' imply that there is a repo |
496 return not matchoutput('hg root 2>&1', | 577 return not matchoutput('hg root 2>&1', br'abort: no repository found', True) |
497 br'abort: no repository found', True) | 578 |
498 | 579 |
499 @check("ssl", "ssl module available") | 580 @check("ssl", "ssl module available") |
500 def has_ssl(): | 581 def has_ssl(): |
501 try: | 582 try: |
502 import ssl | 583 import ssl |
584 | |
503 ssl.CERT_NONE | 585 ssl.CERT_NONE |
504 return True | 586 return True |
505 except ImportError: | 587 except ImportError: |
506 return False | 588 return False |
589 | |
507 | 590 |
508 @check("sslcontext", "python >= 2.7.9 ssl") | 591 @check("sslcontext", "python >= 2.7.9 ssl") |
509 def has_sslcontext(): | 592 def has_sslcontext(): |
510 try: | 593 try: |
511 import ssl | 594 import ssl |
595 | |
512 ssl.SSLContext | 596 ssl.SSLContext |
513 return True | 597 return True |
514 except (ImportError, AttributeError): | 598 except (ImportError, AttributeError): |
515 return False | 599 return False |
600 | |
516 | 601 |
517 @check("defaultcacerts", "can verify SSL certs by system's CA certs store") | 602 @check("defaultcacerts", "can verify SSL certs by system's CA certs store") |
518 def has_defaultcacerts(): | 603 def has_defaultcacerts(): |
519 from mercurial import sslutil, ui as uimod | 604 from mercurial import sslutil, ui as uimod |
605 | |
520 ui = uimod.ui.load() | 606 ui = uimod.ui.load() |
521 return sslutil._defaultcacerts(ui) or sslutil._canloaddefaultcerts | 607 return sslutil._defaultcacerts(ui) or sslutil._canloaddefaultcerts |
608 | |
522 | 609 |
523 @check("defaultcacertsloaded", "detected presence of loaded system CA certs") | 610 @check("defaultcacertsloaded", "detected presence of loaded system CA certs") |
524 def has_defaultcacertsloaded(): | 611 def has_defaultcacertsloaded(): |
525 import ssl | 612 import ssl |
526 from mercurial import sslutil, ui as uimod | 613 from mercurial import sslutil, ui as uimod |
538 else: | 625 else: |
539 ctx.load_default_certs() | 626 ctx.load_default_certs() |
540 | 627 |
541 return len(ctx.get_ca_certs()) > 0 | 628 return len(ctx.get_ca_certs()) > 0 |
542 | 629 |
630 | |
543 @check("tls1.2", "TLS 1.2 protocol support") | 631 @check("tls1.2", "TLS 1.2 protocol support") |
544 def has_tls1_2(): | 632 def has_tls1_2(): |
545 from mercurial import sslutil | 633 from mercurial import sslutil |
634 | |
546 return b'tls1.2' in sslutil.supportedprotocols | 635 return b'tls1.2' in sslutil.supportedprotocols |
636 | |
547 | 637 |
548 @check("windows", "Windows") | 638 @check("windows", "Windows") |
549 def has_windows(): | 639 def has_windows(): |
550 return os.name == 'nt' | 640 return os.name == 'nt' |
551 | 641 |
642 | |
552 @check("system-sh", "system() uses sh") | 643 @check("system-sh", "system() uses sh") |
553 def has_system_sh(): | 644 def has_system_sh(): |
554 return os.name != 'nt' | 645 return os.name != 'nt' |
555 | 646 |
647 | |
556 @check("serve", "platform and python can manage 'hg serve -d'") | 648 @check("serve", "platform and python can manage 'hg serve -d'") |
557 def has_serve(): | 649 def has_serve(): |
558 return True | 650 return True |
651 | |
559 | 652 |
560 @check("test-repo", "running tests from repository") | 653 @check("test-repo", "running tests from repository") |
561 def has_test_repo(): | 654 def has_test_repo(): |
562 t = os.environ["TESTDIR"] | 655 t = os.environ["TESTDIR"] |
563 return os.path.isdir(os.path.join(t, "..", ".hg")) | 656 return os.path.isdir(os.path.join(t, "..", ".hg")) |
564 | 657 |
658 | |
565 @check("tic", "terminfo compiler and curses module") | 659 @check("tic", "terminfo compiler and curses module") |
566 def has_tic(): | 660 def has_tic(): |
567 try: | 661 try: |
568 import curses | 662 import curses |
663 | |
569 curses.COLOR_BLUE | 664 curses.COLOR_BLUE |
570 return matchoutput('test -x "`which tic`"', br'') | 665 return matchoutput('test -x "`which tic`"', br'') |
571 except ImportError: | 666 except ImportError: |
572 return False | 667 return False |
668 | |
573 | 669 |
574 @check("msys", "Windows with MSYS") | 670 @check("msys", "Windows with MSYS") |
575 def has_msys(): | 671 def has_msys(): |
576 return os.getenv('MSYSTEM') | 672 return os.getenv('MSYSTEM') |
577 | 673 |
674 | |
578 @check("aix", "AIX") | 675 @check("aix", "AIX") |
579 def has_aix(): | 676 def has_aix(): |
580 return sys.platform.startswith("aix") | 677 return sys.platform.startswith("aix") |
581 | 678 |
679 | |
582 @check("osx", "OS X") | 680 @check("osx", "OS X") |
583 def has_osx(): | 681 def has_osx(): |
584 return sys.platform == 'darwin' | 682 return sys.platform == 'darwin' |
585 | 683 |
684 | |
586 @check("osxpackaging", "OS X packaging tools") | 685 @check("osxpackaging", "OS X packaging tools") |
587 def has_osxpackaging(): | 686 def has_osxpackaging(): |
588 try: | 687 try: |
589 return (matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1) | 688 return ( |
590 and matchoutput( | 689 matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1) |
591 'productbuild', br'Usage: productbuild ', | 690 and matchoutput( |
592 ignorestatus=1) | 691 'productbuild', br'Usage: productbuild ', ignorestatus=1 |
593 and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1) | 692 ) |
594 and matchoutput( | 693 and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1) |
595 'xar --help', br'Usage: xar', ignorestatus=1)) | 694 and matchoutput('xar --help', br'Usage: xar', ignorestatus=1) |
596 except ImportError: | 695 ) |
597 return False | 696 except ImportError: |
697 return False | |
698 | |
598 | 699 |
599 @check('linuxormacos', 'Linux or MacOS') | 700 @check('linuxormacos', 'Linux or MacOS') |
600 def has_linuxormacos(): | 701 def has_linuxormacos(): |
601 # This isn't a perfect test for MacOS. But it is sufficient for our needs. | 702 # This isn't a perfect test for MacOS. But it is sufficient for our needs. |
602 return sys.platform.startswith(('linux', 'darwin')) | 703 return sys.platform.startswith(('linux', 'darwin')) |
704 | |
603 | 705 |
604 @check("docker", "docker support") | 706 @check("docker", "docker support") |
605 def has_docker(): | 707 def has_docker(): |
606 pat = br'A self-sufficient runtime for' | 708 pat = br'A self-sufficient runtime for' |
607 if matchoutput('docker --help', pat): | 709 if matchoutput('docker --help', pat): |
616 return False | 718 return False |
617 | 719 |
618 return True | 720 return True |
619 return False | 721 return False |
620 | 722 |
723 | |
621 @check("debhelper", "debian packaging tools") | 724 @check("debhelper", "debian packaging tools") |
622 def has_debhelper(): | 725 def has_debhelper(): |
623 # Some versions of dpkg say `dpkg', some say 'dpkg' (` vs ' on the first | 726 # Some versions of dpkg say `dpkg', some say 'dpkg' (` vs ' on the first |
624 # quote), so just accept anything in that spot. | 727 # quote), so just accept anything in that spot. |
625 dpkg = matchoutput('dpkg --version', | 728 dpkg = matchoutput( |
626 br"Debian .dpkg' package management program") | 729 'dpkg --version', br"Debian .dpkg' package management program" |
627 dh = matchoutput('dh --help', | 730 ) |
628 br'dh is a part of debhelper.', ignorestatus=True) | 731 dh = matchoutput( |
629 dh_py2 = matchoutput('dh_python2 --help', | 732 'dh --help', br'dh is a part of debhelper.', ignorestatus=True |
630 br'other supported Python versions') | 733 ) |
734 dh_py2 = matchoutput( | |
735 'dh_python2 --help', br'other supported Python versions' | |
736 ) | |
631 # debuild comes from the 'devscripts' package, though you might want | 737 # debuild comes from the 'devscripts' package, though you might want |
632 # the 'build-debs' package instead, which has a dependency on devscripts. | 738 # the 'build-debs' package instead, which has a dependency on devscripts. |
633 debuild = matchoutput('debuild --help', | 739 debuild = matchoutput( |
634 br'to run debian/rules with given parameter') | 740 'debuild --help', br'to run debian/rules with given parameter' |
741 ) | |
635 return dpkg and dh and dh_py2 and debuild | 742 return dpkg and dh and dh_py2 and debuild |
636 | 743 |
637 @check("debdeps", | 744 |
638 "debian build dependencies (run dpkg-checkbuilddeps in contrib/)") | 745 @check( |
746 "debdeps", "debian build dependencies (run dpkg-checkbuilddeps in contrib/)" | |
747 ) | |
639 def has_debdeps(): | 748 def has_debdeps(): |
640 # just check exit status (ignoring output) | 749 # just check exit status (ignoring output) |
641 path = '%s/../contrib/packaging/debian/control' % os.environ['TESTDIR'] | 750 path = '%s/../contrib/packaging/debian/control' % os.environ['TESTDIR'] |
642 return matchoutput('dpkg-checkbuilddeps %s' % path, br'') | 751 return matchoutput('dpkg-checkbuilddeps %s' % path, br'') |
643 | 752 |
753 | |
644 @check("demandimport", "demandimport enabled") | 754 @check("demandimport", "demandimport enabled") |
645 def has_demandimport(): | 755 def has_demandimport(): |
646 # chg disables demandimport intentionally for performance wins. | 756 # chg disables demandimport intentionally for performance wins. |
647 return ((not has_chg()) and os.environ.get('HGDEMANDIMPORT') != 'disable') | 757 return (not has_chg()) and os.environ.get('HGDEMANDIMPORT') != 'disable' |
758 | |
648 | 759 |
649 @checkvers("py", "Python >= %s", (2.7, 3.5, 3.6, 3.7, 3.8, 3.9)) | 760 @checkvers("py", "Python >= %s", (2.7, 3.5, 3.6, 3.7, 3.8, 3.9)) |
650 def has_python_range(v): | 761 def has_python_range(v): |
651 major, minor = v.split('.')[0:2] | 762 major, minor = v.split('.')[0:2] |
652 py_major, py_minor = sys.version_info.major, sys.version_info.minor | 763 py_major, py_minor = sys.version_info.major, sys.version_info.minor |
653 | 764 |
654 return (py_major, py_minor) >= (int(major), int(minor)) | 765 return (py_major, py_minor) >= (int(major), int(minor)) |
655 | 766 |
767 | |
656 @check("py3", "running with Python 3.x") | 768 @check("py3", "running with Python 3.x") |
657 def has_py3(): | 769 def has_py3(): |
658 return 3 == sys.version_info[0] | 770 return 3 == sys.version_info[0] |
659 | 771 |
772 | |
660 @check("py3exe", "a Python 3.x interpreter is available") | 773 @check("py3exe", "a Python 3.x interpreter is available") |
661 def has_python3exe(): | 774 def has_python3exe(): |
662 return matchoutput('python3 -V', br'^Python 3.(5|6|7|8|9)') | 775 return matchoutput('python3 -V', br'^Python 3.(5|6|7|8|9)') |
663 | 776 |
777 | |
664 @check("pure", "running with pure Python code") | 778 @check("pure", "running with pure Python code") |
665 def has_pure(): | 779 def has_pure(): |
666 return any([ | 780 return any( |
667 os.environ.get("HGMODULEPOLICY") == "py", | 781 [ |
668 os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure", | 782 os.environ.get("HGMODULEPOLICY") == "py", |
669 ]) | 783 os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure", |
784 ] | |
785 ) | |
786 | |
670 | 787 |
671 @check("slow", "allow slow tests (use --allow-slow-tests)") | 788 @check("slow", "allow slow tests (use --allow-slow-tests)") |
672 def has_slow(): | 789 def has_slow(): |
673 return os.environ.get('HGTEST_SLOW') == 'slow' | 790 return os.environ.get('HGTEST_SLOW') == 'slow' |
674 | 791 |
792 | |
675 @check("hypothesis", "Hypothesis automated test generation") | 793 @check("hypothesis", "Hypothesis automated test generation") |
676 def has_hypothesis(): | 794 def has_hypothesis(): |
677 try: | 795 try: |
678 import hypothesis | 796 import hypothesis |
797 | |
679 hypothesis.given | 798 hypothesis.given |
680 return True | 799 return True |
681 except ImportError: | 800 except ImportError: |
682 return False | 801 return False |
802 | |
683 | 803 |
684 @check("unziplinks", "unzip(1) understands and extracts symlinks") | 804 @check("unziplinks", "unzip(1) understands and extracts symlinks") |
685 def unzip_understands_symlinks(): | 805 def unzip_understands_symlinks(): |
686 return matchoutput('unzip --help', br'Info-ZIP') | 806 return matchoutput('unzip --help', br'Info-ZIP') |
687 | 807 |
808 | |
688 @check("zstd", "zstd Python module available") | 809 @check("zstd", "zstd Python module available") |
689 def has_zstd(): | 810 def has_zstd(): |
690 try: | 811 try: |
691 import mercurial.zstd | 812 import mercurial.zstd |
813 | |
692 mercurial.zstd.__version__ | 814 mercurial.zstd.__version__ |
693 return True | 815 return True |
694 except ImportError: | 816 except ImportError: |
695 return False | 817 return False |
818 | |
696 | 819 |
697 @check("devfull", "/dev/full special file") | 820 @check("devfull", "/dev/full special file") |
698 def has_dev_full(): | 821 def has_dev_full(): |
699 return os.path.exists('/dev/full') | 822 return os.path.exists('/dev/full') |
700 | 823 |
824 | |
701 @check("virtualenv", "Python virtualenv support") | 825 @check("virtualenv", "Python virtualenv support") |
702 def has_virtualenv(): | 826 def has_virtualenv(): |
703 try: | 827 try: |
704 import virtualenv | 828 import virtualenv |
829 | |
705 virtualenv.ACTIVATE_SH | 830 virtualenv.ACTIVATE_SH |
706 return True | 831 return True |
707 except ImportError: | 832 except ImportError: |
708 return False | 833 return False |
834 | |
709 | 835 |
710 @check("fsmonitor", "running tests with fsmonitor") | 836 @check("fsmonitor", "running tests with fsmonitor") |
711 def has_fsmonitor(): | 837 def has_fsmonitor(): |
712 return 'HGFSMONITOR_TESTS' in os.environ | 838 return 'HGFSMONITOR_TESTS' in os.environ |
713 | 839 |
840 | |
714 @check("fuzzywuzzy", "Fuzzy string matching library") | 841 @check("fuzzywuzzy", "Fuzzy string matching library") |
715 def has_fuzzywuzzy(): | 842 def has_fuzzywuzzy(): |
716 try: | 843 try: |
717 import fuzzywuzzy | 844 import fuzzywuzzy |
845 | |
718 fuzzywuzzy.__version__ | 846 fuzzywuzzy.__version__ |
719 return True | 847 return True |
720 except ImportError: | 848 except ImportError: |
721 return False | 849 return False |
850 | |
722 | 851 |
723 @check("clang-libfuzzer", "clang new enough to include libfuzzer") | 852 @check("clang-libfuzzer", "clang new enough to include libfuzzer") |
724 def has_clang_libfuzzer(): | 853 def has_clang_libfuzzer(): |
725 mat = matchoutput('clang --version', br'clang version (\d)') | 854 mat = matchoutput('clang --version', br'clang version (\d)') |
726 if mat: | 855 if mat: |
727 # libfuzzer is new in clang 6 | 856 # libfuzzer is new in clang 6 |
728 return int(mat.group(1)) > 5 | 857 return int(mat.group(1)) > 5 |
729 return False | 858 return False |
730 | 859 |
860 | |
731 @check("clang-6.0", "clang 6.0 with version suffix (libfuzzer included)") | 861 @check("clang-6.0", "clang 6.0 with version suffix (libfuzzer included)") |
732 def has_clang60(): | 862 def has_clang60(): |
733 return matchoutput('clang-6.0 --version', br'clang version 6\.') | 863 return matchoutput('clang-6.0 --version', br'clang version 6\.') |
734 | 864 |
865 | |
735 @check("xdiff", "xdiff algorithm") | 866 @check("xdiff", "xdiff algorithm") |
736 def has_xdiff(): | 867 def has_xdiff(): |
737 try: | 868 try: |
738 from mercurial import policy | 869 from mercurial import policy |
870 | |
739 bdiff = policy.importmod('bdiff') | 871 bdiff = policy.importmod('bdiff') |
740 return bdiff.xdiffblocks(b'', b'') == [(0, 0, 0, 0)] | 872 return bdiff.xdiffblocks(b'', b'') == [(0, 0, 0, 0)] |
741 except (ImportError, AttributeError): | 873 except (ImportError, AttributeError): |
742 return False | 874 return False |
743 | 875 |
876 | |
744 @check('extraextensions', 'whether tests are running with extra extensions') | 877 @check('extraextensions', 'whether tests are running with extra extensions') |
745 def has_extraextensions(): | 878 def has_extraextensions(): |
746 return 'HGTESTEXTRAEXTENSIONS' in os.environ | 879 return 'HGTESTEXTRAEXTENSIONS' in os.environ |
880 | |
747 | 881 |
748 def getrepofeatures(): | 882 def getrepofeatures(): |
749 """Obtain set of repository features in use. | 883 """Obtain set of repository features in use. |
750 | 884 |
751 HGREPOFEATURES can be used to define or remove features. It contains | 885 HGREPOFEATURES can be used to define or remove features. It contains |
781 else: | 915 else: |
782 features.add(imply) | 916 features.add(imply) |
783 | 917 |
784 return features | 918 return features |
785 | 919 |
920 | |
786 @check('reporevlogstore', 'repository using the default revlog store') | 921 @check('reporevlogstore', 'repository using the default revlog store') |
787 def has_reporevlogstore(): | 922 def has_reporevlogstore(): |
788 return 'revlogstore' in getrepofeatures() | 923 return 'revlogstore' in getrepofeatures() |
789 | 924 |
925 | |
790 @check('reposimplestore', 'repository using simple storage extension') | 926 @check('reposimplestore', 'repository using simple storage extension') |
791 def has_reposimplestore(): | 927 def has_reposimplestore(): |
792 return 'simplestore' in getrepofeatures() | 928 return 'simplestore' in getrepofeatures() |
793 | 929 |
930 | |
794 @check('repobundlerepo', 'whether we can open bundle files as repos') | 931 @check('repobundlerepo', 'whether we can open bundle files as repos') |
795 def has_repobundlerepo(): | 932 def has_repobundlerepo(): |
796 return 'bundlerepo' in getrepofeatures() | 933 return 'bundlerepo' in getrepofeatures() |
797 | 934 |
935 | |
798 @check('repofncache', 'repository has an fncache') | 936 @check('repofncache', 'repository has an fncache') |
799 def has_repofncache(): | 937 def has_repofncache(): |
800 return 'fncache' in getrepofeatures() | 938 return 'fncache' in getrepofeatures() |
801 | 939 |
940 | |
802 @check('sqlite', 'sqlite3 module is available') | 941 @check('sqlite', 'sqlite3 module is available') |
803 def has_sqlite(): | 942 def has_sqlite(): |
804 try: | 943 try: |
805 import sqlite3 | 944 import sqlite3 |
945 | |
806 version = sqlite3.sqlite_version_info | 946 version = sqlite3.sqlite_version_info |
807 except ImportError: | 947 except ImportError: |
808 return False | 948 return False |
809 | 949 |
810 if version < (3, 8, 3): | 950 if version < (3, 8, 3): |
811 # WITH clause not supported | 951 # WITH clause not supported |
812 return False | 952 return False |
813 | 953 |
814 return matchoutput('sqlite3 -version', br'^3\.\d+') | 954 return matchoutput('sqlite3 -version', br'^3\.\d+') |
815 | 955 |
956 | |
816 @check('vcr', 'vcr http mocking library') | 957 @check('vcr', 'vcr http mocking library') |
817 def has_vcr(): | 958 def has_vcr(): |
818 try: | 959 try: |
819 import vcr | 960 import vcr |
961 | |
820 vcr.VCR | 962 vcr.VCR |
821 return True | 963 return True |
822 except (ImportError, AttributeError): | 964 except (ImportError, AttributeError): |
823 pass | 965 pass |
824 return False | 966 return False |
967 | |
825 | 968 |
826 @check('emacs', 'GNU Emacs') | 969 @check('emacs', 'GNU Emacs') |
827 def has_emacs(): | 970 def has_emacs(): |
828 # Our emacs lisp uses `with-eval-after-load` which is new in emacs | 971 # Our emacs lisp uses `with-eval-after-load` which is new in emacs |
829 # 24.4, so we allow emacs 24.4, 24.5, and 25+ (24.5 was the last | 972 # 24.4, so we allow emacs 24.4, 24.5, and 25+ (24.5 was the last |