• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
17set -e -u
18
19ME="$(basename "${0}")"
20readonly ME
21
22declare -a g_cleanup_dirs
23
24setup() {
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  DMG_VOLUME_NAME=$(read_property "DMG_VOLUME_NAME")
34  DMG_FILE_NAME=$(read_property "DMG_FILE_NAME")
35  HOST_BUNDLE_NAME=$(read_property "HOST_BUNDLE_NAME")
36  HOST_PKG=$(read_property "HOST_PKG")
37  HOST_UNINSTALLER_NAME=$(read_property "HOST_UNINSTALLER_NAME")
38  NATIVE_MESSAGING_HOST_BUNDLE_NAME=$(read_property\
39    "NATIVE_MESSAGING_HOST_BUNDLE_NAME")
40  PREFPANE_BUNDLE_NAME=$(read_property "PREFPANE_BUNDLE_NAME")
41  REMOTE_ASSISTANCE_HOST_BUNDLE_NAME=$(read_property\
42    "REMOTE_ASSISTANCE_HOST_BUNDLE_NAME")
43
44  # Binaries to sign.
45  ME2ME_HOST="PrivilegedHelperTools/${HOST_BUNDLE_NAME}"
46  ME2ME_NM_HOST="PrivilegedHelperTools/${HOST_BUNDLE_NAME}/Contents/MacOS/"`
47                `"${NATIVE_MESSAGING_HOST_BUNDLE_NAME}/Contents/MacOS/"`
48                `"native_messaging_host"
49  IT2ME_NM_HOST="PrivilegedHelperTools/${HOST_BUNDLE_NAME}/Contents/MacOS/"`
50                `"${REMOTE_ASSISTANCE_HOST_BUNDLE_NAME}/Contents/MacOS/"`
51                `"remote_assistance_host"
52  UNINSTALLER="Applications/${HOST_UNINSTALLER_NAME}.app"
53  PREFPANE="PreferencePanes/${PREFPANE_BUNDLE_NAME}"
54
55  # The Chromoting Host installer is a meta-package that consists of 3
56  # components:
57  #  * Chromoting Host Service package
58  #  * Chromoting Host Uninstaller package
59  #  * Keystone package (GoogleSoftwareUpdate - for Official builds only)
60  PKGPROJ_HOST="ChromotingHost.pkgproj"
61  PKGPROJ_HOST_SERVICE="ChromotingHostService.pkgproj"
62  PKGPROJ_HOST_UNINSTALLER="ChromotingHostUninstaller.pkgproj"
63
64  # Final (user-visible) pkg name.
65  PKG_FINAL="${HOST_PKG}.pkg"
66
67  DMG_FILE_NAME="${DMG_FILE_NAME}.dmg"
68
69  # Temp directory for Packages output.
70  PKG_DIR=build
71  g_cleanup_dirs+=("${PKG_DIR}")
72
73  # Temp directories for building the dmg.
74  DMG_TEMP_DIR="$(mktemp -d -t "${ME}"-dmg)"
75  g_cleanup_dirs+=("${DMG_TEMP_DIR}")
76
77  DMG_EMPTY_DIR="$(mktemp -d -t "${ME}"-empty)"
78  g_cleanup_dirs+=("${DMG_EMPTY_DIR}")
79}
80
81err() {
82  echo "[$(date +'%Y-%m-%d %H:%M:%S%z')]: ${@}" >&2
83}
84
85err_exit() {
86  err "${@}"
87  exit 1
88}
89
90# shell_safe_path ensures that |path| is safe to pass to tools as a
91# command-line argument. If the first character in |path| is "-", "./" is
92# prepended to it. The possibly-modified |path| is output.
93shell_safe_path() {
94  local path="${1}"
95  if [[ "${path:0:1}" = "-" ]]; then
96    echo "./${path}"
97  else
98    echo "${path}"
99  fi
100}
101
102# Read a single property from the properties file.
103read_property() {
104  local property="${1}"
105  local filename="${PROPS_FILENAME}"
106  echo `grep "\<${property}\>=" "${filename}" | tail -n 1 | cut -d "=" -f2-`
107}
108
109verify_clean_dir() {
110  local dir="${1}"
111  if [[ ! -d "${dir}" ]]; then
112    mkdir "${dir}"
113  fi
114
115  if [[ -e "${output_dir}/${DMG_FILE_NAME}" ]]; then
116    err "Output directory is dirty from previous build."
117    exit 1
118  fi
119}
120
121sign() {
122  local name="${1}"
123  local keychain="${2}"
124  local id="${3}"
125
126  if [[ ! -e "${name}" ]]; then
127    err_exit "Input file doesn't exist: ${name}"
128  fi
129
130  echo Signing "${name}"
131  codesign -vv -s "${id}" --keychain "${keychain}" "${name}"
132  codesign -v "${name}"
133}
134
135sign_binaries() {
136  local input_dir="${1}"
137  local keychain="${2}"
138  local id="${3}"
139
140  sign "${input_dir}/${ME2ME_NM_HOST}" "${keychain}" "${id}"
141  sign "${input_dir}/${IT2ME_NM_HOST}" "${keychain}" "${id}"
142  sign "${input_dir}/${ME2ME_HOST}" "${keychain}" "${id}"
143  sign "${input_dir}/${UNINSTALLER}" "${keychain}" "${id}"
144  sign "${input_dir}/${PREFPANE}" "${keychain}" "${id}"
145}
146
147sign_installer() {
148  local input_dir="${1}"
149  local keychain="${2}"
150  local id="${3}"
151
152  local package="${input_dir}/${PKG_DIR}/${PKG_FINAL}"
153  productsign --sign "${id}" --keychain "${keychain}" \
154      "${package}" "${package}.signed"
155  mv -f "${package}.signed" "${package}"
156}
157
158build_package() {
159  local pkg="${1}"
160  echo "Building .pkg from ${pkg}"
161  packagesbuild -v "${pkg}"
162}
163
164build_packages() {
165  local input_dir="${1}"
166  build_package "${input_dir}/${PKGPROJ_HOST_SERVICE}"
167  build_package "${input_dir}/${PKGPROJ_HOST_UNINSTALLER}"
168  build_package "${input_dir}/${PKGPROJ_HOST}"
169}
170
171build_dmg() {
172  local input_dir="${1}"
173  local output_dir="${2}"
174
175  # Create the .dmg.
176  echo "Building .dmg..."
177  "${input_dir}/pkg-dmg" \
178      --format UDBZ \
179      --tempdir "${DMG_TEMP_DIR}" \
180      --source "${DMG_EMPTY_DIR}" \
181      --target "${output_dir}/${DMG_FILE_NAME}" \
182      --volname "${DMG_VOLUME_NAME}" \
183      --copy "${input_dir}/${PKG_DIR}/${PKG_FINAL}" \
184      --copy "${input_dir}/Scripts/keystone_install.sh:/.keystone_install"
185
186  if [[ ! -f "${output_dir}/${DMG_FILE_NAME}" ]]; then
187    err_exit "Unable to create disk image: ${DMG_FILE_NAME}"
188  fi
189}
190
191cleanup() {
192  if [[ "${#g_cleanup_dirs[@]}" > 0 ]]; then
193    rm -rf "${g_cleanup_dirs[@]}"
194  fi
195}
196
197usage() {
198  echo "Usage: ${ME} output_dir input_dir [keychain codesign_id"\
199      "[productsign_id]]" >&2
200  echo "  Sign the binaries using the specified <codesign_id>, build" >&2
201  echo "  the installer and then sign the installer using the given" >&2
202  echo "  <productsign_id>." >&2
203  echo "  If the <keychain> and signing ids are not specified then the" >&2
204  echo "  installer is built without signing any binaries." >&2
205}
206
207main() {
208  local output_dir="$(shell_safe_path "${1}")"
209  local input_dir="$(shell_safe_path "${2}")"
210  local do_sign_binaries=0
211  local keychain=""
212  if [[ ${#} -ge 3 ]]; then
213    keychain="$(shell_safe_path "${3}")"
214    do_sign_binaries=1
215    echo "Signing binaries using ${keychain}"
216  else
217    echo "Not signing binaries (no keychain or identify specified)"
218  fi
219  local codesign_id=""
220  if [[ ${#} -ge 4 ]]; then
221    codesign_id="${4}"
222  fi
223  local productsign_id=""
224  if [[ ${#} -ge 5 ]]; then
225    productsign_id="${5}"
226  fi
227
228  if [[ "${do_sign_binaries}" == 1 && -z "${codesign_id}" ]]; then
229    err_exit "Can't sign binaries - please specify a codesign_id"
230  fi
231
232  setup "${input_dir}"
233  verify_clean_dir "${output_dir}"
234
235  if [[ "${do_sign_binaries}" == 1 ]]; then
236    sign_binaries "${input_dir}" "${keychain}" "${codesign_id}"
237  fi
238  build_packages "${input_dir}"
239  if [[ "${do_sign_binaries}" == 1 && -n "${productsign_id}" ]]; then
240    echo "Signing installer..."
241    sign_installer "${input_dir}" "${keychain}" "${productsign_id}"
242  fi
243  build_dmg "${input_dir}" "${output_dir}"
244
245  cleanup
246}
247
248if [[ ${#} < 2 ]]; then
249  usage
250  exit 1
251fi
252
253main "${@}"
254exit ${?}
255