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

Side by Side Diff: pylib/gyp/mac_tool.py

Issue 825453002: Convert plist and strings to binary for iOS. (Closed) Base URL: https://chromium.googlesource.com/external/gyp.git@master
Patch Set: Remove blank line Created 5 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 unified diff | Download patch
« no previous file with comments | « pylib/gyp/generator/ninja.py ('k') | pylib/gyp/xcode_emulation.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 Google Inc. All rights reserved. 2 # Copyright (c) 2012 Google Inc. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Utility functions to perform Xcode-style build steps. 6 """Utility functions to perform Xcode-style build steps.
7 7
8 These functions are executed via gyp-mac-tool when using the Makefile generator. 8 These functions are executed via gyp-mac-tool when using the Makefile generator.
9 """ 9 """
10 10
(...skipping 27 matching lines...) Expand all
38 if len(args) < 1: 38 if len(args) < 1:
39 raise Exception("Not enough arguments") 39 raise Exception("Not enough arguments")
40 40
41 method = "Exec%s" % self._CommandifyName(args[0]) 41 method = "Exec%s" % self._CommandifyName(args[0])
42 return getattr(self, method)(*args[1:]) 42 return getattr(self, method)(*args[1:])
43 43
44 def _CommandifyName(self, name_string): 44 def _CommandifyName(self, name_string):
45 """Transforms a tool name like copy-info-plist to CopyInfoPlist""" 45 """Transforms a tool name like copy-info-plist to CopyInfoPlist"""
46 return name_string.title().replace('-', '') 46 return name_string.title().replace('-', '')
47 47
48 def ExecCopyBundleResource(self, source, dest): 48 def ExecCopyBundleResource(self, source, dest, convert_to_binary):
49 """Copies a resource file to the bundle/Resources directory, performing any 49 """Copies a resource file to the bundle/Resources directory, performing any
50 necessary compilation on each resource.""" 50 necessary compilation on each resource."""
51 extension = os.path.splitext(source)[1].lower() 51 extension = os.path.splitext(source)[1].lower()
52 if os.path.isdir(source): 52 if os.path.isdir(source):
53 # Copy tree. 53 # Copy tree.
54 # TODO(thakis): This copies file attributes like mtime, while the 54 # TODO(thakis): This copies file attributes like mtime, while the
55 # single-file branch below doesn't. This should probably be changed to 55 # single-file branch below doesn't. This should probably be changed to
56 # be consistent with the single-file branch. 56 # be consistent with the single-file branch.
57 if os.path.exists(dest): 57 if os.path.exists(dest):
58 shutil.rmtree(dest) 58 shutil.rmtree(dest)
59 shutil.copytree(source, dest) 59 shutil.copytree(source, dest)
60 elif extension == '.xib': 60 elif extension == '.xib':
61 return self._CopyXIBFile(source, dest) 61 return self._CopyXIBFile(source, dest)
62 elif extension == '.storyboard': 62 elif extension == '.storyboard':
63 return self._CopyXIBFile(source, dest) 63 return self._CopyXIBFile(source, dest)
64 elif extension == '.strings': 64 elif extension == '.strings':
65 self._CopyStringsFile(source, dest) 65 self._CopyStringsFile(source, dest, convert_to_binary)
66 else: 66 else:
67 shutil.copy(source, dest) 67 shutil.copy(source, dest)
68 68
69 def _CopyXIBFile(self, source, dest): 69 def _CopyXIBFile(self, source, dest):
70 """Compiles a XIB file with ibtool into a binary plist in the bundle.""" 70 """Compiles a XIB file with ibtool into a binary plist in the bundle."""
71 71
72 # ibtool sometimes crashes with relative paths. See crbug.com/314728. 72 # ibtool sometimes crashes with relative paths. See crbug.com/314728.
73 base = os.path.dirname(os.path.realpath(__file__)) 73 base = os.path.dirname(os.path.realpath(__file__))
74 if os.path.relpath(source): 74 if os.path.relpath(source):
75 source = os.path.join(base, source) 75 source = os.path.join(base, source)
76 if os.path.relpath(dest): 76 if os.path.relpath(dest):
77 dest = os.path.join(base, dest) 77 dest = os.path.join(base, dest)
78 78
79 args = ['xcrun', 'ibtool', '--errors', '--warnings', '--notices', 79 args = ['xcrun', 'ibtool', '--errors', '--warnings', '--notices',
80 '--output-format', 'human-readable-text', '--compile', dest, source] 80 '--output-format', 'human-readable-text', '--compile', dest, source]
81 ibtool_section_re = re.compile(r'/\*.*\*/') 81 ibtool_section_re = re.compile(r'/\*.*\*/')
82 ibtool_re = re.compile(r'.*note:.*is clipping its content') 82 ibtool_re = re.compile(r'.*note:.*is clipping its content')
83 ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE) 83 ibtoolout = subprocess.Popen(args, stdout=subprocess.PIPE)
84 current_section_header = None 84 current_section_header = None
85 for line in ibtoolout.stdout: 85 for line in ibtoolout.stdout:
86 if ibtool_section_re.match(line): 86 if ibtool_section_re.match(line):
87 current_section_header = line 87 current_section_header = line
88 elif not ibtool_re.match(line): 88 elif not ibtool_re.match(line):
89 if current_section_header: 89 if current_section_header:
90 sys.stdout.write(current_section_header) 90 sys.stdout.write(current_section_header)
91 current_section_header = None 91 current_section_header = None
92 sys.stdout.write(line) 92 sys.stdout.write(line)
93 return ibtoolout.returncode 93 return ibtoolout.returncode
94 94
95 def _CopyStringsFile(self, source, dest): 95 def _ConvertToBinary(self, dest):
96 subprocess.check_call([
97 'xcrun', 'plutil', '-convert', 'binary1', '-o', dest, dest])
98
99 def _CopyStringsFile(self, source, dest, convert_to_binary):
96 """Copies a .strings file using iconv to reconvert the input into UTF-16.""" 100 """Copies a .strings file using iconv to reconvert the input into UTF-16."""
97 input_code = self._DetectInputEncoding(source) or "UTF-8" 101 input_code = self._DetectInputEncoding(source) or "UTF-8"
98 102
99 # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call 103 # Xcode's CpyCopyStringsFile / builtin-copyStrings seems to call
100 # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints 104 # CFPropertyListCreateFromXMLData() behind the scenes; at least it prints
101 # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing 105 # CFPropertyListCreateFromXMLData(): Old-style plist parser: missing
102 # semicolon in dictionary. 106 # semicolon in dictionary.
103 # on invalid files. Do the same kind of validation. 107 # on invalid files. Do the same kind of validation.
104 import CoreFoundation 108 import CoreFoundation
105 s = open(source, 'rb').read() 109 s = open(source, 'rb').read()
106 d = CoreFoundation.CFDataCreate(None, s, len(s)) 110 d = CoreFoundation.CFDataCreate(None, s, len(s))
107 _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None) 111 _, error = CoreFoundation.CFPropertyListCreateFromXMLData(None, d, 0, None)
108 if error: 112 if error:
109 return 113 return
110 114
111 fp = open(dest, 'wb') 115 fp = open(dest, 'wb')
112 fp.write(s.decode(input_code).encode('UTF-16')) 116 fp.write(s.decode(input_code).encode('UTF-16'))
113 fp.close() 117 fp.close()
114 118
119 if convert_to_binary == 'True':
120 self._ConvertToBinary(dest)
121
115 def _DetectInputEncoding(self, file_name): 122 def _DetectInputEncoding(self, file_name):
116 """Reads the first few bytes from file_name and tries to guess the text 123 """Reads the first few bytes from file_name and tries to guess the text
117 encoding. Returns None as a guess if it can't detect it.""" 124 encoding. Returns None as a guess if it can't detect it."""
118 fp = open(file_name, 'rb') 125 fp = open(file_name, 'rb')
119 try: 126 try:
120 header = fp.read(3) 127 header = fp.read(3)
121 except e: 128 except e:
122 fp.close() 129 fp.close()
123 return None 130 return None
124 fp.close() 131 fp.close()
125 if header.startswith("\xFE\xFF"): 132 if header.startswith("\xFE\xFF"):
126 return "UTF-16" 133 return "UTF-16"
127 elif header.startswith("\xFF\xFE"): 134 elif header.startswith("\xFF\xFE"):
128 return "UTF-16" 135 return "UTF-16"
129 elif header.startswith("\xEF\xBB\xBF"): 136 elif header.startswith("\xEF\xBB\xBF"):
130 return "UTF-8" 137 return "UTF-8"
131 else: 138 else:
132 return None 139 return None
133 140
134 def ExecCopyInfoPlist(self, source, dest, *keys): 141 def ExecCopyInfoPlist(self, source, dest, convert_to_binary, *keys):
135 """Copies the |source| Info.plist to the destination directory |dest|.""" 142 """Copies the |source| Info.plist to the destination directory |dest|."""
136 # Read the source Info.plist into memory. 143 # Read the source Info.plist into memory.
137 fd = open(source, 'r') 144 fd = open(source, 'r')
138 lines = fd.read() 145 lines = fd.read()
139 fd.close() 146 fd.close()
140 147
141 # Insert synthesized key/value pairs (e.g. BuildMachineOSBuild). 148 # Insert synthesized key/value pairs (e.g. BuildMachineOSBuild).
142 plist = plistlib.readPlistFromString(lines) 149 plist = plistlib.readPlistFromString(lines)
143 if keys: 150 if keys:
144 plist = dict(plist.items() + json.loads(keys[0]).items()) 151 plist = dict(plist.items() + json.loads(keys[0]).items())
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 185
179 # Write out the file with variables replaced. 186 # Write out the file with variables replaced.
180 fd = open(dest, 'w') 187 fd = open(dest, 'w')
181 fd.write(lines) 188 fd.write(lines)
182 fd.close() 189 fd.close()
183 190
184 # Now write out PkgInfo file now that the Info.plist file has been 191 # Now write out PkgInfo file now that the Info.plist file has been
185 # "compiled". 192 # "compiled".
186 self._WritePkgInfo(dest) 193 self._WritePkgInfo(dest)
187 194
195 if convert_to_binary == 'True':
196 self._ConvertToBinary(dest)
197
188 def _WritePkgInfo(self, info_plist): 198 def _WritePkgInfo(self, info_plist):
189 """This writes the PkgInfo file from the data stored in Info.plist.""" 199 """This writes the PkgInfo file from the data stored in Info.plist."""
190 plist = plistlib.readPlist(info_plist) 200 plist = plistlib.readPlist(info_plist)
191 if not plist: 201 if not plist:
192 return 202 return
193 203
194 # Only create PkgInfo for executable types. 204 # Only create PkgInfo for executable types.
195 package_type = plist['CFBundlePackageType'] 205 package_type = plist['CFBundlePackageType']
196 if package_type != 'APPL': 206 if package_type != 'APPL':
197 return 207 return
(...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after
591 data = data.replace('$(%s)' % key, value) 601 data = data.replace('$(%s)' % key, value)
592 return data 602 return data
593 if isinstance(data, list): 603 if isinstance(data, list):
594 return [self._ExpandVariables(v, substitutions) for v in data] 604 return [self._ExpandVariables(v, substitutions) for v in data]
595 if isinstance(data, dict): 605 if isinstance(data, dict):
596 return {k: self._ExpandVariables(data[k], substitutions) for k in data} 606 return {k: self._ExpandVariables(data[k], substitutions) for k in data}
597 return data 607 return data
598 608
599 if __name__ == '__main__': 609 if __name__ == '__main__':
600 sys.exit(main(sys.argv[1:])) 610 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « pylib/gyp/generator/ninja.py ('k') | pylib/gyp/xcode_emulation.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698