/[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.23 Revision 1.24
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.23 2013/11/15 23:03:23 mgorny Exp $ 3# $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.24 2014/02/23 22:05:55 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 *)
28EXPORT_FUNCTIONS src_unpack 27EXPORT_FUNCTIONS src_unpack
29 28
30if [[ ! ${_GIT_R3} ]]; then 29if [[ ! ${_GIT_R3} ]]; then
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"
34fi 33fi
35 34
36# @ECLASS-VARIABLE: EGIT3_STORE_DIR 35# @ECLASS-VARIABLE: EGIT3_STORE_DIR
37# @DESCRIPTION: 36# @DESCRIPTION:
38# Storage directory for git sources. 37# Storage directory for git sources.
80# @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR 79# @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR
81# @DESCRIPTION: 80# @DESCRIPTION:
82# The directory to check the git sources out to. 81# The directory to check the git sources out to.
83# 82#
84# EGIT_CHECKOUT_DIR=${WORKDIR}/${P} 83# EGIT_CHECKOUT_DIR=${WORKDIR}/${P}
85
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 84
98# @FUNCTION: _git-r3_env_setup 85# @FUNCTION: _git-r3_env_setup
99# @INTERNAL 86# @INTERNAL
100# @DESCRIPTION: 87# @DESCRIPTION:
101# Set the eclass variables as necessary for operation. This can involve 88# Set the eclass variables as necessary for operation. This can involve
215 mkdir -m0755 -p "${EGIT3_STORE_DIR}" || die 202 mkdir -m0755 -p "${EGIT3_STORE_DIR}" || die
216 ) || die "Unable to create ${EGIT3_STORE_DIR}" 203 ) || die "Unable to create ${EGIT3_STORE_DIR}"
217 fi 204 fi
218 205
219 addwrite "${EGIT3_STORE_DIR}" 206 addwrite "${EGIT3_STORE_DIR}"
207 if [[ -e ${GIT_DIR}/shallow ]]; then
208 einfo "${GIT_DIR} was a shallow clone, recreating..."
209 rm -r "${GIT_DIR}" || die
210 fi
220 if [[ ! -d ${GIT_DIR} ]]; then 211 if [[ ! -d ${GIT_DIR} ]]; then
221 mkdir "${GIT_DIR}" || die 212 mkdir "${GIT_DIR}" || die
222 git init --bare || die 213 git init --bare || die
223
224 if [[ ! ${EGIT_NONSHALLOW} ]]; then
225 # avoid auto-unshallow :)
226 touch "${GIT_DIR}"/shallow || die
227 fi
228 fi 214 fi
229} 215}
230 216
231# @FUNCTION: _git-r3_set_submodules 217# @FUNCTION: _git-r3_set_submodules
232# @USAGE: <file-contents> 218# @USAGE: <file-contents>
265 submodule."${subname}".path || die)" 251 submodule."${subname}".path || die)"
266 ) 252 )
267 done < <(echo "${data}" | git config -f /dev/fd/0 -l || die) 253 done < <(echo "${data}" | git config -f /dev/fd/0 -l || die)
268} 254}
269 255
270# @FUNCTION: _git-r3_smart_fetch
271# @USAGE: <git-fetch-args>...
272# @DESCRIPTION:
273# Try fetching without '--depth' and switch to '--depth 1' if that
274# will involve less objects fetched.
275_git-r3_smart_fetch() {
276 debug-print-function ${FUNCNAME} "$@"
277
278 local sed_regexp='.*Counting objects: \([0-9]*\), done\..*'
279
280 # start the main fetch
281 local cmd=( git fetch --progress "${@}" )
282 echo "${cmd[@]}" >&2
283
284 # we copy the output to the 'sed' pipe for parsing. whenever sed finds
285 # the process count, it quits quickly to avoid delays in writing it.
286 # then, we start a dummy 'cat' to keep the pipe alive
287
288 "${cmd[@]}" 2>&1 \
289 | tee >(
290 sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}" \
291 > "${T}"/git-r3_main.count
292 exec cat >/dev/null
293 ) &
294 local main_pid=${!}
295
296 # start the helper process
297 _git-r3_sub_fetch() {
298 # wait for main fetch to get object count; if the server doesn't
299 # output it, we won't even launch the parallel process
300 while [[ ! -s ${T}/git-r3_main.count ]]; do
301 sleep 0.25
302 done
303
304 # ok, let's see if parallel fetch gives us smaller count
305 # --dry-run will prevent it from writing to the local clone
306 # and sed should terminate git with SIGPIPE
307 local sub_count=$(git fetch --progress --dry-run --depth 1 "${@}" 2>&1 \
308 | sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}")
309 local main_count=$(<"${T}"/git-r3_main.count)
310
311 # let's be real sure that '--depth 1' will be good for us.
312 # note that we have purely objects counts, and '--depth 1'
313 # may involve much bigger objects
314 if [[ ${main_count} && ${main_count} -ge $(( sub_count * 3/2 )) ]]
315 then
316 # signal that we want shallow fetch instead,
317 # and terminate the non-shallow fetch process
318 touch "${T}"/git-r3_want_shallow || die
319 kill ${main_pid} &>/dev/null
320 exit 0
321 fi
322
323 exit 1
324 }
325 _git-r3_sub_fetch "${@}" &
326 local sub_pid=${!}
327
328 # wait for main process to terminate, either of its own
329 # or by signal from subprocess
330 wait ${main_pid}
331 local main_ret=${?}
332
333 # wait for subprocess to terminate, killing it if necessary.
334 # if main fetch finished before it, there's no point in keeping
335 # it alive. if main fetch was killed by it, it's done anyway
336 kill ${sub_pid} &>/dev/null
337 wait ${sub_pid}
338
339 # now see if subprocess wanted to tell us something...
340 if [[ -f ${T}/git-r3_want_shallow ]]; then
341 rm "${T}"/git-r3_want_shallow || die
342
343 # if fetch finished already (wasn't killed), ignore it
344 [[ ${main_ret} -eq 0 ]] && return 0
345
346 # otherwise, restart as shallow fetch
347 einfo "Restarting fetch using --depth 1 to save bandwidth ..."
348 local cmd=( git fetch --progress --depth 1 "${@}" )
349 echo "${cmd[@]}" >&2
350 "${cmd[@]}"
351 main_ret=${?}
352 fi
353
354 return ${main_ret}
355}
356
357# @FUNCTION: _git-r3_is_local_repo 256# @FUNCTION: _git-r3_is_local_repo
358# @USAGE: <repo-uri> 257# @USAGE: <repo-uri>
359# @INTERNAL 258# @INTERNAL
360# @DESCRIPTION: 259# @DESCRIPTION:
361# Determine whether the given URI specifies a local (on-disk) 260# Determine whether the given URI specifies a local (on-disk)
411 fi 310 fi
412 311
413 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} 312 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
414 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} 313 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
415 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}} 314 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
416 local local_ref=refs/heads/${local_id}/__main__ 315 local local_ref=refs/git-r3/${local_id}/__main__
417 316
418 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" 317 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
419 318
420 local -x GIT_DIR 319 local -x GIT_DIR
421 _git-r3_set_gitdir "${repos[0]}" 320 _git-r3_set_gitdir "${repos[0]}"
422 321
423 # try to fetch from the remote 322 # try to fetch from the remote
424 local r success 323 local r success
425 for r in "${repos[@]}"; do 324 for r in "${repos[@]}"; do
325 einfo "Fetching ${r} ..."
326
327 local fetch_command=(
328 git fetch --prune "${r}"
329 # mirror the remote branches as local branches
330 "refs/heads/*:refs/heads/*"
331 # pull tags explicitly in order to prune them properly
332 "refs/tags/*:refs/tags/*"
333 )
334
335 set -- "${fetch_command[@]}"
336 echo "${@}" >&2
337 if "${@}"; then
338 # now let's see what the user wants from us
339 local full_remote_ref=$(
340 git rev-parse --verify --symbolic-full-name "${remote_ref}"
341 )
342
343 if [[ ${full_remote_ref} ]]; then
344 # when we are given a ref, create a symbolic ref
345 # so that we preserve the actual argument
346 set -- git symbolic-ref "${local_ref}" "${full_remote_ref}"
347 else
348 # otherwise, we were likely given a commit id
349 set -- git update-ref --no-deref "${local_ref}" "${remote_ref}"
350 fi
351
352 echo "${@}" >&2
353 if ! "${@}"; then
354 die "Referencing ${remote_ref} failed (wrong ref?)."
355 fi
356
357 success=1
358 break
359 fi
360 done
361 [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
362
363 # recursively fetch submodules
364 if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
365 local submodules
366 _git-r3_set_submodules \
367 "$(git cat-file -p "${local_ref}":.gitmodules || die)"
368
369 while [[ ${submodules[@]} ]]; do
370 local subname=${submodules[0]}
371 local url=${submodules[1]}
372 local path=${submodules[2]}
373 local commit=$(git rev-parse "${local_ref}:${path}")
374
375 if [[ ! ${commit} ]]; then
376 die "Unable to get commit id for submodule ${subname}"
377 fi
378 if [[ ${url} == ./* || ${url} == ../* ]]; then
379 local subrepos=( "${repos[@]/%//${url}}" )
380 else
381 local subrepos=( "${url}" )
382 fi
383
384 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}"
385
386 submodules=( "${submodules[@]:3}" ) # shift
387 done
388 fi
389}
390
391# @FUNCTION: git-r3_checkout
392# @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
393# @DESCRIPTION:
394# Check the previously fetched tree to the working copy.
395#
396# <repo-uri> specifies the repository URIs, as a space-separated list.
397# The first URI will be used as repository group identifier
398# and therefore must be used consistently with git-r3_fetch.
399# The remaining URIs are not used and therefore may be omitted.
400# When not specified, defaults to ${EGIT_REPO_URI}.
401#
402# <checkout-path> specifies the path to place the checkout. It defaults
403# to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
404#
405# <local-id> needs to specify the local identifier that was used
406# for respective git-r3_fetch.
407#
408# The checkout operation will write to the working copy, and export
409# the repository state into the environment. If the repository contains
410# submodules, they will be checked out recursively.
411git-r3_checkout() {
412 debug-print-function ${FUNCNAME} "$@"
413
414 local repos
415 if [[ ${1} ]]; then
416 repos=( ${1} )
417 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
418 repos=( "${EGIT_REPO_URI[@]}" )
419 else
420 repos=( ${EGIT_REPO_URI} )
421 fi
422
423 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
424 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
425
426 local -x GIT_DIR
427 _git-r3_set_gitdir "${repos[0]}"
428
429 einfo "Checking out ${repos[0]} to ${out_dir} ..."
430
431 if ! git cat-file -e refs/git-r3/"${local_id}"/__main__; then
432 if [[ ${EVCS_OFFLINE} ]]; then
433 die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE."
434 else
435 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
436 fi
437 fi
438 local remote_ref=$(
439 git symbolic-ref --quiet refs/git-r3/"${local_id}"/__main__
440 )
441 local new_commit_id=$(
442 git rev-parse --verify refs/git-r3/"${local_id}"/__main__
443 )
444
445 set -- git clone --quiet --shared --no-checkout "${GIT_DIR}" "${out_dir}"/
446 echo "${@}" >&2
447 "${@}" || die "git clone (for checkout) failed"
448
449 git-r3_sub_checkout() {
450 local -x GIT_DIR=${out_dir}/.git
451 local -x GIT_WORK_TREE=${out_dir}
452
453 set -- git checkout --quiet
454 if [[ ${remote_ref} ]]; then
455 set -- "${@}" "${remote_ref#refs/heads/}"
456 else
457 set -- "${@}" "${new_commit_id}"
458 fi
459 echo "${@}" >&2
460 "${@}" || die "git checkout ${remote_ref:-${new_commit_id}} failed"
461 }
462 git-r3_sub_checkout
463
464 local old_commit_id=$(
465 git rev-parse --quiet --verify refs/git-r3/"${local_id}"/__old__
466 )
467 if [[ ! ${old_commit_id} ]]; then
468 echo "GIT NEW branch -->"
469 echo " repository: ${repos[0]}"
470 echo " at the commit: ${new_commit_id}"
471 else
472 # diff against previous revision
473 echo "GIT update -->"
474 echo " repository: ${repos[0]}"
475 # write out message based on the revisions
476 if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
477 echo " updating from commit: ${old_commit_id}"
478 echo " to commit: ${new_commit_id}"
479
480 git --no-pager diff --stat \
481 ${old_commit_id}..${new_commit_id}
482 else
483 echo " at the commit: ${new_commit_id}"
484 fi
485 fi
486 git update-ref --no-deref refs/git-r3/"${local_id}"/{__old__,__main__} || die
487
488 # recursively checkout submodules
489 if [[ -f ${out_dir}/.gitmodules ]]; then
490 local submodules
491 _git-r3_set_submodules \
492 "$(<"${out_dir}"/.gitmodules)"
493
494 while [[ ${submodules[@]} ]]; do
495 local subname=${submodules[0]}
496 local url=${submodules[1]}
497 local path=${submodules[2]}
498
499 if [[ ${url} == ./* || ${url} == ../* ]]; then
500 url=${repos[0]%%/}/${url}
501 fi
502
503 git-r3_checkout "${url}" "${out_dir}/${path}" \
504 "${local_id}/${subname}"
505
506 submodules=( "${submodules[@]:3}" ) # shift
507 done
508 fi
509
510 # keep this *after* submodules
511 export EGIT_DIR=${GIT_DIR}
512 export EGIT_VERSION=${new_commit_id}
513}
514
515# @FUNCTION: git-r3_peek_remote_ref
516# @USAGE: [<repo-uri> [<remote-ref>]]
517# @DESCRIPTION:
518# Peek the reference in the remote repository and print the matching
519# (newest) commit SHA1.
520#
521# <repo-uri> specifies the repository URIs to fetch from, as a space-
522# -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
523#
524# <remote-ref> specifies the remote ref to peek. It is preferred to use
525# 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
526# for tags. Alternatively, 'HEAD' may be used for upstream default
527# branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
528# 'HEAD' that is set to a non-null value.
529#
530# The operation will be done purely on the remote, without using local
531# storage. If commit SHA1 is provided as <remote-ref>, the function will
532# fail due to limitations of git protocol.
533#
534# On success, the function returns 0 and writes hexadecimal commit SHA1
535# to stdout. On failure, the function returns 1.
536git-r3_peek_remote_ref() {
537 debug-print-function ${FUNCNAME} "$@"
538
539 local repos
540 if [[ ${1} ]]; then
541 repos=( ${1} )
542 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
543 repos=( "${EGIT_REPO_URI[@]}" )
544 else
545 repos=( ${EGIT_REPO_URI} )
546 fi
547
548 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
549 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
550
551 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
552
553 local r success
554 for r in "${repos[@]}"; do
426 einfo "Fetching ${remote_ref} from ${r} ..." 555 einfo "Peeking ${remote_ref} on ${r} ..." >&2
427 556
428 local is_branch lookup_ref 557 local is_branch lookup_ref
429 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] 558 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
430 then 559 then
431 is_branch=1 560 is_branch=1
434 # ls-remote by commit is going to fail anyway, 563 # ls-remote by commit is going to fail anyway,
435 # so we may as well pass refs/tags/ABCDEF... 564 # so we may as well pass refs/tags/ABCDEF...
436 lookup_ref=refs/tags/${remote_ref} 565 lookup_ref=refs/tags/${remote_ref}
437 fi 566 fi
438 567
439 # first, try ls-remote to see if ${remote_ref} is a real ref
440 # and not a commit id. if it succeeds, we can pass ${remote_ref}
441 # to 'fetch'. otherwise, we will just fetch everything
442
443 # split on whitespace
444 local ref=(
445 $(git ls-remote "${r}" "${lookup_ref}" || echo __FAIL__)
446 )
447
448 # normally, ref[0] is a hash, so we can do magic strings here
449 [[ ${ref[0]} == __FAIL__ ]] && continue
450
451 local nonshallow=${EGIT_NONSHALLOW}
452 local ref_param=()
453 if [[ ! ${ref[0]} ]]; then
454 nonshallow=1
455 fi
456
457 # trying to do a shallow clone of a local repo makes git try to
458 # write to the repo. we don't want that to happen.
459 _git-r3_is_local_repo "${r}" && nonshallow=1
460
461 # 1. if we need a non-shallow clone and we have a shallow one,
462 # we need to unshallow it explicitly.
463 # 2. if we want a shallow clone, we just pass '--depth 1'
464 # to the first fetch in the repo. passing '--depth'
465 # to further requests usually results in more data being
466 # downloaded than without it.
467 # 3. if we update a shallow clone, we try without '--depth'
468 # first since that usually transfers less data. however,
469 # we use git-r3_smart_fetch that can switch into '--depth 1'
470 # if that looks beneficial.
471
472 local fetch_command=( git fetch )
473 if [[ ${nonshallow} ]]; then
474 if [[ -f ${GIT_DIR}/shallow ]]; then
475 ref_param+=( --unshallow )
476 fi
477 # fetch all branches
478 ref_param+=( "refs/heads/*:refs/remotes/origin/*" )
479 else
480 # 'git show-ref --heads' returns 1 when there are no branches
481 if ! git show-ref --heads -q; then
482 ref_param+=( --depth 1 )
483 else
484 fetch_command=( _git-r3_smart_fetch )
485 fi
486 fi
487
488 # now, another important thing. we may only fetch a remote
489 # branch directly to a local branch. Otherwise, we need to fetch
490 # the commit and re-create the branch on top of it.
491
492 if [[ ${ref[0]} ]]; then
493 if [[ ${is_branch} ]]; then
494 ref_param+=( -f "${remote_ref}:${local_id}/__main__" )
495 else
496 ref_param+=( "refs/tags/${remote_ref}" )
497 fi
498 fi
499
500 # if ${remote_ref} is branch or tag, ${ref[@]} will contain
501 # the respective commit id. otherwise, it will be an empty
502 # array, so the following won't evaluate to a parameter.
503 set -- "${fetch_command[@]}" --no-tags "${r}" "${ref_param[@]}"
504 echo "${@}" >&2
505 if "${@}"; then
506 if [[ ! ${is_branch} ]]; then
507 set -- git branch -f "${local_id}/__main__" \
508 "${ref[0]:-${remote_ref}}"
509 echo "${@}" >&2
510 if ! "${@}"; then
511 die "Creating branch for ${remote_ref} failed (wrong ref?)."
512 fi
513 fi
514
515 success=1
516 break
517 fi
518 done
519 [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
520
521 # recursively fetch submodules
522 if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
523 local submodules
524 _git-r3_set_submodules \
525 "$(git cat-file -p "${local_ref}":.gitmodules || die)"
526
527 while [[ ${submodules[@]} ]]; do
528 local subname=${submodules[0]}
529 local url=${submodules[1]}
530 local path=${submodules[2]}
531 local commit=$(git rev-parse "${local_ref}:${path}")
532
533 if [[ ! ${commit} ]]; then
534 die "Unable to get commit id for submodule ${subname}"
535 fi
536 if [[ ${url} == ./* || ${url} == ../* ]]; then
537 local subrepos=( "${repos[@]/%//${url}}" )
538 else
539 local subrepos=( "${url}" )
540 fi
541
542 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}"
543
544 submodules=( "${submodules[@]:3}" ) # shift
545 done
546 fi
547}
548
549# @FUNCTION: git-r3_checkout
550# @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
551# @DESCRIPTION:
552# Check the previously fetched tree to the working copy.
553#
554# <repo-uri> specifies the repository URIs, as a space-separated list.
555# The first URI will be used as repository group identifier
556# and therefore must be used consistently with git-r3_fetch.
557# The remaining URIs are not used and therefore may be omitted.
558# When not specified, defaults to ${EGIT_REPO_URI}.
559#
560# <checkout-path> specifies the path to place the checkout. It defaults
561# to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
562#
563# <local-id> needs to specify the local identifier that was used
564# for respective git-r3_fetch.
565#
566# The checkout operation will write to the working copy, and export
567# the repository state into the environment. If the repository contains
568# submodules, they will be checked out recursively.
569git-r3_checkout() {
570 debug-print-function ${FUNCNAME} "$@"
571
572 local repos
573 if [[ ${1} ]]; then
574 repos=( ${1} )
575 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
576 repos=( "${EGIT_REPO_URI[@]}" )
577 else
578 repos=( ${EGIT_REPO_URI} )
579 fi
580
581 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
582 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
583
584 local -x GIT_DIR GIT_WORK_TREE
585 _git-r3_set_gitdir "${repos[0]}"
586 GIT_WORK_TREE=${out_dir}
587 mkdir -p "${GIT_WORK_TREE}" || die
588
589 einfo "Checking out ${repos[0]} to ${out_dir} ..."
590
591 if ! git cat-file -e refs/heads/"${local_id}"/__main__
592 then
593 if [[ ${EVCS_OFFLINE} ]]; then
594 die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE."
595 else
596 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
597 fi
598 fi
599
600 # Note: this is a hack to avoid parallel checkout issues.
601 # I will try to handle it without locks when I have more time.
602 local lockfile=${GIT_DIR}/.git-r3_checkout_lock
603 local lockfile_l=${lockfile}.${BASHPID}
604 touch "${lockfile_l}" || die
605 until ln "${lockfile_l}" "${lockfile}" &>/dev/null; do
606 sleep 1
607 done
608 rm "${lockfile_l}" || die
609
610 set -- git checkout -f "${local_id}"/__main__ .
611 echo "${@}" >&2
612 "${@}"
613 local ret=${?}
614
615 # Remove the lock!
616 rm "${lockfile}" || die
617
618 [[ ${ret} == 0 ]] || die "git checkout ${local_id}/__main__ failed"
619
620 # diff against previous revision (if any)
621 local new_commit_id=$(git rev-parse --verify "${local_id}"/__main__)
622 local old_commit_id=$(
623 git rev-parse --verify "${local_id}"/__old__ 2>/dev/null
624 )
625
626 if [[ ! ${old_commit_id} ]]; then
627 echo "GIT NEW branch -->"
628 echo " repository: ${repos[0]}"
629 echo " at the commit: ${new_commit_id}"
630 else
631 echo "GIT update -->"
632 echo " repository: ${repos[0]}"
633 # write out message based on the revisions
634 if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
635 echo " updating from commit: ${old_commit_id}"
636 echo " to commit: ${new_commit_id}"
637
638 git --no-pager diff --stat \
639 ${old_commit_id}..${new_commit_id}
640 else
641 echo " at the commit: ${new_commit_id}"
642 fi
643 fi
644 git branch -f "${local_id}"/{__old__,__main__} || die
645
646 # recursively checkout submodules
647 if [[ -f ${GIT_WORK_TREE}/.gitmodules ]]; then
648 local submodules
649 _git-r3_set_submodules \
650 "$(<"${GIT_WORK_TREE}"/.gitmodules)"
651
652 while [[ ${submodules[@]} ]]; do
653 local subname=${submodules[0]}
654 local url=${submodules[1]}
655 local path=${submodules[2]}
656
657 if [[ ${url} == ./* || ${url} == ../* ]]; then
658 url=${repos[0]%%/}/${url}
659 fi
660
661 git-r3_checkout "${url}" "${GIT_WORK_TREE}/${path}" \
662 "${local_id}/${subname}"
663
664 submodules=( "${submodules[@]:3}" ) # shift
665 done
666 fi
667
668 # keep this *after* submodules
669 export EGIT_DIR=${GIT_DIR}
670 export EGIT_VERSION=${new_commit_id}
671
672 # create a fake '.git' directory to satisfy 'git rev-parse HEAD'
673 GIT_DIR=${GIT_WORK_TREE}/.git
674 git init || die
675 echo "${EGIT_VERSION}" > "${GIT_WORK_TREE}"/.git/HEAD || die
676}
677
678# @FUNCTION: git-r3_peek_remote_ref
679# @USAGE: [<repo-uri> [<remote-ref>]]
680# @DESCRIPTION:
681# Peek the reference in the remote repository and print the matching
682# (newest) commit SHA1.
683#
684# <repo-uri> specifies the repository URIs to fetch from, as a space-
685# -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
686#
687# <remote-ref> specifies the remote ref to peek. It is preferred to use
688# 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
689# for tags. Alternatively, 'HEAD' may be used for upstream default
690# branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
691# 'HEAD' that is set to a non-null value.
692#
693# The operation will be done purely on the remote, without using local
694# storage. If commit SHA1 is provided as <remote-ref>, the function will
695# fail due to limitations of git protocol.
696#
697# On success, the function returns 0 and writes hexadecimal commit SHA1
698# to stdout. On failure, the function returns 1.
699git-r3_peek_remote_ref() {
700 debug-print-function ${FUNCNAME} "$@"
701
702 local repos
703 if [[ ${1} ]]; then
704 repos=( ${1} )
705 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
706 repos=( "${EGIT_REPO_URI[@]}" )
707 else
708 repos=( ${EGIT_REPO_URI} )
709 fi
710
711 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
712 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
713
714 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
715
716 local r success
717 for r in "${repos[@]}"; do
718 einfo "Peeking ${remote_ref} on ${r} ..." >&2
719
720 local is_branch lookup_ref
721 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
722 then
723 is_branch=1
724 lookup_ref=${remote_ref}
725 else
726 # ls-remote by commit is going to fail anyway,
727 # so we may as well pass refs/tags/ABCDEF...
728 lookup_ref=refs/tags/${remote_ref}
729 fi
730
731 # split on whitespace 568 # split on whitespace
732 local ref=( 569 local ref=(
733 $(git ls-remote "${r}" "${lookup_ref}") 570 $(git ls-remote "${r}" "${lookup_ref}")
734 ) 571 )
735 572

Legend:
Removed from v.1.23  
changed lines
  Added in v.1.24

  ViewVC Help
Powered by ViewVC 1.1.20