Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Unified Diff: presubmit_canned_checks.py

Issue 9323016: [WebUI] Add some presubmit checks (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixes Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tests/presubmit_unittest.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: presubmit_canned_checks.py
diff --git a/presubmit_canned_checks.py b/presubmit_canned_checks.py
index 41fc6d1926d1925086a55fe89e7bc86b173b0e22..a7eaf6bf1d9d3ca5aea7a483eb72b14fcf2a2c0b 100644
--- a/presubmit_canned_checks.py
+++ b/presubmit_canned_checks.py
@@ -4,6 +4,7 @@
"""Generic presubmit checks that can be reused by other presubmit checks."""
+import re
M-A Ruel 2012/02/03 16:41:35 No need, input_api.re
Dan Beam 2012/02/04 07:26:22 Ah, OK, will do this in new file.
### Description checks
@@ -855,7 +856,7 @@ def PanProjectChecks(input_api, output_api,
r'All rights reserved\.\n'
r'.*? Use of this source code is governed by a BSD-style license that '
r'can be\n'
- r'.*? found in the LICENSE file\.( \*/)?\n'
+ r'.*? found in the LICENSE file\.(?: \*/)?\n'
) % {
'year': input_api.time.strftime('%Y'),
'project': project_name,
@@ -871,6 +872,8 @@ def PanProjectChecks(input_api, output_api,
sources = lambda x: input_api.FilterSourceFile(x, black_list=black_list)
text_files = lambda x: input_api.FilterSourceFile(
x, black_list=black_list, white_list=white_list)
+ resources = lambda x: input_api.FilterSourceFile(x, black_list=black_list,
Evan Stade 2012/02/03 04:13:15 # TODO(dbeam): add more folders to this list
Dan Beam 2012/02/03 04:29:18 Will do soon, this is kind of a hacky version (sho
+ white_list='.*chrome/browser/resources/(?:options2|ntp4).*\.(?j:cs)s$')
M-A Ruel 2012/02/03 16:41:35 This doesn't belong to canned checks. Then if shou
Dan Beam 2012/02/04 07:26:22 Yeah, I figured this yesterday (that this wasn't t
snapshot_memory = []
def snapshot(msg):
@@ -902,6 +905,9 @@ def PanProjectChecks(input_api, output_api,
snapshot("checking singletons")
results.extend(_CheckSingletonInHeaders(
input_api, output_api, source_file_filter=sources))
+ snapshot("checking resouces")
Evan Stade 2012/02/03 04:13:15 sp
Dan Beam 2012/02/03 04:29:18 Thank you.
+ results.extend(_CheckWebDevStyleGuide(
+ input_api, output_api, source_file_filter=resources))
# The following checks are only done on commit, since the commit bot will
# auto-fix most of these.
@@ -920,3 +926,152 @@ def PanProjectChecks(input_api, output_api,
input_api, output_api))
snapshot("done")
return results
+
+def _CheckWebDevStyleGuide(input_api, output_api, source_file_filter):
M-A Ruel 2012/02/03 16:41:35 why the underscore?
Dan Beam 2012/02/04 07:26:22 It was just to match local style (all the other fu
+ def _collapseable_hex(s):
+ return (len(s) == 6 and s[0] == s[1] and s[2] == s[3] and s[4] == s[5])
+
+ def _is_gray(s):
+ return s[0] == s[1] == s[2] if len(s) == 3 else s[0:2] == s[2:4] == s[4:6]
+
+ def _remove_ats(s):
+ return re.sub(re.compile(r'@\w+.*?{(.*{.*?})+.*?}', re.DOTALL), '\\1', s)
+
+ def _remove_comments(s):
+ return re.sub(re.compile(r'/\*.*?\*/', re.DOTALL), '', s)
+
+ def _rgb_from_hex(s):
+ if len(s) == 3:
+ r, g, b = s[0] + s[0], s[1] + s[1], s[2] + s[2]
+ else:
+ r, g, b = s[0:2], s[2:4], s[4:6]
+ return 'rgb(%d, %d, %d)' % (int(r, base=16),
+ int(g, base=16),
+ int(b, base=16))
+
+ # Shared between hex_could_be_shorter and rgb_if_not_gray.
+ hex_reg = r'#([a-fA-F0-9]{3}|[a-fA-F0-9]{6})(?=[^_a-zA-Z0-9-]|$)(?!.+[{,]$)'
+
+ def alphabetize_props(f):
+ errors = []
+ lines = _remove_ats(_remove_comments(input_api.ReadFile(f, 'rb')))
+ for block in re.finditer(r'{(.*?)}', lines, re.DOTALL):
+ rules = filter(lambda l: l.find(': ') >= 0,
+ map(lambda l: l.strip(), block.group(1).split(';'))[0:-1])
+ if rules != sorted(rules):
+ errors.append('%s:\n %s' % (f, '\n '.join(rules)))
+ return errors
+
+ def braces_and_colons_have_space_after(f):
+ errors = []
+ lines = _remove_comments(input_api.ReadFile(f, 'rb')).splitlines()
+ for l in range(0, len(lines)):
+ if re.search(r'(^\s*{)|(?:{|:(?!\/\/|.*[{,]))\S', lines[l]):
+ errors.append(' %s:%d:%s' % (f, l, lines[l]))
+ return errors
+
+ def classes_use_dashes(f):
+ errors = []
+ lines = _remove_comments(input_api.ReadFile(f, 'rb')).splitlines()
+ for l in range(0, len(lines)):
+ # Intentionally dumbed down version of CSS2.1 grammar for class without
+ # non-ASCII, escape chars, or whitespace.
+ m = re.search(r'(?:^| )\.(-?[_a-zA-Z0-9-]+)', lines[l])
+ if m:
+ c = m.group(1)
+ if (c.lower() != c or c.find('_') >= 0):
+ errors.append(' %s:%d:%s' % (f, l, lines[l]))
+ return errors
+
+ def favor_single_quotes(f):
+ errors = []
+ lines = _remove_comments(input_api.ReadFile(f, 'rb')).splitlines()
+ for l in range(0, len(lines)):
+ if lines[l].find('"') >= 0:
+ errors.append(' %s:%d:%s' % (f, l, lines[l]))
+ return errors
+
+ def hex_could_be_shorter(f):
+ errors = []
+ lines = input_api.ReadFile(f, 'rb').splitlines()
+ for l in range(0, len(lines)):
+ m = re.search(hex_reg, lines[l])
+ if (m and _collapseable_hex(m.group(1))):
+ errors.append(' %s:%d:%s' % (f, l, lines[l]))
+ return errors
+
+ def one_selector_per_line(f):
+ errors = []
+ lines = _remove_ats(_remove_comments(input_api.ReadFile(f, 'rb'))
+ ).splitlines()
+ for l in range(0, len(lines)):
+ if re.search(r'[^,]+,[^,]+{', lines[l]):
+ errors.append(' %s:%d:%s' % (f, l, lines[l]))
+ return errors
+
+ def rgb_if_not_gray(f):
+ errors = []
+ lines = _remove_comments(input_api.ReadFile(f, 'rb')).splitlines()
+ for l in range(0, len(lines)):
+ m = re.search(hex_reg, lines[l])
+ if (m and not _is_gray(m.group(1))):
+ rgb = _rgb_from_hex(m.group(1))
+ errors.append(' %s:%d:%s /* = %s */ ' % (f, l, lines[l], rgb))
+ return errors
+
+ def zero_length_values(f):
+ errors = []
+ zeros = ''.join((r'[^0-9](?:0?\.)?0',
+ r'(?:px|em|%|in|cm|mm|pc|pt|ex|deg|g?rad|m?s|k?hz)',
+ r'(?!\s*\{)'))
+ hsl = r'hsl\([^\)]*(?:[, ]|(?<=\())(?:0?\.?)?0%'
+ lines = input_api.ReadFile(f, 'rb').splitlines()
+ for l in range(0, len(lines)):
+ if (re.search(zeros, lines[l]) and not re.search(hsl, lines[l])):
+ errors.append(' %s:%d:%s' % (f, l, lines[l]))
+ return errors
+
+ added_or_modified_files_checks = [
+ { 'desc': 'Alphabetize properties, but list vendor specific (i.e. -webkit) '
+ 'above standard.',
+ 'test': alphabetize_props
+ },
+ { 'desc': 'Braces ({} and colons (:) should have a space after them and no '
+ 'newlines before them.',
+ 'test': braces_and_colons_have_space_after,
+ },
+ { 'desc': 'Classes use .dash-form.',
+ 'test': classes_use_dashes,
+ },
+ { 'desc': 'Use single quotes (\') instead of double quotes (") in strings.',
+ 'test': favor_single_quotes,
+ },
+ { 'desc': 'Favor short hex form (#rgb) when #rrggbb.',
+ 'test': hex_could_be_shorter,
+ },
+ { 'desc': 'One selector per line (what not to do: a, b {}).',
+ 'test': one_selector_per_line,
+ },
+ { 'desc': 'Use rgb() over #hex when not a shade of gray (like #333).',
+ 'test': rgb_if_not_gray,
+ },
+ { 'desc': 'Make all zero length terms (i.e. 0px) 0 unless inside of hsl()'
+ 'or @keyframe.',
+ 'test': zero_length_values,
+ },
+ ]
+
+ errors = []
+ files = [f.AbsoluteLocalPath() for f in
+ input_api.AffectedFiles(include_deletes=False,
+ file_filter=source_file_filter)]
+
+ # Only look at CSS files for now.
+ for f in filter(lambda l: l.endswith('.css'), files):
+ for check in added_or_modified_files_checks:
+ errs = check['test'](f)
+ if errs:
+ msg = '%s\n%s' % (check['desc'], '\n'.join(errs))
+ errors.append(output_api.PresubmitNotifyResult(msg))
+
+ return errors
« no previous file with comments | « no previous file | tests/presubmit_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698