blob: 2bcf8be38f571ea675a9129f5a67aa0c1f1ddc16 [file] [log] [blame]
#!/bin/sh
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# This script downloads and installs the basic packages that the user needs
# in developer mode. It also takes care of some configuration details
# that arise from not havin write access to the root filesystem.
# Constant definitions.
P_CONFIG_CROS=/etc/portage
P_CONFIG_DEVELOPER=/usr/local/etc/portage
EMERGE_PACKAGES="${P_CONFIG_CROS}/bootstrap.packages"
# Global variables.
BINHOST=
CHROMEOS_DEVSERVER=
CHROMEOS_RELEASE_BOARD=
# Process flags.
. /usr/share/misc/shflags || exit 1
DEFINE_string binhost "" \
"URL of the binhost that emerge will use." b
DEFINE_string binhost_version "" \
"Version number to use instead of the one in /etc/lsb-release."
DEFINE_boolean reinstall "${FLAGS_FALSE}" \
"Remove all installed packages and re-bootstrap emerge."
DEFINE_boolean uninstall "${FLAGS_FALSE}" \
"Remove all installed packages."
DEFINE_boolean yes "${FLAGS_FALSE}" \
"Do not prompt for input. Assumes yes's to all responses." y
DEFINE_boolean only_bootstrap "${FLAGS_FALSE}" \
"Only attempt to install the bootstrap packages."
FLAGS "$@" || exit 1
set -e
# Get the portage configuration variables.
. "${P_CONFIG_CROS}/make.profile/make.defaults"
# Echo's args to stderr and prefixes with ERROR(dev_install).
error() {
echo "ERROR(dev_install): $*" >&2
}
# Reads the user's reply and returns 0 if the user responds with y.
# Accepts input like echo for the user prompt i.e. $@.
yes_or_no() {
[ ${FLAGS_yes} -eq ${FLAGS_TRUE} ] && return 0
local reply
read -p "$*? (y/N) " reply
[ "${reply}" = "y" ]
}
# Returns value of variable $2 from /etc/lsb-like file $1.
# $1 - Path to the /etc/lsb-like file.
# $2 - Variable name.
# Returns value or an empty string.
get_lsb_var() {
sed -n "s/^$2=//p" "$1"
}
# Here we simply wipe /usr/local/* since that it's the only directory in which
# packages are installed to.
remove_installed_packages() {
echo "To clean up, we will run:"
echo " rm -rf /usr/local/"
echo "Any content you have stored in there will be deleted."
if yes_or_no "Remove all installed packages now"; then
rm -rf --one-file-system /usr/local/*
echo "Removed all installed packages."
else
echo "Operation cancelled."
exit 0
fi
}
# Parses flags to return the binhost or if none set, use the default binhost
# set up from installation.
get_binhost() {
if [ -n "${FLAGS_binhost}" ]; then
BINHOST="${FLAGS_binhost}"
elif [ -n "${CHROMEOS_DEVSERVER}" ]; then
echo "Devserver URL set to: ${CHROMEOS_DEVSERVER}"
if yes_or_no "Use it as the binhost"; then
local packages_path="static/pkgroot/${CHROMEOS_RELEASE_BOARD}/packages"
BINHOST="${CHROMEOS_DEVSERVER}/${packages_path}"
fi
fi
if [ -z "${BINHOST}" ]; then
local release_number
# Get prefix for binhost.
. "${P_CONFIG_CROS}/repository.conf"
if [ -n "${FLAGS_binhost_version}" ]; then
release_number="${FLAGS_binhost_version}"
else
# Get the release number.
local cr_version="$(/opt/google/chrome/chrome --version)"
# Chrome version looks like (Google Chrome/Chromium) branch.0.a.b
local cr_branch="$(echo "${cr_version}" |
sed -r 's/.*[[:space:]]([0-9]+)\..*/\1/')"
local version="$(get_lsb_var /etc/lsb-release CHROMEOS_RELEASE_VERSION)"
release_number="R${cr_branch}-${version}"
fi
BINHOST="${PREFIX_BINHOST}canary-${release_number}/packages"
fi
}
# Get the static Python binary and portage (emerge script and python modules).
download_bootstrap_packages() {
# Download packages that python/emerge require into /usr/local/bootsrap.
while read line; do
local package_url="${BINHOST}/${line}.tbz2"
local directory="$(echo "${line}" | cut -d "/" -f 1)"
local package_file="${PKGDIR}/${line}.tbz2"
mkdir -p -m 0755 "${PKGDIR}/${directory}"
echo "Downloading ${package_url}"
if ! curl --fail -o "${package_file}" "${package_url}"; then
error "Could not download package."
error "Command curl --fail -o ${package_file} ${package_url} failed."
return 1
fi
echo "Extracting ${package_file}"
# TODO(sosa): pipeline our download/unpack cycles.
# Ignore std error output about trailing garbage after EOF.
if ! tar -C /usr/local/ -xjkf "${package_file}" 2>/dev/null; then
error "Could not extract package."
error "Command tar -C /usr/local -xjf ${package_file} failed."
return 1
fi
done < "${EMERGE_PACKAGES}"
}
# Configure emerge in /usr/local.
configure_emerge() {
# Copy emerge configuration to /usr/local.
mkdir -p -m 0755 "${P_CONFIG_DEVELOPER}"
cp "${P_CONFIG_CROS}/make.profile/make.conf" "${P_CONFIG_DEVELOPER}"
# The source files might be symlinks, and we'll probably clobber/update things
# ourselves locally, so dereference all the symlinks for our local copy.
cp -rfL "${P_CONFIG_CROS}/make.profile" "${P_CONFIG_DEVELOPER}/make.profile"
# Create the directories defined in the portage config files. Permissions are
# consistent with the other directories in /usr/local, which is a bind mount
# for /mnt/stateful_partition/dev_image.
mkdir -p -m 0755 "${PORTDIR}"
mkdir -p -m 0755 "${PKGDIR}"
mkdir -p -m 0755 "${DISTDIR}"
mkdir -p -m 0755 "${RPMDIR}"
mkdir -p -m 0755 "${PORTAGE_TMPDIR}"
mkdir -p -m 0755 "${BUILD_PREFIX}"
echo "PORTAGE_BINHOST=${BINHOST}" >> "${P_CONFIG_DEVELOPER}/make.conf"
# Add LD_LIBRARY_PATH within ebuild.sh.
# TODO(arkaitzr): find out a cleaner way to do this.
sed -i "3 a\export LD_LIBRARY_PATH=\"${LD_LIBRARY_PATH}\"" \
/usr/local/lib/portage/*/ebuild.sh
# Check for package.provided from $BINHOST.
local package_provided="${BINHOST}/package.provided"
local tmp_provided="$(mktemp)"
if ! curl --fail -o "${tmp_provided}" "${package_provided}" &&
[ -n "${CHROMEOS_DEVSERVER}" ]; then
echo "${package_provided} not found"
package_provided="${CHROMEOS_DEVSERVER}/"\
"static/pkgroot/${CHROMEOS_RELEASE_BOARD}/"\
"/etc/portage/profile/package.provided"
echo "Fall back to search ${package_provided}"
if ! curl --fail -o "${tmp_provided}" "${package_provided}"; then
echo "${package_provided} not found"
fi
fi
if [ -s ${tmp_provided} ]; then
mv "${tmp_provided}" \
"${P_CONFIG_DEVELOPER}/make.profile/package.provided/gsutil_provided"
fi
}
install_optional_packages() {
# Install gmerge manually first (even though it's part of the default
# virtual/target-os-dev) since it provides its own list of package.provided
# files. Other packages that virtual/target-os-dev pulls in might rely on
# those lists, so we need them sooner rather than later.
emerge gmerge
if yes_or_no "Install virtual/target-os-dev package now"; then
emerge virtual/target-os-dev
else
echo "You can install virtual/target-os-dev later by typing the command:" \
"emerge virtual/target-os-dev"
fi
}
import_lsb_release() {
local override
CHROMEOS_DEVSERVER=$(get_lsb_var /etc/lsb-release CHROMEOS_DEVSERVER)
CHROMEOS_RELEASE_BOARD=$(get_lsb_var /etc/lsb-release CHROMEOS_RELEASE_BOARD)
# Check local overrides.
if [ -f /usr/local/etc/lsb-release ]; then
override=$(get_lsb_var /usr/local/etc/lsb-release CHROMEOS_DEVSERVER)
[ -n "${override}" ] && CHROMEOS_DEVSERVER="${override}"
override=$(get_lsb_var /usr/local/etc/lsb-release CHROMEOS_RELEASE_BOARD)
[ -n "${override}" ] && CHROMEOS_RELEASE_BOARD="${override}"
fi
}
main() {
# Check if we are root.
if [ $(id -u) -ne 0 ]; then
error "Can not run dev_install."
error "You are not root or you did not use sudo."
return 1
fi
# Sanity check. People often run `su` or `sudo su` and leave off that final
# - which means they don't get a proper environment. Catch them here rather
# than fail randomly midway through the process.
case :${PATH}: in
*:/usr/local/bin:*) ;;
*)
error "Your environment appears to be incomplete. When changing to root,"
error "did you remember to run the full command (don't forget the dash):"
error " $ sudo su -"
return 1
;;
esac
# This script should only run in developer mode or for developer images.
if crossystem "cros_debug?0"; then
error "Can not run dev_install."
error "Chrome OS is not in developer mode."
return 1
fi
if [ ${FLAGS_uninstall} -eq ${FLAGS_TRUE} \
-o ${FLAGS_reinstall} -eq ${FLAGS_TRUE} ]; then
remove_installed_packages
if [ ${FLAGS_uninstall} -eq ${FLAGS_TRUE} ]; then
if [ ${FLAGS_reinstall} -eq ${FLAGS_TRUE} ]; then
error "Reinstall specified but ignored as uninstall was also specified."
fi
return 0
else
echo "Reinstalling emerge."
fi
fi
# Check if packages are already installed.
if [ -d "${P_CONFIG_DEVELOPER}" ]; then
error "Directory ${P_CONFIG_DEVELOPER} exists."
error "Did you mean dev_install --reinstall?"
return 1
fi
# Create this loop so uncompressed files in /usr/local/usr/* will be reachable
# through /usr/local*.
# Note: /usr/local is mount-binded onto the /mnt/stateful_partition/dev_mode
# during chromeos_startup during boot for machines in dev_mode.
if [ ! -d /usr/local/usr ]; then
ln -s . /usr/local/usr
fi
if [ ! -d /usr/local/local ]; then
ln -s . /usr/local/local
fi
# Set up symlinks for etc/{group,passwd}, so that packages can look up users
# and groups correctly.
if [ ! -d /usr/local/etc ]; then
mkdir -p /usr/local/etc
fi
if [ ! -f /usr/local/etc/group ]; then
ln -s ../../../etc/group /usr/local/etc/group
fi
if [ ! -f /usr/local/etc/passwd ]; then
ln -s ../../../etc/passwd /usr/local/etc/passwd
fi
echo "Starting installation of developer packages."
echo "First, we download the necessary files."
import_lsb_release
get_binhost
download_bootstrap_packages
if [ ${FLAGS_only_bootstrap} -eq ${FLAGS_TRUE} ]; then
echo "dev_install done installing bootstrap packages. Enjoy!"
return 0
fi
echo "Files downloaded, configuring emerge."
configure_emerge
echo "Emerge installation complete. Installing additional optional packages."
install_optional_packages
echo "dev_install done. Enjoy!"
}
main