blob: 73d801aac4ed8e3861fc38286c73d21ad216c4b4 [file] [log] [blame]
# Shows the output of a given command only on failure, or when VERBOSE is set.
log_cmd() {
if [ "${VERBOSE:-}" ]; then
"$@"
else
# Record $- into a separate variable because it gets reset in the subshell.
FORWARD_SHELL_OPTS=$-
ERREXIT=$(echo ${FORWARD_SHELL_OPTS} | grep -o e || true)
set +${ERREXIT}
CMD_OUTPUT=$("$@" 2>&1)
ERRCODE=$?
set -${ERREXIT}
if [ ${ERRCODE} -ne 0 ]; then
echo "$@"
echo "${CMD_OUTPUT}"
if [ ${ERREXIT} ]; then
exit ${ERRCODE}
fi
fi
fi
}
# Recursively replace @@include@@ template variables with the referenced file,
# and write the resulting text to stdout.
process_template_includes() {
INCSTACK+="$1->"
# Includes are relative to the file that does the include.
INCDIR=$(dirname $1)
# Clear IFS so 'read' doesn't trim whitespace
local OLDIFS="$IFS"
IFS=''
while read -r LINE
do
INCLINE=$(sed -e '/^[[:space:]]*@@include@@/!d' <<<$LINE)
if [ -n "$INCLINE" ]; then
INCFILE=$(echo $INCLINE | sed -e "s#@@include@@\(.*\)#\1#")
# Simple filename match to detect cyclic includes.
CYCLE=$(sed -e "\#$INCFILE#"'!d' <<<$INCSTACK)
if [ "$CYCLE" ]; then
echo "ERROR: Possible cyclic include detected." 1>&2
echo "$INCSTACK$INCFILE" 1>&2
exit 1
fi
if [ ! -r "$INCDIR/$INCFILE" ]; then
echo "ERROR: Couldn't read include file: $INCDIR/$INCFILE" 1>&2
exit 1
fi
process_template_includes "$INCDIR/$INCFILE"
else
echo "$LINE"
fi
done < "$1"
IFS="$OLDIFS"
INCSTACK=${INCSTACK%"$1->"}
}
# Replace template variables (@@VARNAME@@) in the given template file. If a
# second argument is given, save the processed text to that filename, otherwise
# modify the template file in place.
process_template() (
# Don't worry if some of these substitution variables aren't set.
# Note that this function is run in a sub-shell so we don't leak this
# setting, since we still want unbound variables to be an error elsewhere.
set +u
local TMPLIN="$1"
if [ -z "$2" ]; then
local TMPLOUT="$TMPLIN"
else
local TMPLOUT="$2"
fi
# Process includes first so included text also gets substitutions.
TMPLINCL="$(process_template_includes "$TMPLIN")"
sed \
-e "s#@@PACKAGE@@#${PACKAGE}#g" \
-e "s#@@PACKAGE_ORIG@@#${PACKAGE_ORIG}#g" \
-e "s#@@PACKAGE_FILENAME@@#${PACKAGE_FILENAME}#g" \
-e "s#@@PROGNAME@@#${PROGNAME}#g" \
-e "s#@@CHANNEL@@#${CHANNEL}#g" \
-e "s#@@COMPANY_FULLNAME@@#${COMPANY_FULLNAME}#g" \
-e "s#@@VERSION@@#${VERSION}#g" \
-e "s#@@PACKAGE_RELEASE@@#${PACKAGE_RELEASE}#g" \
-e "s#@@VERSIONFULL@@#${VERSIONFULL}#g" \
-e "s#@@INSTALLDIR@@#${INSTALLDIR}#g" \
-e "s#@@BUILDDIR@@#${BUILDDIR}#g" \
-e "s#@@STAGEDIR@@#${STAGEDIR}#g" \
-e "s#@@SCRIPTDIR@@#${SCRIPTDIR}#g" \
-e "s#@@MENUNAME@@#${MENUNAME}#g" \
-e "s#@@PRODUCTURL@@#${PRODUCTURL}#g" \
-e "s#@@PREDEPENDS@@#${PREDEPENDS}#g" \
-e "s#@@DEPENDS@@#${DEPENDS}#g" \
-e "s#@@PROVIDES@@#${PROVIDES}#g" \
-e "s#@@ARCHITECTURE@@#${ARCHITECTURE}#g" \
-e "s#@@MAINTNAME@@#${MAINTNAME}#g" \
-e "s#@@MAINTMAIL@@#${MAINTMAIL}#g" \
-e "s#@@REPOCONFIG@@#${REPOCONFIG}#g" \
-e "s#@@REPOCONFIGREGEX@@#${REPOCONFIGREGEX}#g" \
-e "s#@@SHORTDESC@@#${SHORTDESC}#g" \
-e "s#@@FULLDESC@@#${FULLDESC}#g" \
-e "s#@@USR_BIN_SYMLINK_NAME@@#${USR_BIN_SYMLINK_NAME:-}#g" \
-e "s#@@LOGO_RESOURCES_PNG@@#${LOGO_RESOURCES_PNG}#g" \
-e "s#@@LOGO_RESOURCE_XPM@@#${LOGO_RESOURCE_XPM}#g" \
> "$TMPLOUT" <<< "$TMPLINCL"
)
# Setup the installation directory hierachy in the package staging area.
prep_staging_common() {
install -m 755 -d "${STAGEDIR}/${INSTALLDIR}" \
"${STAGEDIR}/usr/bin" \
"${STAGEDIR}/usr/share/applications" \
"${STAGEDIR}/usr/share/appdata" \
"${STAGEDIR}/usr/share/gnome-control-center/default-apps" \
"${STAGEDIR}/usr/share/man/man1"
}
get_version_info() {
source "${BUILDDIR}/installer/version.txt"
VERSION="${MAJOR}.${MINOR}.${BUILD}.${PATCH}"
# TODO(phajdan.jr): Provide a mechanism to pass a different package
# release number if needed. The meaning of it is to bump it for
# packaging-only changes while the underlying software has the same version.
# This corresponds to the Release field in RPM spec files and debian_revision
# component of the Version field for DEB control file.
# Generally with Chrome's fast release cycle it'd be more hassle to try
# to bump this number between releases.
PACKAGE_RELEASE="1"
}
stage_install_common() {
log_cmd echo "Staging common install files in '${STAGEDIR}'..."
# Note: Changes here may also need to be applied to ChromeOS's
# chromite/lib/chrome_util.py.
# Note: This only supports static binaries and does not work when the GN
# is_component_build flag is true.
# app
STRIPPEDFILE="${BUILDDIR}/${PROGNAME}.stripped"
install -m 755 "${STRIPPEDFILE}" "${STAGEDIR}/${INSTALLDIR}/${PROGNAME}"
# resources
install -m 644 "${BUILDDIR}/resources.pak" "${STAGEDIR}/${INSTALLDIR}/"
# TODO(mmoss): This has broken a couple times on adding new .pak files. Maybe
# we should flag all installer files in FILES.cfg and get them from there, so
# there's only one place people need to keep track of such things (and in
# only the public repository).
if [ -r "${BUILDDIR}/chrome_100_percent.pak" ]; then
install -m 644 "${BUILDDIR}/chrome_100_percent.pak" "${STAGEDIR}/${INSTALLDIR}/"
install -m 644 "${BUILDDIR}/chrome_200_percent.pak" "${STAGEDIR}/${INSTALLDIR}/"
else
install -m 644 "${BUILDDIR}/theme_resources_100_percent.pak" "${STAGEDIR}/${INSTALLDIR}/"
install -m 644 "${BUILDDIR}/ui_resources_100_percent.pak" "${STAGEDIR}/${INSTALLDIR}/"
fi
# ICU data file; Necessary when the GN icu_use_data_file flag is true.
install -m 644 "${BUILDDIR}/icudtl.dat" "${STAGEDIR}/${INSTALLDIR}/"
# V8 snapshot files; Necessary when the GN v8_use_external_startup_data flag
# is true.
install -m 644 "${BUILDDIR}/natives_blob.bin" "${STAGEDIR}/${INSTALLDIR}/"
install -m 644 "${BUILDDIR}/snapshot_blob.bin" "${STAGEDIR}/${INSTALLDIR}/"
# V8 context snapshot file; it will replace V8's snapshot_blob.bin
# TODO(peria): Remove snapshot_blob.bin when dependencies are resolved.
if [ -f "${BUILDDIR}/v8_context_snapshot.bin" ]; then
install -m 644 "${BUILDDIR}/v8_context_snapshot.bin" "${STAGEDIR}/${INSTALLDIR}/"
fi
# sandbox
# Rename sandbox binary with hyphen instead of underscore because that's what
# the code looks for. Originally, the SCons build system may have had a bug
# where it did not support hyphens, so this is stuck as is to avoid breaking
# anyone who expects the build artifact to have the underscore.
# the code looks for, but the build targets can't use hyphens (scons bug?)
buildfile="${BUILDDIR}/${PROGNAME}_sandbox"
strippedfile="${buildfile}.stripped"
debugfile="${buildfile}.debug"
"${BUILDDIR}/installer/common/eu-strip" -o "${strippedfile}" -f "${debugfile}" "${buildfile}"
install -m 4755 "${strippedfile}" "${STAGEDIR}/${INSTALLDIR}/${PROGNAME}-sandbox"
# l10n paks
install -m 755 -d "${STAGEDIR}/${INSTALLDIR}/locales/"
find "${BUILDDIR}/locales" -type f -name '*.pak' -exec \
cp -a '{}' "${STAGEDIR}/${INSTALLDIR}/locales/" \;
find "${STAGEDIR}/${INSTALLDIR}/locales" -type f -exec chmod 644 '{}' \;
# MEI Preload
if [ -f "${BUILDDIR}/MEIPreload/manifest.json" ]; then
install -m 755 -d "${STAGEDIR}/${INSTALLDIR}/MEIPreload/"
install -m 644 "${BUILDDIR}/MEIPreload/manifest.json" "${STAGEDIR}/${INSTALLDIR}/MEIPreload/"
install -m 644 "${BUILDDIR}/MEIPreload/preloaded_data.pb" "${STAGEDIR}/${INSTALLDIR}/MEIPreload/"
fi
# Widevine CDM.
if [ -f "${BUILDDIR}/libwidevinecdmadapter.so" ]; then
install -m ${SHLIB_PERMS} -s "${BUILDDIR}/libwidevinecdmadapter.so" "${STAGEDIR}/${INSTALLDIR}/"
# No need to strip; libwidevinecdm.so starts out stripped.
install -m ${SHLIB_PERMS} "${BUILDDIR}/libwidevinecdm.so" "${STAGEDIR}/${INSTALLDIR}/"
fi
# ANGLE
if [ -f "${BUILDDIR}/libEGL.so" ]; then
if [ "${CHANNEL}" != "stable" ]; then
for file in libEGL.so libGLESv2.so; do
buildfile="${BUILDDIR}/${file}"
strippedfile="${buildfile}.stripped"
debugfile="${buildfile}.debug"
"${BUILDDIR}/installer/common/eu-strip" -o "${strippedfile}" -f "${debugfile}" "${buildfile}"
install -m ${SHLIB_PERMS} "${strippedfile}" "${STAGEDIR}/${INSTALLDIR}/${file}"
done
fi
fi
# SwiftShader
if [ -f "${BUILDDIR}/swiftshader/libEGL.so" ]; then
install -m 755 -d "${STAGEDIR}/${INSTALLDIR}/swiftshader/"
for file in libEGL.so libGLESv2.so; do
buildfile="${BUILDDIR}/swiftshader/${file}"
strippedfile="${buildfile}.stripped"
debugfile="${buildfile}.debug"
"${BUILDDIR}/installer/common/eu-strip" -o "${strippedfile}" -f "${debugfile}" "${buildfile}"
install -m ${SHLIB_PERMS} "${strippedfile}" "${STAGEDIR}/${INSTALLDIR}/swiftshader/${file}"
done
fi
# libc++
if [ -f "${BUILDDIR}/lib/libc++.so" ]; then
install -m 755 -d "${STAGEDIR}/${INSTALLDIR}/lib/"
install -m ${SHLIB_PERMS} -s "${BUILDDIR}/lib/libc++.so" "${STAGEDIR}/${INSTALLDIR}/lib/"
fi
# nacl_helper and nacl_helper_bootstrap
# Don't use "-s" (strip) because this runs binutils "strip", which
# mangles the special ELF program headers of nacl_helper_bootstrap.
# Explicitly use eu-strip instead, because it doesn't have that problem.
for file in nacl_helper nacl_helper_bootstrap; do
buildfile="${BUILDDIR}/${file}"
if [ -f "${buildfile}" ]; then
strippedfile="${buildfile}.stripped"
debugfile="${buildfile}.debug"
"${BUILDDIR}/installer/common/eu-strip" -o "${strippedfile}" -f "${debugfile}" "${buildfile}"
install -m 755 "${strippedfile}" "${STAGEDIR}/${INSTALLDIR}/${file}"
fi
done
# Don't use "-s" (strip) because this would use the Linux toolchain to
# strip the NaCl binary, which has the potential to break it. It
# certainly resets the OSABI and ABIVERSION fields to non-NaCl values,
# although the NaCl IRT loader doesn't care about these fields. In any
# case, the IRT binaries are already stripped by NaCl's build process.
for filename in ${BUILDDIR}/nacl_irt_*.nexe; do
# Re-check the filename in case globbing matched nothing.
if [ -f "$filename" ]; then
install -m 644 "$filename" "${STAGEDIR}/${INSTALLDIR}/`basename "$filename"`"
fi
done
# default apps
if [ -d "${BUILDDIR}/default_apps" ]; then
cp -a "${BUILDDIR}/default_apps" "${STAGEDIR}/${INSTALLDIR}/"
find "${STAGEDIR}/${INSTALLDIR}/default_apps" -type d -exec chmod 755 '{}' \;
find "${STAGEDIR}/${INSTALLDIR}/default_apps" -type f -exec chmod 644 '{}' \;
fi
# launcher script and symlink
process_template "${BUILDDIR}/installer/common/wrapper" \
"${STAGEDIR}/${INSTALLDIR}/${PACKAGE}"
chmod 755 "${STAGEDIR}/${INSTALLDIR}/${PACKAGE}"
if [ ! -f "${STAGEDIR}/${INSTALLDIR}/${PACKAGE_ORIG}" ]; then
ln -sn "${INSTALLDIR}/${PACKAGE}" \
"${STAGEDIR}/${INSTALLDIR}/${PACKAGE_ORIG}"
fi
ln -snf "${INSTALLDIR}/${PACKAGE}" \
"${STAGEDIR}/usr/bin/${USR_BIN_SYMLINK_NAME}"
# app icons
local icon_regex=".*product_logo_[0-9]\+\."
if [ "$BRANDING" = "google_chrome" ]; then
if [ "$CHANNEL" = "beta" ]; then
icon_regex=".*product_logo_[0-9]\+_beta\."
elif [ "$CHANNEL" = "unstable" ]; then
icon_regex=".*product_logo_[0-9]\+_dev\."
fi
fi
LOGO_RESOURCES_PNG=$(find "${BUILDDIR}/installer/theme/" \
-regextype sed -regex "${icon_regex}png" -printf "%f ")
LOGO_RESOURCE_XPM=$(find "${BUILDDIR}/installer/theme/" \
-regextype sed -regex "${icon_regex}xpm" -printf "%f")
for logo in ${LOGO_RESOURCES_PNG} ${LOGO_RESOURCE_XPM}; do
install -m 644 \
"${BUILDDIR}/installer/theme/${logo}" \
"${STAGEDIR}/${INSTALLDIR}/"
done
# desktop integration
install -m 755 "${BUILDDIR}/xdg-mime" "${STAGEDIR}${INSTALLDIR}/"
install -m 755 "${BUILDDIR}/xdg-settings" "${STAGEDIR}${INSTALLDIR}/"
if [ ${PACKAGE:0:6} = google ]; then
process_template "${BUILDDIR}/installer/common/google-chrome.appdata.xml.template" \
"${STAGEDIR}/usr/share/appdata/${PACKAGE}.appdata.xml"
chmod 644 "${STAGEDIR}/usr/share/appdata/${PACKAGE}.appdata.xml"
else
install -m 644 "${BUILDDIR}/installer/common/chromium-browser.appdata.xml" \
"${STAGEDIR}/usr/share/appdata/${PACKAGE}.appdata.xml"
fi
process_template "${BUILDDIR}/installer/common/desktop.template" \
"${STAGEDIR}/usr/share/applications/${PACKAGE}.desktop"
chmod 644 "${STAGEDIR}/usr/share/applications/${PACKAGE}.desktop"
process_template "${BUILDDIR}/installer/common/default-app.template" \
"${STAGEDIR}/usr/share/gnome-control-center/default-apps/${PACKAGE}.xml"
chmod 644 "${STAGEDIR}/usr/share/gnome-control-center/default-apps/${PACKAGE}.xml"
process_template "${BUILDDIR}/installer/common/default-app-block.template" \
"${STAGEDIR}${INSTALLDIR}/default-app-block"
chmod 644 "${STAGEDIR}${INSTALLDIR}/default-app-block"
# documentation
process_template "${BUILDDIR}/installer/common/manpage.1.in" \
"${STAGEDIR}/usr/share/man/man1/${USR_BIN_SYMLINK_NAME}.1"
gzip -9n "${STAGEDIR}/usr/share/man/man1/${USR_BIN_SYMLINK_NAME}.1"
chmod 644 "${STAGEDIR}/usr/share/man/man1/${USR_BIN_SYMLINK_NAME}.1.gz"
# The stable channel allows launching the app without the "-stable"
# suffix like the other channels. Create a linked man page for the
# app-without-the-channel case.
if [ ! -f "${STAGEDIR}/usr/share/man/man1/${PACKAGE}.1.gz" ]; then
ln -s "${USR_BIN_SYMLINK_NAME}.1.gz" \
"${STAGEDIR}/usr/share/man/man1/${PACKAGE}.1.gz"
fi
# Check to make sure all the ELF binaries are stripped.
UNSTRIPPED=$(find "${STAGEDIR}/${INSTALLDIR}/" -type f | xargs file |
grep ELF | grep -c "not stripped" || true)
if [ "${UNSTRIPPED}" != "0" ]; then
echo "ERROR: Found ${UNSTRIPPED} unstripped ELF files." 1>&2
exit 1
fi
# Check to make sure no ELF binaries set RPATH.
if [ "${TARGET_OS}" != "chromeos" ]; then
RPATH_BINS=
for elf in $(find "${STAGEDIR}/${INSTALLDIR}/" -type f | xargs file |
grep ELF | awk '{print $1;}' | sed 's/:$//'); do
if readelf -d ${elf} | grep "(RPATH)" >/dev/null; then
RPATH_BINS="${RPATH_BINS} $(basename ${elf})"
fi
done
if [ -n "${RPATH_BINS}" ]; then
echo "ERROR: Found binaries with RPATH set:${RPATH_BINS}" 1>&2
exit 1
fi
fi
# Make sure ELF binaries live in INSTALLDIR exclusively.
ELF_OUTSIDE_INSTALLDIR=$(find "${STAGEDIR}/" -not -path \
"${STAGEDIR}${INSTALLDIR}/*" -type f | xargs file -b |
grep -ce "^ELF" || true)
if [ "${ELF_OUTSIDE_INSTALLDIR}" -ne 0 ]; then
echo "ERROR: Found ${ELF_OUTSIDE_INSTALLDIR} ELF binaries" \
"outside of ${INSTALLDIR}" 1>&2
exit 1
fi
# Verify file permissions.
for file in $(find "${STAGEDIR}" -mindepth 1); do
local actual_perms=$(stat -c "%a" "${file}")
local file_type="$(file -b "${file}")"
local base_name=$(basename "${file}")
if [[ "${file_type}" = "directory"* ]]; then
local expected_perms=755
elif [[ "${file_type}" = *"symbolic link"* ]]; then
if [[ "$(readlink ${file})" = "/"* ]]; then
# Absolute symlink.
local expect_exists="${STAGEDIR}/$(readlink "${file}")"
else
# Relative symlink.
local expect_exists="$(dirname "${file}")/$(readlink "${file}")"
fi
if [ ! -f "${expect_exists}" ]; then
echo "Broken symlink: ${file}" 1>&2
exit 1
fi
local expected_perms=777
elif [ "${base_name}" = "chrome-sandbox" ]; then
local expected_perms=4755
elif [[ "${base_name}" = "nacl_irt_"*".nexe" ]]; then
local expected_perms=644
elif [[ "${file_type}" = *"shell script"* ]]; then
local expected_perms=755
elif [[ "${file_type}" = ELF* ]]; then
if [[ "${base_name}" = *".so" ]]; then
local expected_perms=${SHLIB_PERMS}
else
local expected_perms=755
fi
else
# Regular data file.
local expected_perms=644
fi
if [ ${expected_perms} -ne ${actual_perms} ]; then
echo Expected permissions on ${base_name} to be \
${expected_perms}, but they were ${actual_perms} 1>&2
exit 1
fi
done
}