blob: dfb97782dd817f46e5b65baf58180229b64bced5 [file] [log] [blame]
#!/bin/bash
# Copyright 2020 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.
#
# TODO(amcrae): Refactor to use common.sh
#
# Script to update base firmware in a program's config, and then
# regenerate the configs of projects that are part of the program.
# Also updates the firmware manifest, and uploads all of the changes
# for review.
#
# Usage:
# ./update_program_fw program release [ reviewer ]
# E.g:
# ./update_program_fw puff 13291 amcrae@google.com
#
# Environment variables:
# SRC = base of repo tree (default is ~/trunk/src)
# HOME = home directory
#
# Variables
#
TEMPDIR=$(mktemp -d -t fw-XXXXXXXXXX)
CMDNAME=$(basename "$0")
SRC="${SRC:-/mnt/host/source/src}"
PATH="${PATH}:${SRC}/config/bin"
DIGITS="[1-9][0-9][0-9][0-9][0-9]"
PROG=""
BRANCH=""
REVIEWER=""
PROGRAM_CL=""
PROGRAM="program.star"
EDITOR="ex -s"; export EDITOR
#
# Common functions
#
cleanup() {
rm -rf "${TEMPDIR}"
}
trap "exit 1" HUP INT PIPE QUIT TERM
trap 'cleanup' EXIT
usage() {
if [[ "$#" -ge 1 ]]; then
echo "$*"
fi
echo "Usage: ${CMDNAME} program-name release [ reviewer ]"
echo "e.g:"
echo " ${CMDNAME} puff 13271 amcrae@google.com"
exit 1
}
#
# Abort the update, and clean up branches and CLs
#
abort() {
echo "$*"
echo "Aborting..."
CLS=$(gerrit -i --raw search "owner:me status:open hashtag:${BRANCH}")
if [[ -n "${CLS}" ]]; then
echo "Abandoning uploaded CLs"
gerrit -i abandon "${CLS}"
fi
"cros_workon-${PROG}" stop "chromeos-base/chromeos-firmware-${PROG}"
"cros_workon-${PROG}" stop "chromeos-base/chromeos-config-bsp-${PROG}-private"
repo abandon "${BRANCH}"
exit 1
}
#
# Extract a CL number from the file containing
# the output of repo upload
#
getcl() {
CL=$(grep -o "https://chrome-internal-review.googlesource.com/c/chromeos/$1/+/[0-9][0-9]*" "$2")
if [[ -z "${CL}" ]]; then
cat "$2"
abort CL number not found in repo upload output
fi
echo "${CL}" | grep -o "[0-9][0-9]*"
}
#
# If not on this branch, start a branch
#
branch() {
if ! (git branch --show-current | grep -q "${BRANCH}"); then
repo start "${BRANCH}"
else
echo "${BRANCH} already exists, skipping repo start"
fi
}
#
# Return true if repo has changes.
changed() {
[[ -n $(git status -s) ]]
}
#
# Add a Cq-Depend line to a commit.
# Use ex as a line editor to insert it.
#
amend() {
git commit --amend <<EOF
/^Change-Id/
i
$1
.
wq
EOF
}
#
# Validate arguments
#
if [[ "$#" -lt 2 ]] || [[ "$#" -gt 3 ]]; then
usage
fi
#
# Program must exist as a directory
#
PROG="$1"
PROGDIR="${SRC}/program/${PROG}"
if [[ ! -d "${PROGDIR}" ]]; then
usage "${PROG} is not a valid program (${PROGDIR} missing)"
fi
# Release must be a 5 digit number
RELEASE="$2"
if [[ ! "${RELEASE}" =~ ^${DIGITS}$ ]]; then
usage "release must be a 5 digit number"
fi
#
# Check for reviewer argument.
#
if [[ "$#" -eq 3 ]]; then
REVIEWER=$3
fi
BRANCH="update_${PROG}_fw_${RELEASE}"
#
# Update the firmware version in the program config
# From now on, all errors should invoke 'abort'
# so that the branches and CLs are cleaned up.
#
cd "${PROGDIR}" || exit 1
branch
sed "/^ *major_version = ${DIGITS}$/s/${DIGITS}/${RELEASE}/" "${PROGRAM}" > "${TEMPDIR}/new-${PROGRAM}"
#
# Verify that only 1-5 characters have changed.
#
DIFF=$(cmp -l "${PROGRAM}" "${TEMPDIR}/new-${PROGRAM}" | wc -l)
if [[ "${DIFF}" -gt 5 ]]; then
diff "${PROGRAM}" "new-${TEMPDIR}/${PROGRAM}"
abort "${PROGDIR}/${PROGRAM} update error"
exit 1
fi
#
# If program config has changed, create a CL.
#
if [[ "${DIFF}" -ne 0 ]]; then
cp "${TEMPDIR}/new-${PROGRAM}" "${PROGRAM}"
git add .
git commit -F - <<EOF
${PROG}: Update firmware to ${RELEASE}
BUG=none
TEST=FAFT tests on ${PROG}
EOF
repo upload -y "--ht=${BRANCH}" --cbr . > "${TEMPDIR}/upload.output" 2>&1
PROGRAM_CL=$(getcl "program/${PROG}" "${TEMPDIR}/upload.output")
fi
#
# Now walk through the projects and regenerate the configs.
# Create and upload a CL and capture the CL number and project directory
# if the project has changed.
#
PROJ_CLS=()
PROJ_DIRS=()
for PDIR in "${SRC}/project/${PROG}"/*; do
PROJ=$(basename "${PDIR}")
cd "${PDIR}" || abort "Missing directory: ${PDIR}"
branch
./config.star || abort "Generate config failed for ${PROJ}"
check_config > "${TEMPDIR}/check_config-${PROJ}.output" || abort "check_config failed for ${PROJ}"
#
# Check if any files changed.
#
if changed; then
git add .
git commit -F - <<EOF
${PROJ}: Update firmware to ${RELEASE}
BUG=none
TEST=FAFT tests on ${PROG}
EOF
repo upload -y "--ht=${BRANCH}" --cbr . > "${TEMPDIR}/upload.${PROJ}.output" 2>&1
P_CL=$(getcl "project/${PROG}/${PROJ}" "${TEMPDIR}/upload.${PROJ}.output")
PROJ_CLS+=("${P_CL}")
PROJ_DIRS+=("${PDIR}")
fi
done
#
# Create a Cq-Depend line with all the project CLs
#
if [[ -n "${PROJ_CLS[*]}" ]];then
SEP=" "
PROG_CQD="Cq-Depend:"
for CL in "${PROJ_CLS[@]}"; do
PROG_CQD="${PROG_CQD}${SEP}chrome-internal:${CL}"
SEP=", "
done
#
# Add the Cq-Depend line to the program CL commit message.
#
cd "${PROGDIR}" || abort "Missing directory: ${PROGDIR}"
amend "${PROG_CQD}"
repo upload --cbr .
fi
#
# All the boxster configs have been uploaded.
# Now run the update script and update the firmware manifest.
#
# Build base coreboot files
# TODO: Should be selective here.
#
echo "Running emerge for coreboot. This may take a while..."
if ! ("emerge-${PROG}" --quiet-build chromeos-ec coreboot depthcharge vboot_reference \
libpayload chromeos-bootimage coreboot-private-files \
"coreboot-private-files-${PROG}"); then
abort "emerge for coreboot failed!"
fi
echo "emerge of coreboot successful"
OVERLAY="${SRC}/private-overlays/overlay-${PROG}-private/chromeos-base/chromeos-firmware-${PROG}"
EB9999="chromeos-firmware-${PROG}-9999.ebuild"
#
# Remove any previous attempts to build the firmware.
#
"cros_workon-${PROG}" stop "chromeos-base/chromeos-firmware-${PROG}"
"cros_workon-${PROG}" stop "chromeos-base/chromeos-config-bsp-${PROG}-private"
cd "${OVERLAY}" || abort "Missing directory: ${OVERLAY}"
branch
cd "${SRC}/platform/dev/contrib" || abort "Missing directory: ${SRC}/platform/dev/contrib"
if ! (./cros_update_firmware -q "--board=${PROG}"); then
abort "cros_update_firmware failed for ${PROG}"
exit 1
fi
cd "${OVERLAY}" || abort "Missing directory: ${OVERLAY}"
#
# If files have been updated, then create a CL for the changes.
#
OVERLAY_CL=""
if changed; then
#
# Bump the version in the ebuild file. Relies on the format
# of the version so that the last number is at the end of the line.
#
CURVERS=$(grep "VERSION=REVBUMP" "${EB9999}" | grep -o "[0-9][0-9]*$")
NEXTVERS=$((CURVERS + 1))
sed "/VERSION=REVBUMP/s/${CURVERS}$/${NEXTVERS}/" "${EB9999}" > "${TEMPDIR}/new-${EB9999}"
cp "${TEMPDIR}/new-${EB9999}" "${EB9999}"
git add .
git commit -F - <<EOF
${PROG}: Update firmware to ${RELEASE}
BUG=none
TEST=FAFT tests on ${PROG}
${CQD}
EOF
#
# Upload with no-verify since the file lines are too long.
#
repo upload "--ht=${BRANCH}" -y --no-verify --cbr . > "${TEMPDIR}/overlay.output" 2>&1
OVERLAY_CL=$(getcl "overlays/overlay-${PROG}-private" "${TEMPDIR}/overlay.output")
#
# Go back and amend all the project commit messages with a Cq-Depend on
# the program and overlay CLs.
#
CQD="Cq-Depend: chrome-internal:${OVERLAY_CL}"
if [[ -n "${PROGRAM_CL}" ]]; then
CQD="${CQD}, chrome-internal:${PROGRAM_CL}"
fi
for DIR in "${PROJ_DIRS[@]}"; do
cd "${DIR}" || abort "Missing directory: ${DIR}"
amend "${CQD}"
repo upload --cbr .
done
fi
#
# Send all of the CLs to the CQ for a dry run.
#
ALL_CLS=$(gerrit -i --raw search "owner:me status:open hashtag:${BRANCH}")
if [[ -z "${ALL_CLS}" ]]; then
echo "No changes required for program ${PROG}"
repo abandon "${BRANCH}"
exit 0
fi
for cl in ${ALL_CLS}; do
gerrit -i label-cq "${cl}" 1
gerrit -i label-v "${cl}" 1
gerrit -i label-as "${cl}" 1
done
#
# If reviewer is set, then add them to the CLs
#
if [[ -n "${REVIEWER}" ]]; then
echo "Sending CLs ${ALL_CLS} to ${REVIEWER} for review"
for cl in ${ALL_CLS}; do
gerrit -i reviewers "${cl}" "${REVIEWER}"
done
else
echo "Send CLs for review by running:"
echo " for cl in ${ALL_CLS}; do gerrit -i reviewers \$cl <reviewer>; done"
fi
#
# Final instructions.
#
echo "Run:"
echo " /build/${PROG}/usr/sbin/chromeos-firmwareupdate --manifest"
echo "to verify firmware update"
echo "When submitted, cleanup by running:"
echo "repo abandon ${BRANCH}"