Chromium Code Reviews| 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 |