/[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.24 Revision 1.44
1# Copyright 1999-2014 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.24 2014/02/23 22:05:55 mgorny Exp $ 3# $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.44 2014/06/20 11:40:28 mgorny Exp $
4 4
5# @ECLASS: git-r3.eclass 5# @ECLASS: git-r3.eclass
6# @MAINTAINER: 6# @MAINTAINER:
7# Michał Górny <mgorny@gentoo.org> 7# Michał Górny <mgorny@gentoo.org>
8# @BLURB: Eclass for fetching and unpacking git repositories. 8# @BLURB: Eclass for fetching and unpacking git repositories.
27EXPORT_FUNCTIONS src_unpack 27EXPORT_FUNCTIONS src_unpack
28 28
29if [[ ! ${_GIT_R3} ]]; then 29if [[ ! ${_GIT_R3} ]]; then
30 30
31if [[ ! ${_INHERITED_BY_GIT_2} ]]; then 31if [[ ! ${_INHERITED_BY_GIT_2} ]]; then
32 DEPEND="dev-vcs/git" 32 DEPEND=">=dev-vcs/git-1.8.2.1"
33fi 33fi
34 34
35# @ECLASS-VARIABLE: EGIT_CLONE_TYPE
36# @DESCRIPTION:
37# Type of clone that should be used against the remote repository.
38# This can be either of: 'mirror', 'single', 'shallow'.
39#
40# This is intended to be set by user in make.conf. Ebuilds are supposed
41# to set EGIT_MIN_CLONE_TYPE if necessary instead.
42#
43# The 'mirror' type clones all remote branches and tags with complete
44# history and all notes. EGIT_COMMIT can specify any commit hash.
45# Upstream-removed branches and tags are purged from the local clone
46# while fetching. This mode is suitable for cloning the local copy
47# for development or hosting a local git mirror. However, clones
48# of repositories with large diverged branches may quickly grow large.
49#
50# The 'single+tags' type clones the requested branch and all tags
51# in the repository. All notes are fetched as well. EGIT_COMMIT
52# can safely specify hashes throughout the current branch and all tags.
53# No purging of old references is done (if you often switch branches,
54# you may need to remove stale branches yourself). This mode is intended
55# mostly for use with broken git servers such as Google Code that fail
56# to fetch tags along with the branch in 'single' mode.
57#
58# The 'single' type clones only the requested branch or tag. Tags
59# referencing commits throughout the branch history are fetched as well,
60# and all notes. EGIT_COMMIT can safely specify only hashes
61# in the current branch. No purging of old references is done (if you
62# often switch branches, you may need to remove stale branches
63# yourself). This mode is suitable for general use.
64#
65# The 'shallow' type clones only the newest commit on requested branch
66# or tag. EGIT_COMMIT can only specify tags, and since the history is
67# unavailable calls like 'git describe' will not reference prior tags.
68# No purging of old references is done. This mode is intended mostly for
69# embedded systems with limited disk space.
70: ${EGIT_CLONE_TYPE:=single}
71
72# @ECLASS-VARIABLE: EGIT_MIN_CLONE_TYPE
73# @DESCRIPTION:
74# 'Minimum' clone type supported by the ebuild. Takes same values
75# as EGIT_CLONE_TYPE. When user sets a type that's 'lower' (that is,
76# later on the list) than EGIT_MIN_CLONE_TYPE, the eclass uses
77# EGIT_MIN_CLONE_TYPE instead.
78#
79# This variable is intended to be used by ebuilds only. Users are
80# supposed to set EGIT_CLONE_TYPE instead.
81#
82# A common case is to use 'single' whenever the build system requires
83# access to full branch history, or 'single+tags' when Google Code
84# or a similar remote is used that does not support shallow clones
85# and fetching tags along with commits. Please use sparingly, and to fix
86# fatal errors rather than 'non-pretty versions'.
87: ${EGIT_MIN_CLONE_TYPE:=shallow}
88
35# @ECLASS-VARIABLE: EGIT3_STORE_DIR 89# @ECLASS-VARIABLE: EGIT3_STORE_DIR
36# @DESCRIPTION: 90# @DESCRIPTION:
37# Storage directory for git sources. 91# Storage directory for git sources.
38# 92#
93# This is intended to be set by user in make.conf. Ebuilds must not set
94# it.
95#
39# EGIT3_STORE_DIR=${DISTDIR}/git3-src 96# EGIT3_STORE_DIR=${DISTDIR}/git3-src
97
98# @ECLASS-VARIABLE: EGIT_MIRROR_URI
99# @DEFAULT_UNSET
100# @DESCRIPTION:
101# 'Top' URI to a local git mirror. If specified, the eclass will try
102# to fetch from the local mirror instead of using the remote repository.
103#
104# The mirror needs to follow EGIT3_STORE_DIR structure. The directory
105# created by eclass can be used for that purpose.
106#
107# Example:
108# @CODE
109# EGIT_MIRROR_URI="git://mirror.lan/"
110# @CODE
40 111
41# @ECLASS-VARIABLE: EGIT_REPO_URI 112# @ECLASS-VARIABLE: EGIT_REPO_URI
42# @REQUIRED 113# @REQUIRED
43# @DESCRIPTION: 114# @DESCRIPTION:
44# URIs to the repository, e.g. git://foo, https://foo. If multiple URIs 115# URIs to the repository, e.g. git://foo, https://foo. If multiple URIs
87# @DESCRIPTION: 158# @DESCRIPTION:
88# Set the eclass variables as necessary for operation. This can involve 159# Set the eclass variables as necessary for operation. This can involve
89# setting EGIT_* to defaults or ${PN}_LIVE_* variables. 160# setting EGIT_* to defaults or ${PN}_LIVE_* variables.
90_git-r3_env_setup() { 161_git-r3_env_setup() {
91 debug-print-function ${FUNCNAME} "$@" 162 debug-print-function ${FUNCNAME} "$@"
163
164 # check the clone type
165 case "${EGIT_CLONE_TYPE}" in
166 mirror|single+tags|single|shallow)
167 ;;
168 *)
169 die "Invalid EGIT_CLONE_TYPE=${EGIT_CLONE_TYPE}"
170 esac
171 case "${EGIT_MIN_CLONE_TYPE}" in
172 shallow)
173 ;;
174 single)
175 if [[ ${EGIT_CLONE_TYPE} == shallow ]]; then
176 einfo "git-r3: ebuild needs to be cloned in 'single' mode, adjusting"
177 EGIT_CLONE_TYPE=single
178 fi
179 ;;
180 single+tags)
181 if [[ ${EGIT_CLONE_TYPE} == shallow || ${EGIT_CLONE_TYPE} == single ]]; then
182 einfo "git-r3: ebuild needs to be cloned in 'single+tags' mode, adjusting"
183 EGIT_CLONE_TYPE=single+tags
184 fi
185 ;;
186 mirror)
187 if [[ ${EGIT_CLONE_TYPE} != mirror ]]; then
188 einfo "git-r3: ebuild needs to be cloned in 'mirror' mode, adjusting"
189 EGIT_CLONE_TYPE=mirror
190 fi
191 ;;
192 *)
193 die "Invalid EGIT_MIN_CLONE_TYPE=${EGIT_MIN_CLONE_TYPE}"
194 esac
92 195
93 local esc_pn livevar 196 local esc_pn livevar
94 esc_pn=${PN//[-+]/_} 197 esc_pn=${PN//[-+]/_}
95 198
96 livevar=${esc_pn}_LIVE_REPO 199 livevar=${esc_pn}_LIVE_REPO
202 mkdir -m0755 -p "${EGIT3_STORE_DIR}" || die 305 mkdir -m0755 -p "${EGIT3_STORE_DIR}" || die
203 ) || die "Unable to create ${EGIT3_STORE_DIR}" 306 ) || die "Unable to create ${EGIT3_STORE_DIR}"
204 fi 307 fi
205 308
206 addwrite "${EGIT3_STORE_DIR}" 309 addwrite "${EGIT3_STORE_DIR}"
207 if [[ -e ${GIT_DIR}/shallow ]]; then
208 einfo "${GIT_DIR} was a shallow clone, recreating..."
209 rm -r "${GIT_DIR}" || die
210 fi
211 if [[ ! -d ${GIT_DIR} ]]; then 310 if [[ ! -d ${GIT_DIR} ]]; then
212 mkdir "${GIT_DIR}" || die 311 mkdir "${GIT_DIR}" || die
213 git init --bare || die 312 git init --bare || die
214 fi 313 fi
215} 314}
251 submodule."${subname}".path || die)" 350 submodule."${subname}".path || die)"
252 ) 351 )
253 done < <(echo "${data}" | git config -f /dev/fd/0 -l || die) 352 done < <(echo "${data}" | git config -f /dev/fd/0 -l || die)
254} 353}
255 354
355# @FUNCTION: _git-r3_set_subrepos
356# @USAGE: <submodule-uri> <parent-repo-uri>...
357# @INTERNAL
358# @DESCRIPTION:
359# Create 'subrepos' array containing absolute (canonical) submodule URIs
360# for the given <submodule-uri>. If the URI is relative, URIs will be
361# constructed using all <parent-repo-uri>s. Otherwise, this single URI
362# will be placed in the array.
363_git-r3_set_subrepos() {
364 debug-print-function ${FUNCNAME} "$@"
365
366 local suburl=${1}
367 subrepos=( "${@:2}" )
368
369 if [[ ${suburl} == ./* || ${suburl} == ../* ]]; then
370 # drop all possible trailing slashes for consistency
371 subrepos=( "${subrepos[@]%%/}" )
372
373 while true; do
374 if [[ ${suburl} == ./* ]]; then
375 suburl=${suburl:2}
376 elif [[ ${suburl} == ../* ]]; then
377 suburl=${suburl:3}
378
379 # XXX: correctness checking
380
381 # drop the last path component
382 subrepos=( "${subrepos[@]%/*}" )
383 # and then the trailing slashes, again
384 subrepos=( "${subrepos[@]%%/}" )
385 else
386 break
387 fi
388 done
389
390 # append the preprocessed path to the preprocessed URIs
391 subrepos=( "${subrepos[@]/%//${suburl}}")
392 else
393 subrepos=( "${suburl}" )
394 fi
395}
396
397
256# @FUNCTION: _git-r3_is_local_repo 398# @FUNCTION: _git-r3_is_local_repo
257# @USAGE: <repo-uri> 399# @USAGE: <repo-uri>
258# @INTERNAL 400# @INTERNAL
259# @DESCRIPTION: 401# @DESCRIPTION:
260# Determine whether the given URI specifies a local (on-disk) 402# Determine whether the given URI specifies a local (on-disk)
263 debug-print-function ${FUNCNAME} "$@" 405 debug-print-function ${FUNCNAME} "$@"
264 406
265 local uri=${1} 407 local uri=${1}
266 408
267 [[ ${uri} == file://* || ${uri} == /* ]] 409 [[ ${uri} == file://* || ${uri} == /* ]]
410}
411
412# @FUNCTION: _git-r3_find_head
413# @USAGE: <head-ref>
414# @INTERNAL
415# @DESCRIPTION:
416# Given a ref to which remote HEAD was fetched, try to find
417# a branch matching the commit. Expects 'git show-ref'
418# or 'git ls-remote' output on stdin.
419_git-r3_find_head() {
420 debug-print-function ${FUNCNAME} "$@"
421
422 local head_ref=${1}
423 local head_hash=$(git rev-parse --verify "${1}" || die)
424 local matching_ref
425
426 # TODO: some transports support peeking at symbolic remote refs
427 # find a way to use that rather than guessing
428
429 # (based on guess_remote_head() in git-1.9.0/remote.c)
430 local h ref
431 while read h ref; do
432 # look for matching head
433 if [[ ${h} == ${head_hash} ]]; then
434 # either take the first matching ref, or master if it is there
435 if [[ ! ${matching_ref} || ${ref} == refs/heads/master ]]; then
436 matching_ref=${ref}
437 fi
438 fi
439 done
440
441 if [[ ! ${matching_ref} ]]; then
442 die "Unable to find a matching branch for remote HEAD (${head_hash})"
443 fi
444
445 echo "${matching_ref}"
268} 446}
269 447
270# @FUNCTION: git-r3_fetch 448# @FUNCTION: git-r3_fetch
271# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]] 449# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]]
272# @DESCRIPTION: 450# @DESCRIPTION:
317 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" 495 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
318 496
319 local -x GIT_DIR 497 local -x GIT_DIR
320 _git-r3_set_gitdir "${repos[0]}" 498 _git-r3_set_gitdir "${repos[0]}"
321 499
500 # prepend the local mirror if applicable
501 if [[ ${EGIT_MIRROR_URI} ]]; then
502 repos=(
503 "${EGIT_MIRROR_URI%/}/${GIT_DIR##*/}"
504 "${repos[@]}"
505 )
506 fi
507
322 # try to fetch from the remote 508 # try to fetch from the remote
323 local r success 509 local r success
324 for r in "${repos[@]}"; do 510 for r in "${repos[@]}"; do
325 einfo "Fetching ${r} ..." 511 einfo "Fetching ${r} ..."
326 512
513 local fetch_command=( git fetch "${r}" )
514 local clone_type=${EGIT_CLONE_TYPE}
515
516 if [[ ${r} == https://* ]] && ! has_version 'dev-vcs/git[curl]'; then
517 eerror "git-r3: fetching from https:// requested. In order to support https,"
518 eerror "dev-vcs/git needs to be built with USE=curl. Example solution:"
519 eerror
520 eerror " echo dev-vcs/git curl >> /etc/portage/package.use"
521 eerror " emerge -1v dev-vcs/git"
522 die "dev-vcs/git built with USE=curl required."
523 fi
524
525 if [[ ${r} == https://code.google.com/* ]]; then
526 # Google Code has special magic on top of git that:
527 # 1) can't handle shallow clones at all,
528 # 2) fetches duplicately when tags are pulled in with branch
529 # so automatically switch to single+tags mode.
530 if [[ ${clone_type} == shallow ]]; then
531 einfo " Google Code does not support shallow clones"
532 einfo " using EGIT_CLONE_TYPE=single+tags"
533 clone_type=single+tags
534 elif [[ ${clone_type} == single ]]; then
535 einfo " git-r3: Google Code does not send tags properly in 'single' mode"
536 einfo " using EGIT_CLONE_TYPE=single+tags"
537 clone_type=single+tags
538 fi
539 fi
540
541 if [[ ${clone_type} == mirror ]]; then
327 local fetch_command=( 542 fetch_command+=(
328 git fetch --prune "${r}" 543 --prune
329 # mirror the remote branches as local branches 544 # mirror the remote branches as local branches
330 "refs/heads/*:refs/heads/*" 545 "+refs/heads/*:refs/heads/*"
331 # pull tags explicitly in order to prune them properly 546 # pull tags explicitly in order to prune them properly
332 "refs/tags/*:refs/tags/*" 547 "+refs/tags/*:refs/tags/*"
548 # notes in case something needs them
549 "+refs/notes/*:refs/notes/*"
550 # and HEAD in case we need the default branch
551 # (we keep it in refs/git-r3 since otherwise --prune interferes)
552 "+HEAD:refs/git-r3/HEAD"
333 ) 553 )
554 else # single or shallow
555 local fetch_l fetch_r
556
557 if [[ ${remote_ref} == HEAD ]]; then
558 # HEAD
559 fetch_l=HEAD
560 elif [[ ${remote_ref} == refs/heads/* ]]; then
561 # regular branch
562 fetch_l=${remote_ref}
563 else
564 # tag or commit...
565 # let ls-remote figure it out
566 local tagref=$(git ls-remote "${r}" "refs/tags/${remote_ref}")
567
568 # if it was a tag, ls-remote obtained a hash
569 if [[ ${tagref} ]]; then
570 # tag
571 fetch_l=refs/tags/${remote_ref}
572 else
573 # commit
574 # so we need to fetch the branch
575 if [[ ${branch} ]]; then
576 fetch_l=${branch}
577 else
578 fetch_l=HEAD
579 fi
580
581 # fetching by commit in shallow mode? can't do.
582 if [[ ${clone_type} == shallow ]]; then
583 clone_type=single
584 fi
585 fi
586 fi
587
588 if [[ ${fetch_l} == HEAD ]]; then
589 fetch_r=refs/git-r3/HEAD
590 else
591 fetch_r=${fetch_l}
592 fi
593
594 fetch_command+=(
595 "+${fetch_l}:${fetch_r}"
596 )
597
598 if [[ ${clone_type} == single+tags ]]; then
599 fetch_command+=(
600 # pull tags explicitly as requested
601 "+refs/tags/*:refs/tags/*"
602 )
603 fi
604 fi
605
606 if [[ ${clone_type} == shallow ]]; then
607 if _git-r3_is_local_repo; then
608 # '--depth 1' causes sandbox violations with local repos
609 # bug #491260
610 clone_type=single
611 elif [[ ! $(git rev-parse --quiet --verify "${fetch_r}") ]]
612 then
613 # use '--depth 1' when fetching a new branch
614 fetch_command+=( --depth 1 )
615 fi
616 else # non-shallow mode
617 if [[ -f ${GIT_DIR}/shallow ]]; then
618 fetch_command+=( --unshallow )
619 fi
620 fi
334 621
335 set -- "${fetch_command[@]}" 622 set -- "${fetch_command[@]}"
336 echo "${@}" >&2 623 echo "${@}" >&2
337 if "${@}"; then 624 if "${@}"; then
625 if [[ ${clone_type} == mirror ]]; then
626 # find remote HEAD and update our HEAD properly
627 git symbolic-ref HEAD \
628 "$(_git-r3_find_head refs/git-r3/HEAD \
629 < <(git show-ref --heads || die))" \
630 || die "Unable to update HEAD"
631 else # single or shallow
632 if [[ ${fetch_l} == HEAD ]]; then
633 # find out what branch we fetched as HEAD
634 local head_branch=$(_git-r3_find_head \
635 refs/git-r3/HEAD \
636 < <(git ls-remote --heads "${r}" || die))
637
638 # and move it to its regular place
639 git update-ref --no-deref "${head_branch}" \
640 refs/git-r3/HEAD \
641 || die "Unable to sync HEAD branch ${head_branch}"
642 git symbolic-ref HEAD "${head_branch}" \
643 || die "Unable to update HEAD"
644 fi
645 fi
646
338 # now let's see what the user wants from us 647 # now let's see what the user wants from us
339 local full_remote_ref=$( 648 local full_remote_ref=$(
340 git rev-parse --verify --symbolic-full-name "${remote_ref}" 649 git rev-parse --verify --symbolic-full-name "${remote_ref}"
341 ) 650 )
342 651
358 break 667 break
359 fi 668 fi
360 done 669 done
361 [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI" 670 [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
362 671
672 # submodules can reference commits in any branch
673 # always use the 'clone' mode to accomodate that, bug #503332
674 local EGIT_CLONE_TYPE=mirror
675
363 # recursively fetch submodules 676 # recursively fetch submodules
364 if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then 677 if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
365 local submodules 678 local submodules
366 _git-r3_set_submodules \ 679 _git-r3_set_submodules \
367 "$(git cat-file -p "${local_ref}":.gitmodules || die)" 680 "$(git cat-file -p "${local_ref}":.gitmodules || die)"
373 local commit=$(git rev-parse "${local_ref}:${path}") 686 local commit=$(git rev-parse "${local_ref}:${path}")
374 687
375 if [[ ! ${commit} ]]; then 688 if [[ ! ${commit} ]]; then
376 die "Unable to get commit id for submodule ${subname}" 689 die "Unable to get commit id for submodule ${subname}"
377 fi 690 fi
378 if [[ ${url} == ./* || ${url} == ../* ]]; then 691
379 local subrepos=( "${repos[@]/%//${url}}" ) 692 local subrepos
380 else 693 _git-r3_set_subrepos "${url}" "${repos[@]}"
381 local subrepos=( "${url}" )
382 fi
383 694
384 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}" 695 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}"
385 696
386 submodules=( "${submodules[@]:3}" ) # shift 697 submodules=( "${submodules[@]:3}" ) # shift
387 done 698 done
440 ) 751 )
441 local new_commit_id=$( 752 local new_commit_id=$(
442 git rev-parse --verify refs/git-r3/"${local_id}"/__main__ 753 git rev-parse --verify refs/git-r3/"${local_id}"/__main__
443 ) 754 )
444 755
445 set -- git clone --quiet --shared --no-checkout "${GIT_DIR}" "${out_dir}"/
446 echo "${@}" >&2
447 "${@}" || die "git clone (for checkout) failed"
448
449 git-r3_sub_checkout() { 756 git-r3_sub_checkout() {
757 local orig_repo=${GIT_DIR}
450 local -x GIT_DIR=${out_dir}/.git 758 local -x GIT_DIR=${out_dir}/.git
451 local -x GIT_WORK_TREE=${out_dir} 759 local -x GIT_WORK_TREE=${out_dir}
760
761 mkdir -p "${out_dir}" || die
762
763 # use git init+fetch instead of clone since the latter doesn't like
764 # non-empty directories.
765
766 git init --quiet || die
767 # setup 'alternates' to avoid copying objects
768 echo "${orig_repo}/objects" > "${GIT_DIR}"/objects/info/alternates || die
769 # now copy the refs
770 # [htn]* safely catches heads, tags, notes without complaining
771 # on non-existing ones, and omits internal 'git-r3' ref
772 cp -R "${orig_repo}"/refs/[htn]* "${GIT_DIR}"/refs/ || die
773
774 # (no need to copy HEAD, we will set it via checkout)
775
776 if [[ -f ${orig_repo}/shallow ]]; then
777 cp "${orig_repo}"/shallow "${GIT_DIR}"/ || die
778 fi
452 779
453 set -- git checkout --quiet 780 set -- git checkout --quiet
454 if [[ ${remote_ref} ]]; then 781 if [[ ${remote_ref} ]]; then
455 set -- "${@}" "${remote_ref#refs/heads/}" 782 set -- "${@}" "${remote_ref#refs/heads/}"
456 else 783 else
493 820
494 while [[ ${submodules[@]} ]]; do 821 while [[ ${submodules[@]} ]]; do
495 local subname=${submodules[0]} 822 local subname=${submodules[0]}
496 local url=${submodules[1]} 823 local url=${submodules[1]}
497 local path=${submodules[2]} 824 local path=${submodules[2]}
825 local subrepos
826 _git-r3_set_subrepos "${url}" "${repos[@]}"
498 827
499 if [[ ${url} == ./* || ${url} == ../* ]]; then
500 url=${repos[0]%%/}/${url}
501 fi
502
503 git-r3_checkout "${url}" "${out_dir}/${path}" \ 828 git-r3_checkout "${subrepos[*]}" "${out_dir}/${path}" \
504 "${local_id}/${subname}" 829 "${local_id}/${subname}"
505 830
506 submodules=( "${submodules[@]:3}" ) # shift 831 submodules=( "${submodules[@]:3}" ) # shift
507 done 832 done
508 fi 833 fi

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

  ViewVC Help
Powered by ViewVC 1.1.20