/[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.23
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.4 2013/09/13 15:04:36 mgorny Exp $ 3# $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.23 2013/11/15 23:03:23 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
197 GIT_DIR=${EGIT3_STORE_DIR}/${repo_name} 210 GIT_DIR=${EGIT3_STORE_DIR}/${repo_name}
198 211
199 if [[ ! -d ${EGIT3_STORE_DIR} ]]; then 212 if [[ ! -d ${EGIT3_STORE_DIR} ]]; then
200 ( 213 (
201 addwrite / 214 addwrite /
202 mkdir -m0755 -p "${EGIT3_STORE_DIR}" 215 mkdir -m0755 -p "${EGIT3_STORE_DIR}" || die
203 ) || die "Unable to create ${EGIT3_STORE_DIR}" 216 ) || die "Unable to create ${EGIT3_STORE_DIR}"
204 fi 217 fi
205 218
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>
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=*}
239 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
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 || die)"
244 "$(echo "${data}" | git config -f /dev/fd/0 \ 264 "$(echo "${data}" | git config -f /dev/fd/0 \
245 submodule."${subname}".path)" 265 submodule."${subname}".path || die)"
246 ) 266 )
247 done < <(echo "${data}" | git config -f /dev/fd/0 -l) 267 done < <(echo "${data}" | git config -f /dev/fd/0 -l || die)
248} 268}
249 269
250# @FUNCTION: _git-r3_smart_fetch 270# @FUNCTION: _git-r3_smart_fetch
251# @USAGE: <git-fetch-args>... 271# @USAGE: <git-fetch-args>...
252# @DESCRIPTION: 272# @DESCRIPTION:
332 fi 352 fi
333 353
334 return ${main_ret} 354 return ${main_ret}
335} 355}
336 356
357# @FUNCTION: _git-r3_is_local_repo
358# @USAGE: <repo-uri>
359# @INTERNAL
360# @DESCRIPTION:
361# Determine whether the given URI specifies a local (on-disk)
362# repository.
363_git-r3_is_local_repo() {
364 debug-print-function ${FUNCNAME} "$@"
365
366 local uri=${1}
367
368 [[ ${uri} == file://* || ${uri} == /* ]]
369}
370
337# @FUNCTION: git-r3_fetch 371# @FUNCTION: git-r3_fetch
338# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]] 372# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]]
339# @DESCRIPTION: 373# @DESCRIPTION:
340# Fetch new commits to the local clone of repository. 374# Fetch new commits to the local clone of repository.
341# 375#
352# is set to a non-null value. 386# is set to a non-null value.
353# 387#
354# <local-id> specifies the local branch identifier that will be used to 388# <local-id> specifies the local branch identifier that will be used to
355# locally store the fetch result. It should be unique to multiple 389# locally store the fetch result. It should be unique to multiple
356# fetches within the repository that can be performed at the same time 390# fetches within the repository that can be performed at the same time
357# (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT}. 391# (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT%/*}.
358# This default should be fine unless you are fetching multiple trees 392# This default should be fine unless you are fetching multiple trees
359# from the same repository in the same ebuild. 393# from the same repository in the same ebuild.
360# 394#
361# The fetch operation will affect the EGIT_STORE only. It will not touch 395# The fetch operation will affect the EGIT_STORE only. It will not touch
362# the working copy, nor export any environment variables. 396# the working copy, nor export any environment variables.
363# If the repository contains submodules, they will be fetched 397# If the repository contains submodules, they will be fetched
364# recursively. 398# recursively.
365git-r3_fetch() { 399git-r3_fetch() {
366 debug-print-function ${FUNCNAME} "$@" 400 debug-print-function ${FUNCNAME} "$@"
367 401
402 [[ ${EVCS_OFFLINE} ]] && return
403
404 local repos
405 if [[ ${1} ]]; then
406 repos=( ${1} )
407 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
408 repos=( "${EGIT_REPO_URI[@]}" )
409 else
368 local repos=( ${1:-${EGIT_REPO_URI}} ) 410 repos=( ${EGIT_REPO_URI} )
411 fi
412
369 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} 413 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
370 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} 414 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
371 local local_id=${3:-${CATEGORY}/${PN}/${SLOT}} 415 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
372 local local_ref=refs/heads/${local_id}/__main__ 416 local local_ref=refs/heads/${local_id}/__main__
373 417
374 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" 418 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
375 419
376 local -x GIT_DIR 420 local -x GIT_DIR
377 _git-r3_set_gitdir ${repos[0]} 421 _git-r3_set_gitdir "${repos[0]}"
378 422
379 # try to fetch from the remote 423 # try to fetch from the remote
380 local r success 424 local r success
381 for r in ${repos[@]}; do 425 for r in "${repos[@]}"; do
382 einfo "Fetching ${remote_ref} from ${r} ..." 426 einfo "Fetching ${remote_ref} from ${r} ..."
383 427
384 local is_branch lookup_ref 428 local is_branch lookup_ref
385 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] 429 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
386 then 430 then
396 # and not a commit id. if it succeeds, we can pass ${remote_ref} 440 # and not a commit id. if it succeeds, we can pass ${remote_ref}
397 # to 'fetch'. otherwise, we will just fetch everything 441 # to 'fetch'. otherwise, we will just fetch everything
398 442
399 # split on whitespace 443 # split on whitespace
400 local ref=( 444 local ref=(
401 $(git ls-remote "${r}" "${lookup_ref}") 445 $(git ls-remote "${r}" "${lookup_ref}" || echo __FAIL__)
402 ) 446 )
447
448 # normally, ref[0] is a hash, so we can do magic strings here
449 [[ ${ref[0]} == __FAIL__ ]] && continue
403 450
404 local nonshallow=${EGIT_NONSHALLOW} 451 local nonshallow=${EGIT_NONSHALLOW}
405 local ref_param=() 452 local ref_param=()
406 if [[ ! ${ref[0]} ]]; then 453 if [[ ! ${ref[0]} ]]; then
407 nonshallow=1 454 nonshallow=1
408 fi 455 fi
456
457 # trying to do a shallow clone of a local repo makes git try to
458 # write to the repo. we don't want that to happen.
459 _git-r3_is_local_repo "${r}" && nonshallow=1
409 460
410 # 1. if we need a non-shallow clone and we have a shallow one, 461 # 1. if we need a non-shallow clone and we have a shallow one,
411 # we need to unshallow it explicitly. 462 # we need to unshallow it explicitly.
412 # 2. if we want a shallow clone, we just pass '--depth 1' 463 # 2. if we want a shallow clone, we just pass '--depth 1'
413 # to the first fetch in the repo. passing '--depth' 464 # to the first fetch in the repo. passing '--depth'
421 local fetch_command=( git fetch ) 472 local fetch_command=( git fetch )
422 if [[ ${nonshallow} ]]; then 473 if [[ ${nonshallow} ]]; then
423 if [[ -f ${GIT_DIR}/shallow ]]; then 474 if [[ -f ${GIT_DIR}/shallow ]]; then
424 ref_param+=( --unshallow ) 475 ref_param+=( --unshallow )
425 fi 476 fi
477 # fetch all branches
478 ref_param+=( "refs/heads/*:refs/remotes/origin/*" )
426 else 479 else
427 # 'git show-ref --heads' returns 1 when there are no branches 480 # 'git show-ref --heads' returns 1 when there are no branches
428 if ! git show-ref --heads -q; then 481 if ! git show-ref --heads -q; then
429 ref_param+=( --depth 1 ) 482 ref_param+=( --depth 1 )
430 else 483 else
478 local commit=$(git rev-parse "${local_ref}:${path}") 531 local commit=$(git rev-parse "${local_ref}:${path}")
479 532
480 if [[ ! ${commit} ]]; then 533 if [[ ! ${commit} ]]; then
481 die "Unable to get commit id for submodule ${subname}" 534 die "Unable to get commit id for submodule ${subname}"
482 fi 535 fi
536 if [[ ${url} == ./* || ${url} == ../* ]]; then
537 local subrepos=( "${repos[@]/%//${url}}" )
538 else
539 local subrepos=( "${url}" )
540 fi
483 541
484 git-r3_fetch "${url}" "${commit}" "${local_id}/${subname}" 542 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}"
485 543
486 submodules=( "${submodules[@]:3}" ) # shift 544 submodules=( "${submodules[@]:3}" ) # shift
487 done 545 done
488 fi 546 fi
489} 547}
509# the repository state into the environment. If the repository contains 567# the repository state into the environment. If the repository contains
510# submodules, they will be checked out recursively. 568# submodules, they will be checked out recursively.
511git-r3_checkout() { 569git-r3_checkout() {
512 debug-print-function ${FUNCNAME} "$@" 570 debug-print-function ${FUNCNAME} "$@"
513 571
572 local repos
573 if [[ ${1} ]]; then
574 repos=( ${1} )
575 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
576 repos=( "${EGIT_REPO_URI[@]}" )
577 else
514 local repos=( ${1:-${EGIT_REPO_URI}} ) 578 repos=( ${EGIT_REPO_URI} )
579 fi
580
515 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}} 581 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
516 local local_id=${3:-${CATEGORY}/${PN}/${SLOT}} 582 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
517 583
518 local -x GIT_DIR GIT_WORK_TREE 584 local -x GIT_DIR GIT_WORK_TREE
519 _git-r3_set_gitdir ${repos[0]} 585 _git-r3_set_gitdir "${repos[0]}"
520 GIT_WORK_TREE=${out_dir} 586 GIT_WORK_TREE=${out_dir}
521 mkdir -p "${GIT_WORK_TREE}" 587 mkdir -p "${GIT_WORK_TREE}" || die
522 588
523 einfo "Checking out ${repos[0]} to ${out_dir} ..." 589 einfo "Checking out ${repos[0]} to ${out_dir} ..."
524 590
525 if ! git cat-file -e refs/heads/"${local_id}"/__main__ 591 if ! git cat-file -e refs/heads/"${local_id}"/__main__
526 then 592 then
529 else 595 else
530 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?" 596 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
531 fi 597 fi
532 fi 598 fi
533 599
600 # Note: this is a hack to avoid parallel checkout issues.
601 # I will try to handle it without locks when I have more time.
602 local lockfile=${GIT_DIR}/.git-r3_checkout_lock
603 local lockfile_l=${lockfile}.${BASHPID}
604 touch "${lockfile_l}" || die
605 until ln "${lockfile_l}" "${lockfile}" &>/dev/null; do
606 sleep 1
607 done
608 rm "${lockfile_l}" || die
609
534 set -- git checkout -f "${local_id}"/__main__ . 610 set -- git checkout -f "${local_id}"/__main__ .
535 echo "${@}" >&2 611 echo "${@}" >&2
612 "${@}"
613 local ret=${?}
614
615 # Remove the lock!
616 rm "${lockfile}" || die
617
536 "${@}" || die "git checkout ${local_id}/__main__ failed" 618 [[ ${ret} == 0 ]] || die "git checkout ${local_id}/__main__ failed"
537 619
538 # diff against previous revision (if any) 620 # diff against previous revision (if any)
539 local new_commit_id=$(git rev-parse --verify "${local_id}"/__main__) 621 local new_commit_id=$(git rev-parse --verify "${local_id}"/__main__)
540 local old_commit_id=$( 622 local old_commit_id=$(
541 git rev-parse --verify "${local_id}"/__old__ 2>/dev/null 623 git rev-parse --verify "${local_id}"/__old__ 2>/dev/null
570 while [[ ${submodules[@]} ]]; do 652 while [[ ${submodules[@]} ]]; do
571 local subname=${submodules[0]} 653 local subname=${submodules[0]}
572 local url=${submodules[1]} 654 local url=${submodules[1]}
573 local path=${submodules[2]} 655 local path=${submodules[2]}
574 656
657 if [[ ${url} == ./* || ${url} == ../* ]]; then
658 url=${repos[0]%%/}/${url}
659 fi
660
575 git-r3_checkout "${url}" "${GIT_WORK_TREE}/${path}" \ 661 git-r3_checkout "${url}" "${GIT_WORK_TREE}/${path}" \
576 "${local_id}/${subname}" 662 "${local_id}/${subname}"
577 663
578 submodules=( "${submodules[@]:3}" ) # shift 664 submodules=( "${submodules[@]:3}" ) # shift
579 done 665 done
580 fi 666 fi
581 667
582 # keep this *after* submodules 668 # keep this *after* submodules
583 export EGIT_DIR=${GIT_DIR} 669 export EGIT_DIR=${GIT_DIR}
584 export EGIT_VERSION=${new_commit_id} 670 export EGIT_VERSION=${new_commit_id}
671
672 # create a fake '.git' directory to satisfy 'git rev-parse HEAD'
673 GIT_DIR=${GIT_WORK_TREE}/.git
674 git init || die
675 echo "${EGIT_VERSION}" > "${GIT_WORK_TREE}"/.git/HEAD || die
585} 676}
586 677
587# @FUNCTION: git-r3_peek_remote_ref 678# @FUNCTION: git-r3_peek_remote_ref
588# @USAGE: [<repo-uri> [<remote-ref>]] 679# @USAGE: [<repo-uri> [<remote-ref>]]
589# @DESCRIPTION: 680# @DESCRIPTION:
606# On success, the function returns 0 and writes hexadecimal commit SHA1 697# On success, the function returns 0 and writes hexadecimal commit SHA1
607# to stdout. On failure, the function returns 1. 698# to stdout. On failure, the function returns 1.
608git-r3_peek_remote_ref() { 699git-r3_peek_remote_ref() {
609 debug-print-function ${FUNCNAME} "$@" 700 debug-print-function ${FUNCNAME} "$@"
610 701
702 local repos
703 if [[ ${1} ]]; then
704 repos=( ${1} )
705 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
706 repos=( "${EGIT_REPO_URI[@]}" )
707 else
611 local repos=( ${1:-${EGIT_REPO_URI}} ) 708 repos=( ${EGIT_REPO_URI} )
709 fi
710
612 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} 711 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
613 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} 712 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
614 713
615 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" 714 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
616 715
617 local r success 716 local r success
618 for r in ${repos[@]}; do 717 for r in "${repos[@]}"; do
619 einfo "Peeking ${remote_ref} on ${r} ..." >&2 718 einfo "Peeking ${remote_ref} on ${r} ..." >&2
620 719
621 local is_branch lookup_ref 720 local is_branch lookup_ref
622 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] 721 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
623 then 722 then
644} 743}
645 744
646git-r3_src_fetch() { 745git-r3_src_fetch() {
647 debug-print-function ${FUNCNAME} "$@" 746 debug-print-function ${FUNCNAME} "$@"
648 747
649 [[ ${EVCS_OFFLINE} ]] && return
650
651 if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then 748 if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then
652 ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider" 749 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" 750 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" 751 ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones"
655 ewarn "when git-2 eclass becomes deprecated." 752 ewarn "when git-2 eclass becomes deprecated."

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

  ViewVC Help
Powered by ViewVC 1.1.20