/[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.49
1# Copyright 1999-2013 Gentoo Foundation 1# Copyright 1999-2015 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.49 2015/06/22 08:39:36 mrueg 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 maintenance 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# 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
32# @ECLASS-VARIABLE: EGIT3_STORE_DIR 89# @ECLASS-VARIABLE: EGIT3_STORE_DIR
33# @DESCRIPTION: 90# @DESCRIPTION:
34# Storage directory for git sources. 91# Storage directory for git sources.
35# 92#
93# This is intended to be set by user in make.conf. Ebuilds must not set
94# it.
95#
36# 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
37 111
38# @ECLASS-VARIABLE: EGIT_REPO_URI 112# @ECLASS-VARIABLE: EGIT_REPO_URI
39# @REQUIRED 113# @REQUIRED
40# @DESCRIPTION: 114# @DESCRIPTION:
41# 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
42# are provided, the eclass will consider them as fallback URIs to try 116# are provided, the eclass will consider them as fallback URIs to try
43# if the first URI does not work. 117# if the first URI does not work. For supported URI syntaxes, read up
118# the manpage for git-clone(1).
44# 119#
45# It can be overriden via env using ${PN}_LIVE_REPO variable. 120# It can be overriden via env using ${PN}_LIVE_REPO variable.
121#
122# Can be a whitespace-separated list or an array.
46# 123#
47# Example: 124# Example:
48# @CODE 125# @CODE
49# EGIT_REPO_URI="git://a/b.git https://c/d.git" 126# EGIT_REPO_URI="git://a/b.git https://c/d.git"
50# @CODE 127# @CODE
52# @ECLASS-VARIABLE: EVCS_OFFLINE 129# @ECLASS-VARIABLE: EVCS_OFFLINE
53# @DEFAULT_UNSET 130# @DEFAULT_UNSET
54# @DESCRIPTION: 131# @DESCRIPTION:
55# If non-empty, this variable prevents any online operations. 132# If non-empty, this variable prevents any online operations.
56 133
134# @ECLASS-VARIABLE: EVCS_UMASK
135# @DEFAULT_UNSET
136# @DESCRIPTION:
137# Set this variable to a custom umask. This is intended to be set by
138# users. By setting this to something like 002, it can make life easier
139# for people who do development as non-root (but are in the portage
140# group), and then switch over to building with FEATURES=userpriv.
141# Or vice-versa. Shouldn't be a security issue here as anyone who has
142# portage group write access already can screw the system over in more
143# creative ways.
144
57# @ECLASS-VARIABLE: EGIT_BRANCH 145# @ECLASS-VARIABLE: EGIT_BRANCH
58# @DEFAULT_UNSET 146# @DEFAULT_UNSET
59# @DESCRIPTION: 147# @DESCRIPTION:
60# The branch name to check out. If unset, the upstream default (HEAD) 148# The branch name to check out. If unset, the upstream default (HEAD)
61# will be used. 149# will be used.
75# @DESCRIPTION: 163# @DESCRIPTION:
76# The directory to check the git sources out to. 164# The directory to check the git sources out to.
77# 165#
78# EGIT_CHECKOUT_DIR=${WORKDIR}/${P} 166# EGIT_CHECKOUT_DIR=${WORKDIR}/${P}
79 167
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 168# @FUNCTION: _git-r3_env_setup
91# @INTERNAL 169# @INTERNAL
92# @DESCRIPTION: 170# @DESCRIPTION:
93# Set the eclass variables as necessary for operation. This can involve 171# Set the eclass variables as necessary for operation. This can involve
94# setting EGIT_* to defaults or ${PN}_LIVE_* variables. 172# setting EGIT_* to defaults or ${PN}_LIVE_* variables.
95_git-r3_env_setup() { 173_git-r3_env_setup() {
96 debug-print-function ${FUNCNAME} "$@" 174 debug-print-function ${FUNCNAME} "$@"
175
176 # check the clone type
177 case "${EGIT_CLONE_TYPE}" in
178 mirror|single+tags|single|shallow)
179 ;;
180 *)
181 die "Invalid EGIT_CLONE_TYPE=${EGIT_CLONE_TYPE}"
182 esac
183 case "${EGIT_MIN_CLONE_TYPE}" in
184 shallow)
185 ;;
186 single)
187 if [[ ${EGIT_CLONE_TYPE} == shallow ]]; then
188 einfo "git-r3: ebuild needs to be cloned in 'single' mode, adjusting"
189 EGIT_CLONE_TYPE=single
190 fi
191 ;;
192 single+tags)
193 if [[ ${EGIT_CLONE_TYPE} == shallow || ${EGIT_CLONE_TYPE} == single ]]; then
194 einfo "git-r3: ebuild needs to be cloned in 'single+tags' mode, adjusting"
195 EGIT_CLONE_TYPE=single+tags
196 fi
197 ;;
198 mirror)
199 if [[ ${EGIT_CLONE_TYPE} != mirror ]]; then
200 einfo "git-r3: ebuild needs to be cloned in 'mirror' mode, adjusting"
201 EGIT_CLONE_TYPE=mirror
202 fi
203 ;;
204 *)
205 die "Invalid EGIT_MIN_CLONE_TYPE=${EGIT_MIN_CLONE_TYPE}"
206 esac
97 207
98 local esc_pn livevar 208 local esc_pn livevar
99 esc_pn=${PN//[-+]/_} 209 esc_pn=${PN//[-+]/_}
100 210
101 livevar=${esc_pn}_LIVE_REPO 211 livevar=${esc_pn}_LIVE_REPO
169_git-r3_set_gitdir() { 279_git-r3_set_gitdir() {
170 debug-print-function ${FUNCNAME} "$@" 280 debug-print-function ${FUNCNAME} "$@"
171 281
172 local repo_name=${1#*://*/} 282 local repo_name=${1#*://*/}
173 283
284 # strip the trailing slash
285 repo_name=${repo_name%/}
286
174 # strip common prefixes to make paths more likely to match 287 # strip common prefixes to make paths more likely to match
175 # e.g. git://X/Y.git vs https://X/git/Y.git 288 # e.g. git://X/Y.git vs https://X/git/Y.git
176 # (but just one of the prefixes) 289 # (but just one of the prefixes)
177 case "${repo_name}" in 290 case "${repo_name}" in
291 # gnome.org... who else?
292 browse/*) repo_name=${repo_name#browse/};;
178 # cgit can proxy requests to git 293 # cgit can proxy requests to git
179 cgit/*) repo_name=${repo_name#cgit/};; 294 cgit/*) repo_name=${repo_name#cgit/};;
180 # pretty common 295 # pretty common
181 git/*) repo_name=${repo_name#git/};; 296 git/*) repo_name=${repo_name#git/};;
182 # gentoo.org 297 # gentoo.org
197 GIT_DIR=${EGIT3_STORE_DIR}/${repo_name} 312 GIT_DIR=${EGIT3_STORE_DIR}/${repo_name}
198 313
199 if [[ ! -d ${EGIT3_STORE_DIR} ]]; then 314 if [[ ! -d ${EGIT3_STORE_DIR} ]]; then
200 ( 315 (
201 addwrite / 316 addwrite /
202 mkdir -m0755 -p "${EGIT3_STORE_DIR}" 317 mkdir -p "${EGIT3_STORE_DIR}" || die
203 ) || die "Unable to create ${EGIT3_STORE_DIR}" 318 ) || die "Unable to create ${EGIT3_STORE_DIR}"
204 fi 319 fi
205 320
206 addwrite "${EGIT3_STORE_DIR}" 321 addwrite "${EGIT3_STORE_DIR}"
207 if [[ ! -d ${GIT_DIR} ]]; then 322 if [[ ! -d ${GIT_DIR} ]]; then
323 local saved_umask
324 if [[ ${EVCS_UMASK} ]]; then
325 saved_umask=$(umask)
326 umask "${EVCS_UMASK}" || die "Bad options to umask: ${EVCS_UMASK}"
327 fi
208 mkdir "${GIT_DIR}" || die 328 mkdir "${GIT_DIR}" || die
209 git init --bare || die 329 git init --bare || die
210 330 if [[ ${saved_umask} ]]; then
211 # avoid auto-unshallow :) 331 umask "${saved_umask}" || die
212 touch "${GIT_DIR}"/shallow || die 332 fi
213 fi 333 fi
214} 334}
215 335
216# @FUNCTION: _git-r3_set_submodules 336# @FUNCTION: _git-r3_set_submodules
217# @USAGE: <file-contents> 337# @USAGE: <file-contents>
235 [[ ${l} == submodule.*.url=* ]] || continue 355 [[ ${l} == submodule.*.url=* ]] || continue
236 356
237 l=${l#submodule.} 357 l=${l#submodule.}
238 local subname=${l%%.url=*} 358 local subname=${l%%.url=*}
239 359
360 # skip modules that have 'update = none', bug #487262.
361 local upd=$(echo "${data}" | git config -f /dev/fd/0 \
362 submodule."${subname}".update)
363 [[ ${upd} == none ]] && continue
364
240 submodules+=( 365 submodules+=(
241 "${subname}" 366 "${subname}"
242 "$(echo "${data}" | git config -f /dev/fd/0 \ 367 "$(echo "${data}" | git config -f /dev/fd/0 \
243 submodule."${subname}".url)" 368 submodule."${subname}".url || die)"
244 "$(echo "${data}" | git config -f /dev/fd/0 \ 369 "$(echo "${data}" | git config -f /dev/fd/0 \
245 submodule."${subname}".path)" 370 submodule."${subname}".path || die)"
246 ) 371 )
247 done < <(echo "${data}" | git config -f /dev/fd/0 -l) 372 done < <(echo "${data}" | git config -f /dev/fd/0 -l || die)
373}
374
375# @FUNCTION: _git-r3_set_subrepos
376# @USAGE: <submodule-uri> <parent-repo-uri>...
377# @INTERNAL
378# @DESCRIPTION:
379# Create 'subrepos' array containing absolute (canonical) submodule URIs
380# for the given <submodule-uri>. If the URI is relative, URIs will be
381# constructed using all <parent-repo-uri>s. Otherwise, this single URI
382# will be placed in the array.
383_git-r3_set_subrepos() {
384 debug-print-function ${FUNCNAME} "$@"
385
386 local suburl=${1}
387 subrepos=( "${@:2}" )
388
389 if [[ ${suburl} == ./* || ${suburl} == ../* ]]; then
390 # drop all possible trailing slashes for consistency
391 subrepos=( "${subrepos[@]%%/}" )
392
393 while true; do
394 if [[ ${suburl} == ./* ]]; then
395 suburl=${suburl:2}
396 elif [[ ${suburl} == ../* ]]; then
397 suburl=${suburl:3}
398
399 # XXX: correctness checking
400
401 # drop the last path component
402 subrepos=( "${subrepos[@]%/*}" )
403 # and then the trailing slashes, again
404 subrepos=( "${subrepos[@]%%/}" )
405 else
406 break
407 fi
408 done
409
410 # append the preprocessed path to the preprocessed URIs
411 subrepos=( "${subrepos[@]/%//${suburl}}")
412 else
413 subrepos=( "${suburl}" )
414 fi
415}
416
417
418# @FUNCTION: _git-r3_is_local_repo
419# @USAGE: <repo-uri>
420# @INTERNAL
421# @DESCRIPTION:
422# Determine whether the given URI specifies a local (on-disk)
423# repository.
424_git-r3_is_local_repo() {
425 debug-print-function ${FUNCNAME} "$@"
426
427 local uri=${1}
428
429 [[ ${uri} == file://* || ${uri} == /* ]]
430}
431
432# @FUNCTION: _git-r3_find_head
433# @USAGE: <head-ref>
434# @INTERNAL
435# @DESCRIPTION:
436# Given a ref to which remote HEAD was fetched, try to find
437# a branch matching the commit. Expects 'git show-ref'
438# or 'git ls-remote' output on stdin.
439_git-r3_find_head() {
440 debug-print-function ${FUNCNAME} "$@"
441
442 local head_ref=${1}
443 local head_hash=$(git rev-parse --verify "${1}" || die)
444 local matching_ref
445
446 # TODO: some transports support peeking at symbolic remote refs
447 # find a way to use that rather than guessing
448
449 # (based on guess_remote_head() in git-1.9.0/remote.c)
450 local h ref
451 while read h ref; do
452 # look for matching head
453 if [[ ${h} == ${head_hash} ]]; then
454 # either take the first matching ref, or master if it is there
455 if [[ ! ${matching_ref} || ${ref} == refs/heads/master ]]; then
456 matching_ref=${ref}
457 fi
458 fi
459 done
460
461 if [[ ! ${matching_ref} ]]; then
462 die "Unable to find a matching branch for remote HEAD (${head_hash})"
463 fi
464
465 echo "${matching_ref}"
248} 466}
249 467
250# @FUNCTION: git-r3_fetch 468# @FUNCTION: git-r3_fetch
251# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]] 469# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]]
252# @DESCRIPTION: 470# @DESCRIPTION:
265# is set to a non-null value. 483# is set to a non-null value.
266# 484#
267# <local-id> specifies the local branch identifier that will be used to 485# <local-id> specifies the local branch identifier that will be used to
268# locally store the fetch result. It should be unique to multiple 486# locally store the fetch result. It should be unique to multiple
269# fetches within the repository that can be performed at the same time 487# fetches within the repository that can be performed at the same time
270# (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT}. 488# (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT%/*}.
271# This default should be fine unless you are fetching multiple trees 489# This default should be fine unless you are fetching multiple trees
272# from the same repository in the same ebuild. 490# from the same repository in the same ebuild.
273# 491#
274# The fetch operation will affect the EGIT_STORE only. It will not touch 492# The fetch operation will affect the EGIT_STORE only. It will not touch
275# the working copy, nor export any environment variables. 493# the working copy, nor export any environment variables.
276# If the repository contains submodules, they will be fetched 494# If the repository contains submodules, they will be fetched
277# recursively. 495# recursively.
278git-r3_fetch() { 496git-r3_fetch() {
279 debug-print-function ${FUNCNAME} "$@" 497 debug-print-function ${FUNCNAME} "$@"
280 498
499 [[ ${EVCS_OFFLINE} ]] && return
500
501 local repos
502 if [[ ${1} ]]; then
503 repos=( ${1} )
504 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
505 repos=( "${EGIT_REPO_URI[@]}" )
506 else
281 local repos=( ${1:-${EGIT_REPO_URI}} ) 507 repos=( ${EGIT_REPO_URI} )
508 fi
509
282 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} 510 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
283 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} 511 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
284 local local_id=${3:-${CATEGORY}/${PN}/${SLOT}} 512 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
285 local local_ref=refs/heads/${local_id}/__main__ 513 local local_ref=refs/git-r3/${local_id}/__main__
286 514
287 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" 515 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
288 516
289 local -x GIT_DIR 517 local -x GIT_DIR
290 _git-r3_set_gitdir ${repos[0]} 518 _git-r3_set_gitdir "${repos[0]}"
519
520 # prepend the local mirror if applicable
521 if [[ ${EGIT_MIRROR_URI} ]]; then
522 repos=(
523 "${EGIT_MIRROR_URI%/}/${GIT_DIR##*/}"
524 "${repos[@]}"
525 )
526 fi
291 527
292 # try to fetch from the remote 528 # try to fetch from the remote
529 local r success saved_umask
530 if [[ ${EVCS_UMASK} ]]; then
531 saved_umask=$(umask)
532 umask "${EVCS_UMASK}" || die "Bad options to umask: ${EVCS_UMASK}"
533 fi
534 for r in "${repos[@]}"; do
535 einfo "Fetching ${r} ..."
536
537 local fetch_command=( git fetch "${r}" )
538 local clone_type=${EGIT_CLONE_TYPE}
539
540 if [[ ${r} == https://* ]] && ! ROOT=/ has_version 'dev-vcs/git[curl]'; then
541 eerror "git-r3: fetching from https:// requested. In order to support https,"
542 eerror "dev-vcs/git needs to be built with USE=curl. Example solution:"
543 eerror
544 eerror " echo dev-vcs/git curl >> /etc/portage/package.use"
545 eerror " emerge -1v dev-vcs/git"
546 die "dev-vcs/git built with USE=curl required."
547 fi
548
549 if [[ ${r} == https://code.google.com/* ]]; then
550 # Google Code has special magic on top of git that:
551 # 1) can't handle shallow clones at all,
552 # 2) fetches duplicately when tags are pulled in with branch
553 # so automatically switch to single+tags mode.
554 if [[ ${clone_type} == shallow ]]; then
555 einfo " Google Code does not support shallow clones"
556 einfo " using EGIT_CLONE_TYPE=single+tags"
557 clone_type=single+tags
558 elif [[ ${clone_type} == single ]]; then
559 einfo " git-r3: Google Code does not send tags properly in 'single' mode"
560 einfo " using EGIT_CLONE_TYPE=single+tags"
561 clone_type=single+tags
562 fi
563 fi
564
565 if [[ ${clone_type} == mirror ]]; then
566 fetch_command+=(
567 --prune
568 # mirror the remote branches as local branches
569 "+refs/heads/*:refs/heads/*"
570 # pull tags explicitly in order to prune them properly
571 "+refs/tags/*:refs/tags/*"
572 # notes in case something needs them
573 "+refs/notes/*:refs/notes/*"
574 # and HEAD in case we need the default branch
575 # (we keep it in refs/git-r3 since otherwise --prune interferes)
576 "+HEAD:refs/git-r3/HEAD"
577 )
578 else # single or shallow
579 local fetch_l fetch_r
580
581 if [[ ${remote_ref} == HEAD ]]; then
582 # HEAD
583 fetch_l=HEAD
584 elif [[ ${remote_ref} == refs/heads/* ]]; then
585 # regular branch
586 fetch_l=${remote_ref}
587 else
588 # tag or commit...
589 # let ls-remote figure it out
590 local tagref=$(git ls-remote "${r}" "refs/tags/${remote_ref}")
591
592 # if it was a tag, ls-remote obtained a hash
593 if [[ ${tagref} ]]; then
594 # tag
595 fetch_l=refs/tags/${remote_ref}
596 else
597 # commit
598 # so we need to fetch the branch
599 if [[ ${branch} ]]; then
600 fetch_l=${branch}
601 else
602 fetch_l=HEAD
603 fi
604
605 # fetching by commit in shallow mode? can't do.
606 if [[ ${clone_type} == shallow ]]; then
607 clone_type=single
608 fi
609 fi
610 fi
611
612 if [[ ${fetch_l} == HEAD ]]; then
613 fetch_r=refs/git-r3/HEAD
614 else
615 fetch_r=${fetch_l}
616 fi
617
618 fetch_command+=(
619 "+${fetch_l}:${fetch_r}"
620 )
621
622 if [[ ${clone_type} == single+tags ]]; then
623 fetch_command+=(
624 # pull tags explicitly as requested
625 "+refs/tags/*:refs/tags/*"
626 )
627 fi
628 fi
629
630 if [[ ${clone_type} == shallow ]]; then
631 if _git-r3_is_local_repo; then
632 # '--depth 1' causes sandbox violations with local repos
633 # bug #491260
634 clone_type=single
635 elif [[ ! $(git rev-parse --quiet --verify "${fetch_r}") ]]
636 then
637 # use '--depth 1' when fetching a new branch
638 fetch_command+=( --depth 1 )
639 fi
640 else # non-shallow mode
641 if [[ -f ${GIT_DIR}/shallow ]]; then
642 fetch_command+=( --unshallow )
643 fi
644 fi
645
646 set -- "${fetch_command[@]}"
647 echo "${@}" >&2
648 if "${@}"; then
649 if [[ ${clone_type} == mirror ]]; then
650 # find remote HEAD and update our HEAD properly
651 git symbolic-ref HEAD \
652 "$(_git-r3_find_head refs/git-r3/HEAD \
653 < <(git show-ref --heads || die))" \
654 || die "Unable to update HEAD"
655 else # single or shallow
656 if [[ ${fetch_l} == HEAD ]]; then
657 # find out what branch we fetched as HEAD
658 local head_branch=$(_git-r3_find_head \
659 refs/git-r3/HEAD \
660 < <(git ls-remote --heads "${r}" || die))
661
662 # and move it to its regular place
663 git update-ref --no-deref "${head_branch}" \
664 refs/git-r3/HEAD \
665 || die "Unable to sync HEAD branch ${head_branch}"
666 git symbolic-ref HEAD "${head_branch}" \
667 || die "Unable to update HEAD"
668 fi
669 fi
670
671 # now let's see what the user wants from us
672 local full_remote_ref=$(
673 git rev-parse --verify --symbolic-full-name "${remote_ref}"
674 )
675
676 if [[ ${full_remote_ref} ]]; then
677 # when we are given a ref, create a symbolic ref
678 # so that we preserve the actual argument
679 set -- git symbolic-ref "${local_ref}" "${full_remote_ref}"
680 else
681 # otherwise, we were likely given a commit id
682 set -- git update-ref --no-deref "${local_ref}" "${remote_ref}"
683 fi
684
685 echo "${@}" >&2
686 if ! "${@}"; then
687 die "Referencing ${remote_ref} failed (wrong ref?)."
688 fi
689
690 success=1
691 break
692 fi
693 done
694 if [[ ${saved_umask} ]]; then
695 umask "${saved_umask}" || die
696 fi
697 [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
698
699 # submodules can reference commits in any branch
700 # always use the 'clone' mode to accomodate that, bug #503332
701 local EGIT_CLONE_TYPE=mirror
702
703 # recursively fetch submodules
704 if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
705 local submodules
706 _git-r3_set_submodules \
707 "$(git cat-file -p "${local_ref}":.gitmodules || die)"
708
709 while [[ ${submodules[@]} ]]; do
710 local subname=${submodules[0]}
711 local url=${submodules[1]}
712 local path=${submodules[2]}
713 local commit=$(git rev-parse "${local_ref}:${path}")
714
715 if [[ ! ${commit} ]]; then
716 die "Unable to get commit id for submodule ${subname}"
717 fi
718
719 local subrepos
720 _git-r3_set_subrepos "${url}" "${repos[@]}"
721
722 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}"
723
724 submodules=( "${submodules[@]:3}" ) # shift
725 done
726 fi
727}
728
729# @FUNCTION: git-r3_checkout
730# @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
731# @DESCRIPTION:
732# Check the previously fetched tree to the working copy.
733#
734# <repo-uri> specifies the repository URIs, as a space-separated list.
735# The first URI will be used as repository group identifier
736# and therefore must be used consistently with git-r3_fetch.
737# The remaining URIs are not used and therefore may be omitted.
738# When not specified, defaults to ${EGIT_REPO_URI}.
739#
740# <checkout-path> specifies the path to place the checkout. It defaults
741# to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
742#
743# <local-id> needs to specify the local identifier that was used
744# for respective git-r3_fetch.
745#
746# The checkout operation will write to the working copy, and export
747# the repository state into the environment. If the repository contains
748# submodules, they will be checked out recursively.
749git-r3_checkout() {
750 debug-print-function ${FUNCNAME} "$@"
751
752 local repos
753 if [[ ${1} ]]; then
754 repos=( ${1} )
755 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
756 repos=( "${EGIT_REPO_URI[@]}" )
757 else
758 repos=( ${EGIT_REPO_URI} )
759 fi
760
761 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
762 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
763
764 local -x GIT_DIR
765 _git-r3_set_gitdir "${repos[0]}"
766
767 einfo "Checking out ${repos[0]} to ${out_dir} ..."
768
769 if ! git cat-file -e refs/git-r3/"${local_id}"/__main__; then
770 if [[ ${EVCS_OFFLINE} ]]; then
771 die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE."
772 else
773 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
774 fi
775 fi
776 local remote_ref=$(
777 git symbolic-ref --quiet refs/git-r3/"${local_id}"/__main__
778 )
779 local new_commit_id=$(
780 git rev-parse --verify refs/git-r3/"${local_id}"/__main__
781 )
782
783 git-r3_sub_checkout() {
784 local orig_repo=${GIT_DIR}
785 local -x GIT_DIR=${out_dir}/.git
786 local -x GIT_WORK_TREE=${out_dir}
787
788 mkdir -p "${out_dir}" || die
789
790 # use git init+fetch instead of clone since the latter doesn't like
791 # non-empty directories.
792
793 git init --quiet || die
794 # setup 'alternates' to avoid copying objects
795 echo "${orig_repo}/objects" > "${GIT_DIR}"/objects/info/alternates || die
796 # now copy the refs
797 # [htn]* safely catches heads, tags, notes without complaining
798 # on non-existing ones, and omits internal 'git-r3' ref
799 cp -R "${orig_repo}"/refs/[htn]* "${GIT_DIR}"/refs/ || die
800
801 # (no need to copy HEAD, we will set it via checkout)
802
803 if [[ -f ${orig_repo}/shallow ]]; then
804 cp "${orig_repo}"/shallow "${GIT_DIR}"/ || die
805 fi
806
807 set -- git checkout --quiet
808 if [[ ${remote_ref} ]]; then
809 set -- "${@}" "${remote_ref#refs/heads/}"
810 else
811 set -- "${@}" "${new_commit_id}"
812 fi
813 echo "${@}" >&2
814 "${@}" || die "git checkout ${remote_ref:-${new_commit_id}} failed"
815 }
816 git-r3_sub_checkout
817
818 local old_commit_id=$(
819 git rev-parse --quiet --verify refs/git-r3/"${local_id}"/__old__
820 )
821 if [[ ! ${old_commit_id} ]]; then
822 echo "GIT NEW branch -->"
823 echo " repository: ${repos[0]}"
824 echo " at the commit: ${new_commit_id}"
825 else
826 # diff against previous revision
827 echo "GIT update -->"
828 echo " repository: ${repos[0]}"
829 # write out message based on the revisions
830 if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
831 echo " updating from commit: ${old_commit_id}"
832 echo " to commit: ${new_commit_id}"
833
834 git --no-pager diff --stat \
835 ${old_commit_id}..${new_commit_id}
836 else
837 echo " at the commit: ${new_commit_id}"
838 fi
839 fi
840 git update-ref --no-deref refs/git-r3/"${local_id}"/{__old__,__main__} || die
841
842 # recursively checkout submodules
843 if [[ -f ${out_dir}/.gitmodules ]]; then
844 local submodules
845 _git-r3_set_submodules \
846 "$(<"${out_dir}"/.gitmodules)"
847
848 while [[ ${submodules[@]} ]]; do
849 local subname=${submodules[0]}
850 local url=${submodules[1]}
851 local path=${submodules[2]}
852 local subrepos
853 _git-r3_set_subrepos "${url}" "${repos[@]}"
854
855 git-r3_checkout "${subrepos[*]}" "${out_dir}/${path}" \
856 "${local_id}/${subname}"
857
858 submodules=( "${submodules[@]:3}" ) # shift
859 done
860 fi
861
862 # keep this *after* submodules
863 export EGIT_DIR=${GIT_DIR}
864 export EGIT_VERSION=${new_commit_id}
865}
866
867# @FUNCTION: git-r3_peek_remote_ref
868# @USAGE: [<repo-uri> [<remote-ref>]]
869# @DESCRIPTION:
870# Peek the reference in the remote repository and print the matching
871# (newest) commit SHA1.
872#
873# <repo-uri> specifies the repository URIs to fetch from, as a space-
874# -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
875#
876# <remote-ref> specifies the remote ref to peek. It is preferred to use
877# 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
878# for tags. Alternatively, 'HEAD' may be used for upstream default
879# branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
880# 'HEAD' that is set to a non-null value.
881#
882# The operation will be done purely on the remote, without using local
883# storage. If commit SHA1 is provided as <remote-ref>, the function will
884# fail due to limitations of git protocol.
885#
886# On success, the function returns 0 and writes hexadecimal commit SHA1
887# to stdout. On failure, the function returns 1.
888git-r3_peek_remote_ref() {
889 debug-print-function ${FUNCNAME} "$@"
890
891 local repos
892 if [[ ${1} ]]; then
893 repos=( ${1} )
894 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
895 repos=( "${EGIT_REPO_URI[@]}" )
896 else
897 repos=( ${EGIT_REPO_URI} )
898 fi
899
900 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
901 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
902
903 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
904
293 local r success 905 local r success
294 for r in ${repos[@]}; do 906 for r in "${repos[@]}"; do
295 einfo "Fetching ${remote_ref} from ${r} ..." 907 einfo "Peeking ${remote_ref} on ${r} ..." >&2
296 908
297 local is_branch lookup_ref 909 local is_branch lookup_ref
298 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] 910 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
299 then 911 then
300 is_branch=1 912 is_branch=1
303 # ls-remote by commit is going to fail anyway, 915 # ls-remote by commit is going to fail anyway,
304 # so we may as well pass refs/tags/ABCDEF... 916 # so we may as well pass refs/tags/ABCDEF...
305 lookup_ref=refs/tags/${remote_ref} 917 lookup_ref=refs/tags/${remote_ref}
306 fi 918 fi
307 919
308 # first, try ls-remote to see if ${remote_ref} is a real ref
309 # and not a commit id. if it succeeds, we can pass ${remote_ref}
310 # to 'fetch'. otherwise, we will just fetch everything
311
312 # split on whitespace 920 # split on whitespace
313 local ref=( 921 local ref=(
314 $(git ls-remote "${r}" "${lookup_ref}") 922 $(git ls-remote "${r}" "${lookup_ref}")
315 ) 923 )
316 924
317 local ref_param=()
318 if [[ ! ${ref[0]} ]]; then
319 local EGIT_NONSHALLOW=1
320 fi
321
322 # 1. if we need a non-shallow clone and we have a shallow one,
323 # we need to unshallow it explicitly.
324 # 2. if we want a shallow clone, we just pass '--depth 1'
325 # to the first fetch in the repo. passing '--depth'
326 # to further requests usually results in more data being
327 # downloaded than without it.
328 # 3. in any other case, we just do plain 'git fetch' and let
329 # git to do its best (on top of shallow or non-shallow repo).
330
331 if [[ ${EGIT_NONSHALLOW} ]]; then
332 if [[ -f ${GIT_DIR}/shallow ]]; then
333 ref_param+=( --unshallow )
334 fi
335 else
336 # 'git show-ref --heads' returns 1 when there are no branches
337 if ! git show-ref --heads -q; then
338 ref_param+=( --depth 1 )
339 fi
340 fi
341
342 # now, another important thing. we may only fetch a remote
343 # branch directly to a local branch. Otherwise, we need to fetch
344 # the commit and re-create the branch on top of it.
345
346 if [[ ${ref[0]} ]]; then
347 if [[ ${is_branch} ]]; then
348 ref_param+=( -f "${remote_ref}:${local_id}/__main__" )
349 else
350 ref_param+=( "refs/tags/${remote_ref}" )
351 fi
352 fi
353
354 # if ${remote_ref} is branch or tag, ${ref[@]} will contain
355 # the respective commit id. otherwise, it will be an empty
356 # array, so the following won't evaluate to a parameter.
357 set -- git fetch --no-tags "${r}" "${ref_param[@]}"
358 echo "${@}" >&2
359 if "${@}"; then
360 if [[ ! ${is_branch} ]]; then
361 set -- git branch -f "${local_id}/__main__" \
362 "${ref[0]:-${remote_ref}}"
363 echo "${@}" >&2
364 if ! "${@}"; then
365 die "Creating branch for ${remote_ref} failed (wrong ref?)."
366 fi
367 fi
368
369 success=1
370 break
371 fi
372 done
373 [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
374
375 # recursively fetch submodules
376 if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
377 local submodules
378 _git-r3_set_submodules \
379 "$(git cat-file -p "${local_ref}":.gitmodules || die)"
380
381 while [[ ${submodules[@]} ]]; do
382 local subname=${submodules[0]}
383 local url=${submodules[1]}
384 local path=${submodules[2]}
385 local commit=$(git rev-parse "${local_ref}:${path}")
386
387 if [[ ! ${commit} ]]; then
388 die "Unable to get commit id for submodule ${subname}"
389 fi
390
391 git-r3_fetch "${url}" "${commit}" "${local_id}/${subname}"
392
393 submodules=( "${submodules[@]:3}" ) # shift
394 done
395 fi
396}
397
398# @FUNCTION: git-r3_checkout
399# @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
400# @DESCRIPTION:
401# Check the previously fetched tree to the working copy.
402#
403# <repo-uri> specifies the repository URIs, as a space-separated list.
404# The first URI will be used as repository group identifier
405# and therefore must be used consistently with git-r3_fetch.
406# The remaining URIs are not used and therefore may be omitted.
407# When not specified, defaults to ${EGIT_REPO_URI}.
408#
409# <checkout-path> specifies the path to place the checkout. It defaults
410# to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
411#
412# <local-id> needs to specify the local identifier that was used
413# for respective git-r3_fetch.
414#
415# The checkout operation will write to the working copy, and export
416# the repository state into the environment. If the repository contains
417# submodules, they will be checked out recursively.
418git-r3_checkout() {
419 debug-print-function ${FUNCNAME} "$@"
420
421 local repos=( ${1:-${EGIT_REPO_URI}} )
422 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
423 local local_id=${3:-${CATEGORY}/${PN}/${SLOT}}
424
425 local -x GIT_DIR GIT_WORK_TREE
426 _git-r3_set_gitdir ${repos[0]}
427 GIT_WORK_TREE=${out_dir}
428 mkdir -p "${GIT_WORK_TREE}"
429
430 einfo "Checking out ${repos[0]} to ${out_dir} ..."
431
432 if ! git cat-file -e refs/heads/"${local_id}"/__main__
433 then
434 if [[ ${EVCS_OFFLINE} ]]; then
435 die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE."
436 else
437 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
438 fi
439 fi
440
441 set -- git checkout -f "${local_id}"/__main__ .
442 echo "${@}" >&2
443 "${@}" || die "git checkout ${local_id}/__main__ failed"
444
445 # diff against previous revision (if any)
446 local new_commit_id=$(git rev-parse --verify "${local_id}"/__main__)
447 local old_commit_id=$(
448 git rev-parse --verify "${local_id}"/__old__ 2>/dev/null
449 )
450
451 if [[ ! ${old_commit_id} ]]; then
452 echo "GIT NEW branch -->"
453 echo " repository: ${repos[0]}"
454 echo " at the commit: ${new_commit_id}"
455 else
456 echo "GIT update -->"
457 echo " repository: ${repos[0]}"
458 # write out message based on the revisions
459 if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
460 echo " updating from commit: ${old_commit_id}"
461 echo " to commit: ${new_commit_id}"
462
463 git --no-pager diff --stat \
464 ${old_commit_id}..${new_commit_id}
465 else
466 echo " at the commit: ${new_commit_id}"
467 fi
468 fi
469 git branch -f "${local_id}"/{__old__,__main__} || die
470
471 # recursively checkout submodules
472 if [[ -f ${GIT_WORK_TREE}/.gitmodules ]]; then
473 local submodules
474 _git-r3_set_submodules \
475 "$(<"${GIT_WORK_TREE}"/.gitmodules)"
476
477 while [[ ${submodules[@]} ]]; do
478 local subname=${submodules[0]}
479 local url=${submodules[1]}
480 local path=${submodules[2]}
481
482 git-r3_checkout "${url}" "${GIT_WORK_TREE}/${path}" \
483 "${local_id}/${subname}"
484
485 submodules=( "${submodules[@]:3}" ) # shift
486 done
487 fi
488
489 # keep this *after* submodules
490 export EGIT_DIR=${GIT_DIR}
491 export EGIT_VERSION=${new_commit_id}
492}
493
494# @FUNCTION: git-r3_peek_remote_ref
495# @USAGE: [<repo-uri> [<remote-ref>]]
496# @DESCRIPTION:
497# Peek the reference in the remote repository and print the matching
498# (newest) commit SHA1.
499#
500# <repo-uri> specifies the repository URIs to fetch from, as a space-
501# -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
502#
503# <remote-ref> specifies the remote ref to peek. It is preferred to use
504# 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
505# for tags. Alternatively, 'HEAD' may be used for upstream default
506# branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
507# 'HEAD' that is set to a non-null value.
508#
509# The operation will be done purely on the remote, without using local
510# storage. If commit SHA1 is provided as <remote-ref>, the function will
511# fail due to limitations of git protocol.
512#
513# On success, the function returns 0 and writes hexadecimal commit SHA1
514# to stdout. On failure, the function returns 1.
515git-r3_peek_remote_ref() {
516 debug-print-function ${FUNCNAME} "$@"
517
518 local repos=( ${1:-${EGIT_REPO_URI}} )
519 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
520 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
521
522 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
523
524 local r success
525 for r in ${repos[@]}; do
526 einfo "Peeking ${remote_ref} on ${r} ..." >&2
527
528 local is_branch lookup_ref
529 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
530 then
531 is_branch=1
532 lookup_ref=${remote_ref}
533 else
534 # ls-remote by commit is going to fail anyway,
535 # so we may as well pass refs/tags/ABCDEF...
536 lookup_ref=refs/tags/${remote_ref}
537 fi
538
539 # split on whitespace
540 local ref=(
541 $(git ls-remote "${r}" "${lookup_ref}")
542 )
543
544 if [[ ${ref[0]} ]]; then 925 if [[ ${ref[0]} ]]; then
545 echo "${ref[0]}" 926 echo "${ref[0]}"
546 return 0 927 return 0
547 fi 928 fi
548 done 929 done
550 return 1 931 return 1
551} 932}
552 933
553git-r3_src_fetch() { 934git-r3_src_fetch() {
554 debug-print-function ${FUNCNAME} "$@" 935 debug-print-function ${FUNCNAME} "$@"
555
556 [[ ${EVCS_OFFLINE} ]] && return
557 936
558 if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then 937 if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then
559 ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider" 938 ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider"
560 ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use" 939 ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use"
561 ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones" 940 ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones"

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

  ViewVC Help
Powered by ViewVC 1.1.20