1 # Copyright 1999-2015 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
5 # @ECLASS: git-r3.eclass
7 # Michał Górny <mgorny@gentoo.org>
8 # @BLURB: Eclass for fetching and unpacking git repositories.
10 # Third generation eclass for easing maintenance of live ebuilds using
11 # git as remote repository.
17 die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
21 if [[ ! ${_GIT_R3} ]]; then
27 EXPORT_FUNCTIONS src_unpack
29 if [[ ! ${_GIT_R3} ]]; then
31 if [[ ! ${_INHERITED_BY_GIT_2} ]]; then
32 DEPEND=">=dev-vcs/git-1.8.2.1"
35 # @ECLASS-VARIABLE: EGIT_CLONE_TYPE
37 # Type of clone that should be used against the remote repository.
38 # This can be either of: 'mirror', 'single', 'shallow'.
40 # This is intended to be set by user in make.conf. Ebuilds are supposed
41 # to set EGIT_MIN_CLONE_TYPE if necessary instead.
43 # 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.
50 # 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.
58 # 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.
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 : ${EGIT_CLONE_TYPE:=single}
72 # @ECLASS-VARIABLE: EGIT_MIN_CLONE_TYPE
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.
79 # This variable is intended to be used by ebuilds only. Users are
80 # supposed to set EGIT_CLONE_TYPE instead.
82 # A common case is to use 'single' whenever the build system requires
83 # 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 : ${EGIT_MIN_CLONE_TYPE:=shallow}
89 # @ECLASS-VARIABLE: EGIT3_STORE_DIR
91 # Storage directory for git sources.
93 # This is intended to be set by user in make.conf. Ebuilds must not set
96 # EGIT3_STORE_DIR=${DISTDIR}/git3-src
98 # @ECLASS-VARIABLE: EGIT_MIRROR_URI
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.
104 # The mirror needs to follow EGIT3_STORE_DIR structure. The directory
105 # created by eclass can be used for that purpose.
109 # EGIT_MIRROR_URI="git://mirror.lan/"
112 # @ECLASS-VARIABLE: EGIT_REPO_URI
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. For supported URI syntaxes, read up
118 # the manpage for git-clone(1).
120 # It can be overriden via env using ${PN}_LIVE_REPO variable.
122 # Can be a whitespace-separated list or an array.
126 # EGIT_REPO_URI="git://a/b.git https://c/d.git"
129 # @ECLASS-VARIABLE: EVCS_OFFLINE
132 # If non-empty, this variable prevents any online operations.
134 # @ECLASS-VARIABLE: EVCS_UMASK
137 # Set this variable to a custom umask. This is intended to be set by
138 # users. By setting this to something like 002, it can make life easier
139 # for people who do development as non-root (but are in the portage
140 # group), and then switch over to building with FEATURES=userpriv.
141 # Or vice-versa. Shouldn't be a security issue here as anyone who has
142 # portage group write access already can screw the system over in more
145 # @ECLASS-VARIABLE: EGIT_BRANCH
148 # The branch name to check out. If unset, the upstream default (HEAD)
151 # It can be overriden via env using ${PN}_LIVE_BRANCH variable.
153 # @ECLASS-VARIABLE: EGIT_COMMIT
156 # The tag name or commit identifier to check out. If unset, newest
157 # commit from the branch will be used. If set, EGIT_BRANCH will
160 # It can be overriden via env using ${PN}_LIVE_COMMIT variable.
162 # @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR
164 # The directory to check the git sources out to.
166 # EGIT_CHECKOUT_DIR=${WORKDIR}/${P}
168 # @FUNCTION: _git-r3_env_setup
171 # Set the eclass variables as necessary for operation. This can involve
172 # setting EGIT_* to defaults or ${PN}_LIVE_* variables.
173 _git-r3_env_setup() {
174 debug-print-function ${FUNCNAME} "$@"
176 # check the clone type
177 case "${EGIT_CLONE_TYPE}" in
178 mirror|single+tags|single|shallow)
181 die "Invalid EGIT_CLONE_TYPE=${EGIT_CLONE_TYPE}"
183 case "${EGIT_MIN_CLONE_TYPE}" in
187 if [[ ${EGIT_CLONE_TYPE} == shallow ]]; then
188 einfo "git-r3: ebuild needs to be cloned in '\e[1msingle\e[22m' mode, adjusting"
189 EGIT_CLONE_TYPE=single
193 if [[ ${EGIT_CLONE_TYPE} == shallow || ${EGIT_CLONE_TYPE} == single ]]; then
194 einfo "git-r3: ebuild needs to be cloned in '\e[1msingle+tags\e[22m' mode, adjusting"
195 EGIT_CLONE_TYPE=single+tags
199 if [[ ${EGIT_CLONE_TYPE} != mirror ]]; then
200 einfo "git-r3: ebuild needs to be cloned in '\e[1mmirror\e[22m' mode, adjusting"
201 EGIT_CLONE_TYPE=mirror
205 die "Invalid EGIT_MIN_CLONE_TYPE=${EGIT_MIN_CLONE_TYPE}"
211 livevar=${esc_pn}_LIVE_REPO
212 EGIT_REPO_URI=${!livevar:-${EGIT_REPO_URI}}
214 && ewarn "Using ${livevar}, no support will be provided"
216 livevar=${esc_pn}_LIVE_BRANCH
217 EGIT_BRANCH=${!livevar:-${EGIT_BRANCH}}
219 && ewarn "Using ${livevar}, no support will be provided"
221 livevar=${esc_pn}_LIVE_COMMIT
222 EGIT_COMMIT=${!livevar:-${EGIT_COMMIT}}
224 && ewarn "Using ${livevar}, no support will be provided"
226 # Migration helpers. Remove them when git-2 is removed.
228 if [[ ${EGIT_SOURCEDIR} ]]; then
229 eerror "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR. While updating"
230 eerror "your ebuild, please check whether the variable is necessary at all"
231 eerror "since the default has been changed from \${S} to \${WORKDIR}/\${P}."
232 eerror "Therefore, proper setting of S may be sufficient."
233 die "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR."
236 if [[ ${EGIT_MASTER} ]]; then
237 eerror "EGIT_MASTER has been removed. Instead, the upstream default (HEAD)"
238 eerror "is used by the eclass. Please remove the assignment or use EGIT_BRANCH"
239 eerror "as necessary."
240 die "EGIT_MASTER has been removed."
243 if [[ ${EGIT_HAS_SUBMODULES} ]]; then
244 eerror "EGIT_HAS_SUBMODULES has been removed. The eclass no longer needs"
245 eerror "to switch the clone type in order to support submodules and therefore"
246 eerror "submodules are detected and fetched automatically."
247 die "EGIT_HAS_SUBMODULES is no longer necessary."
250 if [[ ${EGIT_PROJECT} ]]; then
251 eerror "EGIT_PROJECT has been removed. Instead, the eclass determines"
252 eerror "the local clone path using path in canonical EGIT_REPO_URI."
253 eerror "If the current algorithm causes issues for you, please report a bug."
254 die "EGIT_PROJECT is no longer necessary."
257 if [[ ${EGIT_BOOTSTRAP} ]]; then
258 eerror "EGIT_BOOTSTRAP has been removed. Please create proper src_prepare()"
260 die "EGIT_BOOTSTRAP has been removed."
263 if [[ ${EGIT_NOUNPACK} ]]; then
264 eerror "EGIT_NOUNPACK has been removed. The eclass no longer calls default"
265 eerror "unpack function. If necessary, please declare proper src_unpack()."
266 die "EGIT_NOUNPACK has been removed."
270 # @FUNCTION: _git-r3_set_gitdir
274 # Obtain the local repository path and set it as GIT_DIR. Creates
275 # a new repository if necessary.
277 # <repo-uri> may be used to compose the path. It should therefore be
278 # a canonical URI to the repository.
279 _git-r3_set_gitdir() {
280 debug-print-function ${FUNCNAME} "$@"
282 local repo_name=${1#*://*/}
284 # strip the trailing slash
285 repo_name=${repo_name%/}
287 # strip common prefixes to make paths more likely to match
288 # e.g. git://X/Y.git vs https://X/git/Y.git
289 # (but just one of the prefixes)
290 case "${repo_name}" in
291 # gnome.org... who else?
292 browse/*) repo_name=${repo_name#browse/};;
293 # cgit can proxy requests to git
294 cgit/*) repo_name=${repo_name#cgit/};;
296 git/*) repo_name=${repo_name#git/};;
298 gitroot/*) repo_name=${repo_name#gitroot/};;
299 # google code, sourceforge
300 p/*) repo_name=${repo_name#p/};;
302 pub/scm/*) repo_name=${repo_name#pub/scm/};;
304 # ensure a .git suffix, same reason
305 repo_name=${repo_name%.git}.git
306 # now replace all the slashes
307 repo_name=${repo_name//\//_}
309 local distdir=${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}}
310 : ${EGIT3_STORE_DIR:=${distdir}/git3-src}
312 GIT_DIR=${EGIT3_STORE_DIR}/${repo_name}
314 if [[ ! -d ${EGIT3_STORE_DIR} ]]; then
317 mkdir -p "${EGIT3_STORE_DIR}"
318 ) || die "Unable to create ${EGIT3_STORE_DIR}"
321 addwrite "${EGIT3_STORE_DIR}"
322 if [[ ! -d ${GIT_DIR} ]]; then
324 if [[ ${EVCS_UMASK} ]]; then
326 umask "${EVCS_UMASK}" || die "Bad options to umask: ${EVCS_UMASK}"
328 mkdir "${GIT_DIR}" || die
329 git init --bare || die
330 if [[ ${saved_umask} ]]; then
331 umask "${saved_umask}" || die
336 # @FUNCTION: _git-r3_set_submodules
337 # @USAGE: <file-contents>
340 # Parse .gitmodules contents passed as <file-contents>
341 # as in "$(cat .gitmodules)"). Composes a 'submodules' array that
342 # contains in order (name, URL, path) for each submodule.
343 _git-r3_set_submodules() {
344 debug-print-function ${FUNCNAME} "$@"
348 # ( name url path ... )
353 # submodule.<path>.path=<path>
354 # submodule.<path>.url=<url>
355 [[ ${l} == submodule.*.url=* ]] || continue
358 local subname=${l%%.url=*}
360 # skip modules that have 'update = none', bug #487262.
361 local upd=$(echo "${data}" | git config -f /dev/fd/0 \
362 submodule."${subname}".update)
363 [[ ${upd} == none ]] && continue
365 # https://github.com/git/git/blob/master/refs.c#L39
366 # for now, we just filter /. because of #572312
367 local enc_subname=${subname//\/.//_}
368 [[ ${enc_subname} == .* ]] && enc_subname=_${enc_subname#.}
372 "$(echo "${data}" | git config -f /dev/fd/0 \
373 submodule."${subname}".url || die)"
374 "$(echo "${data}" | git config -f /dev/fd/0 \
375 submodule."${subname}".path || die)"
377 done < <(echo "${data}" | git config -f /dev/fd/0 -l || die)
380 # @FUNCTION: _git-r3_set_subrepos
381 # @USAGE: <submodule-uri> <parent-repo-uri>...
384 # Create 'subrepos' array containing absolute (canonical) submodule URIs
385 # for the given <submodule-uri>. If the URI is relative, URIs will be
386 # constructed using all <parent-repo-uri>s. Otherwise, this single URI
387 # will be placed in the array.
388 _git-r3_set_subrepos() {
389 debug-print-function ${FUNCNAME} "$@"
392 subrepos=( "${@:2}" )
394 if [[ ${suburl} == ./* || ${suburl} == ../* ]]; then
395 # drop all possible trailing slashes for consistency
396 subrepos=( "${subrepos[@]%%/}" )
399 if [[ ${suburl} == ./* ]]; then
401 elif [[ ${suburl} == ../* ]]; then
404 # XXX: correctness checking
406 # drop the last path component
407 subrepos=( "${subrepos[@]%/*}" )
408 # and then the trailing slashes, again
409 subrepos=( "${subrepos[@]%%/}" )
415 # append the preprocessed path to the preprocessed URIs
416 subrepos=( "${subrepos[@]/%//${suburl}}")
418 subrepos=( "${suburl}" )
423 # @FUNCTION: _git-r3_is_local_repo
427 # Determine whether the given URI specifies a local (on-disk)
429 _git-r3_is_local_repo() {
430 debug-print-function ${FUNCNAME} "$@"
434 [[ ${uri} == file://* || ${uri} == /* ]]
437 # @FUNCTION: _git-r3_find_head
441 # Given a ref to which remote HEAD was fetched, try to find
442 # a branch matching the commit. Expects 'git show-ref'
443 # or 'git ls-remote' output on stdin.
444 _git-r3_find_head() {
445 debug-print-function ${FUNCNAME} "$@"
448 local head_hash=$(git rev-parse --verify "${1}" || die)
451 # TODO: some transports support peeking at symbolic remote refs
452 # find a way to use that rather than guessing
454 # (based on guess_remote_head() in git-1.9.0/remote.c)
457 # look for matching head
458 if [[ ${h} == ${head_hash} ]]; then
459 # either take the first matching ref, or master if it is there
460 if [[ ! ${matching_ref} || ${ref} == refs/heads/master ]]; then
466 if [[ ! ${matching_ref} ]]; then
467 die "Unable to find a matching branch for remote HEAD (${head_hash})"
470 echo "${matching_ref}"
473 # @FUNCTION: git-r3_fetch
474 # @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]]
476 # Fetch new commits to the local clone of repository.
478 # <repo-uri> specifies the repository URIs to fetch from, as a space-
479 # -separated list. The first URI will be used as repository group
480 # identifier and therefore must be used consistently. When not
481 # specified, defaults to ${EGIT_REPO_URI}.
483 # <remote-ref> specifies the remote ref or commit id to fetch.
484 # It is preferred to use 'refs/heads/<branch-name>' for branches
485 # and 'refs/tags/<tag-name>' for tags. Other options are 'HEAD'
486 # for upstream default branch and hexadecimal commit SHA1. Defaults
487 # to the first of EGIT_COMMIT, EGIT_BRANCH or literal 'HEAD' that
488 # is set to a non-null value.
490 # <local-id> specifies the local branch identifier that will be used to
491 # locally store the fetch result. It should be unique to multiple
492 # fetches within the repository that can be performed at the same time
493 # (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT%/*}.
494 # This default should be fine unless you are fetching multiple trees
495 # from the same repository in the same ebuild.
497 # The fetch operation will affect the EGIT_STORE only. It will not touch
498 # the working copy, nor export any environment variables.
499 # If the repository contains submodules, they will be fetched
502 debug-print-function ${FUNCNAME} "$@"
504 [[ ${EVCS_OFFLINE} ]] && return
509 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
510 repos=( "${EGIT_REPO_URI[@]}" )
512 repos=( ${EGIT_REPO_URI} )
515 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
516 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
517 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
518 local local_ref=refs/git-r3/${local_id}/__main__
520 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
523 _git-r3_set_gitdir "${repos[0]}"
525 # prepend the local mirror if applicable
526 if [[ ${EGIT_MIRROR_URI} ]]; then
528 "${EGIT_MIRROR_URI%/}/${GIT_DIR##*/}"
533 # try to fetch from the remote
534 local r success saved_umask
535 if [[ ${EVCS_UMASK} ]]; then
537 umask "${EVCS_UMASK}" || die "Bad options to umask: ${EVCS_UMASK}"
539 for r in "${repos[@]}"; do
540 einfo "Fetching \e[1m${r}\e[22m ..."
542 local fetch_command=( git fetch "${r}" )
543 local clone_type=${EGIT_CLONE_TYPE}
545 if [[ ${r} == https://* ]] && ! ROOT=/ has_version 'dev-vcs/git[curl]'; then
546 eerror "git-r3: fetching from https:// requested. In order to support https,"
547 eerror "dev-vcs/git needs to be built with USE=curl. Example solution:"
549 eerror " echo dev-vcs/git curl >> /etc/portage/package.use"
550 eerror " emerge -1v dev-vcs/git"
551 die "dev-vcs/git built with USE=curl required."
554 if [[ ${r} == https://code.google.com/* ]]; then
555 # Google Code has special magic on top of git that:
556 # 1) can't handle shallow clones at all,
557 # 2) fetches duplicately when tags are pulled in with branch
558 # so automatically switch to single+tags mode.
559 if [[ ${clone_type} == shallow ]]; then
560 einfo " Google Code does not support shallow clones"
561 einfo " using \e[1mEGIT_CLONE_TYPE=single+tags\e[22m"
562 clone_type=single+tags
563 elif [[ ${clone_type} == single ]]; then
564 einfo " git-r3: Google Code does not send tags properly in 'single' mode"
565 einfo " using \e[1mEGIT_CLONE_TYPE=single+tags\e[22m"
566 clone_type=single+tags
570 if [[ ${clone_type} == mirror ]]; then
573 # mirror the remote branches as local branches
574 "+refs/heads/*:refs/heads/*"
575 # pull tags explicitly in order to prune them properly
576 "+refs/tags/*:refs/tags/*"
577 # notes in case something needs them
578 "+refs/notes/*:refs/notes/*"
579 # and HEAD in case we need the default branch
580 # (we keep it in refs/git-r3 since otherwise --prune interferes)
581 "+HEAD:refs/git-r3/HEAD"
583 else # single or shallow
584 local fetch_l fetch_r
586 if [[ ${remote_ref} == HEAD ]]; then
589 elif [[ ${remote_ref} == refs/* ]]; then
590 # regular branch, tag or some other explicit ref
591 fetch_l=${remote_ref}
593 # tag or commit id...
594 # let ls-remote figure it out
595 local tagref=$(git ls-remote "${r}" "refs/tags/${remote_ref}")
597 # if it was a tag, ls-remote obtained a hash
598 if [[ ${tagref} ]]; then
600 fetch_l=refs/tags/${remote_ref}
603 # so we need to fetch the whole branch
604 if [[ ${branch} ]]; then
610 # fetching by commit in shallow mode? can't do.
611 if [[ ${clone_type} == shallow ]]; then
617 if [[ ${fetch_l} == HEAD ]]; then
618 fetch_r=refs/git-r3/HEAD
624 "+${fetch_l}:${fetch_r}"
627 if [[ ${clone_type} == single+tags ]]; then
629 # pull tags explicitly as requested
630 "+refs/tags/*:refs/tags/*"
635 if [[ ${clone_type} == shallow ]]; then
636 if _git-r3_is_local_repo; then
637 # '--depth 1' causes sandbox violations with local repos
640 elif [[ ! $(git rev-parse --quiet --verify "${fetch_r}") ]]
642 # use '--depth 1' when fetching a new branch
643 fetch_command+=( --depth 1 )
645 else # non-shallow mode
646 if [[ -f ${GIT_DIR}/shallow ]]; then
647 fetch_command+=( --unshallow )
651 set -- "${fetch_command[@]}"
654 if [[ ${clone_type} == mirror ]]; then
655 # find remote HEAD and update our HEAD properly
656 git symbolic-ref HEAD \
657 "$(_git-r3_find_head refs/git-r3/HEAD \
658 < <(git show-ref --heads || die))" \
659 || die "Unable to update HEAD"
660 else # single or shallow
661 if [[ ${fetch_l} == HEAD ]]; then
662 # find out what branch we fetched as HEAD
663 local head_branch=$(_git-r3_find_head \
665 < <(git ls-remote --heads "${r}" || die))
667 # and move it to its regular place
668 git update-ref --no-deref "${head_branch}" \
670 || die "Unable to sync HEAD branch ${head_branch}"
671 git symbolic-ref HEAD "${head_branch}" \
672 || die "Unable to update HEAD"
676 # now let's see what the user wants from us
677 local full_remote_ref=$(
678 git rev-parse --verify --symbolic-full-name "${remote_ref}"
681 if [[ ${full_remote_ref} ]]; then
682 # when we are given a ref, create a symbolic ref
683 # so that we preserve the actual argument
684 set -- git symbolic-ref "${local_ref}" "${full_remote_ref}"
686 # otherwise, we were likely given a commit id
687 set -- git update-ref --no-deref "${local_ref}" "${remote_ref}"
692 die "Referencing ${remote_ref} failed (wrong ref?)."
699 if [[ ${saved_umask} ]]; then
700 umask "${saved_umask}" || die
702 [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
704 # submodules can reference commits in any branch
705 # always use the 'mirror' mode to accomodate that, bug #503332
706 local EGIT_CLONE_TYPE=mirror
708 # recursively fetch submodules
709 if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
711 _git-r3_set_submodules \
712 "$(git cat-file -p "${local_ref}":.gitmodules || die)"
714 while [[ ${submodules[@]} ]]; do
715 local subname=${submodules[0]}
716 local url=${submodules[1]}
717 local path=${submodules[2]}
719 # use only submodules for which path does exist
720 # (this is in par with 'git submodule'), bug #551100
721 # note: git cat-file does not work for submodules
722 if [[ $(git ls-tree -d "${local_ref}" "${path}") ]]
724 local commit=$(git rev-parse "${local_ref}:${path}" || die)
726 if [[ ! ${commit} ]]; then
727 die "Unable to get commit id for submodule ${subname}"
731 _git-r3_set_subrepos "${url}" "${repos[@]}"
733 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}"
736 submodules=( "${submodules[@]:3}" ) # shift
741 # @FUNCTION: git-r3_checkout
742 # @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
744 # Check the previously fetched tree to the working copy.
746 # <repo-uri> specifies the repository URIs, as a space-separated list.
747 # The first URI will be used as repository group identifier
748 # and therefore must be used consistently with git-r3_fetch.
749 # The remaining URIs are not used and therefore may be omitted.
750 # When not specified, defaults to ${EGIT_REPO_URI}.
752 # <checkout-path> specifies the path to place the checkout. It defaults
753 # to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
755 # <local-id> needs to specify the local identifier that was used
756 # for respective git-r3_fetch.
758 # The checkout operation will write to the working copy, and export
759 # the repository state into the environment. If the repository contains
760 # submodules, they will be checked out recursively.
762 debug-print-function ${FUNCNAME} "$@"
767 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
768 repos=( "${EGIT_REPO_URI[@]}" )
770 repos=( ${EGIT_REPO_URI} )
773 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
774 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
777 _git-r3_set_gitdir "${repos[0]}"
779 einfo "Checking out \e[1m${repos[0]}\e[22m to \e[1m${out_dir}\e[22m ..."
781 if ! git cat-file -e refs/git-r3/"${local_id}"/__main__; then
782 if [[ ${EVCS_OFFLINE} ]]; then
783 die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE."
785 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
789 git symbolic-ref --quiet refs/git-r3/"${local_id}"/__main__
791 local new_commit_id=$(
792 git rev-parse --verify refs/git-r3/"${local_id}"/__main__
795 git-r3_sub_checkout() {
796 local orig_repo=${GIT_DIR}
797 local -x GIT_DIR=${out_dir}/.git
798 local -x GIT_WORK_TREE=${out_dir}
800 mkdir -p "${out_dir}" || die
802 # use git init+fetch instead of clone since the latter doesn't like
803 # non-empty directories.
805 git init --quiet || die
806 # setup 'alternates' to avoid copying objects
807 echo "${orig_repo}/objects" > "${GIT_DIR}"/objects/info/alternates || die
809 # [htn]* safely catches heads, tags, notes without complaining
810 # on non-existing ones, and omits internal 'git-r3' ref
811 cp -R "${orig_repo}"/refs/[htn]* "${GIT_DIR}"/refs/ || die
813 # (no need to copy HEAD, we will set it via checkout)
815 if [[ -f ${orig_repo}/shallow ]]; then
816 cp "${orig_repo}"/shallow "${GIT_DIR}"/ || die
819 set -- git checkout --quiet
820 if [[ ${remote_ref} ]]; then
821 set -- "${@}" "${remote_ref#refs/heads/}"
823 set -- "${@}" "${new_commit_id}"
826 "${@}" || die "git checkout ${remote_ref:-${new_commit_id}} failed"
829 unset -f git-r3_sub_checkout
831 local old_commit_id=$(
832 git rev-parse --quiet --verify refs/git-r3/"${local_id}"/__old__
834 if [[ ! ${old_commit_id} ]]; then
835 echo "GIT NEW branch -->"
836 echo " repository: ${repos[0]}"
837 echo " at the commit: ${new_commit_id}"
839 # diff against previous revision
840 echo "GIT update -->"
841 echo " repository: ${repos[0]}"
842 # write out message based on the revisions
843 if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
844 echo " updating from commit: ${old_commit_id}"
845 echo " to commit: ${new_commit_id}"
847 git --no-pager diff --stat \
848 ${old_commit_id}..${new_commit_id}
850 echo " at the commit: ${new_commit_id}"
853 git update-ref --no-deref refs/git-r3/"${local_id}"/{__old__,__main__} || die
855 # recursively checkout submodules
856 if [[ -f ${out_dir}/.gitmodules ]]; then
858 _git-r3_set_submodules \
859 "$(<"${out_dir}"/.gitmodules)"
861 while [[ ${submodules[@]} ]]; do
862 local subname=${submodules[0]}
863 local url=${submodules[1]}
864 local path=${submodules[2]}
866 # use only submodules for which path does exist
867 # (this is in par with 'git submodule'), bug #551100
868 if [[ -d ${out_dir}/${path} ]]; then
870 _git-r3_set_subrepos "${url}" "${repos[@]}"
872 git-r3_checkout "${subrepos[*]}" "${out_dir}/${path}" \
873 "${local_id}/${subname}"
876 submodules=( "${submodules[@]:3}" ) # shift
880 # keep this *after* submodules
881 export EGIT_DIR=${GIT_DIR}
882 export EGIT_VERSION=${new_commit_id}
885 # @FUNCTION: git-r3_peek_remote_ref
886 # @USAGE: [<repo-uri> [<remote-ref>]]
888 # Peek the reference in the remote repository and print the matching
889 # (newest) commit SHA1.
891 # <repo-uri> specifies the repository URIs to fetch from, as a space-
892 # -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
894 # <remote-ref> specifies the remote ref to peek. It is preferred to use
895 # 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
896 # for tags. Alternatively, 'HEAD' may be used for upstream default
897 # branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
898 # 'HEAD' that is set to a non-null value.
900 # The operation will be done purely on the remote, without using local
901 # storage. If commit SHA1 is provided as <remote-ref>, the function will
902 # fail due to limitations of git protocol.
904 # On success, the function returns 0 and writes hexadecimal commit SHA1
905 # to stdout. On failure, the function returns 1.
906 git-r3_peek_remote_ref() {
907 debug-print-function ${FUNCNAME} "$@"
912 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
913 repos=( "${EGIT_REPO_URI[@]}" )
915 repos=( ${EGIT_REPO_URI} )
918 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
919 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
921 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
924 for r in "${repos[@]}"; do
925 einfo "Peeking \e[1m${remote_ref}\e[22m on \e[1m${r}\e[22m ..." >&2
928 if [[ ${remote_ref} == refs/* || ${remote_ref} == HEAD ]]
930 lookup_ref=${remote_ref}
932 # ls-remote by commit is going to fail anyway,
933 # so we may as well pass refs/tags/ABCDEF...
934 lookup_ref=refs/tags/${remote_ref}
937 # split on whitespace
939 $(git ls-remote "${r}" "${lookup_ref}")
942 if [[ ${ref[0]} ]]; then
952 debug-print-function ${FUNCNAME} "$@"
954 if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then
955 ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider"
956 ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use"
957 ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones"
958 ewarn "when git-2 eclass becomes deprecated."
965 git-r3_src_unpack() {
966 debug-print-function ${FUNCNAME} "$@"
973 # https://bugs.gentoo.org/show_bug.cgi?id=482666
974 git-r3_pkg_needrebuild() {
975 debug-print-function ${FUNCNAME} "$@"
977 local new_commit_id=$(git-r3_peek_remote_ref)
978 [[ ${new_commit_id} && ${EGIT_VERSION} ]] || die "Lookup failed"
980 if [[ ${EGIT_VERSION} != ${new_commit_id} ]]; then
981 einfo "Update from \e[1m${EGIT_VERSION}\e[22m to \e[1m${new_commit_id}\e[22m"
983 einfo "Local and remote at \e[1m${EGIT_VERSION}\e[22m"
986 [[ ${EGIT_VERSION} != ${new_commit_id} ]]
989 # 'export' locally until this gets into EAPI
990 pkg_needrebuild() { git-r3_pkg_needrebuild; }