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

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (hide annotations) (download)
Thu Sep 5 22:40:12 2013 UTC (11 months, 1 week ago) by mgorny
Branch: MAIN
Changes since 1.1: +22 -14 lines
Do not pass --depth when updating a branch, it trrigers issues in git. Instead, use it for the first fetch only.

1 mgorny 1.1 # Copyright 1999-2013 Gentoo Foundation
2     # Distributed under the terms of the GNU General Public License v2
3 mgorny 1.2 # $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.1 2013/09/05 20:24:10 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     # @ECLASS-VARIABLE: EGIT3_STORE_DIR
33     # @DESCRIPTION:
34     # Storage directory for git sources.
35     #
36     # EGIT3_STORE_DIR=${DISTDIR}/git3-src
37    
38     # @ECLASS-VARIABLE: EGIT_REPO_URI
39     # @REQUIRED
40     # @DESCRIPTION:
41     # URIs to the repository, e.g. git://foo, https://foo. If multiple URIs
42     # are provided, the eclass will consider them as fallback URIs to try
43     # if the first URI does not work.
44     #
45     # It can be overriden via env using ${PN}_LIVE_REPO variable.
46     #
47     # Example:
48     # @CODE
49     # EGIT_REPO_URI="git://a/b.git https://c/d.git"
50     # @CODE
51    
52     # @ECLASS-VARIABLE: EVCS_OFFLINE
53     # @DEFAULT_UNSET
54     # @DESCRIPTION:
55     # If non-empty, this variable prevents any online operations.
56    
57     # @ECLASS-VARIABLE: EGIT_BRANCH
58     # @DEFAULT_UNSET
59     # @DESCRIPTION:
60     # The branch name to check out. If unset, the upstream default (HEAD)
61     # will be used.
62     #
63     # It can be overriden via env using ${PN}_LIVE_BRANCH variable.
64    
65     # @ECLASS-VARIABLE: EGIT_COMMIT
66     # @DEFAULT_UNSET
67     # @DESCRIPTION:
68     # The tag name or commit identifier to check out. If unset, newest
69     # commit from the branch will be used. If set, EGIT_BRANCH will
70     # be ignored.
71     #
72     # It can be overriden via env using ${PN}_LIVE_COMMIT variable.
73    
74     # @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR
75     # @DESCRIPTION:
76     # The directory to check the git sources out to.
77     #
78     # EGIT_CHECKOUT_DIR=${WORKDIR}/${P}
79    
80     # @ECLASS-VARIABLE: EGIT_NONSHALLOW
81     # @DEFAULT_UNSET
82     # @DESCRIPTION:
83     # Disable performing shallow fetches/clones. Shallow clones have
84     # a fair number of limitations. Therefore, if you'd like the eclass to
85     # perform complete clones instead, set this to a non-null value.
86     #
87     # This variable is to be set in make.conf. Ebuilds are not allowed
88     # to set it.
89    
90     # @FUNCTION: _git-r3_env_setup
91     # @INTERNAL
92     # @DESCRIPTION:
93     # Set the eclass variables as necessary for operation. This can involve
94     # setting EGIT_* to defaults or ${PN}_LIVE_* variables.
95     _git-r3_env_setup() {
96     debug-print-function ${FUNCNAME} "$@"
97    
98     local esc_pn livevar
99     esc_pn=${PN//[-+]/_}
100    
101     livevar=${esc_pn}_LIVE_REPO
102     EGIT_REPO_URI=${!livevar:-${EGIT_REPO_URI}}
103     [[ ${!livevar} ]] \
104     && ewarn "Using ${livevar}, no support will be provided"
105    
106     livevar=${esc_pn}_LIVE_BRANCH
107     EGIT_BRANCH=${!livevar:-${EGIT_BRANCH}}
108     [[ ${!livevar} ]] \
109     && ewarn "Using ${livevar}, no support will be provided"
110    
111     livevar=${esc_pn}_LIVE_COMMIT
112     EGIT_COMMIT=${!livevar:-${EGIT_COMMIT}}
113     [[ ${!livevar} ]] \
114     && ewarn "Using ${livevar}, no support will be provided"
115    
116     # Migration helpers. Remove them when git-2 is removed.
117    
118     if [[ ${EGIT_SOURCEDIR} ]]; then
119     eerror "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR. While updating"
120     eerror "your ebuild, please check whether the variable is necessary at all"
121     eerror "since the default has been changed from \${S} to \${WORKDIR}/\${P}."
122     eerror "Therefore, proper setting of S may be sufficient."
123     die "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR."
124     fi
125    
126     if [[ ${EGIT_MASTER} ]]; then
127     eerror "EGIT_MASTER has been removed. Instead, the upstream default (HEAD)"
128     eerror "is used by the eclass. Please remove the assignment or use EGIT_BRANCH"
129     eerror "as necessary."
130     die "EGIT_MASTER has been removed."
131     fi
132    
133     if [[ ${EGIT_HAS_SUBMODULES} ]]; then
134     eerror "EGIT_HAS_SUBMODULES has been removed. The eclass no longer needs"
135     eerror "to switch the clone type in order to support submodules and therefore"
136     eerror "submodules are detected and fetched automatically."
137     die "EGIT_HAS_SUBMODULES is no longer necessary."
138     fi
139    
140     if [[ ${EGIT_PROJECT} ]]; then
141     eerror "EGIT_PROJECT has been removed. Instead, the eclass determines"
142     eerror "the local clone path using path in canonical EGIT_REPO_URI."
143     eerror "If the current algorithm causes issues for you, please report a bug."
144     die "EGIT_PROJECT is no longer necessary."
145     fi
146    
147     if [[ ${EGIT_BOOTSTRAP} ]]; then
148     eerror "EGIT_BOOTSTRAP has been removed. Please create proper src_prepare()"
149     eerror "instead."
150     die "EGIT_BOOTSTRAP has been removed."
151     fi
152    
153     if [[ ${EGIT_NOUNPACK} ]]; then
154     eerror "EGIT_NOUNPACK has been removed. The eclass no longer calls default"
155     eerror "unpack function. If necessary, please declare proper src_unpack()."
156     die "EGIT_NOUNPACK has been removed."
157     fi
158     }
159    
160     # @FUNCTION: _git-r3_set_gitdir
161     # @USAGE: <repo-uri>
162     # @INTERNAL
163     # @DESCRIPTION:
164     # Obtain the local repository path and set it as GIT_DIR. Creates
165     # a new repository if necessary.
166     #
167     # <repo-uri> may be used to compose the path. It should therefore be
168     # a canonical URI to the repository.
169     _git-r3_set_gitdir() {
170     debug-print-function ${FUNCNAME} "$@"
171    
172     local repo_name=${1#*://*/}
173    
174     # strip common prefixes to make paths more likely to match
175     # e.g. git://X/Y.git vs https://X/git/Y.git
176     # (but just one of the prefixes)
177     case "${repo_name}" in
178     # cgit can proxy requests to git
179     cgit/*) repo_name=${repo_name#cgit/};;
180     # pretty common
181     git/*) repo_name=${repo_name#git/};;
182     # gentoo.org
183     gitroot/*) repo_name=${repo_name#gitroot/};;
184     # google code, sourceforge
185     p/*) repo_name=${repo_name#p/};;
186     # kernel.org
187     pub/scm/*) repo_name=${repo_name#pub/scm/};;
188     esac
189     # ensure a .git suffix, same reason
190     repo_name=${repo_name%.git}.git
191     # now replace all the slashes
192     repo_name=${repo_name//\//_}
193    
194     local distdir=${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}}
195     : ${EGIT3_STORE_DIR:=${distdir}/git3-src}
196    
197     GIT_DIR=${EGIT3_STORE_DIR}/${repo_name}
198    
199     if [[ ! -d ${EGIT3_STORE_DIR} ]]; then
200     (
201     addwrite /
202     mkdir -m0755 -p "${EGIT3_STORE_DIR}"
203     ) || die "Unable to create ${EGIT3_STORE_DIR}"
204     fi
205    
206     addwrite "${EGIT3_STORE_DIR}"
207     if [[ ! -d ${GIT_DIR} ]]; then
208     mkdir "${GIT_DIR}" || die
209     git init --bare || die
210    
211     # avoid auto-unshallow :)
212     touch "${GIT_DIR}"/shallow || die
213     fi
214     }
215    
216     # @FUNCTION: _git-r3_set_submodules
217     # @USAGE: <file-contents>
218     # @INTERNAL
219     # @DESCRIPTION:
220     # Parse .gitmodules contents passed as <file-contents>
221     # as in "$(cat .gitmodules)"). Composes a 'submodules' array that
222     # contains in order (name, URL, path) for each submodule.
223     _git-r3_set_submodules() {
224     debug-print-function ${FUNCNAME} "$@"
225    
226     local data=${1}
227    
228     # ( name url path ... )
229     submodules=()
230    
231     local l
232     while read l; do
233     # submodule.<path>.path=<path>
234     # submodule.<path>.url=<url>
235     [[ ${l} == submodule.*.url=* ]] || continue
236    
237     l=${l#submodule.}
238     local subname=${l%%.url=*}
239    
240     submodules+=(
241     "${subname}"
242     "$(echo "${data}" | git config -f /dev/fd/0 \
243     submodule."${subname}".url)"
244     "$(echo "${data}" | git config -f /dev/fd/0 \
245     submodule."${subname}".path)"
246     )
247     done < <(echo "${data}" | git config -f /dev/fd/0 -l)
248     }
249    
250     # @FUNCTION: git-r3_fetch
251     # @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]]
252     # @DESCRIPTION:
253     # Fetch new commits to the local clone of repository.
254     #
255     # <repo-uri> specifies the repository URIs to fetch from, as a space-
256     # -separated list. The first URI will be used as repository group
257     # identifier and therefore must be used consistently. When not
258     # specified, defaults to ${EGIT_REPO_URI}.
259     #
260     # <remote-ref> specifies the remote ref or commit id to fetch.
261     # It is preferred to use 'refs/heads/<branch-name>' for branches
262     # and 'refs/tags/<tag-name>' for tags. Other options are 'HEAD'
263     # for upstream default branch and hexadecimal commit SHA1. Defaults
264     # to the first of EGIT_COMMIT, EGIT_BRANCH or literal 'HEAD' that
265     # is set to a non-null value.
266     #
267     # <local-id> specifies the local branch identifier that will be used to
268     # locally store the fetch result. It should be unique to multiple
269     # fetches within the repository that can be performed at the same time
270     # (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT}.
271     # This default should be fine unless you are fetching multiple trees
272     # from the same repository in the same ebuild.
273     #
274     # The fetch operation will affect the EGIT_STORE only. It will not touch
275     # the working copy, nor export any environment variables.
276     # If the repository contains submodules, they will be fetched
277     # recursively.
278     git-r3_fetch() {
279     debug-print-function ${FUNCNAME} "$@"
280    
281     local repos=( ${1:-${EGIT_REPO_URI}} )
282     local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
283     local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
284     local local_id=${3:-${CATEGORY}/${PN}/${SLOT}}
285     local local_ref=refs/heads/${local_id}/__main__
286    
287     [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
288    
289     local -x GIT_DIR
290     _git-r3_set_gitdir ${repos[0]}
291    
292     # try to fetch from the remote
293     local r success
294     for r in ${repos[@]}; do
295     einfo "Fetching ${remote_ref} from ${r} ..."
296    
297     local is_branch lookup_ref
298     if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
299     then
300     is_branch=1
301     lookup_ref=${remote_ref}
302     else
303     # ls-remote by commit is going to fail anyway,
304     # so we may as well pass refs/tags/ABCDEF...
305     lookup_ref=refs/tags/${remote_ref}
306     fi
307    
308     # first, try ls-remote to see if ${remote_ref} is a real ref
309     # and not a commit id. if it succeeds, we can pass ${remote_ref}
310     # to 'fetch'. otherwise, we will just fetch everything
311    
312     # split on whitespace
313     local ref=(
314     $(git ls-remote "${r}" "${lookup_ref}")
315     )
316    
317     local ref_param=()
318     if [[ ! ${ref[0]} ]]; then
319     local EGIT_NONSHALLOW=1
320     fi
321    
322 mgorny 1.2 # 1. if we need a non-shallow clone and we have a shallow one,
323     # we need to unshallow it explicitly.
324     # 2. if we want a shallow clone, we just pass '--depth 1'
325     # to the first fetch in the repo. passing '--depth'
326     # to further requests usually results in more data being
327     # downloaded than without it.
328     # 3. in any other case, we just do plain 'git fetch' and let
329     # git to do its best (on top of shallow or non-shallow repo).
330    
331     if [[ ${EGIT_NONSHALLOW} ]]; then
332     if [[ -f ${GIT_DIR}/shallow ]]; then
333     ref_param+=( --unshallow )
334     fi
335 mgorny 1.1 else
336 mgorny 1.2 # 'git show-ref --heads' returns 1 when there are no branches
337     if ! git show-ref --heads -q; then
338     ref_param+=( --depth 1 )
339     fi
340 mgorny 1.1 fi
341    
342 mgorny 1.2 # now, another important thing. we may only fetch a remote
343     # branch directly to a local branch. Otherwise, we need to fetch
344     # the commit and re-create the branch on top of it.
345    
346 mgorny 1.1 if [[ ${ref[0]} ]]; then
347     if [[ ${is_branch} ]]; then
348     ref_param+=( -f "${remote_ref}:${local_id}/__main__" )
349     else
350     ref_param+=( "refs/tags/${remote_ref}" )
351     fi
352     fi
353    
354     # if ${remote_ref} is branch or tag, ${ref[@]} will contain
355     # the respective commit id. otherwise, it will be an empty
356     # array, so the following won't evaluate to a parameter.
357     set -- git fetch --no-tags "${r}" "${ref_param[@]}"
358     echo "${@}" >&2
359     if "${@}"; then
360     if [[ ! ${is_branch} ]]; then
361     set -- git branch -f "${local_id}/__main__" \
362     "${ref[0]:-${remote_ref}}"
363     echo "${@}" >&2
364     if ! "${@}"; then
365     die "Creating branch for ${remote_ref} failed (wrong ref?)."
366     fi
367     fi
368    
369     success=1
370     break
371     fi
372     done
373     [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
374    
375     # recursively fetch submodules
376     if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
377     local submodules
378     _git-r3_set_submodules \
379     "$(git cat-file -p "${local_ref}":.gitmodules || die)"
380    
381     while [[ ${submodules[@]} ]]; do
382     local subname=${submodules[0]}
383     local url=${submodules[1]}
384     local path=${submodules[2]}
385     local commit=$(git rev-parse "${local_ref}:${path}")
386    
387     if [[ ! ${commit} ]]; then
388     die "Unable to get commit id for submodule ${subname}"
389     fi
390    
391     git-r3_fetch "${url}" "${commit}" "${local_id}/${subname}"
392    
393     submodules=( "${submodules[@]:3}" ) # shift
394     done
395     fi
396     }
397    
398     # @FUNCTION: git-r3_checkout
399     # @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
400     # @DESCRIPTION:
401     # Check the previously fetched tree to the working copy.
402     #
403     # <repo-uri> specifies the repository URIs, as a space-separated list.
404     # The first URI will be used as repository group identifier
405     # and therefore must be used consistently with git-r3_fetch.
406     # The remaining URIs are not used and therefore may be omitted.
407     # When not specified, defaults to ${EGIT_REPO_URI}.
408     #
409     # <checkout-path> specifies the path to place the checkout. It defaults
410     # to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
411     #
412     # <local-id> needs to specify the local identifier that was used
413     # for respective git-r3_fetch.
414     #
415     # The checkout operation will write to the working copy, and export
416     # the repository state into the environment. If the repository contains
417     # submodules, they will be checked out recursively.
418     git-r3_checkout() {
419     debug-print-function ${FUNCNAME} "$@"
420    
421     local repos=( ${1:-${EGIT_REPO_URI}} )
422     local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
423     local local_id=${3:-${CATEGORY}/${PN}/${SLOT}}
424    
425     local -x GIT_DIR GIT_WORK_TREE
426     _git-r3_set_gitdir ${repos[0]}
427     GIT_WORK_TREE=${out_dir}
428     mkdir -p "${GIT_WORK_TREE}"
429    
430     einfo "Checking out ${repos[0]} to ${out_dir} ..."
431    
432     if ! git cat-file -e refs/heads/"${local_id}"/__main__
433     then
434     if [[ ${EVCS_OFFLINE} ]]; then
435     die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE."
436     else
437     die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
438     fi
439     fi
440    
441     set -- git checkout -f "${local_id}"/__main__ .
442     echo "${@}" >&2
443     "${@}" || die "git checkout ${local_id}/__main__ failed"
444    
445     # diff against previous revision (if any)
446     local new_commit_id=$(git rev-parse --verify "${local_id}"/__main__)
447     local old_commit_id=$(
448     git rev-parse --verify "${local_id}"/__old__ 2>/dev/null
449     )
450    
451     if [[ ! ${old_commit_id} ]]; then
452     echo "GIT NEW branch -->"
453     echo " repository: ${repos[0]}"
454     echo " at the commit: ${new_commit_id}"
455     else
456     echo "GIT update -->"
457     echo " repository: ${repos[0]}"
458     # write out message based on the revisions
459     if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
460     echo " updating from commit: ${old_commit_id}"
461     echo " to commit: ${new_commit_id}"
462    
463     git --no-pager diff --stat \
464     ${old_commit_id}..${new_commit_id}
465     else
466     echo " at the commit: ${new_commit_id}"
467     fi
468     fi
469     git branch -f "${local_id}"/{__old__,__main__} || die
470    
471     # recursively checkout submodules
472     if [[ -f ${GIT_WORK_TREE}/.gitmodules ]]; then
473     local submodules
474     _git-r3_set_submodules \
475     "$(<"${GIT_WORK_TREE}"/.gitmodules)"
476    
477     while [[ ${submodules[@]} ]]; do
478     local subname=${submodules[0]}
479     local url=${submodules[1]}
480     local path=${submodules[2]}
481    
482     git-r3_checkout "${url}" "${GIT_WORK_TREE}/${path}" \
483     "${local_id}/${subname}"
484    
485     submodules=( "${submodules[@]:3}" ) # shift
486     done
487     fi
488    
489     # keep this *after* submodules
490     export EGIT_DIR=${GIT_DIR}
491     export EGIT_VERSION=${new_commit_id}
492     }
493    
494     # @FUNCTION: git-r3_peek_remote_ref
495     # @USAGE: [<repo-uri> [<remote-ref>]]
496     # @DESCRIPTION:
497     # Peek the reference in the remote repository and print the matching
498     # (newest) commit SHA1.
499     #
500     # <repo-uri> specifies the repository URIs to fetch from, as a space-
501     # -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
502     #
503     # <remote-ref> specifies the remote ref to peek. It is preferred to use
504     # 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
505     # for tags. Alternatively, 'HEAD' may be used for upstream default
506     # branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
507     # 'HEAD' that is set to a non-null value.
508     #
509     # The operation will be done purely on the remote, without using local
510     # storage. If commit SHA1 is provided as <remote-ref>, the function will
511     # fail due to limitations of git protocol.
512     #
513     # On success, the function returns 0 and writes hexadecimal commit SHA1
514     # to stdout. On failure, the function returns 1.
515     git-r3_peek_remote_ref() {
516     debug-print-function ${FUNCNAME} "$@"
517    
518     local repos=( ${1:-${EGIT_REPO_URI}} )
519     local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
520     local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
521    
522     [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
523    
524     local r success
525     for r in ${repos[@]}; do
526     einfo "Peeking ${remote_ref} on ${r} ..." >&2
527    
528     local is_branch lookup_ref
529     if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
530     then
531     is_branch=1
532     lookup_ref=${remote_ref}
533     else
534     # ls-remote by commit is going to fail anyway,
535     # so we may as well pass refs/tags/ABCDEF...
536     lookup_ref=refs/tags/${remote_ref}
537     fi
538    
539     # split on whitespace
540     local ref=(
541     $(git ls-remote "${r}" "${lookup_ref}")
542     )
543    
544     if [[ ${ref[0]} ]]; then
545     echo "${ref[0]}"
546     return 0
547     fi
548     done
549    
550     return 1
551     }
552    
553     git-r3_src_fetch() {
554     debug-print-function ${FUNCNAME} "$@"
555    
556     [[ ${EVCS_OFFLINE} ]] && return
557    
558     if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then
559     ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider"
560     ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use"
561     ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones"
562     ewarn "when git-2 eclass becomes deprecated."
563     fi
564    
565     _git-r3_env_setup
566     git-r3_fetch
567     }
568    
569     git-r3_src_unpack() {
570     debug-print-function ${FUNCNAME} "$@"
571    
572     _git-r3_env_setup
573     git-r3_src_fetch
574     git-r3_checkout
575     }
576    
577     # https://bugs.gentoo.org/show_bug.cgi?id=482666
578     git-r3_pkg_outofdate() {
579     debug-print-function ${FUNCNAME} "$@"
580    
581     local new_commit_id=$(git-r3_peek_remote_ref)
582     ewarn "old: ${EGIT_VERSION}"
583     ewarn "new: ${new_commit_id}"
584     [[ ${new_commit_id} && ${old_commit_id} ]] || return 2
585    
586     [[ ${EGIT_VERSION} != ${new_commit_id} ]]
587     }
588    
589     _GIT_R3=1
590     fi

  ViewVC Help
Powered by ViewVC 1.1.20