/[gentoo-x86]/eclass/git-r3.eclass
Gentoo

Diff of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.6 Revision 1.39
1# Copyright 1999-2013 Gentoo Foundation 1# Copyright 1999-2014 Gentoo Foundation
2# Distributed under the terms of the GNU General Public License v2 2# Distributed under the terms of the GNU General Public License v2
3# $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.6 2013/09/19 09:37:14 mgorny Exp $ 3# $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.39 2014/03/03 21:45:06 mgorny Exp $
4 4
5# @ECLASS: git-r3.eclass 5# @ECLASS: git-r3.eclass
6# @MAINTAINER: 6# @MAINTAINER:
7# Michał Górny <mgorny@gentoo.org> 7# Michał Górny <mgorny@gentoo.org>
8# @BLURB: Eclass for fetching and unpacking git repositories. 8# @BLURB: Eclass for fetching and unpacking git repositories.
9# @DESCRIPTION: 9# @DESCRIPTION:
10# Third generation eclass for easing maitenance of live ebuilds using 10# Third generation eclass for easing maitenance of live ebuilds using
11# git as remote repository. The eclass supports lightweight (shallow) 11# git as remote repository.
12# clones and bare clones of submodules.
13 12
14case "${EAPI:-0}" in 13case "${EAPI:-0}" in
15 0|1|2|3|4|5) 14 0|1|2|3|4|5)
16 ;; 15 ;;
17 *) 16 *)
27 26
28EXPORT_FUNCTIONS src_unpack 27EXPORT_FUNCTIONS src_unpack
29 28
30if [[ ! ${_GIT_R3} ]]; then 29if [[ ! ${_GIT_R3} ]]; then
31 30
31if [[ ! ${_INHERITED_BY_GIT_2} ]]; then
32 DEPEND=">=dev-vcs/git-1.8.2.1"
33fi
34
35# @ECLASS-VARIABLE: EGIT_CLONE_TYPE
36# @DESCRIPTION:
37# Type of clone that should be used against the remote repository.
38# This can be either of: 'mirror', 'single', 'shallow'.
39#
40# This is intended to be set by user in make.conf. Ebuilds are supposed
41# to set EGIT_MIN_CLONE_TYPE if necessary instead.
42#
43# The 'mirror' type clones all remote branches and tags with complete
44# history and all notes. EGIT_COMMIT can specify any commit hash.
45# Upstream-removed branches and tags are purged from the local clone
46# while fetching. This mode is suitable for cloning the local copy
47# for development or hosting a local git mirror. However, clones
48# of repositories with large diverged branches may quickly grow large.
49#
50# The 'single' type clones only the requested branch or tag. Tags
51# referencing commits throughout the branch history are fetched as well,
52# and all notes. EGIT_COMMIT can safely specify only hashes
53# in the current branch. No purging of old references is done (if you
54# often switch branches, you may need to remove stale branches
55# yourself). This mode is suitable for general use.
56#
57# The 'shallow' type clones only the newest commit on requested branch
58# or tag. EGIT_COMMIT can only specify tags, and since the history is
59# unavailable calls like 'git describe' will not reference prior tags.
60# No purging of old references is done. This mode is intended mostly for
61# embedded systems with limited disk space.
62: ${EGIT_CLONE_TYPE:=single}
63
64# @ECLASS-VARIABLE: EGIT_MIN_CLONE_TYPE
65# @DESCRIPTION:
66# 'Minimum' clone type supported by the ebuild. Takes same values
67# as EGIT_CLONE_TYPE. When user sets a type that's 'lower' (that is,
68# later on the list) than EGIT_MIN_CLONE_TYPE, the eclass uses
69# EGIT_MIN_CLONE_TYPE instead.
70#
71# This variable is intended to be used by ebuilds only. Users are
72# supposed to set EGIT_CLONE_TYPE instead.
73#
74# A common case is to use 'single' whenever the build system requires
75# access to full branch history or the remote (Google Code) does not
76# support shallow clones. Please use sparingly, and to fix fatal errors
77# rather than 'non-pretty versions'.
78: ${EGIT_MIN_CLONE_TYPE:=shallow}
79
32# @ECLASS-VARIABLE: EGIT3_STORE_DIR 80# @ECLASS-VARIABLE: EGIT3_STORE_DIR
33# @DESCRIPTION: 81# @DESCRIPTION:
34# Storage directory for git sources. 82# Storage directory for git sources.
35# 83#
84# This is intended to be set by user in make.conf. Ebuilds must not set
85# it.
86#
36# EGIT3_STORE_DIR=${DISTDIR}/git3-src 87# EGIT3_STORE_DIR=${DISTDIR}/git3-src
88
89# @ECLASS-VARIABLE: EGIT_MIRROR_URI
90# @DEFAULT_UNSET
91# @DESCRIPTION:
92# 'Top' URI to a local git mirror. If specified, the eclass will try
93# to fetch from the local mirror instead of using the remote repository.
94#
95# The mirror needs to follow EGIT3_STORE_DIR structure. The directory
96# created by eclass can be used for that purpose.
97#
98# Example:
99# @CODE
100# EGIT_MIRROR_URI="git://mirror.lan/"
101# @CODE
37 102
38# @ECLASS-VARIABLE: EGIT_REPO_URI 103# @ECLASS-VARIABLE: EGIT_REPO_URI
39# @REQUIRED 104# @REQUIRED
40# @DESCRIPTION: 105# @DESCRIPTION:
41# URIs to the repository, e.g. git://foo, https://foo. If multiple URIs 106# URIs to the repository, e.g. git://foo, https://foo. If multiple URIs
42# are provided, the eclass will consider them as fallback URIs to try 107# are provided, the eclass will consider them as fallback URIs to try
43# if the first URI does not work. 108# if the first URI does not work.
44# 109#
45# It can be overriden via env using ${PN}_LIVE_REPO variable. 110# It can be overriden via env using ${PN}_LIVE_REPO variable.
111#
112# Can be a whitespace-separated list or an array.
46# 113#
47# Example: 114# Example:
48# @CODE 115# @CODE
49# EGIT_REPO_URI="git://a/b.git https://c/d.git" 116# EGIT_REPO_URI="git://a/b.git https://c/d.git"
50# @CODE 117# @CODE
75# @DESCRIPTION: 142# @DESCRIPTION:
76# The directory to check the git sources out to. 143# The directory to check the git sources out to.
77# 144#
78# EGIT_CHECKOUT_DIR=${WORKDIR}/${P} 145# EGIT_CHECKOUT_DIR=${WORKDIR}/${P}
79 146
80# @ECLASS-VARIABLE: EGIT_NONSHALLOW
81# @DEFAULT_UNSET
82# @DESCRIPTION:
83# Disable performing shallow fetches/clones. Shallow clones have
84# a fair number of limitations. Therefore, if you'd like the eclass to
85# perform complete clones instead, set this to a non-null value.
86#
87# This variable is to be set in make.conf. Ebuilds are not allowed
88# to set it.
89
90# @FUNCTION: _git-r3_env_setup 147# @FUNCTION: _git-r3_env_setup
91# @INTERNAL 148# @INTERNAL
92# @DESCRIPTION: 149# @DESCRIPTION:
93# Set the eclass variables as necessary for operation. This can involve 150# Set the eclass variables as necessary for operation. This can involve
94# setting EGIT_* to defaults or ${PN}_LIVE_* variables. 151# setting EGIT_* to defaults or ${PN}_LIVE_* variables.
95_git-r3_env_setup() { 152_git-r3_env_setup() {
96 debug-print-function ${FUNCNAME} "$@" 153 debug-print-function ${FUNCNAME} "$@"
154
155 # check the clone type
156 case "${EGIT_CLONE_TYPE}" in
157 mirror|single|shallow)
158 ;;
159 *)
160 die "Invalid EGIT_CLONE_TYPE=${EGIT_CLONE_TYPE}"
161 esac
162 case "${EGIT_MIN_CLONE_TYPE}" in
163 shallow)
164 ;;
165 single)
166 if [[ ${EGIT_CLONE_TYPE} == shallow ]]; then
167 einfo "git-r3: ebuild needs to be cloned in 'single' mode, adjusting"
168 EGIT_CLONE_TYPE=single
169 fi
170 ;;
171 mirror)
172 if [[ ${EGIT_CLONE_TYPE} != mirror ]]; then
173 einfo "git-r3: ebuild needs to be cloned in 'mirror' mode, adjusting"
174 EGIT_CLONE_TYPE=mirror
175 fi
176 ;;
177 *)
178 die "Invalid EGIT_MIN_CLONE_TYPE=${EGIT_MIN_CLONE_TYPE}"
179 esac
97 180
98 local esc_pn livevar 181 local esc_pn livevar
99 esc_pn=${PN//[-+]/_} 182 esc_pn=${PN//[-+]/_}
100 183
101 livevar=${esc_pn}_LIVE_REPO 184 livevar=${esc_pn}_LIVE_REPO
169_git-r3_set_gitdir() { 252_git-r3_set_gitdir() {
170 debug-print-function ${FUNCNAME} "$@" 253 debug-print-function ${FUNCNAME} "$@"
171 254
172 local repo_name=${1#*://*/} 255 local repo_name=${1#*://*/}
173 256
257 # strip the trailing slash
258 repo_name=${repo_name%/}
259
174 # strip common prefixes to make paths more likely to match 260 # strip common prefixes to make paths more likely to match
175 # e.g. git://X/Y.git vs https://X/git/Y.git 261 # e.g. git://X/Y.git vs https://X/git/Y.git
176 # (but just one of the prefixes) 262 # (but just one of the prefixes)
177 case "${repo_name}" in 263 case "${repo_name}" in
264 # gnome.org... who else?
265 browse/*) repo_name=${repo_name#browse/};;
178 # cgit can proxy requests to git 266 # cgit can proxy requests to git
179 cgit/*) repo_name=${repo_name#cgit/};; 267 cgit/*) repo_name=${repo_name#cgit/};;
180 # pretty common 268 # pretty common
181 git/*) repo_name=${repo_name#git/};; 269 git/*) repo_name=${repo_name#git/};;
182 # gentoo.org 270 # gentoo.org
197 GIT_DIR=${EGIT3_STORE_DIR}/${repo_name} 285 GIT_DIR=${EGIT3_STORE_DIR}/${repo_name}
198 286
199 if [[ ! -d ${EGIT3_STORE_DIR} ]]; then 287 if [[ ! -d ${EGIT3_STORE_DIR} ]]; then
200 ( 288 (
201 addwrite / 289 addwrite /
202 mkdir -m0755 -p "${EGIT3_STORE_DIR}" 290 mkdir -m0755 -p "${EGIT3_STORE_DIR}" || die
203 ) || die "Unable to create ${EGIT3_STORE_DIR}" 291 ) || die "Unable to create ${EGIT3_STORE_DIR}"
204 fi 292 fi
205 293
206 addwrite "${EGIT3_STORE_DIR}" 294 addwrite "${EGIT3_STORE_DIR}"
207 if [[ ! -d ${GIT_DIR} ]]; then 295 if [[ ! -d ${GIT_DIR} ]]; then
208 mkdir "${GIT_DIR}" || die 296 mkdir "${GIT_DIR}" || die
209 git init --bare || die 297 git init --bare || die
210
211 if [[ ! ${EGIT_NONSHALLOW} ]]; then
212 # avoid auto-unshallow :)
213 touch "${GIT_DIR}"/shallow || die
214 fi
215 fi 298 fi
216} 299}
217 300
218# @FUNCTION: _git-r3_set_submodules 301# @FUNCTION: _git-r3_set_submodules
219# @USAGE: <file-contents> 302# @USAGE: <file-contents>
237 [[ ${l} == submodule.*.url=* ]] || continue 320 [[ ${l} == submodule.*.url=* ]] || continue
238 321
239 l=${l#submodule.} 322 l=${l#submodule.}
240 local subname=${l%%.url=*} 323 local subname=${l%%.url=*}
241 324
325 # skip modules that have 'update = none', bug #487262.
326 local upd=$(echo "${data}" | git config -f /dev/fd/0 \
327 submodule."${subname}".update)
328 [[ ${upd} == none ]] && continue
329
242 submodules+=( 330 submodules+=(
243 "${subname}" 331 "${subname}"
244 "$(echo "${data}" | git config -f /dev/fd/0 \ 332 "$(echo "${data}" | git config -f /dev/fd/0 \
245 submodule."${subname}".url)" 333 submodule."${subname}".url || die)"
246 "$(echo "${data}" | git config -f /dev/fd/0 \ 334 "$(echo "${data}" | git config -f /dev/fd/0 \
247 submodule."${subname}".path)" 335 submodule."${subname}".path || die)"
248 ) 336 )
249 done < <(echo "${data}" | git config -f /dev/fd/0 -l) 337 done < <(echo "${data}" | git config -f /dev/fd/0 -l || die)
250} 338}
251 339
252# @FUNCTION: _git-r3_smart_fetch 340# @FUNCTION: _git-r3_is_local_repo
253# @USAGE: <git-fetch-args>... 341# @USAGE: <repo-uri>
342# @INTERNAL
254# @DESCRIPTION: 343# @DESCRIPTION:
255# Try fetching without '--depth' and switch to '--depth 1' if that 344# Determine whether the given URI specifies a local (on-disk)
256# will involve less objects fetched. 345# repository.
257_git-r3_smart_fetch() { 346_git-r3_is_local_repo() {
258 debug-print-function ${FUNCNAME} "$@" 347 debug-print-function ${FUNCNAME} "$@"
259 348
260 local sed_regexp='.*Counting objects: \([0-9]*\), done\..*' 349 local uri=${1}
261 350
262 # start the main fetch 351 [[ ${uri} == file://* || ${uri} == /* ]]
263 local cmd=( git fetch --progress "${@}" ) 352}
264 echo "${cmd[@]}" >&2
265 353
266 # we copy the output to the 'sed' pipe for parsing. whenever sed finds 354# @FUNCTION: _git-r3_find_head
267 # the process count, it quits quickly to avoid delays in writing it. 355# @USAGE: <head-ref>
268 # then, we start a dummy 'cat' to keep the pipe alive 356# @INTERNAL
357# @DESCRIPTION:
358# Given a ref to which remote HEAD was fetched, try to find
359# a branch matching the commit. Expects 'git show-ref'
360# or 'git ls-remote' output on stdin.
361_git-r3_find_head() {
362 debug-print-function ${FUNCNAME} "$@"
269 363
270 "${cmd[@]}" 2>&1 \ 364 local head_ref=${1}
271 | tee >( 365 local head_hash=$(git rev-parse --verify "${1}" || die)
272 sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}" \ 366 local matching_ref
273 > "${T}"/git-r3_main.count
274 exec cat >/dev/null
275 ) &
276 local main_pid=${!}
277 367
278 # start the helper process 368 # TODO: some transports support peeking at symbolic remote refs
279 _git-r3_sub_fetch() { 369 # find a way to use that rather than guessing
280 # wait for main fetch to get object count; if the server doesn't 370
281 # output it, we won't even launch the parallel process 371 # (based on guess_remote_head() in git-1.9.0/remote.c)
282 while [[ ! -s ${T}/git-r3_main.count ]]; do 372 local h ref
283 sleep 0.25 373 while read h ref; do
374 # look for matching head
375 if [[ ${h} == ${head_hash} ]]; then
376 # either take the first matching ref, or master if it is there
377 if [[ ! ${matching_ref} || ${ref} == refs/heads/master ]]; then
378 matching_ref=${ref}
379 fi
380 fi
284 done 381 done
285 382
286 # ok, let's see if parallel fetch gives us smaller count 383 if [[ ! ${matching_ref} ]]; then
287 # --dry-run will prevent it from writing to the local clone 384 die "Unable to find a matching branch for remote HEAD (${head_hash})"
288 # and sed should terminate git with SIGPIPE
289 local sub_count=$(git fetch --progress --dry-run --depth 1 "${@}" 2>&1 \
290 | sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}")
291 local main_count=$(<"${T}"/git-r3_main.count)
292
293 # let's be real sure that '--depth 1' will be good for us.
294 # note that we have purely objects counts, and '--depth 1'
295 # may involve much bigger objects
296 if [[ ${main_count} && ${main_count} -ge $(( sub_count * 3/2 )) ]]
297 then
298 # signal that we want shallow fetch instead,
299 # and terminate the non-shallow fetch process
300 touch "${T}"/git-r3_want_shallow || die
301 kill ${main_pid} &>/dev/null
302 exit 0
303 fi 385 fi
304 386
305 exit 1 387 echo "${matching_ref}"
306 }
307 _git-r3_sub_fetch "${@}" &
308 local sub_pid=${!}
309
310 # wait for main process to terminate, either of its own
311 # or by signal from subprocess
312 wait ${main_pid}
313 local main_ret=${?}
314
315 # wait for subprocess to terminate, killing it if necessary.
316 # if main fetch finished before it, there's no point in keeping
317 # it alive. if main fetch was killed by it, it's done anyway
318 kill ${sub_pid} &>/dev/null
319 wait ${sub_pid}
320
321 # now see if subprocess wanted to tell us something...
322 if [[ -f ${T}/git-r3_want_shallow ]]; then
323 rm "${T}"/git-r3_want_shallow || die
324
325 # if fetch finished already (wasn't killed), ignore it
326 [[ ${main_ret} -eq 0 ]] && return 0
327
328 # otherwise, restart as shallow fetch
329 einfo "Restarting fetch using --depth 1 to save bandwidth ..."
330 local cmd=( git fetch --progress --depth 1 "${@}" )
331 echo "${cmd[@]}" >&2
332 "${cmd[@]}"
333 main_ret=${?}
334 fi
335
336 return ${main_ret}
337} 388}
338 389
339# @FUNCTION: git-r3_fetch 390# @FUNCTION: git-r3_fetch
340# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]] 391# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]]
341# @DESCRIPTION: 392# @DESCRIPTION:
354# is set to a non-null value. 405# is set to a non-null value.
355# 406#
356# <local-id> specifies the local branch identifier that will be used to 407# <local-id> specifies the local branch identifier that will be used to
357# locally store the fetch result. It should be unique to multiple 408# locally store the fetch result. It should be unique to multiple
358# fetches within the repository that can be performed at the same time 409# fetches within the repository that can be performed at the same time
359# (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT}. 410# (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT%/*}.
360# This default should be fine unless you are fetching multiple trees 411# This default should be fine unless you are fetching multiple trees
361# from the same repository in the same ebuild. 412# from the same repository in the same ebuild.
362# 413#
363# The fetch operation will affect the EGIT_STORE only. It will not touch 414# The fetch operation will affect the EGIT_STORE only. It will not touch
364# the working copy, nor export any environment variables. 415# the working copy, nor export any environment variables.
365# If the repository contains submodules, they will be fetched 416# If the repository contains submodules, they will be fetched
366# recursively. 417# recursively.
367git-r3_fetch() { 418git-r3_fetch() {
368 debug-print-function ${FUNCNAME} "$@" 419 debug-print-function ${FUNCNAME} "$@"
369 420
421 [[ ${EVCS_OFFLINE} ]] && return
422
423 local repos
424 if [[ ${1} ]]; then
425 repos=( ${1} )
426 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
427 repos=( "${EGIT_REPO_URI[@]}" )
428 else
370 local repos=( ${1:-${EGIT_REPO_URI}} ) 429 repos=( ${EGIT_REPO_URI} )
430 fi
431
371 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} 432 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
372 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} 433 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
373 local local_id=${3:-${CATEGORY}/${PN}/${SLOT}} 434 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
374 local local_ref=refs/heads/${local_id}/__main__ 435 local local_ref=refs/git-r3/${local_id}/__main__
375 436
376 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" 437 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
377 438
378 local -x GIT_DIR 439 local -x GIT_DIR
379 _git-r3_set_gitdir ${repos[0]} 440 _git-r3_set_gitdir "${repos[0]}"
441
442 # prepend the local mirror if applicable
443 if [[ ${EGIT_MIRROR_URI} ]]; then
444 repos=(
445 "${EGIT_MIRROR_URI%/}/${GIT_DIR##*/}"
446 "${repos[@]}"
447 )
448 fi
380 449
381 # try to fetch from the remote 450 # try to fetch from the remote
382 local r success 451 local r success
383 for r in ${repos[@]}; do 452 for r in "${repos[@]}"; do
453 einfo "Fetching ${r} ..."
454
455 local fetch_command=( git fetch "${r}" )
456
457 if [[ ${EGIT_CLONE_TYPE} == mirror ]]; then
458 fetch_command+=(
459 --prune
460 # mirror the remote branches as local branches
461 "+refs/heads/*:refs/heads/*"
462 # pull tags explicitly in order to prune them properly
463 "+refs/tags/*:refs/tags/*"
464 # notes in case something needs them
465 "+refs/notes/*:refs/notes/*"
466 # and HEAD in case we need the default branch
467 # (we keep it in refs/git-r3 since otherwise --prune interferes)
468 "+HEAD:refs/git-r3/HEAD"
469 )
470 else # single or shallow
471 local fetch_l fetch_r
472
473 if [[ ${remote_ref} == HEAD ]]; then
474 # HEAD
475 fetch_l=HEAD
476 elif [[ ${remote_ref} == refs/heads/* ]]; then
477 # regular branch
478 fetch_l=${remote_ref}
479 else
480 # tag or commit...
481 # let ls-remote figure it out
482 local tagref=$(git ls-remote "${r}" "refs/tags/${remote_ref}")
483
484 # if it was a tag, ls-remote obtained a hash
485 if [[ ${tagref} ]]; then
486 # tag
487 fetch_l=refs/tags/${remote_ref}
488 else
489 # commit
490 # so we need to fetch the branch
491 if [[ ${branch} ]]; then
492 fetch_l=${branch}
493 else
494 fetch_l=HEAD
495 fi
496
497 # fetching by commit in shallow mode? can't do.
498 if [[ ${EGIT_CLONE_TYPE} == shallow ]]; then
499 local EGIT_CLONE_TYPE=single
500 fi
501 fi
502 fi
503
504 if [[ ${fetch_l} == HEAD ]]; then
505 fetch_r=refs/git-r3/HEAD
506 else
507 fetch_r=${fetch_l}
508 fi
509
510 fetch_command+=(
511 "+${fetch_l}:${fetch_r}"
512 )
513 fi
514
515 if [[ ${EGIT_CLONE_TYPE} == shallow ]]; then
516 if _git-r3_is_local_repo; then
517 # '--depth 1' causes sandbox violations with local repos
518 # bug #491260
519 local EGIT_CLONE_TYPE=single
520 elif [[ ! $(git rev-parse --quiet --verify "${fetch_r}") ]]
521 then
522 # use '--depth 1' when fetching a new branch
523 fetch_command+=( --depth 1 )
524 fi
525 else # non-shallow mode
526 if [[ -f ${GIT_DIR}/shallow ]]; then
527 fetch_command+=( --unshallow )
528 fi
529 fi
530
531 set -- "${fetch_command[@]}"
532 echo "${@}" >&2
533 if "${@}"; then
534 if [[ ${EGIT_CLONE_TYPE} == mirror ]]; then
535 # find remote HEAD and update our HEAD properly
536 git symbolic-ref HEAD \
537 "$(_git-r3_find_head refs/git-r3/HEAD \
538 < <(git show-ref --heads || die))" \
539 || die "Unable to update HEAD"
540 else # single or shallow
541 if [[ ${fetch_l} == HEAD ]]; then
542 # find out what branch we fetched as HEAD
543 local head_branch=$(_git-r3_find_head \
544 refs/git-r3/HEAD \
545 < <(git ls-remote --heads "${r}" || die))
546
547 # and move it to its regular place
548 git update-ref --no-deref "${head_branch}" \
549 refs/git-r3/HEAD \
550 || die "Unable to sync HEAD branch ${head_branch}"
551 git symbolic-ref HEAD "${head_branch}" \
552 || die "Unable to update HEAD"
553 fi
554 fi
555
556 # now let's see what the user wants from us
557 local full_remote_ref=$(
558 git rev-parse --verify --symbolic-full-name "${remote_ref}"
559 )
560
561 if [[ ${full_remote_ref} ]]; then
562 # when we are given a ref, create a symbolic ref
563 # so that we preserve the actual argument
564 set -- git symbolic-ref "${local_ref}" "${full_remote_ref}"
565 else
566 # otherwise, we were likely given a commit id
567 set -- git update-ref --no-deref "${local_ref}" "${remote_ref}"
568 fi
569
570 echo "${@}" >&2
571 if ! "${@}"; then
572 die "Referencing ${remote_ref} failed (wrong ref?)."
573 fi
574
575 success=1
576 break
577 fi
578 done
579 [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
580
581 # submodules can reference commits in any branch
582 # always use the 'clone' mode to accomodate that, bug #503332
583 local EGIT_CLONE_TYPE=mirror
584
585 # recursively fetch submodules
586 if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
587 local submodules
588 _git-r3_set_submodules \
589 "$(git cat-file -p "${local_ref}":.gitmodules || die)"
590
591 while [[ ${submodules[@]} ]]; do
592 local subname=${submodules[0]}
593 local url=${submodules[1]}
594 local path=${submodules[2]}
595 local commit=$(git rev-parse "${local_ref}:${path}")
596
597 if [[ ! ${commit} ]]; then
598 die "Unable to get commit id for submodule ${subname}"
599 fi
600 if [[ ${url} == ./* || ${url} == ../* ]]; then
601 local subrepos=( "${repos[@]/%//${url}}" )
602 else
603 local subrepos=( "${url}" )
604 fi
605
606 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}"
607
608 submodules=( "${submodules[@]:3}" ) # shift
609 done
610 fi
611}
612
613# @FUNCTION: git-r3_checkout
614# @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
615# @DESCRIPTION:
616# Check the previously fetched tree to the working copy.
617#
618# <repo-uri> specifies the repository URIs, as a space-separated list.
619# The first URI will be used as repository group identifier
620# and therefore must be used consistently with git-r3_fetch.
621# The remaining URIs are not used and therefore may be omitted.
622# When not specified, defaults to ${EGIT_REPO_URI}.
623#
624# <checkout-path> specifies the path to place the checkout. It defaults
625# to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
626#
627# <local-id> needs to specify the local identifier that was used
628# for respective git-r3_fetch.
629#
630# The checkout operation will write to the working copy, and export
631# the repository state into the environment. If the repository contains
632# submodules, they will be checked out recursively.
633git-r3_checkout() {
634 debug-print-function ${FUNCNAME} "$@"
635
636 local repos
637 if [[ ${1} ]]; then
638 repos=( ${1} )
639 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
640 repos=( "${EGIT_REPO_URI[@]}" )
641 else
642 repos=( ${EGIT_REPO_URI} )
643 fi
644
645 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
646 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
647
648 local -x GIT_DIR
649 _git-r3_set_gitdir "${repos[0]}"
650
651 einfo "Checking out ${repos[0]} to ${out_dir} ..."
652
653 if ! git cat-file -e refs/git-r3/"${local_id}"/__main__; then
654 if [[ ${EVCS_OFFLINE} ]]; then
655 die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE."
656 else
657 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
658 fi
659 fi
660 local remote_ref=$(
661 git symbolic-ref --quiet refs/git-r3/"${local_id}"/__main__
662 )
663 local new_commit_id=$(
664 git rev-parse --verify refs/git-r3/"${local_id}"/__main__
665 )
666
667 git-r3_sub_checkout() {
668 local orig_repo=${GIT_DIR}
669 local -x GIT_DIR=${out_dir}/.git
670 local -x GIT_WORK_TREE=${out_dir}
671
672 mkdir -p "${out_dir}" || die
673
674 # use git init+fetch instead of clone since the latter doesn't like
675 # non-empty directories.
676
677 git init --quiet || die
678 # setup 'alternates' to avoid copying objects
679 echo "${orig_repo}/objects" > "${GIT_DIR}"/objects/info/alternates || die
680 # now copy the refs
681 # [htn]* safely catches heads, tags, notes without complaining
682 # on non-existing ones, and omits internal 'git-r3' ref
683 cp -R "${orig_repo}"/refs/[htn]* "${GIT_DIR}"/refs/ || die
684
685 # (no need to copy HEAD, we will set it via checkout)
686
687 if [[ -f ${orig_repo}/shallow ]]; then
688 cp "${orig_repo}"/shallow "${GIT_DIR}"/ || die
689 fi
690
691 set -- git checkout --quiet
692 if [[ ${remote_ref} ]]; then
693 set -- "${@}" "${remote_ref#refs/heads/}"
694 else
695 set -- "${@}" "${new_commit_id}"
696 fi
697 echo "${@}" >&2
698 "${@}" || die "git checkout ${remote_ref:-${new_commit_id}} failed"
699 }
700 git-r3_sub_checkout
701
702 local old_commit_id=$(
703 git rev-parse --quiet --verify refs/git-r3/"${local_id}"/__old__
704 )
705 if [[ ! ${old_commit_id} ]]; then
706 echo "GIT NEW branch -->"
707 echo " repository: ${repos[0]}"
708 echo " at the commit: ${new_commit_id}"
709 else
710 # diff against previous revision
711 echo "GIT update -->"
712 echo " repository: ${repos[0]}"
713 # write out message based on the revisions
714 if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
715 echo " updating from commit: ${old_commit_id}"
716 echo " to commit: ${new_commit_id}"
717
718 git --no-pager diff --stat \
719 ${old_commit_id}..${new_commit_id}
720 else
721 echo " at the commit: ${new_commit_id}"
722 fi
723 fi
724 git update-ref --no-deref refs/git-r3/"${local_id}"/{__old__,__main__} || die
725
726 # recursively checkout submodules
727 if [[ -f ${out_dir}/.gitmodules ]]; then
728 local submodules
729 _git-r3_set_submodules \
730 "$(<"${out_dir}"/.gitmodules)"
731
732 while [[ ${submodules[@]} ]]; do
733 local subname=${submodules[0]}
734 local url=${submodules[1]}
735 local path=${submodules[2]}
736
737 if [[ ${url} == ./* || ${url} == ../* ]]; then
738 url=${repos[0]%%/}/${url}
739 fi
740
741 git-r3_checkout "${url}" "${out_dir}/${path}" \
742 "${local_id}/${subname}"
743
744 submodules=( "${submodules[@]:3}" ) # shift
745 done
746 fi
747
748 # keep this *after* submodules
749 export EGIT_DIR=${GIT_DIR}
750 export EGIT_VERSION=${new_commit_id}
751}
752
753# @FUNCTION: git-r3_peek_remote_ref
754# @USAGE: [<repo-uri> [<remote-ref>]]
755# @DESCRIPTION:
756# Peek the reference in the remote repository and print the matching
757# (newest) commit SHA1.
758#
759# <repo-uri> specifies the repository URIs to fetch from, as a space-
760# -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
761#
762# <remote-ref> specifies the remote ref to peek. It is preferred to use
763# 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
764# for tags. Alternatively, 'HEAD' may be used for upstream default
765# branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
766# 'HEAD' that is set to a non-null value.
767#
768# The operation will be done purely on the remote, without using local
769# storage. If commit SHA1 is provided as <remote-ref>, the function will
770# fail due to limitations of git protocol.
771#
772# On success, the function returns 0 and writes hexadecimal commit SHA1
773# to stdout. On failure, the function returns 1.
774git-r3_peek_remote_ref() {
775 debug-print-function ${FUNCNAME} "$@"
776
777 local repos
778 if [[ ${1} ]]; then
779 repos=( ${1} )
780 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
781 repos=( "${EGIT_REPO_URI[@]}" )
782 else
783 repos=( ${EGIT_REPO_URI} )
784 fi
785
786 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
787 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
788
789 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
790
791 local r success
792 for r in "${repos[@]}"; do
384 einfo "Fetching ${remote_ref} from ${r} ..." 793 einfo "Peeking ${remote_ref} on ${r} ..." >&2
385 794
386 local is_branch lookup_ref 795 local is_branch lookup_ref
387 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] 796 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
388 then 797 then
389 is_branch=1 798 is_branch=1
392 # ls-remote by commit is going to fail anyway, 801 # ls-remote by commit is going to fail anyway,
393 # so we may as well pass refs/tags/ABCDEF... 802 # so we may as well pass refs/tags/ABCDEF...
394 lookup_ref=refs/tags/${remote_ref} 803 lookup_ref=refs/tags/${remote_ref}
395 fi 804 fi
396 805
397 # first, try ls-remote to see if ${remote_ref} is a real ref
398 # and not a commit id. if it succeeds, we can pass ${remote_ref}
399 # to 'fetch'. otherwise, we will just fetch everything
400
401 # split on whitespace
402 local ref=(
403 $(git ls-remote "${r}" "${lookup_ref}" || echo __FAIL__)
404 )
405
406 # normally, ref[0] is a hash, so we can do magic strings here
407 [[ ${ref[0]} == __FAIL__ ]] && continue
408
409 local nonshallow=${EGIT_NONSHALLOW}
410 local ref_param=()
411 if [[ ! ${ref[0]} ]]; then
412 nonshallow=1
413 fi
414
415 # 1. if we need a non-shallow clone and we have a shallow one,
416 # we need to unshallow it explicitly.
417 # 2. if we want a shallow clone, we just pass '--depth 1'
418 # to the first fetch in the repo. passing '--depth'
419 # to further requests usually results in more data being
420 # downloaded than without it.
421 # 3. if we update a shallow clone, we try without '--depth'
422 # first since that usually transfers less data. however,
423 # we use git-r3_smart_fetch that can switch into '--depth 1'
424 # if that looks beneficial.
425
426 local fetch_command=( git fetch )
427 if [[ ${nonshallow} ]]; then
428 if [[ -f ${GIT_DIR}/shallow ]]; then
429 ref_param+=( --unshallow )
430 fi
431 else
432 # 'git show-ref --heads' returns 1 when there are no branches
433 if ! git show-ref --heads -q; then
434 ref_param+=( --depth 1 )
435 else
436 fetch_command=( _git-r3_smart_fetch )
437 fi
438 fi
439
440 # now, another important thing. we may only fetch a remote
441 # branch directly to a local branch. Otherwise, we need to fetch
442 # the commit and re-create the branch on top of it.
443
444 if [[ ${ref[0]} ]]; then
445 if [[ ${is_branch} ]]; then
446 ref_param+=( -f "${remote_ref}:${local_id}/__main__" )
447 else
448 ref_param+=( "refs/tags/${remote_ref}" )
449 fi
450 fi
451
452 # if ${remote_ref} is branch or tag, ${ref[@]} will contain
453 # the respective commit id. otherwise, it will be an empty
454 # array, so the following won't evaluate to a parameter.
455 set -- "${fetch_command[@]}" --no-tags "${r}" "${ref_param[@]}"
456 echo "${@}" >&2
457 if "${@}"; then
458 if [[ ! ${is_branch} ]]; then
459 set -- git branch -f "${local_id}/__main__" \
460 "${ref[0]:-${remote_ref}}"
461 echo "${@}" >&2
462 if ! "${@}"; then
463 die "Creating branch for ${remote_ref} failed (wrong ref?)."
464 fi
465 fi
466
467 success=1
468 break
469 fi
470 done
471 [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
472
473 # recursively fetch submodules
474 if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
475 local submodules
476 _git-r3_set_submodules \
477 "$(git cat-file -p "${local_ref}":.gitmodules || die)"
478
479 while [[ ${submodules[@]} ]]; do
480 local subname=${submodules[0]}
481 local url=${submodules[1]}
482 local path=${submodules[2]}
483 local commit=$(git rev-parse "${local_ref}:${path}")
484
485 if [[ ! ${commit} ]]; then
486 die "Unable to get commit id for submodule ${subname}"
487 fi
488
489 git-r3_fetch "${url}" "${commit}" "${local_id}/${subname}"
490
491 submodules=( "${submodules[@]:3}" ) # shift
492 done
493 fi
494}
495
496# @FUNCTION: git-r3_checkout
497# @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
498# @DESCRIPTION:
499# Check the previously fetched tree to the working copy.
500#
501# <repo-uri> specifies the repository URIs, as a space-separated list.
502# The first URI will be used as repository group identifier
503# and therefore must be used consistently with git-r3_fetch.
504# The remaining URIs are not used and therefore may be omitted.
505# When not specified, defaults to ${EGIT_REPO_URI}.
506#
507# <checkout-path> specifies the path to place the checkout. It defaults
508# to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
509#
510# <local-id> needs to specify the local identifier that was used
511# for respective git-r3_fetch.
512#
513# The checkout operation will write to the working copy, and export
514# the repository state into the environment. If the repository contains
515# submodules, they will be checked out recursively.
516git-r3_checkout() {
517 debug-print-function ${FUNCNAME} "$@"
518
519 local repos=( ${1:-${EGIT_REPO_URI}} )
520 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
521 local local_id=${3:-${CATEGORY}/${PN}/${SLOT}}
522
523 local -x GIT_DIR GIT_WORK_TREE
524 _git-r3_set_gitdir ${repos[0]}
525 GIT_WORK_TREE=${out_dir}
526 mkdir -p "${GIT_WORK_TREE}"
527
528 einfo "Checking out ${repos[0]} to ${out_dir} ..."
529
530 if ! git cat-file -e refs/heads/"${local_id}"/__main__
531 then
532 if [[ ${EVCS_OFFLINE} ]]; then
533 die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE."
534 else
535 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
536 fi
537 fi
538
539 set -- git checkout -f "${local_id}"/__main__ .
540 echo "${@}" >&2
541 "${@}" || die "git checkout ${local_id}/__main__ failed"
542
543 # diff against previous revision (if any)
544 local new_commit_id=$(git rev-parse --verify "${local_id}"/__main__)
545 local old_commit_id=$(
546 git rev-parse --verify "${local_id}"/__old__ 2>/dev/null
547 )
548
549 if [[ ! ${old_commit_id} ]]; then
550 echo "GIT NEW branch -->"
551 echo " repository: ${repos[0]}"
552 echo " at the commit: ${new_commit_id}"
553 else
554 echo "GIT update -->"
555 echo " repository: ${repos[0]}"
556 # write out message based on the revisions
557 if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
558 echo " updating from commit: ${old_commit_id}"
559 echo " to commit: ${new_commit_id}"
560
561 git --no-pager diff --stat \
562 ${old_commit_id}..${new_commit_id}
563 else
564 echo " at the commit: ${new_commit_id}"
565 fi
566 fi
567 git branch -f "${local_id}"/{__old__,__main__} || die
568
569 # recursively checkout submodules
570 if [[ -f ${GIT_WORK_TREE}/.gitmodules ]]; then
571 local submodules
572 _git-r3_set_submodules \
573 "$(<"${GIT_WORK_TREE}"/.gitmodules)"
574
575 while [[ ${submodules[@]} ]]; do
576 local subname=${submodules[0]}
577 local url=${submodules[1]}
578 local path=${submodules[2]}
579
580 git-r3_checkout "${url}" "${GIT_WORK_TREE}/${path}" \
581 "${local_id}/${subname}"
582
583 submodules=( "${submodules[@]:3}" ) # shift
584 done
585 fi
586
587 # keep this *after* submodules
588 export EGIT_DIR=${GIT_DIR}
589 export EGIT_VERSION=${new_commit_id}
590}
591
592# @FUNCTION: git-r3_peek_remote_ref
593# @USAGE: [<repo-uri> [<remote-ref>]]
594# @DESCRIPTION:
595# Peek the reference in the remote repository and print the matching
596# (newest) commit SHA1.
597#
598# <repo-uri> specifies the repository URIs to fetch from, as a space-
599# -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
600#
601# <remote-ref> specifies the remote ref to peek. It is preferred to use
602# 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
603# for tags. Alternatively, 'HEAD' may be used for upstream default
604# branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
605# 'HEAD' that is set to a non-null value.
606#
607# The operation will be done purely on the remote, without using local
608# storage. If commit SHA1 is provided as <remote-ref>, the function will
609# fail due to limitations of git protocol.
610#
611# On success, the function returns 0 and writes hexadecimal commit SHA1
612# to stdout. On failure, the function returns 1.
613git-r3_peek_remote_ref() {
614 debug-print-function ${FUNCNAME} "$@"
615
616 local repos=( ${1:-${EGIT_REPO_URI}} )
617 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
618 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
619
620 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
621
622 local r success
623 for r in ${repos[@]}; do
624 einfo "Peeking ${remote_ref} on ${r} ..." >&2
625
626 local is_branch lookup_ref
627 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
628 then
629 is_branch=1
630 lookup_ref=${remote_ref}
631 else
632 # ls-remote by commit is going to fail anyway,
633 # so we may as well pass refs/tags/ABCDEF...
634 lookup_ref=refs/tags/${remote_ref}
635 fi
636
637 # split on whitespace 806 # split on whitespace
638 local ref=( 807 local ref=(
639 $(git ls-remote "${r}" "${lookup_ref}") 808 $(git ls-remote "${r}" "${lookup_ref}")
640 ) 809 )
641 810
648 return 1 817 return 1
649} 818}
650 819
651git-r3_src_fetch() { 820git-r3_src_fetch() {
652 debug-print-function ${FUNCNAME} "$@" 821 debug-print-function ${FUNCNAME} "$@"
653
654 [[ ${EVCS_OFFLINE} ]] && return
655 822
656 if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then 823 if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then
657 ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider" 824 ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider"
658 ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use" 825 ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use"
659 ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones" 826 ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones"

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.39

  ViewVC Help
Powered by ViewVC 1.1.20