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