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

Contents of /eclass/git-r3.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (show annotations) (download)
Thu Sep 5 22:40:12 2013 UTC (12 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 # Copyright 1999-2013 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3 # $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.1 2013/09/05 20:24:10 mgorny Exp $
4
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 # 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 else
336 # '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 fi
341
342 # 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 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