blob: 112c8a30a00af25bcd5722f55432b98f238f6b9d [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.
Andrew McRaef96cd602020-06-23 23:06:19 +100028An optional skip list can be specified to skip selected boards.
Andrew McRae7c9655c2020-06-22 15:09:54 +100029
30The configurations for the selected projects are regenerated,
31and the firmware manifest are updated for the projects.
32
33The necessary CLs for these changes are created and uploaded for review.
34An optional reviewer can be specified to send all the CLs to.
35"
36# Flags
37DEFINE_string board "${DEFAULT_BOARD}" "Which board (program) the firmware is for" b
38DEFINE_integer release 0 "The firmware release to update to" r
39DEFINE_string project "${DEFAULT_PROJECT}" "Which projects this release is for (defaults to all)" p
Andrew McRaef96cd602020-06-23 23:06:19 +100040DEFINE_string skip "${DEFAULT_SKIP}" "Skip these projects" s
Andrew McRae7c9655c2020-06-22 15:09:54 +100041DEFINE_string reviewer "${DEFAULT_REVIEWER}" "The reviewer to send the CLs to (optional)"
42
43# Parse command line
44FLAGS "$@" || exit 1
45eval set -- "${FLAGS_ARGV}"
46set -e
47
48# Script must be run inside the chroot.
49assert_inside_chroot
Andrew McRae0809eb52020-06-18 00:13:36 +100050#
51# Variables
52#
Andrew McRae7c9655c2020-06-22 15:09:54 +100053PATH="${PATH}:${GCLIENT_ROOT}/src/config/bin"
Andrew McRae0809eb52020-06-18 00:13:36 +100054DIGITS="[1-9][0-9][0-9][0-9][0-9]"
Andrew McRae0809eb52020-06-18 00:13:36 +100055BRANCH=""
Andrew McRae0809eb52020-06-18 00:13:36 +100056PROGRAM_CL=""
57PROGRAM="program.star"
Andrew McRae0809eb52020-06-18 00:13:36 +100058#
59# Common functions
60#
61cleanup() {
Andrew McRae7c9655c2020-06-22 15:09:54 +100062 if [[ -d "${TEMPDIR}" ]]; then
63 rm -rf "${TEMPDIR}"
Andrew McRae0809eb52020-06-18 00:13:36 +100064 fi
Andrew McRae0809eb52020-06-18 00:13:36 +100065}
66#
67# Abort the update, and clean up branches and CLs
68#
69abort() {
Andrew McRae0809eb52020-06-18 00:13:36 +100070 CLS=$(gerrit -i --raw search "owner:me status:open hashtag:${BRANCH}")
71 if [[ -n "${CLS}" ]]; then
72 echo "Abandoning uploaded CLs"
Andrew McRaef96cd602020-06-23 23:06:19 +100073 for cl in ${CLS}; do
74 gerrit -i abandon "${cl}"
75 done
Andrew McRae0809eb52020-06-18 00:13:36 +100076 fi
Andrew McRae7c9655c2020-06-22 15:09:54 +100077 "cros_workon-${FLAGS_board}" stop "chromeos-base/chromeos-firmware-${FLAGS_board}"
78 "cros_workon-${FLAGS_board}" stop "chromeos-base/chromeos-config-bsp-${FLAGS_board}-private"
Andrew McRae0809eb52020-06-18 00:13:36 +100079 repo abandon "${BRANCH}"
Andrew McRae7c9655c2020-06-22 15:09:54 +100080 die "$*"
Andrew McRae0809eb52020-06-18 00:13:36 +100081}
82#
83# Extract a CL number from the file containing
84# the output of repo upload
85#
86getcl() {
87 CL=$(grep -o "https://chrome-internal-review.googlesource.com/c/chromeos/$1/+/[0-9][0-9]*" "$2")
88 if [[ -z "${CL}" ]]; then
89 cat "$2"
90 abort CL number not found in repo upload output
91 fi
92 echo "${CL}" | grep -o "[0-9][0-9]*"
93}
94#
95# If not on this branch, start a branch
96#
97branch() {
98 if ! (git branch --show-current | grep -q "${BRANCH}"); then
99 repo start "${BRANCH}"
100 else
101 echo "${BRANCH} already exists, skipping repo start"
102 fi
103}
104#
105# Return true if repo has changes.
106changed() {
107 [[ -n $(git status -s) ]]
108}
109#
110# Add a Cq-Depend line to a commit.
Andrew McRae0809eb52020-06-18 00:13:36 +1000111#
112amend() {
Andrew McRaef96cd602020-06-23 23:06:19 +1000113 git log -1 --pretty=%B > "${TEMPDIR}/amend-msg"
114 sed -i "/^Change-Id/ i ${1}" "${TEMPDIR}/amend-msg"
115 git commit -q --amend -F "${TEMPDIR}/amend-msg"
116}
117#
118# Return true if $1 is in list $2
119#
120in_list() {
121 for S in ${2}; do
122 if [[ "$1" == "${S}" ]]; then
123 return 0
124 fi
125 done
126 return 1
Andrew McRae0809eb52020-06-18 00:13:36 +1000127}
128#
129# Validate arguments
130#
Andrew McRae7c9655c2020-06-22 15:09:54 +1000131if [[ -z "${FLAGS_board}" ]]; then
132 die "-b or --board required."
133fi
134if [[ -z "${FLAGS_release}" ]]; then
135 die "-r or --release required."
Andrew McRae0809eb52020-06-18 00:13:36 +1000136fi
137#
138# Program must exist as a directory
139#
Andrew McRae7c9655c2020-06-22 15:09:54 +1000140PROGDIR="${GCLIENT_ROOT}/src/program/${FLAGS_board}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000141if [[ ! -d "${PROGDIR}" ]]; then
Andrew McRae7c9655c2020-06-22 15:09:54 +1000142 die "${FLAGS_board} is not a valid program (${PROGDIR} missing)"
Andrew McRae0809eb52020-06-18 00:13:36 +1000143fi
144# Release must be a 5 digit number
Andrew McRae7c9655c2020-06-22 15:09:54 +1000145if [[ ! "${FLAGS_release}" =~ ^${DIGITS}$ ]]; then
Andrew McRaef96cd602020-06-23 23:06:19 +1000146 die "release must be a 5 digit number"
Andrew McRae0809eb52020-06-18 00:13:36 +1000147fi
Andrew McRaef96cd602020-06-23 23:06:19 +1000148# Use a common git branch name.
149BRANCH="update_${FLAGS_board}_fw_${FLAGS_release}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000150#
Andrew McRae7c9655c2020-06-22 15:09:54 +1000151# Build the project list.
Andrew McRaef96cd602020-06-23 23:06:19 +1000152# If no projects are specified, use all in the programs directory.
Andrew McRae0809eb52020-06-18 00:13:36 +1000153#
Andrew McRaef96cd602020-06-23 23:06:19 +1000154if [[ -z "${FLAGS_project}" ]]; then
Andrew McRae7c9655c2020-06-22 15:09:54 +1000155 BDIR="${GCLIENT_ROOT}/src/project/${FLAGS_board}"
Andrew McRaef96cd602020-06-23 23:06:19 +1000156 cd "${BDIR}"
157 mapfile -t PROJLIST < <(ls)
158else
159 IFS=',' read -r -a PROJLIST <<< "${FLAGS_project}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000160fi
Andrew McRae7c9655c2020-06-22 15:09:54 +1000161#
Andrew McRaef96cd602020-06-23 23:06:19 +1000162# Filter out the projects that are to be skipped.
163#
164if [[ -n "${FLAGS_skip}" ]]; then
165 PROJECTS=()
166 IFS=',' read -r -a SKIP_ARRAY <<< "${FLAGS_skip}"
167 SKIPPED="${SKIP_ARRAY[*]}"
168 for P in "${PROJLIST[@]}"; do
169 if ! (in_list "${P}" "${SKIPPED}"); then
170 PROJECTS+=("${P}")
171 fi
172 done
173else
174 PROJECTS=("${PROJLIST[@]}")
175fi
176#
177# Validate project list and file locations.
Andrew McRae7c9655c2020-06-22 15:09:54 +1000178#
179for P in "${PROJECTS[@]}"; do
180 PDIR="${GCLIENT_ROOT}/src/project/${FLAGS_board}/${P}"
181 if [[ ! -d "${PDIR}" ]]; then
182 die "${P} is not a valid project (${PDIR} missing)"
183 fi
184done
Andrew McRaef96cd602020-06-23 23:06:19 +1000185# Validate project overlay location
186OVERLAY="${GCLIENT_ROOT}/src/private-overlays/overlay-${FLAGS_board}-private/chromeos-base/chromeos-firmware-${FLAGS_board}"
187if [[ ! -d "${OVERLAY}" ]]; then
188 die "${OVERLAY}: invalid directory"
189fi
190# Validate ebuild file
191EB9999="chromeos-firmware-${FLAGS_board}-9999.ebuild"
192if [[ ! -f "${OVERLAY}/${EB9999}" ]]; then
193 die "${OVERLAY}/${EB9999}: missing file"
194fi
195# Make sure dev/contrib is accessible
196DEVCONTRIB="${GCLIENT_ROOT}/src/platform/dev/contrib"
197if [[ ! -d "${DEVCONTRIB}" ]]; then
198 die "${DEVCONTRIB}: invalid directory"
199fi
Andrew McRae7c9655c2020-06-22 15:09:54 +1000200#
201# Create a temp directory.
202TEMPDIR=$(mktemp -d -t fw-XXXXXXXXXX)
Andrew McRae7c9655c2020-06-22 15:09:54 +1000203
204trap "exit 1" HUP INT PIPE QUIT TERM
205trap 'cleanup' EXIT
206
Andrew McRae0809eb52020-06-18 00:13:36 +1000207#
208# Update the firmware version in the program config
209# From now on, all errors should invoke 'abort'
Andrew McRae7c9655c2020-06-22 15:09:54 +1000210# so that the branches and CLs are cleaned up on exit.
Andrew McRae0809eb52020-06-18 00:13:36 +1000211#
Andrew McRaef96cd602020-06-23 23:06:19 +1000212cd "${PROGDIR}"
Andrew McRae7c9655c2020-06-22 15:09:54 +1000213echo "Updating ${PROGRAM} for board ${FLAGS_board}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000214branch
Andrew McRae7c9655c2020-06-22 15:09:54 +1000215sed "/^ *major_version = ${DIGITS}$/s/${DIGITS}/${FLAGS_release}/" "${PROGRAM}" > "${TEMPDIR}/new-${PROGRAM}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000216#
217# Verify that only 1-5 characters have changed.
218#
219DIFF=$(cmp -l "${PROGRAM}" "${TEMPDIR}/new-${PROGRAM}" | wc -l)
220if [[ "${DIFF}" -gt 5 ]]; then
221 diff "${PROGRAM}" "new-${TEMPDIR}/${PROGRAM}"
222 abort "${PROGDIR}/${PROGRAM} update error"
Andrew McRae0809eb52020-06-18 00:13:36 +1000223fi
224#
225# If program config has changed, create a CL.
226#
227if [[ "${DIFF}" -ne 0 ]]; then
228 cp "${TEMPDIR}/new-${PROGRAM}" "${PROGRAM}"
229 git add .
Andrew McRaef96cd602020-06-23 23:06:19 +1000230 git commit -q -F - <<EOF
Andrew McRae7c9655c2020-06-22 15:09:54 +1000231${FLAGS_board}: Update firmware to ${FLAGS_release}
Andrew McRae0809eb52020-06-18 00:13:36 +1000232
233BUG=none
Andrew McRae7c9655c2020-06-22 15:09:54 +1000234TEST=FAFT tests on ${FLAGS_board}
Andrew McRae0809eb52020-06-18 00:13:36 +1000235EOF
Andrew McRaef96cd602020-06-23 23:06:19 +1000236 if ! repo upload -y "--ht=${BRANCH}" --cbr . > "${TEMPDIR}/upload.output" 2>&1 ;then
237 cat "${TEMPDIR}/upload.output"
238 abort "repo upload failed"
239 fi
Andrew McRae7c9655c2020-06-22 15:09:54 +1000240 PROGRAM_CL=$(getcl "program/${FLAGS_board}" "${TEMPDIR}/upload.output")
Andrew McRae0809eb52020-06-18 00:13:36 +1000241fi
242#
243# Now walk through the projects and regenerate the configs.
244# Create and upload a CL and capture the CL number and project directory
245# if the project has changed.
246#
247PROJ_CLS=()
248PROJ_DIRS=()
Andrew McRae7c9655c2020-06-22 15:09:54 +1000249for PROJ in "${PROJECTS[@]}"; do
250 echo "Updating configs for project ${PROJ}"
251 PDIR="${GCLIENT_ROOT}/src/project/${FLAGS_board}/${PROJ}"
Andrew McRaef96cd602020-06-23 23:06:19 +1000252 cd "${PDIR}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000253 branch
254 ./config.star || abort "Generate config failed for ${PROJ}"
255 check_config > "${TEMPDIR}/check_config-${PROJ}.output" || abort "check_config failed for ${PROJ}"
256 #
257 # Check if any files changed.
258 #
259 if changed; then
Andrew McRaef96cd602020-06-23 23:06:19 +1000260 echo "Creating CL for changes to project ${PROJ}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000261 git add .
Andrew McRaef96cd602020-06-23 23:06:19 +1000262 git commit -q -F - <<EOF
Andrew McRae7c9655c2020-06-22 15:09:54 +1000263${PROJ}: Update firmware to ${FLAGS_release}
Andrew McRaef96cd602020-06-23 23:06:19 +1000264
Andrew McRae0809eb52020-06-18 00:13:36 +1000265BUG=none
Andrew McRae7c9655c2020-06-22 15:09:54 +1000266TEST=FAFT tests on ${FLAGS_board}
Andrew McRae0809eb52020-06-18 00:13:36 +1000267EOF
Andrew McRaef96cd602020-06-23 23:06:19 +1000268 if ! repo upload -y "--ht=${BRANCH}" --cbr . > "${TEMPDIR}/upload.${PROJ}.output" 2>&1 ;then
269 cat "${TEMPDIR}/upload.${PROJ}.output"
270 abort "repo upload failed"
271 fi
Andrew McRae7c9655c2020-06-22 15:09:54 +1000272 P_CL=$(getcl "project/${FLAGS_board}/${PROJ}" "${TEMPDIR}/upload.${PROJ}.output")
Andrew McRae0809eb52020-06-18 00:13:36 +1000273 PROJ_CLS+=("${P_CL}")
274 PROJ_DIRS+=("${PDIR}")
275 fi
276done
277#
278# Create a Cq-Depend line with all the project CLs
279#
280if [[ -n "${PROJ_CLS[*]}" ]];then
281 SEP=" "
282 PROG_CQD="Cq-Depend:"
283 for CL in "${PROJ_CLS[@]}"; do
284 PROG_CQD="${PROG_CQD}${SEP}chrome-internal:${CL}"
285 SEP=", "
286 done
287 #
Andrew McRaef96cd602020-06-23 23:06:19 +1000288 # If a program CL exists, add the Cq-Depend line to it.
Andrew McRae0809eb52020-06-18 00:13:36 +1000289 #
Andrew McRaef96cd602020-06-23 23:06:19 +1000290 if [[ -n "${PROGRAM_CL}" ]]; then
291 cd "${PROGDIR}"
292 amend "${PROG_CQD}"
293 if ! repo upload -y "--ht=${BRANCH}" --cbr . > "${TEMPDIR}/upload.amend.output" 2>&1 ;then
294 cat "${TEMPDIR}/upload.amend.output"
295 abort "repo upload failed"
296 fi
297 fi
Andrew McRae0809eb52020-06-18 00:13:36 +1000298fi
299#
300# All the boxster configs have been uploaded.
301# Now run the update script and update the firmware manifest.
302#
303# Build base coreboot files
304# TODO: Should be selective here.
305#
306echo "Running emerge for coreboot. This may take a while..."
Andrew McRae7c9655c2020-06-22 15:09:54 +1000307if ! ("emerge-${FLAGS_board}" --quiet-build chromeos-ec coreboot depthcharge vboot_reference \
Andrew McRae0809eb52020-06-18 00:13:36 +1000308 libpayload chromeos-bootimage coreboot-private-files \
Andrew McRae7c9655c2020-06-22 15:09:54 +1000309 "coreboot-private-files-${FLAGS_board}"); then
Andrew McRae0809eb52020-06-18 00:13:36 +1000310 abort "emerge for coreboot failed!"
311fi
312echo "emerge of coreboot successful"
Andrew McRae7c9655c2020-06-22 15:09:54 +1000313EB9999="chromeos-firmware-${FLAGS_board}-9999.ebuild"
Andrew McRae0809eb52020-06-18 00:13:36 +1000314#
315# Remove any previous attempts to build the firmware.
316#
Andrew McRae7c9655c2020-06-22 15:09:54 +1000317"cros_workon-${FLAGS_board}" stop "chromeos-base/chromeos-firmware-${FLAGS_board}"
318"cros_workon-${FLAGS_board}" stop "chromeos-base/chromeos-config-bsp-${FLAGS_board}-private"
Andrew McRaef96cd602020-06-23 23:06:19 +1000319cd "${OVERLAY}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000320branch
Andrew McRaef96cd602020-06-23 23:06:19 +1000321cd "${DEVCONTRIB}"
Andrew McRae7c9655c2020-06-22 15:09:54 +1000322if ! (./cros_update_firmware -q "--board=${FLAGS_board}"); then
323 abort "cros_update_firmware failed for ${FLAGS_board}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000324fi
Andrew McRaef96cd602020-06-23 23:06:19 +1000325cd "${OVERLAY}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000326#
327# If files have been updated, then create a CL for the changes.
328#
329OVERLAY_CL=""
330if changed; then
331 #
332 # Bump the version in the ebuild file. Relies on the format
333 # of the version so that the last number is at the end of the line.
334 #
335 CURVERS=$(grep "VERSION=REVBUMP" "${EB9999}" | grep -o "[0-9][0-9]*$")
336 NEXTVERS=$((CURVERS + 1))
Andrew McRaef96cd602020-06-23 23:06:19 +1000337 sed -i "/VERSION=REVBUMP/s/${CURVERS}$/${NEXTVERS}/" "${EB9999}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000338 git add .
Andrew McRaef96cd602020-06-23 23:06:19 +1000339 git commit -q -F - <<EOF
Andrew McRae7c9655c2020-06-22 15:09:54 +1000340${FLAGS_board}: Update firmware to ${FLAGS_release}
Andrew McRae0809eb52020-06-18 00:13:36 +1000341
342BUG=none
Andrew McRae7c9655c2020-06-22 15:09:54 +1000343TEST=FAFT tests on ${FLAGS_board}
Andrew McRae0809eb52020-06-18 00:13:36 +1000344
Andrew McRaef96cd602020-06-23 23:06:19 +1000345${PROG_CQD}
Andrew McRae0809eb52020-06-18 00:13:36 +1000346EOF
347 #
348 # Upload with no-verify since the file lines are too long.
349 #
Andrew McRaef96cd602020-06-23 23:06:19 +1000350 if ! repo upload "--ht=${BRANCH}" -y --no-verify --cbr . > "${TEMPDIR}/overlay.output" 2>&1 ;then
351 cat "${TEMPDIR}/overlay.output"
352 abort "repo upload failed"
353 fi
Andrew McRae7c9655c2020-06-22 15:09:54 +1000354 OVERLAY_CL=$(getcl "overlays/overlay-${FLAGS_board}-private" "${TEMPDIR}/overlay.output")
Andrew McRae0809eb52020-06-18 00:13:36 +1000355 #
356 # Go back and amend all the project commit messages with a Cq-Depend on
357 # the program and overlay CLs.
358 #
359 CQD="Cq-Depend: chrome-internal:${OVERLAY_CL}"
360 if [[ -n "${PROGRAM_CL}" ]]; then
361 CQD="${CQD}, chrome-internal:${PROGRAM_CL}"
362 fi
363 for DIR in "${PROJ_DIRS[@]}"; do
Andrew McRaef96cd602020-06-23 23:06:19 +1000364 cd "${DIR}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000365 amend "${CQD}"
Andrew McRaef96cd602020-06-23 23:06:19 +1000366 if ! repo upload -y --cbr . > "${TEMPDIR}/cqd.output" 2>&1 ;then
367 cat "${TEMPDIR}/cqd.output"
368 abort "repo upload failed"
369 fi
Andrew McRae0809eb52020-06-18 00:13:36 +1000370 done
371fi
372#
373# Send all of the CLs to the CQ for a dry run.
374#
375ALL_CLS=$(gerrit -i --raw search "owner:me status:open hashtag:${BRANCH}")
376if [[ -z "${ALL_CLS}" ]]; then
Andrew McRae7c9655c2020-06-22 15:09:54 +1000377 echo "No changes required for program ${FLAGS_board}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000378 repo abandon "${BRANCH}"
379 exit 0
380fi
381for cl in ${ALL_CLS}; do
382 gerrit -i label-cq "${cl}" 1
383 gerrit -i label-v "${cl}" 1
384 gerrit -i label-as "${cl}" 1
385done
386#
387# If reviewer is set, then add them to the CLs
388#
Andrew McRae7c9655c2020-06-22 15:09:54 +1000389if [[ -n "${FLAGS_reviewer}" ]]; then
390 echo "Sending CLs ${ALL_CLS} to ${FLAGS_reviewer} for review"
Andrew McRae0809eb52020-06-18 00:13:36 +1000391 for cl in ${ALL_CLS}; do
Andrew McRae7c9655c2020-06-22 15:09:54 +1000392 gerrit -i reviewers "${cl}" "${FLAGS_reviewer}"
Andrew McRae0809eb52020-06-18 00:13:36 +1000393 done
394else
395 echo "Send CLs for review by running:"
396 echo " for cl in ${ALL_CLS}; do gerrit -i reviewers \$cl <reviewer>; done"
397fi
398#
399# Final instructions.
400#
401echo "Run:"
Andrew McRae7c9655c2020-06-22 15:09:54 +1000402echo " /build/${FLAGS_board}/usr/sbin/chromeos-firmwareupdate --manifest"
Andrew McRae0809eb52020-06-18 00:13:36 +1000403echo "to verify firmware update"
404echo "When submitted, cleanup by running:"
405echo "repo abandon ${BRANCH}"