contrib/check-config.py
author Mark Thomas <mbthomas@fb.com>
Fri, 24 Nov 2017 12:53:58 -0800
branchstable
changeset 35172 a92b9f8e11ba
parent 33570 e470f12d7d05
child 35919 143d7b27b09c
permissions -rwxr-xr-x
merge: check created file dirs for path conflicts only once (issue5716) In large repositories, updates involving the creation of many files check the same directories repeatedly in the wctx manifest. Move these checks out to a separate loop to avoid repeated checks hitting the manifest. Differential Revision: https://phab.mercurial-scm.org/D1226
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     1
#!/usr/bin/env python
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     2
#
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     3
# check-config - a config flag documentation checker for Mercurial
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     4
#
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     5
# Copyright 2015 Matt Mackall <mpm@selenic.com>
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     6
#
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     7
# This software may be used and distributed according to the terms of the
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     8
# GNU General Public License version 2 or any later version.
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
     9
28352
a92ee4d8a574 check-config: use absolute_import and print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 27992
diff changeset
    10
from __future__ import absolute_import, print_function
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    11
import re
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    12
import sys
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    13
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    14
foundopts = {}
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    15
documented = {}
33195
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32849
diff changeset
    16
allowinconsistent = set()
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    17
32847
e5a6a540ae63 check-config: use compiled regexp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 28352
diff changeset
    18
configre = re.compile(r'''
e5a6a540ae63 check-config: use compiled regexp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 28352
diff changeset
    19
    # Function call
32848
485b8e87e244 check-config: use named groups in regexp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32847
diff changeset
    20
    ui\.config(?P<ctype>|int|bool|list)\(
32847
e5a6a540ae63 check-config: use compiled regexp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 28352
diff changeset
    21
        # First argument.
32848
485b8e87e244 check-config: use named groups in regexp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32847
diff changeset
    22
        ['"](?P<section>\S+)['"],\s*
32847
e5a6a540ae63 check-config: use compiled regexp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 28352
diff changeset
    23
        # Second argument
32848
485b8e87e244 check-config: use named groups in regexp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32847
diff changeset
    24
        ['"](?P<option>\S+)['"](,\s+
485b8e87e244 check-config: use named groups in regexp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32847
diff changeset
    25
        (?:default=)?(?P<default>\S+?))?
32847
e5a6a540ae63 check-config: use compiled regexp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 28352
diff changeset
    26
    \)''', re.VERBOSE | re.MULTILINE)
e5a6a540ae63 check-config: use compiled regexp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 28352
diff changeset
    27
32849
e9fc5550be46 check-config: look for ui.configwith
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32848
diff changeset
    28
configwithre = re.compile('''
e9fc5550be46 check-config: look for ui.configwith
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32848
diff changeset
    29
    ui\.config(?P<ctype>with)\(
e9fc5550be46 check-config: look for ui.configwith
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32848
diff changeset
    30
        # First argument is callback function. This doesn't parse robustly
e9fc5550be46 check-config: look for ui.configwith
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32848
diff changeset
    31
        # if it is e.g. a function call.
e9fc5550be46 check-config: look for ui.configwith
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32848
diff changeset
    32
        [^,]+,\s*
e9fc5550be46 check-config: look for ui.configwith
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32848
diff changeset
    33
        ['"](?P<section>\S+)['"],\s*
e9fc5550be46 check-config: look for ui.configwith
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32848
diff changeset
    34
        ['"](?P<option>\S+)['"](,\s+
e9fc5550be46 check-config: look for ui.configwith
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32848
diff changeset
    35
        (?:default=)?(?P<default>\S+?))?
e9fc5550be46 check-config: look for ui.configwith
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32848
diff changeset
    36
    \)''', re.VERBOSE | re.MULTILINE)
e9fc5550be46 check-config: look for ui.configwith
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32848
diff changeset
    37
27313
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    38
configpartialre = (r"""ui\.config""")
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    39
33195
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32849
diff changeset
    40
ignorere = re.compile(r'''
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32849
diff changeset
    41
    \#\s(?P<reason>internal|experimental|deprecated|developer|inconsistent)\s
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32849
diff changeset
    42
    config:\s(?P<config>\S+\.\S+)$
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32849
diff changeset
    43
    ''', re.VERBOSE | re.MULTILINE)
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32849
diff changeset
    44
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    45
def main(args):
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    46
    for f in args:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    47
        sect = ''
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    48
        prevname = ''
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    49
        confsect = ''
27313
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    50
        carryover = ''
33570
e470f12d7d05 check-config: mention the file and line of the error
Ryan McElroy <rmcelroy@fb.com>
parents: 33195
diff changeset
    51
        linenum = 0
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    52
        for l in open(f):
33570
e470f12d7d05 check-config: mention the file and line of the error
Ryan McElroy <rmcelroy@fb.com>
parents: 33195
diff changeset
    53
            linenum += 1
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    54
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    55
            # check topic-like bits
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    56
            m = re.match('\s*``(\S+)``', l)
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    57
            if m:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    58
                prevname = m.group(1)
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    59
            if re.match('^\s*-+$', l):
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    60
                sect = prevname
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    61
                prevname = ''
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    62
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    63
            if sect and prevname:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    64
                name = sect + '.' + prevname
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    65
                documented[name] = 1
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    66
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    67
            # check docstring bits
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    68
            m = re.match(r'^\s+\[(\S+)\]', l)
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    69
            if m:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    70
                confsect = m.group(1)
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    71
                continue
27311
24a1c24fad6e check-config: allow numbers in configs
timeless <timeless@mozdev.org>
parents: 27310
diff changeset
    72
            m = re.match(r'^\s+(?:#\s*)?(\S+) = ', l)
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    73
            if m:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    74
                name = confsect + '.' + m.group(1)
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    75
                documented[name] = 1
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    76
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    77
            # like the bugzilla extension
27311
24a1c24fad6e check-config: allow numbers in configs
timeless <timeless@mozdev.org>
parents: 27310
diff changeset
    78
            m = re.match(r'^\s*(\S+\.\S+)$', l)
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    79
            if m:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    80
                documented[m.group(1)] = 1
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    81
27310
9c98fe1416c2 check-config: recognize convert style documentation
timeless <timeless@mozdev.org>
parents: 25849
diff changeset
    82
            # like convert
9c98fe1416c2 check-config: recognize convert style documentation
timeless <timeless@mozdev.org>
parents: 25849
diff changeset
    83
            m = re.match(r'^\s*:(\S+\.\S+):\s+', l)
9c98fe1416c2 check-config: recognize convert style documentation
timeless <timeless@mozdev.org>
parents: 25849
diff changeset
    84
            if m:
9c98fe1416c2 check-config: recognize convert style documentation
timeless <timeless@mozdev.org>
parents: 25849
diff changeset
    85
                documented[m.group(1)] = 1
9c98fe1416c2 check-config: recognize convert style documentation
timeless <timeless@mozdev.org>
parents: 25849
diff changeset
    86
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    87
            # quoted in help or docstrings
27311
24a1c24fad6e check-config: allow numbers in configs
timeless <timeless@mozdev.org>
parents: 27310
diff changeset
    88
            m = re.match(r'.*?``(\S+\.\S+)``', l)
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    89
            if m:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    90
                documented[m.group(1)] = 1
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    91
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    92
            # look for ignore markers
33195
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32849
diff changeset
    93
            m = ignorere.search(l)
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    94
            if m:
33195
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32849
diff changeset
    95
                if m.group('reason') == 'inconsistent':
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32849
diff changeset
    96
                    allowinconsistent.add(m.group('config'))
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32849
diff changeset
    97
                else:
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32849
diff changeset
    98
                    documented[m.group('config')] = 1
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    99
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   100
            # look for code-like bits
27313
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
   101
            line = carryover + l
32849
e9fc5550be46 check-config: look for ui.configwith
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32848
diff changeset
   102
            m = configre.search(line) or configwithre.search(line)
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   103
            if m:
32848
485b8e87e244 check-config: use named groups in regexp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32847
diff changeset
   104
                ctype = m.group('ctype')
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   105
                if not ctype:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   106
                    ctype = 'str'
32848
485b8e87e244 check-config: use named groups in regexp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32847
diff changeset
   107
                name = m.group('section') + "." + m.group('option')
485b8e87e244 check-config: use named groups in regexp
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32847
diff changeset
   108
                default = m.group('default')
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   109
                if default in (None, 'False', 'None', '0', '[]', '""', "''"):
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   110
                    default = ''
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   111
                if re.match('[a-z.]+$', default):
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   112
                    default = '<variable>'
33195
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32849
diff changeset
   113
                if (name in foundopts and (ctype, default) != foundopts[name]
5d8942dbe49e check-config: syntax to allow inconsistent config values
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32849
diff changeset
   114
                    and name not in allowinconsistent):
33570
e470f12d7d05 check-config: mention the file and line of the error
Ryan McElroy <rmcelroy@fb.com>
parents: 33195
diff changeset
   115
                    print(l.rstrip())
28352
a92ee4d8a574 check-config: use absolute_import and print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 27992
diff changeset
   116
                    print("conflict on %s: %r != %r" % (name, (ctype, default),
a92ee4d8a574 check-config: use absolute_import and print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 27992
diff changeset
   117
                                                        foundopts[name]))
33570
e470f12d7d05 check-config: mention the file and line of the error
Ryan McElroy <rmcelroy@fb.com>
parents: 33195
diff changeset
   118
                    print("at %s:%d:" % (f, linenum))
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   119
                foundopts[name] = (ctype, default)
27313
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
   120
                carryover = ''
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
   121
            else:
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
   122
                m = re.search(configpartialre, line)
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
   123
                if m:
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
   124
                    carryover = line
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
   125
                else:
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
   126
                    carryover = ''
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   127
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   128
    for name in sorted(foundopts):
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   129
        if name not in documented:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   130
            if not (name.startswith("devel.") or
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   131
                    name.startswith("experimental.") or
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   132
                    name.startswith("debug.")):
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   133
                ctype, default = foundopts[name]
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   134
                if default:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   135
                    default = ' [%s]' % default
28352
a92ee4d8a574 check-config: use absolute_import and print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 27992
diff changeset
   136
                print("undocumented: %s (%s)%s" % (name, ctype, default))
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   137
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   138
if __name__ == "__main__":
27992
8f244b75cc5e tests: execute check-config.py without xargs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 27313
diff changeset
   139
    if len(sys.argv) > 1:
8f244b75cc5e tests: execute check-config.py without xargs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 27313
diff changeset
   140
        sys.exit(main(sys.argv[1:]))
8f244b75cc5e tests: execute check-config.py without xargs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 27313
diff changeset
   141
    else:
8f244b75cc5e tests: execute check-config.py without xargs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 27313
diff changeset
   142
        sys.exit(main([l.rstrip() for l in sys.stdin]))