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.

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

mercurial