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

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.41 - (show annotations) (download)
Thu Apr 17 20:28:37 2014 UTC (4 months, 1 week ago) by mgorny
Branch: MAIN
Changes since 1.40: +25 -8 lines
Automatically switch to EGIT_CLONE_TYPE=single+tags for Google Code.

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

  ViewVC Help
Powered by ViewVC 1.1.20