style: make style hook work with pre-qrefresh and update to use new code

clean up the code a little bit while we're at it.

I recommend that everyone adds the pre-qrefresh hook below since it
will make qref run the style hook and not just commit/qpush

[extensions]
style = <m5 path>/util/style.py

[hooks]
pretxncommit.style = python:style.check_whitespace
pre-qrefresh.style = python:style.check_whitespace
This commit is contained in:
Nathan Binkert 2010-12-30 12:53:56 -05:00
parent 04f5bb34ce
commit fe6574ecc0
3 changed files with 122 additions and 61 deletions

View file

@ -165,6 +165,7 @@ style = %s/util/style.py
[hooks] [hooks]
pretxncommit.style = python:style.check_whitespace pretxncommit.style = python:style.check_whitespace
pre-qrefresh.style = python:style.check_whitespace
""" % (main.root) """ % (main.root)
mercurial_bin_not_found = """ mercurial_bin_not_found = """

89
util/file_types.py Normal file
View file

@ -0,0 +1,89 @@
import os
# lanuage type for each file extension
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",
'.pl' : "perl",
'.pm' : "perl",
'.s' : "asm",
'.S' : "asm",
'.l' : "lex",
'.ll' : "lex",
'.y' : "yacc",
'.yy' : "yacc",
'.isa' : "isa",
'.sh' : "shell",
'.slicc' : "slicc",
'.sm' : "slicc",
'.awk' : "awk",
'.el' : "lisp",
'.txt' : "text",
'.tex' : "tex",
}
# languages based on file prefix
lang_prefixes = (
('SCons', 'scons'),
('Make', 'make'),
('make', 'make'),
('Doxyfile', 'doxygen'),
)
# languages based on #! line of first file
hash_bang = (
('python', 'python'),
('perl', 'perl'),
('sh', 'shell'),
)
# the list of all languages that we detect
all_languages = frozenset(lang_types.itervalues())
all_languages |= frozenset(lang for start,lang in lang_prefixes)
all_languages |= frozenset(lang for start,lang in hash_bang)
def lang_type(filename, firstline=None, openok=True):
'''identify the language of a given filename and potentially the
firstline of the file. If the firstline of the file is not
provided and openok is True, open the file and read the first line
if necessary'''
basename = os.path.basename(filename)
name,extension = os.path.splitext(basename)
# first try to detect language based on file extension
try:
return lang_types[extension]
except KeyError:
pass
# now try to detect language based on file prefix
for start,lang in lang_prefixes:
if basename.startswith(start):
return start
# if a first line was not provided but the file is ok to open,
# grab the first line of the file.
if firstline is None and openok:
handle = file(filename, 'r')
firstline = handle.readline()
handle.close()
# try to detect language based on #! in first line
if firstline and firstline.startswith('#!'):
for string,lang in hash_bang:
if firstline.find(string) > 0:
return lang
# sorry, we couldn't detect the language
return None

View file

@ -32,47 +32,17 @@ import re
import os import os
import sys import sys
sys.path.insert(0, os.path.dirname(__file__))
from file_types import lang_type
lead = re.compile(r'^([ \t]+)') lead = re.compile(r'^([ \t]+)')
trail = re.compile(r'([ \t]+)$') trail = re.compile(r'([ \t]+)$')
any_control = re.compile(r'\b(if|while|for)[ \t]*[(]') any_control = re.compile(r'\b(if|while|for)[ \t]*[(]')
good_control = re.compile(r'\b(if|while|for) [(]') good_control = re.compile(r'\b(if|while|for) [(]')
lang_types = { 'c' : "C", whitespace_types = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons'))
'h' : "C", format_types = set(('C', '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" }
def file_type(filename):
extension = filename.split('.')
extension = len(extension) > 1 and extension[-1]
return lang_types.get(extension, None)
whitespace_types = ('C', 'C++', 'swig', 'python', 'asm', 'isa')
def whitespace_file(filename):
if file_type(filename) in whitespace_types:
return True
if filename.startswith("SCons"):
return True
return False
format_types = ( 'C', 'C++' )
def format_file(filename):
if file_type(filename) in format_types:
return True
return True
def checkwhite_line(line): def checkwhite_line(line):
match = lead.search(line) match = lead.search(line)
@ -86,7 +56,7 @@ def checkwhite_line(line):
return True return True
def checkwhite(filename): def checkwhite(filename):
if not whitespace_file(filename): if lang_type(filename) not in whitespace_types:
return return
try: try:
@ -116,7 +86,7 @@ def fixwhite_line(line, tabsize):
return line.rstrip() + '\n' return line.rstrip() + '\n'
def fixwhite(filename, tabsize, fixonly=None): def fixwhite(filename, tabsize, fixonly=None):
if not whitespace_file(filename): if lang_type(filename) not in whitespace_types:
return return
try: try:
@ -174,7 +144,7 @@ class ValidationStats(object):
self.trailwhite or self.badcontrol or self.cret self.trailwhite or self.badcontrol or self.cret
def validate(filename, stats, verbose, exit_code): def validate(filename, stats, verbose, exit_code):
if not format_file(filename): if lang_type(filename) not in format_types:
return return
def msg(lineno, line, message): def msg(lineno, line, message):
@ -186,13 +156,6 @@ def validate(filename, stats, verbose, exit_code):
if exit_code is not None: if exit_code is not None:
sys.exit(exit_code) 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: try:
f = file(filename, 'r') f = file(filename, 'r')
except OSError: except OSError:
@ -314,7 +277,7 @@ def do_check_whitespace(ui, repo, *files, **args):
if skip(fname): if skip(fname):
continue continue
if not whitespace_file(fname): if lang_type(fname) not in whitespace_types:
continue continue
fctx = wctx.filectx(fname) fctx = wctx.filectx(fname)
@ -348,19 +311,7 @@ def do_check_whitespace(ui, repo, *files, **args):
if prompt(fname, fixonly): if prompt(fname, fixonly):
return True return True
def check_whitespace(ui, repo, hooktype, node, parent1, parent2, **kwargs): def do_check_format(ui, repo, **args):
if hooktype != 'pretxncommit':
raise AttributeError, \
"This hook is only meant for pretxncommit, not %s" % hooktype
args = { 'tabsize' : 8 }
return do_check_whitespace(ui, repo, **args)
def check_format(ui, repo, hooktype, node, parent1, parent2, **kwargs):
if hooktype != 'pretxncommit':
raise AttributeError, \
"This hook is only meant for pretxncommit, not %s" % hooktype
modified, added, removed, deleted, unknown, ignore, clean = repo.status() modified, added, removed, deleted, unknown, ignore, clean = repo.status()
verbose = 0 verbose = 0
@ -381,6 +332,21 @@ def check_format(ui, repo, hooktype, node, parent1, parent2, **kwargs):
return False 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_whitespace(ui, repo, hooktype, **kwargs):
check_hook(hooktype)
args = { 'tabsize' : 8 }
return do_check_whitespace(ui, repo, **args)
def check_format(ui, repo, hooktype, **kwargs):
check_hook(hooktype)
args = {}
return do_check_format(ui, repo, **args)
try: try:
from mercurial.i18n import _ from mercurial.i18n import _
except ImportError: except ImportError:
@ -392,8 +358,13 @@ cmdtable = {
( do_check_whitespace, ( do_check_whitespace,
[ ('a', 'auto', False, _("automatically fix whitespace")), [ ('a', 'auto', False, _("automatically fix whitespace")),
('t', 'tabsize', 8, _("Number of spaces TAB indents")) ], ('t', 'tabsize', 8, _("Number of spaces TAB indents")) ],
_('hg m5check [-t <tabsize>] [FILE]...')), _('hg m5style [-a] [-t <tabsize>] [FILE]...')),
'^m5format' :
( do_check_format,
[ ],
_('hg m5format [FILE]...')),
} }
if __name__ == '__main__': if __name__ == '__main__':
import getopt import getopt