diff options
author | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-18 14:33:06 +0000 |
---|---|---|
committer | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-18 14:33:06 +0000 |
commit | 8d3a1274d60801b4bc11e49c0ab9c54141ed1d25 (patch) | |
tree | 4572448e28370f7c5c5d597f275448ef02572905 /chrome/tools | |
parent | 929c142e8540ad767ed07ae3f3c02e08aa606bf8 (diff) | |
download | chromium_src-8d3a1274d60801b4bc11e49c0ab9c54141ed1d25.zip chromium_src-8d3a1274d60801b4bc11e49c0ab9c54141ed1d25.tar.gz chromium_src-8d3a1274d60801b4bc11e49c0ab9c54141ed1d25.tar.bz2 |
[Mac] Rewrite tweak_info_plist as a Python script instead of bash.
The output is identical to that of the bash script; no other changes are included
in this CL.
BUG=80558
TEST=Build a branded Chrome and everything is as it should be.
Review URL: http://codereview.chromium.org/7029018
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85761 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/tools')
-rwxr-xr-x | chrome/tools/build/mac/tweak_info_plist | 407 |
1 files changed, 237 insertions, 170 deletions
diff --git a/chrome/tools/build/mac/tweak_info_plist b/chrome/tools/build/mac/tweak_info_plist index 4abca09..eeec906 100755 --- a/chrome/tools/build/mac/tweak_info_plist +++ b/chrome/tools/build/mac/tweak_info_plist @@ -1,49 +1,9 @@ -#!/bin/bash +#!/usr/bin/python2.6 -# Copyright (c) 2009 The Chromium Authors. All rights reserved. +# Copyright (c) 2011 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. -set -e - -# Pull off the optional args -USE_BREAKPAD=0 -USE_KEYSTONE=0 -USE_SVN=1 -OPTERR=0 -while getopts ":b:k:s:" an_opt ; do - case $an_opt in - b) - USE_BREAKPAD=$OPTARG - ;; - k) - USE_KEYSTONE=$OPTARG - ;; - s) - USE_SVN=$OPTARG - ;; - \?) - echo "Unknown option $OPTARG" - exit 1 - ;; - :) - echo "Option $OPTARG missing it's value" - exit 1 - ;; - *) - echo "Not recognized argument $an_opt" - exit 1 - ;; - esac -done -shift $(($OPTIND - 1)) - -# Make sure the branding argument was supplied. -if [ $# -ne 2 ]; then - echo "usage: $0 [-b 1] [-k 1] [-s 1] BRANDING IDENTIFIER" >&2 - exit 1 -fi - # # Xcode supports build variable substitutions and CPP; sadly, that doesn't work # because: @@ -60,131 +20,238 @@ fi # by the time the app target is done, the info.plist is correct. # -TOP="${SRCROOT}/.." -BUILD_BRANDING=$1 -IDENTIFIER=$2 - -if [ "${USE_SVN}" = "1" ] ; then - # Visible in the about:version page. - SVN_INFO=$(svn info "${TOP}" 2>/dev/null || true) - SVN_REVISION=$(echo "${SVN_INFO}" | sed -Ene 's/^Revision: (.*)$/\1/p') - if [ -z "${SVN_REVISION}" ] ; then - GIT_INFO=$(git log -1 --grep=git-svn-id --format=%b 2>/dev/null || true) - SVN_REVISION=$(echo "${GIT_INFO}" | \ - sed -Ene 's/^git-svn-id: .*@([0-9]+).*$/\1/p') - # Finding the revision for git and svn has failed. - if [ -z "${SVN_REVISION}" ] ; then - echo "Could not determine svn revision. This may be OK." >&2 - else - SVN_PATH=$(echo "${GIT_INFO}" | \ - sed -Ene 's%^git-svn-id: .*/chrome/(.*)@.*$%/\1%p') - fi - else - # Grab the path to the source root in the Subversion repository by taking - # the URL to the source root directory and the repository root, and - # removing the latter from the former. This ensures that SVN_PATH will - # contain a useful path regardless of the Subversion server, mirror, and - # authentication scheme in use. - SVN_URL=$(echo "${SVN_INFO}" | sed -Ene 's/^URL: (.*)$/\1/p') - SVN_ROOT=$(echo "${SVN_INFO}" | sed -Ene 's/^Repository Root: (.*)$/\1/p') - if [ -n "${SVN_ROOT}" ] && \ - [ "${SVN_URL:0:${#SVN_ROOT}}" = "${SVN_ROOT}" ] ; then - SVN_PATH="${SVN_URL:${#SVN_ROOT}}" - fi - fi -fi - -# Pull in the Chrome version number. -VERSION_TOOL="${TOP}/chrome/tools/build/version.py" -VERSION_FILE="${TOP}/chrome/VERSION" -FULL_VERSION=$("${VERSION_TOOL}" -f "${VERSION_FILE}" \ - -t "@MAJOR@.@MINOR@.@BUILD@.@PATCH@") -BUNDLE_VERSION=$("${VERSION_TOOL}" -f "${VERSION_FILE}" -t "@BUILD@.@PATCH@") - -# I really hate how "defaults" doesn't take a real pathname but instead insists -# on appending ".plist" to everything. -TMP_INFO_PLIST_DEFAULTS="${TEMP_DIR}/Info" -TMP_INFO_PLIST="${TMP_INFO_PLIST_DEFAULTS}.plist" -cp "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}" "${TMP_INFO_PLIST}" - -# Save off the Subversion revision number and source root path in case they're -# needed. -if [ ! -z "${SVN_REVISION}" ] ; then - defaults write "${TMP_INFO_PLIST_DEFAULTS}" \ - SVNRevision -string "${SVN_REVISION}" -else - defaults delete "${TMP_INFO_PLIST_DEFAULTS}" SVNRevision 2> /dev/null || true -fi -if [ ! -z "${SVN_PATH}" ] ; then - defaults write "${TMP_INFO_PLIST_DEFAULTS}" SVNPath -string "${SVN_PATH}" -else - defaults delete "${TMP_INFO_PLIST_DEFAULTS}" SVNPath 2> /dev/null || true -fi - -# Add public version info so "Get Info" works -defaults write "${TMP_INFO_PLIST_DEFAULTS}" \ - CFBundleShortVersionString -string "${FULL_VERSION}" -# Honor the 429496.72.95 limit. The maximum comes from splitting 2^32 - 1 into -# 6, 2, 2 digits. The limitation was present in Tiger, but it could have been -# fixed in later OS release, but hasn't been tested (it's easy enough to find -# out with "lsregister -dump). -# http://lists.apple.com/archives/carbon-dev/2006/Jun/msg00139.html -# BUILD will always be an increasing value, so BUILD_PATH gives us something -# unique that meetings what LS wants. -defaults write "${TMP_INFO_PLIST_DEFAULTS}" \ - CFBundleVersion -string "${BUNDLE_VERSION}" - -# Add or remove the Breakpad keys. -if [ "${USE_BREAKPAD}" = "1" ] ; then - defaults write "${TMP_INFO_PLIST_DEFAULTS}" \ - BreakpadURL "https://clients2.google.com/cr/report" - defaults write "${TMP_INFO_PLIST_DEFAULTS}" BreakpadReportInterval "3600" - defaults write "${TMP_INFO_PLIST_DEFAULTS}" \ - BreakpadProduct "${BUILD_BRANDING}_Mac" - defaults write "${TMP_INFO_PLIST_DEFAULTS}" \ - BreakpadProductDisplay "${BUILD_BRANDING}" - defaults write "${TMP_INFO_PLIST_DEFAULTS}" \ - BreakpadVersion -string "${FULL_VERSION}" - defaults write "${TMP_INFO_PLIST_DEFAULTS}" BreakpadSendAndExit "YES" - defaults write "${TMP_INFO_PLIST_DEFAULTS}" BreakpadSkipConfirm "YES" -else - # Make sure the keys aren't there, || true to avoid errors if they aren't. - defaults delete "${TMP_INFO_PLIST_DEFAULTS}" BreakpadURL \ - 2> /dev/null || true - defaults delete "${TMP_INFO_PLIST_DEFAULTS}" BreakpadReportInterval \ - 2> /dev/null || true - defaults delete "${TMP_INFO_PLIST_DEFAULTS}" BreakpadProduct \ - 2> /dev/null || true - defaults delete "${TMP_INFO_PLIST_DEFAULTS}" BreakpadProductDisplay \ - 2> /dev/null || true - defaults delete "${TMP_INFO_PLIST_DEFAULTS}" BreakpadVersion \ - 2> /dev/null || true - defaults delete "${TMP_INFO_PLIST_DEFAULTS}" BreakpadSendAndExit \ - 2> /dev/null || true - defaults delete "${TMP_INFO_PLIST_DEFAULTS}" BreakpadSkipConfirm \ - 2> /dev/null || true -fi - -# Add or remove the Keystone keys (only supported in release builds). -if [ "${USE_KEYSTONE}" = "1" ] && [ "${CONFIGURATION}" = "Release" ] ; then - KEYSTONE_URL="https://tools.google.com/service/update2" - KEYSTONE_APP_ID="${IDENTIFIER}" - defaults write "${TMP_INFO_PLIST_DEFAULTS}" \ - KSVersion -string "${FULL_VERSION}" - defaults write "${TMP_INFO_PLIST_DEFAULTS}" KSProductID "${KEYSTONE_APP_ID}" - defaults write "${TMP_INFO_PLIST_DEFAULTS}" KSUpdateURL "${KEYSTONE_URL}" -else - # Make sure the keys aren't there, || true to avoid errors if they aren't. - defaults delete "${TMP_INFO_PLIST_DEFAULTS}" KSVersion 2> /dev/null || true - defaults delete "${TMP_INFO_PLIST_DEFAULTS}" KSProductID 2> /dev/null || true - defaults delete "${TMP_INFO_PLIST_DEFAULTS}" KSUpdateURL 2> /dev/null || true -fi - -# Info.plist will work perfectly well in any plist format, but traditionally -# applications use xml1 for this, so convert it back after whatever defaults -# might have done. -plutil -convert xml1 "${TMP_INFO_PLIST}" -cp "${TMP_INFO_PLIST}" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}" - -# Clean up. -rm -f "${TMP_INFO_PLIST}" +import optparse +import os +from os import environ as env +import plistlib +import re +import subprocess +import sys +import tempfile + +TOP = os.path.join(env['SRCROOT'], '..') + + +def _GetOutput(args): + """Runs a subprocess and waits for termination. Returns (stdout, returncode) + of the process. stderr is attached to the parent.""" + proc = subprocess.Popen(args, stdout=subprocess.PIPE) + (stdout, stderr) = proc.communicate() + return (stdout, proc.returncode) + + +def _GetOutputNoError(args): + """Behaves identically to _GetOutput() but ignores stderr.""" + proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdout, stderr) = proc.communicate() + return (stdout, proc.returncode) + + +def _RemoveKeys(plist, *keys): + """Removes a varargs of keys from the plist.""" + for key in keys: + try: + del plist[key] + except KeyError: + pass + + +def _AddVersionKeys(plist): + """Adds the product version number into the plist. Returns True on success and + False on error. The error will be printed to stderr.""" + # Pull in the Chrome version number. + VERSION_TOOL = os.path.join(TOP, 'chrome/tools/build/version.py') + VERSION_FILE = os.path.join(TOP, 'chrome/VERSION') + + (stdout, retval1) = _GetOutput([VERSION_TOOL, '-f', VERSION_FILE, '-t', + '@MAJOR@.@MINOR@.@BUILD@.@PATCH@']) + full_version = stdout.rstrip() + + (stdout, retval2) = _GetOutput([VERSION_TOOL, '-f', VERSION_FILE, '-t', + '@BUILD@.@PATCH@']) + bundle_version = stdout.rstrip() + + # If either of the two version commands finished with non-zero returncode, + # report the error up. + if retval1 or retval2: + return False + + # Add public version info so "Get Info" works. + plist['CFBundleShortVersionString'] = full_version + + # Honor the 429496.72.95 limit. The maximum comes from splitting 2^32 - 1 + # into 6, 2, 2 digits. The limitation was present in Tiger, but it could + # have been fixed in later OS release, but hasn't been tested (it's easy + # enough to find out with "lsregister -dump). + # http://lists.apple.com/archives/carbon-dev/2006/Jun/msg00139.html + # BUILD will always be an increasing value, so BUILD_PATH gives us something + # unique that meetings what LS wants. + plist['CFBundleVersion'] = bundle_version + + # Return with no error. + return True + + +def _GetSCMInfo(): + """Returns a 2-Tuple of (scm_path, scm_revision) for the SVN information.""" + # Attempt to get both the SVN revision number and the branch (or trunk). + scm_revision = None + scm_path = None + + # First attempt to get the SVN revision number and path. + (stdout, retval) = _GetOutputNoError(['svn', 'info', TOP]) + if not retval: + match = re.search('^Revision: ([0-9]+)$', stdout, re.MULTILINE) + if match: + scm_revision = match.group(1) + + match = re.search('^Repository Root: (.+)$', stdout, re.MULTILINE) + if match: + svn_repo_root = match.group(1) + + match = re.search('^URL: (.+)$', stdout, re.MULTILINE) + if match: + svn_url = match.group(1) + + # If there's both a repo root and a URL, find the branch path. + if svn_repo_root and svn_url and svn_url.startswith(svn_repo_root): + # Grab the path to the source root in the Subversion repository by taking + # the URL to the source root directory and the repository root, and + # removing the latter from the former. This ensures that scm_path will + # contain a useful path regardless of the Subversion server, mirror, and + # authentication scheme in use. + scm_path = svn_url[len(svn_repo_root):] + + # If a SVN revision number couldn't be found, try getting it through git. + (stdout, retval) = _GetOutputNoError(['git', 'log', '-1', + '--grep=git-svn-id', '--format=%b']) + # Extract both the last changed SVN revision and the branch path (see block + # comment above). + # git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85528 0039d316-1c4b... + if not retval: + match = re.search(r'git-svn-id: .*/(chrome|svn)(/.*)@([0-9]+)', stdout, + re.MULTILINE) + if match: + scm_path = match.group(2) + scm_revision = match.group(3) + + # Finally, return the results (which could be None on error). + return (scm_path, scm_revision) + + +def _DoSVNKeys(plist, add_keys): + """Adds the SVN information, visible in about:version, to property list. If + |add_keys| is True, it will insert the keys, otherwise it will remove them.""" + (scm_path, scm_revision) = None, None + if add_keys: + (scm_path, scm_revision) = _GetSCMInfo() + + # See if the operation failed. + _RemoveKeys(plist, 'SVNRevision') + if scm_revision != None: + plist['SVNRevision'] = scm_revision + elif add_keys: + print >>sys.stderr, 'Could not determine svn revision. This may be OK.' + + if scm_path != None: + plist['SVNPath'] = scm_path + else: + _RemoveKeys(plist, 'SVNPath') + + +def _AddBreakpadKeys(plist, branding): + """Adds the Breakpad keys. This must be called AFTER _AddVersionKeys() and + also requires the |branding| argument.""" + plist['BreakpadURL'] = 'https://clients2.google.com/cr/report' + plist['BreakpadReportInterval'] = '3600' # Deliberately a string. + plist['BreakpadProduct'] = '%s_Mac' % branding + plist['BreakpadProductDisplay'] = branding + plist['BreakpadVersion'] = plist['CFBundleShortVersionString'] + # These are both deliberately strings and not boolean. + plist['BreakpadSendAndExit'] = 'YES' + plist['BreakpadSkipConfirm'] = 'YES' + + +def _RemoveBreakpadKeys(plist): + """Removes any set Breakpad keys.""" + _RemoveKeys(plist, + 'BreakpadURL', + 'BreakpadReportInterval', + 'BreakpadProduct', + 'BreakpadProductDisplay', + 'BreakpadVersion', + 'BreakpadSendAndExit', + 'BreakpadSkipConfirm') + + +def _AddKeystoneKeys(plist, bundle_identifier): + """Adds the Keystone keys. This must be called AFTER _AddVersionKeys() and + also requires the |bundle_identifier| argument (com.example.product).""" + plist['KSVersion'] = plist['CFBundleShortVersionString'] + plist['KSProductID'] = bundle_identifier + plist['KSUpdateURL'] = 'https://tools.google.com/service/update2' + + +def _RemoveKeystoneKeys(plist): + """Removes any set Keystone keys.""" + _RemoveKeys(plist, + 'KSVersion', + 'KSProductID', + 'KSUpdateURL') + + +def Main(argv): + parser = optparse.OptionParser('%prog [options] branding bundle-id') + parser.add_option('-b', dest='use_breakpad', action='store', type='int', + default=False, help='Enable Breakpad [1 or 0]') + parser.add_option('-k', dest='use_keystone', action='store', type='int', + default=False, help='Enable Keystone [1 or 0]') + parser.add_option('-s', dest='add_svn_info', action='store', type='int', + default=True, help='Add SVN metadata [1 or 0]') + (options, args) = parser.parse_args(argv) + + if len(args) < 2: + print >>sys.stderr, parser.get_usage() + return 1 + + # Extract remaining arguments. + branding = args[0] + bundle_identifier = args[1] + + # Read the plist into its parsed format. + DEST_INFO_PLIST = os.path.join(env['TARGET_BUILD_DIR'], env['INFOPLIST_PATH']) + plist = plistlib.readPlist(DEST_INFO_PLIST) + + # Insert the product version. + if not _AddVersionKeys(plist): + return 2 + + # Add Breakpad if configured to do so. + if options.use_breakpad: + _AddBreakpadKeys(plist, branding) + else: + _RemoveBreakpadKeys(plist) + + # Only add Keystone in Release builds. + if options.use_keystone and env['CONFIGURATION'] == 'Release': + _AddKeystoneKeys(plist, bundle_identifier) + else: + _RemoveKeystoneKeys(plist) + + # Adds or removes any SVN keys. + _DoSVNKeys(plist, options.add_svn_info) + + # Now that all keys have been mutated, rewrite the file. + temp_info_plist = tempfile.NamedTemporaryFile() + plistlib.writePlist(plist, temp_info_plist.name) + + # Info.plist will work perfectly well in any plist format, but traditionally + # applications use xml1 for this, so convert it to ensure that it's valid. + proc = subprocess.Popen(['plutil', '-convert', 'xml1', '-o', DEST_INFO_PLIST, + temp_info_plist.name]) + proc.wait() + return proc.returncode + + +if __name__ == '__main__': + sys.exit(Main(sys.argv[1:])) |