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

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.37 - (hide annotations) (download)
Sun Mar 2 11:50:23 2014 UTC (9 months, 2 weeks ago) by mgorny
Branch: MAIN
Changes since 1.36: +7 -3 lines
Do not try shallow clones on local repositories.

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.37 # $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.36 2014/03/02 11:49:49 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     # 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 mgorny 1.32 #
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 mgorny 1.33 #
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 mgorny 1.32 : ${EGIT_CLONE_TYPE:=single}
60 mgorny 1.31
61 mgorny 1.35 # @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 mgorny 1.1 # @ECLASS-VARIABLE: EGIT3_STORE_DIR
75     # @DESCRIPTION:
76     # Storage directory for git sources.
77     #
78 mgorny 1.27 # This is intended to be set by user in make.conf. Ebuilds must not set
79     # it.
80     #
81 mgorny 1.1 # EGIT3_STORE_DIR=${DISTDIR}/git3-src
82    
83 mgorny 1.30 # @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 mgorny 1.1 # @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 mgorny 1.9 # Can be a whitespace-separated list or an array.
107     #
108 mgorny 1.1 # 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 mgorny 1.31 # check the clone type
150     case "${EGIT_CLONE_TYPE}" in
151 mgorny 1.33 mirror|single|shallow)
152 mgorny 1.31 ;;
153     *)
154     die "Invalid EGIT_CLONE_TYPE=${EGIT_CLONE_TYPE}"
155     esac
156 mgorny 1.35 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 mgorny 1.31
175 mgorny 1.1 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 mgorny 1.7 # strip the trailing slash
252     repo_name=${repo_name%/}
253    
254 mgorny 1.1 # 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 mgorny 1.8 # gnome.org... who else?
259     browse/*) repo_name=${repo_name#browse/};;
260 mgorny 1.1 # 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 mgorny 1.17 mkdir -m0755 -p "${EGIT3_STORE_DIR}" || die
285 mgorny 1.1 ) || 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 mgorny 1.15 # skip modules that have 'update = none', bug #487262.
320     local upd=$(echo "${data}" | git config -f /dev/fd/0 \
321 mgorny 1.18 submodule."${subname}".update)
322 mgorny 1.15 [[ ${upd} == none ]] && continue
323    
324 mgorny 1.1 submodules+=(
325     "${subname}"
326     "$(echo "${data}" | git config -f /dev/fd/0 \
327 mgorny 1.17 submodule."${subname}".url || die)"
328 mgorny 1.1 "$(echo "${data}" | git config -f /dev/fd/0 \
329 mgorny 1.17 submodule."${subname}".path || die)"
330 mgorny 1.1 )
331 mgorny 1.17 done < <(echo "${data}" | git config -f /dev/fd/0 -l || die)
332 mgorny 1.1 }
333    
334 mgorny 1.23 # @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 mgorny 1.32 # @FUNCTION: _git-r3_find_head
349     # @USAGE: <head-ref>
350 mgorny 1.29 # @INTERNAL
351     # @DESCRIPTION:
352 mgorny 1.32 # 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 mgorny 1.29 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 mgorny 1.32 done
376 mgorny 1.29
377     if [[ ! ${matching_ref} ]]; then
378     die "Unable to find a matching branch for remote HEAD (${head_hash})"
379     fi
380    
381 mgorny 1.32 echo "${matching_ref}"
382 mgorny 1.29 }
383    
384 mgorny 1.1 # @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 mgorny 1.20 # (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT%/*}.
405 mgorny 1.1 # 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 mgorny 1.16 [[ ${EVCS_OFFLINE} ]] && return
416    
417 mgorny 1.11 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 mgorny 1.9 fi
425    
426 mgorny 1.1 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
427     local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
428 mgorny 1.20 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
429 mgorny 1.24 local local_ref=refs/git-r3/${local_id}/__main__
430 mgorny 1.1
431     [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
432    
433     local -x GIT_DIR
434 mgorny 1.9 _git-r3_set_gitdir "${repos[0]}"
435 mgorny 1.1
436 mgorny 1.30 # 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 mgorny 1.1 # try to fetch from the remote
445     local r success
446 mgorny 1.9 for r in "${repos[@]}"; do
447 mgorny 1.24 einfo "Fetching ${r} ..."
448 mgorny 1.1
449 mgorny 1.32 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 mgorny 1.36 "+refs/heads/*:refs/heads/*"
456 mgorny 1.32 # pull tags explicitly in order to prune them properly
457 mgorny 1.36 "+refs/tags/*:refs/tags/*"
458 mgorny 1.32 # notes in case something needs them
459 mgorny 1.36 "+refs/notes/*:refs/notes/*"
460 mgorny 1.32 # and HEAD in case we need the default branch
461     # (we keep it in refs/git-r3 since otherwise --prune interferes)
462 mgorny 1.36 "+HEAD:refs/git-r3/HEAD"
463 mgorny 1.32 )
464 mgorny 1.33 else # single or shallow
465 mgorny 1.32 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 mgorny 1.34 # commit
484     # so we need to fetch the branch
485 mgorny 1.32 if [[ ${branch} ]]; then
486     fetch_l=${branch}
487     else
488     fetch_l=HEAD
489     fi
490 mgorny 1.34
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 mgorny 1.32 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 mgorny 1.36 "+${fetch_l}:${fetch_r}"
506 mgorny 1.32 )
507     fi
508 mgorny 1.1
509 mgorny 1.33 if [[ ${EGIT_CLONE_TYPE} == shallow ]]; then
510 mgorny 1.37 if _git-r3_is_local_repo; then
511     # '--depth 1' causes sandbox violations with local repos
512     # bug #491260
513     local EGIT_CLONE_TYPE=single
514     elif [[ ! $(git rev-parse --quiet --verify "${fetch_r}") ]]
515 mgorny 1.33 then
516 mgorny 1.37 # use '--depth 1' when fetching a new branch
517 mgorny 1.33 fetch_command+=( --depth 1 )
518     fi
519     else # non-shallow mode
520     if [[ -f ${GIT_DIR}/shallow ]]; then
521     fetch_command+=( --unshallow )
522     fi
523     fi
524    
525 mgorny 1.24 set -- "${fetch_command[@]}"
526     echo "${@}" >&2
527     if "${@}"; then
528 mgorny 1.32 if [[ ${EGIT_CLONE_TYPE} == mirror ]]; then
529     # find remote HEAD and update our HEAD properly
530     git symbolic-ref HEAD \
531     "$(_git-r3_find_head refs/git-r3/HEAD \
532     < <(git show-ref --heads || die))" \
533     || die "Unable to update HEAD"
534 mgorny 1.33 else # single or shallow
535 mgorny 1.32 if [[ ${fetch_l} == HEAD ]]; then
536     # find out what branch we fetched as HEAD
537     local head_branch=$(_git-r3_find_head \
538     refs/git-r3/HEAD \
539     < <(git ls-remote --heads "${r}" || die))
540    
541     # and move it to its regular place
542     git update-ref --no-deref "${head_branch}" \
543     refs/git-r3/HEAD \
544     || die "Unable to sync HEAD branch ${head_branch}"
545     git symbolic-ref HEAD "${head_branch}" \
546     || die "Unable to update HEAD"
547     fi
548     fi
549 mgorny 1.29
550 mgorny 1.24 # now let's see what the user wants from us
551     local full_remote_ref=$(
552     git rev-parse --verify --symbolic-full-name "${remote_ref}"
553     )
554    
555     if [[ ${full_remote_ref} ]]; then
556     # when we are given a ref, create a symbolic ref
557     # so that we preserve the actual argument
558     set -- git symbolic-ref "${local_ref}" "${full_remote_ref}"
559 mgorny 1.3 else
560 mgorny 1.24 # otherwise, we were likely given a commit id
561     set -- git update-ref --no-deref "${local_ref}" "${remote_ref}"
562 mgorny 1.2 fi
563    
564 mgorny 1.24 echo "${@}" >&2
565     if ! "${@}"; then
566     die "Referencing ${remote_ref} failed (wrong ref?)."
567 mgorny 1.1 fi
568    
569     success=1
570     break
571     fi
572     done
573     [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
574    
575     # recursively fetch submodules
576     if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
577     local submodules
578     _git-r3_set_submodules \
579     "$(git cat-file -p "${local_ref}":.gitmodules || die)"
580    
581     while [[ ${submodules[@]} ]]; do
582     local subname=${submodules[0]}
583     local url=${submodules[1]}
584     local path=${submodules[2]}
585     local commit=$(git rev-parse "${local_ref}:${path}")
586    
587     if [[ ! ${commit} ]]; then
588     die "Unable to get commit id for submodule ${subname}"
589     fi
590 mgorny 1.19 if [[ ${url} == ./* || ${url} == ../* ]]; then
591     local subrepos=( "${repos[@]/%//${url}}" )
592     else
593     local subrepos=( "${url}" )
594     fi
595 mgorny 1.1
596 mgorny 1.19 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}"
597 mgorny 1.1
598     submodules=( "${submodules[@]:3}" ) # shift
599     done
600     fi
601     }
602    
603     # @FUNCTION: git-r3_checkout
604     # @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
605     # @DESCRIPTION:
606     # Check the previously fetched tree to the working copy.
607     #
608     # <repo-uri> specifies the repository URIs, as a space-separated list.
609     # The first URI will be used as repository group identifier
610     # and therefore must be used consistently with git-r3_fetch.
611     # The remaining URIs are not used and therefore may be omitted.
612     # When not specified, defaults to ${EGIT_REPO_URI}.
613     #
614     # <checkout-path> specifies the path to place the checkout. It defaults
615     # to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
616     #
617     # <local-id> needs to specify the local identifier that was used
618     # for respective git-r3_fetch.
619     #
620     # The checkout operation will write to the working copy, and export
621     # the repository state into the environment. If the repository contains
622     # submodules, they will be checked out recursively.
623     git-r3_checkout() {
624     debug-print-function ${FUNCNAME} "$@"
625    
626 mgorny 1.11 local repos
627     if [[ ${1} ]]; then
628     repos=( ${1} )
629     elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
630     repos=( "${EGIT_REPO_URI[@]}" )
631     else
632     repos=( ${EGIT_REPO_URI} )
633 mgorny 1.9 fi
634    
635 mgorny 1.1 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
636 mgorny 1.20 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
637 mgorny 1.1
638 mgorny 1.24 local -x GIT_DIR
639 mgorny 1.9 _git-r3_set_gitdir "${repos[0]}"
640 mgorny 1.1
641     einfo "Checking out ${repos[0]} to ${out_dir} ..."
642    
643 mgorny 1.24 if ! git cat-file -e refs/git-r3/"${local_id}"/__main__; then
644 mgorny 1.1 if [[ ${EVCS_OFFLINE} ]]; then
645     die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE."
646     else
647     die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
648     fi
649     fi
650 mgorny 1.24 local remote_ref=$(
651     git symbolic-ref --quiet refs/git-r3/"${local_id}"/__main__
652     )
653     local new_commit_id=$(
654     git rev-parse --verify refs/git-r3/"${local_id}"/__main__
655     )
656 mgorny 1.1
657 mgorny 1.24 git-r3_sub_checkout() {
658 mgorny 1.25 local orig_repo=${GIT_DIR}
659 mgorny 1.24 local -x GIT_DIR=${out_dir}/.git
660     local -x GIT_WORK_TREE=${out_dir}
661    
662 mgorny 1.26 mkdir -p "${out_dir}" || die
663    
664     # use git init+fetch instead of clone since the latter doesn't like
665     # non-empty directories.
666    
667     git init --quiet || die
668 mgorny 1.28 # setup 'alternates' to avoid copying objects
669     echo "${orig_repo}/objects" > "${GIT_DIR}"/objects/info/alternates || die
670     # now copy the refs
671     # [htn]* safely catches heads, tags, notes without complaining
672     # on non-existing ones, and omits internal 'git-r3' ref
673     cp -R "${orig_repo}"/refs/[htn]* "${GIT_DIR}"/refs/ || die
674 mgorny 1.26
675 mgorny 1.28 # (no need to copy HEAD, we will set it via checkout)
676 mgorny 1.25
677 mgorny 1.33 if [[ -f ${orig_repo}/shallow ]]; then
678     cp "${orig_repo}"/shallow "${GIT_DIR}"/ || die
679     fi
680    
681 mgorny 1.24 set -- git checkout --quiet
682     if [[ ${remote_ref} ]]; then
683     set -- "${@}" "${remote_ref#refs/heads/}"
684     else
685     set -- "${@}" "${new_commit_id}"
686     fi
687     echo "${@}" >&2
688     "${@}" || die "git checkout ${remote_ref:-${new_commit_id}} failed"
689     }
690     git-r3_sub_checkout
691 mgorny 1.22
692 mgorny 1.1 local old_commit_id=$(
693 mgorny 1.24 git rev-parse --quiet --verify refs/git-r3/"${local_id}"/__old__
694 mgorny 1.1 )
695     if [[ ! ${old_commit_id} ]]; then
696     echo "GIT NEW branch -->"
697     echo " repository: ${repos[0]}"
698     echo " at the commit: ${new_commit_id}"
699     else
700 mgorny 1.24 # diff against previous revision
701 mgorny 1.1 echo "GIT update -->"
702     echo " repository: ${repos[0]}"
703     # write out message based on the revisions
704     if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
705     echo " updating from commit: ${old_commit_id}"
706     echo " to commit: ${new_commit_id}"
707    
708     git --no-pager diff --stat \
709     ${old_commit_id}..${new_commit_id}
710     else
711     echo " at the commit: ${new_commit_id}"
712     fi
713     fi
714 mgorny 1.24 git update-ref --no-deref refs/git-r3/"${local_id}"/{__old__,__main__} || die
715 mgorny 1.1
716     # recursively checkout submodules
717 mgorny 1.24 if [[ -f ${out_dir}/.gitmodules ]]; then
718 mgorny 1.1 local submodules
719     _git-r3_set_submodules \
720 mgorny 1.24 "$(<"${out_dir}"/.gitmodules)"
721 mgorny 1.1
722     while [[ ${submodules[@]} ]]; do
723     local subname=${submodules[0]}
724     local url=${submodules[1]}
725     local path=${submodules[2]}
726    
727 mgorny 1.19 if [[ ${url} == ./* || ${url} == ../* ]]; then
728     url=${repos[0]%%/}/${url}
729     fi
730    
731 mgorny 1.24 git-r3_checkout "${url}" "${out_dir}/${path}" \
732 mgorny 1.1 "${local_id}/${subname}"
733    
734     submodules=( "${submodules[@]:3}" ) # shift
735     done
736     fi
737    
738     # keep this *after* submodules
739     export EGIT_DIR=${GIT_DIR}
740     export EGIT_VERSION=${new_commit_id}
741     }
742    
743     # @FUNCTION: git-r3_peek_remote_ref
744     # @USAGE: [<repo-uri> [<remote-ref>]]
745     # @DESCRIPTION:
746     # Peek the reference in the remote repository and print the matching
747     # (newest) commit SHA1.
748     #
749     # <repo-uri> specifies the repository URIs to fetch from, as a space-
750     # -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
751     #
752     # <remote-ref> specifies the remote ref to peek. It is preferred to use
753     # 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
754     # for tags. Alternatively, 'HEAD' may be used for upstream default
755     # branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
756     # 'HEAD' that is set to a non-null value.
757     #
758     # The operation will be done purely on the remote, without using local
759     # storage. If commit SHA1 is provided as <remote-ref>, the function will
760     # fail due to limitations of git protocol.
761     #
762     # On success, the function returns 0 and writes hexadecimal commit SHA1
763     # to stdout. On failure, the function returns 1.
764     git-r3_peek_remote_ref() {
765     debug-print-function ${FUNCNAME} "$@"
766    
767 mgorny 1.11 local repos
768     if [[ ${1} ]]; then
769     repos=( ${1} )
770     elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
771     repos=( "${EGIT_REPO_URI[@]}" )
772     else
773     repos=( ${EGIT_REPO_URI} )
774 mgorny 1.9 fi
775    
776 mgorny 1.1 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
777     local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
778    
779     [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
780    
781     local r success
782 mgorny 1.9 for r in "${repos[@]}"; do
783 mgorny 1.1 einfo "Peeking ${remote_ref} on ${r} ..." >&2
784    
785     local is_branch lookup_ref
786     if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
787     then
788     is_branch=1
789     lookup_ref=${remote_ref}
790     else
791     # ls-remote by commit is going to fail anyway,
792     # so we may as well pass refs/tags/ABCDEF...
793     lookup_ref=refs/tags/${remote_ref}
794     fi
795    
796     # split on whitespace
797     local ref=(
798     $(git ls-remote "${r}" "${lookup_ref}")
799     )
800    
801     if [[ ${ref[0]} ]]; then
802     echo "${ref[0]}"
803     return 0
804     fi
805     done
806    
807     return 1
808     }
809    
810     git-r3_src_fetch() {
811     debug-print-function ${FUNCNAME} "$@"
812    
813     if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then
814     ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider"
815     ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use"
816     ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones"
817     ewarn "when git-2 eclass becomes deprecated."
818     fi
819    
820     _git-r3_env_setup
821     git-r3_fetch
822     }
823    
824     git-r3_src_unpack() {
825     debug-print-function ${FUNCNAME} "$@"
826    
827     _git-r3_env_setup
828     git-r3_src_fetch
829     git-r3_checkout
830     }
831    
832     # https://bugs.gentoo.org/show_bug.cgi?id=482666
833     git-r3_pkg_outofdate() {
834     debug-print-function ${FUNCNAME} "$@"
835    
836     local new_commit_id=$(git-r3_peek_remote_ref)
837     ewarn "old: ${EGIT_VERSION}"
838     ewarn "new: ${new_commit_id}"
839     [[ ${new_commit_id} && ${old_commit_id} ]] || return 2
840    
841     [[ ${EGIT_VERSION} != ${new_commit_id} ]]
842     }
843    
844     _GIT_R3=1
845     fi

  ViewVC Help
Powered by ViewVC 1.1.20