2013-10-08 14:31:16 +02:00
|
|
|
#!/usr/bin/env python
|
2013-10-25 23:46:02 +02:00
|
|
|
import os
|
|
|
|
import sys
|
2013-11-08 22:45:20 +01:00
|
|
|
import subprocess
|
2013-10-25 23:46:02 +02:00
|
|
|
|
2013-10-08 14:31:16 +02:00
|
|
|
class Record:
|
|
|
|
pass
|
|
|
|
|
2013-11-18 22:57:55 +01:00
|
|
|
def validate(fn, check_indent=True):
|
2013-10-08 14:31:16 +02:00
|
|
|
text = open(fn).read()
|
|
|
|
|
|
|
|
state = Record()
|
|
|
|
|
|
|
|
def NoStartTag(end_tag):
|
2013-11-18 22:57:55 +01:00
|
|
|
raise Exception('''
|
|
|
|
No start tag
|
|
|
|
fn: %s
|
|
|
|
end tag:
|
|
|
|
%s
|
|
|
|
line %d, col %d
|
|
|
|
''' % (fn, end_tag, state.line, state.col))
|
2013-10-08 14:31:16 +02:00
|
|
|
|
|
|
|
def start_tag_matcher(s):
|
|
|
|
start_line = state.line
|
|
|
|
start_col = state.col
|
|
|
|
state.depth += 1
|
|
|
|
tag = s[1:-1]
|
|
|
|
start_tag = tag.split()[0]
|
|
|
|
old_matcher = state.matcher
|
|
|
|
def f(end_tag):
|
|
|
|
problem = None
|
|
|
|
if start_tag != end_tag[2:-1]:
|
|
|
|
problem = 'Mismatched tag.'
|
2013-11-18 22:57:55 +01:00
|
|
|
elif check_indent and state.line > start_line + 1 and state.col != start_col:
|
2013-10-08 14:31:16 +02:00
|
|
|
problem = 'Bad indentation.'
|
|
|
|
if problem:
|
|
|
|
raise Exception('''
|
|
|
|
fn: %s
|
|
|
|
%s
|
|
|
|
start:
|
|
|
|
%s
|
|
|
|
line %d, col %d
|
|
|
|
end tag:
|
|
|
|
%s
|
|
|
|
line %d, col %d
|
|
|
|
''' % (fn, problem, s, start_line, start_col, end_tag, state.line, state.col))
|
|
|
|
state.matcher = old_matcher
|
|
|
|
state.depth -= 1
|
2013-11-18 22:57:55 +01:00
|
|
|
state.matcher = f
|
2013-10-08 14:31:16 +02:00
|
|
|
|
|
|
|
state.depth = 0
|
|
|
|
state.i = 0
|
|
|
|
state.line = 1
|
|
|
|
state.col = 1
|
|
|
|
state.matcher = NoStartTag
|
|
|
|
|
|
|
|
def advance(n):
|
|
|
|
for _ in range(n):
|
|
|
|
state.i += 1
|
|
|
|
if state.i >= 0 and text[state.i - 1] == '\n':
|
|
|
|
state.line += 1
|
|
|
|
state.col = 1
|
|
|
|
else:
|
|
|
|
state.col += 1
|
|
|
|
|
|
|
|
while True:
|
|
|
|
if state.i >= len(text):
|
|
|
|
break
|
|
|
|
c = text[state.i]
|
|
|
|
if c == '<':
|
|
|
|
end = state.i + 1
|
|
|
|
while end < len(text) and text[end] != '>':
|
|
|
|
end += 1
|
|
|
|
if text[end] != '>':
|
|
|
|
raise Exception('Tag missing >')
|
|
|
|
s = text[state.i:end+1]
|
|
|
|
if s.startswith('</'):
|
|
|
|
state.matcher(s)
|
|
|
|
else:
|
2013-11-18 22:57:55 +01:00
|
|
|
tag = s[1:-1].split()[0]
|
|
|
|
ignore = s.startswith('<!--') or s.endswith('/>') or tag in ['img', 'meta', 'br', 'input']
|
|
|
|
if not ignore:
|
|
|
|
start_tag_matcher(s)
|
2013-10-08 14:31:16 +02:00
|
|
|
advance(len(s))
|
|
|
|
continue
|
|
|
|
advance(1)
|
|
|
|
|
2013-11-18 22:57:55 +01:00
|
|
|
if state.depth != 0:
|
|
|
|
return state.matcher("(NO TAG)")
|
2013-10-08 14:31:16 +02:00
|
|
|
|
2013-11-08 22:45:20 +01:00
|
|
|
git_files = map(str.strip, subprocess.check_output(['git', 'ls-files']).split('\n'))
|
2013-10-25 20:47:03 +02:00
|
|
|
|
|
|
|
# Check all our handlebars templates.
|
2013-10-08 14:31:16 +02:00
|
|
|
templates = [fn for fn in git_files if fn.endswith('.handlebars')]
|
|
|
|
assert len(templates) >= 10 # sanity check that we are actually doing work
|
2013-11-18 22:57:55 +01:00
|
|
|
for fn in templates:
|
|
|
|
validate(fn)
|
|
|
|
|
|
|
|
# Django templates are pretty messy now, so we do minimal checking.
|
|
|
|
templates = sorted([fn for fn in git_files if fn.endswith('.html') and 'templates' in fn])
|
|
|
|
|
|
|
|
def ok(fn):
|
|
|
|
if 'api.html' in fn: return False
|
|
|
|
if 'base.html' in fn: return False
|
|
|
|
if 'emails/' in fn: return False
|
|
|
|
return True
|
2013-10-25 20:47:03 +02:00
|
|
|
|
2013-11-18 22:57:55 +01:00
|
|
|
templates = filter(ok, templates)
|
2013-10-25 20:47:03 +02:00
|
|
|
|
2013-11-18 22:57:55 +01:00
|
|
|
|
|
|
|
assert len(templates) >= 10 # sanity check that we are actually doing work
|
2013-10-08 14:31:16 +02:00
|
|
|
for fn in templates:
|
2013-11-18 22:57:55 +01:00
|
|
|
validate(fn, check_indent=False)
|