git-r3.eclass: Respect overrides and fallbacks in ls-remote call

Refactor the eclass logic to defer the 'git ls-remote' call used to
determine the object format until overrides are in place.  Move it into
repository fetching loop so that mirrors and fallback URIs are respected
as well.  While at it, fix duplicate directory entries in
EVCS_STORE_DIRS, and avoid creating an empty directory if 'git
ls-remote' fails.

For historical reasons, git-r3_set_gitdir function was responsible both
for setting the value of GIT_DIR and creating it if necessary.
To ensure that GIT_DIR was stable, the canonical URI was always used.
No network traffic was involved at this stage.

While adding sha256 support in 0477949bcf,
an additional 'git ls-remote' call was added to determine the remote
object format before creating GIT_DIR.  We've missed that this call
would be performed early on, with no respect for repository URI
overrides, mirrors and fallback URIs.  Most of the time this wasn't
a problem, at least as long as the canonical URI was reachable and had
the same object format.

It seems that the cleanest solution to this is to split setting GIT_DIR
from creating it.  The former still needs to be done early, using
the canonical URI.  The latter is best done in the fetching loop where
we are already iterating over the final list of URIs.  This also permits
us to easily support fallback when the initial URI fails, much like we
do in the 'git fetch' invocation.

Closes: https://bugs.gentoo.org/979189
Signed-off-by: Michał Górny <mgorny@gentoo.org>
Part-of: https://codeberg.org/gentoo/gentoo/pulls/1708
Merges: https://codeberg.org/gentoo/gentoo/pulls/1708
This commit is contained in:
Michał Górny
2026-08-22 10:18:41 +02:00
parent 11a2406ca4
commit eae4d76cd2

View File

@@ -343,6 +343,47 @@ _git-r3_get_object_format() {
esac
}
# @FUNCTION: _git-r3_create_gitdir
# @USAGE: <repo-uri>
# @RETURN: 0 if successful or GIT_DIR exists already, 1 if ls-remote failed
# @INTERNAL
# @DESCRIPTION:
# Create GIT_DIR if necessary.
_git-r3_create_gitdir() {
local repo_uri=${1}
[[ -d ${GIT_DIR} ]] && return 0
if [[ ! -d ${EGIT3_STORE_DIR} ]]; then
(
addwrite /
mkdir -p "${EGIT3_STORE_DIR}"
) || die "Unable to create ${EGIT3_STORE_DIR}"
fi
# determine the remote object format
local head_ref
head_ref=(
$(git ls-remote "${repo_uri}" "HEAD")
)
[[ ${?} -ne 0 ]] && return 1
local object_format=$(_git-r3_get_object_format "${head_ref[0]}")
addwrite "${EGIT3_STORE_DIR}"
local saved_umask
if [[ ${EVCS_UMASK} ]]; then
saved_umask=$(umask)
umask "${EVCS_UMASK}" || die "Bad options to umask: ${EVCS_UMASK}"
fi
mkdir "${GIT_DIR}" || die
git init --object-format="${object_format}" --bare -b __init__ || die
if [[ ${saved_umask} ]]; then
umask "${saved_umask}" || die
fi
return 0
}
# @FUNCTION: _git-r3_set_gitdir
# @USAGE: <repo-uri>
# @INTERNAL
@@ -387,43 +428,6 @@ _git-r3_set_gitdir() {
: "${EGIT3_STORE_DIR:=${distdir}/git3-src}"
GIT_DIR=${EGIT3_STORE_DIR}/${repo_name}
EVCS_STORE_DIRS+=( "${GIT_DIR}" )
if [[ ! -d ${EGIT3_STORE_DIR} && ! ${EVCS_OFFLINE} ]]; then
(
addwrite /
mkdir -p "${EGIT3_STORE_DIR}"
) || die "Unable to create ${EGIT3_STORE_DIR}"
fi
addwrite "${EGIT3_STORE_DIR}"
if [[ ! -d ${GIT_DIR} ]]; then
if [[ ${EVCS_OFFLINE} ]]; then
eerror "A clone of the following repository is required to proceed:"
eerror " ${1}"
eerror "However, networking activity has been disabled using EVCS_OFFLINE and there"
eerror "is no local clone available."
die "No local clone of ${1}. Unable to proceed with EVCS_OFFLINE."
fi
local saved_umask
if [[ ${EVCS_UMASK} ]]; then
saved_umask=$(umask)
umask "${EVCS_UMASK}" || die "Bad options to umask: ${EVCS_UMASK}"
fi
mkdir "${GIT_DIR}" || die
# determine the remote object format
local head_ref=(
$(git ls-remote "${repo_uri}" "HEAD" || die)
)
local object_format=$(_git-r3_get_object_format "${head_ref[0]}")
git init --object-format="${object_format}" --bare -b __init__ || die
if [[ ${saved_umask} ]]; then
umask "${saved_umask}" || die
fi
fi
}
# @FUNCTION: _git-r3_set_submodules
@@ -619,6 +623,14 @@ git-r3_fetch() {
local -x GIT_DIR
_git-r3_set_gitdir "${repos[0]}"
if [[ ! -d ${GIT_DIR} && ${EVCS_OFFLINE} ]]; then
eerror "A clone of the following repository is required to proceed:"
eerror " ${repos[0]}"
eerror "However, network activity has been disabled using EVCS_OFFLINE and there"
eerror "is no local clone available."
die "No local clone of ${repos[0]}. Unable to proceed with EVCS_OFFLINE."
fi
EVCS_STORE_DIRS+=( "${GIT_DIR}" )
einfo "Repository id: ${GIT_DIR##*/}"
@@ -692,6 +704,7 @@ git-r3_fetch() {
for r in "${repos[@]}"; do
if [[ ! ${EVCS_OFFLINE} ]]; then
einfo "Fetching ${r} ..."
_git-r3_create_gitdir "${r}" || continue
local fetch_command=( git fetch "${r}" )
local clone_type=${EGIT_CLONE_TYPE}