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