style.py (8226:bca419132437) | style.py (8227:f3aaa2470b5a) |
---|---|
1#! /usr/bin/env python 2# Copyright (c) 2006 The Regents of The University of Michigan | 1#! /usr/bin/env python 2# Copyright (c) 2006 The Regents of The University of Michigan |
3# Copyright (c) 2007 The Hewlett-Packard Development Company | 3# Copyright (c) 2007,2011 The Hewlett-Packard Development Company |
4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are 8# met: redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer; 10# redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the --- 11 unchanged lines hidden (view full) --- 23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28# 29# Authors: Nathan Binkert 30 | 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are 8# met: redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer; 10# redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the --- 11 unchanged lines hidden (view full) --- 23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28# 29# Authors: Nathan Binkert 30 |
31import re | 31import heapq |
32import os | 32import os |
33import re |
|
33import sys 34 | 34import sys 35 |
35sys.path.insert(0, os.path.dirname(__file__)) | 36from os.path import dirname, join as joinpath 37from itertools import count 38from mercurial import bdiff, mdiff |
36 | 39 |
40current_dir = dirname(__file__) 41sys.path.insert(0, current_dir) 42sys.path.insert(1, joinpath(dirname(current_dir), 'src', 'python')) 43 44from m5.util import neg_inf, pos_inf, Region, Regions |
|
37from file_types import lang_type 38 | 45from file_types import lang_type 46 |
47all_regions = Region(neg_inf, pos_inf) 48 |
|
39tabsize = 8 40lead = re.compile(r'^([ \t]+)') 41trail = re.compile(r'([ \t]+)$') 42any_control = re.compile(r'\b(if|while|for)[ \t]*[(]') 43good_control = re.compile(r'\b(if|while|for) [(]') 44 | 49tabsize = 8 50lead = re.compile(r'^([ \t]+)') 51trail = re.compile(r'([ \t]+)$') 52any_control = re.compile(r'\b(if|while|for)[ \t]*[(]') 53good_control = re.compile(r'\b(if|while|for) [(]') 54 |
45whitespace_types = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons')) | |
46format_types = set(('C', 'C++')) 47 | 55format_types = set(('C', 'C++')) 56 |
57def modified_regions(old_data, new_data): 58 regions = Regions() 59 beg = None 60 for pbeg, pend, fbeg, fend in bdiff.blocks(old_data, new_data): 61 if beg is not None and beg != fbeg: 62 regions.append(beg, fbeg) 63 beg = fend 64 return regions 65 66def modregions(wctx, fname): 67 fctx = wctx.filectx(fname) 68 pctx = fctx.parents() 69 70 file_data = fctx.data() 71 lines = mdiff.splitnewlines(file_data) 72 if len(pctx) in (1, 2): 73 mod_regions = modified_regions(pctx[0].data(), file_data) 74 if len(pctx) == 2: 75 m2 = modified_regions(pctx[1].data(), file_data) 76 # only the lines that are new in both 77 mod_regions &= m2 78 else: 79 mod_regions = Regions() 80 mod_regions.add(0, len(lines)) 81 82 return mod_regions 83 |
|
48class UserInterface(object): 49 def __init__(self, verbose=False, auto=False): 50 self.auto = auto 51 self.verbose = verbose 52 53 def prompt(self, prompt, results, default): 54 if self.auto: 55 return self.auto --- 16 unchanged lines hidden (view full) --- 72 73class StdioUI(UserInterface): 74 def do_prompt(self, prompt, results, default): 75 return raw_input(prompt) or default 76 77 def write(self, string): 78 sys.stdout.write(string) 79 | 84class UserInterface(object): 85 def __init__(self, verbose=False, auto=False): 86 self.auto = auto 87 self.verbose = verbose 88 89 def prompt(self, prompt, results, default): 90 if self.auto: 91 return self.auto --- 16 unchanged lines hidden (view full) --- 108 109class StdioUI(UserInterface): 110 def do_prompt(self, prompt, results, default): 111 return raw_input(prompt) or default 112 113 def write(self, string): 114 sys.stdout.write(string) 115 |
80def checkwhite_line(line): 81 match = lead.search(line) 82 if match and match.group(1).find('\t') != -1: 83 return False | 116class Region(object): 117 def __init__(self, asdf): 118 self.regions = Foo |
84 | 119 |
85 match = trail.search(line) 86 if match: 87 return False | 120class Verifier(object): 121 def __init__(self, ui, repo=None): 122 self.ui = ui 123 self.repo = repo 124 if repo is None: 125 self.wctx = None |
88 | 126 |
89 return True | 127 def __getattr__(self, attr): 128 if attr in ('prompt', 'write'): 129 return getattr(self.ui, attr) |
90 | 130 |
91def checkwhite(filename): 92 if lang_type(filename) not in whitespace_types: 93 return | 131 if attr == 'wctx': 132 try: 133 wctx = repo.workingctx() 134 except: 135 from mercurial import context 136 wctx = context.workingctx(repo) 137 self.wctx = wctx 138 return wctx |
94 | 139 |
95 try: 96 f = file(filename, 'r+') 97 except OSError, msg: 98 print 'could not open file %s: %s' % (filename, msg) 99 return | 140 raise AttributeError |
100 | 141 |
101 for num,line in enumerate(f): 102 if not checkwhite_line(line): 103 yield line,num + 1 | 142 def open(self, filename, mode): 143 if self.repo: 144 filename = self.repo.wjoin(filename) |
104 | 145 |
105def fixwhite_line(line): 106 if lead.search(line): 107 newline = '' 108 for i,c in enumerate(line): 109 if c == ' ': 110 newline += ' ' 111 elif c == '\t': 112 newline += ' ' * (tabsize - len(newline) % tabsize) 113 else: 114 newline += line[i:] 115 break | 146 try: 147 f = file(filename, mode) 148 except OSError, msg: 149 print 'could not open file %s: %s' % (filename, msg) 150 return None |
116 | 151 |
117 line = newline | 152 return f |
118 | 153 |
119 return line.rstrip() + '\n' | 154 def skip(self, filename): 155 return lang_type(filename) not in self.languages |
120 | 156 |
121def fixwhite(filename, fixonly=None): 122 if lang_type(filename) not in whitespace_types: 123 return | 157 def check(self, filename, regions=all_regions): 158 f = self.open(filename, 'r') |
124 | 159 |
125 try: 126 f = file(filename, 'r+') 127 except OSError, msg: 128 print 'could not open file %s: %s' % (filename, msg) 129 return | 160 errors = 0 161 for num,line in enumerate(f): 162 if num not in regions: 163 continue 164 if not self.check_line(line): 165 self.write("invalid %s in %s:%d\n" % \ 166 (self.test_name, filename, num + 1)) 167 if self.ui.verbose: 168 self.write(">>%s<<\n" % line[-1]) 169 errors += 1 170 return errors |
130 | 171 |
131 lines = list(f) | 172 def fix(self, filename, regions=all_regions): 173 f = self.open(filename, 'r+') |
132 | 174 |
133 f.seek(0) 134 f.truncate() | 175 lines = list(f) |
135 | 176 |
136 for i,line in enumerate(lines): 137 if fixonly is None or i in fixonly: 138 line = fixwhite_line(line) | 177 f.seek(0) 178 f.truncate() |
139 | 179 |
140 print >>f, line, | 180 for i,line in enumerate(lines): 181 if i in regions: 182 line = self.fix_line(line) |
141 | 183 |
184 f.write(line) 185 f.close() 186 187class Whitespace(Verifier): 188 languages = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons')) 189 test_name = 'whitespace' 190 def check_line(self, line): 191 match = lead.search(line) 192 if match and match.group(1).find('\t') != -1: 193 return False 194 195 match = trail.search(line) 196 if match: 197 return False 198 199 return True 200 201 def fix_line(self, line): 202 if lead.search(line): 203 newline = '' 204 for i,c in enumerate(line): 205 if c == ' ': 206 newline += ' ' 207 elif c == '\t': 208 newline += ' ' * (tabsize - len(newline) % tabsize) 209 else: 210 newline += line[i:] 211 break 212 213 line = newline 214 215 return line.rstrip() + '\n' 216 |
|
142def linelen(line): 143 tabs = line.count('\t') 144 if not tabs: 145 return len(line) 146 147 count = 0 148 for c in line: 149 if c == '\t': --- 86 unchanged lines hidden (view full) --- 236 if cpp: 237 match = any_control.search(line) 238 if match and not good_control.search(line): 239 stats.badcontrol += 1 240 if verbose > 1: 241 msg(i, line, 'improper spacing after %s' % match.group(1)) 242 bad() 243 | 217def linelen(line): 218 tabs = line.count('\t') 219 if not tabs: 220 return len(line) 221 222 count = 0 223 for c in line: 224 if c == '\t': --- 86 unchanged lines hidden (view full) --- 311 if cpp: 312 match = any_control.search(line) 313 if match and not good_control.search(line): 314 stats.badcontrol += 1 315 if verbose > 1: 316 msg(i, line, 'improper spacing after %s' % match.group(1)) 317 bad() 318 |
244def modified_lines(old_data, new_data, max_lines): 245 from itertools import count 246 from mercurial import bdiff, mdiff 247 248 modified = set() 249 counter = count() 250 for pbeg, pend, fbeg, fend in bdiff.blocks(old_data, new_data): 251 for i in counter: 252 if i < fbeg: 253 modified.add(i) 254 elif i + 1 >= fend: 255 break 256 elif i > max_lines: 257 break 258 return modified 259 | |
260def do_check_style(hgui, repo, *files, **args): 261 """check files for proper m5 style guidelines""" 262 from mercurial import mdiff, util 263 264 auto = args.get('auto', False) 265 if auto: 266 auto = 'f' 267 ui = MercurialUI(hgui, hgui.verbose, auto) 268 269 if files: 270 files = frozenset(files) 271 272 def skip(name): 273 return files and name in files 274 | 319def do_check_style(hgui, repo, *files, **args): 320 """check files for proper m5 style guidelines""" 321 from mercurial import mdiff, util 322 323 auto = args.get('auto', False) 324 if auto: 325 auto = 'f' 326 ui = MercurialUI(hgui, hgui.verbose, auto) 327 328 if files: 329 files = frozenset(files) 330 331 def skip(name): 332 return files and name in files 333 |
275 def prompt(name, func, fixonly=None): | 334 def prompt(name, func, regions=all_regions): |
276 result = ui.prompt("(a)bort, (i)gnore, or (f)ix?", 'aif', 'a') 277 if result == 'a': 278 return True 279 elif result == 'f': | 335 result = ui.prompt("(a)bort, (i)gnore, or (f)ix?", 'aif', 'a') 336 if result == 'a': 337 return True 338 elif result == 'f': |
280 func(repo.wjoin(name), fixonly) | 339 func(repo.wjoin(name), regions) |
281 282 return False 283 284 modified, added, removed, deleted, unknown, ignore, clean = repo.status() 285 | 340 341 return False 342 343 modified, added, removed, deleted, unknown, ignore, clean = repo.status() 344 |
345 whitespace = Whitespace(ui) |
|
286 for fname in added: | 346 for fname in added: |
287 if skip(fname): | 347 if skip(fname) or whitespace.skip(fname): |
288 continue 289 | 348 continue 349 |
290 ok = True 291 for line,num in checkwhite(repo.wjoin(fname)): 292 ui.write("invalid whitespace in %s:%d\n" % (fname, num)) 293 if ui.verbose: 294 ui.write(">>%s<<\n" % line[-1]) 295 ok = False 296 297 if not ok: 298 if prompt(fname, fixwhite): | 350 errors = whitespace.check(fname) 351 if errors: 352 print errors 353 if prompt(fname, whitespace.fix): |
299 return True 300 301 try: 302 wctx = repo.workingctx() 303 except: 304 from mercurial import context 305 wctx = context.workingctx(repo) 306 307 for fname in modified: | 354 return True 355 356 try: 357 wctx = repo.workingctx() 358 except: 359 from mercurial import context 360 wctx = context.workingctx(repo) 361 362 for fname in modified: |
308 if skip(fname): | 363 if skip(fname) or whitespace.skip(fname): |
309 continue 310 | 364 continue 365 |
311 if lang_type(fname) not in whitespace_types: 312 continue | 366 regions = modregions(wctx, fname) |
313 | 367 |
314 fctx = wctx.filectx(fname) 315 pctx = fctx.parents() 316 317 file_data = fctx.data() 318 lines = mdiff.splitnewlines(file_data) 319 if len(pctx) in (1, 2): 320 mod_lines = modified_lines(pctx[0].data(), file_data, len(lines)) 321 if len(pctx) == 2: 322 m2 = modified_lines(pctx[1].data(), file_data, len(lines)) 323 # only the lines that are new in both 324 mod_lines = mod_lines & m2 325 else: 326 mod_lines = xrange(0, len(lines)) 327 328 fixonly = set() 329 for i,line in enumerate(lines): 330 if i not in mod_lines: 331 continue 332 333 if checkwhite_line(line): 334 continue 335 336 ui.write("invalid whitespace: %s:%d\n" % (fname, i+1)) 337 if ui.verbose: 338 ui.write(">>%s<<\n" % line[:-1]) 339 fixonly.add(i) 340 341 if fixonly: 342 if prompt(fname, fixwhite, fixonly): | 368 errors = whitespace.check(fname, regions) 369 if errors: 370 if prompt(fname, whitespace.fix, regions): |
343 return True 344 345def do_check_format(hgui, repo, **args): 346 ui = MercurialUI(hgui, hgui.verbose, auto) 347 348 modified, added, removed, deleted, unknown, ignore, clean = repo.status() 349 350 verbose = 0 --- 111 unchanged lines hidden --- | 371 return True 372 373def do_check_format(hgui, repo, **args): 374 ui = MercurialUI(hgui, hgui.verbose, auto) 375 376 modified, added, removed, deleted, unknown, ignore, clean = repo.status() 377 378 verbose = 0 --- 111 unchanged lines hidden --- |