view doc/check-seclevel.py @ 43252:32187ae9eeb3

copies: simplify the handling of merges Instead of stacking copies for both parent on the head, we move copies outside of the heap into a dedicated dictionary. The two side of merge can we merged sooner, making the algorithm simpler. This simplicity reflect in the heap structure and speed up the execution for copies involving a large amount of merges. Here are timing for perfpathcopies of multiple revision pairs. - filelog: timing using filelog (with the introrev condition dropped) - base: this series base - before: the parent of this changeset - after: this changeset revision: large amount; added files: large amount; rename small amount; c3b14617fbd7 9ba6ab77fd29 filelog: ! wall 3.679613 comb 3.680000 user 3.580000 sys 0.100000 (median of 3) base: ! wall 8.884369 comb 8.880000 user 8.850000 sys 0.030000 (median of 3) before: ! wall 8.443747 comb 8.420000 user 8.410000 sys 0.010000 (median of 3) after: ! wall 4.697917 comb 4.690000 user 4.660000 sys 0.030000 (median of 3) revision: large amount; added files: small amount; rename small amount; c3b14617fbd7 f650a9b140d2 filelog: ! wall 0.003357 comb 0.010000 user 0.010000 sys 0.000000 (median of 781) base: ! wall 12.398524 comb 12.400000 user 12.330000 sys 0.070000 (median of 3) before: ! wall 10.852593 comb 10.850000 user 10.800000 sys 0.050000 (median of 3) after: ! wall 6.750832 comb 6.750000 user 6.640000 sys 0.110000 (median of 3) revision: large amount; added files: large amount; rename large amount; 08ea3258278e d9fa043f30c0 filelog: ! wall 2.754687 comb 2.760000 user 2.650000 sys 0.110000 (median of 4) base: ! wall 1.423166 comb 1.420000 user 1.400000 sys 0.020000 (median of 8) before: ! wall 1.068041 comb 1.060000 user 1.050000 sys 0.010000 (median of 10) after: ! wall 1.045916 comb 1.050000 user 1.040000 sys 0.010000 (median of 10) revision: small amount; added files: large amount; rename large amount; df6f7a526b60 a83dc6a2d56f filelog: ! wall 1.552293 comb 1.550000 user 1.510000 sys 0.040000 (median of 6 base: ! wall 0.022662 comb 0.020000 user 0.020000 sys 0.000000 (median of 128) before: ! wall 0.021111 comb 0.020000 user 0.020000 sys 0.000000 (median of 139) after: ! wall 0.021577 comb 0.020000 user 0.020000 sys 0.000000 (median of 138) revision: small amount; added files: large amount; rename small amount; 4aa4e1f8e19a 169138063d63 filelog: ! wall 1.500983 comb 1.500000 user 1.420000 sys 0.080000 (median of 7) base: ! wall 0.006956 comb 0.010000 user 0.010000 sys 0.000000 (median of 392) before: ! wall 0.004356 comb 0.010000 user 0.010000 sys 0.000000 (median of 675) after: ! wall 0.004329 comb 0.000000 user 0.000000 sys 0.000000 (median of 682) revision: small amount; added files: small amount; rename small amount; 4bc173b045a6 964879152e2e filelog: ! wall 0.011745 comb 0.020000 user 0.020000 sys 0.000000 (median of 250) base: ! wall 0.000156 comb 0.000000 user 0.000000 sys 0.000000 (median of 17180) before: ! wall 0.000100 comb 0.000000 user 0.000000 sys 0.000000 (median of 26912) after: ! wall 0.000105 comb 0.000000 user 0.000000 sys 0.000000 (median of 25689) revision: medium amount; added files: large amount; rename medium amount; c95f1ced15f2 2c68e87c3efe filelog: ! wall 3.228230 comb 3.230000 user 3.110000 sys 0.120000 (median of 4) base: ! wall 0.997640 comb 1.000000 user 0.980000 sys 0.020000 (median of 10) before: ! wall 0.778291 comb 0.780000 user 0.780000 sys 0.000000 (median of 13) after: ! wall 0.706594 comb 0.710000 user 0.710000 sys 0.000000 (median of 15) revision: medium amount; added files: medium amount; rename small amount; d343da0c55a8 d7746d32bf9d filelog: ! wall 1.052501 comb 1.060000 user 1.040000 sys 0.020000 (median of 10 base: ! wall 0.214519 comb 0.220000 user 0.220000 sys 0.000000 (median of 45) before: ! wall 0.160804 comb 0.160000 user 0.160000 sys 0.000000 (median of 62) after: ! wall 0.163736 comb 0.160000 user 0.160000 sys 0.000000 (median of 60) Differential Revision: https://phab.mercurial-scm.org/D7069
author Pierre-Yves David <pierre-yves.david@octobus.net>
date Wed, 02 Oct 2019 13:43:27 -0400
parents e8cf9ad52a78
children c102b704edb5
line wrap: on
line source

#!/usr/bin/env python
#
# checkseclevel - checking section title levels in each online help document

from __future__ import absolute_import

import optparse
import os
import sys

# import from the live mercurial repo
os.environ['HGMODULEPOLICY'] = 'py'
sys.path.insert(0, "..")
from mercurial import demandimport

demandimport.enable()
from mercurial import (
    commands,
    extensions,
    help,
    minirst,
    ui as uimod,
)

table = commands.table
helptable = help.helptable

level2mark = [b'"', b'=', b'-', b'.', b'#']
reservedmarks = [b'"']

mark2level = {}
for m, l in zip(level2mark, range(len(level2mark))):
    if m not in reservedmarks:
        mark2level[m] = l

initlevel_topic = 0
initlevel_cmd = 1
initlevel_ext = 1
initlevel_ext_cmd = 3


def showavailables(ui, initlevel):
    avail = '    available marks and order of them in this help: %s\n' % (
        ', '.join(['%r' % (m * 4) for m in level2mark[initlevel + 1 :]])
    )
    ui.warn(avail.encode('utf-8'))


def checkseclevel(ui, doc, name, initlevel):
    ui.notenoi18n('checking "%s"\n' % name)
    if not isinstance(doc, bytes):
        doc = doc.encode('utf-8')
    blocks, pruned = minirst.parse(doc, 0, ['verbose'])
    errorcnt = 0
    curlevel = initlevel
    for block in blocks:
        if block[b'type'] != b'section':
            continue
        mark = block[b'underline']
        title = block[b'lines'][0]
        if (mark not in mark2level) or (mark2level[mark] <= initlevel):
            ui.warn(
                (
                    'invalid section mark %r for "%s" of %s\n'
                    % (mark * 4, title, name)
                ).encode('utf-8')
            )
            showavailables(ui, initlevel)
            errorcnt += 1
            continue
        nextlevel = mark2level[mark]
        if curlevel < nextlevel and curlevel + 1 != nextlevel:
            ui.warnnoi18n(
                'gap of section level at "%s" of %s\n' % (title, name)
            )
            showavailables(ui, initlevel)
            errorcnt += 1
            continue
        ui.notenoi18n(
            'appropriate section level for "%s %s"\n'
            % (mark * (nextlevel * 2), title)
        )
        curlevel = nextlevel

    return errorcnt


def checkcmdtable(ui, cmdtable, namefmt, initlevel):
    errorcnt = 0
    for k, entry in cmdtable.items():
        name = k.split(b"|")[0].lstrip(b"^")
        if not entry[0].__doc__:
            ui.notenoi18n(
                'skip checking %s: no help document\n' % (namefmt % name)
            )
            continue
        errorcnt += checkseclevel(
            ui, entry[0].__doc__, namefmt % name, initlevel
        )
    return errorcnt


def checkhghelps(ui):
    errorcnt = 0
    for h in helptable:
        names, sec, doc = h[0:3]
        if callable(doc):
            doc = doc(ui)
        errorcnt += checkseclevel(
            ui, doc, '%s help topic' % names[0], initlevel_topic
        )

    errorcnt += checkcmdtable(ui, table, '%s command', initlevel_cmd)

    for name in sorted(
        list(extensions.enabled()) + list(extensions.disabled())
    ):
        mod = extensions.load(ui, name, None)
        if not mod.__doc__:
            ui.notenoi18n(
                'skip checking %s extension: no help document\n' % name
            )
            continue
        errorcnt += checkseclevel(
            ui, mod.__doc__, '%s extension' % name, initlevel_ext
        )

        cmdtable = getattr(mod, 'cmdtable', None)
        if cmdtable:
            errorcnt += checkcmdtable(
                ui,
                cmdtable,
                '%%s command of %s extension' % name,
                initlevel_ext_cmd,
            )
    return errorcnt


def checkfile(ui, filename, initlevel):
    if filename == '-':
        filename = 'stdin'
        doc = sys.stdin.read()
    else:
        with open(filename) as fp:
            doc = fp.read()

    ui.notenoi18n(
        'checking input from %s with initlevel %d\n' % (filename, initlevel)
    )
    return checkseclevel(ui, doc, 'input from %s' % filename, initlevel)


def main():
    optparser = optparse.OptionParser(
        """%prog [options]

This checks all help documents of Mercurial (topics, commands,
extensions and commands of them), if no file is specified by --file
option.
"""
    )
    optparser.add_option(
        "-v", "--verbose", help="enable additional output", action="store_true"
    )
    optparser.add_option(
        "-d", "--debug", help="debug mode", action="store_true"
    )
    optparser.add_option(
        "-f",
        "--file",
        help="filename to read in (or '-' for stdin)",
        action="store",
        default="",
    )

    optparser.add_option(
        "-t",
        "--topic",
        help="parse file as help topic",
        action="store_const",
        dest="initlevel",
        const=0,
    )
    optparser.add_option(
        "-c",
        "--command",
        help="parse file as help of core command",
        action="store_const",
        dest="initlevel",
        const=1,
    )
    optparser.add_option(
        "-e",
        "--extension",
        help="parse file as help of extension",
        action="store_const",
        dest="initlevel",
        const=1,
    )
    optparser.add_option(
        "-C",
        "--extension-command",
        help="parse file as help of extension command",
        action="store_const",
        dest="initlevel",
        const=3,
    )

    optparser.add_option(
        "-l",
        "--initlevel",
        help="set initial section level manually",
        action="store",
        type="int",
        default=0,
    )

    (options, args) = optparser.parse_args()

    ui = uimod.ui.load()
    ui.setconfig(b'ui', b'verbose', options.verbose, b'--verbose')
    ui.setconfig(b'ui', b'debug', options.debug, b'--debug')

    if options.file:
        if checkfile(ui, options.file, options.initlevel):
            sys.exit(1)
    else:
        if checkhghelps(ui):
            sys.exit(1)


if __name__ == "__main__":
    main()