Mercurial > public > mercurial-scm > hg-stable
diff 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 |
line wrap: on
line diff
--- a/tests/hghave.py Sat Oct 05 10:29:34 2019 -0400 +++ b/tests/hghave.py Sun Oct 06 09:45:02 2019 -0400 @@ -17,6 +17,7 @@ try: import msvcrt + msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY) msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY) except ImportError: @@ -26,6 +27,7 @@ stderr = getattr(sys.stderr, 'buffer', sys.stderr) if sys.version_info[0] >= 3: + def _bytespath(p): if p is None: return p @@ -35,35 +37,47 @@ if p is None: return p return p.decode('utf-8') + + else: + def _bytespath(p): return p _strpath = _bytespath + def check(name, desc): """Registers a check function for a feature.""" + def decorator(func): checks[name] = (func, desc) return func + return decorator + def checkvers(name, desc, vers): """Registers a check function for each of a series of versions. vers can be a list or an iterator""" + def decorator(func): def funcv(v): def f(): return func(v) + return f + for v in vers: v = str(v) f = funcv(v) checks['%s%s' % (name, v.replace('.', ''))] = (f, desc % v) return func + return decorator + def checkfeatures(features): result = { 'error': [], @@ -94,13 +108,15 @@ return result + def require(features): """Require that features are available, exiting if not.""" result = checkfeatures(features) for missing in result['missing']: - stderr.write(('skipped: unknown feature: %s\n' - % missing).encode('utf-8')) + stderr.write( + ('skipped: unknown feature: %s\n' % missing).encode('utf-8') + ) for msg in result['skipped']: stderr.write(('skipped: %s\n' % msg).encode('utf-8')) for msg in result['error']: @@ -112,21 +128,25 @@ if result['skipped'] or result['error']: sys.exit(1) + def matchoutput(cmd, regexp, ignorestatus=False): """Return the match object if cmd executes successfully and its output is matched by the supplied regular expression. """ r = re.compile(regexp) p = subprocess.Popen( - cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT + ) s = p.communicate()[0] ret = p.returncode return (ignorestatus or not ret) and r.search(s) + @check("baz", "GNU Arch baz client") def has_baz(): return matchoutput('baz --version 2>&1', br'baz Bazaar version') + @check("bzr", "Canonical's Bazaar client") def has_bzr(): try: @@ -135,48 +155,61 @@ import bzrlib.errors import bzrlib.revision import bzrlib.revisionspec + bzrlib.revisionspec.RevisionSpec return bzrlib.__doc__ is not None except (AttributeError, ImportError): return False + @checkvers("bzr", "Canonical's Bazaar client >= %s", (1.14,)) def has_bzr_range(v): major, minor = v.split('rc')[0].split('.')[0:2] try: import bzrlib - return (bzrlib.__doc__ is not None - and bzrlib.version_info[:2] >= (int(major), int(minor))) + + return bzrlib.__doc__ is not None and bzrlib.version_info[:2] >= ( + int(major), + int(minor), + ) except ImportError: return False + @check("chg", "running with chg") def has_chg(): return 'CHGHG' in os.environ + @check("cvs", "cvs client/server") def has_cvs(): re = br'Concurrent Versions System.*?server' return matchoutput('cvs --version 2>&1', re) and not has_msys() + @check("cvs112", "cvs client/server 1.12.* (not cvsnt)") def has_cvs112(): re = br'Concurrent Versions System \(CVS\) 1.12.*?server' return matchoutput('cvs --version 2>&1', re) and not has_msys() + @check("cvsnt", "cvsnt client/server") def has_cvsnt(): re = br'Concurrent Versions System \(CVSNT\) (\d+).(\d+).*\(client/server\)' return matchoutput('cvsnt --version 2>&1', re) + @check("darcs", "darcs client") def has_darcs(): return matchoutput('darcs --version', br'\b2\.([2-9]|\d{2})', True) + @check("mtn", "monotone client (>= 1.0)") def has_mtn(): return matchoutput('mtn --version', br'monotone', True) and not matchoutput( - 'mtn --version', br'monotone 0\.', True) + 'mtn --version', br'monotone 0\.', True + ) + @check("eol-in-paths", "end-of-lines in paths") def has_eol_in_paths(): @@ -188,6 +221,7 @@ except (IOError, OSError): return False + @check("execbit", "executable bit") def has_executablebit(): try: @@ -198,7 +232,7 @@ m = os.stat(fn).st_mode & 0o777 new_file_has_exec = m & EXECFLAGS os.chmod(fn, m ^ EXECFLAGS) - exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0o777) == m) + exec_flags_cannot_flip = (os.stat(fn).st_mode & 0o777) == m finally: os.unlink(fn) except (IOError, OSError): @@ -206,6 +240,7 @@ return False return not (new_file_has_exec or exec_flags_cannot_flip) + @check("icasefs", "case insensitive file system") def has_icasefs(): # Stolen from mercurial.util @@ -225,6 +260,7 @@ finally: os.remove(path) + @check("fifo", "named pipes") def has_fifo(): if getattr(os, "mkfifo", None) is None: @@ -237,10 +273,12 @@ except OSError: return False + @check("killdaemons", 'killdaemons.py support') def has_killdaemons(): return True + @check("cacheable", "cacheable filesystem") def has_cacheable_fs(): from mercurial import util @@ -252,59 +290,71 @@ finally: os.remove(path) + @check("lsprof", "python lsprof module") def has_lsprof(): try: import _lsprof - _lsprof.Profiler # silence unused import warning + + _lsprof.Profiler # silence unused import warning return True except ImportError: return False + def gethgversion(): m = matchoutput('hg --version --quiet 2>&1', br'(\d+)\.(\d+)') if not m: return (0, 0) return (int(m.group(1)), int(m.group(2))) -@checkvers("hg", "Mercurial >= %s", - list([(1.0 * x) / 10 for x in range(9, 99)])) + +@checkvers( + "hg", "Mercurial >= %s", list([(1.0 * x) / 10 for x in range(9, 99)]) +) def has_hg_range(v): major, minor = v.split('.')[0:2] return gethgversion() >= (int(major), int(minor)) + @check("hg08", "Mercurial >= 0.8") def has_hg08(): if checks["hg09"][0](): return True return matchoutput('hg help annotate 2>&1', '--date') + @check("hg07", "Mercurial >= 0.7") def has_hg07(): if checks["hg08"][0](): return True return matchoutput('hg --version --quiet 2>&1', 'Mercurial Distributed SCM') + @check("hg06", "Mercurial >= 0.6") def has_hg06(): if checks["hg07"][0](): return True return matchoutput('hg --version --quiet 2>&1', 'Mercurial version') + @check("gettext", "GNU Gettext (msgfmt)") def has_gettext(): return matchoutput('msgfmt --version', br'GNU gettext-tools') + @check("git", "git command line client") def has_git(): return matchoutput('git --version 2>&1', br'^git version') + def getgitversion(): m = matchoutput('git --version 2>&1', br'git version (\d+)\.(\d+)') if not m: return (0, 0) return (int(m.group(1)), int(m.group(2))) + # https://github.com/git-lfs/lfs-test-server @check("lfs-test-server", "git-lfs test server") def has_lfsserver(): @@ -316,40 +366,49 @@ for path in os.environ["PATH"].split(os.pathsep) ) + @checkvers("git", "git client (with ext::sh support) version >= %s", (1.9,)) def has_git_range(v): major, minor = v.split('.')[0:2] return getgitversion() >= (int(major), int(minor)) + @check("docutils", "Docutils text processing library") def has_docutils(): try: import docutils.core - docutils.core.publish_cmdline # silence unused import + + docutils.core.publish_cmdline # silence unused import return True except ImportError: return False + def getsvnversion(): m = matchoutput('svn --version --quiet 2>&1', br'^(\d+)\.(\d+)') if not m: return (0, 0) return (int(m.group(1)), int(m.group(2))) + @checkvers("svn", "subversion client and admin tools >= %s", (1.3, 1.5)) def has_svn_range(v): major, minor = v.split('.')[0:2] return getsvnversion() >= (int(major), int(minor)) + @check("svn", "subversion client and admin tools") def has_svn(): - return (matchoutput('svn --version 2>&1', br'^svn, version') and - matchoutput('svnadmin --version 2>&1', br'^svnadmin, version')) + return matchoutput('svn --version 2>&1', br'^svn, version') and matchoutput( + 'svnadmin --version 2>&1', br'^svnadmin, version' + ) + @check("svn-bindings", "subversion python bindings") def has_svn_bindings(): try: import svn.core + version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR if version < (1, 4): return False @@ -357,10 +416,13 @@ except ImportError: return False + @check("p4", "Perforce server and client") def has_p4(): - return (matchoutput('p4 -V', br'Rev\. P4/') and - matchoutput('p4d -V', br'Rev\. P4D/')) + return matchoutput('p4 -V', br'Rev\. P4/') and matchoutput( + 'p4d -V', br'Rev\. P4D/' + ) + @check("symlink", "symbolic links") def has_symlink(): @@ -374,9 +436,11 @@ except (OSError, AttributeError): return False + @check("hardlink", "hardlinks") def has_hardlink(): from mercurial import util + fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix) os.close(fh) name = tempfile.mktemp(dir='.', prefix=tempprefix) @@ -389,15 +453,18 @@ finally: os.unlink(fn) + @check("hardlink-whitelisted", "hardlinks on whitelisted filesystems") def has_hardlink_whitelisted(): from mercurial import util + try: fstype = util.getfstype(b'.') except OSError: return False return fstype in util._hardlinkfswhitelist + @check("rmcwd", "can remove current working directory") def has_rmcwd(): ocwd = os.getcwd() @@ -418,22 +485,27 @@ except OSError: pass + @check("tla", "GNU Arch tla client") def has_tla(): return matchoutput('tla --version 2>&1', br'The GNU Arch Revision') + @check("gpg", "gpg client") def has_gpg(): return matchoutput('gpg --version 2>&1', br'GnuPG') + @check("gpg2", "gpg client v2") def has_gpg2(): return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.') + @check("gpg21", "gpg client v2.1+") def has_gpg21(): return matchoutput('gpg --version 2>&1', br'GnuPG[^0-9]+2\.(?!0)') + @check("unix-permissions", "unix-style permissions") def has_unix_permissions(): d = tempfile.mkdtemp(dir='.', prefix=tempprefix) @@ -451,25 +523,30 @@ finally: os.rmdir(d) + @check("unix-socket", "AF_UNIX socket family") def has_unix_socket(): return getattr(socket, 'AF_UNIX', None) is not None + @check("root", "root permissions") def has_root(): return getattr(os, 'geteuid', None) and os.geteuid() == 0 + @check("pyflakes", "Pyflakes python linter") def has_pyflakes(): - return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"", - br"<stdin>:1: 're' imported but unused", - True) + return matchoutput( + "sh -c \"echo 'import re' 2>&1 | pyflakes\"", + br"<stdin>:1: 're' imported but unused", + True, + ) + @check("pylint", "Pylint python linter") def has_pylint(): - return matchoutput("pylint --help", - br"Usage: pylint", - True) + return matchoutput("pylint --help", br"Usage: pylint", True) + @check("clang-format", "clang-format C code formatter") def has_clang_format(): @@ -477,49 +554,59 @@ # style changed somewhere between 4.x and 6.x return m and int(m.group(1)) >= 6 + @check("jshint", "JSHint static code analysis tool") def has_jshint(): return matchoutput("jshint --version 2>&1", br"jshint v") + @check("pygments", "Pygments source highlighting library") def has_pygments(): try: import pygments - pygments.highlight # silence unused import warning + + pygments.highlight # silence unused import warning return True except ImportError: return False + @check("outer-repo", "outer repo") def has_outer_repo(): # failing for other reasons than 'no repo' imply that there is a repo - return not matchoutput('hg root 2>&1', - br'abort: no repository found', True) + return not matchoutput('hg root 2>&1', br'abort: no repository found', True) + @check("ssl", "ssl module available") def has_ssl(): try: import ssl + ssl.CERT_NONE return True except ImportError: return False + @check("sslcontext", "python >= 2.7.9 ssl") def has_sslcontext(): try: import ssl + ssl.SSLContext return True except (ImportError, AttributeError): return False + @check("defaultcacerts", "can verify SSL certs by system's CA certs store") def has_defaultcacerts(): from mercurial import sslutil, ui as uimod + ui = uimod.ui.load() return sslutil._defaultcacerts(ui) or sslutil._canloaddefaultcerts + @check("defaultcacertsloaded", "detected presence of loaded system CA certs") def has_defaultcacertsloaded(): import ssl @@ -540,67 +627,82 @@ return len(ctx.get_ca_certs()) > 0 + @check("tls1.2", "TLS 1.2 protocol support") def has_tls1_2(): from mercurial import sslutil + return b'tls1.2' in sslutil.supportedprotocols + @check("windows", "Windows") def has_windows(): return os.name == 'nt' + @check("system-sh", "system() uses sh") def has_system_sh(): return os.name != 'nt' + @check("serve", "platform and python can manage 'hg serve -d'") def has_serve(): return True + @check("test-repo", "running tests from repository") def has_test_repo(): t = os.environ["TESTDIR"] return os.path.isdir(os.path.join(t, "..", ".hg")) + @check("tic", "terminfo compiler and curses module") def has_tic(): try: import curses + curses.COLOR_BLUE return matchoutput('test -x "`which tic`"', br'') except ImportError: return False + @check("msys", "Windows with MSYS") def has_msys(): return os.getenv('MSYSTEM') + @check("aix", "AIX") def has_aix(): return sys.platform.startswith("aix") + @check("osx", "OS X") def has_osx(): return sys.platform == 'darwin' + @check("osxpackaging", "OS X packaging tools") def has_osxpackaging(): try: - return (matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1) - and matchoutput( - 'productbuild', br'Usage: productbuild ', - ignorestatus=1) - and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1) - and matchoutput( - 'xar --help', br'Usage: xar', ignorestatus=1)) + return ( + matchoutput('pkgbuild', br'Usage: pkgbuild ', ignorestatus=1) + and matchoutput( + 'productbuild', br'Usage: productbuild ', ignorestatus=1 + ) + and matchoutput('lsbom', br'Usage: lsbom', ignorestatus=1) + and matchoutput('xar --help', br'Usage: xar', ignorestatus=1) + ) except ImportError: return False + @check('linuxormacos', 'Linux or MacOS') def has_linuxormacos(): # This isn't a perfect test for MacOS. But it is sufficient for our needs. return sys.platform.startswith(('linux', 'darwin')) + @check("docker", "docker support") def has_docker(): pat = br'A self-sufficient runtime for' @@ -618,33 +720,42 @@ return True return False + @check("debhelper", "debian packaging tools") def has_debhelper(): # Some versions of dpkg say `dpkg', some say 'dpkg' (` vs ' on the first # quote), so just accept anything in that spot. - dpkg = matchoutput('dpkg --version', - br"Debian .dpkg' package management program") - dh = matchoutput('dh --help', - br'dh is a part of debhelper.', ignorestatus=True) - dh_py2 = matchoutput('dh_python2 --help', - br'other supported Python versions') + dpkg = matchoutput( + 'dpkg --version', br"Debian .dpkg' package management program" + ) + dh = matchoutput( + 'dh --help', br'dh is a part of debhelper.', ignorestatus=True + ) + dh_py2 = matchoutput( + 'dh_python2 --help', br'other supported Python versions' + ) # debuild comes from the 'devscripts' package, though you might want # the 'build-debs' package instead, which has a dependency on devscripts. - debuild = matchoutput('debuild --help', - br'to run debian/rules with given parameter') + debuild = matchoutput( + 'debuild --help', br'to run debian/rules with given parameter' + ) return dpkg and dh and dh_py2 and debuild -@check("debdeps", - "debian build dependencies (run dpkg-checkbuilddeps in contrib/)") + +@check( + "debdeps", "debian build dependencies (run dpkg-checkbuilddeps in contrib/)" +) def has_debdeps(): # just check exit status (ignoring output) path = '%s/../contrib/packaging/debian/control' % os.environ['TESTDIR'] return matchoutput('dpkg-checkbuilddeps %s' % path, br'') + @check("demandimport", "demandimport enabled") def has_demandimport(): # chg disables demandimport intentionally for performance wins. - return ((not has_chg()) and os.environ.get('HGDEMANDIMPORT') != 'disable') + return (not has_chg()) and os.environ.get('HGDEMANDIMPORT') != 'disable' + @checkvers("py", "Python >= %s", (2.7, 3.5, 3.6, 3.7, 3.8, 3.9)) def has_python_range(v): @@ -653,73 +764,91 @@ return (py_major, py_minor) >= (int(major), int(minor)) + @check("py3", "running with Python 3.x") def has_py3(): return 3 == sys.version_info[0] + @check("py3exe", "a Python 3.x interpreter is available") def has_python3exe(): return matchoutput('python3 -V', br'^Python 3.(5|6|7|8|9)') + @check("pure", "running with pure Python code") def has_pure(): - return any([ - os.environ.get("HGMODULEPOLICY") == "py", - os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure", - ]) + return any( + [ + os.environ.get("HGMODULEPOLICY") == "py", + os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure", + ] + ) + @check("slow", "allow slow tests (use --allow-slow-tests)") def has_slow(): return os.environ.get('HGTEST_SLOW') == 'slow' + @check("hypothesis", "Hypothesis automated test generation") def has_hypothesis(): try: import hypothesis + hypothesis.given return True except ImportError: return False + @check("unziplinks", "unzip(1) understands and extracts symlinks") def unzip_understands_symlinks(): return matchoutput('unzip --help', br'Info-ZIP') + @check("zstd", "zstd Python module available") def has_zstd(): try: import mercurial.zstd + mercurial.zstd.__version__ return True except ImportError: return False + @check("devfull", "/dev/full special file") def has_dev_full(): return os.path.exists('/dev/full') + @check("virtualenv", "Python virtualenv support") def has_virtualenv(): try: import virtualenv + virtualenv.ACTIVATE_SH return True except ImportError: return False + @check("fsmonitor", "running tests with fsmonitor") def has_fsmonitor(): return 'HGFSMONITOR_TESTS' in os.environ + @check("fuzzywuzzy", "Fuzzy string matching library") def has_fuzzywuzzy(): try: import fuzzywuzzy + fuzzywuzzy.__version__ return True except ImportError: return False + @check("clang-libfuzzer", "clang new enough to include libfuzzer") def has_clang_libfuzzer(): mat = matchoutput('clang --version', br'clang version (\d)') @@ -728,23 +857,28 @@ return int(mat.group(1)) > 5 return False + @check("clang-6.0", "clang 6.0 with version suffix (libfuzzer included)") def has_clang60(): return matchoutput('clang-6.0 --version', br'clang version 6\.') + @check("xdiff", "xdiff algorithm") def has_xdiff(): try: from mercurial import policy + bdiff = policy.importmod('bdiff') return bdiff.xdiffblocks(b'', b'') == [(0, 0, 0, 0)] except (ImportError, AttributeError): return False + @check('extraextensions', 'whether tests are running with extra extensions') def has_extraextensions(): return 'HGTESTEXTRAEXTENSIONS' in os.environ + def getrepofeatures(): """Obtain set of repository features in use. @@ -783,26 +917,32 @@ return features + @check('reporevlogstore', 'repository using the default revlog store') def has_reporevlogstore(): return 'revlogstore' in getrepofeatures() + @check('reposimplestore', 'repository using simple storage extension') def has_reposimplestore(): return 'simplestore' in getrepofeatures() + @check('repobundlerepo', 'whether we can open bundle files as repos') def has_repobundlerepo(): return 'bundlerepo' in getrepofeatures() + @check('repofncache', 'repository has an fncache') def has_repofncache(): return 'fncache' in getrepofeatures() + @check('sqlite', 'sqlite3 module is available') def has_sqlite(): try: import sqlite3 + version = sqlite3.sqlite_version_info except ImportError: return False @@ -813,16 +953,19 @@ return matchoutput('sqlite3 -version', br'^3\.\d+') + @check('vcr', 'vcr http mocking library') def has_vcr(): try: import vcr + vcr.VCR return True except (ImportError, AttributeError): pass return False + @check('emacs', 'GNU Emacs') def has_emacs(): # Our emacs lisp uses `with-eval-after-load` which is new in emacs