blob: 719ae3bd3d237735534c65b6e196a322cbf419aa [file] [log] [blame]
Andrew McRae0809eb52020-06-18 00:13:36 +10001#!/bin/bash
2# Copyright 2020 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5#
Andrew McRae0809eb52020-06-18 00:13:36 +10006# Script to update base firmware in a program's config, and then
7# regenerate the configs of projects that are part of the program.
8# Also updates the firmware manifest, and uploads all of the changes
9# for review.
10#
11# Usage:
Andrew McRae7c9655c2020-06-22 15:09:54 +100012# ./update_program_fw --board=program --release=NNNNN [ --reviewer=reviewer ]
13# [ --project=proj... ]
Andrew McRae0809eb52020-06-18 00:13:36 +100014# E.g:
Andrew McRae7c9655c2020-06-22 15:09:54 +100015# ./update_program_fw --board=puff --release=13291 --reviewer=amcrae@google.com
Andrew McRae0809eb52020-06-18 00:13:36 +100016#
Andrew McRae7c9655c2020-06-22 15:09:54 +100017CONTRIB_DIR=$(dirname "$(readlink -f "$0")")
18. "${CONTRIB_DIR}/common.sh" || exit 1
19
20FLAGS_HELP="
21Command to update the firmware version for a board.
22
23Updates the master_version firmware configuration for a board's
24master configuration (program.star) and for selected projects
25that include the master configuration.
26
27If no projects are specified, all projects for that board are selected.
28
29The configurations for the selected projects are regenerated,
30and the firmware manifest are updated for the projects.
31
32The necessary CLs for these changes are created and uploaded for review.
33An optional reviewer can be specified to send all the CLs to.
34"
35# Flags
36DEFINE_string board "${DEFAULT_BOARD}" "Which board (program) the firmware is for" b
37DEFINE_integer release 0 "The firmware release to update to" r
38DEFINE_string project "${DEFAULT_PROJECT}" "Which projects this release is for (defaults to all)" p
39DEFINE_string reviewer "${DEFAULT_REVIEWER}" "The reviewer to send the CLs to (optional)"
40
41# Parse command line
42FLAGS "$@" || exit 1
43eval set -- "${FLAGS_ARGV}"
44set -e
45
46# Script must be run inside the chroot.
47assert_inside_chroot
Andrew McRae0809eb52020-06-18 00:13:36 +100048#
49# Variables
50#
Andrew McRae7c9655c2020-06-22 15:09:54 +100051PATH="${PATH}:${GCLIENT_ROOT}/src/config/bin"
Andrew McRae0809eb52020-06-18 00:13:36 +100052DIGITS="[1-9][0-9][0-9][0-9][0-9]"
Andrew McRae0809eb52020-06-18 00:13:36 +100053BRANCH=""
Andrew McRae0809eb52020-06-18 00:13:36 +100054PROGRAM_CL=""
55PROGRAM="program.star"
56EDITOR="ex -s"; export EDITOR
57#
58# Common functions
59#
60cleanup() {
Andrew McRae7c9655c2020-06-22 15:09:54 +100061 if [[ -d "${TEMPDIR}" ]]; then
62 rm -rf "${TEMPDIR}"
Andrew McRae0809eb52020-06-18 00:13:36 +100063 fi
Andrew McRae0809eb52020-06-18 00:13:36 +100064}
65#
66# Abort the update, and clean up branches and CLs
67#
68abort() {
Andrew McRae0809eb52020-06-18 00:13:36 +100069 CLS=$(gerrit -i --raw search "owner:me status:open hashtag:${BRANCH}")
70 if [[ -n "${CLS}" ]]; then
71 echo "Abandoning uploaded CLs"
72 gerrit -i abandon "${CLS}"
73 fi
Andrew McRae7c9655c2020-06-22 15:09:54 +100074 "cros_workon-${FLAGS_board}" stop "chromeos-base/chromeos-firmware-${FLAGS_board}"
75 "cros_workon-${FLAGS_board}" stop "chromeos-base/chromeos-config-bsp-${FLAGS_board}-private"
Andrew McRae0809eb52020-06-18 00:13:36 +100076 repo abandon "${BRANCH}"
Andrew McRae7c9655c2020-06-22 15:09:54 +100077 die "$*"
Andrew McRae0809eb52020-06-18 00:13:36 +100078}
79#
80# Extract a CL number from the file containing
81# the output of repo upload
82#
83getcl() {
84 CL=$(grep -o "https://chrome-internal-review.googlesource.com/c/chromeos/$1/+/[0-9][0-9]*" "$2")
85 if [[ -z "${CL}" ]]; then
86 cat "$2"
87 abort CL number not found in repo upload output
88 fi
89 echo "${CL}" | grep -o "[0-9][0-9]*"
90}
91#
92# If not on this branch, start a branch
93#
94branch() {
95 if ! (git branch --show-current | grep -q "${BRANCH}"); then
96 repo start "${BRANCH}"
97 else
98 echo "${BRANCH} already exists, skipping repo start"
99 fi
100}
101#
102# Return true if repo has changes.
103changed() {
104 [[ -n $(git status -s) ]]
105}
106#
107# Add a Cq-Depend line to a commit.
108# Use ex as a line editor to insert it.
109#
110amend() {
111 git commit --amend <<EOF
112/^Change-Id/
113i
114$1
115.
116wq
117EOF
118}
119#
120# Validate arguments
121#
Andrew McRae7c9655c2020-06-22 15:09:54 +1000122if [[ -z "${FLAGS_board}" ]]; then
123 die "-b or --board required."
124fi
125if [[ -z "${FLAGS_release}" ]]; then
126 die "-r or --release required."
Andrew McRae0809eb52020-06-18 00:13:36 +1000127fi
128#
129# Program must exist as a directory
130#
Andrew McRae7c9655c2020-06-22 15:09:54 +1000131PROGDIR="${GCLIENT_ROOT}/src/program/${FLAGS_board}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000132if [[ ! -d "${PROGDIR}" ]]; then
Andrew McRae7c9655c2020-06-22 15:09:54 +1000133 die "${FLAGS_board} is not a valid program (${PROGDIR} missing)"
Andrew McRae0809eb52020-06-18 00:13:36 +1000134fi
135# Release must be a 5 digit number
Andrew McRae7c9655c2020-06-22 15:09:54 +1000136if [[ ! "${FLAGS_release}" =~ ^${DIGITS}$ ]]; then
137 die "release must be a 5 digit number"
Andrew McRae0809eb52020-06-18 00:13:36 +1000138fi
139#
Andrew McRae7c9655c2020-06-22 15:09:54 +1000140# Build the project list.
141# If no projects are specified, use all in the program's directory.
Andrew McRae0809eb52020-06-18 00:13:36 +1000142#
Andrew McRae7c9655c2020-06-22 15:09:54 +1000143if [[ -n "${FLAGS_project}" ]]; then
144 IFS=',' read -r -a PROJECTS <<< "${FLAGS_project}"
145else
146 BDIR="${GCLIENT_ROOT}/src/project/${FLAGS_board}"
147 cd "${BDIR}" || die "${BDIR} does not exist"
148 mapfile -t PROJECTS < <(ls)
Andrew McRae0809eb52020-06-18 00:13:36 +1000149fi
Andrew McRae7c9655c2020-06-22 15:09:54 +1000150#
151# Validate project list
152#
153for P in "${PROJECTS[@]}"; do
154 PDIR="${GCLIENT_ROOT}/src/project/${FLAGS_board}/${P}"
155 if [[ ! -d "${PDIR}" ]]; then
156 die "${P} is not a valid project (${PDIR} missing)"
157 fi
158done
159#
160# Create a temp directory.
161TEMPDIR=$(mktemp -d -t fw-XXXXXXXXXX)
162# Use a common git branch name.
163BRANCH="update_${FLAGS_board}_fw_${FLAGS_release}"
164
165trap "exit 1" HUP INT PIPE QUIT TERM
166trap 'cleanup' EXIT
167
Andrew McRae0809eb52020-06-18 00:13:36 +1000168#
169# Update the firmware version in the program config
170# From now on, all errors should invoke 'abort'
Andrew McRae7c9655c2020-06-22 15:09:54 +1000171# so that the branches and CLs are cleaned up on exit.
Andrew McRae0809eb52020-06-18 00:13:36 +1000172#
Andrew McRae7c9655c2020-06-22 15:09:54 +1000173cd "${PROGDIR}" || die "Missing ${PROGDIR}"
174echo "Updating ${PROGRAM} for board ${FLAGS_board}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000175branch
Andrew McRae7c9655c2020-06-22 15:09:54 +1000176sed "/^ *major_version = ${DIGITS}$/s/${DIGITS}/${FLAGS_release}/" "${PROGRAM}" > "${TEMPDIR}/new-${PROGRAM}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000177#
178# Verify that only 1-5 characters have changed.
179#
180DIFF=$(cmp -l "${PROGRAM}" "${TEMPDIR}/new-${PROGRAM}" | wc -l)
181if [[ "${DIFF}" -gt 5 ]]; then
182 diff "${PROGRAM}" "new-${TEMPDIR}/${PROGRAM}"
183 abort "${PROGDIR}/${PROGRAM} update error"
Andrew McRae0809eb52020-06-18 00:13:36 +1000184fi
185#
186# If program config has changed, create a CL.
187#
188if [[ "${DIFF}" -ne 0 ]]; then
189 cp "${TEMPDIR}/new-${PROGRAM}" "${PROGRAM}"
190 git add .
191 git commit -F - <<EOF
Andrew McRae7c9655c2020-06-22 15:09:54 +1000192${FLAGS_board}: Update firmware to ${FLAGS_release}
Andrew McRae0809eb52020-06-18 00:13:36 +1000193
194BUG=none
Andrew McRae7c9655c2020-06-22 15:09:54 +1000195TEST=FAFT tests on ${FLAGS_board}
Andrew McRae0809eb52020-06-18 00:13:36 +1000196EOF
197 repo upload -y "--ht=${BRANCH}" --cbr . > "${TEMPDIR}/upload.output" 2>&1
Andrew McRae7c9655c2020-06-22 15:09:54 +1000198 PROGRAM_CL=$(getcl "program/${FLAGS_board}" "${TEMPDIR}/upload.output")
Andrew McRae0809eb52020-06-18 00:13:36 +1000199fi
200#
201# Now walk through the projects and regenerate the configs.
202# Create and upload a CL and capture the CL number and project directory
203# if the project has changed.
204#
205PROJ_CLS=()
206PROJ_DIRS=()
Andrew McRae7c9655c2020-06-22 15:09:54 +1000207for PROJ in "${PROJECTS[@]}"; do
208 echo "Updating configs for project ${PROJ}"
209 PDIR="${GCLIENT_ROOT}/src/project/${FLAGS_board}/${PROJ}"
210 cd "${PDIR}" || abort "${PROJ}: Missing directory: ${PDIR}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000211 branch
212 ./config.star || abort "Generate config failed for ${PROJ}"
213 check_config > "${TEMPDIR}/check_config-${PROJ}.output" || abort "check_config failed for ${PROJ}"
214 #
215 # Check if any files changed.
216 #
217 if changed; then
218 git add .
219 git commit -F - <<EOF
Andrew McRae7c9655c2020-06-22 15:09:54 +1000220${PROJ}: Update firmware to ${FLAGS_release}
Andrew McRae0809eb52020-06-18 00:13:36 +1000221BUG=none
Andrew McRae7c9655c2020-06-22 15:09:54 +1000222TEST=FAFT tests on ${FLAGS_board}
Andrew McRae0809eb52020-06-18 00:13:36 +1000223EOF
224 repo upload -y "--ht=${BRANCH}" --cbr . > "${TEMPDIR}/upload.${PROJ}.output" 2>&1
Andrew McRae7c9655c2020-06-22 15:09:54 +1000225 P_CL=$(getcl "project/${FLAGS_board}/${PROJ}" "${TEMPDIR}/upload.${PROJ}.output")
Andrew McRae0809eb52020-06-18 00:13:36 +1000226 PROJ_CLS+=("${P_CL}")
227 PROJ_DIRS+=("${PDIR}")
228 fi
229done
230#
231# Create a Cq-Depend line with all the project CLs
232#
233if [[ -n "${PROJ_CLS[*]}" ]];then
234 SEP=" "
235 PROG_CQD="Cq-Depend:"
236 for CL in "${PROJ_CLS[@]}"; do
237 PROG_CQD="${PROG_CQD}${SEP}chrome-internal:${CL}"
238 SEP=", "
239 done
240 #
241 # Add the Cq-Depend line to the program CL commit message.
242 #
243 cd "${PROGDIR}" || abort "Missing directory: ${PROGDIR}"
244 amend "${PROG_CQD}"
245 repo upload --cbr .
246fi
247#
248# All the boxster configs have been uploaded.
249# Now run the update script and update the firmware manifest.
250#
251# Build base coreboot files
252# TODO: Should be selective here.
253#
254echo "Running emerge for coreboot. This may take a while..."
Andrew McRae7c9655c2020-06-22 15:09:54 +1000255if ! ("emerge-${FLAGS_board}" --quiet-build chromeos-ec coreboot depthcharge vboot_reference \
Andrew McRae0809eb52020-06-18 00:13:36 +1000256 libpayload chromeos-bootimage coreboot-private-files \
Andrew McRae7c9655c2020-06-22 15:09:54 +1000257 "coreboot-private-files-${FLAGS_board}"); then
Andrew McRae0809eb52020-06-18 00:13:36 +1000258 abort "emerge for coreboot failed!"
259fi
260echo "emerge of coreboot successful"
Andrew McRae7c9655c2020-06-22 15:09:54 +1000261OVERLAY="${GCLIENT_ROOT}/src/private-overlays/overlay-${FLAGS_board}-private/chromeos-base/chromeos-firmware-${FLAGS_board}"
262EB9999="chromeos-firmware-${FLAGS_board}-9999.ebuild"
Andrew McRae0809eb52020-06-18 00:13:36 +1000263#
264# Remove any previous attempts to build the firmware.
265#
Andrew McRae7c9655c2020-06-22 15:09:54 +1000266"cros_workon-${FLAGS_board}" stop "chromeos-base/chromeos-firmware-${FLAGS_board}"
267"cros_workon-${FLAGS_board}" stop "chromeos-base/chromeos-config-bsp-${FLAGS_board}-private"
Andrew McRae0809eb52020-06-18 00:13:36 +1000268cd "${OVERLAY}" || abort "Missing directory: ${OVERLAY}"
269branch
Andrew McRae7c9655c2020-06-22 15:09:54 +1000270cd "${GCLIENT_ROOT}/src/platform/dev/contrib" || abort "Missing directory: ${GCLIENT_ROOT}/src/platform/dev/contrib"
271if ! (./cros_update_firmware -q "--board=${FLAGS_board}"); then
272 abort "cros_update_firmware failed for ${FLAGS_board}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000273fi
274cd "${OVERLAY}" || abort "Missing directory: ${OVERLAY}"
275#
276# If files have been updated, then create a CL for the changes.
277#
278OVERLAY_CL=""
279if changed; then
280 #
281 # Bump the version in the ebuild file. Relies on the format
282 # of the version so that the last number is at the end of the line.
283 #
284 CURVERS=$(grep "VERSION=REVBUMP" "${EB9999}" | grep -o "[0-9][0-9]*$")
285 NEXTVERS=$((CURVERS + 1))
286 sed "/VERSION=REVBUMP/s/${CURVERS}$/${NEXTVERS}/" "${EB9999}" > "${TEMPDIR}/new-${EB9999}"
287 cp "${TEMPDIR}/new-${EB9999}" "${EB9999}"
288 git add .
289 git commit -F - <<EOF
Andrew McRae7c9655c2020-06-22 15:09:54 +1000290${FLAGS_board}: Update firmware to ${FLAGS_release}
Andrew McRae0809eb52020-06-18 00:13:36 +1000291
292BUG=none
Andrew McRae7c9655c2020-06-22 15:09:54 +1000293TEST=FAFT tests on ${FLAGS_board}
Andrew McRae0809eb52020-06-18 00:13:36 +1000294
295${CQD}
296EOF
297 #
298 # Upload with no-verify since the file lines are too long.
299 #
300 repo upload "--ht=${BRANCH}" -y --no-verify --cbr . > "${TEMPDIR}/overlay.output" 2>&1
Andrew McRae7c9655c2020-06-22 15:09:54 +1000301 OVERLAY_CL=$(getcl "overlays/overlay-${FLAGS_board}-private" "${TEMPDIR}/overlay.output")
Andrew McRae0809eb52020-06-18 00:13:36 +1000302 #
303 # Go back and amend all the project commit messages with a Cq-Depend on
304 # the program and overlay CLs.
305 #
306 CQD="Cq-Depend: chrome-internal:${OVERLAY_CL}"
307 if [[ -n "${PROGRAM_CL}" ]]; then
308 CQD="${CQD}, chrome-internal:${PROGRAM_CL}"
309 fi
310 for DIR in "${PROJ_DIRS[@]}"; do
311 cd "${DIR}" || abort "Missing directory: ${DIR}"
312 amend "${CQD}"
313 repo upload --cbr .
314 done
315fi
316#
317# Send all of the CLs to the CQ for a dry run.
318#
319ALL_CLS=$(gerrit -i --raw search "owner:me status:open hashtag:${BRANCH}")
320if [[ -z "${ALL_CLS}" ]]; then
Andrew McRae7c9655c2020-06-22 15:09:54 +1000321 echo "No changes required for program ${FLAGS_board}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000322 repo abandon "${BRANCH}"
323 exit 0
324fi
325for cl in ${ALL_CLS}; do
326 gerrit -i label-cq "${cl}" 1
327 gerrit -i label-v "${cl}" 1
328 gerrit -i label-as "${cl}" 1
329done
330#
331# If reviewer is set, then add them to the CLs
332#
Andrew McRae7c9655c2020-06-22 15:09:54 +1000333if [[ -n "${FLAGS_reviewer}" ]]; then
334 echo "Sending CLs ${ALL_CLS} to ${FLAGS_reviewer} for review"
Andrew McRae0809eb52020-06-18 00:13:36 +1000335 for cl in ${ALL_CLS}; do
Andrew McRae7c9655c2020-06-22 15:09:54 +1000336 gerrit -i reviewers "${cl}" "${FLAGS_reviewer}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000337 done
338else
339 echo "Send CLs for review by running:"
340 echo " for cl in ${ALL_CLS}; do gerrit -i reviewers \$cl <reviewer>; done"
341fi
342#
343# Final instructions.
344#
345echo "Run:"
Andrew McRae7c9655c2020-06-22 15:09:54 +1000346echo " /build/${FLAGS_board}/usr/sbin/chromeos-firmwareupdate --manifest"
Andrew McRae0809eb52020-06-18 00:13:36 +1000347echo "to verify firmware update"
348echo "When submitted, cleanup by running:"
349echo "repo abandon ${BRANCH}"