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

Legend:
Removed from v.1.14  
changed lines
  Added in v.1.35

  ViewVC Help
Powered by ViewVC 1.1.20