summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct1
-rw-r--r--util/file_types.py89
-rw-r--r--util/style.py93
3 files changed, 122 insertions, 61 deletions
diff --git a/SConstruct b/SConstruct
index 817e7b921..07ddfd540 100644
--- a/SConstruct
+++ b/SConstruct
@@ -165,6 +165,7 @@ style = %s/util/style.py
[hooks]
pretxncommit.style = python:style.check_whitespace
+pre-qrefresh.style = python:style.check_whitespace
""" % (main.root)
mercurial_bin_not_found = """
diff --git a/util/file_types.py b/util/file_types.py
new file mode 100644
index 000000000..3315a747f
--- /dev/null
+++ b/util/file_types.py
@@ -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
diff --git a/util/style.py b/util/style.py
index 606d5984b..553a9b996 100644
--- a/util/style.py
+++ b/util/style.py
@@ -32,47 +32,17 @@ import re
import os
import sys
+sys.path.insert(0, os.path.dirname(__file__))
+
+from file_types import lang_type
+
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" }
-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
+whitespace_types = set(('C', 'C++', 'swig', 'python', 'asm', 'isa', 'scons'))
+format_types = set(('C', 'C++'))
def checkwhite_line(line):
match = lead.search(line)
@@ -86,7 +56,7 @@ def checkwhite_line(line):
return True
def checkwhite(filename):
- if not whitespace_file(filename):
+ if lang_type(filename) not in whitespace_types:
return
try:
@@ -116,7 +86,7 @@ def fixwhite_line(line, tabsize):
return line.rstrip() + '\n'
def fixwhite(filename, tabsize, fixonly=None):
- if not whitespace_file(filename):
+ if lang_type(filename) not in whitespace_types:
return
try:
@@ -174,7 +144,7 @@ class ValidationStats(object):
self.trailwhite or self.badcontrol or self.cret
def validate(filename, stats, verbose, exit_code):
- if not format_file(filename):
+ if lang_type(filename) not in format_types:
return
def msg(lineno, line, message):
@@ -186,13 +156,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:
@@ -314,7 +277,7 @@ def do_check_whitespace(ui, repo, *files, **args):
if skip(fname):
continue
- if not whitespace_file(fname):
+ if lang_type(fname) not in whitespace_types:
continue
fctx = wctx.filectx(fname)
@@ -348,19 +311,7 @@ def do_check_whitespace(ui, repo, *files, **args):
if prompt(fname, fixonly):
return True
-def check_whitespace(ui, repo, hooktype, node, parent1, parent2, **kwargs):
- 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
-
+def do_check_format(ui, repo, **args):
modified, added, removed, deleted, unknown, ignore, clean = repo.status()
verbose = 0
@@ -381,6 +332,21 @@ def check_format(ui, repo, hooktype, node, parent1, parent2, **kwargs):
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:
from mercurial.i18n import _
except ImportError:
@@ -392,8 +358,13 @@ cmdtable = {
( do_check_whitespace,
[ ('a', 'auto', False, _("automatically fix whitespace")),
('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__':
import getopt