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