blob: edf50a7cf606d0447d6fd82bd4fcd313bce7197e [file] [log] [blame]
#!/usr/bin/env bash
# Copyright 2018 The Fuchsia Authors
#
# Use of this source code is governed by a MIT-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/MIT
readonly SCRIPT_DIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)"
readonly ZIRCON_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
readonly PREBUILTS_DIR="$(cd "${ZIRCON_ROOT}/prebuilt" && pwd)"
readonly DOWNLOAD_DIR="${PREBUILTS_DIR}/downloads"
readonly ENSURE_FILE="${PREBUILTS_DIR}/zircon.ensure"
readonly VERSIONS_FILE="${PREBUILTS_DIR}/zircon.versions"
readonly URL_PREFIX="https://chrome-infra-packages.appspot.com/dl/fuchsia"
# This script assumes that ENSURE_FILE and VERSIONS_FILE match up.
# `cipd ensure` checks this and `cips ensure-file-resolve` ensures it.
# When a `cipd` binary is available, ENSURE_FILE controls the downloads
# and points `cipd` at VERSIONS_FILE for resolved pinned versions.
# Otherwise, VERSIONS_FILE controls the downloads directly. In both
# cases we write $DOWNLOAD_DIR/$PACKAGE.stamp files with the versions
# from VERSIONS_FILE on faith that that's what we just unpacked.
set -o pipefail
cipd_ok=true
case "$#:$1" in
0:)
mode=update
;;
1:--verify)
mode=verify
;;
1:--list)
mode=list
;;
1:--resolve)
mode=resolve
;;
1:--no-cipd)
mode=update
cipd_ok=false
;;
*)
echo >&2 "Usage: $0 [--verify|--list|--no-cipd]"
exit 1
;;
esac
readonly cipd_ok
case "$(uname)-$(uname -m)" in
Darwin-x86_64)
PLATFORM=mac-amd64
;;
Linux-x86_64)
PLATFORM=linux-amd64
;;
Linux-aarch64)
PLATFORM=linux-arm64
;;
*)
echo 'Unknown operating system.'
exit 1
;;
esac
readonly PLATFORM
update_stamp() {
local -r package="$1" version="$2" download_file="$3"
local -r stamp="${DOWNLOAD_DIR}/${download_file%.*}.stamp"
mkdir -p "$(dirname "$stamp")" && echo "$version" > "$stamp"
}
verify_stamp() {
local verbose=false
if [[ "$1" = "--verbose" ]]; then
verbose=true
shift
fi
local -r package="$1" version="$2" download_file="$3"
local -r stamp="${DOWNLOAD_DIR}/${download_file%.*}.stamp"
local stamp_version
if [[ -r "$stamp" ]]; then
stamp_version="$(< "$stamp")"
else
stamp_version="missing"
fi
if [[ "$stamp_version" = "$version" ]]; then
return 0
fi
if $verbose; then
echo "WARNING: unpacked $package $stamp_version != current $version"
fi
return 1
}
list_package() {
local -r package="$1" version="$2" download_file="$3" single_file="$4"
local -r package_suffix="$5"
local -r stamp="${DOWNLOAD_DIR}/${download_file%.*}.stamp"
local stamp_version
if [[ -r "$stamp" ]]; then
stamp_version="$(< "$stamp")"
else
stamp_version="missing"
fi
local installed="${stamp_version:-missing}"
if [[ "$installed" = "$version" ]]; then
installed="current"
fi
echo "$package$package_suffix" "installed=$installed" "current=$version"
}
verify_file() {
local -r file="$1"
local -r sum="$2"
if [[ "${#sum}" = "40" ]]; then
shasum --binary --check --status <<EOF
$sum *$file
EOF
elif [[ "${#sum}" = "44" ]]; then
digest="$(echo $sum | tr '_-' '/+' | base64 --decode | xxd -p -c 64)"
shasum -a 256 --binary --check --status <<EOF
${digest:0:64} *$file
EOF
else
echo >&2 "$0: unknown digest type for file ${file}: ${sum}"
return 1
fi
}
download_package() {
local -r package="$1" version="$2" download_file="$3" single_file="$4"
local -r package_suffix="$5"
local -r url="${URL_PREFIX}/${package}${package_suffix}/+/${version}"
local -r download_file_with_dir="${DOWNLOAD_DIR}/${download_file}"
# If the stamp file says it's already in place, do nothing more.
verify_stamp "$package" "$version" "$download_file" && return
rm -f -- "$download_file_with_dir"
echo "Downloading $url"
curl --progress-bar -continue-at=- --location \
--create-dirs --output "$download_file_with_dir" "$url" || return
verify_file "$download_file_with_dir" "$version" || {
echo >&2 "*** VERIFICATION ERROR ***"
echo >&2 "*** VERIFICATION ERROR *** $download_file from $url"
echo >&2 "*** VERIFICATION ERROR *** Not using the file!"
return 1
}
echo "Unpacking $download_file"
if $single_file; then
# The archive contains .cipd* metadata files and a single real file
# whose name is the same as the basename of the package.
unzip -q -o -d "$DOWNLOAD_DIR" "$download_file_with_dir" \
"${package##*/}" || return
else
local -r dir="${download_file_with_dir%.zip}"
rm -rf -- "$dir"
unzip -q -d "$dir" "$download_file_with_dir" || return
fi
update_stamp "$package" "$version" "$download_file"
}
for_each_package() {
local package tag version download_file single_file package_suffix status=0
local line next=package
while read line; do
case "$line" in
''|\#*)
continue
;;
esac
eval $next=\$line
case $next in
package)
next=tag
continue
;;
tag)
next=version
continue
;;
version)
next=package
;;
esac
# Now we've seen all three lines: package, tag, version.
case "$package" in
fuchsia/*)
package="${package#fuchsia/}"
;;
*)
continue
;;
esac
case "$package" in
tools/*/${PLATFORM})
# These are standalone executables contained in a .zip file.
package="${package%/*}"
download_file="${package#tools/}.zip"
single_file=true
package_suffix="/${PLATFORM}"
;;
sysroot/*)
# These are the same for every host platform.
# The $os-$cpu gets rewritten from CIPD names (amd64) to GN names (x64).
download_file="${package/%amd64/x64}.zip"
single_file=false
package_suffix=''
;;
*/${PLATFORM})
package="${package%/*}"
# Subdirectories are packed in .zip files.
if [[ "$package" == third_party/* ]]; then
download_file="${package#*/}.zip"
else
download_file="${package}.zip"
fi
single_file=false
package_suffix="/${PLATFORM}"
;;
firmware/*)
# These are the same for every host platform.
download_file="${package}.zip"
single_file=false
package_suffix=''
;;
*)
# Skip packages for other platforms.
continue
;;
esac
"$@" "$package" "$version" "$download_file" $single_file "$package_suffix" ||
status=$?
done
return $status
}
find_cipd() {
# If the Zircon checkout is part of a jiri checkout that includes
# //buildtools, then find cipd there. Otherwise, if cipd is in
# the PATH, take it from there.
type -p "${ZIRCON_ROOT}/../buildtools/cipd" || type -p cipd
}
run_cipd() {
local -r CIPD="$1" internal_access="$2" command="$3"
shift 3
local -r cipd_args=("$@")
local -a ensure_files=("${PREBUILTS_DIR}/zircon.ensure")
if $internal_access; then
ensure_files+=("${PREBUILTS_DIR}/zircon_internal.ensure")
fi
# The $ResolvedVersions file name is taken to be relative to the directory
# containing the -ensure-file argument. But since that's - to pipe in the
# combined file, make sure CIPD runs with its current directory being the
# one where $VERSIONS_FILE is found.
(sed '/^\$/!d' "${ensure_files[@]}" && sed '/^\$/d' "${ensure_files[@]}") |
(cd "$PREBUILTS_DIR" &&
"$CIPD" "$command" -ensure-file - -log-level warning "${cipd_args[@]}")
rc=$?
if [[ $rc -ne 0 ]]; then
echo >&2 "$0: $CIPD failed. For direct downloads, remove cipd from PATH."
return $rc
fi
}
update_via_cipd() {
run_cipd "$1" "$2" ensure -root "$DOWNLOAD_DIR"
# Now update the .stamp files so that --verify will be happy.
for_each_package update_stamp < "$VERSIONS_FILE"
}
write_sysroot_path() {
local -r package="$1" version="$2"
if [[ "$package" = sysroot ]]; then
echo "SYSROOT_${PLATFORM}_PATH = \$(LKMAKEROOT)/prebuilt/downloads/sysroot"
fi
}
write_config() {
local -r internal_access="$1"
local -r config_gni="${PREBUILTS_DIR}/config.gni"
rm -f -- "$config_gni"
echo > "$config_gni" "# Generated by $0. DO NOT EDIT!
have_firmware = $internal_access"
}
update() {
local CIPD
local internal_access=false
if $cipd_ok && CIPD="$(find_cipd)"; then
# We have CIPD, so use it.
if [[ "$("$CIPD" ls fuchsia_internal | tail -1)" != "No matching packages." ]]; then
internal_access=true
fi
update_via_cipd "$CIPD" "$internal_access" || return
else
# We don't have CIPD, so don't use it.
for_each_package download_package < "$VERSIONS_FILE" || return
fi
write_config "$internal_access"
}
verify() {
for_each_package verify_stamp --verbose < "$VERSIONS_FILE"
}
list() {
for_each_package list_package < "$VERSIONS_FILE"
}
resolve() {
run_cipd "$(find_cipd)" true ensure-file-resolve
}
$mode