15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/bin/bash -p 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# usage: dmgdiffer.sh product_name old_dmg new_dmg patch_dmg 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# dmgdiffer creates a disk image containing a binary update able to patch 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# a product originally distributed in old_dmg to the version in new_dmg. Much 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# of this script is generic, but the make_patch_fs function is specific to 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# a product: in this case, Google Chrome. 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This script operates by mounting old_dmg and new_dmg, creating a new 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# filesystem structure containing dirpatches generated by dirdiffer and 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# goobsdiff (which should be located in the same directory as this script), 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# and producing a disk image from that structure. 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The Chrome make_patch_fs function produces an disk image that is able to 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# update a single old version on any Keystone channel to a new version on a 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# specific Keystone channel (the Keystone channel associated with new_dmg). 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Chrome's updates are split into two dirpatches: one updates the old 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# versioned directory to the new one, and the other updates the remainder of 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the application. The versioned directory is split out from the rest because 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# it contains the bulk of the application and its name changes from version to 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# version, and dirdiffer/dirpatcher do not directly handle name changes. This 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# approach also allows the versioned directory dirpatch to be applied in-place 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# in most cases during an update, rather than relying on a temporary 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# directory. In order to allow a single update dmg to apply to an old version 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# on any Keystone channel, several small files are never distributed as diffs, 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# and only as full (possibly compressed) versions of the new files. These 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# files include the outer application's Info.plist which contains Keystone 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# channel information, and anything created or modified by code-signing the 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# outer application. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Application of update disk images produced by this script is 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# product-specific. With updates managed by Keystone, the update disk images 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# can contain a .keystone_install script that is able to locate and update 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# the installed product. 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Exit codes: 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 0 OK 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 1 Unknown failure 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 2 Incorrect number of parameters 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 3 Input disk images do not exist 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 4 Output disk image already exists 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 5 Parent of output directory does not exist or is not a directory 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 6 Could not mount old_dmg 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 7 Could not mount new_dmg 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 8 Could not create temporary patch filesystem directory 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 9 Could not create disk image 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 10 Could not read old application data 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 11 Could not read new application data 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 12 Old or new application sanity check failure 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 13 Could not write the patch 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Exit codes in the range 21-40 are mapped to codes 1-20 as returned by the 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# first dirdiffer invocation. Codes 41-60 are mapped to codes 1-20 as returned 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# by the second. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)set -eu 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Environment sanitization. Set a known-safe PATH. Clear environment variables 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# that might impact the interpreter's operation. The |bash -p| invocation 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# on the #! line takes the bite out of BASH_ENV, ENV, and SHELLOPTS (among 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# other features), but clearing them here ensures that they won't impact any 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# shell scripts used as utility programs. SHELLOPTS is read-only and can't be 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# unset, only unexported. 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)export PATH="/usr/bin:/bin:/usr/sbin:/sbin" 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unset BASH_ENV CDPATH ENV GLOBIGNORE IFS POSIXLY_CORRECT 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)export -n SHELLOPTS 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ME="$(basename "${0}")" 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly ME 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SCRIPT_DIR="$(dirname "${0}")" 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly SCRIPT_DIR 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly DIRDIFFER="${SCRIPT_DIR}/dirdiffer.sh" 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)readonly PKG_DMG="${SCRIPT_DIR}/pkg-dmg" 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)err() { 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local error="${1}" 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${ME}: ${error}" >& 2 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)declare -a g_cleanup g_cleanup_mount_points 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cleanup() { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local status=${?} 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trap - EXIT 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trap '' HUP INT QUIT TERM 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ ${status} -ge 128 ]]; then 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "Caught signal $((${status} - 128))" 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${#g_cleanup_mount_points[@]}" -gt 0 ]]; then 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local mount_point 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for mount_point in "${g_cleanup_mount_points[@]}"; do 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hdiutil detach "${mount_point}" -force >& /dev/null || true 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) done 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${#g_cleanup[@]}" -gt 0 ]]; then 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -rf "${g_cleanup[@]}" 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit ${status} 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)mount_dmg() { 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local dmg="${1}" 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local mount_point="${2}" 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! hdiutil attach "${1}" -mountpoint "${2}" \ 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) -nobrowse -owners off > /dev/null; then 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # set -e is in effect. return ${?} so that the caller can check the return 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # code if desired, perhaps to print a more useful error message or to exit 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # with a more precise status than would be possible here. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ${?} 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# make_patch_fs is responsible for comparing the old and new disk images 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# mounted at old_fs and new_fs, respectively, and populating patch_fs with the 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# contents of what will become a disk image able to update old_fs to new_fs. 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# It then outputs a string which will be used as the volume name of the 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# patch_dmg. 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The entire patch contents are placed into a .patch directory to hide them 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# from ordinary view. The disk image will be given a volume name like 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# "Google Chrome 5.0.375.55-5.0.375.70" as an identifying aid, although 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# uniqueness is not important and users will never interact directly with 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# them. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)make_patch_fs() { 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local product_name="${1}" 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_fs="${2}" 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_fs="${3}" 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_fs="${4}" 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) readonly APP_NAME="${product_name}.app" 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) readonly APP_NAME_RE="${product_name}\\.app" 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) readonly APP_PLIST="Contents/Info" 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) readonly APP_VERSION_KEY="CFBundleShortVersionString" 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) readonly APP_BUNDLEID_KEY="CFBundleIdentifier" 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) readonly KS_VERSION_KEY="KSVersion" 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) readonly KS_PRODUCT_KEY="KSProductID" 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) readonly KS_CHANNEL_KEY="KSChannelID" 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) readonly VERSIONS_DIR="Contents/Versions" 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) readonly BUILD_RE="^[0-9]+\\.[0-9]+\\.([0-9]+)\\.[0-9]+\$" 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) readonly MIN_BUILD=434 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local product_url="http://www.google.com/chrome/" 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${product_name}" = "Google Chrome Canary" ]]; then 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) product_url="http://tools.google.com/dlpage/chromesxs" 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_app_path="${old_fs}/${APP_NAME}" 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_app_plist="${old_app_path}/${APP_PLIST}" 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_app_version 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! old_app_version="$(defaults read "${old_app_plist}" \ 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${APP_VERSION_KEY}")"; then 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not read old app version" 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 10 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! [[ "${old_app_version}" =~ ${BUILD_RE} ]]; then 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "old app version not of expected format" 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 10 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_app_version_build="${BASH_REMATCH[1]}" 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_app_bundleid 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! old_app_bundleid="$(defaults read "${old_app_plist}" \ 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${APP_BUNDLEID_KEY}")"; then 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not read old app bundle ID" 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 10 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_ks_plist="${old_app_plist}" 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_ks_version 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! old_ks_version="$(defaults read "${old_ks_plist}" \ 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${KS_VERSION_KEY}")"; then 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not read old Keystone version" 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 10 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_app_path="${new_fs}/${APP_NAME}" 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_app_plist="${new_app_path}/${APP_PLIST}" 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_app_version 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! new_app_version="$(defaults read "${new_app_plist}" \ 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${APP_VERSION_KEY}")"; then 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not read new app version" 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 11 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! [[ "${new_app_version}" =~ ${BUILD_RE} ]]; then 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "new app version not of expected format" 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 11 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_app_version_build="${BASH_REMATCH[1]}" 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_ks_plist="${new_app_plist}" 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_ks_version 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! new_ks_version="$(defaults read "${new_ks_plist}" \ 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${KS_VERSION_KEY}")"; then 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not read new Keystone version" 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 11 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_ks_product 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! new_ks_product="$(defaults read "${new_app_plist}" \ 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${KS_PRODUCT_KEY}")"; then 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not read new Keystone product ID" 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 11 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ ${old_app_version_build} -lt ${MIN_BUILD} ]] || 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) [[ ${new_app_version_build} -lt ${MIN_BUILD} ]]; then 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "old and new versions must be build ${MIN_BUILD} or newer" 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 12 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_ks_channel 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_ks_channel="$(defaults read "${new_app_plist}" \ 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${KS_CHANNEL_KEY}" 2> /dev/null || true)" 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local name_extra 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${new_ks_channel}" = "beta" ]]; then 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_extra=" Beta" 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif [[ "${new_ks_channel}" = "dev" ]]; then 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_extra=" Dev" 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif [[ "${new_ks_channel}" = "canary" ]]; then 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_extra= 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) elif [[ -n "${new_ks_channel}" ]]; then 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name_extra=" ${new_ks_channel}" 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_versioned_dir="${old_app_path}/${VERSIONS_DIR}/${old_app_version}" 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_versioned_dir="${new_app_path}/${VERSIONS_DIR}/${new_app_version}" 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! cp -p "${SCRIPT_DIR}/keystone_install.sh" \ 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${patch_fs}/.keystone_install"; then 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not copy .keystone_install" 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 13 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_keychain_reauthorize_dir="${patch_fs}/.keychain_reauthorize" 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! mkdir "${patch_keychain_reauthorize_dir}"; then 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not mkdir patch_keychain_reauthorize_dir" 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 13 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! cp -p "${SCRIPT_DIR}/.keychain_reauthorize/${old_app_bundleid}" \ 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${patch_keychain_reauthorize_dir}/${old_app_bundleid}"; then 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not copy keychain_reauthorize" 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 13 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_dotpatch_dir="${patch_fs}/.patch" 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! mkdir "${patch_dotpatch_dir}"; then 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not mkdir patch_dotpatch_dir" 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 13 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! cp -p "${SCRIPT_DIR}/dirpatcher.sh" \ 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${SCRIPT_DIR}/goobspatch" \ 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${SCRIPT_DIR}/liblzma_decompress.dylib" \ 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${SCRIPT_DIR}/xzdec" \ 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${patch_dotpatch_dir}/"; then 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not copy patching tools" 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 13 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! echo "${new_ks_product}" > "${patch_dotpatch_dir}/ks_product" || 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ! echo "${old_app_version}" > "${patch_dotpatch_dir}/old_app_version" || 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ! echo "${new_app_version}" > "${patch_dotpatch_dir}/new_app_version" || 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ! echo "${old_ks_version}" > "${patch_dotpatch_dir}/old_ks_version" || 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ! echo "${new_ks_version}" > "${patch_dotpatch_dir}/new_ks_version"; then 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not write patch product or version information" 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 13 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_ks_channel_file="${patch_dotpatch_dir}/ks_channel" 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -n "${new_ks_channel}" ]]; then 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! echo "${new_ks_channel}" > "${patch_ks_channel_file}"; then 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not write Keystone channel information" 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 13 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! touch "${patch_ks_channel_file}"; then 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not write empty Keystone channel information" 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 13 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The only visible contents of the disk image will be a README file that 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # explains the image's purpose. 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_app_version_extra="${new_app_version}${name_extra}" 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cat > "${patch_fs}/README.txt" << __EOF__ || \ 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (err "could not write README.txt" && exit 13) 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This disk image contains a differential updater that can update 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)${product_name} from version ${old_app_version} to ${new_app_version_extra}. 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This image is part of the auto-update system and is not independently 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)useful. 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)To install ${product_name}, please visit 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)<${product_url}>. 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)__EOF__ 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_versioned_dir="\ 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)${patch_dotpatch_dir}/version_${old_app_version}_${new_app_version}.dirpatch" 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! "${DIRDIFFER}" "${old_versioned_dir}" \ 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${new_versioned_dir}" \ 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${patch_versioned_dir}"; then 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local status=${?} 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not create a dirpatch for the versioned directory" 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit $((${status} + 20)) 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Set DIRDIFFER_EXCLUDE to exclude the contents of the Versions directory, 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # but to include an empty Versions directory. The versioned directory was 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # already addressed in the preceding dirpatch. 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) export DIRDIFFER_EXCLUDE="/${APP_NAME_RE}/Contents/Versions/" 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Set DIRDIFFER_NO_DIFF to exclude files introduced by or modified by 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Keystone channel and brand tagging and subsequent code signing. 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) export DIRDIFFER_NO_DIFF="\ 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/${APP_NAME_RE}/Contents/\ 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(CodeResources|Info\\.plist|MacOS/${product_name}|_CodeSignature/.*)$" 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_app_dir="${patch_dotpatch_dir}/application.dirpatch" 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! "${DIRDIFFER}" "${old_app_path}" \ 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${new_app_path}" \ 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${patch_app_dir}"; then 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local status=${?} 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not create a dirpatch for the application directory" 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit $((${status} + 40)) 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unset DIRDIFFER_EXCLUDE DIRDIFFER_NO_DIFF 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${product_name} ${old_app_version}-${new_app_version_extra} Update" 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# package_patch_dmg creates a disk image at patch_dmg with the contents of 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# patch_fs. The disk image's volume name is taken from volume_name. temp_dir 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# is a work directory such as /tmp for the packager's use. 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)package_patch_dmg() { 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_fs="${1}" 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_dmg="${2}" 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local volume_name="${3}" 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local temp_dir="${4}" 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Because most of the contents of ${patch_fs} are already compressed, the 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # overall compression on the disk image is mostly used to minimize the sizes 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # of the filesystem structures. In the presence of so much 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # already-compressed data, zlib performs better than bzip2, so use UDZO. 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! "${PKG_DMG}" \ 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --verbosity 0 \ 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --source "${patch_fs}" \ 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --target "${patch_dmg}" \ 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --tempdir "${temp_dir}" \ 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --format UDZO \ 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --volname "${volume_name}" \ 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --config "openfolder_bless=0"; then 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "disk image creation failed" 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 9 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# make_patch_dmg mounts old_dmg and new_dmg, invokes make_patch_fs to prepare 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# a patch filesystem, and then hands the patch filesystem to package_patch_dmg 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# to create patch_dmg. 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)make_patch_dmg() { 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local product_name="${1}" 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_dmg="${2}" 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_dmg="${3}" 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_dmg="${4}" 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local temp_dir 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) temp_dir="$(mktemp -d -t "${ME}")" 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_cleanup+=("${temp_dir}") 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local old_mount_point="${temp_dir}/old" 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_cleanup_mount_points+=("${old_mount_point}") 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! mount_dmg "${old_dmg}" "${old_mount_point}"; then 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not mount old_dmg ${old_dmg}" 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 6 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local new_mount_point="${temp_dir}/new" 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) g_cleanup_mount_points+=("${new_mount_point}") 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! mount_dmg "${new_dmg}" "${new_mount_point}"; then 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not mount new_dmg ${new_dmg}" 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 7 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_fs="${temp_dir}/patch" 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! mkdir "${patch_fs}"; then 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "could not mkdir patch_fs ${patch_fs}" 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 8 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local volume_name 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) volume_name="$(make_patch_fs "${product_name}" \ 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${old_mount_point}" \ 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${new_mount_point}" \ 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "${patch_fs}")" 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hdiutil detach "${new_mount_point}" > /dev/null 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unset g_cleanup_mount_points[${#g_cleanup_mount_points[@]}] 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hdiutil detach "${old_mount_point}" > /dev/null 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unset g_cleanup_mount_points[${#g_cleanup_mount_points[@]}] 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) package_patch_dmg "${patch_fs}" "${patch_dmg}" "${volume_name}" "${temp_dir}" 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rm -rf "${temp_dir}" 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unset g_cleanup[${#g_cleanup[@]}] 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# shell_safe_path ensures that |path| is safe to pass to tools as a 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# command-line argument. If the first character in |path| is "-", "./" is 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# prepended to it. The possibly-modified |path| is output. 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)shell_safe_path() { 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local path="${1}" 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ "${path:0:1}" = "-" ]]; then 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "./${path}" 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "${path}" 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)usage() { 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) echo "usage: ${ME} product_name old_dmg new_dmg patch_dmg" >& 2 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)main() { 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local product_name old_dmg new_dmg patch_dmg 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) product_name="${1}" 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_dmg="$(shell_safe_path "${2}")" 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_dmg="$(shell_safe_path "${3}")" 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_dmg="$(shell_safe_path "${4}")" 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trap cleanup EXIT HUP INT QUIT TERM 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! [[ -f "${old_dmg}" ]] || ! [[ -f "${new_dmg}" ]]; then 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "old_dmg and new_dmg must exist and be files" 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 3 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if [[ -e "${patch_dmg}" ]]; then 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "patch_dmg must not exist" 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 4 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) local patch_dmg_parent 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) patch_dmg_parent="$(dirname "${patch_dmg}")" 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ! [[ -d "${patch_dmg_parent}" ]]; then 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) err "patch_dmg parent directory must exist and be a directory" 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 5 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) fi 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) make_patch_dmg "${product_name}" "${old_dmg}" "${new_dmg}" "${patch_dmg}" 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) trap - EXIT 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if [[ ${#} -ne 4 ]]; then 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usage 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exit 2 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)fi 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)main "${@}" 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)exit ${?} 480