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

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.34 - (hide annotations) (download)
Sun Mar 2 11:48:28 2014 UTC (7 months, 2 weeks ago) by mgorny
Branch: MAIN
Changes since 1.33: +8 -3 lines
Auto-unshallow when fetching by commit hash.

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

  ViewVC Help
Powered by ViewVC 1.1.20