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

Unified Diff: build/config/mac/gen_plist.py

Issue 2367923002: Fail to build with unbound Info.plist substitutions instead of silently dropping them. (Closed)
Patch Set: Add a temporary flag to go back to skipping unbound substitutions Created 4 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 | « build/config/mac/BuildInfo.plist ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: build/config/mac/gen_plist.py
diff --git a/build/config/mac/gen_plist.py b/build/config/mac/gen_plist.py
index 0004179505ee6e63bc5988c65b4aeba58f3d1b93..a05c4279e8d5bbc503d33d629f196a9b539e1712 100644
--- a/build/config/mac/gen_plist.py
+++ b/build/config/mac/gen_plist.py
@@ -21,6 +21,12 @@ SUBST_RE = re.compile(r'\$\{(?P<id>[^}]*?)(?P<modifier>:[^}]*)?\}')
IDENT_RE = re.compile(r'[_/\s]')
+class SubstitutionError(Exception):
+ def __init__(self, key):
+ super(SubstitutionError, self).__init__()
+ self.key = key
+
+
class ArgumentParser(argparse.ArgumentParser):
"""Subclass of argparse.ArgumentParser to work with GN response files.
@@ -34,27 +40,6 @@ class ArgumentParser(argparse.ArgumentParser):
return shlex.split(arg_line)
-def InterpolateList(values, substitutions):
- """Interpolates variable references into |value| using |substitutions|.
-
- Inputs:
- values: a list of values
- substitutions: a mapping of variable names to values
-
- Returns:
- A new list of values with all variables references ${VARIABLE} replaced
- by their value in |substitutions| or None if any of the variable has no
- subsitution.
- """
- result = []
- for value in values:
- interpolated = InterpolateValue(value, substitutions)
- if interpolated is None:
- return None
- result.append(interpolated)
- return result
-
-
def InterpolateString(value, substitutions):
"""Interpolates variable references into |value| using |substitutions|.
@@ -64,29 +49,28 @@ def InterpolateString(value, substitutions):
Returns:
A new string with all variables references ${VARIABLES} replaced by their
- value in |substitutions| or None if any of the variable has no substitution.
+ value in |substitutions|. Raises SubstitutionError if a variable has no
+ substitution.
"""
- result = value
- for match in reversed(list(SUBST_RE.finditer(value))):
+ def repl(match):
variable = match.group('id')
if variable not in substitutions:
- return None
+ raise SubstitutionError(variable)
# Some values need to be identifier and thus the variables references may
# contains :modifier attributes to indicate how they should be converted
# to identifiers ("identifier" replaces all invalid characters by '_' and
# "rfc1034identifier" replaces them by "-" to make valid URI too).
modifier = match.group('modifier')
if modifier == ':identifier':
- interpolated = IDENT_RE.sub('_', substitutions[variable])
+ return IDENT_RE.sub('_', substitutions[variable])
elif modifier == ':rfc1034identifier':
- interpolated = IDENT_RE.sub('-', substitutions[variable])
+ return IDENT_RE.sub('-', substitutions[variable])
else:
- interpolated = substitutions[variable]
- result = result[:match.start()] + interpolated + result[match.end():]
- return result
+ return substitutions[variable]
+ return SUBST_RE.sub(repl, value)
-def InterpolateValue(value, substitutions):
+def Interpolate(value, substitutions, map_fn=map):
"""Interpolates variable references into |value| using |substitutions|.
Inputs:
@@ -95,38 +79,20 @@ def InterpolateValue(value, substitutions):
Returns:
A new value with all variables references ${VARIABLES} replaced by their
- value in |substitutions| or None if any of the variable has no substitution.
+ value in |substitutions|. Raises SubstitutionError if a variable has no
+ substitution.
"""
if isinstance(value, dict):
- return Interpolate(value, substitutions)
+ return dict(map_fn(lambda (k, v): (k, Interpolate(v, substitutions,
+ map_fn=map_fn)), value.iteritems()))
if isinstance(value, list):
- return InterpolateList(value, substitutions)
+ return list(map_fn(lambda v: Interpolate(v, substitutions, map_fn=map_fn),
+ value.iteritems()))
if isinstance(value, str):
return InterpolateString(value, substitutions)
sdefresne 2016/09/27 08:26:00 I think call may lead to uncaught SubstitutionErro
Sidney San Martín 2016/09/27 20:15:22 I think the current behavior might be correct, but
return value
-def Interpolate(plist, substitutions):
- """Interpolates variable references into |value| using |substitutions|.
-
- Inputs:
- plist: a dictionary representing a Property List (.plist) file
- substitutions: a mapping of variable names to values
-
- Returns:
- A new plist with all variables references ${VARIABLES} replaced by their
- value in |substitutions|. All values that contains references with no
- substitutions will be removed and the corresponding key will be cleared
- from the plist (not recursively).
- """
- result = {}
- for key in plist:
- value = InterpolateValue(plist[key], substitutions)
- if value is not None:
- result[key] = value
- return result
-
-
def LoadPList(path):
"""Loads Plist at |path| and returns it as a dictionary."""
fd, name = tempfile.mkstemp()
@@ -165,19 +131,12 @@ def MergePList(plist1, plist2):
|plist1| with |plist2|. If any value is a dictionary, they are merged
recursively, otherwise |plist2| value is used.
"""
- if not isinstance(plist1, dict) or not isinstance(plist2, dict):
- if plist2 is not None:
- return plist2
- else:
- return plist1
- result = {}
- for key in set(plist1) | set(plist2):
- if key in plist2:
- value = plist2[key]
- else:
- value = plist1[key]
+ result = plist1.copy()
+ for key, value in plist2.iteritems():
if isinstance(value, dict):
- value = MergePList(plist1.get(key, None), plist2.get(key, None))
+ old_value = result.get(key)
+ if isinstance(old_value, dict):
+ value = MergePList(old_value, value)
result[key] = value
return result
@@ -192,6 +151,10 @@ def main():
help='Substitution rule in the format "key=value".')
parser.add_argument('-f', '--format', required=True,
help='Plist format (e.g. binary1, xml1) to output.')
+ parser.add_argument('--skip-unbound-variables', action='store_true',
+ help="""When an item uses an unbound variable, skip it
+ instead of raising an error.
+ """)
parser.add_argument('path', nargs="+", help='Path to input plist files.')
args = parser.parse_args()
substitutions = {}
@@ -199,9 +162,28 @@ def main():
key, value = subst.split('=', 1)
substitutions[key] = value
data = {}
+ if args.skip_unbound_variables:
+ def interpolate_fn(*args):
+ def map_fn(f, iterable):
+ for v in iterable:
+ try:
+ yield f(v)
+ except SubstitutionError:
+ pass
+ return Interpolate(*args, map_fn=map_fn)
+ else:
+ interpolate_fn = Interpolate
+
for filename in args.path:
- data = MergePList(data, LoadPList(filename))
- data = Interpolate(data, substitutions)
+ plist = LoadPList(filename)
+ try:
+ data = MergePList(data, interpolate_fn(plist, substitutions))
+ except SubstitutionError as e:
+ print >>sys.stderr, (
+ "SubstitutionError: No substitution found for '{0}' in {1}"
+ .format(e.key, filename))
+ return 1
+
SavePList(args.output, args.format, data)
return 0
« no previous file with comments | « build/config/mac/BuildInfo.plist ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698