blob: 1a670699b27de15a4c1b60ba595c26674d5f1ce5 [file] [log] [blame]
#!/bin/bash
# Copyright 2018 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
## usage: pave-prebuilt <prebuilt-path>
##
## Take the pre-built path and use it to pave a device. The pre-built path may
## point to a directory or a TAR-ed (and optionally gzipped) file.
##
## The pre-built should contain the following
## - bootserver in a directory called 'tools'
## - zircon.bin at its root
## - any relevant kernel bootdatas at its root
## - the args.gn used to do the build that produced these outputs at the root
## - an 'images' directory containing the images to feed to bootserver
# NOTE: This tool must be able to be run with only the //scripts repo
# present: the workflows that use it do not have a fuchsia checkout.
# TESTING: Unit tests live in ./tests/pave-prebuilt-tests.
# This file must not run any commands when being 'source'-ed while TESTING=1.
set -o errexit
set -o nounset
set -o pipefail
function usage {
# Prints lines from this file that begin with ##.
sed -n -e 's/^## //p' -e 's/^##$//p' < "${BASH_SOURCE[0]}"
}
# archive_to_unique_id <path-to-archive>
#
# Prints stable, unique ID associated with the archive, with a prefix indicating
# where the ID came from.
function archive_to_unique_id {
local archive="$1"
if [[ ! -f "${archive}" ]]; then
>&2 echo "ERROR: ${archive} does not exist or is not a file"
return 1
fi
# Just the filename.
local base_name="$(basename "${archive}")"
if [[ "${base_name}" =~ ^fuchsia\..* ]]; then
# fuchsia.tar.gz files tend to live in directories named after their build
# numbers.
# Absolute path to the file's parent directory.
local parent_dir
# Note: 'local' will swallow failures on the same line, so do the
# cd/pwd on a separate line.
parent_dir="$(cd "$(dirname "${archive}")" && pwd)"
# The directory name should be the buildbucket ID, a decimal string
# with around 19 digits. Check for 15 to give it some leeway.
local build_id="$(basename "${parent_dir}")"
if [[ "${build_id}" =~ ^[0-9]{15,}$ ]]; then
echo "build-${build_id}"
return 0
fi
# Else, fall through to the "hash the file" case.
else
# Before 2018-09, downloaded files were named <sha-hash>.tar[.gz], where
# the hash component had 40+ characters. See if this file looks like a
# hash-named file.
if [[ "${base_name}" =~ ^[0-9a-f]{40,}\..*$ ]]; then
# Starts with 40 or more hex characters immediately followed by
# an extension. Print everything before the first dot.
echo "stem-${base_name%%.*}"
return 0
fi
fi
# The archive path doesn't have an obvious ID; use a SHA-1 hash of the
# archive data.
echo -n 'hash-'
# shasum will print "<hash><whitespace><filename>"; the sed command removes
# everything but the hash. It will also print the filename to stderr, so send
# that output to /dev/null.
shasum --binary --algorithm=1 "${archive}" 2> /dev/null \
| sed -e 's/[[:space:]].*//'
}
# run_bootserver <expanded-archive-root>
function run_bootserver {
local dir_src="$1"
local bootserver="${dir_src}/tools/bootserver"
local kernel="${dir_src}/zircon.bin"
local bootdata="${dir_src}/bootdata-blob-pc.bin"
local -a bootserver_args=()
local esp_raw="${dir_src}/images/local-pc.esp.blk"
if [[ -r "${esp_raw}" ]]; then
bootserver_args+=(--efi "${esp_raw}")
fi
local vboot="${dir_src}/images/zircon-pc.vboot"
if [[ -r "${vboot}" ]]; then
bootserver_args+=(--kernc "${vboot}")
fi
bootserver_args+=(--zircona "${bootdata}" --zirconr "${bootdata}")
bootserver_args+=(--fvm "${dir_src}/images/fvm.sparse.blk")
local fvm_data="${dir_src}/images/fvm.data.sparse.blk"
if [[ -r "${fvm_data}" ]]; then
bootserver_args+=(--fvm "${fvm_data}")
fi
bootserver_args+=("${kernel}" "${bootdata}")
echo "Starting bootserver"
(
set -x # Print the commandline before running it.
"${bootserver}" "${bootserver_args[@]}"
)
}
function main {
if [[ $# -lt 1 ]]; then
>&2 echo "ERROR: Missing build archive/directory argument"
usage
return 1
fi
if [[ "$1" == "-h" ]] || [[ "$1" == "--help" ]]; then
usage
return 0
fi
local input_path="$1"
# The directory containing the files to pave.
local dir_src
if [[ -d "${input_path}" ]]; then
# The commandline arg points to a directory. See if it contains an
# already-expanded archive.
if [[ ! -f "${input_path}/tools/bootserver" ]]; then
>&2 echo "ERROR: Supplied path '${input_path}' does not contain an "$(
)"expanded fuchsia.tar.gz archive"
usage
return 1
fi
dir_src="${input_path}"
elif [[ -f "${input_path}" ]]; then
# The commandline arg points to a file. Treat it as an archive to expand.
# A stable, unique ID associated with this archive.
local unique_id
unique_id="$(archive_to_unique_id "${input_path}")"
# The parent directory of the //scripts checkout.
local top_level_dir
top_level_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# The directory to expand the archive to; a sibling of the //scripts
# checkout.
local targ_dir="${top_level_dir}/expanded-images/${unique_id}"
if [[ -f "${targ_dir}/tools/bootserver" ]]; then
echo "Re-using previously expanded archive contents under '${targ_dir}'"
else
echo "Expanding '${input_path}' to '${targ_dir}'"
mkdir -p "${targ_dir}"
local failed=0
tar xf "${input_path}" -C "${targ_dir}" &>/dev/null || failed=1
if (( failed )); then
# The "|| failed=1" trick prevents "set -o errexit" from immediately
# killing this script if tar fails, giving us a chance to print a
# message.
>&2 echo "ERROR: Failed to expand '${input_path}'"
return 1
fi
fi
dir_src="${targ_dir}"
else
>&2 echo "ERROR: Supplied path '${input_path}' is not a file or directory"
usage
return 1
fi
run_bootserver "${dir_src}"
}
# ./tests/pave-prebuilt-tests will set TESTING=1 when sourcing this file.
if [[ "${TESTING:-0}" != '1' ]]; then
main "$@"
fi