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

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.45 - (hide annotations) (download)
Mon Jul 7 14:41:56 2014 UTC (2 months, 2 weeks ago) by mgorny
Branch: MAIN
Changes since 1.44: +2 -2 lines
Stop forcing -m0755 on EGIT3_STORE_DIR and parents, bug #516508.

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

  ViewVC Help
Powered by ViewVC 1.1.20