| Index: chrome_mac/Google Chrome Packaging/generate_dmgs
|
| ===================================================================
|
| --- chrome_mac/Google Chrome Packaging/generate_dmgs (revision 0)
|
| +++ chrome_mac/Google Chrome Packaging/generate_dmgs (revision 0)
|
| @@ -0,0 +1,674 @@
|
| +#!/bin/bash -p
|
| +
|
| +# Copyright (c) 2012 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.
|
| +
|
| +# This is expected to be invoked by the Pulse build step. It takes care of
|
| +# doing the code signing and building the needed disk images. All needed
|
| +# support files are assumed to live next to this script on disk.
|
| +#
|
| +# usage: generate_dmgs output_dir input_dir codesign_keychain codesign_id \
|
| +# omahaproxy_url [live_dmg_dir]
|
| +#
|
| +# Disk images are placed in output_dir. input_dir is the directory containing
|
| +# unzipped packaging data. omahaproxy_url will be consulted to determine the
|
| +# current live versions and URLs where they can be downloaded. live_dmg_dir
|
| +# is no longer used but is accepted on the command line to allow the script
|
| +# that calls this one to continue passing that argument to older versions of
|
| +# this script.
|
| +
|
| +set -eu
|
| +
|
| +# Environment sanitization. Set a known-safe PATH. Clear environment variables
|
| +# that might impact the interpreter's operation. The |bash -p| invocation
|
| +# on the #! line takes the bite out of BASH_ENV, ENV, and SHELLOPTS (among
|
| +# other features), but clearing them here ensures that they won't impact any
|
| +# shell scripts used as utility programs. SHELLOPTS is read-only and can't be
|
| +# unset, only unexported.
|
| +export PATH="/usr/bin:/bin:/usr/sbin:/sbin"
|
| +unset BASH_ENV CDPATH ENV GLOBIGNORE IFS POSIXLY_CORRECT
|
| +export -n SHELLOPTS
|
| +
|
| +ME="$(basename "${0}")"
|
| +readonly ME
|
| +PACKAGING_DIR="$(dirname "${0}")"
|
| +readonly PACKAGING_DIR
|
| +
|
| +readonly PRODUCT_NAME="Google Chrome"
|
| +readonly APP_NAME="${PRODUCT_NAME}.app"
|
| +DMG_PRODUCT_NAME="$(sed -e "s/ //" <<< "${PRODUCT_NAME}")"
|
| +readonly DMG_PRODUCT_NAME
|
| +
|
| +readonly APP_ID_KEY="CFBundleIdentifier"
|
| +readonly APP_VERSION_KEY="CFBundleShortVersionString"
|
| +readonly KS_VERSION_KEY="KSVersion"
|
| +readonly KS_CHANNEL_KEY="KSChannelID"
|
| +readonly KS_BRAND_KEY="KSBrandID"
|
| +readonly KS_ID_KEY="KSProductID"
|
| +readonly BP_VERSION_KEY="BreakpadVersion"
|
| +
|
| +readonly RSYNC_FLAGS=("-Clprt" "--include" "*.so" "--copy-unsafe-links")
|
| +readonly CURL_FLAGS=("--fail" "--location" "--silent" "--show-error")
|
| +
|
| +readonly OMAHAPROXY_PLATFORM="mac"
|
| +readonly MIN_DIFF_VERSION="6.0.434.0"
|
| +
|
| +# CH, BR, and NF are parallel arrays. An element at the same index in any of
|
| +# these arrays corresponds to the element at the same index in the others.
|
| +# CH is used for Keystone channel codes; BR is used for Keystone brand codes;
|
| +# NF is used for name fragments appended to the disk image name.
|
| +declare -a CH BR NF
|
| +
|
| +# Stable channel, generic, with no brand code.
|
| +CH+=(""); BR+=(""); NF+=("")
|
| +
|
| +# Stable channel with brand codes.
|
| +# Pure organic installs.
|
| +CH+=(""); BR+=("GGRO"); NF+=("Stable-PureOrganic")
|
| +
|
| +# google.xx marketing channels (house ads, toast promo, etc.)
|
| +CH+=(""); BR+=("GGRM"); NF+=("Stable-GoogleMarketing")
|
| +
|
| +# Off-network marketing installs (not originating from google.xx marketing.)
|
| +CH+=(""); BR+=("CHFA"); NF+=("Stable-OffNetworkMarketing")
|
| +
|
| +# Distribution deals.
|
| +CH+=(""); BR+=("MACD"); NF+=("Stable-DistributionDeals")
|
| +
|
| +# Beta, Dev, and Canary channels, no brand codes.
|
| +CH+=("beta"); BR+=(""); NF+=("Beta")
|
| +CH+=("dev"); BR+=(""); NF+=("Dev")
|
| +CH+=("canary"); BR+=(""); NF+=("Canary")
|
| +
|
| +readonly CH BR NF
|
| +
|
| +g_temp_dir=
|
| +
|
| +err() {
|
| + local error="${1}"
|
| +
|
| + echo "${ME}: ${error}" >& 2
|
| +}
|
| +
|
| +declare -a g_cleanup
|
| +cleanup() {
|
| + local status=${?}
|
| +
|
| + trap - EXIT
|
| + trap '' HUP INT QUIT TERM
|
| +
|
| + if [[ ${status} -ge 128 ]]; then
|
| + err "Caught signal $((${status} - 128))"
|
| + fi
|
| +
|
| + if [[ "${#g_cleanup[@]}" -gt 0 ]]; then
|
| + rm -rf "${g_cleanup[@]}"
|
| + fi
|
| +
|
| + exit ${status}
|
| +}
|
| +
|
| +# Returns 0 if ${version1} and ${version2} are equal. Returns 1 if ${version1}
|
| +# is less than ${version2}. Returns 2 if ${version1} is greater than
|
| +# ${version2}. Returns 3 if ${version1} or ${version2} don't meet the expected
|
| +# format. A piece-wise comparison is performed.
|
| +readonly VERSION_RE="^([0-9]+)\\.([0-9]+)\\.([0-9]+)\\.([0-9]+)\$"
|
| +version_compare() {
|
| + local version1="${1}"
|
| + local version2="${2}"
|
| +
|
| + if ! [[ "${version1}" =~ ${VERSION_RE} ]]; then
|
| + return 3
|
| + fi
|
| +
|
| + local version1_components=("${BASH_REMATCH[1]}"
|
| + "${BASH_REMATCH[2]}"
|
| + "${BASH_REMATCH[3]}"
|
| + "${BASH_REMATCH[4]}")
|
| +
|
| + if ! [[ "${version2}" =~ ${VERSION_RE} ]]; then
|
| + return 3
|
| + fi
|
| +
|
| + local version2_components=("${BASH_REMATCH[1]}"
|
| + "${BASH_REMATCH[2]}"
|
| + "${BASH_REMATCH[3]}"
|
| + "${BASH_REMATCH[4]}")
|
| +
|
| + local i
|
| + for i in "${!version1_components[@]}"; do
|
| + local version1_component="${version1_components[${i}]}"
|
| + local version2_component="${version2_components[${i}]}"
|
| +
|
| + if [[ ${version1_component} -lt ${version2_component} ]]; then
|
| + # version1 is less than version2.
|
| + return 1
|
| + fi
|
| + if [[ ${version1_component} -gt ${version2_component} ]]; then
|
| + # version1 is greater than version2.
|
| + return 2
|
| + fi
|
| + done
|
| +
|
| + # The version numbers are equal.
|
| + return 0
|
| +}
|
| +
|
| +is_version_gt() {
|
| + local version1="${1}"
|
| + local version2="${2}"
|
| +
|
| + if version_compare "${version1}" "${version2}"; then
|
| + # They're equal.
|
| + return 1
|
| + elif [[ ${?} -eq 2 ]]; then
|
| + return 0
|
| + fi
|
| +
|
| + return 1
|
| +}
|
| +
|
| +is_version_ge() {
|
| + local version1="${1}"
|
| + local version2="${2}"
|
| +
|
| + if version_compare "${version1}" "${version2}"; then
|
| + # They're equal.
|
| + return 0
|
| + elif [[ ${?} -eq 2 ]]; then
|
| + return 0
|
| + fi
|
| +
|
| + return 1
|
| +}
|
| +
|
| +build_dmg() {
|
| + if [[ ${#} -ne 8 ]]; then
|
| + err "build_dmg: wrong number of arguments"
|
| + exit 1
|
| + fi
|
| +
|
| + local output_dir="${1}"
|
| + local half_signed_app_path="${2}"
|
| + local codesign_keychain="${3}"
|
| + local codesign_id="${4}"
|
| + local app_version="${5}"
|
| + local channel_id="${6}"
|
| + local brand_id="${7}"
|
| + local name_fragment="${8}"
|
| +
|
| + # If the name fragment isn't empty, add a dash in front of it.
|
| + local dash_fragment="${name_fragment}"
|
| + if [[ -n "${dash_fragment}" ]]; then
|
| + dash_fragment="-${dash_fragment}"
|
| + fi
|
| +
|
| + local dmg_product_name="${DMG_PRODUCT_NAME}"
|
| + local product_name="${PRODUCT_NAME}"
|
| +
|
| + # Canary: The disk image should use GoogleChromeCanary as the product name
|
| + # instead of putting the fragment after the version number.
|
| + if [[ "${channel_id}" = "canary" ]]; then
|
| + product_name="${product_name} ${name_fragment}"
|
| + dmg_product_name="${dmg_product_name}${name_fragment}"
|
| + dash_fragment=""
|
| + fi
|
| +
|
| + local dmg_name="${dmg_product_name}-${app_version}${dash_fragment}.dmg"
|
| +
|
| + # Even with --verbosity 0, and even when it succeeds, hdiutil (via pkg-dmg)
|
| + # prints a newline to stderr. That looks pretty weird. Make it evident that
|
| + # things are progressing by printing a message for each disk image.
|
| + err "creating ${dmg_name}"
|
| +
|
| + local variant_dir="${g_temp_dir}/variant"
|
| + mkdir "${variant_dir}"
|
| + local variant_app_path="${variant_dir}/${APP_NAME}"
|
| +
|
| + # Copy the half-signed application to a variant-specific directory.
|
| + rsync "${RSYNC_FLAGS[@]}" "${half_signed_app_path}/" "${variant_app_path}"
|
| +
|
| + local app_plist="${variant_app_path}/Contents/Info"
|
| + local ks_plist="${app_plist}"
|
| +
|
| + # Apply the channel and brand code changes.
|
| + if [[ -z "${channel_id}" ]]; then
|
| + defaults delete "${ks_plist}" "${KS_CHANNEL_KEY}" 2> /dev/null || true
|
| + else
|
| + defaults write "${ks_plist}" "${KS_CHANNEL_KEY}" -string "${channel_id}"
|
| + fi
|
| +
|
| + if [[ -z "${brand_id}" ]]; then
|
| + defaults delete "${ks_plist}" "${KS_BRAND_KEY}" 2> /dev/null || true
|
| + else
|
| + defaults write "${ks_plist}" "${KS_BRAND_KEY}" -string "${brand_id}"
|
| + fi
|
| +
|
| + # Canary: the outer application bundle needs a distinct bundle ID for the
|
| + # system's bundle ID to disambiguate from a simultaneously-installed
|
| + # non-canary, and for Keystone to support side-by-side auto-update. It must
|
| + # keep the original Breakpad ID as this ID has been white-listed by the
|
| + # crash server. The CrProductDirName key, normally absent, is set specially
|
| + # in the canary build to force the default profile to an alternate
|
| + # directory. The CFBundleSignature key and PkgInfo file are set to contain
|
| + # the canary's distinct signature. The executable is renamed, and
|
| + # CFBundleExecutable is changed to point to it.
|
| + local app_bundle_id_old="$(defaults read "${app_plist}" "${APP_ID_KEY}")"
|
| + local app_bundle_id_new="${app_bundle_id_old}"
|
| + if [[ "${channel_id}" = "canary" ]]; then
|
| + app_bundle_id_new="${app_bundle_id_old}.canary"
|
| + defaults write "${app_plist}" "${APP_ID_KEY}" "${app_bundle_id_new}"
|
| + local ks_bundle_id="$(defaults read "${ks_plist}" "${KS_ID_KEY}")"
|
| + defaults write "${ks_plist}" "${KS_ID_KEY}" "${ks_bundle_id}.canary"
|
| + defaults write "${app_plist}" CrProductDirName "Google/Chrome Canary"
|
| + readonly CANARY_SIGNATURE="Pipi"
|
| + defaults write "${app_plist}" CFBundleSignature "${CANARY_SIGNATURE}"
|
| + echo -n "APPL${CANARY_SIGNATURE}" > "${variant_app_path}/Contents/PkgInfo"
|
| +
|
| + mv "${variant_app_path}/Contents/MacOS/Google Chrome" \
|
| + "${variant_app_path}/Contents/MacOS/Google Chrome Canary"
|
| + defaults write "${app_plist}" CFBundleExecutable "Google Chrome Canary"
|
| + 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 "${app_plist}.plist"
|
| + if [[ "${app_plist}" != "${ks_plist}" ]]; then
|
| + plutil -convert xml1 "${ks_plist}.plist"
|
| + fi
|
| +
|
| + # Canary: use different icons for the application and its documents. Adjust
|
| + # the bundle ID used for the managed preferences manifest.
|
| + if [[ "${channel}" = "canary" ]]; then
|
| + rsync "${RSYNC_FLAGS[@]}" "${PACKAGING_DIR}/app_canary.icns" \
|
| + "${variant_app_path}/Contents/Resources/app.icns"
|
| + rsync "${RSYNC_FLAGS[@]}" "${PACKAGING_DIR}/document_canary.icns" \
|
| + "${variant_app_path}/Contents/Resources/document.icns"
|
| +
|
| + local manifest_dir_new="\
|
| +${variant_app_path}/Contents/Resources/${app_bundle_id_new}.manifest"
|
| + mv "${variant_app_path}/Contents/Resources/${app_bundle_id_old}.manifest" \
|
| + "${manifest_dir_new}"
|
| + local manifest_plist_tmp="${variant_dir}/manifest"
|
| + mv "${manifest_dir_new}/Contents/Resources/${app_bundle_id_old}.manifest" \
|
| + "${manifest_plist_tmp}.plist"
|
| + defaults write "${manifest_plist_tmp}" pfm_domain "${app_bundle_id_new}"
|
| + plutil -convert xml1 "${manifest_plist_tmp}.plist"
|
| + mv "${manifest_plist_tmp}.plist" \
|
| + "${manifest_dir_new}/Contents/Resources/${app_bundle_id_new}.manifest"
|
| + fi
|
| +
|
| + # Sign the application - it's now fully signed.
|
| + "${PACKAGING_DIR}/sign_app.sh" "${variant_app_path}" \
|
| + "${codesign_keychain}" "${codesign_id}"
|
| +
|
| + local app_name="${APP_NAME}"
|
| +
|
| + # Canary: the application's name in the disk image should be changed from
|
| + # Google Chrome.app to Google Chrome Canary.app. The canary also uses a
|
| + # different .DS_Store file and has a different volume icon.
|
| + local dsstore_name="chrome_dmg_dsstore"
|
| + local icon_name="chrome_dmg_icon.icns"
|
| + if [[ "${channel_id}" = "canary" ]]; then
|
| + app_name="$(sed -e "s/\\.app\$/ ${name_fragment}.app/" <<< "${app_name}")"
|
| + dsstore_name="chrome_canary_dmg_dsstore"
|
| + icon_name="chrome_canary_dmg_icon.icns"
|
| + fi
|
| +
|
| + # A locally-created empty directory is more trustworthy than /var/empty.
|
| + local empty_dir="${g_temp_dir}/empty"
|
| + mkdir "${empty_dir}"
|
| +
|
| + local dmg_path="${output_dir}/${dmg_name}"
|
| +
|
| + # Make the disk image. Don't include ${name_fragment}, ${dash_fragment},
|
| + # or anything else in --volname because the .DS_Store expects the volume
|
| + # name to be constant. Don't put a name on the /Applications symbolic link
|
| + # because the same disk image is used for all languages.
|
| + "${PACKAGING_DIR}/pkg-dmg" \
|
| + --verbosity 0 \
|
| + --tempdir "${g_temp_dir}" \
|
| + --source "${empty_dir}" \
|
| + --target "${dmg_path}" \
|
| + --format UDBZ \
|
| + --volname "${product_name}" \
|
| + --icon "${PACKAGING_DIR}/${icon_name}" \
|
| + --copy "${variant_app_path}/:/${app_name}" \
|
| + --copy "${PACKAGING_DIR}/keystone_install.sh:/.keystone_install" \
|
| + --mkdir "/.background" \
|
| + --copy \
|
| +"${PACKAGING_DIR}/chrome_dmg_background.png:/.background/background.png" \
|
| + --copy "${PACKAGING_DIR}/${dsstore_name}:/.DS_Store" \
|
| + --symlink "/Applications:/ " \
|
| + --mkdir "/.keychain_reauthorize" \
|
| + --copy \
|
| +"${PACKAGING_DIR}/.keychain_reauthorize/${app_bundle_id_new}:/.keychain_reauthorize/${app_bundle_id_new}"
|
| +
|
| + rmdir "${empty_dir}"
|
| + rm -rf "${variant_dir}"
|
| +}
|
| +
|
| +# shell_safe_path ensures that |path| is safe to pass to tools as a
|
| +# command-line argument. If the first character in |path| is "-", "./" is
|
| +# prepended to it. The possibily-modified |path| is output.
|
| +shell_safe_path() {
|
| + local path="${1}"
|
| + if [[ "${path:0:1}" = "-" ]]; then
|
| + echo "./${path}"
|
| + else
|
| + echo "${path}"
|
| + fi
|
| +}
|
| +
|
| +usage() {
|
| + echo "usage: ${ME}: output_dir input_dir codesign_keychain codesign_id \
|
| +omahaproxy_url" >& 2
|
| +}
|
| +
|
| +main() {
|
| + local output_dir input_dir codesign_keychain codesign_id omahaproxy_url
|
| + output_dir="$(shell_safe_path "${1}")"
|
| + input_dir="$(shell_safe_path "${2}")"
|
| + codesign_keychain="$(shell_safe_path "${3}")"
|
| + codesign_id="${4}"
|
| + omahaproxy_url="${5}"
|
| +
|
| + trap cleanup EXIT HUP INT QUIT TERM
|
| +
|
| + err "output_dir=${output_dir}"
|
| + err "input_dir=${input_dir}"
|
| + err "codesign_keychain=${codesign_keychain}"
|
| + err "codesign_id=${codesign_id}"
|
| + err "omahaproxy_url=${omahaproxy_url}"
|
| +
|
| + if [[ -z "${input_dir}" ]] ||
|
| + [[ "${input_dir:0:1}" != "/" ]] ||
|
| + [[ ! -d "${input_dir}" ]]; then
|
| + # input_dir needs to be an absolute path because that's what |defaults|
|
| + # requires.
|
| + err "input_dir must exist and be an absolute path to a directory"
|
| + usage
|
| + exit 1
|
| + fi
|
| + if [[ ! -f "${codesign_keychain}" ]]; then
|
| + err "codesign_keychain must exist and be a file"
|
| + usage
|
| + exit 1
|
| + fi
|
| +
|
| + local source_app_path="${input_dir}/${APP_NAME}"
|
| +
|
| + if [[ ! -d "${source_app_path}" ]]; then
|
| + err "${source_app_path} not found"
|
| + exit 1
|
| + fi
|
| +
|
| + # Make sure ${output_dir} doesn't already exist, or if it does, make sure
|
| + # it's empty.
|
| + if [[ ! -d "${output_dir}" ]]; then
|
| + mkdir "${output_dir}"
|
| + fi
|
| + shopt -s nullglob dotglob
|
| + local output_dir_contents=("${output_dir}"/*)
|
| + shopt -u nullglob dotglob
|
| + if [[ ${#output_dir_contents[@]} -ne 0 ]]; then
|
| + err "output_dir must not exist or be empty"
|
| + exit 1
|
| + fi
|
| +
|
| + # Application sanity checks. Make sure that it smells right and that the
|
| + # version numbers in the various plists match.
|
| + local app_plist="${source_app_path}/Contents/Info"
|
| + local app_version
|
| + app_version="$(defaults read "${app_plist}" "${APP_VERSION_KEY}")"
|
| + local versioned_dir="${source_app_path}/Contents/Versions/${app_version}"
|
| + local framework_path="${versioned_dir}/${PRODUCT_NAME} Framework.framework"
|
| + local framework_plist="${framework_path}/Resources/Info"
|
| +
|
| + local ks_plist="${app_plist}"
|
| + local ks_version
|
| + if ! ks_version="$(defaults read "${ks_plist}" "${KS_VERSION_KEY}")"; then
|
| + err "Keystone version not present"
|
| + exit 1
|
| + fi
|
| + if [[ "${ks_version}" != "${app_version}" ]]; then
|
| + err "Keystone version does not match application version"
|
| + exit 1
|
| + fi
|
| +
|
| + local bp_plist="${framework_plist}"
|
| + local bp_version
|
| + if ! bp_version="$(defaults read "${bp_plist}" "${BP_VERSION_KEY}")"; then
|
| + err "Breakpad version not present"
|
| + exit 1
|
| + fi
|
| + if [[ "${bp_version}" != "${app_version}" ]]; then
|
| + err "Breakpad version does not match application version"
|
| + exit 1
|
| + fi
|
| +
|
| + # Consult omahaproxy to determine the current live versions on each channel.
|
| + # Get omahaproxy output first in a separate variable, allowing a failure
|
| + # to be caught directly.
|
| + #
|
| + # omahaproxy runs on appengine, which makes it the least reliable part of
|
| + # the process. Loop around omahaproxy to retry in the event of a failure.
|
| + # Do this early, so that the script can fail before performing major work
|
| + # in the event that omahaproxy output can't be collected.
|
| + local omahaproxy_full_url="\
|
| +${omahaproxy_url}/dl_urls?os=${OMAHAPROXY_PLATFORM}"
|
| + err "consulting ${omahaproxy_full_url}"
|
| + local omahaproxy_output
|
| + local i
|
| + for i in {1..5}; do
|
| + if ! omahaproxy_output="$(curl "${CURL_FLAGS[@]}" --max-time 15 \
|
| + "${omahaproxy_full_url}")" ||
|
| + [[ -z "${omahaproxy_output}" ]]; then
|
| + if [[ ${i} -lt 5 ]]; then
|
| + err "warning: could not get omahaproxy output, will retry"
|
| + sleep 15
|
| + else
|
| + err "could not get omahaproxy output"
|
| + exit 1
|
| + fi
|
| + else
|
| + break
|
| + fi
|
| + done
|
| +
|
| + # Loop through the live versions reported by omahaproxy.
|
| + local platform channel version url
|
| + local live_versions=()
|
| + local live_urls=()
|
| + local line_number=0
|
| + while IFS="," read -r platform channel version url; do
|
| + line_number=$((${line_number} + 1))
|
| + if [[ ${line_number} -eq 1 ]]; then
|
| + # Skip the first line, it's a header.
|
| + continue
|
| + fi
|
| +
|
| + if [[ "${platform}" != "${OMAHAPROXY_PLATFORM}" ]]; then
|
| + err "omahaproxy returned data for platform ${platform}"
|
| + exit 1
|
| + fi
|
| +
|
| + # In CH and as used with Keystone, the stable channel is an empty/unset
|
| + # string. omahaproxy reports it as "stable". Change "stable" to "" for
|
| + # comparison with the elements of the CH array.
|
| + if [[ "${channel}" = "stable" ]]; then
|
| + channel=""
|
| + fi
|
| +
|
| + # Loop through the known channels, and save the live version for each
|
| + # known channel.
|
| + for i in "${!CH[@]}"; do
|
| + local channel_i="${CH[${i}]}"
|
| +
|
| + # Skip anything with a brand code. Every channel with a brand code
|
| + # should also appear once without a brand code.
|
| + if [[ -n "${BR[${i}]}" ]]; then
|
| + continue
|
| + fi
|
| +
|
| + if [[ "${channel_i}" = "${channel}" ]]; then
|
| + live_versions[${i}]="${version}"
|
| + live_urls[${i}]="${url}"
|
| + fi
|
| + done
|
| + done <<< "${omahaproxy_output}"
|
| +
|
| + g_cleanup+=("${output_dir}")
|
| +
|
| + g_temp_dir="$(mktemp -d -t "${ME}")"
|
| + g_cleanup+=("${g_temp_dir}")
|
| +
|
| + # A "half-signed" application has its inner components signed, but the
|
| + # outermost browser application bundle is unsigned. The outer bundle can't
|
| + # be signed until Keystone channel and branding values are added in
|
| + # build_dmg. However, in order to facilitate differential updates, the inner
|
| + # components need to be byte-for-byte identical regardless of the Keystone
|
| + # values. The Keystone values are not placed in any inner component, and the
|
| + # inner components are signed just once, here, in order to guarantee
|
| + # that they'll be identical for each Keystone channel and branding setting.
|
| + # A signature includes a signing timestamp, so there can be only one signing
|
| + # operation of the inner components even if there are no other changes.
|
| +
|
| + local half_signed_dir="${g_temp_dir}/half_signed"
|
| + mkdir "${half_signed_dir}"
|
| + local half_signed_app_path="${half_signed_dir}/${APP_NAME}"
|
| +
|
| + rsync "${RSYNC_FLAGS[@]}" "${source_app_path}/" "${half_signed_app_path}"
|
| +
|
| + err "half-signing application"
|
| + "${PACKAGING_DIR}/sign_versioned_dir.sh" "${half_signed_app_path}" \
|
| + "${codesign_keychain}" "${codesign_id}"
|
| +
|
| + if [[ ${#CH[@]} -ne ${#BR[@]} ]] ||
|
| + [[ ${#CH[@]} -ne ${#NF[@]} ]]; then
|
| + err "there must be the same number of channels, brands, and name fragments"
|
| + exit 1
|
| + fi
|
| +
|
| + # Loop through, setting the channels and brand codes, signing everything,
|
| + # and building disk images.
|
| + for i in "${!CH[@]}"; do
|
| + local channel="${CH[${i}]}"
|
| + local brand="${BR[${i}]}"
|
| + local name_fragment="${NF[${i}]}"
|
| +
|
| + build_dmg "${output_dir}" "${half_signed_app_path}" \
|
| + "${codesign_keychain}" "${codesign_id}" \
|
| + "${app_version}" "${channel}" "${brand}" "${name_fragment}"
|
| + done
|
| +
|
| + # Loop through everything with a live version. Note that bash arrays are
|
| + # sparse, and ${!live_versions[@]} will only return indices that were set in
|
| + # the ${live_versions} array.
|
| + for i in "${!live_versions[@]}"; do
|
| + local live_version="${live_versions[${i}]}"
|
| + local live_url="${live_urls[${i}]}"
|
| + local channel="${CH[${i}]}"
|
| + local name_fragment="${NF[${i}]}"
|
| +
|
| + # If the name fragment isn't empty, add a dash in front of it.
|
| + local dash_fragment="${name_fragment}"
|
| + if [[ -n "${dash_fragment}" ]]; then
|
| + dash_fragment="-${dash_fragment}"
|
| + fi
|
| +
|
| + local product_name="${PRODUCT_NAME}"
|
| + local dmg_product_name="${DMG_PRODUCT_NAME}"
|
| +
|
| + # Canary: The disk image should use GoogleChromeCanary as the product name
|
| + # instead of putting the fragment after the version number.
|
| + if [[ "${channel}" = "canary" ]]; then
|
| + product_name="${product_name} ${name_fragment}"
|
| + dmg_product_name="${dmg_product_name}${name_fragment}"
|
| + dash_fragment=""
|
| + fi
|
| +
|
| + local print_channel="${channel}"
|
| + if [[ -z "${print_channel}" ]]; then
|
| + print_channel="stable"
|
| + fi
|
| +
|
| + if ! is_version_ge "${live_version}" "${MIN_DIFF_VERSION}"; then
|
| + # The live version is too old to be updated with a differential
|
| + # updater. Skip it.
|
| + err "skipping ${print_channel} differential updater, \
|
| +live ${live_version} < minimum ${MIN_DIFF_VERSION}"
|
| + continue
|
| + fi
|
| +
|
| + if ! is_version_gt "${app_version}" "${live_version}"; then
|
| + # The live version is newer than the app version; a differential updater
|
| + # would actually be a downgrader. Skip it.
|
| + err "skipping ${print_channel} differential updater, \
|
| +new ${app_version} <= live ${live_version}"
|
| + continue
|
| + fi
|
| +
|
| + local live_major=$(cut -d. -f1 <<< "${live_version}")
|
| + local app_major=$(cut -d. -f1 <<< "${app_version}")
|
| + if [[ ${app_major} -gt $((${live_major} + 1)) ]]; then
|
| + err "skipping ${print_channel} differential updater, \
|
| +new ${app_version} is more than one major version ahead of live ${live_version}"
|
| + continue
|
| + fi
|
| +
|
| + err "downloading ${live_url}"
|
| + local live_dmg="${g_temp_dir}/\
|
| +${dmg_product_name}-${live_version}${dash_fragment}.dmg"
|
| + for i in {1..5}; do
|
| + if ! curl "${CURL_FLAGS[@]}" --max-time 120 "${live_url}" \
|
| + -o "${live_dmg}" ||
|
| + ! [[ -f "${live_dmg}" ]]; then
|
| + if [[ ${i} -lt 5 ]]; then
|
| + err "warning: could not get live image, will retry"
|
| + sleep 15
|
| + else
|
| + err "live_dmg file ${live_dmg} not found"
|
| + exit 1
|
| + fi
|
| + else
|
| + break
|
| + fi
|
| + done
|
| +
|
| + local new_dmg="${output_dir}/\
|
| +${dmg_product_name}-${app_version}${dash_fragment}.dmg"
|
| + if ! [[ -f "${new_dmg}" ]]; then
|
| + err "new_dmg file ${new_dmg} not found"
|
| + exit 1
|
| + fi
|
| +
|
| + local patch_dmg_name=\
|
| +"${dmg_product_name}-${live_version}-${app_version}${dash_fragment}-Update.dmg"
|
| + local patch_dmg="${output_dir}/${patch_dmg_name}"
|
| +
|
| + err "creating ${patch_dmg_name}"
|
| + "${PACKAGING_DIR}/dmgdiffer.sh" \
|
| + "${product_name}" "${live_dmg}" "${new_dmg}" "${patch_dmg}"
|
| + done
|
| +
|
| + rm -rf "${g_temp_dir}"
|
| + unset g_cleanup[${#g_cleanup[@]}] # g_temp_dir
|
| +
|
| + unset g_cleanup[${#g_cleanup[@]}] # out_dir
|
| + trap - EXIT
|
| +}
|
| +
|
| +# Use -lt instead of -eq to tolerate this script's caller providing more
|
| +# arguments. This script's caller may be upgraded to provide more arguments
|
| +# to future versions of this script, but if this version runs, it should be
|
| +# able to operate with only the arguments it needs.
|
| +if [[ ${#} -lt 5 ]]; then
|
| + usage
|
| + exit 1
|
| +fi
|
| +
|
| +main "${@}"
|
| +exit ${?}
|
|
|
| Property changes on: chrome_mac/Google Chrome Packaging/generate_dmgs
|
| ___________________________________________________________________
|
| Added: svn:executable
|
| + *
|
|
|
|
|