/[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.2 Revision 1.15
1# Copyright 1999-2013 Gentoo Foundation 1# Copyright 1999-2013 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.2 2013/09/05 22:40:12 mgorny Exp $ 3# $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.15 2013/10/09 17:14:07 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.
27 27
28EXPORT_FUNCTIONS src_unpack 28EXPORT_FUNCTIONS src_unpack
29 29
30if [[ ! ${_GIT_R3} ]]; then 30if [[ ! ${_GIT_R3} ]]; then
31 31
32if [[ ! ${_INHERITED_BY_GIT_2} ]]; then
33 DEPEND=">=dev-vcs/git-1.8.2.1"
34fi
35
32# @ECLASS-VARIABLE: EGIT3_STORE_DIR 36# @ECLASS-VARIABLE: EGIT3_STORE_DIR
33# @DESCRIPTION: 37# @DESCRIPTION:
34# Storage directory for git sources. 38# Storage directory for git sources.
35# 39#
36# EGIT3_STORE_DIR=${DISTDIR}/git3-src 40# EGIT3_STORE_DIR=${DISTDIR}/git3-src
41# URIs to the repository, e.g. git://foo, https://foo. If multiple URIs 45# 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 46# are provided, the eclass will consider them as fallback URIs to try
43# if the first URI does not work. 47# if the first URI does not work.
44# 48#
45# It can be overriden via env using ${PN}_LIVE_REPO variable. 49# It can be overriden via env using ${PN}_LIVE_REPO variable.
50#
51# Can be a whitespace-separated list or an array.
46# 52#
47# Example: 53# Example:
48# @CODE 54# @CODE
49# EGIT_REPO_URI="git://a/b.git https://c/d.git" 55# EGIT_REPO_URI="git://a/b.git https://c/d.git"
50# @CODE 56# @CODE
82# @DESCRIPTION: 88# @DESCRIPTION:
83# Disable performing shallow fetches/clones. Shallow clones have 89# Disable performing shallow fetches/clones. Shallow clones have
84# a fair number of limitations. Therefore, if you'd like the eclass to 90# 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. 91# perform complete clones instead, set this to a non-null value.
86# 92#
87# This variable is to be set in make.conf. Ebuilds are not allowed 93# This variable can be set in make.conf and ebuilds. The make.conf
88# to set it. 94# value specifies user-specific default, while ebuilds may use it
95# to force deep clones when the server does not support shallow clones
96# (e.g. Google Code).
89 97
90# @FUNCTION: _git-r3_env_setup 98# @FUNCTION: _git-r3_env_setup
91# @INTERNAL 99# @INTERNAL
92# @DESCRIPTION: 100# @DESCRIPTION:
93# Set the eclass variables as necessary for operation. This can involve 101# Set the eclass variables as necessary for operation. This can involve
169_git-r3_set_gitdir() { 177_git-r3_set_gitdir() {
170 debug-print-function ${FUNCNAME} "$@" 178 debug-print-function ${FUNCNAME} "$@"
171 179
172 local repo_name=${1#*://*/} 180 local repo_name=${1#*://*/}
173 181
182 # strip the trailing slash
183 repo_name=${repo_name%/}
184
174 # strip common prefixes to make paths more likely to match 185 # strip common prefixes to make paths more likely to match
175 # e.g. git://X/Y.git vs https://X/git/Y.git 186 # e.g. git://X/Y.git vs https://X/git/Y.git
176 # (but just one of the prefixes) 187 # (but just one of the prefixes)
177 case "${repo_name}" in 188 case "${repo_name}" in
189 # gnome.org... who else?
190 browse/*) repo_name=${repo_name#browse/};;
178 # cgit can proxy requests to git 191 # cgit can proxy requests to git
179 cgit/*) repo_name=${repo_name#cgit/};; 192 cgit/*) repo_name=${repo_name#cgit/};;
180 # pretty common 193 # pretty common
181 git/*) repo_name=${repo_name#git/};; 194 git/*) repo_name=${repo_name#git/};;
182 # gentoo.org 195 # gentoo.org
206 addwrite "${EGIT3_STORE_DIR}" 219 addwrite "${EGIT3_STORE_DIR}"
207 if [[ ! -d ${GIT_DIR} ]]; then 220 if [[ ! -d ${GIT_DIR} ]]; then
208 mkdir "${GIT_DIR}" || die 221 mkdir "${GIT_DIR}" || die
209 git init --bare || die 222 git init --bare || die
210 223
224 if [[ ! ${EGIT_NONSHALLOW} ]]; then
211 # avoid auto-unshallow :) 225 # avoid auto-unshallow :)
212 touch "${GIT_DIR}"/shallow || die 226 touch "${GIT_DIR}"/shallow || die
227 fi
213 fi 228 fi
214} 229}
215 230
216# @FUNCTION: _git-r3_set_submodules 231# @FUNCTION: _git-r3_set_submodules
217# @USAGE: <file-contents> 232# @USAGE: <file-contents>
234 # submodule.<path>.url=<url> 249 # submodule.<path>.url=<url>
235 [[ ${l} == submodule.*.url=* ]] || continue 250 [[ ${l} == submodule.*.url=* ]] || continue
236 251
237 l=${l#submodule.} 252 l=${l#submodule.}
238 local subname=${l%%.url=*} 253 local subname=${l%%.url=*}
254
255 # skip modules that have 'update = none', bug #487262.
256 local upd=$(echo "${data}" | git config -f /dev/fd/0 \
257 submodule."${subname}".update)
258 [[ ${upd} == none ]] && continue
239 259
240 submodules+=( 260 submodules+=(
241 "${subname}" 261 "${subname}"
242 "$(echo "${data}" | git config -f /dev/fd/0 \ 262 "$(echo "${data}" | git config -f /dev/fd/0 \
243 submodule."${subname}".url)" 263 submodule."${subname}".url)"
245 submodule."${subname}".path)" 265 submodule."${subname}".path)"
246 ) 266 )
247 done < <(echo "${data}" | git config -f /dev/fd/0 -l) 267 done < <(echo "${data}" | git config -f /dev/fd/0 -l)
248} 268}
249 269
270# @FUNCTION: _git-r3_smart_fetch
271# @USAGE: <git-fetch-args>...
272# @DESCRIPTION:
273# Try fetching without '--depth' and switch to '--depth 1' if that
274# will involve less objects fetched.
275_git-r3_smart_fetch() {
276 debug-print-function ${FUNCNAME} "$@"
277
278 local sed_regexp='.*Counting objects: \([0-9]*\), done\..*'
279
280 # start the main fetch
281 local cmd=( git fetch --progress "${@}" )
282 echo "${cmd[@]}" >&2
283
284 # we copy the output to the 'sed' pipe for parsing. whenever sed finds
285 # the process count, it quits quickly to avoid delays in writing it.
286 # then, we start a dummy 'cat' to keep the pipe alive
287
288 "${cmd[@]}" 2>&1 \
289 | tee >(
290 sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}" \
291 > "${T}"/git-r3_main.count
292 exec cat >/dev/null
293 ) &
294 local main_pid=${!}
295
296 # start the helper process
297 _git-r3_sub_fetch() {
298 # wait for main fetch to get object count; if the server doesn't
299 # output it, we won't even launch the parallel process
300 while [[ ! -s ${T}/git-r3_main.count ]]; do
301 sleep 0.25
302 done
303
304 # ok, let's see if parallel fetch gives us smaller count
305 # --dry-run will prevent it from writing to the local clone
306 # and sed should terminate git with SIGPIPE
307 local sub_count=$(git fetch --progress --dry-run --depth 1 "${@}" 2>&1 \
308 | sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}")
309 local main_count=$(<"${T}"/git-r3_main.count)
310
311 # let's be real sure that '--depth 1' will be good for us.
312 # note that we have purely objects counts, and '--depth 1'
313 # may involve much bigger objects
314 if [[ ${main_count} && ${main_count} -ge $(( sub_count * 3/2 )) ]]
315 then
316 # signal that we want shallow fetch instead,
317 # and terminate the non-shallow fetch process
318 touch "${T}"/git-r3_want_shallow || die
319 kill ${main_pid} &>/dev/null
320 exit 0
321 fi
322
323 exit 1
324 }
325 _git-r3_sub_fetch "${@}" &
326 local sub_pid=${!}
327
328 # wait for main process to terminate, either of its own
329 # or by signal from subprocess
330 wait ${main_pid}
331 local main_ret=${?}
332
333 # wait for subprocess to terminate, killing it if necessary.
334 # if main fetch finished before it, there's no point in keeping
335 # it alive. if main fetch was killed by it, it's done anyway
336 kill ${sub_pid} &>/dev/null
337 wait ${sub_pid}
338
339 # now see if subprocess wanted to tell us something...
340 if [[ -f ${T}/git-r3_want_shallow ]]; then
341 rm "${T}"/git-r3_want_shallow || die
342
343 # if fetch finished already (wasn't killed), ignore it
344 [[ ${main_ret} -eq 0 ]] && return 0
345
346 # otherwise, restart as shallow fetch
347 einfo "Restarting fetch using --depth 1 to save bandwidth ..."
348 local cmd=( git fetch --progress --depth 1 "${@}" )
349 echo "${cmd[@]}" >&2
350 "${cmd[@]}"
351 main_ret=${?}
352 fi
353
354 return ${main_ret}
355}
356
250# @FUNCTION: git-r3_fetch 357# @FUNCTION: git-r3_fetch
251# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]] 358# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]]
252# @DESCRIPTION: 359# @DESCRIPTION:
253# Fetch new commits to the local clone of repository. 360# Fetch new commits to the local clone of repository.
254# 361#
276# If the repository contains submodules, they will be fetched 383# If the repository contains submodules, they will be fetched
277# recursively. 384# recursively.
278git-r3_fetch() { 385git-r3_fetch() {
279 debug-print-function ${FUNCNAME} "$@" 386 debug-print-function ${FUNCNAME} "$@"
280 387
388 local repos
389 if [[ ${1} ]]; then
390 repos=( ${1} )
391 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
392 repos=( "${EGIT_REPO_URI[@]}" )
393 else
281 local repos=( ${1:-${EGIT_REPO_URI}} ) 394 repos=( ${EGIT_REPO_URI} )
395 fi
396
282 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} 397 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
283 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} 398 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
284 local local_id=${3:-${CATEGORY}/${PN}/${SLOT}} 399 local local_id=${3:-${CATEGORY}/${PN}/${SLOT}}
285 local local_ref=refs/heads/${local_id}/__main__ 400 local local_ref=refs/heads/${local_id}/__main__
286 401
287 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" 402 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
288 403
289 local -x GIT_DIR 404 local -x GIT_DIR
290 _git-r3_set_gitdir ${repos[0]} 405 _git-r3_set_gitdir "${repos[0]}"
291 406
292 # try to fetch from the remote 407 # try to fetch from the remote
293 local r success 408 local r success
294 for r in ${repos[@]}; do 409 for r in "${repos[@]}"; do
295 einfo "Fetching ${remote_ref} from ${r} ..." 410 einfo "Fetching ${remote_ref} from ${r} ..."
296 411
297 local is_branch lookup_ref 412 local is_branch lookup_ref
298 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] 413 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
299 then 414 then
309 # and not a commit id. if it succeeds, we can pass ${remote_ref} 424 # and not a commit id. if it succeeds, we can pass ${remote_ref}
310 # to 'fetch'. otherwise, we will just fetch everything 425 # to 'fetch'. otherwise, we will just fetch everything
311 426
312 # split on whitespace 427 # split on whitespace
313 local ref=( 428 local ref=(
314 $(git ls-remote "${r}" "${lookup_ref}") 429 $(git ls-remote "${r}" "${lookup_ref}" || echo __FAIL__)
315 ) 430 )
316 431
432 # normally, ref[0] is a hash, so we can do magic strings here
433 [[ ${ref[0]} == __FAIL__ ]] && continue
434
435 local nonshallow=${EGIT_NONSHALLOW}
317 local ref_param=() 436 local ref_param=()
318 if [[ ! ${ref[0]} ]]; then 437 if [[ ! ${ref[0]} ]]; then
319 local EGIT_NONSHALLOW=1 438 nonshallow=1
320 fi 439 fi
321 440
322 # 1. if we need a non-shallow clone and we have a shallow one, 441 # 1. if we need a non-shallow clone and we have a shallow one,
323 # we need to unshallow it explicitly. 442 # we need to unshallow it explicitly.
324 # 2. if we want a shallow clone, we just pass '--depth 1' 443 # 2. if we want a shallow clone, we just pass '--depth 1'
325 # to the first fetch in the repo. passing '--depth' 444 # to the first fetch in the repo. passing '--depth'
326 # to further requests usually results in more data being 445 # to further requests usually results in more data being
327 # downloaded than without it. 446 # downloaded than without it.
328 # 3. in any other case, we just do plain 'git fetch' and let 447 # 3. if we update a shallow clone, we try without '--depth'
329 # git to do its best (on top of shallow or non-shallow repo). 448 # first since that usually transfers less data. however,
449 # we use git-r3_smart_fetch that can switch into '--depth 1'
450 # if that looks beneficial.
330 451
331 if [[ ${EGIT_NONSHALLOW} ]]; then 452 local fetch_command=( git fetch )
453 if [[ ${nonshallow} ]]; then
332 if [[ -f ${GIT_DIR}/shallow ]]; then 454 if [[ -f ${GIT_DIR}/shallow ]]; then
333 ref_param+=( --unshallow ) 455 ref_param+=( --unshallow )
334 fi 456 fi
457 # fetch all branches
458 ref_param+=( "refs/heads/*:refs/remotes/origin/*" )
335 else 459 else
336 # 'git show-ref --heads' returns 1 when there are no branches 460 # 'git show-ref --heads' returns 1 when there are no branches
337 if ! git show-ref --heads -q; then 461 if ! git show-ref --heads -q; then
338 ref_param+=( --depth 1 ) 462 ref_param+=( --depth 1 )
463 else
464 fetch_command=( _git-r3_smart_fetch )
339 fi 465 fi
340 fi 466 fi
341 467
342 # now, another important thing. we may only fetch a remote 468 # now, another important thing. we may only fetch a remote
343 # branch directly to a local branch. Otherwise, we need to fetch 469 # branch directly to a local branch. Otherwise, we need to fetch
352 fi 478 fi
353 479
354 # if ${remote_ref} is branch or tag, ${ref[@]} will contain 480 # if ${remote_ref} is branch or tag, ${ref[@]} will contain
355 # the respective commit id. otherwise, it will be an empty 481 # the respective commit id. otherwise, it will be an empty
356 # array, so the following won't evaluate to a parameter. 482 # array, so the following won't evaluate to a parameter.
357 set -- git fetch --no-tags "${r}" "${ref_param[@]}" 483 set -- "${fetch_command[@]}" --no-tags "${r}" "${ref_param[@]}"
358 echo "${@}" >&2 484 echo "${@}" >&2
359 if "${@}"; then 485 if "${@}"; then
360 if [[ ! ${is_branch} ]]; then 486 if [[ ! ${is_branch} ]]; then
361 set -- git branch -f "${local_id}/__main__" \ 487 set -- git branch -f "${local_id}/__main__" \
362 "${ref[0]:-${remote_ref}}" 488 "${ref[0]:-${remote_ref}}"
416# the repository state into the environment. If the repository contains 542# the repository state into the environment. If the repository contains
417# submodules, they will be checked out recursively. 543# submodules, they will be checked out recursively.
418git-r3_checkout() { 544git-r3_checkout() {
419 debug-print-function ${FUNCNAME} "$@" 545 debug-print-function ${FUNCNAME} "$@"
420 546
547 local repos
548 if [[ ${1} ]]; then
549 repos=( ${1} )
550 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
551 repos=( "${EGIT_REPO_URI[@]}" )
552 else
421 local repos=( ${1:-${EGIT_REPO_URI}} ) 553 repos=( ${EGIT_REPO_URI} )
554 fi
555
422 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}} 556 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
423 local local_id=${3:-${CATEGORY}/${PN}/${SLOT}} 557 local local_id=${3:-${CATEGORY}/${PN}/${SLOT}}
424 558
425 local -x GIT_DIR GIT_WORK_TREE 559 local -x GIT_DIR GIT_WORK_TREE
426 _git-r3_set_gitdir ${repos[0]} 560 _git-r3_set_gitdir "${repos[0]}"
427 GIT_WORK_TREE=${out_dir} 561 GIT_WORK_TREE=${out_dir}
428 mkdir -p "${GIT_WORK_TREE}" 562 mkdir -p "${GIT_WORK_TREE}"
429 563
430 einfo "Checking out ${repos[0]} to ${out_dir} ..." 564 einfo "Checking out ${repos[0]} to ${out_dir} ..."
431 565
513# On success, the function returns 0 and writes hexadecimal commit SHA1 647# On success, the function returns 0 and writes hexadecimal commit SHA1
514# to stdout. On failure, the function returns 1. 648# to stdout. On failure, the function returns 1.
515git-r3_peek_remote_ref() { 649git-r3_peek_remote_ref() {
516 debug-print-function ${FUNCNAME} "$@" 650 debug-print-function ${FUNCNAME} "$@"
517 651
652 local repos
653 if [[ ${1} ]]; then
654 repos=( ${1} )
655 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
656 repos=( "${EGIT_REPO_URI[@]}" )
657 else
518 local repos=( ${1:-${EGIT_REPO_URI}} ) 658 repos=( ${EGIT_REPO_URI} )
659 fi
660
519 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} 661 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
520 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} 662 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
521 663
522 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" 664 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
523 665
524 local r success 666 local r success
525 for r in ${repos[@]}; do 667 for r in "${repos[@]}"; do
526 einfo "Peeking ${remote_ref} on ${r} ..." >&2 668 einfo "Peeking ${remote_ref} on ${r} ..." >&2
527 669
528 local is_branch lookup_ref 670 local is_branch lookup_ref
529 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] 671 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
530 then 672 then

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.15

  ViewVC Help
Powered by ViewVC 1.1.20