/[gentoo-x86]/eclass/git-r3.eclass
Gentoo

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.47 - (hide annotations) (download)
Mon Jul 28 14:13:50 2014 UTC (3 months ago) by mgorny
Branch: MAIN
CVS Tags: HEAD
Changes since 1.46: +3 -2 lines
Mention git-clone man page for URI syntax, bug #511636.

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

  ViewVC Help
Powered by ViewVC 1.1.20