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

Unified Diff: build/config/ios/ios_gen_plist.py

Issue 1752873002: Use bundle_data and create_bundle to add support for iOS app bundle. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@gn-create-bundle
Patch Set: Remove conditional around bundle_data, use response_file_contents, clean description of compile_xca… Created 4 years, 9 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/ios/BuildInfo.plist ('k') | build/config/ios/ios_sdk.gni » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: build/config/ios/ios_gen_plist.py
diff --git a/build/config/ios/ios_gen_plist.py b/build/config/ios/ios_gen_plist.py
new file mode 100644
index 0000000000000000000000000000000000000000..cca2ba49d8ecefb06de48b4f257462ef0b4b6aa1
--- /dev/null
+++ b/build/config/ios/ios_gen_plist.py
@@ -0,0 +1,207 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import plistlib
+import os
+import re
+import subprocess
+import sys
+import tempfile
+import shlex
+
+
+# Xcode substitutes variables like ${PRODUCT_NAME} when compiling Info.plist.
+# It also supports supports modifiers like :identifier or :rfc1034identifier.
+# SUBST_RE matches a variable substitution pattern with an optional modifier,
+# while IDENT_RE matches all characters that are not valid in an "identifier"
+# value (used when applying the modifier).
+SUBST_RE = re.compile(r'\$\{(?P<id>[^}]*?)(?P<modifier>:[^}]*)?\}')
+IDENT_RE = re.compile(r'[/\s]')
+
+
+class ArgumentParser(argparse.ArgumentParser):
+ """Subclass of argparse.ArgumentParser to work with GN response files.
+
+ GN response file writes all the arguments on a single line and assumes
+ that the python script uses shlext.split() to extract them. Since the
+ default ArgumentParser expects a single argument per line, we need to
+ provide a subclass to have the correct support for @{{response_file_name}}.
+ """
+
+ def convert_arg_line_to_args(self, arg_line):
+ 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|.
+
+ Inputs:
+ value: a string
+ substitutions: a mapping of variable names to values
+
+ 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.
+ """
+ result = value
+ for match in reversed(list(SUBST_RE.finditer(value))):
+ variable = match.group('id')
+ if variable not in substitutions:
+ return None
+ # 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])
+ elif modifier == 'rfc1034identifier':
+ interpolated = IDENT_RE.sub('_', substitutions[variable])
+ else:
+ interpolated = substitutions[variable]
+ result = result[:match.start()] + interpolated + result[match.end():]
+ return result
+
+
+def InterpolateValue(value, substitutions):
+ """Interpolates variable references into |value| using |substitutions|.
+
+ Inputs:
+ value: a value, can be a dictionary, list, string or other
+ substitutions: a mapping of variable names to values
+
+ 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.
+ """
+ if isinstance(value, dict):
+ return Interpolate(value, substitutions)
+ if isinstance(value, list):
+ return InterpolateList(value, substitutions)
+ if isinstance(value, str):
+ return InterpolateString(value, substitutions)
+ 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()
+ try:
+ subprocess.check_call(['plutil', '-convert', 'xml1', '-o', name, path])
+ with os.fdopen(fd, 'r') as f:
+ return plistlib.readPlist(f)
+ finally:
+ os.unlink(name)
+
+
+def SavePList(path, data):
+ """Saves |data| as a Plist to |path| in binary1 format."""
+ fd, name = tempfile.mkstemp()
+ try:
+ with os.fdopen(fd, 'w') as f:
+ plistlib.writePlist(data, f)
+ subprocess.check_call(['plutil', '-convert', 'binary1', '-o', path, name])
+ finally:
+ os.unlink(name)
+
+
+def MergePList(plist1, plist2):
+ """Merges |plist1| with |plist2| recursively.
+
+ Creates a new dictionary representing a Property List (.plist) files by
+ merging the two dictionary |plist1| and |plist2| recursively (only for
+ dictionary values).
+
+ Args:
+ plist1: a dictionary representing a Property List (.plist) file
+ plist2: a dictionary representing a Property List (.plist) file
+
+ Returns:
+ A new dictionary representing a Property List (.plist) file by merging
+ |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]
+ if isinstance(value, dict):
+ value = MergePList(plist1.get(key, None), plist2.get(key, None))
+ result[key] = value
+ return result
+
+
+def main():
+ parser = ArgumentParser(
+ description='A script to generate iOS application Info.plist.',
+ fromfile_prefix_chars='@')
+ parser.add_argument('-o', '--output', required=True,
+ help='Path to output plist file.')
+ parser.add_argument('-s', '--subst', action='append', default=[],
+ help='Substitution rule in the format "key=value".')
+ parser.add_argument('path', nargs="+", help='Path to input plist files.')
+ args = parser.parse_args()
+ substitutions = {}
+ for subst in args.subst:
+ key, value = subst.split('=', 1)
+ substitutions[key] = value
+ data = {}
+ for filename in args.path:
+ data = MergePList(data, LoadPList(filename))
+ data = Interpolate(data, substitutions)
+ SavePList(args.output, data)
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
« no previous file with comments | « build/config/ios/BuildInfo.plist ('k') | build/config/ios/ios_sdk.gni » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698