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

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.23 - (hide annotations) (download)
Fri Nov 15 23:03:23 2013 UTC (9 months, 1 week ago) by mgorny
Branch: MAIN
Changes since 1.22: +19 -1 lines
Use shallow clones for local repos. Bug #491260.

1 mgorny 1.1 # Copyright 1999-2013 Gentoo Foundation
2     # Distributed under the terms of the GNU General Public License v2
3 mgorny 1.23 # $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.22 2013/10/30 19:21:12 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     # git as remote repository. The eclass supports lightweight (shallow)
12     # clones and bare clones of submodules.
13    
14     case "${EAPI:-0}" in
15     0|1|2|3|4|5)
16     ;;
17     *)
18     die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
19     ;;
20     esac
21    
22     if [[ ! ${_GIT_R3} ]]; then
23    
24     inherit eutils
25    
26     fi
27    
28     EXPORT_FUNCTIONS src_unpack
29    
30     if [[ ! ${_GIT_R3} ]]; then
31    
32 mgorny 1.14 if [[ ! ${_INHERITED_BY_GIT_2} ]]; then
33     DEPEND=">=dev-vcs/git-1.8.2.1"
34     fi
35 mgorny 1.13
36 mgorny 1.1 # @ECLASS-VARIABLE: EGIT3_STORE_DIR
37     # @DESCRIPTION:
38     # Storage directory for git sources.
39     #
40     # EGIT3_STORE_DIR=${DISTDIR}/git3-src
41    
42     # @ECLASS-VARIABLE: EGIT_REPO_URI
43     # @REQUIRED
44     # @DESCRIPTION:
45     # URIs to the repository, e.g. git://foo, https://foo. If multiple URIs
46     # are provided, the eclass will consider them as fallback URIs to try
47     # if the first URI does not work.
48     #
49     # It can be overriden via env using ${PN}_LIVE_REPO variable.
50     #
51 mgorny 1.9 # Can be a whitespace-separated list or an array.
52     #
53 mgorny 1.1 # Example:
54     # @CODE
55     # EGIT_REPO_URI="git://a/b.git https://c/d.git"
56     # @CODE
57    
58     # @ECLASS-VARIABLE: EVCS_OFFLINE
59     # @DEFAULT_UNSET
60     # @DESCRIPTION:
61     # If non-empty, this variable prevents any online operations.
62    
63     # @ECLASS-VARIABLE: EGIT_BRANCH
64     # @DEFAULT_UNSET
65     # @DESCRIPTION:
66     # The branch name to check out. If unset, the upstream default (HEAD)
67     # will be used.
68     #
69     # It can be overriden via env using ${PN}_LIVE_BRANCH variable.
70    
71     # @ECLASS-VARIABLE: EGIT_COMMIT
72     # @DEFAULT_UNSET
73     # @DESCRIPTION:
74     # The tag name or commit identifier to check out. If unset, newest
75     # commit from the branch will be used. If set, EGIT_BRANCH will
76     # be ignored.
77     #
78     # It can be overriden via env using ${PN}_LIVE_COMMIT variable.
79    
80     # @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR
81     # @DESCRIPTION:
82     # The directory to check the git sources out to.
83     #
84     # EGIT_CHECKOUT_DIR=${WORKDIR}/${P}
85    
86     # @ECLASS-VARIABLE: EGIT_NONSHALLOW
87     # @DEFAULT_UNSET
88     # @DESCRIPTION:
89     # Disable performing shallow fetches/clones. Shallow clones have
90     # a fair number of limitations. Therefore, if you'd like the eclass to
91     # perform complete clones instead, set this to a non-null value.
92     #
93 mgorny 1.10 # This variable can be set in make.conf and ebuilds. The make.conf
94     # value specifies user-specific default, while ebuilds may use it
95     # to force deep clones when the server does not support shallow clones
96     # (e.g. Google Code).
97 mgorny 1.1
98     # @FUNCTION: _git-r3_env_setup
99     # @INTERNAL
100     # @DESCRIPTION:
101     # Set the eclass variables as necessary for operation. This can involve
102     # setting EGIT_* to defaults or ${PN}_LIVE_* variables.
103     _git-r3_env_setup() {
104     debug-print-function ${FUNCNAME} "$@"
105    
106     local esc_pn livevar
107     esc_pn=${PN//[-+]/_}
108    
109     livevar=${esc_pn}_LIVE_REPO
110     EGIT_REPO_URI=${!livevar:-${EGIT_REPO_URI}}
111     [[ ${!livevar} ]] \
112     && ewarn "Using ${livevar}, no support will be provided"
113    
114     livevar=${esc_pn}_LIVE_BRANCH
115     EGIT_BRANCH=${!livevar:-${EGIT_BRANCH}}
116     [[ ${!livevar} ]] \
117     && ewarn "Using ${livevar}, no support will be provided"
118    
119     livevar=${esc_pn}_LIVE_COMMIT
120     EGIT_COMMIT=${!livevar:-${EGIT_COMMIT}}
121     [[ ${!livevar} ]] \
122     && ewarn "Using ${livevar}, no support will be provided"
123    
124     # Migration helpers. Remove them when git-2 is removed.
125    
126     if [[ ${EGIT_SOURCEDIR} ]]; then
127     eerror "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR. While updating"
128     eerror "your ebuild, please check whether the variable is necessary at all"
129     eerror "since the default has been changed from \${S} to \${WORKDIR}/\${P}."
130     eerror "Therefore, proper setting of S may be sufficient."
131     die "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR."
132     fi
133    
134     if [[ ${EGIT_MASTER} ]]; then
135     eerror "EGIT_MASTER has been removed. Instead, the upstream default (HEAD)"
136     eerror "is used by the eclass. Please remove the assignment or use EGIT_BRANCH"
137     eerror "as necessary."
138     die "EGIT_MASTER has been removed."
139     fi
140    
141     if [[ ${EGIT_HAS_SUBMODULES} ]]; then
142     eerror "EGIT_HAS_SUBMODULES has been removed. The eclass no longer needs"
143     eerror "to switch the clone type in order to support submodules and therefore"
144     eerror "submodules are detected and fetched automatically."
145     die "EGIT_HAS_SUBMODULES is no longer necessary."
146     fi
147    
148     if [[ ${EGIT_PROJECT} ]]; then
149     eerror "EGIT_PROJECT has been removed. Instead, the eclass determines"
150     eerror "the local clone path using path in canonical EGIT_REPO_URI."
151     eerror "If the current algorithm causes issues for you, please report a bug."
152     die "EGIT_PROJECT is no longer necessary."
153     fi
154    
155     if [[ ${EGIT_BOOTSTRAP} ]]; then
156     eerror "EGIT_BOOTSTRAP has been removed. Please create proper src_prepare()"
157     eerror "instead."
158     die "EGIT_BOOTSTRAP has been removed."
159     fi
160    
161     if [[ ${EGIT_NOUNPACK} ]]; then
162     eerror "EGIT_NOUNPACK has been removed. The eclass no longer calls default"
163     eerror "unpack function. If necessary, please declare proper src_unpack()."
164     die "EGIT_NOUNPACK has been removed."
165     fi
166     }
167    
168     # @FUNCTION: _git-r3_set_gitdir
169     # @USAGE: <repo-uri>
170     # @INTERNAL
171     # @DESCRIPTION:
172     # Obtain the local repository path and set it as GIT_DIR. Creates
173     # a new repository if necessary.
174     #
175     # <repo-uri> may be used to compose the path. It should therefore be
176     # a canonical URI to the repository.
177     _git-r3_set_gitdir() {
178     debug-print-function ${FUNCNAME} "$@"
179    
180     local repo_name=${1#*://*/}
181    
182 mgorny 1.7 # strip the trailing slash
183     repo_name=${repo_name%/}
184    
185 mgorny 1.1 # strip common prefixes to make paths more likely to match
186     # e.g. git://X/Y.git vs https://X/git/Y.git
187     # (but just one of the prefixes)
188     case "${repo_name}" in
189 mgorny 1.8 # gnome.org... who else?
190     browse/*) repo_name=${repo_name#browse/};;
191 mgorny 1.1 # cgit can proxy requests to git
192     cgit/*) repo_name=${repo_name#cgit/};;
193     # pretty common
194     git/*) repo_name=${repo_name#git/};;
195     # gentoo.org
196     gitroot/*) repo_name=${repo_name#gitroot/};;
197     # google code, sourceforge
198     p/*) repo_name=${repo_name#p/};;
199     # kernel.org
200     pub/scm/*) repo_name=${repo_name#pub/scm/};;
201     esac
202     # ensure a .git suffix, same reason
203     repo_name=${repo_name%.git}.git
204     # now replace all the slashes
205     repo_name=${repo_name//\//_}
206    
207     local distdir=${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}}
208     : ${EGIT3_STORE_DIR:=${distdir}/git3-src}
209    
210     GIT_DIR=${EGIT3_STORE_DIR}/${repo_name}
211    
212     if [[ ! -d ${EGIT3_STORE_DIR} ]]; then
213     (
214     addwrite /
215 mgorny 1.17 mkdir -m0755 -p "${EGIT3_STORE_DIR}" || die
216 mgorny 1.1 ) || die "Unable to create ${EGIT3_STORE_DIR}"
217     fi
218    
219     addwrite "${EGIT3_STORE_DIR}"
220     if [[ ! -d ${GIT_DIR} ]]; then
221     mkdir "${GIT_DIR}" || die
222     git init --bare || die
223    
224 mgorny 1.6 if [[ ! ${EGIT_NONSHALLOW} ]]; then
225     # avoid auto-unshallow :)
226     touch "${GIT_DIR}"/shallow || die
227     fi
228 mgorny 1.1 fi
229     }
230    
231     # @FUNCTION: _git-r3_set_submodules
232     # @USAGE: <file-contents>
233     # @INTERNAL
234     # @DESCRIPTION:
235     # Parse .gitmodules contents passed as <file-contents>
236     # as in "$(cat .gitmodules)"). Composes a 'submodules' array that
237     # contains in order (name, URL, path) for each submodule.
238     _git-r3_set_submodules() {
239     debug-print-function ${FUNCNAME} "$@"
240    
241     local data=${1}
242    
243     # ( name url path ... )
244     submodules=()
245    
246     local l
247     while read l; do
248     # submodule.<path>.path=<path>
249     # submodule.<path>.url=<url>
250     [[ ${l} == submodule.*.url=* ]] || continue
251    
252     l=${l#submodule.}
253     local subname=${l%%.url=*}
254    
255 mgorny 1.15 # skip modules that have 'update = none', bug #487262.
256     local upd=$(echo "${data}" | git config -f /dev/fd/0 \
257 mgorny 1.18 submodule."${subname}".update)
258 mgorny 1.15 [[ ${upd} == none ]] && continue
259    
260 mgorny 1.1 submodules+=(
261     "${subname}"
262     "$(echo "${data}" | git config -f /dev/fd/0 \
263 mgorny 1.17 submodule."${subname}".url || die)"
264 mgorny 1.1 "$(echo "${data}" | git config -f /dev/fd/0 \
265 mgorny 1.17 submodule."${subname}".path || die)"
266 mgorny 1.1 )
267 mgorny 1.17 done < <(echo "${data}" | git config -f /dev/fd/0 -l || die)
268 mgorny 1.1 }
269    
270 mgorny 1.3 # @FUNCTION: _git-r3_smart_fetch
271     # @USAGE: <git-fetch-args>...
272     # @DESCRIPTION:
273     # Try fetching without '--depth' and switch to '--depth 1' if that
274     # will involve less objects fetched.
275     _git-r3_smart_fetch() {
276     debug-print-function ${FUNCNAME} "$@"
277    
278     local sed_regexp='.*Counting objects: \([0-9]*\), done\..*'
279    
280     # start the main fetch
281     local cmd=( git fetch --progress "${@}" )
282     echo "${cmd[@]}" >&2
283    
284     # we copy the output to the 'sed' pipe for parsing. whenever sed finds
285     # the process count, it quits quickly to avoid delays in writing it.
286     # then, we start a dummy 'cat' to keep the pipe alive
287    
288     "${cmd[@]}" 2>&1 \
289     | tee >(
290     sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}" \
291     > "${T}"/git-r3_main.count
292     exec cat >/dev/null
293     ) &
294     local main_pid=${!}
295    
296     # start the helper process
297     _git-r3_sub_fetch() {
298     # wait for main fetch to get object count; if the server doesn't
299     # output it, we won't even launch the parallel process
300     while [[ ! -s ${T}/git-r3_main.count ]]; do
301     sleep 0.25
302     done
303    
304     # ok, let's see if parallel fetch gives us smaller count
305     # --dry-run will prevent it from writing to the local clone
306     # and sed should terminate git with SIGPIPE
307     local sub_count=$(git fetch --progress --dry-run --depth 1 "${@}" 2>&1 \
308     | sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}")
309     local main_count=$(<"${T}"/git-r3_main.count)
310    
311     # let's be real sure that '--depth 1' will be good for us.
312     # note that we have purely objects counts, and '--depth 1'
313     # may involve much bigger objects
314     if [[ ${main_count} && ${main_count} -ge $(( sub_count * 3/2 )) ]]
315     then
316     # signal that we want shallow fetch instead,
317     # and terminate the non-shallow fetch process
318     touch "${T}"/git-r3_want_shallow || die
319     kill ${main_pid} &>/dev/null
320     exit 0
321     fi
322    
323     exit 1
324     }
325     _git-r3_sub_fetch "${@}" &
326     local sub_pid=${!}
327    
328     # wait for main process to terminate, either of its own
329     # or by signal from subprocess
330     wait ${main_pid}
331     local main_ret=${?}
332    
333     # wait for subprocess to terminate, killing it if necessary.
334     # if main fetch finished before it, there's no point in keeping
335     # it alive. if main fetch was killed by it, it's done anyway
336     kill ${sub_pid} &>/dev/null
337     wait ${sub_pid}
338    
339     # now see if subprocess wanted to tell us something...
340     if [[ -f ${T}/git-r3_want_shallow ]]; then
341     rm "${T}"/git-r3_want_shallow || die
342    
343     # if fetch finished already (wasn't killed), ignore it
344     [[ ${main_ret} -eq 0 ]] && return 0
345    
346     # otherwise, restart as shallow fetch
347     einfo "Restarting fetch using --depth 1 to save bandwidth ..."
348     local cmd=( git fetch --progress --depth 1 "${@}" )
349     echo "${cmd[@]}" >&2
350     "${cmd[@]}"
351     main_ret=${?}
352     fi
353    
354     return ${main_ret}
355     }
356    
357 mgorny 1.23 # @FUNCTION: _git-r3_is_local_repo
358     # @USAGE: <repo-uri>
359     # @INTERNAL
360     # @DESCRIPTION:
361     # Determine whether the given URI specifies a local (on-disk)
362     # repository.
363     _git-r3_is_local_repo() {
364     debug-print-function ${FUNCNAME} "$@"
365    
366     local uri=${1}
367    
368     [[ ${uri} == file://* || ${uri} == /* ]]
369     }
370    
371 mgorny 1.1 # @FUNCTION: git-r3_fetch
372     # @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]]
373     # @DESCRIPTION:
374     # Fetch new commits to the local clone of repository.
375     #
376     # <repo-uri> specifies the repository URIs to fetch from, as a space-
377     # -separated list. The first URI will be used as repository group
378     # identifier and therefore must be used consistently. When not
379     # specified, defaults to ${EGIT_REPO_URI}.
380     #
381     # <remote-ref> specifies the remote ref or commit id to fetch.
382     # It is preferred to use 'refs/heads/<branch-name>' for branches
383     # and 'refs/tags/<tag-name>' for tags. Other options are 'HEAD'
384     # for upstream default branch and hexadecimal commit SHA1. Defaults
385     # to the first of EGIT_COMMIT, EGIT_BRANCH or literal 'HEAD' that
386     # is set to a non-null value.
387     #
388     # <local-id> specifies the local branch identifier that will be used to
389     # locally store the fetch result. It should be unique to multiple
390     # fetches within the repository that can be performed at the same time
391 mgorny 1.20 # (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT%/*}.
392 mgorny 1.1 # This default should be fine unless you are fetching multiple trees
393     # from the same repository in the same ebuild.
394     #
395     # The fetch operation will affect the EGIT_STORE only. It will not touch
396     # the working copy, nor export any environment variables.
397     # If the repository contains submodules, they will be fetched
398     # recursively.
399     git-r3_fetch() {
400     debug-print-function ${FUNCNAME} "$@"
401    
402 mgorny 1.16 [[ ${EVCS_OFFLINE} ]] && return
403    
404 mgorny 1.11 local repos
405     if [[ ${1} ]]; then
406     repos=( ${1} )
407     elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
408     repos=( "${EGIT_REPO_URI[@]}" )
409     else
410     repos=( ${EGIT_REPO_URI} )
411 mgorny 1.9 fi
412    
413 mgorny 1.1 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
414     local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
415 mgorny 1.20 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
416 mgorny 1.1 local local_ref=refs/heads/${local_id}/__main__
417    
418     [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
419    
420     local -x GIT_DIR
421 mgorny 1.9 _git-r3_set_gitdir "${repos[0]}"
422 mgorny 1.1
423     # try to fetch from the remote
424     local r success
425 mgorny 1.9 for r in "${repos[@]}"; do
426 mgorny 1.1 einfo "Fetching ${remote_ref} from ${r} ..."
427    
428     local is_branch lookup_ref
429     if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
430     then
431     is_branch=1
432     lookup_ref=${remote_ref}
433     else
434     # ls-remote by commit is going to fail anyway,
435     # so we may as well pass refs/tags/ABCDEF...
436     lookup_ref=refs/tags/${remote_ref}
437     fi
438    
439     # first, try ls-remote to see if ${remote_ref} is a real ref
440     # and not a commit id. if it succeeds, we can pass ${remote_ref}
441     # to 'fetch'. otherwise, we will just fetch everything
442    
443     # split on whitespace
444     local ref=(
445 mgorny 1.5 $(git ls-remote "${r}" "${lookup_ref}" || echo __FAIL__)
446 mgorny 1.1 )
447    
448 mgorny 1.5 # normally, ref[0] is a hash, so we can do magic strings here
449     [[ ${ref[0]} == __FAIL__ ]] && continue
450    
451 mgorny 1.4 local nonshallow=${EGIT_NONSHALLOW}
452 mgorny 1.1 local ref_param=()
453     if [[ ! ${ref[0]} ]]; then
454 mgorny 1.4 nonshallow=1
455 mgorny 1.1 fi
456    
457 mgorny 1.23 # trying to do a shallow clone of a local repo makes git try to
458     # write to the repo. we don't want that to happen.
459     _git-r3_is_local_repo "${r}" && nonshallow=1
460    
461 mgorny 1.2 # 1. if we need a non-shallow clone and we have a shallow one,
462     # we need to unshallow it explicitly.
463     # 2. if we want a shallow clone, we just pass '--depth 1'
464     # to the first fetch in the repo. passing '--depth'
465     # to further requests usually results in more data being
466     # downloaded than without it.
467 mgorny 1.3 # 3. if we update a shallow clone, we try without '--depth'
468     # first since that usually transfers less data. however,
469     # we use git-r3_smart_fetch that can switch into '--depth 1'
470     # if that looks beneficial.
471 mgorny 1.2
472 mgorny 1.3 local fetch_command=( git fetch )
473 mgorny 1.4 if [[ ${nonshallow} ]]; then
474 mgorny 1.2 if [[ -f ${GIT_DIR}/shallow ]]; then
475     ref_param+=( --unshallow )
476     fi
477 mgorny 1.12 # fetch all branches
478     ref_param+=( "refs/heads/*:refs/remotes/origin/*" )
479 mgorny 1.1 else
480 mgorny 1.2 # 'git show-ref --heads' returns 1 when there are no branches
481     if ! git show-ref --heads -q; then
482     ref_param+=( --depth 1 )
483 mgorny 1.3 else
484     fetch_command=( _git-r3_smart_fetch )
485 mgorny 1.2 fi
486 mgorny 1.1 fi
487    
488 mgorny 1.2 # now, another important thing. we may only fetch a remote
489     # branch directly to a local branch. Otherwise, we need to fetch
490     # the commit and re-create the branch on top of it.
491    
492 mgorny 1.1 if [[ ${ref[0]} ]]; then
493     if [[ ${is_branch} ]]; then
494     ref_param+=( -f "${remote_ref}:${local_id}/__main__" )
495     else
496     ref_param+=( "refs/tags/${remote_ref}" )
497     fi
498     fi
499    
500     # if ${remote_ref} is branch or tag, ${ref[@]} will contain
501     # the respective commit id. otherwise, it will be an empty
502     # array, so the following won't evaluate to a parameter.
503 mgorny 1.3 set -- "${fetch_command[@]}" --no-tags "${r}" "${ref_param[@]}"
504 mgorny 1.1 echo "${@}" >&2
505     if "${@}"; then
506     if [[ ! ${is_branch} ]]; then
507     set -- git branch -f "${local_id}/__main__" \
508     "${ref[0]:-${remote_ref}}"
509     echo "${@}" >&2
510     if ! "${@}"; then
511     die "Creating branch for ${remote_ref} failed (wrong ref?)."
512     fi
513     fi
514    
515     success=1
516     break
517     fi
518     done
519     [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
520    
521     # recursively fetch submodules
522     if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
523     local submodules
524     _git-r3_set_submodules \
525     "$(git cat-file -p "${local_ref}":.gitmodules || die)"
526    
527     while [[ ${submodules[@]} ]]; do
528     local subname=${submodules[0]}
529     local url=${submodules[1]}
530     local path=${submodules[2]}
531     local commit=$(git rev-parse "${local_ref}:${path}")
532    
533     if [[ ! ${commit} ]]; then
534     die "Unable to get commit id for submodule ${subname}"
535     fi
536 mgorny 1.19 if [[ ${url} == ./* || ${url} == ../* ]]; then
537     local subrepos=( "${repos[@]/%//${url}}" )
538     else
539     local subrepos=( "${url}" )
540     fi
541 mgorny 1.1
542 mgorny 1.19 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}"
543 mgorny 1.1
544     submodules=( "${submodules[@]:3}" ) # shift
545     done
546     fi
547     }
548    
549     # @FUNCTION: git-r3_checkout
550     # @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
551     # @DESCRIPTION:
552     # Check the previously fetched tree to the working copy.
553     #
554     # <repo-uri> specifies the repository URIs, as a space-separated list.
555     # The first URI will be used as repository group identifier
556     # and therefore must be used consistently with git-r3_fetch.
557     # The remaining URIs are not used and therefore may be omitted.
558     # When not specified, defaults to ${EGIT_REPO_URI}.
559     #
560     # <checkout-path> specifies the path to place the checkout. It defaults
561     # to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
562     #
563     # <local-id> needs to specify the local identifier that was used
564     # for respective git-r3_fetch.
565     #
566     # The checkout operation will write to the working copy, and export
567     # the repository state into the environment. If the repository contains
568     # submodules, they will be checked out recursively.
569     git-r3_checkout() {
570     debug-print-function ${FUNCNAME} "$@"
571    
572 mgorny 1.11 local repos
573     if [[ ${1} ]]; then
574     repos=( ${1} )
575     elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
576     repos=( "${EGIT_REPO_URI[@]}" )
577     else
578     repos=( ${EGIT_REPO_URI} )
579 mgorny 1.9 fi
580    
581 mgorny 1.1 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
582 mgorny 1.20 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
583 mgorny 1.1
584     local -x GIT_DIR GIT_WORK_TREE
585 mgorny 1.9 _git-r3_set_gitdir "${repos[0]}"
586 mgorny 1.1 GIT_WORK_TREE=${out_dir}
587 mgorny 1.17 mkdir -p "${GIT_WORK_TREE}" || die
588 mgorny 1.1
589     einfo "Checking out ${repos[0]} to ${out_dir} ..."
590    
591     if ! git cat-file -e refs/heads/"${local_id}"/__main__
592     then
593     if [[ ${EVCS_OFFLINE} ]]; then
594     die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE."
595     else
596     die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
597     fi
598     fi
599    
600 mgorny 1.22 # Note: this is a hack to avoid parallel checkout issues.
601     # I will try to handle it without locks when I have more time.
602     local lockfile=${GIT_DIR}/.git-r3_checkout_lock
603     local lockfile_l=${lockfile}.${BASHPID}
604     touch "${lockfile_l}" || die
605     until ln "${lockfile_l}" "${lockfile}" &>/dev/null; do
606     sleep 1
607     done
608     rm "${lockfile_l}" || die
609    
610 mgorny 1.1 set -- git checkout -f "${local_id}"/__main__ .
611     echo "${@}" >&2
612 mgorny 1.22 "${@}"
613     local ret=${?}
614    
615     # Remove the lock!
616     rm "${lockfile}" || die
617    
618     [[ ${ret} == 0 ]] || die "git checkout ${local_id}/__main__ failed"
619 mgorny 1.1
620     # diff against previous revision (if any)
621     local new_commit_id=$(git rev-parse --verify "${local_id}"/__main__)
622     local old_commit_id=$(
623     git rev-parse --verify "${local_id}"/__old__ 2>/dev/null
624     )
625    
626     if [[ ! ${old_commit_id} ]]; then
627     echo "GIT NEW branch -->"
628     echo " repository: ${repos[0]}"
629     echo " at the commit: ${new_commit_id}"
630     else
631     echo "GIT update -->"
632     echo " repository: ${repos[0]}"
633     # write out message based on the revisions
634     if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
635     echo " updating from commit: ${old_commit_id}"
636     echo " to commit: ${new_commit_id}"
637    
638     git --no-pager diff --stat \
639     ${old_commit_id}..${new_commit_id}
640     else
641     echo " at the commit: ${new_commit_id}"
642     fi
643     fi
644     git branch -f "${local_id}"/{__old__,__main__} || die
645    
646     # recursively checkout submodules
647     if [[ -f ${GIT_WORK_TREE}/.gitmodules ]]; then
648     local submodules
649     _git-r3_set_submodules \
650     "$(<"${GIT_WORK_TREE}"/.gitmodules)"
651    
652     while [[ ${submodules[@]} ]]; do
653     local subname=${submodules[0]}
654     local url=${submodules[1]}
655     local path=${submodules[2]}
656    
657 mgorny 1.19 if [[ ${url} == ./* || ${url} == ../* ]]; then
658     url=${repos[0]%%/}/${url}
659     fi
660    
661 mgorny 1.1 git-r3_checkout "${url}" "${GIT_WORK_TREE}/${path}" \
662     "${local_id}/${subname}"
663    
664     submodules=( "${submodules[@]:3}" ) # shift
665     done
666     fi
667    
668     # keep this *after* submodules
669     export EGIT_DIR=${GIT_DIR}
670     export EGIT_VERSION=${new_commit_id}
671 mgorny 1.21
672     # create a fake '.git' directory to satisfy 'git rev-parse HEAD'
673     GIT_DIR=${GIT_WORK_TREE}/.git
674     git init || die
675     echo "${EGIT_VERSION}" > "${GIT_WORK_TREE}"/.git/HEAD || die
676 mgorny 1.1 }
677    
678     # @FUNCTION: git-r3_peek_remote_ref
679     # @USAGE: [<repo-uri> [<remote-ref>]]
680     # @DESCRIPTION:
681     # Peek the reference in the remote repository and print the matching
682     # (newest) commit SHA1.
683     #
684     # <repo-uri> specifies the repository URIs to fetch from, as a space-
685     # -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
686     #
687     # <remote-ref> specifies the remote ref to peek. It is preferred to use
688     # 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
689     # for tags. Alternatively, 'HEAD' may be used for upstream default
690     # branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
691     # 'HEAD' that is set to a non-null value.
692     #
693     # The operation will be done purely on the remote, without using local
694     # storage. If commit SHA1 is provided as <remote-ref>, the function will
695     # fail due to limitations of git protocol.
696     #
697     # On success, the function returns 0 and writes hexadecimal commit SHA1
698     # to stdout. On failure, the function returns 1.
699     git-r3_peek_remote_ref() {
700     debug-print-function ${FUNCNAME} "$@"
701    
702 mgorny 1.11 local repos
703     if [[ ${1} ]]; then
704     repos=( ${1} )
705     elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
706     repos=( "${EGIT_REPO_URI[@]}" )
707     else
708     repos=( ${EGIT_REPO_URI} )
709 mgorny 1.9 fi
710    
711 mgorny 1.1 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
712     local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
713    
714     [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
715    
716     local r success
717 mgorny 1.9 for r in "${repos[@]}"; do
718 mgorny 1.1 einfo "Peeking ${remote_ref} on ${r} ..." >&2
719    
720     local is_branch lookup_ref
721     if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
722     then
723     is_branch=1
724     lookup_ref=${remote_ref}
725     else
726     # ls-remote by commit is going to fail anyway,
727     # so we may as well pass refs/tags/ABCDEF...
728     lookup_ref=refs/tags/${remote_ref}
729     fi
730    
731     # split on whitespace
732     local ref=(
733     $(git ls-remote "${r}" "${lookup_ref}")
734     )
735    
736     if [[ ${ref[0]} ]]; then
737     echo "${ref[0]}"
738     return 0
739     fi
740     done
741    
742     return 1
743     }
744    
745     git-r3_src_fetch() {
746     debug-print-function ${FUNCNAME} "$@"
747    
748     if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then
749     ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider"
750     ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use"
751     ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones"
752     ewarn "when git-2 eclass becomes deprecated."
753     fi
754    
755     _git-r3_env_setup
756     git-r3_fetch
757     }
758    
759     git-r3_src_unpack() {
760     debug-print-function ${FUNCNAME} "$@"
761    
762     _git-r3_env_setup
763     git-r3_src_fetch
764     git-r3_checkout
765     }
766    
767     # https://bugs.gentoo.org/show_bug.cgi?id=482666
768     git-r3_pkg_outofdate() {
769     debug-print-function ${FUNCNAME} "$@"
770    
771     local new_commit_id=$(git-r3_peek_remote_ref)
772     ewarn "old: ${EGIT_VERSION}"
773     ewarn "new: ${new_commit_id}"
774     [[ ${new_commit_id} && ${old_commit_id} ]] || return 2
775    
776     [[ ${EGIT_VERSION} != ${new_commit_id} ]]
777     }
778    
779     _GIT_R3=1
780     fi

  ViewVC Help
Powered by ViewVC 1.1.20