build.sh revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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    # TODO(phajdan.jr): Do that for all packages for SxS,
69    # http://crbug.com/38598 .
70    if [ "$CHANNEL" = "trunk" ] || [ "$CHANNEL" = "asan" ]; then
71      local PACKAGE="${PACKAGE}-${CHANNEL}"
72    fi
73
74    # Make it possible to distinguish between menu entries
75    # for different channels.
76    local MENUNAME="${MENUNAME} (${CHANNEL})"
77  fi
78  prep_staging_debian
79  stage_install_common
80  echo "Staging Debian install files in '${STAGEDIR}'..."
81  install -m 755 -d "${STAGEDIR}/${INSTALLDIR}/cron"
82  process_template "${BUILDDIR}/installer/common/repo.cron" \
83      "${STAGEDIR}/${INSTALLDIR}/cron/${PACKAGE}"
84  chmod 755 "${STAGEDIR}/${INSTALLDIR}/cron/${PACKAGE}"
85  pushd "${STAGEDIR}/etc/cron.daily/"
86  ln -snf "${INSTALLDIR}/cron/${PACKAGE}" "${PACKAGE}"
87  popd
88  process_template "${BUILDDIR}/installer/debian/debian.menu" \
89    "${STAGEDIR}/usr/share/menu/${PACKAGE}.menu"
90  chmod 644 "${STAGEDIR}/usr/share/menu/${PACKAGE}.menu"
91  process_template "${BUILDDIR}/installer/debian/postinst" \
92    "${STAGEDIR}/DEBIAN/postinst"
93  chmod 755 "${STAGEDIR}/DEBIAN/postinst"
94  process_template "${BUILDDIR}/installer/debian/prerm" \
95    "${STAGEDIR}/DEBIAN/prerm"
96  chmod 755 "${STAGEDIR}/DEBIAN/prerm"
97  process_template "${BUILDDIR}/installer/debian/postrm" \
98    "${STAGEDIR}/DEBIAN/postrm"
99  chmod 755 "${STAGEDIR}/DEBIAN/postrm"
100}
101
102# Actually generate the package file.
103do_package() {
104  echo "Packaging ${ARCHITECTURE}..."
105  PREDEPENDS="$COMMON_PREDEPS"
106  DEPENDS="${COMMON_DEPS}"
107  # Trunk is a special package, mostly for development testing, so don't make
108  # it replace any installed release packages.
109  if [ "$CHANNEL" != "trunk" ] && [ "$CHANNEL" != "asan" ]; then
110    REPLACES="${PACKAGE}"
111    CONFLICTS="${PACKAGE}"
112    PROVIDES="${PACKAGE}, www-browser"
113  fi
114  gen_changelog
115  process_template "${SCRIPTDIR}/control.template" "${DEB_CONTROL}"
116  export DEB_HOST_ARCH="${ARCHITECTURE}"
117  if [ -f "${DEB_CONTROL}" ]; then
118    gen_control
119  fi
120  fakeroot dpkg-deb -Zlzma -b "${STAGEDIR}" .
121}
122
123# Remove temporary files and unwanted packaging output.
124cleanup() {
125  echo "Cleaning..."
126  rm -rf "${STAGEDIR}"
127  rm -rf "${TMPFILEDIR}"
128}
129
130usage() {
131  echo "usage: $(basename $0) [-c channel] [-a target_arch] [-o 'dir'] "
132  echo "                      [-b 'dir']"
133  echo "-c channel the package channel (trunk, asan, unstable, beta, stable)"
134  echo "-a arch    package architecture (ia32 or x64)"
135  echo "-o dir     package output directory [${OUTPUTDIR}]"
136  echo "-b dir     build input directory    [${BUILDDIR}]"
137  echo "-h         this help message"
138}
139
140# Check that the channel name is one of the allowable ones.
141verify_channel() {
142  case $CHANNEL in
143    stable )
144      CHANNEL=stable
145      RELEASENOTES="http://googlechromereleases.blogspot.com/search/label/Stable%20updates"
146      ;;
147    unstable|dev|alpha )
148      CHANNEL=unstable
149      RELEASENOTES="http://googlechromereleases.blogspot.com/search/label/Dev%20updates"
150      ;;
151    testing|beta )
152      CHANNEL=beta
153      RELEASENOTES="http://googlechromereleases.blogspot.com/search/label/Beta%20updates"
154      ;;
155    trunk|asan )
156      # Setting this to empty will prevent it from updating any existing configs
157      # from release packages.
158      REPOCONFIG=""
159      RELEASENOTES="http://googlechromereleases.blogspot.com/"
160      ;;
161    * )
162      echo
163      echo "ERROR: '$CHANNEL' is not a valid channel type."
164      echo
165      exit 1
166      ;;
167  esac
168}
169
170process_opts() {
171  while getopts ":o:b:c:a:h" OPTNAME
172  do
173    case $OPTNAME in
174      o )
175        OUTPUTDIR=$(readlink -f "${OPTARG}")
176        mkdir -p "${OUTPUTDIR}"
177        ;;
178      b )
179        BUILDDIR=$(readlink -f "${OPTARG}")
180        ;;
181      c )
182        CHANNEL="$OPTARG"
183        ;;
184      a )
185        TARGETARCH="$OPTARG"
186        ;;
187      h )
188        usage
189        exit 0
190        ;;
191      \: )
192        echo "'-$OPTARG' needs an argument."
193        usage
194        exit 1
195        ;;
196      * )
197        echo "invalid command-line option: $OPTARG"
198        usage
199        exit 1
200        ;;
201    esac
202  done
203}
204
205#=========
206# MAIN
207#=========
208
209SCRIPTDIR=$(readlink -f "$(dirname "$0")")
210OUTPUTDIR="${PWD}"
211STAGEDIR=$(mktemp -d -t deb.build.XXXXXX) || exit 1
212TMPFILEDIR=$(mktemp -d -t deb.tmp.XXXXXX) || exit 1
213DEB_CHANGELOG="${TMPFILEDIR}/changelog"
214DEB_FILES="${TMPFILEDIR}/files"
215DEB_CONTROL="${TMPFILEDIR}/control"
216CHANNEL="trunk"
217# Default target architecture to same as build host.
218if [ "$(uname -m)" = "x86_64" ]; then
219  TARGETARCH="x64"
220else
221  TARGETARCH="ia32"
222fi
223
224# call cleanup() on exit
225trap cleanup 0
226process_opts "$@"
227if [ ! "$BUILDDIR" ]; then
228  BUILDDIR=$(readlink -f "${SCRIPTDIR}/../../../../../out/Release")
229fi
230
231source ${BUILDDIR}/installer/common/installer.include
232
233get_version_info
234VERSIONFULL="${VERSION}-${PACKAGE_RELEASE}"
235
236if [ "$CHROMIUM_BUILD" = "_google_chrome" ]; then
237  source "${BUILDDIR}/installer/common/google-chrome.info"
238else
239  source "${BUILDDIR}/installer/common/chromium-browser.info"
240fi
241eval $(sed -e "s/^\([^=]\+\)=\(.*\)$/export \1='\2'/" \
242  "${BUILDDIR}/installer/theme/BRANDING")
243
244REPOCONFIG="deb http://dl.google.com/linux/chrome/deb/ stable main"
245verify_channel
246
247# Some Debian packaging tools want these set.
248export DEBFULLNAME="${MAINTNAME}"
249export DEBEMAIL="${MAINTMAIL}"
250
251# We'd like to eliminate more of these deps by relying on the 'lsb' package, but
252# that brings in tons of unnecessary stuff, like an mta and rpm. Until that full
253# 'lsb' package is installed by default on DEB distros, we'll have to stick with
254# the LSB sub-packages, to avoid pulling in all that stuff that's not installed
255# by default.
256
257# Need a dummy debian/control file for dpkg-shlibdeps.
258DUMMY_STAGING_DIR="${TMPFILEDIR}/dummy_staging"
259mkdir "$DUMMY_STAGING_DIR"
260cd "$DUMMY_STAGING_DIR"
261mkdir debian
262touch debian/control
263
264# Generate the dependencies,
265# TODO(mmoss): This is a workaround for a problem where dpkg-shlibdeps was
266# resolving deps using some of our build output shlibs (i.e.
267# out/Release/lib.target/libfreetype.so.6), and was then failing with:
268#   dpkg-shlibdeps: error: no dependency information found for ...
269# It's not clear if we ever want to look in LD_LIBRARY_PATH to resolve deps,
270# but it seems that we don't currently, so this is the most expediant fix.
271SAVE_LDLP=${LD_LIBRARY_PATH:-}
272unset LD_LIBRARY_PATH
273DPKG_SHLIB_DEPS=$(dpkg-shlibdeps -O "$BUILDDIR/chrome" 2> /dev/null | \
274  sed 's/^shlibs:Depends=//')
275if [ -n "$SAVE_LDLP" ]; then
276  LD_LIBRARY_PATH=$SAVE_LDLP
277fi
278
279# Format it nicely and save it for comparison.
280# The grep -v is for a duplicate libc6 dep caused by Lucid glibc silliness.
281echo "$DPKG_SHLIB_DEPS" | sed 's/, /\n/g' | \
282  grep -v '^libc6 (>= 2.3.6-6~)$' > actual
283
284# Compare the expected dependency list to the generate list.
285BAD_DIFF=0
286diff "$SCRIPTDIR/expected_deps" actual || BAD_DIFF=1
287if [ $BAD_DIFF -ne 0 ] && [ -z "${IGNORE_DEPS_CHANGES:-}" ]; then
288  echo
289  echo "ERROR: Shared library dependencies changed!"
290  echo "If this is intentional, please update:"
291  echo "chrome/installer/linux/debian/expected_deps"
292  echo
293  exit $BAD_DIFF
294fi
295rm -rf "$DUMMY_STAGING_DIR"
296
297# Additional dependencies not in the dpkg-shlibdeps output.
298# Pull a more recent version of NSS than required by runtime linking, for
299# security and stability updates in NSS.
300ADDITION_DEPS="ca-certificates, libcurl3, libnss3 (>= 3.14.3), \
301  lsb-base (>=3.2), xdg-utils (>= 1.0.2), wget"
302
303# Fix-up libnspr dependency due to renaming in Ubuntu (the old package still
304# exists, but it was moved to "universe" repository, which isn't installed by
305# default).
306DPKG_SHLIB_DEPS=$(sed \
307    's/\(libnspr4-0d ([^)]*)\), /\1 | libnspr4 (>= 4.9.5-0ubuntu0), /g' \
308    <<< $DPKG_SHLIB_DEPS)
309
310# Fix-up libudev dependency because Ubuntu 13.04 has libudev1 instead of
311# libudev0.
312DPKG_SHLIB_DEPS=$(sed 's/\(libudev0 ([^)]*)\), /\1 | libudev1 (>= 198), /g' \
313                  <<< $DPKG_SHLIB_DEPS)
314
315COMMON_DEPS="${DPKG_SHLIB_DEPS}, ${ADDITION_DEPS}"
316COMMON_PREDEPS="dpkg (>= 1.14.0)"
317
318
319# Make everything happen in the OUTPUTDIR.
320cd "${OUTPUTDIR}"
321
322case "$TARGETARCH" in
323  ia32 )
324    export ARCHITECTURE="i386"
325    stage_install_debian
326    ;;
327  x64 )
328    export ARCHITECTURE="amd64"
329    stage_install_debian
330    ;;
331  * )
332    echo
333    echo "ERROR: Don't know how to build DEBs for '$TARGETARCH'."
334    echo
335    exit 1
336    ;;
337esac
338
339do_package
340