hgstyle.py revision 11406:dd204e5baba7
1#! /usr/bin/env python 2# Copyright (c) 2014 ARM Limited 3# All rights reserved 4# 5# The license below extends only to copyright in the software and shall 6# not be construed as granting a license to any other intellectual 7# property including but not limited to intellectual property relating 8# to a hardware implementation of the functionality of the software 9# licensed hereunder. You may use the software subject to the license 10# terms below provided that you ensure that this notice is replicated 11# unmodified and in its entirety in all distributions of the software, 12# modified or unmodified, in source code or in binary form. 13# 14# Copyright (c) 2006 The Regents of The University of Michigan 15# Copyright (c) 2007,2011 The Hewlett-Packard Development Company 16# Copyright (c) 2016 Advanced Micro Devices, Inc. 17# All rights reserved. 18# 19# Redistribution and use in source and binary forms, with or without 20# modification, are permitted provided that the following conditions are 21# met: redistributions of source code must retain the above copyright 22# notice, this list of conditions and the following disclaimer; 23# redistributions in binary form must reproduce the above copyright 24# notice, this list of conditions and the following disclaimer in the 25# documentation and/or other materials provided with the distribution; 26# neither the name of the copyright holders nor the names of its 27# contributors may be used to endorse or promote products derived from 28# this software without specific prior written permission. 29# 30# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 36# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 37# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 38# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 39# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 40# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41# 42# Authors: Nathan Binkert 43# Steve Reinhardt 44 45import sys 46import os 47from os.path import join as joinpath 48 49current_dir = os.path.dirname(__file__) 50sys.path.insert(0, current_dir) 51 52from style.verifiers import all_verifiers 53from style.style import MercurialUI, check_ignores 54from style.region import * 55 56from mercurial import bdiff, mdiff, commands 57 58def modified_regions(old_data, new_data): 59 regions = Regions() 60 beg = None 61 for pbeg, pend, fbeg, fend in bdiff.blocks(old_data, new_data): 62 if beg is not None and beg != fbeg: 63 regions.append(beg, fbeg) 64 beg = fend 65 return regions 66 67def modregions(wctx, fname): 68 fctx = wctx.filectx(fname) 69 pctx = fctx.parents() 70 71 file_data = fctx.data() 72 lines = mdiff.splitnewlines(file_data) 73 if len(pctx) in (1, 2): 74 mod_regions = modified_regions(pctx[0].data(), file_data) 75 if len(pctx) == 2: 76 m2 = modified_regions(pctx[1].data(), file_data) 77 # only the lines that are new in both 78 mod_regions &= m2 79 else: 80 mod_regions = Regions() 81 mod_regions.append(0, len(lines)) 82 83 return mod_regions 84 85 86def _modified_regions(repo, patterns, **kwargs): 87 opt_all = kwargs.get('all', False) 88 opt_no_ignore = kwargs.get('no_ignore', False) 89 90 # Import the match (repository file name matching helper) 91 # function. Different versions of Mercurial keep it in different 92 # modules and implement them differently. 93 try: 94 from mercurial import scmutil 95 m = scmutil.match(repo[None], patterns, kwargs) 96 except ImportError: 97 from mercurial import cmdutil 98 m = cmdutil.match(repo, patterns, kwargs) 99 100 modified, added, removed, deleted, unknown, ignore, clean = \ 101 repo.status(match=m, clean=opt_all) 102 103 if not opt_all: 104 try: 105 wctx = repo.workingctx() 106 except: 107 from mercurial import context 108 wctx = context.workingctx(repo) 109 110 files = [ (fn, all_regions) for fn in added ] + \ 111 [ (fn, modregions(wctx, fn)) for fn in modified ] 112 else: 113 files = [ (fn, all_regions) for fn in added + modified + clean ] 114 115 for fname, mod_regions in files: 116 if opt_no_ignore or not check_ignores(fname): 117 yield fname, mod_regions 118 119 120def do_check_style(hgui, repo, *pats, **opts): 121 """check files for proper m5 style guidelines 122 123 Without an argument, checks all modified and added files for gem5 124 coding style violations. A list of files can be specified to limit 125 the checker to a subset of the repository. The style rules are 126 normally applied on a diff of the repository state (i.e., added 127 files are checked in their entirety while only modifications of 128 modified files are checked). 129 130 The --all option can be specified to include clean files and check 131 modified files in their entirety. 132 133 The --fix-<check>, --ignore-<check>, and --skip-<check> options 134 can be used to control individual style checks: 135 136 --fix-<check> will perform the check and automatically attempt to 137 fix sny style error (printing a warning if unsuccessful) 138 139 --ignore-<check> will perform the check but ignore any errors 140 found (other than printing a message for each) 141 142 --skip-<check> will skip performing the check entirely 143 144 If none of these options are given, all checks will be performed 145 and the user will be prompted on how to handle each error. 146 147 --fix-all, --ignore-all, and --skip-all are equivalent to specifying 148 --fix-<check>, --ignore-<check>, or --skip-<check> for all checks, 149 respectively. However, option settings for specific checks take 150 precedence. Thus --skip-all --fix-white can be used to skip every 151 check other than whitespace errors, which will be checked and 152 automatically fixed. 153 154 The -v/--verbose flag will display the offending line(s) as well 155 as their location. 156 """ 157 158 ui = MercurialUI(hgui, verbose=hgui.verbose) 159 160 # instantiate varifier objects 161 verifiers = [v(ui, opts, base=repo.root) for v in all_verifiers] 162 163 for fname, mod_regions in _modified_regions(repo, pats, **opts): 164 for verifier in verifiers: 165 if verifier.apply(joinpath(repo.root, fname), mod_regions): 166 return True 167 168 return False 169 170def check_hook(hooktype): 171 if hooktype not in ('pretxncommit', 'pre-qrefresh'): 172 raise AttributeError, \ 173 "This hook is not meant for %s" % hooktype 174 175# This function provides a hook that is called before transaction 176# commit and on qrefresh 177def check_style(ui, repo, hooktype, **kwargs): 178 check_hook(hooktype) 179 args = {} 180 181 try: 182 return do_check_style(ui, repo, **args) 183 except Exception, e: 184 import traceback 185 traceback.print_exc() 186 return True 187 188try: 189 from mercurial.i18n import _ 190except ImportError: 191 def _(arg): 192 return arg 193 194_common_region_options = [ 195 ('a', 'all', False, 196 _("include clean files and unmodified parts of modified files")), 197 ('', 'no-ignore', False, _("ignore the style ignore list")), 198 ] 199 200 201fix_opts = [('f', 'fix-all', False, _("fix all style errors"))] + \ 202 [('', 'fix-' + v.opt_name, False, 203 _('fix errors in ' + v.test_name)) for v in all_verifiers] 204ignore_opts = [('', 'ignore-all', False, _("ignore all style errors"))] + \ 205 [('', 'ignore-' + v.opt_name, False, 206 _('ignore errors in ' + v.test_name)) for v in all_verifiers] 207skip_opts = [('', 'skip-all', False, _("skip all style error checks"))] + \ 208 [('', 'skip-' + v.opt_name, False, 209 _('skip checking for ' + v.test_name)) for v in all_verifiers] 210all_opts = fix_opts + ignore_opts + skip_opts 211 212 213cmdtable = { 214 '^m5style' : ( 215 do_check_style, all_opts + _common_region_options + commands.walkopts, 216 _('hg m5style [-a] [FILE]...')), 217} 218 219if __name__ == '__main__': 220 print >> sys.stderr, "This file cannot be used from the command line. Use" 221 print >> sys.stderr, "style.py instead." 222 sys.exit(1) 223