python3-ratchet.py
161 lines
| 4.5 KiB
| text/x-python
|
PythonLexer
/ contrib / python3-ratchet.py
Augie Fackler
|
r32855 | # Copyright 2012 Facebook | ||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
"""Find tests that newly pass under Python 3. | ||||
The approach is simple: we maintain a whitelist of Python 3 passing | ||||
tests in the repository, and periodically run all the /other/ tests | ||||
and look for new passes. Any newly passing tests get automatically | ||||
added to the whitelist. | ||||
You probably want to run it like this: | ||||
$ cd tests | ||||
$ python3 ../contrib/python3-ratchet.py \ | ||||
> --working-tests=../contrib/python3-whitelist | ||||
""" | ||||
import argparse | ||||
import json | ||||
import os | ||||
import subprocess | ||||
import sys | ||||
_hgenv = dict(os.environ) | ||||
Augie Fackler
|
r43346 | _hgenv.update( | ||
Augie Fackler
|
r46554 | { | ||
'HGPLAIN': '1', | ||||
} | ||||
Augie Fackler
|
r43346 | ) | ||
Augie Fackler
|
r32855 | |||
_HG_FIRST_CHANGE = '9117c6561b0bd7792fa13b50d28239d51b78e51f' | ||||
Augie Fackler
|
r43346 | |||
Augie Fackler
|
r32855 | def _runhg(*args): | ||
return subprocess.check_output(args, env=_hgenv) | ||||
Augie Fackler
|
r43346 | |||
Augie Fackler
|
r32855 | def _is_hg_repo(path): | ||
Augie Fackler
|
r43346 | return ( | ||
_runhg('hg', 'log', '-R', path, '-r0', '--template={node}').strip() | ||||
== _HG_FIRST_CHANGE | ||||
) | ||||
Augie Fackler
|
r32855 | |||
def _py3default(): | ||||
if sys.version_info[0] >= 3: | ||||
return sys.executable | ||||
return 'python3' | ||||
Augie Fackler
|
r43346 | |||
Augie Fackler
|
r32855 | def main(argv=()): | ||
p = argparse.ArgumentParser() | ||||
Augie Fackler
|
r43346 | p.add_argument( | ||
'--working-tests', help='List of tests that already work in Python 3.' | ||||
) | ||||
p.add_argument( | ||||
'--commit-to-repo', | ||||
help='If set, commit newly fixed tests to the given repo', | ||||
) | ||||
p.add_argument( | ||||
'-j', | ||||
Augie Fackler
|
r43906 | default=os.sysconf('SC_NPROCESSORS_ONLN'), | ||
Augie Fackler
|
r43346 | type=int, | ||
help='Number of parallel tests to run.', | ||||
) | ||||
p.add_argument( | ||||
'--python3', | ||||
default=_py3default(), | ||||
help='python3 interpreter to use for test run', | ||||
) | ||||
p.add_argument( | ||||
'--commit-user', | ||||
default='python3-ratchet@mercurial-scm.org', | ||||
help='Username to specify when committing to a repo.', | ||||
) | ||||
Augie Fackler
|
r32855 | opts = p.parse_args(argv) | ||
if opts.commit_to_repo: | ||||
if not _is_hg_repo(opts.commit_to_repo): | ||||
print('abort: specified repository is not the hg repository') | ||||
sys.exit(1) | ||||
if not opts.working_tests or not os.path.isfile(opts.working_tests): | ||||
Augie Fackler
|
r43346 | print( | ||
'abort: --working-tests must exist and be a file (got %r)' | ||||
% opts.working_tests | ||||
) | ||||
Augie Fackler
|
r32855 | sys.exit(1) | ||
elif opts.commit_to_repo: | ||||
root = _runhg('hg', 'root').strip() | ||||
if not opts.working_tests.startswith(root): | ||||
Augie Fackler
|
r43346 | print( | ||
'abort: if --commit-to-repo is given, ' | ||||
'--working-tests must be from that repo' | ||||
) | ||||
Augie Fackler
|
r32855 | sys.exit(1) | ||
try: | ||||
Augie Fackler
|
r43346 | subprocess.check_call( | ||
[ | ||||
opts.python3, | ||||
'-c', | ||||
'import sys ; ' | ||||
'assert ((3, 5) <= sys.version_info < (3, 6) ' | ||||
'or sys.version_info >= (3, 6, 2))', | ||||
] | ||||
) | ||||
Augie Fackler
|
r32855 | except subprocess.CalledProcessError: | ||
Augie Fackler
|
r43346 | print( | ||
'warning: Python 3.6.0 and 3.6.1 have ' | ||||
'a bug which breaks Mercurial' | ||||
) | ||||
Augie Fackler
|
r32855 | print('(see https://bugs.python.org/issue29714 for details)') | ||
Kevin Bullock
|
r36607 | sys.exit(1) | ||
Augie Fackler
|
r32855 | |||
Augie Fackler
|
r43346 | rt = subprocess.Popen( | ||
[ | ||||
opts.python3, | ||||
'run-tests.py', | ||||
'-j', | ||||
str(opts.j), | ||||
'--blacklist', | ||||
opts.working_tests, | ||||
'--json', | ||||
] | ||||
) | ||||
Augie Fackler
|
r32855 | rt.wait() | ||
with open('report.json') as f: | ||||
data = f.read() | ||||
report = json.loads(data.split('=', 1)[1]) | ||||
newpass = set() | ||||
for test, result in report.items(): | ||||
if result['result'] != 'success': | ||||
continue | ||||
# A new passing test! Huzzah! | ||||
newpass.add(test) | ||||
if newpass: | ||||
# We already validated the repo, so we can just dive right in | ||||
# and commit. | ||||
if opts.commit_to_repo: | ||||
print(len(newpass), 'new passing tests on Python 3!') | ||||
with open(opts.working_tests) as f: | ||||
oldpass = {l for l in f.read().splitlines() if l} | ||||
with open(opts.working_tests, 'w') as f: | ||||
for p in sorted(oldpass | newpass): | ||||
f.write('%s\n' % p) | ||||
Augie Fackler
|
r43346 | _runhg( | ||
'hg', | ||||
'commit', | ||||
'-R', | ||||
opts.commit_to_repo, | ||||
'--user', | ||||
opts.commit_user, | ||||
'--message', | ||||
'python3: expand list of passing tests', | ||||
) | ||||
Augie Fackler
|
r32855 | else: | ||
print('Newly passing tests:', '\n'.join(sorted(newpass))) | ||||
sys.exit(2) | ||||
Augie Fackler
|
r43346 | |||
Augie Fackler
|
r32855 | if __name__ == '__main__': | ||
main(sys.argv[1:]) | ||||