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

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.39 - (hide annotations) (download)
Mon Mar 3 21:45:06 2014 UTC (6 months, 4 weeks ago) by mgorny
Branch: MAIN
Changes since 1.38: +5 -1 lines
Force EGIT_CLONE_TYPE=mirror for submodules since they can reference commits in any branch without explicitly naming the branch, bug #503332.

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

  ViewVC Help
Powered by ViewVC 1.1.20