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

Side by Side Diff: build/config/ios/ios_gen_plist.py

Issue 1611363003: Add support for iOS application bundle to GN. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@gn-bundles
Patch Set: Created 4 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 unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2016 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import argparse
6 import plistlib
7 import os
8 import re
9 import subprocess
10 import sys
11 import tempfile
12 import shlex
13
14
15 IDENT_RE = re.compile(r'[/\s]')
brettw 2016/01/22 19:00:12 Can you provide documentation for these about what
sdefresne 2016/01/25 14:01:22 Done.
16 SUBST_RE = re.compile(r'\$\{(?P<id>[^}]*?)(?P<modifier>:[^}]*)?\}')
17
18
19 class ArgumentParser(argparse.ArgumentParser):
20
brettw 2016/01/22 19:00:12 Delete blank line.
sdefresne 2016/01/25 14:01:22 Done.
21 """Subclass of argparse.ArgumentParser to work with GN response files."""
22
23 def convert_arg_line_to_args(self, arg_line):
24 return shlex.split(arg_line)
25
26
27 def Merge(plist1, plist2):
28 """Recursively merges |plist2| into |plist1|."""
29 if not plist1:
30 return plist2
31 for key in plist2:
32 value = plist2[key]
33 if isinstance(value, dict):
34 plist1[key] = Merge(plist1.get(key, {}), value)
35 else:
36 plist1[key] = value
37 return plist1
38
39
40 def Interpolate(plist, substitutions):
41 """Interpolates ${variable} into |plist| using mapping in |substitutions|."""
42 result = []
43 groups = SUBST_RE.split(plistlib.writePlistToString(plist))
44 # SUBST_RE defines two patterns, so given a string, SUBST_RE.split will
45 # return a list whose position correspond to an unmatched fragment, a
46 # match identifier or a match modifier (may be None as it is optional).
47 # Enumerate over the value and check the index modulo 3 to figure out
48 # the category of the value.
49 for i, value in enumerate(groups):
50 if i % 3 == 0:
51 result.append(value)
52 elif i % 3 == 1:
53 if value in substitutions:
54 result.append(substitutions[value])
55 else:
56 result.append('${%s}' % value)
57 elif i % 3 == 2:
58 value, modifier = result[-1], value
59 if modifier == 'identifier':
60 value = IDENT_RE.sub('-', value)
61 elif modifier == 'rfc1034identifier':
62 value = IDENT_RE.sub('_', value)
63 result[-1] = value
64 return CleanPlist(plistlib.readPlistFromString(''.join(result)))
65
66
67 def CleanPlist(plist):
68 """Removes all key of |plist| with unexpanded variables substitution."""
69 key_to_remove = []
70 for key in plist:
71 value = plist[key]
72 data = plistlib.writePlistToString(value)
73 if SUBST_RE.search(data):
74 key_to_remove.append(key)
75 for key in key_to_remove:
76 del plist[key]
77 return plist
78
79
80 def LoadPList(path):
81 """Loads Plist at |path| and returns it as a dictionary."""
82 fd, name = tempfile.mkstemp()
83 try:
84 subprocess.check_call(['plutil', '-convert', 'xml1', '-o', name, path])
85 with os.fdopen(fd, 'r') as f:
86 return plistlib.readPlist(f)
87 finally:
88 os.unlink(name)
89
90
91 def SavePList(path, data):
92 """Saves |data| as a Plist to |path| in binary1 format."""
93 fd, name = tempfile.mkstemp()
94 try:
95 with os.fdopen(fd, 'w') as f:
96 plistlib.writePlist(data, f)
97 subprocess.check_call(['plutil', '-convert', 'binary1', '-o', path, name])
98 finally:
99 os.unlink(name)
100
101
102 def main():
103 parser = ArgumentParser(
104 description='A script to generate iOS application Info.plist.',
105 fromfile_prefix_chars='@')
106 parser.add_argument('-o', '--output', required=True,
107 help='Path to output plist file.')
108 parser.add_argument('-s', '--subst', action='append', default=[],
109 help='Substitution rule in the format "key=value".')
110 parser.add_argument('path', nargs="+", help='Path to input plist files.')
111 args = parser.parse_args()
112
113 substitutions = {}
114 for subst in args.subst:
115 key, value = subst.split('=', 1)
116 substitutions[key] = value
117
118 data = {}
119 for path in args.path:
120 data = Merge(data, LoadPList(path))
121
122 data = Interpolate(data, substitutions)
123 SavePList(args.output, data)
124 return 0
125
126
127 if __name__ == '__main__':
128 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698