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