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

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.36 - (show annotations) (download)
Sun Mar 2 11:49:49 2014 UTC (6 months, 3 weeks ago) by mgorny
Branch: MAIN
Changes since 1.35: +6 -6 lines
Force non-forward updates on git refs.

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

  ViewVC Help
Powered by ViewVC 1.1.20