Home | History | Annotate | Download | only in mac
      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