1 #!/bin/sh 2 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 4 # Use of this source code is governed by a BSD-style license that can be 5 # found in the LICENSE file. 6 7 # This script signs the Chromoting binaries, builds the Chrome Remote Desktop 8 # installer and then packages it into a .dmg. It requires that Packages be 9 # installed (for 'packagesbuild'). 10 # Packages: http://s.sudre.free.fr/Software/Packages/about.html 11 # 12 # usage: do_signing.sh output_dir input_dir [codesign_keychain codesign_id 13 # [productsign_id]] 14 # 15 # The final disk image (dmg) is placed in |output_dir|. 16 17 set -e -u 18 19 ME="$(basename "${0}")" 20 readonly ME 21 22 declare -a g_cleanup_dirs 23 24 setup() { 25 local input_dir="${1}" 26 27 # The file that contains the properties for this signing build. 28 # The file should contain only key=value pairs, one per line. 29 PROPS_FILENAME="${input_dir}/do_signing.props" 30 31 # Individually load the properties for this build. Don't 'source' the file 32 # to guard against code accidentally being added to the props file. 33 HOST_UNINSTALLER_NAME=$(read_property "HOST_UNINSTALLER_NAME") 34 HOST_PKG=$(read_property "HOST_PKG") 35 DMG_VOLUME_NAME=$(read_property "DMG_VOLUME_NAME") 36 DMG_FILE_NAME=$(read_property "DMG_FILE_NAME") 37 38 # Binaries to sign. 39 ME2ME_HOST='PrivilegedHelperTools/org.chromium.chromoting.me2me_host.app' 40 UNINSTALLER="Applications/${HOST_UNINSTALLER_NAME}.app" 41 PREFPANE='PreferencePanes/org.chromium.chromoting.prefPane' 42 43 # The Chromoting Host installer is a meta-package that consists of 3 44 # components: 45 # * Chromoting Host Service package 46 # * Chromoting Host Uninstaller package 47 # * Keystone package (GoogleSoftwareUpdate - for Official builds only) 48 PKGPROJ_HOST='ChromotingHost.pkgproj' 49 PKGPROJ_HOST_SERVICE='ChromotingHostService.pkgproj' 50 PKGPROJ_HOST_UNINSTALLER='ChromotingHostUninstaller.pkgproj' 51 52 # Final (user-visible) pkg name. 53 PKG_FINAL="${HOST_PKG}.pkg" 54 55 DMG_FILE_NAME="${DMG_FILE_NAME}.dmg" 56 57 # Temp directory for Packages output. 58 PKG_DIR=build 59 g_cleanup_dirs+=("${PKG_DIR}") 60 61 # Temp directories for building the dmg. 62 DMG_TEMP_DIR="$(mktemp -d -t "${ME}"-dmg)" 63 g_cleanup_dirs+=("${DMG_TEMP_DIR}") 64 65 DMG_EMPTY_DIR="$(mktemp -d -t "${ME}"-empty)" 66 g_cleanup_dirs+=("${DMG_EMPTY_DIR}") 67 } 68 69 err() { 70 echo "[$(date +'%Y-%m-%d %H:%M:%S%z')]: ${@}" >&2 71 } 72 73 err_exit() { 74 err "${@}" 75 exit 1 76 } 77 78 # shell_safe_path ensures that |path| is safe to pass to tools as a 79 # command-line argument. If the first character in |path| is "-", "./" is 80 # prepended to it. The possibly-modified |path| is output. 81 shell_safe_path() { 82 local path="${1}" 83 if [[ "${path:0:1}" = "-" ]]; then 84 echo "./${path}" 85 else 86 echo "${path}" 87 fi 88 } 89 90 # Read a single property from the properties file. 91 read_property() { 92 local property="${1}" 93 local filename="${PROPS_FILENAME}" 94 echo `grep "${property}" "${filename}" | tail -n 1 | cut -d "=" -f2-` 95 } 96 97 verify_clean_dir() { 98 local dir="${1}" 99 if [[ ! -d "${dir}" ]]; then 100 mkdir "${dir}" 101 fi 102 103 if [[ -e "${output_dir}/${DMG_FILE_NAME}" ]]; then 104 err "Output directory is dirty from previous build." 105 exit 1 106 fi 107 } 108 109 sign() { 110 local name="${1}" 111 local keychain="${2}" 112 local id="${3}" 113 114 if [[ ! -e "${name}" ]]; then 115 err_exit "Input file doesn't exist: ${name}" 116 fi 117 118 echo Signing "${name}" 119 codesign -vv -s "${id}" --keychain "${keychain}" "${name}" 120 codesign -v "${name}" 121 } 122 123 sign_binaries() { 124 local input_dir="${1}" 125 local keychain="${2}" 126 local id="${3}" 127 128 sign "${input_dir}/${ME2ME_HOST}" "${keychain}" "${id}" 129 sign "${input_dir}/${UNINSTALLER}" "${keychain}" "${id}" 130 sign "${input_dir}/${PREFPANE}" "${keychain}" "${id}" 131 } 132 133 sign_installer() { 134 local input_dir="${1}" 135 local keychain="${2}" 136 local id="${3}" 137 138 local package="${input_dir}/${PKG_DIR}/${PKG_FINAL}" 139 productsign --sign "${id}" --keychain "${keychain}" \ 140 "${package}" "${package}.signed" 141 mv -f "${package}.signed" "${package}" 142 } 143 144 build_package() { 145 local pkg="${1}" 146 echo "Building .pkg from ${pkg}" 147 packagesbuild -v "${pkg}" 148 } 149 150 build_packages() { 151 local input_dir="${1}" 152 build_package "${input_dir}/${PKGPROJ_HOST_SERVICE}" 153 build_package "${input_dir}/${PKGPROJ_HOST_UNINSTALLER}" 154 build_package "${input_dir}/${PKGPROJ_HOST}" 155 } 156 157 build_dmg() { 158 local input_dir="${1}" 159 local output_dir="${2}" 160 161 # Create the .dmg. 162 echo "Building .dmg..." 163 "${input_dir}/pkg-dmg" \ 164 --format UDBZ \ 165 --tempdir "${DMG_TEMP_DIR}" \ 166 --source "${DMG_EMPTY_DIR}" \ 167 --target "${output_dir}/${DMG_FILE_NAME}" \ 168 --volname "${DMG_VOLUME_NAME}" \ 169 --copy "${input_dir}/${PKG_DIR}/${PKG_FINAL}" \ 170 --copy "${input_dir}/Scripts/keystone_install.sh:/.keystone_install" 171 172 if [[ ! -f "${output_dir}/${DMG_FILE_NAME}" ]]; then 173 err_exit "Unable to create disk image: ${DMG_FILE_NAME}" 174 fi 175 } 176 177 cleanup() { 178 if [[ "${#g_cleanup_dirs[@]}" > 0 ]]; then 179 rm -rf "${g_cleanup_dirs[@]}" 180 fi 181 } 182 183 usage() { 184 echo "Usage: ${ME} output_dir input_dir [keychain codesign_id"\ 185 "[productsign_id]]" >&2 186 echo " Sign the binaries using the specified <codesign_id>, build" >&2 187 echo " the installer and then sign the installer using the given" >&2 188 echo " <productsign_id>." >&2 189 echo " If the <keychain> and signing ids are not specified then the" >&2 190 echo " installer is built without signing any binaries." >&2 191 } 192 193 main() { 194 local output_dir="$(shell_safe_path "${1}")" 195 local input_dir="$(shell_safe_path "${2}")" 196 local do_sign_binaries=0 197 local keychain="" 198 if [[ ${#} -ge 3 ]]; then 199 keychain="$(shell_safe_path "${3}")" 200 do_sign_binaries=1 201 echo "Signing binaries using ${keychain}" 202 else 203 echo "Not signing binaries (no keychain or identify specified)" 204 fi 205 local codesign_id="" 206 if [[ ${#} -ge 4 ]]; then 207 codesign_id="${4}" 208 fi 209 local productsign_id="" 210 if [[ ${#} -ge 5 ]]; then 211 productsign_id="${5}" 212 fi 213 214 if [[ "${do_sign_binaries}" == 1 && -z "${codesign_id}" ]]; then 215 err_exit "Can't sign binaries - please specify a codesign_id" 216 fi 217 218 setup "${input_dir}" 219 verify_clean_dir "${output_dir}" 220 221 if [[ "${do_sign_binaries}" == 1 ]]; then 222 sign_binaries "${input_dir}" "${keychain}" "${codesign_id}" 223 fi 224 build_packages "${input_dir}" 225 if [[ "${do_sign_binaries}" == 1 && -n "${productsign_id}" ]]; then 226 echo "Signing installer..." 227 sign_installer "${input_dir}" "${keychain}" "${productsign_id}" 228 fi 229 build_dmg "${input_dir}" "${output_dir}" 230 231 cleanup 232 } 233 234 if [[ ${#} < 2 ]]; then 235 usage 236 exit 1 237 fi 238 239 main "${@}" 240 exit ${?} 241