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

Legend:
Removed from v.1.4  
changed lines
  Added in v.1.34

  ViewVC Help
Powered by ViewVC 1.1.20