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

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.34 - (show annotations) (download)
Sun Mar 2 11:48:28 2014 UTC (14 months, 3 weeks ago) by mgorny
Branch: MAIN
Changes since 1.33: +8 -3 lines
Auto-unshallow when fetching by commit hash.

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

  ViewVC Help
Powered by ViewVC 1.1.20