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

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


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

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

  ViewVC Help
Powered by ViewVC 1.1.20