style.py revision 9081:bbb0132f0369
18706Sandreas.hansson@arm.com#! /usr/bin/env python 212522Sandreas.sandberg@arm.com# Copyright (c) 2006 The Regents of The University of Michigan 38706Sandreas.hansson@arm.com# Copyright (c) 2007,2011 The Hewlett-Packard Development Company 48706Sandreas.hansson@arm.com# All rights reserved. 58706Sandreas.hansson@arm.com# 68706Sandreas.hansson@arm.com# Redistribution and use in source and binary forms, with or without 78706Sandreas.hansson@arm.com# modification, are permitted provided that the following conditions are 88706Sandreas.hansson@arm.com# met: redistributions of source code must retain the above copyright 98706Sandreas.hansson@arm.com# notice, this list of conditions and the following disclaimer; 108706Sandreas.hansson@arm.com# redistributions in binary form must reproduce the above copyright 118706Sandreas.hansson@arm.com# notice, this list of conditions and the following disclaimer in the 128706Sandreas.hansson@arm.com# documentation and/or other materials provided with the distribution; 138706Sandreas.hansson@arm.com# neither the name of the copyright holders nor the names of its 148706Sandreas.hansson@arm.com# contributors may be used to endorse or promote products derived from 158706Sandreas.hansson@arm.com# this software without specific prior written permission. 168706Sandreas.hansson@arm.com# 178706Sandreas.hansson@arm.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 188706Sandreas.hansson@arm.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 198706Sandreas.hansson@arm.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 208706Sandreas.hansson@arm.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 218706Sandreas.hansson@arm.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 228706Sandreas.hansson@arm.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 238706Sandreas.hansson@arm.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 248706Sandreas.hansson@arm.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 258706Sandreas.hansson@arm.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 268706Sandreas.hansson@arm.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 278706Sandreas.hansson@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 288706Sandreas.hansson@arm.com# 298706Sandreas.hansson@arm.com# Authors: Nathan Binkert 308706Sandreas.hansson@arm.com 318706Sandreas.hansson@arm.comimport heapq 328706Sandreas.hansson@arm.comimport os 338706Sandreas.hansson@arm.comimport re 348706Sandreas.hansson@arm.comimport sys 358706Sandreas.hansson@arm.com 368706Sandreas.hansson@arm.comfrom os.path import dirname, join as joinpath 378706Sandreas.hansson@arm.comfrom itertools import count 388706Sandreas.hansson@arm.comfrom mercurial import bdiff, mdiff 398706Sandreas.hansson@arm.com 408706Sandreas.hansson@arm.comcurrent_dir = dirname(__file__) 418706Sandreas.hansson@arm.comsys.path.insert(0, current_dir) 428706Sandreas.hansson@arm.comsys.path.insert(1, joinpath(dirname(current_dir), 'src', 'python')) 438706Sandreas.hansson@arm.com 448853Sandreas.hansson@arm.comfrom m5.util import neg_inf, pos_inf, Region, Regions 458853Sandreas.hansson@arm.comimport sort_includes 468853Sandreas.hansson@arm.comfrom file_types import lang_type 478853Sandreas.hansson@arm.com 488853Sandreas.hansson@arm.comall_regions = Regions(Region(neg_inf, pos_inf)) 498853Sandreas.hansson@arm.com 508853Sandreas.hansson@arm.comtabsize = 8 518853Sandreas.hansson@arm.comlead = re.compile(r'^([ \t]+)') 528853Sandreas.hansson@arm.comtrail = re.compile(r'([ \t]+)$') 538853Sandreas.hansson@arm.comany_control = re.compile(r'\b(if|while|for)[ \t]*[(]') 548853Sandreas.hansson@arm.comgood_control = re.compile(r'\b(if|while|for) [(]') 558706Sandreas.hansson@arm.com 568706Sandreas.hansson@arm.comformat_types = set(('C', 'C++')) 578706Sandreas.hansson@arm.com 588706Sandreas.hansson@arm.comdef modified_regions(old_data, new_data): 598706Sandreas.hansson@arm.com regions = Regions() 608706Sandreas.hansson@arm.com beg = None 618706Sandreas.hansson@arm.com for pbeg, pend, fbeg, fend in bdiff.blocks(old_data, new_data): 628706Sandreas.hansson@arm.com if beg is not None and beg != fbeg: 638706Sandreas.hansson@arm.com regions.append(beg, fbeg) 648706Sandreas.hansson@arm.com beg = fend 658706Sandreas.hansson@arm.com return regions 668853Sandreas.hansson@arm.com 678853Sandreas.hansson@arm.comdef modregions(wctx, fname): 688706Sandreas.hansson@arm.com fctx = wctx.filectx(fname) 698706Sandreas.hansson@arm.com pctx = fctx.parents() 708706Sandreas.hansson@arm.com 718706Sandreas.hansson@arm.com file_data = fctx.data() 728706Sandreas.hansson@arm.com lines = mdiff.splitnewlines(file_data) 738706Sandreas.hansson@arm.com if len(pctx) in (1, 2): 748706Sandreas.hansson@arm.com mod_regions = modified_regions(pctx[0].data(), file_data) 758706Sandreas.hansson@arm.com if len(pctx) == 2: 768706Sandreas.hansson@arm.com m2 = modified_regions(pctx[1].data(), file_data) 778706Sandreas.hansson@arm.com # only the lines that are new in both 788706Sandreas.hansson@arm.com mod_regions &= m2 798706Sandreas.hansson@arm.com else: 808706Sandreas.hansson@arm.com mod_regions = Regions() 818853Sandreas.hansson@arm.com mod_regions.add(0, len(lines)) 828853Sandreas.hansson@arm.com 838853Sandreas.hansson@arm.com return mod_regions 848922Swilliam.wang@arm.com 858706Sandreas.hansson@arm.comclass UserInterface(object): 869814Sandreas.hansson@arm.com def __init__(self, verbose=False, auto=False): 879814Sandreas.hansson@arm.com self.auto = auto 889814Sandreas.hansson@arm.com self.verbose = verbose 898706Sandreas.hansson@arm.com 909814Sandreas.hansson@arm.com def prompt(self, prompt, results, default): 9113893Sgabeblack@google.com if self.auto: 9213893Sgabeblack@google.com return self.auto 938706Sandreas.hansson@arm.com 948706Sandreas.hansson@arm.com while True: 958706Sandreas.hansson@arm.com result = self.do_prompt(prompt, results, default) 968706Sandreas.hansson@arm.com if result in results: 9714008Sgabeblack@google.com return result 9812532Sandreas.sandberg@arm.com 9912532Sandreas.sandberg@arm.comclass MercurialUI(UserInterface): 10012532Sandreas.sandberg@arm.com def __init__(self, ui, *args, **kwargs): 10112532Sandreas.sandberg@arm.com super(MercurialUI, self).__init__(*args, **kwargs) 10212532Sandreas.sandberg@arm.com self.ui = ui 10312532Sandreas.sandberg@arm.com 10412532Sandreas.sandberg@arm.com def do_prompt(self, prompt, results, default): 10512532Sandreas.sandberg@arm.com return self.ui.prompt(prompt, default=default) 10612532Sandreas.sandberg@arm.com 10712532Sandreas.sandberg@arm.com def write(self, string): 10812532Sandreas.sandberg@arm.com self.ui.write(string) 10912532Sandreas.sandberg@arm.com 11012532Sandreas.sandberg@arm.comclass StdioUI(UserInterface): 11112532Sandreas.sandberg@arm.com def do_prompt(self, prompt, results, default): 11212532Sandreas.sandberg@arm.com return raw_input(prompt) or default 11312532Sandreas.sandberg@arm.com 11412532Sandreas.sandberg@arm.com def write(self, string): 11512532Sandreas.sandberg@arm.com sys.stdout.write(string) 1168706Sandreas.hansson@arm.com 11714008Sgabeblack@google.comclass Verifier(object): 11814008Sgabeblack@google.com def __init__(self, ui, repo=None): 11914008Sgabeblack@google.com self.ui = ui 12014008Sgabeblack@google.com self.repo = repo 12114008Sgabeblack@google.com if repo is None: 12214008Sgabeblack@google.com self.wctx = None 12314008Sgabeblack@google.com 12414008Sgabeblack@google.com def __getattr__(self, attr): 12514008Sgabeblack@google.com if attr in ('prompt', 'write'): 12614008Sgabeblack@google.com return getattr(self.ui, attr) 12714008Sgabeblack@google.com 12814008Sgabeblack@google.com if attr == 'wctx': 12914008Sgabeblack@google.com try: 13014008Sgabeblack@google.com wctx = repo.workingctx() 13114008Sgabeblack@google.com except: 13214008Sgabeblack@google.com from mercurial import context 13314008Sgabeblack@google.com wctx = context.workingctx(repo) 13414008Sgabeblack@google.com self.wctx = wctx 13514008Sgabeblack@google.com return wctx 13614008Sgabeblack@google.com 13714008Sgabeblack@google.com raise AttributeError 13814008Sgabeblack@google.com 13914008Sgabeblack@google.com def open(self, filename, mode): 14014008Sgabeblack@google.com if self.repo: 14114008Sgabeblack@google.com filename = self.repo.wjoin(filename) 14214008Sgabeblack@google.com 14314008Sgabeblack@google.com try: 14414008Sgabeblack@google.com f = file(filename, mode) 14514008Sgabeblack@google.com except OSError, msg: 14614008Sgabeblack@google.com print 'could not open file %s: %s' % (filename, msg) 14714008Sgabeblack@google.com return None 14814008Sgabeblack@google.com 14914008Sgabeblack@google.com return f 15014008Sgabeblack@google.com 15114008Sgabeblack@google.com def skip(self, filename): 15214008Sgabeblack@google.com return lang_type(filename) not in self.languages 15314008Sgabeblack@google.com 15414008Sgabeblack@google.com def check(self, filename, regions=all_regions): 15514008Sgabeblack@google.com f = self.open(filename, 'r') 15614008Sgabeblack@google.com 15714008Sgabeblack@google.com errors = 0 15814008Sgabeblack@google.com for num,line in enumerate(f): 15914008Sgabeblack@google.com if num not in regions: 16014008Sgabeblack@google.com continue 16114008Sgabeblack@google.com if not self.check_line(line): 16214008Sgabeblack@google.com self.write("invalid %s in %s:%d\n" % \ 16314008Sgabeblack@google.com (self.test_name, filename, num + 1)) 16414008Sgabeblack@google.com if self.ui.verbose: 16514008Sgabeblack@google.com self.write(">>%s<<\n" % line[-1]) 16614008Sgabeblack@google.com errors += 1 16714008Sgabeblack@google.com return errors 16814008Sgabeblack@google.com 16914008Sgabeblack@google.com def fix(self, filename, regions=all_regions): 17014008Sgabeblack@google.com f = self.open(filename, 'r+') 17114008Sgabeblack@google.com 17214008Sgabeblack@google.com lines = list(f) 17314008Sgabeblack@google.com 17414008Sgabeblack@google.com f.seek(0) 17514008Sgabeblack@google.com f.truncate() 17614008Sgabeblack@google.com 17714008Sgabeblack@google.com for i,line in enumerate(lines): 17814008Sgabeblack@google.com if i in regions: 17914008Sgabeblack@google.com line = self.fix_line(line) 18014008Sgabeblack@google.com 18114008Sgabeblack@google.com f.write(line) 18214008Sgabeblack@google.com f.close() 18314008Sgabeblack@google.com 18414008Sgabeblack@google.com def apply(self, filename, prompt, regions=all_regions): 18514008Sgabeblack@google.com if not self.skip(filename): 18614008Sgabeblack@google.com errors = self.check(filename, regions) 18714008Sgabeblack@google.com if errors: 1888706Sandreas.hansson@arm.com if prompt(filename, self.fix, regions): 1898706Sandreas.hansson@arm.com return True 1908706Sandreas.hansson@arm.com return False 1918706Sandreas.hansson@arm.com 1928861Sandreas.hansson@arm.com 1938706Sandreas.hansson@arm.comclass Whitespace(Verifier): 1948706Sandreas.hansson@arm.com languages = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons')) 1958706Sandreas.hansson@arm.com test_name = 'whitespace' 1968706Sandreas.hansson@arm.com def check_line(self, line): 1978706Sandreas.hansson@arm.com match = lead.search(line) 1988861Sandreas.hansson@arm.com if match and match.group(1).find('\t') != -1: 1998706Sandreas.hansson@arm.com return False 20012522Sandreas.sandberg@arm.com 20112522Sandreas.sandberg@arm.com match = trail.search(line) 20213893Sgabeblack@google.com if match: 20312522Sandreas.sandberg@arm.com return False 20412522Sandreas.sandberg@arm.com 20513893Sgabeblack@google.com return True 20612522Sandreas.sandberg@arm.com 20712522Sandreas.sandberg@arm.com def fix_line(self, line): 20812522Sandreas.sandberg@arm.com if lead.search(line): 20913893Sgabeblack@google.com newline = '' 21012522Sandreas.sandberg@arm.com for i,c in enumerate(line): 21112522Sandreas.sandberg@arm.com if c == ' ': 21213893Sgabeblack@google.com newline += ' ' 21314008Sgabeblack@google.com elif c == '\t': 21414008Sgabeblack@google.com newline += ' ' * (tabsize - len(newline) % tabsize) 21514008Sgabeblack@google.com else: 21614008Sgabeblack@google.com newline += line[i:] 21714008Sgabeblack@google.com break 21814008Sgabeblack@google.com 21914008Sgabeblack@google.com line = newline 22014008Sgabeblack@google.com 22114008Sgabeblack@google.com return line.rstrip() + '\n' 22214008Sgabeblack@google.com 22314008Sgabeblack@google.comclass SortedIncludes(Verifier): 22414008Sgabeblack@google.com languages = sort_includes.default_languages 22514008Sgabeblack@google.com def __init__(self, *args, **kwargs): 22614008Sgabeblack@google.com super(SortedIncludes, self).__init__(*args, **kwargs) 22714008Sgabeblack@google.com self.sort_includes = sort_includes.SortIncludes() 22814008Sgabeblack@google.com 22914008Sgabeblack@google.com def check(self, filename, regions=all_regions): 23014008Sgabeblack@google.com f = self.open(filename, 'r') 23114008Sgabeblack@google.com 23214008Sgabeblack@google.com lines = [ l.rstrip('\n') for l in f.xreadlines() ] 23314008Sgabeblack@google.com old = ''.join(line + '\n' for line in lines) 23414008Sgabeblack@google.com f.close() 23514008Sgabeblack@google.com 23614008Sgabeblack@google.com if len(lines) == 0: 23714008Sgabeblack@google.com return 0 23814008Sgabeblack@google.com 23914008Sgabeblack@google.com language = lang_type(filename, lines[0]) 24014008Sgabeblack@google.com sort_lines = list(self.sort_includes(lines, filename, language)) 24114008Sgabeblack@google.com new = ''.join(line + '\n' for line in sort_lines) 24214008Sgabeblack@google.com 24314008Sgabeblack@google.com mod = modified_regions(old, new) 24414008Sgabeblack@google.com modified = mod & regions 2458706Sandreas.hansson@arm.com 2468706Sandreas.hansson@arm.com if modified: 2478706Sandreas.hansson@arm.com self.write("invalid sorting of includes in %s\n" % (filename)) 2488706Sandreas.hansson@arm.com if self.ui.verbose: 2498706Sandreas.hansson@arm.com for start, end in modified.regions: 2508861Sandreas.hansson@arm.com self.write("bad region [%d, %d)\n" % (start, end)) 2518706Sandreas.hansson@arm.com return 1 2528706Sandreas.hansson@arm.com 2538706Sandreas.hansson@arm.com return 0 2548706Sandreas.hansson@arm.com 2558706Sandreas.hansson@arm.com def fix(self, filename, regions=all_regions): 2568706Sandreas.hansson@arm.com f = self.open(filename, 'r+') 2578706Sandreas.hansson@arm.com 2588706Sandreas.hansson@arm.com old = f.readlines() 2598861Sandreas.hansson@arm.com lines = [ l.rstrip('\n') for l in old ] 2608706Sandreas.hansson@arm.com language = lang_type(filename, lines[0]) 2618706Sandreas.hansson@arm.com sort_lines = list(self.sort_includes(lines, filename, language)) 2628706Sandreas.hansson@arm.com new = ''.join(line + '\n' for line in sort_lines) 2638706Sandreas.hansson@arm.com 26412522Sandreas.sandberg@arm.com f.seek(0) 26512522Sandreas.sandberg@arm.com f.truncate() 26613893Sgabeblack@google.com 26712522Sandreas.sandberg@arm.com for i,line in enumerate(sort_lines): 26812522Sandreas.sandberg@arm.com f.write(line) 26912522Sandreas.sandberg@arm.com f.write('\n') 27012522Sandreas.sandberg@arm.com f.close() 27112522Sandreas.sandberg@arm.com 27212522Sandreas.sandberg@arm.comdef linelen(line): 27312522Sandreas.sandberg@arm.com tabs = line.count('\t') 27412522Sandreas.sandberg@arm.com if not tabs: 27513893Sgabeblack@google.com return len(line) 27612522Sandreas.sandberg@arm.com 27712522Sandreas.sandberg@arm.com count = 0 27812522Sandreas.sandberg@arm.com for c in line: 27912522Sandreas.sandberg@arm.com if c == '\t': 28012522Sandreas.sandberg@arm.com count += tabsize - count % tabsize 2818706Sandreas.hansson@arm.com else: 282 count += 1 283 284 return count 285 286class ValidationStats(object): 287 def __init__(self): 288 self.toolong = 0 289 self.toolong80 = 0 290 self.leadtabs = 0 291 self.trailwhite = 0 292 self.badcontrol = 0 293 self.cret = 0 294 295 def dump(self): 296 print '''\ 297%d violations of lines over 79 chars. %d of which are 80 chars exactly. 298%d cases of whitespace at the end of a line. 299%d cases of tabs to indent. 300%d bad parens after if/while/for. 301%d carriage returns found. 302''' % (self.toolong, self.toolong80, self.trailwhite, self.leadtabs, 303 self.badcontrol, self.cret) 304 305 def __nonzero__(self): 306 return self.toolong or self.toolong80 or self.leadtabs or \ 307 self.trailwhite or self.badcontrol or self.cret 308 309def validate(filename, stats, verbose, exit_code): 310 if lang_type(filename) not in format_types: 311 return 312 313 def msg(lineno, line, message): 314 print '%s:%d>' % (filename, lineno + 1), message 315 if verbose > 2: 316 print line 317 318 def bad(): 319 if exit_code is not None: 320 sys.exit(exit_code) 321 322 try: 323 f = file(filename, 'r') 324 except OSError: 325 if verbose > 0: 326 print 'could not open file %s' % filename 327 bad() 328 return 329 330 for i,line in enumerate(f): 331 line = line.rstrip('\n') 332 333 # no carriage returns 334 if line.find('\r') != -1: 335 self.cret += 1 336 if verbose > 1: 337 msg(i, line, 'carriage return found') 338 bad() 339 340 # lines max out at 79 chars 341 llen = linelen(line) 342 if llen > 79: 343 stats.toolong += 1 344 if llen == 80: 345 stats.toolong80 += 1 346 if verbose > 1: 347 msg(i, line, 'line too long (%d chars)' % llen) 348 bad() 349 350 # no tabs used to indent 351 match = lead.search(line) 352 if match and match.group(1).find('\t') != -1: 353 stats.leadtabs += 1 354 if verbose > 1: 355 msg(i, line, 'using tabs to indent') 356 bad() 357 358 # no trailing whitespace 359 if trail.search(line): 360 stats.trailwhite +=1 361 if verbose > 1: 362 msg(i, line, 'trailing whitespace') 363 bad() 364 365 # for c++, exactly one space betwen if/while/for and ( 366 if cpp: 367 match = any_control.search(line) 368 if match and not good_control.search(line): 369 stats.badcontrol += 1 370 if verbose > 1: 371 msg(i, line, 'improper spacing after %s' % match.group(1)) 372 bad() 373 374def do_check_style(hgui, repo, *files, **args): 375 """check files for proper m5 style guidelines""" 376 from mercurial import mdiff, util 377 378 auto = args.get('auto', False) 379 if auto: 380 auto = 'f' 381 ui = MercurialUI(hgui, hgui.verbose, auto) 382 383 if files: 384 files = frozenset(files) 385 386 def skip(name): 387 return files and name in files 388 389 def prompt(name, func, regions=all_regions): 390 result = ui.prompt("(a)bort, (i)gnore, or (f)ix?", 'aif', 'a') 391 if result == 'a': 392 return True 393 elif result == 'f': 394 func(repo.wjoin(name), regions) 395 396 return False 397 398 modified, added, removed, deleted, unknown, ignore, clean = repo.status() 399 400 whitespace = Whitespace(ui) 401 sorted_includes = SortedIncludes(ui) 402 for fname in added: 403 if skip(fname): 404 continue 405 406 fpath = joinpath(repo.root, fname) 407 408 if whitespace.apply(fpath, prompt): 409 return True 410 411 if sorted_includes.apply(fpath, prompt): 412 return True 413 414 try: 415 wctx = repo.workingctx() 416 except: 417 from mercurial import context 418 wctx = context.workingctx(repo) 419 420 for fname in modified: 421 if skip(fname): 422 continue 423 424 fpath = joinpath(repo.root, fname) 425 regions = modregions(wctx, fname) 426 427 if whitespace.apply(fpath, prompt, regions): 428 return True 429 430 if sorted_includes.apply(fpath, prompt, regions): 431 return True 432 433 return False 434 435def do_check_format(hgui, repo, **args): 436 ui = MercurialUI(hgui, hgui.verbose, auto) 437 438 modified, added, removed, deleted, unknown, ignore, clean = repo.status() 439 440 verbose = 0 441 stats = ValidationStats() 442 for f in modified + added: 443 validate(joinpath(repo.root, f), stats, verbose, None) 444 445 if stats: 446 stats.dump() 447 result = ui.prompt("invalid formatting\n(i)gnore or (a)bort?", 448 'ai', 'a') 449 if result == 'a': 450 return True 451 452 return False 453 454def check_hook(hooktype): 455 if hooktype not in ('pretxncommit', 'pre-qrefresh'): 456 raise AttributeError, \ 457 "This hook is not meant for %s" % hooktype 458 459def check_style(ui, repo, hooktype, **kwargs): 460 check_hook(hooktype) 461 args = {} 462 463 try: 464 return do_check_style(ui, repo, **args) 465 except Exception, e: 466 import traceback 467 traceback.print_exc() 468 return True 469 470def check_format(ui, repo, hooktype, **kwargs): 471 check_hook(hooktype) 472 args = {} 473 474 try: 475 return do_check_format(ui, repo, **args) 476 except Exception, e: 477 import traceback 478 traceback.print_exc() 479 return True 480 481try: 482 from mercurial.i18n import _ 483except ImportError: 484 def _(arg): 485 return arg 486 487cmdtable = { 488 '^m5style' : 489 ( do_check_style, 490 [ ('a', 'auto', False, _("automatically fix whitespace")) ], 491 _('hg m5style [-a] [FILE]...')), 492 '^m5format' : 493 ( do_check_format, 494 [ ], 495 _('hg m5format [FILE]...')), 496} 497 498if __name__ == '__main__': 499 import getopt 500 501 progname = sys.argv[0] 502 if len(sys.argv) < 2: 503 sys.exit('usage: %s <command> [<command args>]' % progname) 504 505 fixwhite_usage = '%s fixwhite [-t <tabsize> ] <path> [...] \n' % progname 506 chkformat_usage = '%s chkformat <path> [...] \n' % progname 507 chkwhite_usage = '%s chkwhite <path> [...] \n' % progname 508 509 command = sys.argv[1] 510 if command == 'fixwhite': 511 flags = 't:' 512 usage = fixwhite_usage 513 elif command == 'chkwhite': 514 flags = 'nv' 515 usage = chkwhite_usage 516 elif command == 'chkformat': 517 flags = 'nv' 518 usage = chkformat_usage 519 else: 520 sys.exit(fixwhite_usage + chkwhite_usage + chkformat_usage) 521 522 opts, args = getopt.getopt(sys.argv[2:], flags) 523 524 code = 1 525 verbose = 1 526 for opt,arg in opts: 527 if opt == '-n': 528 code = None 529 if opt == '-t': 530 tabsize = int(arg) 531 if opt == '-v': 532 verbose += 1 533 534 if command == 'fixwhite': 535 for filename in args: 536 fixwhite(filename, tabsize) 537 elif command == 'chkwhite': 538 for filename in args: 539 for line,num in checkwhite(filename): 540 print 'invalid whitespace: %s:%d' % (filename, num) 541 if verbose: 542 print '>>%s<<' % line[:-1] 543 elif command == 'chkformat': 544 stats = ValidationStats() 545 for filename in args: 546 validate(filename, stats=stats, verbose=verbose, exit_code=code) 547 548 if verbose > 0: 549 stats.dump() 550 else: 551 sys.exit("command '%s' not found" % command) 552