build.sh revision 116680a4aac90f2aa7413d9095a592090648e557
1#!/bin/bash
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# TODO(mmoss) This currently only works with official builds, since non-official
8# builds don't add the "${BUILDDIR}/installer/" files needed for packaging.
9
10set -e
11if [ "$VERBOSE" ]; then
12  set -x
13fi
14set -u
15
16# Create the Debian changelog file needed by dpkg-gencontrol. This just adds a
17# placeholder change, indicating it is the result of an automatic build.
18# TODO(mmoss) Release packages should create something meaningful for a
19# changelog, but simply grabbing the actual 'svn log' is way too verbose. Do we
20# have any type of "significant/visible changes" log that we could use for this?
21gen_changelog() {
22  rm -f "${DEB_CHANGELOG}"
23  process_template "${SCRIPTDIR}/changelog.template" "${DEB_CHANGELOG}"
24  debchange -a --nomultimaint -m --changelog "${DEB_CHANGELOG}" \
25    "Release Notes: ${RELEASENOTES}"
26  GZLOG="${STAGEDIR}/usr/share/doc/${PACKAGE}-${CHANNEL}/changelog.gz"
27  mkdir -p "$(dirname "${GZLOG}")"
28  gzip -9 -c "${DEB_CHANGELOG}" > "${GZLOG}"
29  chmod 644 "${GZLOG}"
30}
31
32# Create the Debian control file needed by dpkg-deb.
33gen_control() {
34  dpkg-gencontrol -v"${VERSIONFULL}" -c"${DEB_CONTROL}" -l"${DEB_CHANGELOG}" \
35  -f"${DEB_FILES}" -p"${PACKAGE}-${CHANNEL}" -P"${STAGEDIR}" \
36  -O > "${STAGEDIR}/DEBIAN/control"
37  rm -f "${DEB_CONTROL}"
38}
39
40# Setup the installation directory hierachy in the package staging area.
41prep_staging_debian() {
42  prep_staging_common
43  install -m 755 -d "${STAGEDIR}/DEBIAN" \
44    "${STAGEDIR}/etc/cron.daily" \
45    "${STAGEDIR}/usr/share/menu" \
46    "${STAGEDIR}/usr/share/doc/${PACKAGE}"
47}
48
49# Put the package contents in the staging area.
50stage_install_debian() {
51  # Always use a different name for /usr/bin symlink depending on channel.
52  # First, to avoid file collisions. Second, to make it possible to
53  # use update-alternatives for /usr/bin/google-chrome.
54  local USR_BIN_SYMLINK_NAME="${PACKAGE}-${CHANNEL}"
55
56  if [ "$CHANNEL" != "stable" ]; then
57    # This would ideally be compiled into the app, but that's a bit too
58    # intrusive of a change for these limited use channels, so we'll just hack
59    # it into the wrapper script. The user can still override since it seems to
60    # work to specify --user-data-dir multiple times on the command line, with
61    # the last occurrence winning.
62    local SXS_USER_DATA_DIR="\${XDG_CONFIG_HOME:-\${HOME}/.config}/${PACKAGE}-${CHANNEL}"
63    local DEFAULT_FLAGS="--user-data-dir=\"${SXS_USER_DATA_DIR}\""
64
65    # Avoid file collisions between channels.
66    local INSTALLDIR="${INSTALLDIR}-${CHANNEL}"
67
68    local PACKAGE="${PACKAGE}-${CHANNEL}"
69
70    # Make it possible to distinguish between menu entries
71    # for different channels.
72    local MENUNAME="${MENUNAME} (${CHANNEL})"
73  fi
74  prep_staging_debian
75  stage_install_common
76  echo "Staging Debian install files in '${STAGEDIR}'..."
77  install -m 755 -d "${STAGEDIR}/${INSTALLDIR}/cron"
78  process_template "${BUILDDIR}/installer/common/repo.cron" \
79      "${STAGEDIR}/${INSTALLDIR}/cron/${PACKAGE}"
80  chmod 755 "${STAGEDIR}/${INSTALLDIR}/cron/${PACKAGE}"
81  pushd "${STAGEDIR}/etc/cron.daily/"
82  ln -snf "${INSTALLDIR}/cron/${PACKAGE}" "${PACKAGE}"
83  popd
84  process_template "${BUILDDIR}/installer/debian/debian.menu" \
85    "${STAGEDIR}/usr/share/menu/${PACKAGE}.menu"
86  chmod 644 "${STAGEDIR}/usr/share/menu/${PACKAGE}.menu"
87  process_template "${BUILDDIR}/installer/debian/postinst" \
88    "${STAGEDIR}/DEBIAN/postinst"
89  chmod 755 "${STAGEDIR}/DEBIAN/postinst"
90  process_template "${BUILDDIR}/installer/debian/prerm" \
91    "${STAGEDIR}/DEBIAN/prerm"
92  chmod 755 "${STAGEDIR}/DEBIAN/prerm"
93  process_template "${BUILDDIR}/installer/debian/postrm" \
94    "${STAGEDIR}/DEBIAN/postrm"
95  chmod 755 "${STAGEDIR}/DEBIAN/postrm"
96}
97
98# Actually generate the package file.
99do_package() {
100  echo "Packaging ${ARCHITECTURE}..."
101  PREDEPENDS="$COMMON_PREDEPS"
102  DEPENDS="${COMMON_DEPS}"
103  REPLACES=""
104  CONFLICTS=""
105  PROVIDES="www-browser"
106  gen_changelog
107  process_template "${SCRIPTDIR}/control.template" "${DEB_CONTROL}"
108  export DEB_HOST_ARCH="${ARCHITECTURE}"
109  if [ -f "${DEB_CONTROL}" ]; then
110    gen_control
111  fi
112  fakeroot dpkg-deb -Zlzma -b "${STAGEDIR}" .
113}
114
115# Remove temporary files and unwanted packaging output.
116cleanup() {
117  echo "Cleaning..."
118  rm -rf "${STAGEDIR}"
119  rm -rf "${TMPFILEDIR}"
120}
121
122usage() {
123  echo "usage: $(basename $0) [-c channel] [-a target_arch] [-o 'dir'] "
124  echo "                      [-b 'dir']"
125  echo "-c channel the package channel (trunk, asan, unstable, beta, stable)"
126  echo "-a arch    package architecture (ia32 or x64)"
127  echo "-o dir     package output directory [${OUTPUTDIR}]"
128  echo "-b dir     build input directory    [${BUILDDIR}]"
129  echo "-h         this help message"
130}
131
132# Check that the channel name is one of the allowable ones.
133verify_channel() {
134  case $CHANNEL in
135    stable )
136      CHANNEL=stable
137      RELEASENOTES="http://googlechromereleases.blogspot.com/search/label/Stable%20updates"
138      ;;
139    unstable|dev|alpha )
140      CHANNEL=unstable
141      RELEASENOTES="http://googlechromereleases.blogspot.com/search/label/Dev%20updates"
142      ;;
143    testing|beta )
144      CHANNEL=beta
145      RELEASENOTES="http://googlechromereleases.blogspot.com/search/label/Beta%20updates"
146      ;;
147    trunk|asan )
148      # Setting this to empty will prevent it from updating any existing configs
149      # from release packages.
150      REPOCONFIG=""
151      RELEASENOTES="http://googlechromereleases.blogspot.com/"
152      ;;
153    * )
154      echo
155      echo "ERROR: '$CHANNEL' is not a valid channel type."
156      echo
157      exit 1
158      ;;
159  esac
160}
161
162process_opts() {
163  while getopts ":o:b:c:a:h" OPTNAME
164  do
165    case $OPTNAME in
166      o )
167        OUTPUTDIR=$(readlink -f "${OPTARG}")
168        mkdir -p "${OUTPUTDIR}"
169        ;;
170      b )
171        BUILDDIR=$(readlink -f "${OPTARG}")
172        ;;
173      c )
174        CHANNEL="$OPTARG"
175        ;;
176      a )
177        TARGETARCH="$OPTARG"
178        ;;
179      h )
180        usage
181        exit 0
182        ;;
183      \: )
184        echo "'-$OPTARG' needs an argument."
185        usage
186        exit 1
187        ;;
188      * )
189        echo "invalid command-line option: $OPTARG"
190        usage
191        exit 1
192        ;;
193    esac
194  done
195}
196
197#=========
198# MAIN
199#=========
200
201SCRIPTDIR=$(readlink -f "$(dirname "$0")")
202OUTPUTDIR="${PWD}"
203STAGEDIR=$(mktemp -d -t deb.build.XXXXXX) || exit 1
204TMPFILEDIR=$(mktemp -d -t deb.tmp.XXXXXX) || exit 1
205DEB_CHANGELOG="${TMPFILEDIR}/changelog"
206DEB_FILES="${TMPFILEDIR}/files"
207DEB_CONTROL="${TMPFILEDIR}/control"
208CHANNEL="trunk"
209# Default target architecture to same as build host.
210if [ "$(uname -m)" = "x86_64" ]; then
211  TARGETARCH="x64"
212else
213  TARGETARCH="ia32"
214fi
215
216# call cleanup() on exit
217trap cleanup 0
218process_opts "$@"
219if [ ! "$BUILDDIR" ]; then
220  BUILDDIR=$(readlink -f "${SCRIPTDIR}/../../../../../out/Release")
221fi
222
223source ${BUILDDIR}/installer/common/installer.include
224
225get_version_info
226VERSIONFULL="${VERSION}-${PACKAGE_RELEASE}"
227
228if [ "$CHROMIUM_BUILD" = "_google_chrome" ]; then
229  source "${BUILDDIR}/installer/common/google-chrome.info"
230else
231  source "${BUILDDIR}/installer/common/chromium-browser.info"
232fi
233eval $(sed -e "s/^\([^=]\+\)=\(.*\)$/export \1='\2'/" \
234  "${BUILDDIR}/installer/theme/BRANDING")
235
236REPOCONFIG="deb http://dl.google.com/linux/chrome/deb/ stable main"
237verify_channel
238
239# Some Debian packaging tools want these set.
240export DEBFULLNAME="${MAINTNAME}"
241export DEBEMAIL="${MAINTMAIL}"
242
243# We'd like to eliminate more of these deps by relying on the 'lsb' package, but
244# that brings in tons of unnecessary stuff, like an mta and rpm. Until that full
245# 'lsb' package is installed by default on DEB distros, we'll have to stick with
246# the LSB sub-packages, to avoid pulling in all that stuff that's not installed
247# by default.
248
249# Need a dummy debian/control file for dpkg-shlibdeps.
250DUMMY_STAGING_DIR="${TMPFILEDIR}/dummy_staging"
251mkdir "$DUMMY_STAGING_DIR"
252cd "$DUMMY_STAGING_DIR"
253mkdir debian
254touch debian/control
255
256# Generate the dependencies,
257# TODO(mmoss): This is a workaround for a problem where dpkg-shlibdeps was
258# resolving deps using some of our build output shlibs (i.e.
259# out/Release/lib.target/libfreetype.so.6), and was then failing with:
260#   dpkg-shlibdeps: error: no dependency information found for ...
261# It's not clear if we ever want to look in LD_LIBRARY_PATH to resolve deps,
262# but it seems that we don't currently, so this is the most expediant fix.
263SAVE_LDLP=${LD_LIBRARY_PATH:-}
264unset LD_LIBRARY_PATH
265DPKG_SHLIB_DEPS=$(dpkg-shlibdeps -O "$BUILDDIR/chrome" 2> /dev/null | \
266  sed 's/^shlibs:Depends=//')
267if [ -n "$SAVE_LDLP" ]; then
268  LD_LIBRARY_PATH=$SAVE_LDLP
269fi
270
271# Format it nicely and save it for comparison.
272# The grep -v is for a duplicate libc6 dep caused by Lucid glibc silliness.
273echo "$DPKG_SHLIB_DEPS" | sed 's/, /\n/g' | \
274  grep -v '^libc6 (>= 2.3.6-6~)$' > actual
275
276# Compare the expected dependency list to the generate list.
277BAD_DIFF=0
278diff "$SCRIPTDIR/expected_deps_$TARGETARCH" actual || BAD_DIFF=1
279if [ $BAD_DIFF -ne 0 ] && [ -z "${IGNORE_DEPS_CHANGES:-}" ]; then
280  echo
281  echo "ERROR: Shared library dependencies changed!"
282  echo "If this is intentional, please update:"
283  echo "chrome/installer/linux/debian/expected_deps_ia32"
284  echo "chrome/installer/linux/debian/expected_deps_x64"
285  echo
286  exit $BAD_DIFF
287fi
288rm -rf "$DUMMY_STAGING_DIR"
289
290# Additional dependencies not in the dpkg-shlibdeps output.
291# Pull a more recent version of NSS than required by runtime linking, for
292# security and stability updates in NSS.
293ADDITION_DEPS="ca-certificates, libappindicator1, libcurl3, \
294  libnss3 (>= 3.14.3), lsb-base (>=3.2), xdg-utils (>= 1.0.2), wget"
295
296# Fix-up libnspr dependency due to renaming in Ubuntu (the old package still
297# exists, but it was moved to "universe" repository, which isn't installed by
298# default).
299DPKG_SHLIB_DEPS=$(sed \
300    's/\(libnspr4-0d ([^)]*)\), /\1 | libnspr4 (>= 4.9.5-0ubuntu0), /g' \
301    <<< $DPKG_SHLIB_DEPS)
302
303# Fix-up libudev dependency because Ubuntu 13.04 has libudev1 instead of
304# libudev0.
305DPKG_SHLIB_DEPS=$(sed 's/\(libudev0 ([^)]*)\), /\1 | libudev1 (>= 198), /g' \
306                  <<< $DPKG_SHLIB_DEPS)
307
308COMMON_DEPS="${DPKG_SHLIB_DEPS}, ${ADDITION_DEPS}"
309COMMON_PREDEPS="dpkg (>= 1.14.0)"
310
311
312# Make everything happen in the OUTPUTDIR.
313cd "${OUTPUTDIR}"
314
315case "$TARGETARCH" in
316  ia32 )
317    export ARCHITECTURE="i386"
318    stage_install_debian
319    ;;
320  x64 )
321    export ARCHITECTURE="amd64"
322    stage_install_debian
323    ;;
324  * )
325    echo
326    echo "ERROR: Don't know how to build DEBs for '$TARGETARCH'."
327    echo
328    exit 1
329    ;;
330esac
331
332do_package
333