new_variant: Add support for including a depthcharge target

Now that depthcharge implicitly includes the static_fw_config.h file
directly from coreboot (and each variant defines its own FW_CONFIG
fields), a depthcharge build target is required for each variant as
well. This patch adds support for this, and updates the new_variant
integration test.

BUG=b:193527706
TEST=new_variant_fulltest.sh brya0 passes

Cq-Depend: chromium:3039838
Signed-off-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Change-Id: If4ebfa6c292006c11ac6f08daaf7625abd148a90
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/3039050
Reviewed-by: Paul Fagerburg <pfagerburg@chromium.org>
Reviewed-by: Nick Vaccaro <nvaccaro@google.com>
diff --git a/contrib/variant/brya0.py b/contrib/variant/brya0.py
index 01c3c2a..2b49ce3 100644
--- a/contrib/variant/brya0.py
+++ b/contrib/variant/brya0.py
@@ -22,6 +22,7 @@
     step_names.FW_BUILD_CONFIG,
     step_names.CB_VARIANT,
     step_names.CB_CONFIG,
+    step_names.DC_VARIANT,
     step_names.ADD_FIT,
     step_names.GEN_FIT,
     step_names.COMMIT_FIT,
diff --git a/contrib/variant/create_depthcharge_variant.sh b/contrib/variant/create_depthcharge_variant.sh
new file mode 100755
index 0000000..2b59602
--- /dev/null
+++ b/contrib/variant/create_depthcharge_variant.sh
@@ -0,0 +1,137 @@
+#!/bin/bash
+# Copyright 2021 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.
+
+VERSION="1.0.0"
+SCRIPT="$(basename -- "$0")"
+set -e
+
+# Disable a warning about DC_SRC_DIR not being defined; we look for it in
+# the environment, and if it isn't found, then we'll exit.
+# shellcheck disable=SC2154
+if [[ -z "${DC_SRC_DIR}" ]]; then
+  echo "DC_SRC_DIR must be set in the environment"
+  exit 1
+fi
+
+if [[ "$#" -lt 3 ]]; then
+  echo "Usage: ${SCRIPT} base_name reference_name variant_name [bug_number]"
+  echo "e.g., ${SCRIPT} brya brya0 primus"
+  echo "e.g., ${SCRIPT} brya brask brask"
+  echo "* Copies the template files for the baseboard to the new variant"
+  exit 1
+fi
+
+to_lower() {
+  # Convert a string to lower case using ASCII translation rules.
+  LC_ALL=C LOWER="${1,,}"
+  echo "${LOWER}"
+}
+
+to_upper() {
+  # Convert a string to upper case using ASCII translation rules.
+  LC_ALL=C UPPER="${1^^}"
+  echo "${UPPER}"
+}
+
+# shellcheck source=check_standalone.sh
+# shellcheck disable=SC1091
+source "${BASH_SOURCE%/*}/check_standalone.sh"
+check_standalone
+
+# shellcheck source=check_pending_changes.sh
+# shellcheck disable=SC1091
+source "${BASH_SOURCE%/*}/check_pending_changes.sh"
+
+# This is the name of the base board
+BASE="$(to_lower "$1")"
+# This is the name of the reference board that we're using to make the variant.
+REFERENCE="$(to_lower "$2")"
+# This is the name of the variant that is being cloned.
+VARIANT="$(to_lower "$3")"
+
+# Assign BUG= text, or "None" if that parameter wasn't specified.
+BUG="${4:-None}"
+
+# Assign the value for BRANCH= in the commit message, or use None if unspecified
+COMMIT_MSG_BRANCH="${NEW_VARIANT_BRANCH:-None}"
+
+# The template files are in ${DC_SRC_DIR}/util/template
+DEFCONFIG="${DC_SRC_DIR}/util/template/board/${BASE}/defconfig"
+VARIANTC="${DC_SRC_DIR}/util/template/src/board/${BASE}/variant.c"
+
+pushd "${DC_SRC_DIR}"
+
+# Make sure the variant doesn't already exist.
+if [[ -e "${DC_SRC_DIR}/src/board/${VARIANT}/board.c" ]]; then
+  echo "${VARIANT}/board.c already exists."
+  echo "Have you already created this variant?"
+  exit 1
+fi
+
+# If there are pending changes, exit the script (unless overridden)
+check_pending_changes "$(pwd)"
+
+# Start a branch. Use YMD timestamp to avoid collisions.
+DATE="$(date +%Y%m%d)"
+BRANCH="depthcharge_${VARIANT}_${DATE}"
+repo start "${BRANCH}" . --head #"${NEW_VARIANT_WIP:+--head}"
+# ${parameter:+word}" substitutes "word" if $parameter is set to a non-null
+# value, or substitutes null if $parameter is null or unset.
+
+abandon() {
+  # If there is an error after the `repo start` and before we start adding
+  # changes to git, then delete the new variant directory and `repo abandon`
+    # the new branch.
+  rm -rRf "${DC_SRC_DIR}/src/board/${BASE}/${VARIANT}"
+  rm -Rf "${DC_SRC_DIR}/board/${VARIANT}/defconfig"
+  repo abandon "${BRANCH}" .
+}
+trap 'abandon' ERR
+
+# Copy template defconfig
+pushd "${DC_SRC_DIR}"
+mkdir -p "board/${VARIANT}/"
+cp "${DEFCONFIG}" "board/${VARIANT}/defconfig"
+
+# Fixup CONFIG_VARIANT_NAME
+sed -i -e "s/CONFIG_VARIANT_NAME.*/CONFIG_VARIANT_NAME=\"${VARIANT}\"/" \
+    "board/${VARIANT}/defconfig"
+
+# Copy variant.c
+cp "${VARIANTC}" "src/board/${BASE}/${VARIANT}.c"
+
+git add "src/board/${BASE}/${VARIANT}.c"
+git add "board/${VARIANT}/defconfig"
+
+restore_git() {
+  # After adding changes to git, now to recover from an error we need to
+  # remove the variant from the git commit
+  pushd "${DC_SRC_DIR}/"
+  git restore --staged .
+  git restore .
+  popd
+  # And call the previous trap function.
+  abandon
+}
+trap 'restore_git' ERR
+
+# Now commit the files. Use fmt to word-wrap the main commit message.
+MSG=$(echo "Create a depthcharge target ${VARIANT} by copying the template
+files from the reference ${REFERENCE} to the appropriate
+places in the source tree." | fmt -w 70)
+
+git commit -sm "Create ${VARIANT} variant
+
+${MSG}
+
+(Auto-Generated by ${SCRIPT} version ${VERSION}).
+
+BUG=${BUG}
+BRANCH=${COMMIT_MSG_BRANCH}
+TEST=FW_NAME=${VARIANT} emerge-${BASE} depthcharge
+"
+# TODO(b/149702214): verify that it builds correctly
+
+popd
diff --git a/contrib/variant/new_variant.py b/contrib/variant/new_variant.py
index e608872..f4d04fe 100755
--- a/contrib/variant/new_variant.py
+++ b/contrib/variant/new_variant.py
@@ -13,6 +13,7 @@
 
 * platform/dev/contrib/variant/create_coreboot_variant.sh
 * platform/dev/contrib/variant/create_coreboot_config.sh
+* platform/dev/contrib/variant/create_depthcharge_config.sh
 * private-overlays/baseboard-hatch-private/sys-boot/
  * coreboot-private-files-hatch/files/add_fitimage.sh
  * coreboot-private-files-hatch/asset_generation/gen_fit_image.sh
@@ -27,6 +28,7 @@
 * third_party/coreboot
 * third_party/chromiumos-overlay
 * private-overlays/baseboard-hatch-private
+* platform/depthcharge
 * platform/ec
 * private-overlays/overlay-hatch-private
 * overlays
@@ -234,6 +236,8 @@
     * cb_config_dir - base directory for coreboot configs, usually
         third_party/chromiumos-overlay/sys-boot/coreboot/files/configs but
         could differ for processors that use a private repo
+    * depthcharge_dir - base directory for depthcharge, usually
+        platform/depthcharge
     * step_list - list of steps (named in step_names.py) to run in sequence
         to create the new variant of the reference board
     * ec_board - EC board to use as a reference. Defaults to the value of
@@ -374,6 +378,12 @@
     status.coreboot_reference   = getattr(module, 'coreboot_reference',
                                           status.board)
     status.cb_config_dir        = getattr(module, 'cb_config_dir', None)
+    status.depthcharge_dir      = getattr(module, 'depthcharge_base',
+                                          'platform/depthcharge')
+    status.depthcharge_base     = getattr(module, 'depthcharge_base',
+                                          status.coreboot_base)
+    status.depthcharge_ref      = getattr(module, 'depthcharge_ref',
+                                          status.coreboot_base)
     status.ec_board             = getattr(module, 'ec_board', status.board)
     status.emerge_cmd           = module.emerge_cmd
     status.emerge_pkgs          = module.emerge_pkgs
@@ -425,6 +435,7 @@
         step_names.FW_BUILD_CONFIG: fw_build_config,
         step_names.CB_VARIANT:      create_coreboot_variant,
         step_names.CB_CONFIG:       create_coreboot_config,
+        step_names.DC_VARIANT:      create_depthcharge_variant,
         step_names.CRAS_CONFIG:     copy_cras_config,
         step_names.ADD_FIT:         add_fitimage,
         step_names.GEN_FIT:         gen_fit_image_outside_chroot,
@@ -794,6 +805,35 @@
     return rc
 
 
+def create_depthcharge_variant(status):
+    """Create source files for a new variant of the reference board in depthcharge
+
+    This function calls create_depthcharge_variant.sh to set up a new variant
+    of the reference board.
+
+    Args:
+        status: variant_status object tracking our board, variant, etc.
+
+    Returns:
+        True if everything succeeded, False if something failed
+    """
+    logging.info('Running step create_depthcharge_variant')
+    dc_src_dir = os.path.join('/mnt/host/source/src/', status.depthcharge_dir)
+    environ = {**os.environ, 'DC_SRC_DIR': dc_src_dir,
+               'NEW_VARIANT_BRANCH': status.branch}
+    create_depthcharge_variant_sh = os.path.join(status.my_loc,
+        'create_depthcharge_variant.sh')
+    rc = run_process(
+        [create_depthcharge_variant_sh,
+        status.depthcharge_base,        # base
+        status.depthcharge_ref,         # reference
+        status.variant,                 # variant
+        status.bug], env=environ)
+    if rc:
+        status.commits[step_names.DC_VARIANT] = get_git_commit_data(dc_src_dir)
+    return rc
+
+
 def copy_cras_config(status):
     """Copy the cras config for a new variant
 
diff --git a/contrib/variant/step_names.py b/contrib/variant/step_names.py
index a35da81..3f3ce45 100644
--- a/contrib/variant/step_names.py
+++ b/contrib/variant/step_names.py
@@ -13,6 +13,7 @@
 PROJECT_CONFIG  = 'project_config'
 CB_VARIANT      = 'cb_variant'
 CB_CONFIG       = 'cb_config'
+DC_VARIANT      = 'dc_variant'
 CRAS_CONFIG     = 'cras_config'
 ADD_FIT         = 'add_fit'
 GEN_FIT         = 'gen_fit'
diff --git a/contrib/variant/testdata/new_variant_fulltest.sh b/contrib/variant/testdata/new_variant_fulltest.sh
index 9c68bf9..cef46fd 100755
--- a/contrib/variant/testdata/new_variant_fulltest.sh
+++ b/contrib/variant/testdata/new_variant_fulltest.sh
@@ -236,6 +236,13 @@
   popd
 fi
 
+# Explicitly set the desired firmware targets
+BUILD_TARGETS_SED="s/_FW_BUILD_CONFIG = None/_FW_BUILD_CONFIG = sc.create_fw_build_config(sc.create_fw_build_targets(\
+coreboot='${NEW}',\
+depthcharge='${NEW}',\
+libpayload='${BASE}',\
+ec='${NEW}'))\n/"
+
 # Create the project configuration repo, if defined.
 if [[ ! -z ${CONFIG_DIR+x} ]] ; then
   mkdir -p "${CONFIG_DIR}/${NEW}"
@@ -247,8 +254,9 @@
   # fw_build_config.sh to make the changes we need. Instead just apply the
   # changes manually.
   pushd "${CONFIG_DIR}/${NEW}"
-  # Apply FW_BUILD_CONFIG to new project and build the config
-  sed -i -e "s/_FW_BUILD_CONFIG = None/_FW_BUILD_CONFIG = program.firmware_build_config(_${NEW_UPPER})/" config.star
+  # Load sw_config.star and update FW_BUILD_CONFIG to new project and build the config
+  sed -i '4s/^/load("\/\/config\/util\/sw_config.star",sc="sw_config")\n/' config.star
+  sed -i -e "${BUILD_TARGETS_SED}" config.star
   ./config.star
   popd
 fi