ARM: Squash state on FPSCR stride or len write.
[gem5.git] / util / style.py
index 2512d69205f79feee34c7814a1df14f7eab4293f..1307f87286927b74d2c3953acb8ba1112ea0040c 100644 (file)
@@ -1,5 +1,6 @@
 #! /usr/bin/env python
-# Copyright (c) 2007 The Regents of The University of Michigan
+# Copyright (c) 2006 The Regents of The University of Michigan
+# Copyright (c) 2007 The Hewlett-Packard Development Company
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -31,33 +32,18 @@ import re
 import os
 import sys
 
+sys.path.insert(0, os.path.dirname(__file__))
+
+from file_types import lang_type
+
+tabsize = 8
 lead = re.compile(r'^([ \t]+)')
 trail = re.compile(r'([ \t]+)$')
 any_control = re.compile(r'\b(if|while|for)[ \t]*[(]')
 good_control = re.compile(r'\b(if|while|for) [(]')
 
-lang_types = { 'c'   : "C",
-               'h'   : "C",
-               'cc'  : "C++",
-               'hh'  : "C++",
-               'cxx' : "C++",
-               'hxx' : "C++",
-               'cpp' : "C++",
-               'hpp' : "C++",
-               'C'   : "C++",
-               'H'   : "C++",
-               'i'   : "swig",
-               'py'  : "python",
-               's'   : "asm",
-               'S'   : "asm",
-               'isa' : "isa" }
-whitespace_types = ('C', 'C++', 'swig', 'python', 'asm', 'isa')
-format_types = ( 'C', 'C++' )
-
-def file_type(filename):
-    extension = filename.split('.')
-    extension = len(extension) > 1 and extension[-1]
-    return lang_types.get(extension, None)
+whitespace_types = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons'))
+format_types = set(('C', 'C++'))
 
 def checkwhite_line(line):
     match = lead.search(line)
@@ -71,7 +57,7 @@ def checkwhite_line(line):
     return True
 
 def checkwhite(filename):
-    if file_type(filename) not in whitespace_types:
+    if lang_type(filename) not in whitespace_types:
         return
 
     try:
@@ -84,7 +70,7 @@ def checkwhite(filename):
         if not checkwhite_line(line):
             yield line,num + 1
 
-def fixwhite_line(line, tabsize):
+def fixwhite_line(line):
     if lead.search(line):
         newline = ''
         for i,c in enumerate(line):
@@ -100,8 +86,8 @@ def fixwhite_line(line, tabsize):
 
     return line.rstrip() + '\n'
 
-def fixwhite(filename, tabsize, fixonly=None):
-    if file_type(filename) not in whitespace_types:
+def fixwhite(filename, fixonly=None):
+    if lang_type(filename) not in whitespace_types:
         return
 
     try:
@@ -117,7 +103,7 @@ def fixwhite(filename, tabsize, fixonly=None):
 
     for i,line in enumerate(lines):
         if fixonly is None or i in fixonly:
-            line = fixwhite_line(line, tabsize)
+            line = fixwhite_line(line)
 
         print >>f, line,
 
@@ -159,7 +145,7 @@ class ValidationStats(object):
                self.trailwhite or self.badcontrol or self.cret
 
 def validate(filename, stats, verbose, exit_code):
-    if file_type(filename) not in format_types:
+    if lang_type(filename) not in format_types:
         return
 
     def msg(lineno, line, message):
@@ -171,13 +157,6 @@ def validate(filename, stats, verbose, exit_code):
         if exit_code is not None:
             sys.exit(exit_code)
 
-    cpp = filename.endswith('.cc') or filename.endswith('.hh')
-    py = filename.endswith('.py')
-
-    if py + cpp != 1:
-        raise AttributeError, \
-              "I don't know how to deal with the file %s" % filename
-
     try:
         f = file(filename, 'r')
     except OSError:
@@ -230,7 +209,7 @@ def validate(filename, stats, verbose, exit_code):
                     msg(i, line, 'improper spacing after %s' % match.group(1))
                 bad()
 
-def modified_lines(old_data, new_data):
+def modified_lines(old_data, new_data, max_lines):
     from itertools import count
     from mercurial import bdiff, mdiff
 
@@ -242,58 +221,82 @@ def modified_lines(old_data, new_data):
                 modified.add(i)
             elif i + 1 >= fend:
                 break
+            elif i > max_lines:
+                break
     return modified
 
-def check_whitespace(ui, repo, hooktype, node, parent1, parent2):
-    from mercurial import mdiff
+def do_check_style(ui, repo, *files, **args):
+    """check files for proper m5 style guidelines"""
+    from mercurial import mdiff, util
 
-    if hooktype != 'pretxncommit':
-        raise AttributeError, \
-              "This hook is only meant for pretxncommit, not %s" % hooktype
+    if files:
+        files = frozenset(files)
+
+    def skip(name):
+        return files and name in files
+
+    def prompt(name, func, fixonly=None):
+        if args.get('auto', False):
+            result = 'f'
+        else:
+            while True:
+                result = ui.prompt("(a)bort, (i)gnore, or (f)ix?", default='a')
+                if result in 'aif':
+                    break
 
-    tabsize = 8
-    verbose = ui.configbool('style', 'verbose', False)
-    def prompt(name, fixonly=None):
-        result = ui.prompt("(a)bort, (i)gnore, or (f)ix?", "^[aif]$", "a")
         if result == 'a':
             return True
-        elif result == 'i':
-            pass
         elif result == 'f':
-            fixwhite(repo.wjoin(name), tabsize, fixonly)
-        else:
-            raise RepoError, "Invalid response: '%s'" % result
+            func(repo.wjoin(name), fixonly)
 
         return False
 
     modified, added, removed, deleted, unknown, ignore, clean = repo.status()
 
     for fname in added:
+        if skip(fname):
+            continue
+
         ok = True
-        for line,num in checkwhite(fname):
+        for line,num in checkwhite(repo.wjoin(fname)):
             ui.write("invalid whitespace in %s:%d\n" % (fname, num))
-            if verbose:
+            if ui.verbose:
                 ui.write(">>%s<<\n" % line[-1])
             ok = False
 
         if not ok:
-            if prompt(fname):
+            if prompt(fname, fixwhite):
                 return True
 
-    wctx = repo.workingctx()
+    try:
+        wctx = repo.workingctx()
+    except:
+        from mercurial import context
+        wctx = context.workingctx(repo)
+
     for fname in modified:
+        if skip(fname):
+            continue
+
+        if lang_type(fname) not in whitespace_types:
+            continue
+
         fctx = wctx.filectx(fname)
         pctx = fctx.parents()
-        assert len(pctx) in (1, 2)
 
         file_data = fctx.data()
-        mod_lines = modified_lines(pctx[0].data(), file_data)
-        if len(pctx) == 2:
-            m2 = modified_lines(pctx[1].data(), file_data)
-            mod_lines = mod_lines & m2 # only the lines that are new in both
+        lines = mdiff.splitnewlines(file_data)
+        if len(pctx) in (1, 2):
+            mod_lines = modified_lines(pctx[0].data(), file_data, len(lines))
+            if len(pctx) == 2:
+                m2 = modified_lines(pctx[1].data(), file_data, len(lines))
+                # only the lines that are new in both
+                mod_lines = mod_lines & m2
+        else:
+            mod_lines = xrange(0, len(lines))
 
         fixonly = set()
-        for i,line in enumerate(mdiff.splitnewlines(file_data)):
+        for i,line in enumerate(lines):
             if i not in mod_lines:
                 continue
 
@@ -301,19 +304,15 @@ def check_whitespace(ui, repo, hooktype, node, parent1, parent2):
                 continue
 
             ui.write("invalid whitespace: %s:%d\n" % (fname, i+1))
-            if verbose:
+            if ui.verbose:
                 ui.write(">>%s<<\n" % line[:-1])
             fixonly.add(i)
 
         if fixonly:
-            if prompt(fname, fixonly):
+            if prompt(fname, fixwhite, fixonly):
                 return True
 
-def check_format(ui, repo, hooktype, node, parent1, parent2):
-    if hooktype != 'pretxncommit':
-        raise AttributeError, \
-              "This hook is only meant for pretxncommit, not %s" % hooktype
-
+def do_check_format(ui, repo, **args):
     modified, added, removed, deleted, unknown, ignore, clean = repo.status()
 
     verbose = 0
@@ -330,10 +329,54 @@ def check_format(ui, repo, hooktype, node, parent1, parent2):
         elif result.startswith('a'):
             return True
         else:
-            raise RepoError, "Invalid response: '%s'" % result
+            raise util.Abort(_("Invalid response: '%s'") % result)
 
     return False
 
+def check_hook(hooktype):
+    if hooktype not in ('pretxncommit', 'pre-qrefresh'):
+        raise AttributeError, \
+              "This hook is not meant for %s" % hooktype
+
+def check_style(ui, repo, hooktype, **kwargs):
+    check_hook(hooktype)
+    args = {}
+
+    try:
+        return do_check_style(ui, repo, **args)
+    except Exception, e:
+        import traceback
+        traceback.print_exc()
+        return True
+
+def check_format(ui, repo, hooktype, **kwargs):
+    check_hook(hooktype)
+    args = {}
+
+    try:
+        return do_check_format(ui, repo, **args)
+    except Exception, e:
+        import traceback
+        traceback.print_exc()
+        return True
+
+try:
+    from mercurial.i18n import _
+except ImportError:
+    def _(arg):
+        return arg
+
+cmdtable = {
+    '^m5style' :
+    ( do_check_style,
+      [ ('a', 'auto', False, _("automatically fix whitespace")) ],
+      _('hg m5style [-a] [FILE]...')),
+    '^m5format' :
+    ( do_check_format,
+      [ ],
+      _('hg m5format [FILE]...')),
+}
+
 if __name__ == '__main__':
     import getopt
 
@@ -362,7 +405,6 @@ if __name__ == '__main__':
 
     code = 1
     verbose = 1
-    tabsize = 8
     for opt,arg in opts:
         if opt == '-n':
             code = None
@@ -376,12 +418,13 @@ if __name__ == '__main__':
             fixwhite(filename, tabsize)
     elif command == 'chkwhite':
         for filename in args:
-            line = checkwhite(filename)
-            if line:
-                print 'invalid whitespace at %s:%d' % (filename, line)
+            for line,num in checkwhite(filename):
+                print 'invalid whitespace: %s:%d' % (filename, num)
+                if verbose:
+                    print '>>%s<<' % line[:-1]
     elif command == 'chkformat':
         stats = ValidationStats()
-        for filename in files:
+        for filename in args:
             validate(filename, stats=stats, verbose=verbose, exit_code=code)
 
         if verbose > 0: