view tests/testlib/check-compat-strings.py @ 6224:17ffdea0edbb stable

evolve: look for split successors of the correct ancestor (issue6648) Consider two changesets, 1 and 2. 1 is split into two new changesets and 2 is pruned. If we stand on 2 and call hg evolve, _singlesuccessor() will traverse ancestors of wdp in search of a changeset with successors to update to (it will be 1, which was split). In case of a split, select_split_successor() gets control. The issue is this function didn't traverse ancestors, and instead tried to look up successors of the original changeset (i.e. 2 in our case, which was pruned). We can make select_split_successor() aware of _singlesuccessor() logic by using the changeset that actually has successors without traversing ancestors again. It's done by storing that changeset in MultipleSuccessorsError exception.
author Anton Shestakov <av6@dwimlabs.net>
date Thu, 21 Apr 2022 22:19:27 +0400
parents 73cd416a1653
children
line wrap: on
line source

#!/usr/bin/env python
"""
This script finds compatibility-related comments with a node hash specified
in all files in a given directory (. by default) and looks up the hash in a
repo (~/hg by default) to determine if each of the comments is correct and,
if not, it suggests the correct release. This can prevent accidentally
removing a piece of code that was misattributed to a different (earlier)
release of core hg.

Usage: $0 WDIR HGREPO where WDIR is usually evolve/hgext3rd/ and HGREPO is
the place with core Mercurial repo (not just checkout). Said repo has to be
sufficiently up-to-date, otherwise this script may not work correctly.
"""

from __future__ import print_function

import argparse
import os
import re
from subprocess import check_output

def grepall(workdir, linere):
    for root, dirs, files in os.walk(workdir):
        for fname in files:
            if not fname.endswith('.py'):
                continue
            path = os.path.join(root, fname)
            with open(path, 'r') as src:
                for lineno, line in enumerate(src, 1):
                    for groups in linere.findall(line):
                        yield path, lineno, line, groups

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument('workdir', nargs='?', default='.')
    ap.add_argument('hgdir', nargs='?', default=os.path.expanduser('~/hg'))

    opts = ap.parse_args()

    linere = re.compile(r'hg <= ([0-9.]+) \(([0-9a-f+]+)\)')
    basecmd = ['hg', '--cwd', opts.hgdir, 'log', '-T', '{tags}']
    hgenv = {'HGPLAIN': '1', 'HGENCODING': 'UTF-8'}
    relcache = {}

    for path, lineno, line, match in grepall(opts.workdir, linere):
        expected, revset = match

        if revset not in relcache:
            tagrevset = 'max(tag("re:^[0-9]\\.[0-9]$") - (%s)::)' % revset
            cmd = basecmd + ['-r', tagrevset]
            relcache[revset] = check_output(cmd, env=hgenv).decode('UTF-8')

        lastrel = relcache[revset]

        if lastrel != expected:
            print('%s:%d:%s' % (path, lineno, line.rstrip('\r\n')))
            print('\\ actual last major release without %s is %s'
                  % (revset, lastrel))
            print()

if __name__ == '__main__':
    main()