##// END OF EJS Templates
configitems: declare items in a TOML file...
configitems: declare items in a TOML file Mercurial ships with Rust code that also needs to read from the config. Having a way of presenting `configitems` to both Python and Rust is needed to prevent duplication, drift, and have the appropriate devel warnings. Abstracting away from Python means choosing a config format. No single format is perfect, and I have yet to come across a developer that doesn't hate all of them in some way. Since we have a strict no-dependencies policy for Mercurial, we either need to use whatever comes with Python, vendor a library, or implement a custom format ourselves. Python stdlib means using JSON, which doesn't support comments and isn't great for humans, or `configparser` which is an obscure, untyped format that nobody uses and doesn't have a commonplace Rust parser. Implementing a custom format is error-prone, tedious and subject to the same issues as picking an existing format. Vendoring opens us to the vast array of common config formats. The ones being picked for most modern software are YAML and TOML. YAML is older and common in the Python community, but TOML is much simpler and less error-prone. I would much rather be responsible for the <1000 lines of `tomli`, on top of TOML being the choice of the Rust community, with robust crates for reading it. The structure of `configitems.toml` is explained inline.

File last commit:

r49730:6000f5b2 default
r51655:c51b178b default
Show More
python3-ratchet.py
161 lines | 4.5 KiB | text/x-python | PythonLexer
/ contrib / python3-ratchet.py
Augie Fackler
contrib: add a ratchet for tests in Python 3...
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
formatting: blacken the codebase...
r43346 _hgenv.update(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 {
'HGPLAIN': '1',
}
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855
_HG_FIRST_CHANGE = '9117c6561b0bd7792fa13b50d28239d51b78e51f'
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 def _runhg(*args):
return subprocess.check_output(args, env=_hgenv)
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 def _is_hg_repo(path):
Augie Fackler
formatting: blacken the codebase...
r43346 return (
_runhg('hg', 'log', '-R', path, '-r0', '--template={node}').strip()
== _HG_FIRST_CHANGE
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855
def _py3default():
if sys.version_info[0] >= 3:
return sys.executable
return 'python3'
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 def main(argv=()):
p = argparse.ArgumentParser()
Augie Fackler
formatting: blacken the codebase...
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
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 default=os.sysconf('SC_NPROCESSORS_ONLN'),
Augie Fackler
formatting: blacken the codebase...
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
contrib: add a ratchet for tests in Python 3...
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
formatting: blacken the codebase...
r43346 print(
'abort: --working-tests must exist and be a file (got %r)'
% opts.working_tests
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 sys.exit(1)
elif opts.commit_to_repo:
root = _runhg('hg', 'root').strip()
if not opts.working_tests.startswith(root):
Augie Fackler
formatting: blacken the codebase...
r43346 print(
'abort: if --commit-to-repo is given, '
'--working-tests must be from that repo'
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 sys.exit(1)
try:
Augie Fackler
formatting: blacken the codebase...
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
contrib: add a ratchet for tests in Python 3...
r32855 except subprocess.CalledProcessError:
Augie Fackler
formatting: blacken the codebase...
r43346 print(
'warning: Python 3.6.0 and 3.6.1 have '
'a bug which breaks Mercurial'
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 print('(see https://bugs.python.org/issue29714 for details)')
Kevin Bullock
py3: bail on ratcheting tests forward on 3.6.0 and 3.6.1
r36607 sys.exit(1)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855
Augie Fackler
formatting: blacken the codebase...
r43346 rt = subprocess.Popen(
[
opts.python3,
'run-tests.py',
'-j',
str(opts.j),
'--blacklist',
opts.working_tests,
'--json',
]
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
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
formatting: blacken the codebase...
r43346 _runhg(
'hg',
'commit',
'-R',
opts.commit_to_repo,
'--user',
opts.commit_user,
'--message',
'python3: expand list of passing tests',
)
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 else:
print('Newly passing tests:', '\n'.join(sorted(newpass)))
sys.exit(2)
Augie Fackler
formatting: blacken the codebase...
r43346
Augie Fackler
contrib: add a ratchet for tests in Python 3...
r32855 if __name__ == '__main__':
main(sys.argv[1:])