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

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.40 - (show annotations) (download)
Mon Mar 24 21:32:31 2014 UTC (8 months, 3 weeks ago) by mgorny
Branch: MAIN
Changes since 1.39: +27 -5 lines
Add a single+tags mode to handle Google Code more efficiently, bug #503708.

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.39 2014/03/03 21:45:06 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
472 if [[ ${EGIT_CLONE_TYPE} == mirror ]]; then
473 fetch_command+=(
474 --prune
475 # mirror the remote branches as local branches
476 "+refs/heads/*:refs/heads/*"
477 # pull tags explicitly in order to prune them properly
478 "+refs/tags/*:refs/tags/*"
479 # notes in case something needs them
480 "+refs/notes/*:refs/notes/*"
481 # and HEAD in case we need the default branch
482 # (we keep it in refs/git-r3 since otherwise --prune interferes)
483 "+HEAD:refs/git-r3/HEAD"
484 )
485 else # single or shallow
486 local fetch_l fetch_r
487
488 if [[ ${remote_ref} == HEAD ]]; then
489 # HEAD
490 fetch_l=HEAD
491 elif [[ ${remote_ref} == refs/heads/* ]]; then
492 # regular branch
493 fetch_l=${remote_ref}
494 else
495 # tag or commit...
496 # let ls-remote figure it out
497 local tagref=$(git ls-remote "${r}" "refs/tags/${remote_ref}")
498
499 # if it was a tag, ls-remote obtained a hash
500 if [[ ${tagref} ]]; then
501 # tag
502 fetch_l=refs/tags/${remote_ref}
503 else
504 # commit
505 # so we need to fetch the branch
506 if [[ ${branch} ]]; then
507 fetch_l=${branch}
508 else
509 fetch_l=HEAD
510 fi
511
512 # fetching by commit in shallow mode? can't do.
513 if [[ ${EGIT_CLONE_TYPE} == shallow ]]; then
514 local EGIT_CLONE_TYPE=single
515 fi
516 fi
517 fi
518
519 if [[ ${fetch_l} == HEAD ]]; then
520 fetch_r=refs/git-r3/HEAD
521 else
522 fetch_r=${fetch_l}
523 fi
524
525 fetch_command+=(
526 "+${fetch_l}:${fetch_r}"
527 )
528
529 if [[ ${EGIT_CLONE_TYPE} == single+tags ]]; then
530 fetch_command+=(
531 # pull tags explicitly as requested
532 "+refs/tags/*:refs/tags/*"
533 )
534 fi
535 fi
536
537 if [[ ${EGIT_CLONE_TYPE} == shallow ]]; then
538 if _git-r3_is_local_repo; then
539 # '--depth 1' causes sandbox violations with local repos
540 # bug #491260
541 local EGIT_CLONE_TYPE=single
542 elif [[ ! $(git rev-parse --quiet --verify "${fetch_r}") ]]
543 then
544 # use '--depth 1' when fetching a new branch
545 fetch_command+=( --depth 1 )
546 fi
547 else # non-shallow mode
548 if [[ -f ${GIT_DIR}/shallow ]]; then
549 fetch_command+=( --unshallow )
550 fi
551 fi
552
553 set -- "${fetch_command[@]}"
554 echo "${@}" >&2
555 if "${@}"; then
556 if [[ ${EGIT_CLONE_TYPE} == mirror ]]; then
557 # find remote HEAD and update our HEAD properly
558 git symbolic-ref HEAD \
559 "$(_git-r3_find_head refs/git-r3/HEAD \
560 < <(git show-ref --heads || die))" \
561 || die "Unable to update HEAD"
562 else # single or shallow
563 if [[ ${fetch_l} == HEAD ]]; then
564 # find out what branch we fetched as HEAD
565 local head_branch=$(_git-r3_find_head \
566 refs/git-r3/HEAD \
567 < <(git ls-remote --heads "${r}" || die))
568
569 # and move it to its regular place
570 git update-ref --no-deref "${head_branch}" \
571 refs/git-r3/HEAD \
572 || die "Unable to sync HEAD branch ${head_branch}"
573 git symbolic-ref HEAD "${head_branch}" \
574 || die "Unable to update HEAD"
575 fi
576 fi
577
578 # now let's see what the user wants from us
579 local full_remote_ref=$(
580 git rev-parse --verify --symbolic-full-name "${remote_ref}"
581 )
582
583 if [[ ${full_remote_ref} ]]; then
584 # when we are given a ref, create a symbolic ref
585 # so that we preserve the actual argument
586 set -- git symbolic-ref "${local_ref}" "${full_remote_ref}"
587 else
588 # otherwise, we were likely given a commit id
589 set -- git update-ref --no-deref "${local_ref}" "${remote_ref}"
590 fi
591
592 echo "${@}" >&2
593 if ! "${@}"; then
594 die "Referencing ${remote_ref} failed (wrong ref?)."
595 fi
596
597 success=1
598 break
599 fi
600 done
601 [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
602
603 # submodules can reference commits in any branch
604 # always use the 'clone' mode to accomodate that, bug #503332
605 local EGIT_CLONE_TYPE=mirror
606
607 # recursively fetch submodules
608 if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
609 local submodules
610 _git-r3_set_submodules \
611 "$(git cat-file -p "${local_ref}":.gitmodules || die)"
612
613 while [[ ${submodules[@]} ]]; do
614 local subname=${submodules[0]}
615 local url=${submodules[1]}
616 local path=${submodules[2]}
617 local commit=$(git rev-parse "${local_ref}:${path}")
618
619 if [[ ! ${commit} ]]; then
620 die "Unable to get commit id for submodule ${subname}"
621 fi
622 if [[ ${url} == ./* || ${url} == ../* ]]; then
623 local subrepos=( "${repos[@]/%//${url}}" )
624 else
625 local subrepos=( "${url}" )
626 fi
627
628 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}"
629
630 submodules=( "${submodules[@]:3}" ) # shift
631 done
632 fi
633 }
634
635 # @FUNCTION: git-r3_checkout
636 # @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
637 # @DESCRIPTION:
638 # Check the previously fetched tree to the working copy.
639 #
640 # <repo-uri> specifies the repository URIs, as a space-separated list.
641 # The first URI will be used as repository group identifier
642 # and therefore must be used consistently with git-r3_fetch.
643 # The remaining URIs are not used and therefore may be omitted.
644 # When not specified, defaults to ${EGIT_REPO_URI}.
645 #
646 # <checkout-path> specifies the path to place the checkout. It defaults
647 # to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
648 #
649 # <local-id> needs to specify the local identifier that was used
650 # for respective git-r3_fetch.
651 #
652 # The checkout operation will write to the working copy, and export
653 # the repository state into the environment. If the repository contains
654 # submodules, they will be checked out recursively.
655 git-r3_checkout() {
656 debug-print-function ${FUNCNAME} "$@"
657
658 local repos
659 if [[ ${1} ]]; then
660 repos=( ${1} )
661 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
662 repos=( "${EGIT_REPO_URI[@]}" )
663 else
664 repos=( ${EGIT_REPO_URI} )
665 fi
666
667 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
668 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
669
670 local -x GIT_DIR
671 _git-r3_set_gitdir "${repos[0]}"
672
673 einfo "Checking out ${repos[0]} to ${out_dir} ..."
674
675 if ! git cat-file -e refs/git-r3/"${local_id}"/__main__; then
676 if [[ ${EVCS_OFFLINE} ]]; then
677 die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE."
678 else
679 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
680 fi
681 fi
682 local remote_ref=$(
683 git symbolic-ref --quiet refs/git-r3/"${local_id}"/__main__
684 )
685 local new_commit_id=$(
686 git rev-parse --verify refs/git-r3/"${local_id}"/__main__
687 )
688
689 git-r3_sub_checkout() {
690 local orig_repo=${GIT_DIR}
691 local -x GIT_DIR=${out_dir}/.git
692 local -x GIT_WORK_TREE=${out_dir}
693
694 mkdir -p "${out_dir}" || die
695
696 # use git init+fetch instead of clone since the latter doesn't like
697 # non-empty directories.
698
699 git init --quiet || die
700 # setup 'alternates' to avoid copying objects
701 echo "${orig_repo}/objects" > "${GIT_DIR}"/objects/info/alternates || die
702 # now copy the refs
703 # [htn]* safely catches heads, tags, notes without complaining
704 # on non-existing ones, and omits internal 'git-r3' ref
705 cp -R "${orig_repo}"/refs/[htn]* "${GIT_DIR}"/refs/ || die
706
707 # (no need to copy HEAD, we will set it via checkout)
708
709 if [[ -f ${orig_repo}/shallow ]]; then
710 cp "${orig_repo}"/shallow "${GIT_DIR}"/ || die
711 fi
712
713 set -- git checkout --quiet
714 if [[ ${remote_ref} ]]; then
715 set -- "${@}" "${remote_ref#refs/heads/}"
716 else
717 set -- "${@}" "${new_commit_id}"
718 fi
719 echo "${@}" >&2
720 "${@}" || die "git checkout ${remote_ref:-${new_commit_id}} failed"
721 }
722 git-r3_sub_checkout
723
724 local old_commit_id=$(
725 git rev-parse --quiet --verify refs/git-r3/"${local_id}"/__old__
726 )
727 if [[ ! ${old_commit_id} ]]; then
728 echo "GIT NEW branch -->"
729 echo " repository: ${repos[0]}"
730 echo " at the commit: ${new_commit_id}"
731 else
732 # diff against previous revision
733 echo "GIT update -->"
734 echo " repository: ${repos[0]}"
735 # write out message based on the revisions
736 if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
737 echo " updating from commit: ${old_commit_id}"
738 echo " to commit: ${new_commit_id}"
739
740 git --no-pager diff --stat \
741 ${old_commit_id}..${new_commit_id}
742 else
743 echo " at the commit: ${new_commit_id}"
744 fi
745 fi
746 git update-ref --no-deref refs/git-r3/"${local_id}"/{__old__,__main__} || die
747
748 # recursively checkout submodules
749 if [[ -f ${out_dir}/.gitmodules ]]; then
750 local submodules
751 _git-r3_set_submodules \
752 "$(<"${out_dir}"/.gitmodules)"
753
754 while [[ ${submodules[@]} ]]; do
755 local subname=${submodules[0]}
756 local url=${submodules[1]}
757 local path=${submodules[2]}
758
759 if [[ ${url} == ./* || ${url} == ../* ]]; then
760 url=${repos[0]%%/}/${url}
761 fi
762
763 git-r3_checkout "${url}" "${out_dir}/${path}" \
764 "${local_id}/${subname}"
765
766 submodules=( "${submodules[@]:3}" ) # shift
767 done
768 fi
769
770 # keep this *after* submodules
771 export EGIT_DIR=${GIT_DIR}
772 export EGIT_VERSION=${new_commit_id}
773 }
774
775 # @FUNCTION: git-r3_peek_remote_ref
776 # @USAGE: [<repo-uri> [<remote-ref>]]
777 # @DESCRIPTION:
778 # Peek the reference in the remote repository and print the matching
779 # (newest) commit SHA1.
780 #
781 # <repo-uri> specifies the repository URIs to fetch from, as a space-
782 # -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
783 #
784 # <remote-ref> specifies the remote ref to peek. It is preferred to use
785 # 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
786 # for tags. Alternatively, 'HEAD' may be used for upstream default
787 # branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
788 # 'HEAD' that is set to a non-null value.
789 #
790 # The operation will be done purely on the remote, without using local
791 # storage. If commit SHA1 is provided as <remote-ref>, the function will
792 # fail due to limitations of git protocol.
793 #
794 # On success, the function returns 0 and writes hexadecimal commit SHA1
795 # to stdout. On failure, the function returns 1.
796 git-r3_peek_remote_ref() {
797 debug-print-function ${FUNCNAME} "$@"
798
799 local repos
800 if [[ ${1} ]]; then
801 repos=( ${1} )
802 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
803 repos=( "${EGIT_REPO_URI[@]}" )
804 else
805 repos=( ${EGIT_REPO_URI} )
806 fi
807
808 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
809 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
810
811 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
812
813 local r success
814 for r in "${repos[@]}"; do
815 einfo "Peeking ${remote_ref} on ${r} ..." >&2
816
817 local is_branch lookup_ref
818 if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
819 then
820 is_branch=1
821 lookup_ref=${remote_ref}
822 else
823 # ls-remote by commit is going to fail anyway,
824 # so we may as well pass refs/tags/ABCDEF...
825 lookup_ref=refs/tags/${remote_ref}
826 fi
827
828 # split on whitespace
829 local ref=(
830 $(git ls-remote "${r}" "${lookup_ref}")
831 )
832
833 if [[ ${ref[0]} ]]; then
834 echo "${ref[0]}"
835 return 0
836 fi
837 done
838
839 return 1
840 }
841
842 git-r3_src_fetch() {
843 debug-print-function ${FUNCNAME} "$@"
844
845 if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then
846 ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider"
847 ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use"
848 ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones"
849 ewarn "when git-2 eclass becomes deprecated."
850 fi
851
852 _git-r3_env_setup
853 git-r3_fetch
854 }
855
856 git-r3_src_unpack() {
857 debug-print-function ${FUNCNAME} "$@"
858
859 _git-r3_env_setup
860 git-r3_src_fetch
861 git-r3_checkout
862 }
863
864 # https://bugs.gentoo.org/show_bug.cgi?id=482666
865 git-r3_pkg_outofdate() {
866 debug-print-function ${FUNCNAME} "$@"
867
868 local new_commit_id=$(git-r3_peek_remote_ref)
869 ewarn "old: ${EGIT_VERSION}"
870 ewarn "new: ${new_commit_id}"
871 [[ ${new_commit_id} && ${old_commit_id} ]] || return 2
872
873 [[ ${EGIT_VERSION} != ${new_commit_id} ]]
874 }
875
876 _GIT_R3=1
877 fi

  ViewVC Help
Powered by ViewVC 1.1.20