Home | History | Annotate | Download | only in debian
      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 
     10 set -e
     11 if [ "$VERBOSE" ]; then
     12   set -x
     13 fi
     14 set -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?
     21 gen_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.
     33 gen_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.
     41 prep_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.
     50 stage_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.
    121 do_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.
    142 cleanup() {
    143   echo "Cleaning..."
    144   rm -rf "${STAGEDIR}"
    145   rm -rf "${TMPFILEDIR}"
    146 }
    147 
    148 usage() {
    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.
    159 verify_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 
    188 process_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 
    227 SCRIPTDIR=$(readlink -f "$(dirname "$0")")
    228 OUTPUTDIR="${PWD}"
    229 STAGEDIR=$(mktemp -d -t deb.build.XXXXXX) || exit 1
    230 TMPFILEDIR=$(mktemp -d -t deb.tmp.XXXXXX) || exit 1
    231 DEB_CHANGELOG="${TMPFILEDIR}/changelog"
    232 DEB_FILES="${TMPFILEDIR}/files"
    233 DEB_CONTROL="${TMPFILEDIR}/control"
    234 CHANNEL="trunk"
    235 # Default target architecture to same as build host.
    236 if [ "$(uname -m)" = "x86_64" ]; then
    237   TARGETARCH="x64"
    238 else
    239   TARGETARCH="ia32"
    240 fi
    241 
    242 # call cleanup() on exit
    243 trap cleanup 0
    244 process_opts "$@"
    245 if [ ! "$BUILDDIR" ]; then
    246   BUILDDIR=$(readlink -f "${SCRIPTDIR}/../../../../../out/Release")
    247 fi
    248 
    249 source ${BUILDDIR}/installer/common/installer.include
    250 
    251 get_version_info
    252 VERSIONFULL="${VERSION}-${PACKAGE_RELEASE}"
    253 
    254 if [ "$CHROMIUM_BUILD" = "_google_chrome" ]; then
    255   source "${BUILDDIR}/installer/common/google-chrome.info"
    256 else
    257   source "${BUILDDIR}/installer/common/chromium-browser.info"
    258 fi
    259 eval $(sed -e "s/^\([^=]\+\)=\(.*\)$/export \1='\2'/" \
    260   "${BUILDDIR}/installer/theme/BRANDING")
    261 
    262 REPOCONFIG="deb http://dl.google.com/linux/chrome/deb/ stable main"
    263 verify_channel
    264 
    265 # Some Debian packaging tools want these set.
    266 export DEBFULLNAME="${MAINTNAME}"
    267 export 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.
    276 DUMMY_STAGING_DIR="${TMPFILEDIR}/dummy_staging"
    277 mkdir "$DUMMY_STAGING_DIR"
    278 cd "$DUMMY_STAGING_DIR"
    279 mkdir debian
    280 touch 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.
    289 SAVE_LDLP=${LD_LIBRARY_PATH:-}
    290 unset LD_LIBRARY_PATH
    291 DPKG_SHLIB_DEPS=$(dpkg-shlibdeps -O "$BUILDDIR/chrome" 2> /dev/null | \
    292   sed 's/^shlibs:Depends=//')
    293 if [ -n "$SAVE_LDLP" ]; then
    294   LD_LIBRARY_PATH=$SAVE_LDLP
    295 fi
    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.
    299 echo "$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.
    303 BAD_DIFF=0
    304 diff "$SCRIPTDIR/expected_deps" actual || BAD_DIFF=1
    305 if [ $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
    312 fi
    313 rm -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.
    318 ADDITION_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).
    324 DPKG_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.
    330 DPKG_SHLIB_DEPS=$(sed 's/\(libudev0 ([^)]*)\), /\1 | libudev1 (>= 198), /g' \
    331                   <<< $DPKG_SHLIB_DEPS)
    332 
    333 COMMON_DEPS="${DPKG_SHLIB_DEPS}, ${ADDITION_DEPS}"
    334 COMMON_PREDEPS="dpkg (>= 1.14.0)"
    335 
    336 
    337 # Make everything happen in the OUTPUTDIR.
    338 cd "${OUTPUTDIR}"
    339 
    340 case "$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     ;;
    355 esac
    356 
    357 do_package
    358