Mercurial > public > mercurial-scm > hg
diff mercurial/configitems.py @ 33499:0407a51b9d8c
codemod: register core configitems using a script
This is done by a script [2] using RedBaron [1], a tool designed for doing
code refactoring. All "default" values are decided by the script and are
strongly consistent with the existing code.
There are 2 changes done manually to fix tests:
[warn] mercurial/exchange.py: experimental.bundle2-output-capture: default needs manual removal
[warn] mercurial/localrepo.py: experimental.hook-track-tags: default needs manual removal
Since RedBaron is not confident about how to indent things [2].
[1]: https://github.com/PyCQA/redbaron
[2]: https://github.com/PyCQA/redbaron/issues/100
[3]:
#!/usr/bin/env python
# codemod_configitems.py - codemod tool to fill configitems
#
# Copyright 2017 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import, print_function
import os
import sys
import redbaron
def readpath(path):
with open(path) as f:
return f.read()
def writepath(path, content):
with open(path, 'w') as f:
f.write(content)
_configmethods = {'config', 'configbool', 'configint', 'configbytes',
'configlist', 'configdate'}
def extractstring(rnode):
"""get the string from a RedBaron string or call_argument node"""
while rnode.type != 'string':
rnode = rnode.value
return rnode.value[1:-1] # unquote, "'str'" -> "str"
def uiconfigitems(red):
"""match *.ui.config* pattern, yield (node, method, args, section, name)"""
for node in red.find_all('atomtrailers'):
entry = None
try:
obj = node[-3].value
method = node[-2].value
args = node[-1]
section = args[0].value
name = args[1].value
if (obj in ('ui', 'self') and method in _configmethods
and section.type == 'string' and name.type == 'string'):
entry = (node, method, args, extractstring(section),
extractstring(name))
except Exception:
pass
else:
if entry:
yield entry
def coreconfigitems(red):
"""match coreconfigitem(...) pattern, yield (node, args, section, name)"""
for node in red.find_all('atomtrailers'):
entry = None
try:
args = node[1]
section = args[0].value
name = args[1].value
if (node[0].value == 'coreconfigitem' and section.type == 'string'
and name.type == 'string'):
entry = (node, args, extractstring(section),
extractstring(name))
except Exception:
pass
else:
if entry:
yield entry
def registercoreconfig(cfgred, section, name, defaultrepr):
"""insert coreconfigitem to cfgred AST
section and name are plain string, defaultrepr is a string
"""
# find a place to insert the "coreconfigitem" item
entries = list(coreconfigitems(cfgred))
for node, args, nodesection, nodename in reversed(entries):
if (nodesection, nodename) < (section, name):
# insert after this entry
node.insert_after(
'coreconfigitem(%r, %r,\n'
' default=%s,\n'
')' % (section, name, defaultrepr))
return
def main(argv):
if not argv:
print('Usage: codemod_configitems.py FILES\n'
'For example, FILES could be "{hgext,mercurial}/*/**.py"')
dirname = os.path.dirname
reporoot = dirname(dirname(dirname(os.path.abspath(__file__))))
# register configitems to this destination
cfgpath = os.path.join(reporoot, 'mercurial', 'configitems.py')
cfgred = redbaron.RedBaron(readpath(cfgpath))
# state about what to do
registered = set((s, n) for n, a, s, n in coreconfigitems(cfgred))
toregister = {} # {(section, name): defaultrepr}
coreconfigs = set() # {(section, name)}, whether it's used in core
# first loop: scan all files before taking any action
for i, path in enumerate(argv):
print('(%d/%d) scanning %s' % (i + 1, len(argv), path))
iscore = ('mercurial' in path) and ('hgext' not in path)
red = redbaron.RedBaron(readpath(path))
# find all repo.ui.config* and ui.config* calls, and collect their
# section, name and default value information.
for node, method, args, section, name in uiconfigitems(red):
if section == 'web':
# [web] section has some weirdness, ignore them for now
continue
defaultrepr = None
key = (section, name)
if len(args) == 2:
if key in registered:
continue
if method == 'configlist':
defaultrepr = 'list'
elif method == 'configbool':
defaultrepr = 'False'
else:
defaultrepr = 'None'
elif len(args) >= 3 and (args[2].target is None or
args[2].target.value == 'default'):
# try to understand the "default" value
dnode = args[2].value
if dnode.type == 'name':
if dnode.value in {'None', 'True', 'False'}:
defaultrepr = dnode.value
elif dnode.type == 'string':
defaultrepr = repr(dnode.value[1:-1])
elif dnode.type in ('int', 'float'):
defaultrepr = dnode.value
# inconsistent default
if key in toregister and toregister[key] != defaultrepr:
defaultrepr = None
# interesting to rewrite
if key not in registered:
if defaultrepr is None:
print('[note] %s: %s.%s: unsupported default'
% (path, section, name))
registered.add(key) # skip checking it again
else:
toregister[key] = defaultrepr
if iscore:
coreconfigs.add(key)
# second loop: rewrite files given "toregister" result
for path in argv:
# reconstruct redbaron - trade CPU for memory
red = redbaron.RedBaron(readpath(path))
changed = False
for node, method, args, section, name in uiconfigitems(red):
key = (section, name)
defaultrepr = toregister.get(key)
if defaultrepr is None or key not in coreconfigs:
continue
if len(args) >= 3 and (args[2].target is None or
args[2].target.value == 'default'):
try:
del args[2]
changed = True
except Exception:
# redbaron fails to do the rewrite due to indentation
# see https://github.com/PyCQA/redbaron/issues/100
print('[warn] %s: %s.%s: default needs manual removal'
% (path, section, name))
if key not in registered:
print('registering %s.%s' % (section, name))
registercoreconfig(cfgred, section, name, defaultrepr)
registered.add(key)
if changed:
print('updating %s' % path)
writepath(path, red.dumps())
if toregister:
print('updating configitems.py')
writepath(cfgpath, cfgred.dumps())
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
author | Jun Wu <quark@fb.com> |
---|---|
date | Fri, 14 Jul 2017 14:22:40 -0700 |
parents | c514b4fb5e27 |
children | 3b7e36f7e632 |
line wrap: on
line diff
--- a/mercurial/configitems.py Tue Jul 11 08:52:55 2017 -0700 +++ b/mercurial/configitems.py Fri Jul 14 14:22:40 2017 -0700 @@ -76,12 +76,30 @@ coreconfigitem('bundle', 'reorder', default='auto', ) +coreconfigitem('censor', 'policy', + default='abort', +) +coreconfigitem('chgserver', 'idletimeout', + default=3600, +) +coreconfigitem('chgserver', 'skiphash', + default=False, +) +coreconfigitem('cmdserver', 'log', + default=None, +) coreconfigitem('color', 'mode', default='auto', ) coreconfigitem('color', 'pagermode', default=dynamicdefault, ) +coreconfigitem('commands', 'status.relative', + default=False, +) +coreconfigitem('commands', 'update.requiredest', + default=False, +) coreconfigitem('devel', 'all-warnings', default=False, ) @@ -94,6 +112,12 @@ coreconfigitem('devel', 'check-relroot', default=False, ) +coreconfigitem('devel', 'default-date', + default=None, +) +coreconfigitem('devel', 'deprec-warn', + default=False, +) coreconfigitem('devel', 'disableloaddefaultcerts', default=False, ) @@ -112,6 +136,99 @@ coreconfigitem('devel', 'strip-obsmarkers', default=True, ) +coreconfigitem('email', 'charsets', + default=list, +) +coreconfigitem('email', 'method', + default='smtp', +) +coreconfigitem('experimental', 'bundle-phases', + default=False, +) +coreconfigitem('experimental', 'bundle2-advertise', + default=True, +) +coreconfigitem('experimental', 'bundle2-output-capture', + default=False, +) +coreconfigitem('experimental', 'bundle2.pushback', + default=False, +) +coreconfigitem('experimental', 'bundle2lazylocking', + default=False, +) +coreconfigitem('experimental', 'bundlecomplevel', + default=None, +) +coreconfigitem('experimental', 'changegroup3', + default=False, +) +coreconfigitem('experimental', 'clientcompressionengines', + default=list, +) +coreconfigitem('experimental', 'crecordtest', + default=None, +) +coreconfigitem('experimental', 'disablecopytrace', + default=False, +) +coreconfigitem('experimental', 'editortmpinhg', + default=False, +) +coreconfigitem('experimental', 'evolution', + default=list, +) +coreconfigitem('experimental', 'evolution.bundle-obsmarker', + default=False, +) +coreconfigitem('experimental', 'evolution.track-operation', + default=False, +) +coreconfigitem('experimental', 'exportableenviron', + default=list, +) +coreconfigitem('experimental', 'extendedheader.index', + default=None, +) +coreconfigitem('experimental', 'extendedheader.similarity', + default=False, +) +coreconfigitem('experimental', 'format.compression', + default='zlib', +) +coreconfigitem('experimental', 'graphshorten', + default=False, +) +coreconfigitem('experimental', 'hook-track-tags', + default=False, +) +coreconfigitem('experimental', 'httppostargs', + default=False, +) +coreconfigitem('experimental', 'manifestv2', + default=False, +) +coreconfigitem('experimental', 'mergedriver', + default=None, +) +coreconfigitem('experimental', 'obsmarkers-exchange-debug', + default=False, +) +coreconfigitem('experimental', 'revertalternateinteractivemode', + default=True, +) +coreconfigitem('experimental', 'revlogv2', + default=None, +) +coreconfigitem('experimental', 'spacemovesdown', + default=False, +) +coreconfigitem('experimental', 'treemanifest', + default=False, +) +coreconfigitem('experimental', 'updatecheck', + default=None, +) coreconfigitem('format', 'aggressivemergedeltas', default=False, ) @@ -148,21 +265,90 @@ coreconfigitem('hostsecurity', 'disabletls10warning', default=False, ) +coreconfigitem('http_proxy', 'always', + default=False, +) +coreconfigitem('http_proxy', 'host', + default=None, +) +coreconfigitem('http_proxy', 'no', + default=list, +) +coreconfigitem('http_proxy', 'passwd', + default=None, +) +coreconfigitem('http_proxy', 'user', + default=None, +) +coreconfigitem('merge', 'followcopies', + default=True, +) +coreconfigitem('pager', 'ignore', + default=list, +) coreconfigitem('patch', 'eol', default='strict', ) coreconfigitem('patch', 'fuzz', default=2, ) +coreconfigitem('paths', 'default', + default=None, +) +coreconfigitem('paths', 'default-push', + default=None, +) +coreconfigitem('phases', 'checksubrepos', + default='follow', +) +coreconfigitem('phases', 'publish', + default=True, +) +coreconfigitem('profiling', 'enabled', + default=False, +) +coreconfigitem('profiling', 'format', + default='text', +) +coreconfigitem('profiling', 'freq', + default=1000, +) +coreconfigitem('profiling', 'limit', + default=30, +) +coreconfigitem('profiling', 'nested', + default=0, +) +coreconfigitem('profiling', 'sort', + default='inlinetime', +) +coreconfigitem('profiling', 'statformat', + default='hotpath', +) coreconfigitem('progress', 'assume-tty', default=False, ) +coreconfigitem('progress', 'changedelay', + default=1, +) coreconfigitem('progress', 'clear-complete', default=True, ) +coreconfigitem('progress', 'debug', + default=False, +) +coreconfigitem('progress', 'delay', + default=3, +) +coreconfigitem('progress', 'disable', + default=False, +) coreconfigitem('progress', 'estimate', default=2, ) +coreconfigitem('progress', 'refresh', + default=0.1, +) coreconfigitem('progress', 'width', default=dynamicdefault, ) @@ -187,6 +373,9 @@ coreconfigitem('server', 'preferuncompressed', default=False, ) +coreconfigitem('server', 'uncompressed', + default=True, +) coreconfigitem('server', 'uncompressedallowsecret', default=False, ) @@ -196,18 +385,171 @@ coreconfigitem('server', 'zliblevel', default=-1, ) +coreconfigitem('smtp', 'host', + default=None, +) +coreconfigitem('smtp', 'local_hostname', + default=None, +) +coreconfigitem('smtp', 'password', + default=None, +) +coreconfigitem('smtp', 'tls', + default='none', +) +coreconfigitem('smtp', 'username', + default=None, +) +coreconfigitem('sparse', 'missingwarning', + default=True, +) +coreconfigitem('trusted', 'groups', + default=list, +) +coreconfigitem('trusted', 'users', + default=list, +) +coreconfigitem('ui', '_usedassubrepo', + default=False, +) +coreconfigitem('ui', 'allowemptycommit', + default=False, +) +coreconfigitem('ui', 'archivemeta', + default=True, +) +coreconfigitem('ui', 'askusername', + default=False, +) +coreconfigitem('ui', 'clonebundlefallback', + default=False, +) coreconfigitem('ui', 'clonebundleprefers', default=list, ) +coreconfigitem('ui', 'clonebundles', + default=True, +) +coreconfigitem('ui', 'commitsubrepos', + default=False, +) +coreconfigitem('ui', 'debug', + default=False, +) +coreconfigitem('ui', 'debugger', + default=None, +) +coreconfigitem('ui', 'forcemerge', + default=None, +) +coreconfigitem('ui', 'formatdebug', + default=False, +) +coreconfigitem('ui', 'formatjson', + default=False, +) +coreconfigitem('ui', 'formatted', + default=None, +) +coreconfigitem('ui', 'graphnodetemplate', + default=None, +) +coreconfigitem('ui', 'http2debuglevel', + default=None, +) coreconfigitem('ui', 'interactive', default=None, ) +coreconfigitem('ui', 'interface', + default=None, +) +coreconfigitem('ui', 'logblockedtimes', + default=False, +) +coreconfigitem('ui', 'logtemplate', + default=None, +) +coreconfigitem('ui', 'merge', + default=None, +) +coreconfigitem('ui', 'mergemarkers', + default='basic', +) +coreconfigitem('ui', 'nontty', + default=False, +) +coreconfigitem('ui', 'origbackuppath', + default=None, +) +coreconfigitem('ui', 'paginate', + default=True, +) +coreconfigitem('ui', 'patch', + default=None, +) +coreconfigitem('ui', 'portablefilenames', + default='warn', +) +coreconfigitem('ui', 'promptecho', + default=False, +) coreconfigitem('ui', 'quiet', default=False, ) +coreconfigitem('ui', 'quietbookmarkmove', + default=False, +) +coreconfigitem('ui', 'remotecmd', + default='hg', +) +coreconfigitem('ui', 'report_untrusted', + default=True, +) +coreconfigitem('ui', 'rollback', + default=True, +) +coreconfigitem('ui', 'slash', + default=False, +) +coreconfigitem('ui', 'ssh', + default='ssh', +) +coreconfigitem('ui', 'statuscopies', + default=False, +) +coreconfigitem('ui', 'strict', + default=False, +) +coreconfigitem('ui', 'style', + default='', +) +coreconfigitem('ui', 'supportcontact', + default=None, +) +coreconfigitem('ui', 'textwidth', + default=78, +) +coreconfigitem('ui', 'timeout', + default='600', +) +coreconfigitem('ui', 'traceback', + default=False, +) +coreconfigitem('ui', 'tweakdefaults', + default=False, +) +coreconfigitem('ui', 'usehttp2', + default=False, +) coreconfigitem('ui', 'username', alias=[('ui', 'user')] ) +coreconfigitem('ui', 'verbose', + default=False, +) +coreconfigitem('verify', 'skipflags', + default=None, +) coreconfigitem('worker', 'backgroundclose', default=dynamicdefault, )