hgstyle.py revision 11406
14678SN/A#! /usr/bin/env python
210293SN/A# Copyright (c) 2014 ARM Limited
310293SN/A# All rights reserved
410293SN/A#
510293SN/A# The license below extends only to copyright in the software and shall
610293SN/A# not be construed as granting a license to any other intellectual
710293SN/A# property including but not limited to intellectual property relating
810293SN/A# to a hardware implementation of the functionality of the software
910293SN/A# licensed hereunder.  You may use the software subject to the license
1010293SN/A# terms below provided that you ensure that this notice is replicated
1110293SN/A# unmodified and in its entirety in all distributions of the software,
1210293SN/A# modified or unmodified, in source code or in binary form.
1310293SN/A#
145465SN/A# Copyright (c) 2006 The Regents of The University of Michigan
158227SN/A# Copyright (c) 2007,2011 The Hewlett-Packard Development Company
1611319SN/A# Copyright (c) 2016 Advanced Micro Devices, Inc.
174678SN/A# All rights reserved.
184678SN/A#
194678SN/A# Redistribution and use in source and binary forms, with or without
204678SN/A# modification, are permitted provided that the following conditions are
214678SN/A# met: redistributions of source code must retain the above copyright
224678SN/A# notice, this list of conditions and the following disclaimer;
234678SN/A# redistributions in binary form must reproduce the above copyright
244678SN/A# notice, this list of conditions and the following disclaimer in the
254678SN/A# documentation and/or other materials provided with the distribution;
264678SN/A# neither the name of the copyright holders nor the names of its
274678SN/A# contributors may be used to endorse or promote products derived from
284678SN/A# this software without specific prior written permission.
294678SN/A#
304678SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
314678SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
324678SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
334678SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
344678SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
354678SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
364678SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
374678SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
384678SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
394678SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
404678SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
414678SN/A#
424678SN/A# Authors: Nathan Binkert
4311319SN/A#          Steve Reinhardt
444678SN/A
4511406Sandreas.sandberg@arm.comimport sys
468227SN/Aimport os
4711406Sandreas.sandberg@arm.comfrom os.path import join as joinpath
484678SN/A
4911406Sandreas.sandberg@arm.comcurrent_dir = os.path.dirname(__file__)
5011406Sandreas.sandberg@arm.comsys.path.insert(0, current_dir)
5111406Sandreas.sandberg@arm.com
5211406Sandreas.sandberg@arm.comfrom style.verifiers import all_verifiers
5311406Sandreas.sandberg@arm.comfrom style.style import MercurialUI, check_ignores
5411406Sandreas.sandberg@arm.comfrom style.region import *
5511406Sandreas.sandberg@arm.com
5610293SN/Afrom mercurial import bdiff, mdiff, commands
577807SN/A
588227SN/Adef modified_regions(old_data, new_data):
598227SN/A    regions = Regions()
608227SN/A    beg = None
618227SN/A    for pbeg, pend, fbeg, fend in bdiff.blocks(old_data, new_data):
628227SN/A        if beg is not None and beg != fbeg:
638227SN/A            regions.append(beg, fbeg)
648227SN/A        beg = fend
658227SN/A    return regions
668227SN/A
678227SN/Adef modregions(wctx, fname):
688227SN/A    fctx = wctx.filectx(fname)
698227SN/A    pctx = fctx.parents()
708227SN/A
718227SN/A    file_data = fctx.data()
728227SN/A    lines = mdiff.splitnewlines(file_data)
738227SN/A    if len(pctx) in (1, 2):
748227SN/A        mod_regions = modified_regions(pctx[0].data(), file_data)
758227SN/A        if len(pctx) == 2:
768227SN/A            m2 = modified_regions(pctx[1].data(), file_data)
778227SN/A            # only the lines that are new in both
788227SN/A            mod_regions &= m2
798227SN/A    else:
808227SN/A        mod_regions = Regions()
819135SN/A        mod_regions.append(0, len(lines))
828227SN/A
838227SN/A    return mod_regions
848227SN/A
8510293SN/A
8610692SN/Adef _modified_regions(repo, patterns, **kwargs):
8710692SN/A    opt_all = kwargs.get('all', False)
8810692SN/A    opt_no_ignore = kwargs.get('no_ignore', False)
8910692SN/A
9010692SN/A    # Import the match (repository file name matching helper)
9110692SN/A    # function. Different versions of Mercurial keep it in different
9210692SN/A    # modules and implement them differently.
9310692SN/A    try:
9410692SN/A        from mercurial import scmutil
9510692SN/A        m = scmutil.match(repo[None], patterns, kwargs)
9610692SN/A    except ImportError:
9710692SN/A        from mercurial import cmdutil
9810692SN/A        m = cmdutil.match(repo, patterns, kwargs)
9910692SN/A
10010692SN/A    modified, added, removed, deleted, unknown, ignore, clean = \
10110692SN/A        repo.status(match=m, clean=opt_all)
10210692SN/A
10310692SN/A    if not opt_all:
10410692SN/A        try:
10510692SN/A            wctx = repo.workingctx()
10610692SN/A        except:
10710692SN/A            from mercurial import context
10810692SN/A            wctx = context.workingctx(repo)
10910692SN/A
11010692SN/A        files = [ (fn, all_regions) for fn in added ] + \
11110692SN/A            [ (fn,  modregions(wctx, fn)) for fn in modified ]
11210692SN/A    else:
11310692SN/A        files = [ (fn, all_regions) for fn in added + modified + clean ]
11410692SN/A
11510692SN/A    for fname, mod_regions in files:
11610692SN/A        if opt_no_ignore or not check_ignores(fname):
11710692SN/A            yield fname, mod_regions
11810692SN/A
11910692SN/A
12010293SN/Adef do_check_style(hgui, repo, *pats, **opts):
12110293SN/A    """check files for proper m5 style guidelines
12210293SN/A
12310293SN/A    Without an argument, checks all modified and added files for gem5
12410293SN/A    coding style violations. A list of files can be specified to limit
12510293SN/A    the checker to a subset of the repository. The style rules are
12610293SN/A    normally applied on a diff of the repository state (i.e., added
12710293SN/A    files are checked in their entirety while only modifications of
12810293SN/A    modified files are checked).
12910293SN/A
13010293SN/A    The --all option can be specified to include clean files and check
13110293SN/A    modified files in their entirety.
13211319SN/A
13311319SN/A    The --fix-<check>, --ignore-<check>, and --skip-<check> options
13411319SN/A    can be used to control individual style checks:
13511319SN/A
13611319SN/A    --fix-<check> will perform the check and automatically attempt to
13711319SN/A      fix sny style error (printing a warning if unsuccessful)
13811319SN/A
13911319SN/A    --ignore-<check> will perform the check but ignore any errors
14011319SN/A      found (other than printing a message for each)
14111319SN/A
14211319SN/A    --skip-<check> will skip performing the check entirely
14311319SN/A
14411319SN/A    If none of these options are given, all checks will be performed
14511319SN/A    and the user will be prompted on how to handle each error.
14611319SN/A
14711319SN/A    --fix-all, --ignore-all, and --skip-all are equivalent to specifying
14811319SN/A    --fix-<check>, --ignore-<check>, or --skip-<check> for all checks,
14911319SN/A    respectively.  However, option settings for specific checks take
15011319SN/A    precedence.  Thus --skip-all --fix-white can be used to skip every
15111319SN/A    check other than whitespace errors, which will be checked and
15211319SN/A    automatically fixed.
15311319SN/A
15411319SN/A    The -v/--verbose flag will display the offending line(s) as well
15511319SN/A    as their location.
15610293SN/A    """
15710691SN/A
15810691SN/A    ui = MercurialUI(hgui, verbose=hgui.verbose)
1595465SN/A
16011319SN/A    # instantiate varifier objects
16111406Sandreas.sandberg@arm.com    verifiers = [v(ui, opts, base=repo.root) for v in all_verifiers]
1624678SN/A
16310692SN/A    for fname, mod_regions in _modified_regions(repo, pats, **opts):
16411319SN/A        for verifier in verifiers:
16511406Sandreas.sandberg@arm.com            if verifier.apply(joinpath(repo.root, fname), mod_regions):
16610692SN/A                return True
1674678SN/A
1684678SN/A    return False
1694678SN/A
1707807SN/Adef check_hook(hooktype):
1717807SN/A    if hooktype not in ('pretxncommit', 'pre-qrefresh'):
1727807SN/A        raise AttributeError, \
1737807SN/A              "This hook is not meant for %s" % hooktype
1747807SN/A
17511319SN/A# This function provides a hook that is called before transaction
17611319SN/A# commit and on qrefresh
1777827SN/Adef check_style(ui, repo, hooktype, **kwargs):
1787807SN/A    check_hook(hooktype)
1797827SN/A    args = {}
1807828SN/A
1817828SN/A    try:
1827828SN/A        return do_check_style(ui, repo, **args)
1837828SN/A    except Exception, e:
1847828SN/A        import traceback
1857828SN/A        traceback.print_exc()
1867828SN/A        return True
1877807SN/A
1885465SN/Atry:
1895465SN/A    from mercurial.i18n import _
1905465SN/Aexcept ImportError:
1915465SN/A    def _(arg):
1925465SN/A        return arg
1935465SN/A
19410692SN/A_common_region_options = [
19510692SN/A    ('a', 'all', False,
19610692SN/A     _("include clean files and unmodified parts of modified files")),
19710692SN/A    ('', 'no-ignore', False, _("ignore the style ignore list")),
19810692SN/A    ]
19910692SN/A
20011319SN/A
20111319SN/Afix_opts = [('f', 'fix-all', False, _("fix all style errors"))] + \
20211319SN/A           [('', 'fix-' + v.opt_name, False,
20311319SN/A             _('fix errors in ' + v.test_name)) for v in all_verifiers]
20411319SN/Aignore_opts = [('', 'ignore-all', False, _("ignore all style errors"))] + \
20511319SN/A              [('', 'ignore-' + v.opt_name, False,
20611319SN/A                _('ignore errors in ' + v.test_name)) for v in all_verifiers]
20711319SN/Askip_opts = [('', 'skip-all', False, _("skip all style error checks"))] + \
20811319SN/A            [('', 'skip-' + v.opt_name, False,
20911319SN/A              _('skip checking for ' + v.test_name)) for v in all_verifiers]
21011319SN/Aall_opts = fix_opts + ignore_opts + skip_opts
21111319SN/A
21211319SN/A
2135465SN/Acmdtable = {
21410293SN/A    '^m5style' : (
21511319SN/A        do_check_style, all_opts + _common_region_options + commands.walkopts,
21610293SN/A        _('hg m5style [-a] [FILE]...')),
2175465SN/A}
2187807SN/A
2194678SN/Aif __name__ == '__main__':
22011406Sandreas.sandberg@arm.com    print >> sys.stderr, "This file cannot be used from the command line. Use"
22111406Sandreas.sandberg@arm.com    print >> sys.stderr, "style.py instead."
22211406Sandreas.sandberg@arm.com    sys.exit(1)
223