/[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.7 Revision 1.27
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.7 2013/09/19 09:42:32 mgorny Exp $ 3# $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.27 2014/03/02 11:44:19 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"
33fi
34
32# @ECLASS-VARIABLE: EGIT3_STORE_DIR 35# @ECLASS-VARIABLE: EGIT3_STORE_DIR
33# @DESCRIPTION: 36# @DESCRIPTION:
34# Storage directory for git sources. 37# Storage directory for git sources.
38#
39# This is intended to be set by user in make.conf. Ebuilds must not set
40# it.
35# 41#
36# EGIT3_STORE_DIR=${DISTDIR}/git3-src 42# EGIT3_STORE_DIR=${DISTDIR}/git3-src
37 43
38# @ECLASS-VARIABLE: EGIT_REPO_URI 44# @ECLASS-VARIABLE: EGIT_REPO_URI
39# @REQUIRED 45# @REQUIRED
41# URIs to the repository, e.g. git://foo, https://foo. If multiple URIs 47# 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 48# are provided, the eclass will consider them as fallback URIs to try
43# if the first URI does not work. 49# if the first URI does not work.
44# 50#
45# It can be overriden via env using ${PN}_LIVE_REPO variable. 51# It can be overriden via env using ${PN}_LIVE_REPO variable.
52#
53# Can be a whitespace-separated list or an array.
46# 54#
47# Example: 55# Example:
48# @CODE 56# @CODE
49# EGIT_REPO_URI="git://a/b.git https://c/d.git" 57# EGIT_REPO_URI="git://a/b.git https://c/d.git"
50# @CODE 58# @CODE
74# @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR 82# @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR
75# @DESCRIPTION: 83# @DESCRIPTION:
76# The directory to check the git sources out to. 84# The directory to check the git sources out to.
77# 85#
78# EGIT_CHECKOUT_DIR=${WORKDIR}/${P} 86# EGIT_CHECKOUT_DIR=${WORKDIR}/${P}
79
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 87
90# @FUNCTION: _git-r3_env_setup 88# @FUNCTION: _git-r3_env_setup
91# @INTERNAL 89# @INTERNAL
92# @DESCRIPTION: 90# @DESCRIPTION:
93# Set the eclass variables as necessary for operation. This can involve 91# Set the eclass variables as necessary for operation. This can involve
176 174
177 # strip common prefixes to make paths more likely to match 175 # strip common prefixes to make paths more likely to match
178 # e.g. git://X/Y.git vs https://X/git/Y.git 176 # e.g. git://X/Y.git vs https://X/git/Y.git
179 # (but just one of the prefixes) 177 # (but just one of the prefixes)
180 case "${repo_name}" in 178 case "${repo_name}" in
179 # gnome.org... who else?
180 browse/*) repo_name=${repo_name#browse/};;
181 # cgit can proxy requests to git 181 # cgit can proxy requests to git
182 cgit/*) repo_name=${repo_name#cgit/};; 182 cgit/*) repo_name=${repo_name#cgit/};;
183 # pretty common 183 # pretty common
184 git/*) repo_name=${repo_name#git/};; 184 git/*) repo_name=${repo_name#git/};;
185 # gentoo.org 185 # gentoo.org
200 GIT_DIR=${EGIT3_STORE_DIR}/${repo_name} 200 GIT_DIR=${EGIT3_STORE_DIR}/${repo_name}
201 201
202 if [[ ! -d ${EGIT3_STORE_DIR} ]]; then 202 if [[ ! -d ${EGIT3_STORE_DIR} ]]; then
203 ( 203 (
204 addwrite / 204 addwrite /
205 mkdir -m0755 -p "${EGIT3_STORE_DIR}" 205 mkdir -m0755 -p "${EGIT3_STORE_DIR}" || die
206 ) || die "Unable to create ${EGIT3_STORE_DIR}" 206 ) || die "Unable to create ${EGIT3_STORE_DIR}"
207 fi 207 fi
208 208
209 addwrite "${EGIT3_STORE_DIR}" 209 addwrite "${EGIT3_STORE_DIR}"
210 if [[ -e ${GIT_DIR}/shallow ]]; then
211 einfo "${GIT_DIR} was a shallow clone, recreating..."
212 rm -r "${GIT_DIR}" || die
213 fi
210 if [[ ! -d ${GIT_DIR} ]]; then 214 if [[ ! -d ${GIT_DIR} ]]; then
211 mkdir "${GIT_DIR}" || die 215 mkdir "${GIT_DIR}" || die
212 git init --bare || die 216 git init --bare || die
213
214 if [[ ! ${EGIT_NONSHALLOW} ]]; then
215 # avoid auto-unshallow :)
216 touch "${GIT_DIR}"/shallow || die
217 fi
218 fi 217 fi
219} 218}
220 219
221# @FUNCTION: _git-r3_set_submodules 220# @FUNCTION: _git-r3_set_submodules
222# @USAGE: <file-contents> 221# @USAGE: <file-contents>
240 [[ ${l} == submodule.*.url=* ]] || continue 239 [[ ${l} == submodule.*.url=* ]] || continue
241 240
242 l=${l#submodule.} 241 l=${l#submodule.}
243 local subname=${l%%.url=*} 242 local subname=${l%%.url=*}
244 243
244 # skip modules that have 'update = none', bug #487262.
245 local upd=$(echo "${data}" | git config -f /dev/fd/0 \
246 submodule."${subname}".update)
247 [[ ${upd} == none ]] && continue
248
245 submodules+=( 249 submodules+=(
246 "${subname}" 250 "${subname}"
247 "$(echo "${data}" | git config -f /dev/fd/0 \ 251 "$(echo "${data}" | git config -f /dev/fd/0 \
248 submodule."${subname}".url)" 252 submodule."${subname}".url || die)"
249 "$(echo "${data}" | git config -f /dev/fd/0 \ 253 "$(echo "${data}" | git config -f /dev/fd/0 \
250 submodule."${subname}".path)" 254 submodule."${subname}".path || die)"
251 ) 255 )
252 done < <(echo "${data}" | git config -f /dev/fd/0 -l) 256 done < <(echo "${data}" | git config -f /dev/fd/0 -l || die)
253} 257}
254 258
255# @FUNCTION: _git-r3_smart_fetch 259# @FUNCTION: _git-r3_is_local_repo
256# @USAGE: <git-fetch-args>... 260# @USAGE: <repo-uri>
261# @INTERNAL
257# @DESCRIPTION: 262# @DESCRIPTION:
258# Try fetching without '--depth' and switch to '--depth 1' if that 263# Determine whether the given URI specifies a local (on-disk)
259# will involve less objects fetched. 264# repository.
260_git-r3_smart_fetch() { 265_git-r3_is_local_repo() {
261 debug-print-function ${FUNCNAME} "$@" 266 debug-print-function ${FUNCNAME} "$@"
262 267
263 local sed_regexp='.*Counting objects: \([0-9]*\), done\..*'
264
265 # start the main fetch
266 local cmd=( git fetch --progress "${@}" )
267 echo "${cmd[@]}" >&2
268
269 # we copy the output to the 'sed' pipe for parsing. whenever sed finds
270 # the process count, it quits quickly to avoid delays in writing it.
271 # then, we start a dummy 'cat' to keep the pipe alive
272
273 "${cmd[@]}" 2>&1 \
274 | tee >(
275 sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}" \
276 > "${T}"/git-r3_main.count
277 exec cat >/dev/null
278 ) &
279 local main_pid=${!}
280
281 # start the helper process
282 _git-r3_sub_fetch() {
283 # wait for main fetch to get object count; if the server doesn't
284 # output it, we won't even launch the parallel process
285 while [[ ! -s ${T}/git-r3_main.count ]]; do
286 sleep 0.25
287 done
288
289 # ok, let's see if parallel fetch gives us smaller count
290 # --dry-run will prevent it from writing to the local clone
291 # and sed should terminate git with SIGPIPE
292 local sub_count=$(git fetch --progress --dry-run --depth 1 "${@}" 2>&1 \
293 | sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}")
294 local main_count=$(<"${T}"/git-r3_main.count)
295
296 # let's be real sure that '--depth 1' will be good for us.
297 # note that we have purely objects counts, and '--depth 1'
298 # may involve much bigger objects
299 if [[ ${main_count} && ${main_count} -ge $(( sub_count * 3/2 )) ]]
300 then
301 # signal that we want shallow fetch instead,
302 # and terminate the non-shallow fetch process
303 touch "${T}"/git-r3_want_shallow || die
304 kill ${main_pid} &>/dev/null
305 exit 0
306 fi
307
308 exit 1
309 }
310 _git-r3_sub_fetch "${@}" &
311 local sub_pid=${!} 268 local uri=${1}
312 269
313 # wait for main process to terminate, either of its own 270 [[ ${uri} == file://* || ${uri} == /* ]]
314 # or by signal from subprocess
315 wait ${main_pid}
316 local main_ret=${?}
317
318 # wait for subprocess to terminate, killing it if necessary.
319 # if main fetch finished before it, there's no point in keeping
320 # it alive. if main fetch was killed by it, it's done anyway
321 kill ${sub_pid} &>/dev/null
322 wait ${sub_pid}
323
324 # now see if subprocess wanted to tell us something...
325 if [[ -f ${T}/git-r3_want_shallow ]]; then
326 rm "${T}"/git-r3_want_shallow || die
327
328 # if fetch finished already (wasn't killed), ignore it
329 [[ ${main_ret} -eq 0 ]] && return 0
330
331 # otherwise, restart as shallow fetch
332 einfo "Restarting fetch using --depth 1 to save bandwidth ..."
333 local cmd=( git fetch --progress --depth 1 "${@}" )
334 echo "${cmd[@]}" >&2
335 "${cmd[@]}"
336 main_ret=${?}
337 fi
338
339 return ${main_ret}
340} 271}
341 272
342# @FUNCTION: git-r3_fetch 273# @FUNCTION: git-r3_fetch
343# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]] 274# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]]
344# @DESCRIPTION: 275# @DESCRIPTION:
357# is set to a non-null value. 288# is set to a non-null value.
358# 289#
359# <local-id> specifies the local branch identifier that will be used to 290# <local-id> specifies the local branch identifier that will be used to
360# locally store the fetch result. It should be unique to multiple 291# locally store the fetch result. It should be unique to multiple
361# fetches within the repository that can be performed at the same time 292# fetches within the repository that can be performed at the same time
362# (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT}. 293# (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT%/*}.
363# This default should be fine unless you are fetching multiple trees 294# This default should be fine unless you are fetching multiple trees
364# from the same repository in the same ebuild. 295# from the same repository in the same ebuild.
365# 296#
366# The fetch operation will affect the EGIT_STORE only. It will not touch 297# The fetch operation will affect the EGIT_STORE only. It will not touch
367# the working copy, nor export any environment variables. 298# the working copy, nor export any environment variables.
368# If the repository contains submodules, they will be fetched 299# If the repository contains submodules, they will be fetched
369# recursively. 300# recursively.
370git-r3_fetch() { 301git-r3_fetch() {
371 debug-print-function ${FUNCNAME} "$@" 302 debug-print-function ${FUNCNAME} "$@"
372 303
304 [[ ${EVCS_OFFLINE} ]] && return
305
306 local repos
307 if [[ ${1} ]]; then
308 repos=( ${1} )
309 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
310 repos=( "${EGIT_REPO_URI[@]}" )
311 else
373 local repos=( ${1:-${EGIT_REPO_URI}} ) 312 repos=( ${EGIT_REPO_URI} )
313 fi
314
374 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} 315 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
375 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} 316 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
376 local local_id=${3:-${CATEGORY}/${PN}/${SLOT}} 317 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
377 local local_ref=refs/heads/${local_id}/__main__ 318 local local_ref=refs/git-r3/${local_id}/__main__
378 319
379 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" 320 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
380 321
381 local -x GIT_DIR 322 local -x GIT_DIR
382 _git-r3_set_gitdir ${repos[0]} 323 _git-r3_set_gitdir "${repos[0]}"
383 324
384 # try to fetch from the remote 325 # try to fetch from the remote
385 local r success 326 local r success
386 for r in ${repos[@]}; do 327 for r in "${repos[@]}"; do
328 einfo "Fetching ${r} ..."
329
330 local fetch_command=(
331 git fetch --prune "${r}"
332 # mirror the remote branches as local branches
333 "refs/heads/*:refs/heads/*"
334 # pull tags explicitly in order to prune them properly
335 "refs/tags/*:refs/tags/*"
336 # notes in case something needs them
337 "refs/notes/*:refs/notes/*"
338 )
339
340 set -- "${fetch_command[@]}"
341 echo "${@}" >&2
342 if "${@}"; then
343 # now let's see what the user wants from us
344 local full_remote_ref=$(
345 git rev-parse --verify --symbolic-full-name "${remote_ref}"
346 )
347
348 if [[ ${full_remote_ref} ]]; then
349 # when we are given a ref, create a symbolic ref
350 # so that we preserve the actual argument
351 set -- git symbolic-ref "${local_ref}" "${full_remote_ref}"
352 else
353 # otherwise, we were likely given a commit id
354 set -- git update-ref --no-deref "${local_ref}" "${remote_ref}"
355 fi
356
357 echo "${@}" >&2
358 if ! "${@}"; then
359 die "Referencing ${remote_ref} failed (wrong ref?)."
360 fi
361
362 success=1
363 break
364 fi
365 done
366 [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
367
368 # recursively fetch submodules
369 if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
370 local submodules
371 _git-r3_set_submodules \
372 "$(git cat-file -p "${local_ref}":.gitmodules || die)"
373
374 while [[ ${submodules[@]} ]]; do
375 local subname=${submodules[0]}
376 local url=${submodules[1]}
377 local path=${submodules[2]}
378 local commit=$(git rev-parse "${local_ref}:${path}")
379
380 if [[ ! ${commit} ]]; then
381 die "Unable to get commit id for submodule ${subname}"
382 fi
383 if [[ ${url} == ./* || ${url} == ../* ]]; then
384 local subrepos=( "${repos[@]/%//${url}}" )
385 else
386 local subrepos=( "${url}" )
387 fi
388
389 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}"
390
391 submodules=( "${submodules[@]:3}" ) # shift
392 done
393 fi
394}
395
396# @FUNCTION: git-r3_checkout
397# @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
398# @DESCRIPTION:
399# Check the previously fetched tree to the working copy.
400#
401# <repo-uri> specifies the repository URIs, as a space-separated list.
402# The first URI will be used as repository group identifier
403# and therefore must be used consistently with git-r3_fetch.
404# The remaining URIs are not used and therefore may be omitted.
405# When not specified, defaults to ${EGIT_REPO_URI}.
406#
407# <checkout-path> specifies the path to place the checkout. It defaults
408# to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
409#
410# <local-id> needs to specify the local identifier that was used
411# for respective git-r3_fetch.
412#
413# The checkout operation will write to the working copy, and export
414# the repository state into the environment. If the repository contains
415# submodules, they will be checked out recursively.
416git-r3_checkout() {
417 debug-print-function ${FUNCNAME} "$@"
418
419 local repos
420 if [[ ${1} ]]; then
421 repos=( ${1} )
422 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
423 repos=( "${EGIT_REPO_URI[@]}" )
424 else
425 repos=( ${EGIT_REPO_URI} )
426 fi
427
428 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
429 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
430
431 local -x GIT_DIR
432 _git-r3_set_gitdir "${repos[0]}"
433
434 einfo "Checking out ${repos[0]} to ${out_dir} ..."
435
436 if ! git cat-file -e refs/git-r3/"${local_id}"/__main__; then
437 if [[ ${EVCS_OFFLINE} ]]; then
438 die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE."
439 else
440 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
441 fi
442 fi
443 local remote_ref=$(
444 git symbolic-ref --quiet refs/git-r3/"${local_id}"/__main__
445 )
446 local new_commit_id=$(
447 git rev-parse --verify refs/git-r3/"${local_id}"/__main__
448 )
449
450 git-r3_sub_checkout() {
451 local orig_repo=${GIT_DIR}
452 local -x GIT_DIR=${out_dir}/.git
453 local -x GIT_WORK_TREE=${out_dir}
454
455 mkdir -p "${out_dir}" || die
456
457 # use git init+fetch instead of clone since the latter doesn't like
458 # non-empty directories.
459
460 git init --quiet || die
461 set -- git fetch --update-head-ok "${orig_repo}" \
462 "refs/heads/*:refs/heads/*" \
463 "refs/tags/*:refs/tags/*" \
464 "refs/notes/*:refs/notes/*"
465
466 echo "${@}" >&2
467 "${@}" || die "git fetch into checkout dir failed"
468
469 set -- git checkout --quiet
470 if [[ ${remote_ref} ]]; then
471 set -- "${@}" "${remote_ref#refs/heads/}"
472 else
473 set -- "${@}" "${new_commit_id}"
474 fi
475 echo "${@}" >&2
476 "${@}" || die "git checkout ${remote_ref:-${new_commit_id}} failed"
477 }
478 git-r3_sub_checkout
479
480 local old_commit_id=$(
481 git rev-parse --quiet --verify refs/git-r3/"${local_id}"/__old__
482 )
483 if [[ ! ${old_commit_id} ]]; then
484 echo "GIT NEW branch -->"
485 echo " repository: ${repos[0]}"
486 echo " at the commit: ${new_commit_id}"
487 else
488 # diff against previous revision
489 echo "GIT update -->"
490 echo " repository: ${repos[0]}"
491 # write out message based on the revisions
492 if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
493 echo " updating from commit: ${old_commit_id}"
494 echo " to commit: ${new_commit_id}"
495
496 git --no-pager diff --stat \
497 ${old_commit_id}..${new_commit_id}
498 else
499 echo " at the commit: ${new_commit_id}"
500 fi
501 fi
502 git update-ref --no-deref refs/git-r3/"${local_id}"/{__old__,__main__} || die
503
504 # recursively checkout submodules
505 if [[ -f ${out_dir}/.gitmodules ]]; then
506 local submodules
507 _git-r3_set_submodules \
508 "$(<"${out_dir}"/.gitmodules)"
509
510 while [[ ${submodules[@]} ]]; do
511 local subname=${submodules[0]}
512 local url=${submodules[1]}
513 local path=${submodules[2]}
514
515 if [[ ${url} == ./* || ${url} == ../* ]]; then
516 url=${repos[0]%%/}/${url}
517 fi
518
519 git-r3_checkout "${url}" "${out_dir}/${path}" \
520 "${local_id}/${subname}"
521
522 submodules=( "${submodules[@]:3}" ) # shift
523 done
524 fi
525
526 # keep this *after* submodules
527 export EGIT_DIR=${GIT_DIR}
528 export EGIT_VERSION=${new_commit_id}
529}
530
531# @FUNCTION: git-r3_peek_remote_ref
532# @USAGE: [<repo-uri> [<remote-ref>]]
533# @DESCRIPTION:
534# Peek the reference in the remote repository and print the matching
535# (newest) commit SHA1.
536#
537# <repo-uri> specifies the repository URIs to fetch from, as a space-
538# -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
539#
540# <remote-ref> specifies the remote ref to peek. It is preferred to use
541# 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
542# for tags. Alternatively, 'HEAD' may be used for upstream default
543# branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
544# 'HEAD' that is set to a non-null value.
545#
546# The operation will be done purely on the remote, without using local
547# storage. If commit SHA1 is provided as <remote-ref>, the function will
548# fail due to limitations of git protocol.
549#
550# On success, the function returns 0 and writes hexadecimal commit SHA1
551# to stdout. On failure, the function returns 1.
552git-r3_peek_remote_ref() {
553 debug-print-function ${FUNCNAME} "$@"
554
555 local repos
556 if [[ ${1} ]]; then
557 repos=( ${1} )
558 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
559 repos=( "${EGIT_REPO_URI[@]}" )
560 else
561 repos=( ${EGIT_REPO_URI} )
562 fi
563
564 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
565 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
566
567 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
568
569 local r success
570 for r in "${repos[@]}"; do
387 einfo "Fetching ${remote_ref} from ${r} ..." 571 einfo "Peeking ${remote_ref} on ${r} ..." >&2
388 572
389 local is_branch lookup_ref 573 local is_branch lookup_ref
390 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] 574 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
391 then 575 then
392 is_branch=1 576 is_branch=1
395 # ls-remote by commit is going to fail anyway, 579 # ls-remote by commit is going to fail anyway,
396 # so we may as well pass refs/tags/ABCDEF... 580 # so we may as well pass refs/tags/ABCDEF...
397 lookup_ref=refs/tags/${remote_ref} 581 lookup_ref=refs/tags/${remote_ref}
398 fi 582 fi
399 583
400 # first, try ls-remote to see if ${remote_ref} is a real ref
401 # and not a commit id. if it succeeds, we can pass ${remote_ref}
402 # to 'fetch'. otherwise, we will just fetch everything
403
404 # split on whitespace
405 local ref=(
406 $(git ls-remote "${r}" "${lookup_ref}" || echo __FAIL__)
407 )
408
409 # normally, ref[0] is a hash, so we can do magic strings here
410 [[ ${ref[0]} == __FAIL__ ]] && continue
411
412 local nonshallow=${EGIT_NONSHALLOW}
413 local ref_param=()
414 if [[ ! ${ref[0]} ]]; then
415 nonshallow=1
416 fi
417
418 # 1. if we need a non-shallow clone and we have a shallow one,
419 # we need to unshallow it explicitly.
420 # 2. if we want a shallow clone, we just pass '--depth 1'
421 # to the first fetch in the repo. passing '--depth'
422 # to further requests usually results in more data being
423 # downloaded than without it.
424 # 3. if we update a shallow clone, we try without '--depth'
425 # first since that usually transfers less data. however,
426 # we use git-r3_smart_fetch that can switch into '--depth 1'
427 # if that looks beneficial.
428
429 local fetch_command=( git fetch )
430 if [[ ${nonshallow} ]]; then
431 if [[ -f ${GIT_DIR}/shallow ]]; then
432 ref_param+=( --unshallow )
433 fi
434 else
435 # 'git show-ref --heads' returns 1 when there are no branches
436 if ! git show-ref --heads -q; then
437 ref_param+=( --depth 1 )
438 else
439 fetch_command=( _git-r3_smart_fetch )
440 fi
441 fi
442
443 # now, another important thing. we may only fetch a remote
444 # branch directly to a local branch. Otherwise, we need to fetch
445 # the commit and re-create the branch on top of it.
446
447 if [[ ${ref[0]} ]]; then
448 if [[ ${is_branch} ]]; then
449 ref_param+=( -f "${remote_ref}:${local_id}/__main__" )
450 else
451 ref_param+=( "refs/tags/${remote_ref}" )
452 fi
453 fi
454
455 # if ${remote_ref} is branch or tag, ${ref[@]} will contain
456 # the respective commit id. otherwise, it will be an empty
457 # array, so the following won't evaluate to a parameter.
458 set -- "${fetch_command[@]}" --no-tags "${r}" "${ref_param[@]}"
459 echo "${@}" >&2
460 if "${@}"; then
461 if [[ ! ${is_branch} ]]; then
462 set -- git branch -f "${local_id}/__main__" \
463 "${ref[0]:-${remote_ref}}"
464 echo "${@}" >&2
465 if ! "${@}"; then
466 die "Creating branch for ${remote_ref} failed (wrong ref?)."
467 fi
468 fi
469
470 success=1
471 break
472 fi
473 done
474 [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
475
476 # recursively fetch submodules
477 if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
478 local submodules
479 _git-r3_set_submodules \
480 "$(git cat-file -p "${local_ref}":.gitmodules || die)"
481
482 while [[ ${submodules[@]} ]]; do
483 local subname=${submodules[0]}
484 local url=${submodules[1]}
485 local path=${submodules[2]}
486 local commit=$(git rev-parse "${local_ref}:${path}")
487
488 if [[ ! ${commit} ]]; then
489 die "Unable to get commit id for submodule ${subname}"
490 fi
491
492 git-r3_fetch "${url}" "${commit}" "${local_id}/${subname}"
493
494 submodules=( "${submodules[@]:3}" ) # shift
495 done
496 fi
497}
498
499# @FUNCTION: git-r3_checkout
500# @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
501# @DESCRIPTION:
502# Check the previously fetched tree to the working copy.
503#
504# <repo-uri> specifies the repository URIs, as a space-separated list.
505# The first URI will be used as repository group identifier
506# and therefore must be used consistently with git-r3_fetch.
507# The remaining URIs are not used and therefore may be omitted.
508# When not specified, defaults to ${EGIT_REPO_URI}.
509#
510# <checkout-path> specifies the path to place the checkout. It defaults
511# to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
512#
513# <local-id> needs to specify the local identifier that was used
514# for respective git-r3_fetch.
515#
516# The checkout operation will write to the working copy, and export
517# the repository state into the environment. If the repository contains
518# submodules, they will be checked out recursively.
519git-r3_checkout() {
520 debug-print-function ${FUNCNAME} "$@"
521
522 local repos=( ${1:-${EGIT_REPO_URI}} )
523 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
524 local local_id=${3:-${CATEGORY}/${PN}/${SLOT}}
525
526 local -x GIT_DIR GIT_WORK_TREE
527 _git-r3_set_gitdir ${repos[0]}
528 GIT_WORK_TREE=${out_dir}
529 mkdir -p "${GIT_WORK_TREE}"
530
531 einfo "Checking out ${repos[0]} to ${out_dir} ..."
532
533 if ! git cat-file -e refs/heads/"${local_id}"/__main__
534 then
535 if [[ ${EVCS_OFFLINE} ]]; then
536 die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE."
537 else
538 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
539 fi
540 fi
541
542 set -- git checkout -f "${local_id}"/__main__ .
543 echo "${@}" >&2
544 "${@}" || die "git checkout ${local_id}/__main__ failed"
545
546 # diff against previous revision (if any)
547 local new_commit_id=$(git rev-parse --verify "${local_id}"/__main__)
548 local old_commit_id=$(
549 git rev-parse --verify "${local_id}"/__old__ 2>/dev/null
550 )
551
552 if [[ ! ${old_commit_id} ]]; then
553 echo "GIT NEW branch -->"
554 echo " repository: ${repos[0]}"
555 echo " at the commit: ${new_commit_id}"
556 else
557 echo "GIT update -->"
558 echo " repository: ${repos[0]}"
559 # write out message based on the revisions
560 if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
561 echo " updating from commit: ${old_commit_id}"
562 echo " to commit: ${new_commit_id}"
563
564 git --no-pager diff --stat \
565 ${old_commit_id}..${new_commit_id}
566 else
567 echo " at the commit: ${new_commit_id}"
568 fi
569 fi
570 git branch -f "${local_id}"/{__old__,__main__} || die
571
572 # recursively checkout submodules
573 if [[ -f ${GIT_WORK_TREE}/.gitmodules ]]; then
574 local submodules
575 _git-r3_set_submodules \
576 "$(<"${GIT_WORK_TREE}"/.gitmodules)"
577
578 while [[ ${submodules[@]} ]]; do
579 local subname=${submodules[0]}
580 local url=${submodules[1]}
581 local path=${submodules[2]}
582
583 git-r3_checkout "${url}" "${GIT_WORK_TREE}/${path}" \
584 "${local_id}/${subname}"
585
586 submodules=( "${submodules[@]:3}" ) # shift
587 done
588 fi
589
590 # keep this *after* submodules
591 export EGIT_DIR=${GIT_DIR}
592 export EGIT_VERSION=${new_commit_id}
593}
594
595# @FUNCTION: git-r3_peek_remote_ref
596# @USAGE: [<repo-uri> [<remote-ref>]]
597# @DESCRIPTION:
598# Peek the reference in the remote repository and print the matching
599# (newest) commit SHA1.
600#
601# <repo-uri> specifies the repository URIs to fetch from, as a space-
602# -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
603#
604# <remote-ref> specifies the remote ref to peek. It is preferred to use
605# 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
606# for tags. Alternatively, 'HEAD' may be used for upstream default
607# branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
608# 'HEAD' that is set to a non-null value.
609#
610# The operation will be done purely on the remote, without using local
611# storage. If commit SHA1 is provided as <remote-ref>, the function will
612# fail due to limitations of git protocol.
613#
614# On success, the function returns 0 and writes hexadecimal commit SHA1
615# to stdout. On failure, the function returns 1.
616git-r3_peek_remote_ref() {
617 debug-print-function ${FUNCNAME} "$@"
618
619 local repos=( ${1:-${EGIT_REPO_URI}} )
620 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
621 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
622
623 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
624
625 local r success
626 for r in ${repos[@]}; do
627 einfo "Peeking ${remote_ref} on ${r} ..." >&2
628
629 local is_branch lookup_ref
630 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
631 then
632 is_branch=1
633 lookup_ref=${remote_ref}
634 else
635 # ls-remote by commit is going to fail anyway,
636 # so we may as well pass refs/tags/ABCDEF...
637 lookup_ref=refs/tags/${remote_ref}
638 fi
639
640 # split on whitespace 584 # split on whitespace
641 local ref=( 585 local ref=(
642 $(git ls-remote "${r}" "${lookup_ref}") 586 $(git ls-remote "${r}" "${lookup_ref}")
643 ) 587 )
644 588
652} 596}
653 597
654git-r3_src_fetch() { 598git-r3_src_fetch() {
655 debug-print-function ${FUNCNAME} "$@" 599 debug-print-function ${FUNCNAME} "$@"
656 600
657 [[ ${EVCS_OFFLINE} ]] && return
658
659 if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then 601 if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then
660 ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider" 602 ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider"
661 ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use" 603 ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use"
662 ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones" 604 ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones"
663 ewarn "when git-2 eclass becomes deprecated." 605 ewarn "when git-2 eclass becomes deprecated."

Legend:
Removed from v.1.7  
changed lines
  Added in v.1.27

  ViewVC Help
Powered by ViewVC 1.1.20