contrib/check-config.py
author FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
Sun, 13 Nov 2016 06:06:23 +0900
branchstable
changeset 30319 b496a464399c
parent 28352 a92ee4d8a574
child 32847 e5a6a540ae63
permissions -rwxr-xr-x
util: add utility function to skip avoiding file stat ambiguity if EPERM Now, advancing stat.st_mtime by os.utime() is used to avoid file stat ambiguity. But according to POSIX specification, utime(2) with an explicit time information is permitted only for a process with: - the effective user ID equal to the user ID of the file, or - appropriate privileges http://pubs.opengroup.org/onlinepubs/9699919799/functions/utime.html Therefore, just having group write access to a file causes EPERM at applying os.utime() on it (e.g. working on the repository shared by group access permission). This patch adds class filestat utility function avoidamgig() to avoid file stat ambiguity but skip it if EPERM. It is reasonable to always ignore EPERM, because utime(2) causes EPERM only in the case described above (EACCES is used only for utime(2) with NULL).
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 = {}
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    16
27313
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    17
configre = (r"""ui\.config(|int|bool|list)\(['"](\S+)['"],\s*"""
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    18
            r"""['"](\S+)['"](,\s+(?:default=)?(\S+?))?\)""")
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    19
configpartialre = (r"""ui\.config""")
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    20
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    21
def main(args):
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    22
    for f in args:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    23
        sect = ''
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    24
        prevname = ''
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    25
        confsect = ''
27313
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    26
        carryover = ''
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    27
        for l in open(f):
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    28
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    29
            # check topic-like bits
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    30
            m = re.match('\s*``(\S+)``', l)
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    31
            if m:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    32
                prevname = m.group(1)
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    33
            if re.match('^\s*-+$', l):
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    34
                sect = prevname
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    35
                prevname = ''
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    36
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    37
            if sect and prevname:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    38
                name = sect + '.' + prevname
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    39
                documented[name] = 1
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    40
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    41
            # check docstring bits
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    42
            m = re.match(r'^\s+\[(\S+)\]', l)
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    43
            if m:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    44
                confsect = m.group(1)
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    45
                continue
27311
24a1c24fad6e check-config: allow numbers in configs
timeless <timeless@mozdev.org>
parents: 27310
diff changeset
    46
            m = re.match(r'^\s+(?:#\s*)?(\S+) = ', l)
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    47
            if m:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    48
                name = confsect + '.' + m.group(1)
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    49
                documented[name] = 1
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    50
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    51
            # like the bugzilla extension
27311
24a1c24fad6e check-config: allow numbers in configs
timeless <timeless@mozdev.org>
parents: 27310
diff changeset
    52
            m = re.match(r'^\s*(\S+\.\S+)$', l)
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    53
            if m:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    54
                documented[m.group(1)] = 1
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    55
27310
9c98fe1416c2 check-config: recognize convert style documentation
timeless <timeless@mozdev.org>
parents: 25849
diff changeset
    56
            # like convert
9c98fe1416c2 check-config: recognize convert style documentation
timeless <timeless@mozdev.org>
parents: 25849
diff changeset
    57
            m = re.match(r'^\s*:(\S+\.\S+):\s+', l)
9c98fe1416c2 check-config: recognize convert style documentation
timeless <timeless@mozdev.org>
parents: 25849
diff changeset
    58
            if m:
9c98fe1416c2 check-config: recognize convert style documentation
timeless <timeless@mozdev.org>
parents: 25849
diff changeset
    59
                documented[m.group(1)] = 1
9c98fe1416c2 check-config: recognize convert style documentation
timeless <timeless@mozdev.org>
parents: 25849
diff changeset
    60
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    61
            # quoted in help or docstrings
27311
24a1c24fad6e check-config: allow numbers in configs
timeless <timeless@mozdev.org>
parents: 27310
diff changeset
    62
            m = re.match(r'.*?``(\S+\.\S+)``', l)
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    63
            if m:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    64
                documented[m.group(1)] = 1
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    65
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    66
            # look for ignore markers
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    67
            m = re.search(r'# (?:internal|experimental|deprecated|developer)'
27312
f925d492113a check-config: escape period in regexp for inline comments
timeless <timeless@mozdev.org>
parents: 27311
diff changeset
    68
                          ' config: (\S+\.\S+)$', l)
25790
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
                documented[m.group(1)] = 1
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    71
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    72
            # look for code-like bits
27313
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    73
            line = carryover + l
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    74
            m = re.search(configre, line, re.MULTILINE)
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    75
            if m:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    76
                ctype = m.group(1)
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    77
                if not ctype:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    78
                    ctype = 'str'
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    79
                name = m.group(2) + "." + m.group(3)
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    80
                default = m.group(5)
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    81
                if default in (None, 'False', 'None', '0', '[]', '""', "''"):
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    82
                    default = ''
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    83
                if re.match('[a-z.]+$', default):
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    84
                    default = '<variable>'
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    85
                if name in foundopts and (ctype, default) != foundopts[name]:
28352
a92ee4d8a574 check-config: use absolute_import and print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 27992
diff changeset
    86
                    print(l)
a92ee4d8a574 check-config: use absolute_import and print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 27992
diff changeset
    87
                    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
    88
                                                        foundopts[name]))
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    89
                foundopts[name] = (ctype, default)
27313
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    90
                carryover = ''
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    91
            else:
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    92
                m = re.search(configpartialre, line)
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    93
                if m:
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    94
                    carryover = line
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    95
                else:
9d155accd8f1 check-config: handle multiline config
timeless <timeless@mozdev.org>
parents: 27312
diff changeset
    96
                    carryover = ''
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    97
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    98
    for name in sorted(foundopts):
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
    99
        if name not in documented:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   100
            if not (name.startswith("devel.") or
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   101
                    name.startswith("experimental.") or
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   102
                    name.startswith("debug.")):
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   103
                ctype, default = foundopts[name]
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   104
                if default:
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   105
                    default = ' [%s]' % default
28352
a92ee4d8a574 check-config: use absolute_import and print_function
Pulkit Goyal <7895pulkit@gmail.com>
parents: 27992
diff changeset
   106
                print("undocumented: %s (%s)%s" % (name, ctype, default))
25790
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   107
db5b6a1c064d check-config: add config option checker
Matt Mackall <mpm@selenic.com>
parents:
diff changeset
   108
if __name__ == "__main__":
27992
8f244b75cc5e tests: execute check-config.py without xargs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 27313
diff changeset
   109
    if len(sys.argv) > 1:
8f244b75cc5e tests: execute check-config.py without xargs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 27313
diff changeset
   110
        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
   111
    else:
8f244b75cc5e tests: execute check-config.py without xargs
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 27313
diff changeset
   112
        sys.exit(main([l.rstrip() for l in sys.stdin]))