#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # Copyright (C) 2018-present Team LibreELEC (https://libreelec.tv) # Handler for git # Usage (in package.mk): # PKG_URL (mandatory) must point to a git repository (git://... or https://example.com/repo.git) # PKG_VERSION (mandatory) must point to a commit SHA, e.g. a1b2c3d # PKG_GIT_SHA (optional) full hash of git commit # PKG_GIT_CLONE_BRANCH (optional) clone specific branch # PKG_GIT_CLONE_SINGLE (optional) clone single branch only (set to yes) # PKG_GIT_CLONE_DEPTH (optional) history to clone, must be a number # PKG_GIT_SUBMODULE_DEPTH (optional) history of submodules to clone, must be a number set -e set -o pipefail #_debug=true if [[ "${_debug}" ]] ; then export PS4='+${BASH_SOURCE}:${LINENO}: ' set -x fi _clean_repo() { git clean -fdx git restore --staged . || git switch --force # Clear changes and ensure correct branch } _repo_exists_and_valid() { if [[ -d "${PACKAGE}" ]]; then pushd "${PACKAGE}" > /dev/null _clean_repo || return 1 if ! git ls-remote . | grep -q -m1 "^${PKG_VERSION}"; then echo "ERROR: ${PACKAGE}: failed to determine git HEAD" >&2 return 1 fi if [[ "${PKG_URL}" != "$(git remote get-url origin)" ]]; then echo "ERROR: ${PACKAGE}: failed to obtain URL of origin" >&2 return 1 fi if [[ -n "${PKG_GIT_CLONE_BRANCH}" && "${PKG_GIT_CLONE_BRANCH}" != "$(git rev-parse --abbrev-ref HEAD)" ]]; then echo "ERROR: ${PACKAGE}: failed to determine current git branch" >&2 return 1 fi popd > /dev/null return 0 fi return 1 } _update_submodules() { if [[ -n "${GIT_SUBMODULE_PARAMS}" ]]; then submodules=$(git config --file .gitmodules --get-regexp path | awk '{ print $2 }') else submodules=$(git submodule | awk '{ print $2 }') fi for submodule in $submodules; do echo "Updating submodule: $submodule" # Try to update the submodule git submodule update --init --recursive ${GIT_SUBMODULE_PARAMS} -- "${submodule}" _rv=$? if [[ $_rv != 0 ]] ; then echo "Failed to update submodule: $submodule" # Deinit, sync, and reinit the submodule echo "Deinitializing submodule: $submodule" git submodule deinit -f "${submodule}" echo "Syncing submodule: $submodule" git submodule sync -- "${submodule}" echo "Reinitializing submodule: $submodule" git submodule update --init --recursive ${GIT_SUBMODULE_PARAMS} -- "${submodule}" _rv=$? if [[ $_rv != 0 ]] ; then echo "Failed to reinitialize submodule: $submodule" return 1 fi fi #popd > /dev/null done return 0 } _get_repo() { local git_params=("--recursive" "--shallow-submodules" "--filter=blob:none" "--no-tags") [[ -n "${PKG_GIT_CLONE_BRANCH}" ]] && git_params+=("--branch" "${PKG_GIT_CLONE_BRANCH}") [[ "${PKG_GIT_CLONE_SINGLE}" == "yes" ]] && git_params+=("--single-branch") if [[ -n "${PKG_GIT_CLONE_DEPTH}" ]]; then if [[ "${PKG_GIT_CLONE_DEPTH}" =~ ^[0-9]+$ ]]; then git_params+=("--depth" "${PKG_GIT_CLONE_DEPTH}") else echo "ERROR: PKG_GIT_CLONE_DEPTH is not a number! (${PKG_GIT_CLONE_DEPTH})" >&2 return 1 fi fi if [[ -n "${PKG_GIT_SUBMODULE_DEPTH}" ]]; then if [[ "${PKG_GIT_SUBMODULE_DEPTH}" =~ ^[0-9]+$ ]]; then GIT_SUBMODULE_PARAMS="${GIT_SUBMODULE_PARAMS} --depth ${PKG_GIT_SUBMODULE_DEPTH}" else die "ERROR: PKG_GIT_SUBMODULE_DEPTH is not a number! (${PKG_GIT_SUBMODULE_DEPTH})" fi fi # Check if the destination directory exists and is non-empty if [[ -d "${PACKAGE}" && "$(ls -A "${PACKAGE}")" ]]; then echo "Directory ${PACKAGE} already exists and is not empty. Removing it." rm -rf "${PACKAGE}" && mkdir "${PACKAGE}" || return 1 fi cd .. echo "Cloning repository with parameters: ${git_params[*]}" git clone "${git_params[@]}" "${PKG_URL}" "${PACKAGE}" || return 1 pushd "${PACKAGE}" > /dev/null echo "Resetting to commit: ${PKG_VERSION}" git reset --hard "${PKG_VERSION}" || return 1 echo "Updating submodules..." _update_submodules || { echo "Submodule update failed." return 1 } popd > /dev/null # Get the SHA of the current HEAD local GIT_SHA while read -r line; do if [[ $line == *HEAD ]]; then GIT_SHA="${line%%[[:space:]]*}" break fi done < <(git ls-remote "${PACKAGE}") if [[ -z "${GIT_SHA}" ]]; then echo "Failed to retrieve GIT_SHA." return 1 fi if [[ -n "${PKG_GIT_SHA}" && "${PKG_GIT_SHA}" != "${GIT_SHA}" ]]; then build_msg "CLR_WARNING" "WARNING" "Incorrect git hash in repository: got ${GIT_SHA}, wanted ${PKG_GIT_SHA}" >&2 return 1 fi echo "Repository setup completed successfully." return 0 } _fetch_missing_submodule_commits() { git submodule sync --recursive for submodule in $(git config --file .gitmodules --get-regexp path | awk '{ print $2 }'); do pushd "${submodule}" > /dev/null echo "Fetching all refs and tags for submodule: ${submodule}" git fetch --all --tags --prune || return 1 if ! git rev-parse "${PKG_VERSION}" &> /dev/null; then echo "Commit ${PKG_VERSION} not found in ${submodule}, attempting to fetch it explicitly." git fetch origin "${PKG_VERSION}:${PKG_VERSION}" || return 1 fi if ! git checkout "${PKG_VERSION}" ; then echo "Failed to checkout commit ${PKG_VERSION} in ${submodule}, trying branch instead." git checkout -B "${PKG_GIT_CLONE_BRANCH}" || return 1 fi popd > /dev/null done } main(){ # Acquire lock on source dir lock_source_dir "${1}" # Check if repo already exists and is valid _repo_exists_and_valid && exit 0 if [[ "${PKG_USETOKEN}" == "yes" && -n "${ARCHR_GHTOKEN}" ]]; then PKG_URL="${PKG_URL/https:\/\//https:\/\/${ARCHR_GHTOKEN}@}" fi # If not valid, proceed to get the repo build_msg "CLR_GET" "GET" "${1} (git)" "indent" # Remove stale stamps rm -f "${STAMP_URL}" "${STAMP_SHA}" # Clone or update the repository _get_repo || exit 1 # Verify the git hash GIT_SHA="" while IFS=$'\t' read -r sha ref; do if [[ "$ref" == "HEAD" ]]; then GIT_SHA="$sha" break fi done < <(git ls-remote "${PACKAGE}") # Check if GIT_SHA was successfully retrieved if [[ -z "$GIT_SHA" ]]; then echo "Failed to retrieve GIT_SHA." >&2 exit 1 fi # Verify that the retrieved SHA matches the expected one if [[ -n "${PKG_GIT_SHA}" && "${PKG_GIT_SHA}" != "${GIT_SHA}" ]]; then build_msg "CLR_WARNING" "WARNING" "Incorrect git hash in repository: got ${GIT_SHA}, wanted ${PKG_GIT_SHA}" >&2 exit 1 fi echo "Repository setup completed successfully." } main