media/webrtc/trunk/build/mac/tweak_info_plist.py

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rwxr-xr-x

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 #!/usr/bin/env python
michael@0 2
michael@0 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
michael@0 4 # Use of this source code is governed by a BSD-style license that can be
michael@0 5 # found in the LICENSE file.
michael@0 6
michael@0 7 #
michael@0 8 # Xcode supports build variable substitutions and CPP; sadly, that doesn't work
michael@0 9 # because:
michael@0 10 #
michael@0 11 # 1. Xcode wants to do the Info.plist work before it runs any build phases,
michael@0 12 # this means if we were to generate a .h file for INFOPLIST_PREFIX_HEADER
michael@0 13 # we'd have to put it in another target so it runs in time.
michael@0 14 # 2. Xcode also doesn't check to see if the header being used as a prefix for
michael@0 15 # the Info.plist has changed. So even if we updated it, it's only looking
michael@0 16 # at the modtime of the info.plist to see if that's changed.
michael@0 17 #
michael@0 18 # So, we work around all of this by making a script build phase that will run
michael@0 19 # during the app build, and simply update the info.plist in place. This way
michael@0 20 # by the time the app target is done, the info.plist is correct.
michael@0 21 #
michael@0 22
michael@0 23 import optparse
michael@0 24 import os
michael@0 25 from os import environ as env
michael@0 26 import plistlib
michael@0 27 import re
michael@0 28 import subprocess
michael@0 29 import sys
michael@0 30 import tempfile
michael@0 31
michael@0 32 TOP = os.path.join(env['SRCROOT'], '..')
michael@0 33
michael@0 34 sys.path.insert(0, os.path.join(TOP, "build/util"))
michael@0 35 import lastchange
michael@0 36
michael@0 37
michael@0 38 def _GetOutput(args):
michael@0 39 """Runs a subprocess and waits for termination. Returns (stdout, returncode)
michael@0 40 of the process. stderr is attached to the parent."""
michael@0 41 proc = subprocess.Popen(args, stdout=subprocess.PIPE)
michael@0 42 (stdout, stderr) = proc.communicate()
michael@0 43 return (stdout, proc.returncode)
michael@0 44
michael@0 45
michael@0 46 def _GetOutputNoError(args):
michael@0 47 """Similar to _GetOutput() but ignores stderr. If there's an error launching
michael@0 48 the child (like file not found), the exception will be caught and (None, 1)
michael@0 49 will be returned to mimic quiet failure."""
michael@0 50 try:
michael@0 51 proc = subprocess.Popen(args, stdout=subprocess.PIPE,
michael@0 52 stderr=subprocess.PIPE)
michael@0 53 except OSError:
michael@0 54 return (None, 1)
michael@0 55 (stdout, stderr) = proc.communicate()
michael@0 56 return (stdout, proc.returncode)
michael@0 57
michael@0 58
michael@0 59 def _RemoveKeys(plist, *keys):
michael@0 60 """Removes a varargs of keys from the plist."""
michael@0 61 for key in keys:
michael@0 62 try:
michael@0 63 del plist[key]
michael@0 64 except KeyError:
michael@0 65 pass
michael@0 66
michael@0 67
michael@0 68 def _AddVersionKeys(plist):
michael@0 69 """Adds the product version number into the plist. Returns True on success and
michael@0 70 False on error. The error will be printed to stderr."""
michael@0 71 # Pull in the Chrome version number.
michael@0 72 VERSION_TOOL = os.path.join(TOP, 'chrome/tools/build/version.py')
michael@0 73 VERSION_FILE = os.path.join(TOP, 'chrome/VERSION')
michael@0 74
michael@0 75 (stdout, retval1) = _GetOutput([VERSION_TOOL, '-f', VERSION_FILE, '-t',
michael@0 76 '@MAJOR@.@MINOR@.@BUILD@.@PATCH@'])
michael@0 77 full_version = stdout.rstrip()
michael@0 78
michael@0 79 (stdout, retval2) = _GetOutput([VERSION_TOOL, '-f', VERSION_FILE, '-t',
michael@0 80 '@BUILD@.@PATCH@'])
michael@0 81 bundle_version = stdout.rstrip()
michael@0 82
michael@0 83 # If either of the two version commands finished with non-zero returncode,
michael@0 84 # report the error up.
michael@0 85 if retval1 or retval2:
michael@0 86 return False
michael@0 87
michael@0 88 # Add public version info so "Get Info" works.
michael@0 89 plist['CFBundleShortVersionString'] = full_version
michael@0 90
michael@0 91 # Honor the 429496.72.95 limit. The maximum comes from splitting 2^32 - 1
michael@0 92 # into 6, 2, 2 digits. The limitation was present in Tiger, but it could
michael@0 93 # have been fixed in later OS release, but hasn't been tested (it's easy
michael@0 94 # enough to find out with "lsregister -dump).
michael@0 95 # http://lists.apple.com/archives/carbon-dev/2006/Jun/msg00139.html
michael@0 96 # BUILD will always be an increasing value, so BUILD_PATH gives us something
michael@0 97 # unique that meetings what LS wants.
michael@0 98 plist['CFBundleVersion'] = bundle_version
michael@0 99
michael@0 100 # Return with no error.
michael@0 101 return True
michael@0 102
michael@0 103
michael@0 104 def _DoSCMKeys(plist, add_keys):
michael@0 105 """Adds the SCM information, visible in about:version, to property list. If
michael@0 106 |add_keys| is True, it will insert the keys, otherwise it will remove them."""
michael@0 107 scm_path, scm_revision = None, None
michael@0 108 if add_keys:
michael@0 109 version_info = lastchange.FetchVersionInfo(
michael@0 110 default_lastchange=None, directory=TOP)
michael@0 111 scm_path, scm_revision = version_info.url, version_info.revision
michael@0 112
michael@0 113 # See if the operation failed.
michael@0 114 _RemoveKeys(plist, 'SCMRevision')
michael@0 115 if scm_revision != None:
michael@0 116 plist['SCMRevision'] = scm_revision
michael@0 117 elif add_keys:
michael@0 118 print >>sys.stderr, 'Could not determine SCM revision. This may be OK.'
michael@0 119
michael@0 120 if scm_path != None:
michael@0 121 plist['SCMPath'] = scm_path
michael@0 122 else:
michael@0 123 _RemoveKeys(plist, 'SCMPath')
michael@0 124
michael@0 125
michael@0 126 def _DoPDFKeys(plist, add_keys):
michael@0 127 """Adds PDF support to the document types list. If add_keys is True, it will
michael@0 128 add the type information dictionary. If it is False, it will remove it if
michael@0 129 present."""
michael@0 130
michael@0 131 PDF_FILE_EXTENSION = 'pdf'
michael@0 132
michael@0 133 def __AddPDFKeys(sub_plist):
michael@0 134 """Writes the keys into a sub-dictionary of the plist."""
michael@0 135 sub_plist['CFBundleTypeExtensions'] = [PDF_FILE_EXTENSION]
michael@0 136 sub_plist['CFBundleTypeIconFile'] = 'document.icns'
michael@0 137 sub_plist['CFBundleTypeMIMETypes'] = 'application/pdf'
michael@0 138 sub_plist['CFBundleTypeName'] = 'PDF Document'
michael@0 139 sub_plist['CFBundleTypeRole'] = 'Viewer'
michael@0 140
michael@0 141 DOCUMENT_TYPES_KEY = 'CFBundleDocumentTypes'
michael@0 142
michael@0 143 # First get the list of document types, creating it if necessary.
michael@0 144 try:
michael@0 145 extensions = plist[DOCUMENT_TYPES_KEY]
michael@0 146 except KeyError:
michael@0 147 # If this plist doesn't have a type dictionary, create one if set to add the
michael@0 148 # keys. If not, bail.
michael@0 149 if not add_keys:
michael@0 150 return
michael@0 151 extensions = plist[DOCUMENT_TYPES_KEY] = []
michael@0 152
michael@0 153 # Loop over each entry in the list, looking for one that handles PDF types.
michael@0 154 for i, ext in enumerate(extensions):
michael@0 155 # If an entry for .pdf files is found...
michael@0 156 if 'CFBundleTypeExtensions' not in ext:
michael@0 157 continue
michael@0 158 if PDF_FILE_EXTENSION in ext['CFBundleTypeExtensions']:
michael@0 159 if add_keys:
michael@0 160 # Overwrite the existing keys with new ones.
michael@0 161 __AddPDFKeys(ext)
michael@0 162 else:
michael@0 163 # Otherwise, delete the entry entirely.
michael@0 164 del extensions[i]
michael@0 165 return
michael@0 166
michael@0 167 # No PDF entry exists. If one needs to be added, do so now.
michael@0 168 if add_keys:
michael@0 169 pdf_entry = {}
michael@0 170 __AddPDFKeys(pdf_entry)
michael@0 171 extensions.append(pdf_entry)
michael@0 172
michael@0 173
michael@0 174 def _AddBreakpadKeys(plist, branding):
michael@0 175 """Adds the Breakpad keys. This must be called AFTER _AddVersionKeys() and
michael@0 176 also requires the |branding| argument."""
michael@0 177 plist['BreakpadReportInterval'] = '3600' # Deliberately a string.
michael@0 178 plist['BreakpadProduct'] = '%s_Mac' % branding
michael@0 179 plist['BreakpadProductDisplay'] = branding
michael@0 180 plist['BreakpadVersion'] = plist['CFBundleShortVersionString']
michael@0 181 # These are both deliberately strings and not boolean.
michael@0 182 plist['BreakpadSendAndExit'] = 'YES'
michael@0 183 plist['BreakpadSkipConfirm'] = 'YES'
michael@0 184
michael@0 185
michael@0 186 def _RemoveBreakpadKeys(plist):
michael@0 187 """Removes any set Breakpad keys."""
michael@0 188 _RemoveKeys(plist,
michael@0 189 'BreakpadURL',
michael@0 190 'BreakpadReportInterval',
michael@0 191 'BreakpadProduct',
michael@0 192 'BreakpadProductDisplay',
michael@0 193 'BreakpadVersion',
michael@0 194 'BreakpadSendAndExit',
michael@0 195 'BreakpadSkipConfirm')
michael@0 196
michael@0 197
michael@0 198 def _AddKeystoneKeys(plist, bundle_identifier):
michael@0 199 """Adds the Keystone keys. This must be called AFTER _AddVersionKeys() and
michael@0 200 also requires the |bundle_identifier| argument (com.example.product)."""
michael@0 201 plist['KSVersion'] = plist['CFBundleShortVersionString']
michael@0 202 plist['KSProductID'] = bundle_identifier
michael@0 203 plist['KSUpdateURL'] = 'https://tools.google.com/service/update2'
michael@0 204
michael@0 205
michael@0 206 def _RemoveKeystoneKeys(plist):
michael@0 207 """Removes any set Keystone keys."""
michael@0 208 _RemoveKeys(plist,
michael@0 209 'KSVersion',
michael@0 210 'KSProductID',
michael@0 211 'KSUpdateURL')
michael@0 212
michael@0 213
michael@0 214 def Main(argv):
michael@0 215 parser = optparse.OptionParser('%prog [options]')
michael@0 216 parser.add_option('--breakpad', dest='use_breakpad', action='store',
michael@0 217 type='int', default=False, help='Enable Breakpad [1 or 0]')
michael@0 218 parser.add_option('--breakpad_uploads', dest='breakpad_uploads',
michael@0 219 action='store', type='int', default=False,
michael@0 220 help='Enable Breakpad\'s uploading of crash dumps [1 or 0]')
michael@0 221 parser.add_option('--keystone', dest='use_keystone', action='store',
michael@0 222 type='int', default=False, help='Enable Keystone [1 or 0]')
michael@0 223 parser.add_option('--scm', dest='add_scm_info', action='store', type='int',
michael@0 224 default=True, help='Add SCM metadata [1 or 0]')
michael@0 225 parser.add_option('--pdf', dest='add_pdf_support', action='store', type='int',
michael@0 226 default=False, help='Add PDF file handler support [1 or 0]')
michael@0 227 parser.add_option('--branding', dest='branding', action='store',
michael@0 228 type='string', default=None, help='The branding of the binary')
michael@0 229 parser.add_option('--bundle_id', dest='bundle_identifier',
michael@0 230 action='store', type='string', default=None,
michael@0 231 help='The bundle id of the binary')
michael@0 232 (options, args) = parser.parse_args(argv)
michael@0 233
michael@0 234 if len(args) > 0:
michael@0 235 print >>sys.stderr, parser.get_usage()
michael@0 236 return 1
michael@0 237
michael@0 238 # Read the plist into its parsed format.
michael@0 239 DEST_INFO_PLIST = os.path.join(env['TARGET_BUILD_DIR'], env['INFOPLIST_PATH'])
michael@0 240 plist = plistlib.readPlist(DEST_INFO_PLIST)
michael@0 241
michael@0 242 # Insert the product version.
michael@0 243 if not _AddVersionKeys(plist):
michael@0 244 return 2
michael@0 245
michael@0 246 # Add Breakpad if configured to do so.
michael@0 247 if options.use_breakpad:
michael@0 248 if options.branding is None:
michael@0 249 print >>sys.stderr, 'Use of Breakpad requires branding.'
michael@0 250 return 1
michael@0 251 _AddBreakpadKeys(plist, options.branding)
michael@0 252 if options.breakpad_uploads:
michael@0 253 plist['BreakpadURL'] = 'https://clients2.google.com/cr/report'
michael@0 254 else:
michael@0 255 # This allows crash dumping to a file without uploading the
michael@0 256 # dump, for testing purposes. Breakpad does not recognise
michael@0 257 # "none" as a special value, but this does stop crash dump
michael@0 258 # uploading from happening. We need to specify something
michael@0 259 # because if "BreakpadURL" is not present, Breakpad will not
michael@0 260 # register its crash handler and no crash dumping will occur.
michael@0 261 plist['BreakpadURL'] = 'none'
michael@0 262 else:
michael@0 263 _RemoveBreakpadKeys(plist)
michael@0 264
michael@0 265 # Only add Keystone in Release builds.
michael@0 266 if options.use_keystone and env['CONFIGURATION'] == 'Release':
michael@0 267 if options.bundle_identifier is None:
michael@0 268 print >>sys.stderr, 'Use of Keystone requires the bundle id.'
michael@0 269 return 1
michael@0 270 _AddKeystoneKeys(plist, options.bundle_identifier)
michael@0 271 else:
michael@0 272 _RemoveKeystoneKeys(plist)
michael@0 273
michael@0 274 # Adds or removes any SCM keys.
michael@0 275 _DoSCMKeys(plist, options.add_scm_info)
michael@0 276
michael@0 277 # Adds or removes the PDF file handler entry.
michael@0 278 _DoPDFKeys(plist, options.add_pdf_support)
michael@0 279
michael@0 280 # Now that all keys have been mutated, rewrite the file.
michael@0 281 temp_info_plist = tempfile.NamedTemporaryFile()
michael@0 282 plistlib.writePlist(plist, temp_info_plist.name)
michael@0 283
michael@0 284 # Info.plist will work perfectly well in any plist format, but traditionally
michael@0 285 # applications use xml1 for this, so convert it to ensure that it's valid.
michael@0 286 proc = subprocess.Popen(['plutil', '-convert', 'xml1', '-o', DEST_INFO_PLIST,
michael@0 287 temp_info_plist.name])
michael@0 288 proc.wait()
michael@0 289 return proc.returncode
michael@0 290
michael@0 291
michael@0 292 if __name__ == '__main__':
michael@0 293 sys.exit(Main(sys.argv[1:]))

mercurial