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

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.33 - (show annotations) (download)
Sun Mar 2 11:48:05 2014 UTC (6 months, 3 weeks ago) by mgorny
Branch: MAIN
Changes since 1.32: +28 -10 lines
Support EGIT_CLONE_TYPE=shallow.

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

  ViewVC Help
Powered by ViewVC 1.1.20