kde-plasma/breeze-gtk: x86 stable wrt bug #613144
[gentoo.git] / eclass / git-r3.eclass
1 # Copyright 1999-2015 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3
4 # @ECLASS: git-r3.eclass
5 # @MAINTAINER:
6 # Michał Górny <mgorny@gentoo.org>
7 # @BLURB: Eclass for fetching and unpacking git repositories.
8 # @DESCRIPTION:
9 # Third generation eclass for easing maintenance of live ebuilds using
10 # git as remote repository.
11
12 case "${EAPI:-0}" in
13         0|1|2|3|4|5|6)
14                 ;;
15         *)
16                 die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
17                 ;;
18 esac
19
20 if [[ ! ${_GIT_R3} ]]; then
21
22 inherit eutils
23
24 fi
25
26 EXPORT_FUNCTIONS src_unpack
27
28 if [[ ! ${_GIT_R3} ]]; then
29
30 if [[ ! ${_INHERITED_BY_GIT_2} ]]; then
31         DEPEND=">=dev-vcs/git-1.8.2.1"
32 fi
33
34 # @ECLASS-VARIABLE: EGIT_CLONE_TYPE
35 # @DESCRIPTION:
36 # Type of clone that should be used against the remote repository.
37 # This can be either of: 'mirror', 'single', 'shallow'.
38 #
39 # This is intended to be set by user in make.conf. Ebuilds are supposed
40 # to set EGIT_MIN_CLONE_TYPE if necessary instead.
41 #
42 # The 'mirror' type clones all remote branches and tags with complete
43 # history and all notes. EGIT_COMMIT can specify any commit hash.
44 # Upstream-removed branches and tags are purged from the local clone
45 # while fetching. This mode is suitable for cloning the local copy
46 # for development or hosting a local git mirror. However, clones
47 # of repositories with large diverged branches may quickly grow large.
48 #
49 # The 'single+tags' type clones the requested branch and all tags
50 # in the repository. All notes are fetched as well. EGIT_COMMIT
51 # can safely specify hashes throughout the current branch and all tags.
52 # No purging of old references is done (if you often switch branches,
53 # you may need to remove stale branches yourself). This mode is intended
54 # mostly for use with broken git servers such as Google Code that fail
55 # to fetch tags along with the branch in 'single' mode.
56 #
57 # The 'single' type clones only the requested branch or tag. Tags
58 # referencing commits throughout the branch history are fetched as well,
59 # and all notes. EGIT_COMMIT can safely specify only hashes
60 # in the current branch. No purging of old references is done (if you
61 # often switch branches, you may need to remove stale branches
62 # yourself). This mode is suitable for general use.
63 #
64 # The 'shallow' type clones only the newest commit on requested branch
65 # or tag. EGIT_COMMIT can only specify tags, and since the history is
66 # unavailable calls like 'git describe' will not reference prior tags.
67 # No purging of old references is done. This mode is intended mostly for
68 # embedded systems with limited disk space.
69 : ${EGIT_CLONE_TYPE:=single}
70
71 # @ECLASS-VARIABLE: EGIT_MIN_CLONE_TYPE
72 # @DESCRIPTION:
73 # 'Minimum' clone type supported by the ebuild. Takes same values
74 # as EGIT_CLONE_TYPE. When user sets a type that's 'lower' (that is,
75 # later on the list) than EGIT_MIN_CLONE_TYPE, the eclass uses
76 # EGIT_MIN_CLONE_TYPE instead.
77 #
78 # This variable is intended to be used by ebuilds only. Users are
79 # supposed to set EGIT_CLONE_TYPE instead.
80 #
81 # A common case is to use 'single' whenever the build system requires
82 # access to full branch history, or 'single+tags' when Google Code
83 # or a similar remote is used that does not support shallow clones
84 # and fetching tags along with commits. Please use sparingly, and to fix
85 # fatal errors rather than 'non-pretty versions'.
86 : ${EGIT_MIN_CLONE_TYPE:=shallow}
87
88 # @ECLASS-VARIABLE: EGIT3_STORE_DIR
89 # @DESCRIPTION:
90 # Storage directory for git sources.
91 #
92 # This is intended to be set by user in make.conf. Ebuilds must not set
93 # it.
94 #
95 # EGIT3_STORE_DIR=${DISTDIR}/git3-src
96
97 # @ECLASS-VARIABLE: EGIT_MIRROR_URI
98 # @DEFAULT_UNSET
99 # @DESCRIPTION:
100 # 'Top' URI to a local git mirror. If specified, the eclass will try
101 # to fetch from the local mirror instead of using the remote repository.
102 #
103 # The mirror needs to follow EGIT3_STORE_DIR structure. The directory
104 # created by eclass can be used for that purpose.
105 #
106 # Example:
107 # @CODE
108 # EGIT_MIRROR_URI="git://mirror.lan/"
109 # @CODE
110
111 # @ECLASS-VARIABLE: EGIT_REPO_URI
112 # @REQUIRED
113 # @DESCRIPTION:
114 # URIs to the repository, e.g. git://foo, https://foo. If multiple URIs
115 # are provided, the eclass will consider them as fallback URIs to try
116 # if the first URI does not work. For supported URI syntaxes, read up
117 # the manpage for git-clone(1).
118 #
119 # It can be overriden via env using ${PN}_LIVE_REPO variable.
120 #
121 # Can be a whitespace-separated list or an array.
122 #
123 # Example:
124 # @CODE
125 # EGIT_REPO_URI="git://a/b.git https://c/d.git"
126 # @CODE
127
128 # @ECLASS-VARIABLE: EVCS_OFFLINE
129 # @DEFAULT_UNSET
130 # @DESCRIPTION:
131 # If non-empty, this variable prevents any online operations.
132
133 # @ECLASS-VARIABLE: EVCS_UMASK
134 # @DEFAULT_UNSET
135 # @DESCRIPTION:
136 # Set this variable to a custom umask. This is intended to be set by
137 # users. By setting this to something like 002, it can make life easier
138 # for people who do development as non-root (but are in the portage
139 # group), and then switch over to building with FEATURES=userpriv.
140 # Or vice-versa. Shouldn't be a security issue here as anyone who has
141 # portage group write access already can screw the system over in more
142 # creative ways.
143
144 # @ECLASS-VARIABLE: EGIT_BRANCH
145 # @DEFAULT_UNSET
146 # @DESCRIPTION:
147 # The branch name to check out. If unset, the upstream default (HEAD)
148 # will be used.
149 #
150 # It can be overriden via env using ${PN}_LIVE_BRANCH variable.
151
152 # @ECLASS-VARIABLE: EGIT_COMMIT
153 # @DEFAULT_UNSET
154 # @DESCRIPTION:
155 # The tag name or commit identifier to check out. If unset, newest
156 # commit from the branch will be used. Note that if set to a commit
157 # not on HEAD branch, EGIT_BRANCH needs to be set to a branch on which
158 # the commit is available.
159 #
160 # It can be overriden via env using ${PN}_LIVE_COMMIT variable.
161
162 # @ECLASS-VARIABLE: EGIT_COMMIT_DATE
163 # @DEFAULT_UNSET
164 # @DESCRIPTION:
165 # Attempt to check out the repository state for the specified timestamp.
166 # The date should be in format understood by 'git rev-list'. The commits
167 # on EGIT_BRANCH will be considered.
168 #
169 # The eclass will select the last commit with commit date preceding
170 # the specified date. When merge commits are found, only first parents
171 # will be considered in order to avoid switching into external branches
172 # (assuming that merges are done correctly). In other words, each merge
173 # will be considered alike a single commit with date corresponding
174 # to the merge commit date.
175 #
176 # It can be overriden via env using ${PN}_LIVE_COMMIT_DATE variable.
177
178 # @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR
179 # @DESCRIPTION:
180 # The directory to check the git sources out to.
181 #
182 # EGIT_CHECKOUT_DIR=${WORKDIR}/${P}
183
184 # @ECLASS-VARIABLE: EGIT_SUBMODULES
185 # @DEFAULT_UNSET
186 # @DESCRIPTION:
187 # An array of inclusive and exclusive wildcards on submodule names,
188 # stating which submodules are fetched and checked out. Exclusions
189 # start with '-', and exclude previously matched submodules.
190 #
191 # If unset, all submodules are enabled. Empty list disables all
192 # submodules. In order to use an exclude-only list, start the array
193 # with '*'.
194 #
195 # Remember that wildcards need to be quoted in order to prevent filename
196 # expansion.
197 #
198 # Examples:
199 # @CODE
200 # # Disable all submodules
201 # EGIT_SUBMODULES=()
202 #
203 # # Include only foo and bar
204 # EGIT_SUBMODULES=( foo bar )
205 #
206 # # Use all submodules except for test-* but include test-lib
207 # EGIT_SUBMODULES=( '*' '-test-*' test-lib )
208 # @CODE
209
210 # @FUNCTION: _git-r3_env_setup
211 # @INTERNAL
212 # @DESCRIPTION:
213 # Set the eclass variables as necessary for operation. This can involve
214 # setting EGIT_* to defaults or ${PN}_LIVE_* variables.
215 _git-r3_env_setup() {
216         debug-print-function ${FUNCNAME} "$@"
217
218         # check the clone type
219         case "${EGIT_CLONE_TYPE}" in
220                 mirror|single+tags|single|shallow)
221                         ;;
222                 *)
223                         die "Invalid EGIT_CLONE_TYPE=${EGIT_CLONE_TYPE}"
224         esac
225         case "${EGIT_MIN_CLONE_TYPE}" in
226                 shallow)
227                         ;;
228                 single)
229                         if [[ ${EGIT_CLONE_TYPE} == shallow ]]; then
230                                 einfo "git-r3: ebuild needs to be cloned in '\e[1msingle\e[22m' mode, adjusting"
231                                 EGIT_CLONE_TYPE=single
232                         fi
233                         ;;
234                 single+tags)
235                         if [[ ${EGIT_CLONE_TYPE} == shallow || ${EGIT_CLONE_TYPE} == single ]]; then
236                                 einfo "git-r3: ebuild needs to be cloned in '\e[1msingle+tags\e[22m' mode, adjusting"
237                                 EGIT_CLONE_TYPE=single+tags
238                         fi
239                         ;;
240                 mirror)
241                         if [[ ${EGIT_CLONE_TYPE} != mirror ]]; then
242                                 einfo "git-r3: ebuild needs to be cloned in '\e[1mmirror\e[22m' mode, adjusting"
243                                 EGIT_CLONE_TYPE=mirror
244                         fi
245                         ;;
246                 *)
247                         die "Invalid EGIT_MIN_CLONE_TYPE=${EGIT_MIN_CLONE_TYPE}"
248         esac
249
250         if [[ ${EGIT_SUBMODULES[@]+1} && $(declare -p EGIT_SUBMODULES) != "declare -a"* ]]
251         then
252                 die 'EGIT_SUBMODULES must be an array.'
253         fi
254
255         local esc_pn livevar
256         esc_pn=${PN//[-+]/_}
257         [[ ${esc_pn} == [0-9]* ]] && esc_pn=_${esc_pn}
258
259         livevar=${esc_pn}_LIVE_REPO
260         EGIT_REPO_URI=${!livevar-${EGIT_REPO_URI}}
261         [[ ${!livevar} ]] \
262                 && ewarn "Using ${livevar}, no support will be provided"
263
264         livevar=${esc_pn}_LIVE_BRANCH
265         EGIT_BRANCH=${!livevar-${EGIT_BRANCH}}
266         [[ ${!livevar} ]] \
267                 && ewarn "Using ${livevar}, no support will be provided"
268
269         livevar=${esc_pn}_LIVE_COMMIT
270         EGIT_COMMIT=${!livevar-${EGIT_COMMIT}}
271         [[ ${!livevar} ]] \
272                 && ewarn "Using ${livevar}, no support will be provided"
273
274         livevar=${esc_pn}_LIVE_COMMIT_DATE
275         EGIT_COMMIT_DATE=${!livevar-${EGIT_COMMIT_DATE}}
276         [[ ${!livevar} ]] \
277                 && ewarn "Using ${livevar}, no support will be provided"
278
279         if [[ ${EGIT_COMMIT} && ${EGIT_COMMIT_DATE} ]]; then
280                 die "EGIT_COMMIT and EGIT_COMMIT_DATE can not be specified simultaneously"
281         fi
282
283         # Migration helpers. Remove them when git-2 is removed.
284
285         if [[ ${EGIT_SOURCEDIR} ]]; then
286                 eerror "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR. While updating"
287                 eerror "your ebuild, please check whether the variable is necessary at all"
288                 eerror "since the default has been changed from \${S} to \${WORKDIR}/\${P}."
289                 eerror "Therefore, proper setting of S may be sufficient."
290                 die "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR."
291         fi
292
293         if [[ ${EGIT_MASTER} ]]; then
294                 eerror "EGIT_MASTER has been removed. Instead, the upstream default (HEAD)"
295                 eerror "is used by the eclass. Please remove the assignment or use EGIT_BRANCH"
296                 eerror "as necessary."
297                 die "EGIT_MASTER has been removed."
298         fi
299
300         if [[ ${EGIT_HAS_SUBMODULES} ]]; then
301                 eerror "EGIT_HAS_SUBMODULES has been removed. The eclass no longer needs"
302                 eerror "to switch the clone type in order to support submodules and therefore"
303                 eerror "submodules are detected and fetched automatically. If you need to"
304                 eerror "disable or filter submodules, see EGIT_SUBMODULES."
305                 die "EGIT_HAS_SUBMODULES is no longer necessary."
306         fi
307
308         if [[ ${EGIT_PROJECT} ]]; then
309                 eerror "EGIT_PROJECT has been removed. Instead, the eclass determines"
310                 eerror "the local clone path using path in canonical EGIT_REPO_URI."
311                 eerror "If the current algorithm causes issues for you, please report a bug."
312                 die "EGIT_PROJECT is no longer necessary."
313         fi
314
315         if [[ ${EGIT_BOOTSTRAP} ]]; then
316                 eerror "EGIT_BOOTSTRAP has been removed. Please create proper src_prepare()"
317                 eerror "instead."
318                 die "EGIT_BOOTSTRAP has been removed."
319         fi
320
321         if [[ ${EGIT_NOUNPACK} ]]; then
322                 eerror "EGIT_NOUNPACK has been removed. The eclass no longer calls default"
323                 eerror "unpack function. If necessary, please declare proper src_unpack()."
324                 die "EGIT_NOUNPACK has been removed."
325         fi
326 }
327
328 # @FUNCTION: _git-r3_set_gitdir
329 # @USAGE: <repo-uri>
330 # @INTERNAL
331 # @DESCRIPTION:
332 # Obtain the local repository path and set it as GIT_DIR. Creates
333 # a new repository if necessary.
334 #
335 # <repo-uri> may be used to compose the path. It should therefore be
336 # a canonical URI to the repository.
337 _git-r3_set_gitdir() {
338         debug-print-function ${FUNCNAME} "$@"
339
340         local repo_name=${1#*://*/}
341
342         # strip the trailing slash
343         repo_name=${repo_name%/}
344
345         # strip common prefixes to make paths more likely to match
346         # e.g. git://X/Y.git vs https://X/git/Y.git
347         # (but just one of the prefixes)
348         case "${repo_name}" in
349                 # gnome.org... who else?
350                 browse/*) repo_name=${repo_name#browse/};;
351                 # cgit can proxy requests to git
352                 cgit/*) repo_name=${repo_name#cgit/};;
353                 # pretty common
354                 git/*) repo_name=${repo_name#git/};;
355                 # gentoo.org
356                 gitroot/*) repo_name=${repo_name#gitroot/};;
357                 # sourceforge
358                 p/*) repo_name=${repo_name#p/};;
359                 # kernel.org
360                 pub/scm/*) repo_name=${repo_name#pub/scm/};;
361         esac
362         # ensure a .git suffix, same reason
363         repo_name=${repo_name%.git}.git
364         # now replace all the slashes
365         repo_name=${repo_name//\//_}
366
367         local distdir=${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}}
368         : ${EGIT3_STORE_DIR:=${distdir}/git3-src}
369
370         GIT_DIR=${EGIT3_STORE_DIR}/${repo_name}
371
372         if [[ ! -d ${EGIT3_STORE_DIR} && ! ${EVCS_OFFLINE} ]]; then
373                 (
374                         addwrite /
375                         mkdir -p "${EGIT3_STORE_DIR}"
376                 ) || die "Unable to create ${EGIT3_STORE_DIR}"
377         fi
378
379         addwrite "${EGIT3_STORE_DIR}"
380         if [[ ! -d ${GIT_DIR} ]]; then
381                 if [[ ${EVCS_OFFLINE} ]]; then
382                         eerror "A clone of the following repository is required to proceed:"
383                         eerror "  ${1}"
384                         eerror "However, networking activity has been disabled using EVCS_OFFLINE and there"
385                         eerror "is no local clone available."
386                         die "No local clone of ${1}. Unable to proceed with EVCS_OFFLINE."
387                 fi
388
389                 local saved_umask
390                 if [[ ${EVCS_UMASK} ]]; then
391                         saved_umask=$(umask)
392                         umask "${EVCS_UMASK}" || die "Bad options to umask: ${EVCS_UMASK}"
393                 fi
394                 mkdir "${GIT_DIR}" || die
395                 git init --bare || die
396                 if [[ ${saved_umask} ]]; then
397                         umask "${saved_umask}" || die
398                 fi
399         fi
400 }
401
402 # @FUNCTION: _git-r3_set_submodules
403 # @USAGE: <file-contents>
404 # @INTERNAL
405 # @DESCRIPTION:
406 # Parse .gitmodules contents passed as <file-contents>
407 # as in "$(cat .gitmodules)"). Composes a 'submodules' array that
408 # contains in order (name, URL, path) for each submodule.
409 _git-r3_set_submodules() {
410         debug-print-function ${FUNCNAME} "$@"
411
412         local data=${1}
413
414         # ( name url path ... )
415         submodules=()
416
417         local l
418         while read l; do
419                 # submodule.<path>.path=<path>
420                 # submodule.<path>.url=<url>
421                 [[ ${l} == submodule.*.url=* ]] || continue
422
423                 l=${l#submodule.}
424                 local subname=${l%%.url=*}
425
426                 # filter out on EGIT_SUBMODULES
427                 if declare -p EGIT_SUBMODULES &>/dev/null; then
428                         local p l_res res=
429                         for p in "${EGIT_SUBMODULES[@]}"; do
430                                 if [[ ${p} == -* ]]; then
431                                         p=${p#-}
432                                         l_res=
433                                 else
434                                         l_res=1
435                                 fi
436
437                                 [[ ${subname} == ${p} ]] && res=${l_res}
438                         done
439
440                         if [[ ! ${res} ]]; then
441                                 einfo "Skipping submodule \e[1m${subname}\e[22m"
442                                 continue
443                         fi
444                 fi
445
446                 # skip modules that have 'update = none', bug #487262.
447                 local upd=$(echo "${data}" | git config -f /dev/fd/0 \
448                         submodule."${subname}".update)
449                 [[ ${upd} == none ]] && continue
450
451                 # https://github.com/git/git/blob/master/refs.c#L31
452                 # we are more restrictive than git itself but that should not
453                 # cause any issues, #572312, #606950
454                 # TODO: check escaped names for collisions
455                 local enc_subname=${subname//[^a-zA-Z0-9-]/_}
456
457                 submodules+=(
458                         "${enc_subname}"
459                         "$(echo "${data}" | git config -f /dev/fd/0 \
460                                 submodule."${subname}".url || die)"
461                         "$(echo "${data}" | git config -f /dev/fd/0 \
462                                 submodule."${subname}".path || die)"
463                 )
464         done < <(echo "${data}" | git config -f /dev/fd/0 -l || die)
465 }
466
467 # @FUNCTION: _git-r3_set_subrepos
468 # @USAGE: <submodule-uri> <parent-repo-uri>...
469 # @INTERNAL
470 # @DESCRIPTION:
471 # Create 'subrepos' array containing absolute (canonical) submodule URIs
472 # for the given <submodule-uri>. If the URI is relative, URIs will be
473 # constructed using all <parent-repo-uri>s. Otherwise, this single URI
474 # will be placed in the array.
475 _git-r3_set_subrepos() {
476         debug-print-function ${FUNCNAME} "$@"
477
478         local suburl=${1}
479         subrepos=( "${@:2}" )
480
481         if [[ ${suburl} == ./* || ${suburl} == ../* ]]; then
482                 # drop all possible trailing slashes for consistency
483                 subrepos=( "${subrepos[@]%%/}" )
484
485                 while true; do
486                         if [[ ${suburl} == ./* ]]; then
487                                 suburl=${suburl:2}
488                         elif [[ ${suburl} == ../* ]]; then
489                                 suburl=${suburl:3}
490
491                                 # XXX: correctness checking
492
493                                 # drop the last path component
494                                 subrepos=( "${subrepos[@]%/*}" )
495                                 # and then the trailing slashes, again
496                                 subrepos=( "${subrepos[@]%%/}" )
497                         else
498                                 break
499                         fi
500                 done
501
502                 # append the preprocessed path to the preprocessed URIs
503                 subrepos=( "${subrepos[@]/%//${suburl}}")
504         else
505                 subrepos=( "${suburl}" )
506         fi
507 }
508
509
510 # @FUNCTION: _git-r3_is_local_repo
511 # @USAGE: <repo-uri>
512 # @INTERNAL
513 # @DESCRIPTION:
514 # Determine whether the given URI specifies a local (on-disk)
515 # repository.
516 _git-r3_is_local_repo() {
517         debug-print-function ${FUNCNAME} "$@"
518
519         local uri=${1}
520
521         [[ ${uri} == file://* || ${uri} == /* ]]
522 }
523
524 # @FUNCTION: git-r3_fetch
525 # @USAGE: [<repo-uri> [<remote-ref> [<local-id> [<commit-date>]]]]
526 # @DESCRIPTION:
527 # Fetch new commits to the local clone of repository.
528 #
529 # <repo-uri> specifies the repository URIs to fetch from, as a space-
530 # -separated list. The first URI will be used as repository group
531 # identifier and therefore must be used consistently. When not
532 # specified, defaults to ${EGIT_REPO_URI}.
533 #
534 # <remote-ref> specifies the remote ref or commit id to fetch.
535 # It is preferred to use 'refs/heads/<branch-name>' for branches
536 # and 'refs/tags/<tag-name>' for tags. Other options are 'HEAD'
537 # for upstream default branch and hexadecimal commit SHA1. Defaults
538 # to the first of EGIT_COMMIT, EGIT_BRANCH or literal 'HEAD' that
539 # is set to a non-null value.
540 #
541 # <local-id> specifies the local branch identifier that will be used to
542 # locally store the fetch result. It should be unique to multiple
543 # fetches within the repository that can be performed at the same time
544 # (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT%/*}.
545 # This default should be fine unless you are fetching multiple trees
546 # from the same repository in the same ebuild.
547 #
548 # <commit-id> requests attempting to use repository state as of specific
549 # date. For more details, see EGIT_COMMIT_DATE.
550 #
551 # The fetch operation will affect the EGIT_STORE only. It will not touch
552 # the working copy, nor export any environment variables.
553 # If the repository contains submodules, they will be fetched
554 # recursively.
555 git-r3_fetch() {
556         debug-print-function ${FUNCNAME} "$@"
557
558         local repos
559         if [[ ${1} ]]; then
560                 repos=( ${1} )
561         elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
562                 repos=( "${EGIT_REPO_URI[@]}" )
563         else
564                 repos=( ${EGIT_REPO_URI} )
565         fi
566
567         local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
568         local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
569         local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
570         local local_ref=refs/git-r3/${local_id}/__main__
571         local commit_date=${4:-${EGIT_COMMIT_DATE}}
572
573         [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
574
575         local -x GIT_DIR
576         _git-r3_set_gitdir "${repos[0]}"
577
578         # prepend the local mirror if applicable
579         if [[ ${EGIT_MIRROR_URI} ]]; then
580                 repos=(
581                         "${EGIT_MIRROR_URI%/}/${GIT_DIR##*/}"
582                         "${repos[@]}"
583                 )
584         fi
585
586         # try to fetch from the remote
587         local r success saved_umask
588         if [[ ${EVCS_UMASK} ]]; then
589                 saved_umask=$(umask)
590                 umask "${EVCS_UMASK}" || die "Bad options to umask: ${EVCS_UMASK}"
591         fi
592         for r in "${repos[@]}"; do
593                 if [[ ! ${EVCS_OFFLINE} ]]; then
594                         einfo "Fetching \e[1m${r}\e[22m ..."
595
596                         local fetch_command=( git fetch "${r}" )
597                         local clone_type=${EGIT_CLONE_TYPE}
598
599                         if [[ ${r} == http://* || ${r} == https://* ]] &&
600                                         [[ ! ${EGIT_CURL_WARNED} ]] &&
601                                         ! ROOT=/ has_version 'dev-vcs/git[curl]'
602                         then
603                                 ewarn "git-r3: fetching from HTTP(S) requested. In order to support HTTP(S),"
604                                 ewarn "dev-vcs/git needs to be built with USE=curl. Example solution:"
605                                 ewarn
606                                 ewarn " echo dev-vcs/git curl >> /etc/portage/package.use"
607                                 ewarn " emerge -1v dev-vcs/git"
608                                 ewarn
609                                 ewarn "HTTP(S) URIs will be skipped."
610                                 EGIT_CURL_WARNED=1
611                         fi
612
613                         if [[ ${clone_type} == mirror ]]; then
614                                 fetch_command+=(
615                                         --prune
616                                         # mirror the remote branches as local branches
617                                         "+refs/heads/*:refs/heads/*"
618                                         # pull tags explicitly in order to prune them properly
619                                         "+refs/tags/*:refs/tags/*"
620                                         # notes in case something needs them
621                                         "+refs/notes/*:refs/notes/*"
622                                         # and HEAD in case we need the default branch
623                                         # (we keep it in refs/git-r3 since otherwise --prune interferes)
624                                         "+HEAD:refs/git-r3/HEAD"
625                                 )
626                         else # single or shallow
627                                 local fetch_l fetch_r
628
629                                 if [[ ${remote_ref} == HEAD ]]; then
630                                         # HEAD
631                                         fetch_l=HEAD
632                                 elif [[ ${remote_ref} == refs/* ]]; then
633                                         # regular branch, tag or some other explicit ref
634                                         fetch_l=${remote_ref}
635                                 else
636                                         # tag or commit id...
637                                         # let ls-remote figure it out
638                                         local tagref=$(git ls-remote "${r}" "refs/tags/${remote_ref}")
639
640                                         # if it was a tag, ls-remote obtained a hash
641                                         if [[ ${tagref} ]]; then
642                                                 # tag
643                                                 fetch_l=refs/tags/${remote_ref}
644                                         else
645                                                 # commit id
646                                                 # so we need to fetch the whole branch
647                                                 if [[ ${branch} ]]; then
648                                                         fetch_l=${branch}
649                                                 else
650                                                         fetch_l=HEAD
651                                                 fi
652
653                                                 # fetching by commit in shallow mode? can't do.
654                                                 if [[ ${clone_type} == shallow ]]; then
655                                                         clone_type=single
656                                                 fi
657                                         fi
658                                 fi
659
660                                 # checkout by date does not make sense in shallow mode
661                                 if [[ ${commit_date} && ${clone_type} == shallow ]]; then
662                                         clone_type=single
663                                 fi
664
665                                 if [[ ${fetch_l} == HEAD ]]; then
666                                         fetch_r=refs/git-r3/HEAD
667                                 else
668                                         fetch_r=${fetch_l}
669                                 fi
670
671                                 fetch_command+=(
672                                         "+${fetch_l}:${fetch_r}"
673                                 )
674
675                                 if [[ ${clone_type} == single+tags ]]; then
676                                         fetch_command+=(
677                                                 # pull tags explicitly as requested
678                                                 "+refs/tags/*:refs/tags/*"
679                                         )
680                                 fi
681                         fi
682
683                         if [[ ${clone_type} == shallow ]]; then
684                                 if _git-r3_is_local_repo; then
685                                         # '--depth 1' causes sandbox violations with local repos
686                                         # bug #491260
687                                         clone_type=single
688                                 elif [[ ! $(git rev-parse --quiet --verify "${fetch_r}") ]]
689                                 then
690                                         # use '--depth 1' when fetching a new branch
691                                         fetch_command+=( --depth 1 )
692                                 fi
693                         else # non-shallow mode
694                                 if [[ -f ${GIT_DIR}/shallow ]]; then
695                                         fetch_command+=( --unshallow )
696                                 fi
697                         fi
698
699                         set -- "${fetch_command[@]}"
700                         echo "${@}" >&2
701                         "${@}" || continue
702
703                         if [[ ${clone_type} == mirror || ${fetch_l} == HEAD ]]; then
704                                 # update our HEAD to match our remote HEAD ref
705                                 git symbolic-ref HEAD refs/git-r3/HEAD \
706                                                 || die "Unable to update HEAD"
707                         fi
708                 fi
709
710                 # now let's see what the user wants from us
711                 if [[ ${commit_date} ]]; then
712                         local dated_commit_id=$(
713                                 git rev-list --first-parent --before="${commit_date}" \
714                                         -n 1 "${remote_ref}"
715                         )
716                         if [[ ${?} -ne 0 ]]; then
717                                 die "Listing ${remote_ref} failed (wrong ref?)."
718                         elif [[ ! ${dated_commit_id} ]]; then
719                                 die "Unable to find commit for date ${commit_date}."
720                         else
721                                 set -- git update-ref --no-deref "${local_ref}" "${dated_commit_id}"
722                         fi
723                 else
724                         local full_remote_ref=$(
725                                 git rev-parse --verify --symbolic-full-name "${remote_ref}"
726                         )
727
728                         if [[ ${full_remote_ref} ]]; then
729                                 # when we are given a ref, create a symbolic ref
730                                 # so that we preserve the actual argument
731                                 set -- git symbolic-ref "${local_ref}" "${full_remote_ref}"
732                         else
733                                 # otherwise, we were likely given a commit id
734                                 set -- git update-ref --no-deref "${local_ref}" "${remote_ref}"
735                         fi
736                 fi
737
738                 echo "${@}" >&2
739                 if ! "${@}"; then
740                         if [[ ${EVCS_OFFLINE} ]]; then
741                                 eerror "A clone of the following repository is required to proceed:"
742                                 eerror "  ${r}"
743                                 eerror "However, networking activity has been disabled using EVCS_OFFLINE and the local"
744                                 eerror "clone does not have requested ref:"
745                                 eerror "  ${remote_ref}"
746                                 die "Local clone of ${r} does not have requested ref: ${remote_ref}. Unable to proceed with EVCS_OFFLINE."
747                         else
748                                 die "Referencing ${remote_ref} failed (wrong ref?)."
749                         fi
750                 fi
751
752                 success=1
753                 break
754         done
755         if [[ ${saved_umask} ]]; then
756                 umask "${saved_umask}" || die
757         fi
758         [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
759
760         # submodules can reference commits in any branch
761         # always use the 'mirror' mode to accomodate that, bug #503332
762         local EGIT_CLONE_TYPE=mirror
763
764         # recursively fetch submodules
765         if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
766                 local submodules
767                 _git-r3_set_submodules \
768                         "$(git cat-file -p "${local_ref}":.gitmodules || die)"
769
770                 while [[ ${submodules[@]} ]]; do
771                         local subname=${submodules[0]}
772                         local url=${submodules[1]}
773                         local path=${submodules[2]}
774
775                         # use only submodules for which path does exist
776                         # (this is in par with 'git submodule'), bug #551100
777                         # note: git cat-file does not work for submodules
778                         if [[ $(git ls-tree -d "${local_ref}" "${path}") ]]
779                         then
780                                 local commit=$(git rev-parse "${local_ref}:${path}" || die)
781
782                                 if [[ ! ${commit} ]]; then
783                                         die "Unable to get commit id for submodule ${subname}"
784                                 fi
785
786                                 local subrepos
787                                 _git-r3_set_subrepos "${url}" "${repos[@]}"
788
789                                 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}"
790                         fi
791
792                         submodules=( "${submodules[@]:3}" ) # shift
793                 done
794         fi
795 }
796
797 # @FUNCTION: git-r3_checkout
798 # @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
799 # @DESCRIPTION:
800 # Check the previously fetched tree to the working copy.
801 #
802 # <repo-uri> specifies the repository URIs, as a space-separated list.
803 # The first URI will be used as repository group identifier
804 # and therefore must be used consistently with git-r3_fetch.
805 # The remaining URIs are not used and therefore may be omitted.
806 # When not specified, defaults to ${EGIT_REPO_URI}.
807 #
808 # <checkout-path> specifies the path to place the checkout. It defaults
809 # to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
810 #
811 # <local-id> needs to specify the local identifier that was used
812 # for respective git-r3_fetch.
813 #
814 # The checkout operation will write to the working copy, and export
815 # the repository state into the environment. If the repository contains
816 # submodules, they will be checked out recursively.
817 git-r3_checkout() {
818         debug-print-function ${FUNCNAME} "$@"
819
820         local repos
821         if [[ ${1} ]]; then
822                 repos=( ${1} )
823         elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
824                 repos=( "${EGIT_REPO_URI[@]}" )
825         else
826                 repos=( ${EGIT_REPO_URI} )
827         fi
828
829         local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
830         local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
831
832         local -x GIT_DIR
833         _git-r3_set_gitdir "${repos[0]}"
834
835         einfo "Checking out \e[1m${repos[0]}\e[22m to \e[1m${out_dir}\e[22m ..."
836
837         if ! git cat-file -e refs/git-r3/"${local_id}"/__main__; then
838                 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
839         fi
840         local remote_ref=$(
841                 git symbolic-ref --quiet refs/git-r3/"${local_id}"/__main__
842         )
843         local new_commit_id=$(
844                 git rev-parse --verify refs/git-r3/"${local_id}"/__main__
845         )
846
847         git-r3_sub_checkout() {
848                 local orig_repo=${GIT_DIR}
849                 local -x GIT_DIR=${out_dir}/.git
850                 local -x GIT_WORK_TREE=${out_dir}
851
852                 mkdir -p "${out_dir}" || die
853
854                 # use git init+fetch instead of clone since the latter doesn't like
855                 # non-empty directories.
856
857                 git init --quiet || die
858                 # setup 'alternates' to avoid copying objects
859                 echo "${orig_repo}/objects" > "${GIT_DIR}"/objects/info/alternates || die
860                 # now copy the refs
861                 cp -R "${orig_repo}"/refs/* "${GIT_DIR}"/refs/ || die
862
863                 # (no need to copy HEAD, we will set it via checkout)
864
865                 if [[ -f ${orig_repo}/shallow ]]; then
866                         cp "${orig_repo}"/shallow "${GIT_DIR}"/ || die
867                 fi
868
869                 set -- git checkout --quiet
870                 if [[ ${remote_ref} ]]; then
871                         set -- "${@}" "${remote_ref#refs/heads/}"
872                 else
873                         set -- "${@}" "${new_commit_id}"
874                 fi
875                 echo "${@}" >&2
876                 "${@}" || die "git checkout ${remote_ref:-${new_commit_id}} failed"
877         }
878         git-r3_sub_checkout
879         unset -f git-r3_sub_checkout
880
881         local old_commit_id=$(
882                 git rev-parse --quiet --verify refs/git-r3/"${local_id}"/__old__
883         )
884         if [[ ! ${old_commit_id} ]]; then
885                 echo "GIT NEW branch -->"
886                 echo "   repository:               ${repos[0]}"
887                 echo "   at the commit:            ${new_commit_id}"
888         else
889                 # diff against previous revision
890                 echo "GIT update -->"
891                 echo "   repository:               ${repos[0]}"
892                 # write out message based on the revisions
893                 if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
894                         echo "   updating from commit:     ${old_commit_id}"
895                         echo "   to commit:                ${new_commit_id}"
896
897                         git --no-pager diff --stat \
898                                 ${old_commit_id}..${new_commit_id}
899                 else
900                         echo "   at the commit:            ${new_commit_id}"
901                 fi
902         fi
903         git update-ref --no-deref refs/git-r3/"${local_id}"/{__old__,__main__} || die
904
905         # recursively checkout submodules
906         if [[ -f ${out_dir}/.gitmodules ]]; then
907                 local submodules
908                 _git-r3_set_submodules \
909                         "$(<"${out_dir}"/.gitmodules)"
910
911                 while [[ ${submodules[@]} ]]; do
912                         local subname=${submodules[0]}
913                         local url=${submodules[1]}
914                         local path=${submodules[2]}
915
916                         # use only submodules for which path does exist
917                         # (this is in par with 'git submodule'), bug #551100
918                         if [[ -d ${out_dir}/${path} ]]; then
919                                 local subrepos
920                                 _git-r3_set_subrepos "${url}" "${repos[@]}"
921
922                                 git-r3_checkout "${subrepos[*]}" "${out_dir}/${path}" \
923                                         "${local_id}/${subname}"
924                         fi
925
926                         submodules=( "${submodules[@]:3}" ) # shift
927                 done
928         fi
929
930         # keep this *after* submodules
931         export EGIT_DIR=${GIT_DIR}
932         export EGIT_VERSION=${new_commit_id}
933 }
934
935 # @FUNCTION: git-r3_peek_remote_ref
936 # @USAGE: [<repo-uri> [<remote-ref>]]
937 # @DESCRIPTION:
938 # Peek the reference in the remote repository and print the matching
939 # (newest) commit SHA1.
940 #
941 # <repo-uri> specifies the repository URIs to fetch from, as a space-
942 # -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
943 #
944 # <remote-ref> specifies the remote ref to peek.  It is preferred to use
945 # 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
946 # for tags. Alternatively, 'HEAD' may be used for upstream default
947 # branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
948 # 'HEAD' that is set to a non-null value.
949 #
950 # The operation will be done purely on the remote, without using local
951 # storage. If commit SHA1 is provided as <remote-ref>, the function will
952 # fail due to limitations of git protocol.
953 #
954 # On success, the function returns 0 and writes hexadecimal commit SHA1
955 # to stdout. On failure, the function returns 1.
956 git-r3_peek_remote_ref() {
957         debug-print-function ${FUNCNAME} "$@"
958
959         local repos
960         if [[ ${1} ]]; then
961                 repos=( ${1} )
962         elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
963                 repos=( "${EGIT_REPO_URI[@]}" )
964         else
965                 repos=( ${EGIT_REPO_URI} )
966         fi
967
968         local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
969         local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
970
971         [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
972
973         local r success
974         for r in "${repos[@]}"; do
975                 einfo "Peeking \e[1m${remote_ref}\e[22m on \e[1m${r}\e[22m ..." >&2
976
977                 local lookup_ref
978                 if [[ ${remote_ref} == refs/* || ${remote_ref} == HEAD ]]
979                 then
980                         lookup_ref=${remote_ref}
981                 else
982                         # ls-remote by commit is going to fail anyway,
983                         # so we may as well pass refs/tags/ABCDEF...
984                         lookup_ref=refs/tags/${remote_ref}
985                 fi
986
987                 # split on whitespace
988                 local ref=(
989                         $(git ls-remote "${r}" "${lookup_ref}")
990                 )
991
992                 if [[ ${ref[0]} ]]; then
993                         echo "${ref[0]}"
994                         return 0
995                 fi
996         done
997
998         return 1
999 }
1000
1001 git-r3_src_fetch() {
1002         debug-print-function ${FUNCNAME} "$@"
1003
1004         if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then
1005                 ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider"
1006                 ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use"
1007                 ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones"
1008                 ewarn "when git-2 eclass becomes deprecated."
1009         fi
1010
1011         _git-r3_env_setup
1012         git-r3_fetch
1013 }
1014
1015 git-r3_src_unpack() {
1016         debug-print-function ${FUNCNAME} "$@"
1017
1018         _git-r3_env_setup
1019         git-r3_src_fetch
1020         git-r3_checkout
1021 }
1022
1023 # https://bugs.gentoo.org/show_bug.cgi?id=482666
1024 git-r3_pkg_needrebuild() {
1025         debug-print-function ${FUNCNAME} "$@"
1026
1027         local new_commit_id=$(git-r3_peek_remote_ref)
1028         [[ ${new_commit_id} && ${EGIT_VERSION} ]] || die "Lookup failed"
1029
1030         if [[ ${EGIT_VERSION} != ${new_commit_id} ]]; then
1031                 einfo "Update from \e[1m${EGIT_VERSION}\e[22m to \e[1m${new_commit_id}\e[22m"
1032         else
1033                 einfo "Local and remote at \e[1m${EGIT_VERSION}\e[22m"
1034         fi
1035
1036         [[ ${EGIT_VERSION} != ${new_commit_id} ]]
1037 }
1038
1039 # 'export' locally until this gets into EAPI
1040 pkg_needrebuild() { git-r3_pkg_needrebuild; }
1041
1042 _GIT_R3=1
1043 fi