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