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

Unified Diff: pylib/gyp/input.py

Issue 202059: Add a --check flag. This causes gyp to check syntax of files more carefully,... (Closed) Base URL: http://gyp.googlecode.com/svn/trunk/
Patch Set: '' Created 11 years, 3 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 | « pylib/gyp/__init__.py ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pylib/gyp/input.py
===================================================================
--- pylib/gyp/input.py (revision 640)
+++ pylib/gyp/input.py (working copy)
@@ -1,5 +1,13 @@
#!/usr/bin/python
+from compiler.ast import Const
+from compiler.ast import Dict
+from compiler.ast import Discard
+from compiler.ast import List
+from compiler.ast import Module
+from compiler.ast import Node
+from compiler.ast import Stmt
+import compiler
import copy
import gyp.common
import optparse
@@ -107,9 +115,51 @@
return included
+def CheckedEval(file_contents):
+ """Return the eval of a gyp file.
+ The gyp file is restricted to dictionaries and lists only, and
+ repeated keys are not allowed.
+
+ Note that this is slower than eval() is.
+ """
+
+ ast = compiler.parse(file_contents)
+ assert isinstance(ast, Module)
+ c1 = ast.getChildren()
+ assert c1[0] is None
+ assert isinstance(c1[1], Stmt)
+ c2 = c1[1].getChildren()
+ assert isinstance(c2[0], Discard)
+ c3 = c2[0].getChildren()
+ assert len(c3) == 1
+ return CheckNode(c3[0],0)
+
+def CheckNode(node, level):
+ if isinstance(node, Dict):
+ c = node.getChildren()
+ dict = {}
+ for n in range(0, len(c), 2):
+ assert isinstance(c[n], Const)
+ key = c[n].getChildren()[0]
+ if key in dict:
+ raise KeyError, "Key '" + key + "' repeated at level " \
+ + repr(level)
+ dict[key] = CheckNode(c[n + 1], level + 1)
+ return dict
+ elif isinstance(node, List):
+ c = node.getChildren()
+ list = []
+ for child in c:
+ list.append(CheckNode(child, level + 1))
+ return list
+ elif isinstance(node, Const):
+ return node.getChildren()[0]
+ else:
+ raise TypeError, "Unknown AST node " + repr(node)
+
def LoadOneBuildFile(build_file_path, data, aux_data, variables, includes,
- is_target):
+ is_target, check):
if build_file_path in data:
return data[build_file_path]
@@ -120,7 +170,11 @@
build_file_data = None
try:
- build_file_data = eval(build_file_contents, {'__builtins__': None}, None)
+ if check:
+ build_file_data = CheckedEval(build_file_contents)
+ else:
+ build_file_data = eval(build_file_contents, {'__builtins__': None},
+ None)
except SyntaxError, e:
e.filename = build_file_path
raise
@@ -135,10 +189,10 @@
try:
if is_target:
LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data,
- aux_data, variables, includes)
+ aux_data, variables, includes, check)
else:
LoadBuildFileIncludesIntoDict(build_file_data, build_file_path, data,
- aux_data, variables, None)
+ aux_data, variables, None, check)
except Exception, e:
gyp.common.ExceptionAppend(e,
'while reading includes of ' + build_file_path)
@@ -148,7 +202,7 @@
def LoadBuildFileIncludesIntoDict(subdict, subdict_path, data, aux_data,
- variables, includes):
+ variables, includes, check):
includes_list = []
if includes != None:
includes_list.extend(includes)
@@ -170,35 +224,36 @@
aux_data[subdict_path]['included'].append(include)
MergeDicts(subdict,
LoadOneBuildFile(include, data, aux_data, variables, None,
- False),
+ False, check),
subdict_path, include)
# Recurse into subdictionaries.
for k, v in subdict.iteritems():
if v.__class__ == dict:
LoadBuildFileIncludesIntoDict(v, subdict_path, data, aux_data, variables,
- None)
+ None, check)
elif v.__class__ == list:
- LoadBuildFileIncludesIntoList(v, subdict_path, data, aux_data, variables)
+ LoadBuildFileIncludesIntoList(v, subdict_path, data, aux_data, variables,
+ check)
# This recurses into lists so that it can look for dicts.
def LoadBuildFileIncludesIntoList(sublist, sublist_path, data, aux_data,
- variables):
+ variables, check):
for item in sublist:
if item.__class__ == dict:
LoadBuildFileIncludesIntoDict(item, sublist_path, data, aux_data,
- variables, None)
+ variables, None, check)
elif item.__class__ == list:
LoadBuildFileIncludesIntoList(item, sublist_path, data, aux_data,
- variables)
+ variables, check)
# TODO(mark): I don't love this name. It just means that it's going to load
# a build file that contains targets and is expected to provide a targets dict
# that contains the targets...
def LoadTargetBuildFile(build_file_path, data, aux_data, variables, includes,
- depth):
+ depth, check):
global absolute_build_file_paths
# If depth is set, predefine the DEPTH variable to be a relative path from
@@ -219,7 +274,7 @@
return
build_file_data = LoadOneBuildFile(build_file_path, data, aux_data, variables,
- includes, True)
+ includes, True, check)
# Store DEPTH for later use in generators.
build_file_data['_DEPTH'] = depth
@@ -283,7 +338,7 @@
gyp.common.BuildFileAndTarget(build_file_path, dependency)[0]
try:
LoadTargetBuildFile(other_build_file, data, aux_data, variables,
- includes, depth)
+ includes, depth, check)
except Exception, e:
gyp.common.ExceptionAppend(
e, 'while loading dependencies of %s' % build_file_path)
@@ -1684,7 +1739,7 @@
"in file %s should be a dictionary." %
(target_name, build_file))
-def Load(build_files, variables, includes, depth, generator_input_info):
+def Load(build_files, variables, includes, depth, generator_input_info, check):
# Set up path_sections and non_configuration_keys with the default data plus
# the generator-specifc data.
global path_sections
@@ -1718,7 +1773,8 @@
# used as keys to the data dict and for references between input files.
build_file = os.path.normpath(build_file)
try:
- LoadTargetBuildFile(build_file, data, aux_data, variables, includes, depth)
+ LoadTargetBuildFile(build_file, data, aux_data, variables, includes,
+ depth, check)
except Exception, e:
gyp.common.ExceptionAppend(e, 'while trying to load %s' % build_file)
raise
« no previous file with comments | « pylib/gyp/__init__.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698