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 |
+ * |