#!/usr/bin/env sh # helper script: create code trees based on git revision, with patches # (currently used for downloading coreboot, seabios and u-boot) # # Copyright (C) 2014-2016,2020,2021,2023 Leah Rowe # Copyright (C) 2022 Alper Nebi Yasak # Copyright (C) 2022 Ferass El Hafidi # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # [ "x${DEBUG+set}" = 'xset' ] && set -v set -u -e . "include/err.sh" _target="" tree="" rev="" project="" cfgsdir="" main() { rm -f "${cfgsdir}"/*/seen || err_rm_seen "main 1" printf "Downloading %s and (if available) applying patches\n" \ ${project} [ -z "${1}" ] && err "project name not specified" project="${1}" cfgsdir="config/${project}" [ -d "${cfgsdir}" ] || err "unsupported project name" shift 1 targets=$(./build command options "${cfgsdir}") [ $# -gt 0 ] && targets=$@ [ -z "${targets}" ] && \ err "No targets available for project: ${project}" for x in ${targets}; do rm -f "${cfgsdir}"/*/seen || err_rm_seen "main 2" download_for_target "${x}" || \ err "${project}/${target}: cannot download source tree" done rm -f "${cfgsdir}"/*/seen || err_rm_seen "main 3" } download_for_target() { _target="${1}" tree="undefined" rev="undefined" fetch_config "${_target}" || \ err "download_for_target: ${project}/${_target}: bad target.cfg" rm -f "${cfgsdir}"/*/seen || err_rm_seen "download_for_target" if [ -d "${project}/${tree}" ]; then printf "REMARK: download/%s %s: exists. Skipping.\n" \ "${project}" "${tree}" 1>&2 [ "${tree}" != "${_target}" ] && \ printf "(for target: '%s}')\n" "${_target}" 1>&2 return 0 fi fetch_from_upstream || \ err "download_for_target: cannot fetch: ${project}" prepare_new_tree "${_target}" "${tree}" "${rev}" || \ err "download_for_target: cannot create tree: ${project}/${tree}" } fetch_config() { _target=${1} while true; do rev="undefined" tree="undefined" check_config_for_target "${_target}" || return 1 # This is to override $rev and $tree . "${cfgsdir}/${_target}/target.cfg" || \ err "fetch_config: no \"${cfgsdir}/${_target}/target.cfg\"" if [ "${_target}" != "${tree}" ]; then _target="${tree}" continue elif [ "${tree}" = "undefined" ]; then printf "ERROR (fetch_config): download/%s:" 1>&2 printf " tree name undefined for '%s\n'" \ "${project}" "${_target}" 1>&2 return 1 elif [ "${rev}" = "undefined" ]; then printf "ERROR (fetch_config): download/%s:" 1>&2 printf " commit ID undefined for '%s'\n" \ "${project}" "${_target}" 1>&2 return 1 else break fi done } check_config_for_target() { _target=${1} if [ ! -f "${cfgsdir}/${_target}/target.cfg" ]; then printf "ERROR: download/%s: target.cfg does not" \ "${project}" 1>&2 printf " exist for '%s'\n" "${_target}" 1>&2 return 1 elif [ -f "${cfgsdir}/${_target}/seen" ]; then printf "ERROR: download/%s: logical loop:" "${project}" 1>&2 printf " '%s' target.cfg refers to another tree," "${_target}" \ 1>&2 printf " which ultimately refers back to '%s'." "${_target}" \ 1>&2 return 1 fi touch "${cfgsdir}/${_target}/seen" || \ err "${project}/${_target}: touch \"${cfgsdir}/${_target}/seen\"" } fetch_from_upstream() { [ -d "${project}" ] || mkdir -p "${project}" || return 1 [ -d "${project}" ] || return 1 [ -d "${project}/${project}" ] && return 0 ./update project repo ${project} || return 1 } prepare_new_tree() { target=${1} tree=${2} rev=${3} printf "Preparing %s tree: %s\n" ${project} ${tree} [ "${tree}" != "${target}" ] && \ printf "(for target, %s)\n" "${target}" cp -R "${project}/${project}" "${project}/${tree}" || \ err "${project}/${tree}: cannot copy source tree" ( cd "${project}/${tree}" || err "cannot cd to ${project}/${tree}" git reset --hard ${rev} || \ err "cannot reset ${project} revision for tree, ${tree}" git submodule update --init --checkout || \ err "cannot update ${project} submodules for tree, ${tree}" for patch in "../../${cfgsdir}/${tree}/patches/"*.patch; do [ -f "${patch}" ] || continue if ! git am "${patch}"; then git am --abort || \ err "${project}/${tree}: FAILED: git am --abort" err "cannot patch: ${project}/${tree}" fi done # extra.sh can be used for anything # but should *only* be a last resort if [ -f "../../${cfgsdir}/${tree}/extra.sh" ]; then "../../${cfgsdir}/${tree}/extra.sh" || \ err "prepare_new_tree ${project}/${tree}: extra.sh: error" fi ) } err_rm_seen() { err "${1}: ${project}/${target}: cannot rm: \"${cfgsdir}/*/seen\"" } main $@