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

Legend:
Removed from v.1.10  
changed lines
  Added in v.1.44

  ViewVC Help
Powered by ViewVC 1.1.20