blob: 48684cbbb3f9d06aa197119b5a157b6660accc7d [file] [log] [blame]
# Copyright (c) 2012 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.
# Script to download and unpack prebuilt Chromium OS images.
# This tool will cache downloaded archives in the images directory, named like
# "~/trunk/src/build/images/${BOARD}/". If an archive is the
# correct size it will be reused instead of being re-downloaded. Likewise,
# images are only extracted the first time they are requested.
# For internally-consistent terminology:
# archive: a zip file with multiple images
# image: a single .bin file; e.g. 'chromiumos_test_image.bin'
# variant: the human name for a single image; e.g. 'test'
if [[ ! -d ${SCRIPT_ROOT} ]]; then
echo "Failed to load required libraries;" \
"please run cros_sdk to enter the chroot" >&2
exit 1
# TODO(cwolfe): The --channel switch is temporarily disabled while we sort
# out some ACL problems.
# DEFINE_string channel "archive" "Channel from which to fetch the image"
DEFINE_string board "${DEFAULT_BOARD}" "Name of the board"
DEFINE_string version "" "Version to fetch, like 'R18-1650' or '1650'"
DEFINE_string symlink "latest" "Short name to link to the unpacked archive"
FLAGS_HELP="Usage: cros_fetch_image [FLAGS] variant...
Downloads and extracts Chromium OS image archives from the automated builders.
The following image variants can be extracted, if created by the builder:
base dev qemu recovery test
# Download the latest archive and extract base and test images from it.
$ cros_fetch_image --board=x86-generic base test
# Parse command line flags.
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
# The call into shflags is the last unsafe code, so can now die on error.
if [[ -z ${FLAGS_board} ]]; then
die "Did not find a default board, so the --board argument is required."
# Check that the version flag is valid.
if ! cros_archive_get_numeric_pattern "${FLAGS_version}" >/dev/null; then
die "Failed to parse version '${FLAGS_version}'"
# Build the list of image file names from the command-line variants.
for variant in "$@"; do
case ${variant} in
base) image='chromiumos_base_image.bin' ;;
dev) image='chromiumos_image.bin' ;;
qemu) image='chromiumos_qemu_image.bin' ;;
recovery) image='recovery_image.bin' ;;
test) image='chromiumos_test_image.bin' ;;
*) die "Unknown image variant '${$variant}'"
requested_images+=( "${image}" )
if [[ ${#requested_images[@]} -eq 0 ]]; then
warn "No image variants specified on the command line;" \
"assuming the test image."
requested_images=( 'chromiumos_test_image.bin' )
echo 'Searching for matching archives...' >&2
if ! gsurl=$(cros_archive_gs_list "${FLAGS_channel}" "${FLAGS_board}" \
"${FLAGS_version}") ||
[[ -z ${gsurl} ]]; then
echo >&2
die_notrace \
"Failed to find the requested archive for channel '${FLAGS_channel}'" \
"and board '${FLAGS_board}'. This may be because a build failed;" \
"please check the archives at:" \
echo " found ${gsurl}" >&2
echo >&2
archivename=$(cros_archive_gs_get_url_version "${FLAGS_channel}" \
"${FLAGS_board}" "${gsurl}")
mkdir -p "${archivedir}"
# Check the size of the local and remote archives.
if [[ -s ${archivedir}/${archivename}.zip ]]; then
echo 'Checking expected archive size...' >&2
imgsize=$(stat -c '%s' "${archivedir}/${archivename}.zip")
gssize=$(gsutil ls -l "${gsurl}" 2>/dev/null | sed 's/ .*//;q')
echo " found ${gssize}" >&2
echo " local ${imgsize}" >&2
echo >&2
# Download the archive if needed.
if [[ ${imgsize} -ne ${gssize} ]]; then
gsutil cp "${gsurl}" "${archivedir}/${archivename}.zip"
# Generate the list of images available in the zip and sort the requested ones.
available_images=( $(unzip -l "${archivedir}/${archivename}.zip" |
egrep -o '[^ ]+\.bin' | sort -u ) )
requested_images=( $(printf '%s\n' "${requested_images[@]}" | sort -u ) )
missing_images=() # requested but not available; will error later
exclude_images=() # available but not requested; will exclude from unzip
extract_images=() # available and requested; will extract during unzip
# Compare the available and requested lists. The 'comm' here needs to use a
# non-whitespace delimeter ('|') to prevent bash from dropping empty fields.
while IFS='|' read -r missing exclude extract; do
[[ -z ${missing} ]] || missing_images+=( "${missing}" )
[[ -z ${exclude} ]] || exclude_images+=( "${exclude}" )
[[ -z ${extract} ]] || extract_images+=( "${extract}" )
done < <( comm --output-delimiter='|' \
<( printf '%s\n' "${requested_images[@]}" ) \
<( printf '%s\n' "${available_images[@]}" ) )
# Construct and execute the unzip command.
unzip_cmd=( unzip -u "${archivedir}/${archivename}.zip" )
if [[ ${#exclude_images} -gt 0 ]]; then
# The -x switch interprets all later operands as excluded filenames.
unzip_cmd+=( -x "${exclude_images[@]}" )
unzip_cmd+=( -d "${imagedir}" )
# Update the symlink (usually 'latest').
if [[ -n ${FLAGS_symlink} ]]; then
echo >&2
info "Updating ${FLAGS_symlink} to refer to ${archivename}"
ln -fsT "${archivename}" "${archivedir}/${FLAGS_symlink}"
# Now report failure if any requested images were missing.
if [[ ${#missing_images} -gt 0 ]]; then
echo >&2
die_error \
"The following images were requested, but not available in the archive:"
" ${missing_images[*]}"