1 # Copyright 1999-2017 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
4 # @ECLASS: git-r3.eclass
6 # Michał Górny <mgorny@gentoo.org>
7 # @BLURB: Eclass for fetching and unpacking git repositories.
9 # Third generation eclass for easing maintenance of live ebuilds using
10 # git as remote repository.
16 die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
20 EXPORT_FUNCTIONS src_unpack
22 if [[ ! ${_GIT_R3} ]]; then
24 if [[ ! ${_INHERITED_BY_GIT_2} ]]; then
25 DEPEND=">=dev-vcs/git-1.8.2.1"
28 # @ECLASS-VARIABLE: EGIT_CLONE_TYPE
30 # Type of clone that should be used against the remote repository.
31 # This can be either of: 'mirror', 'single', 'shallow'.
33 # This is intended to be set by user in make.conf. Ebuilds are supposed
34 # to set EGIT_MIN_CLONE_TYPE if necessary instead.
36 # The 'mirror' type clones all remote branches and tags with complete
37 # history and all notes. EGIT_COMMIT can specify any commit hash.
38 # Upstream-removed branches and tags are purged from the local clone
39 # while fetching. This mode is suitable for cloning the local copy
40 # for development or hosting a local git mirror. However, clones
41 # of repositories with large diverged branches may quickly grow large.
43 # The 'single+tags' type clones the requested branch and all tags
44 # in the repository. All notes are fetched as well. EGIT_COMMIT
45 # can safely specify hashes throughout the current branch and all tags.
46 # No purging of old references is done (if you often switch branches,
47 # you may need to remove stale branches yourself). This mode is intended
48 # mostly for use with broken git servers such as Google Code that fail
49 # to fetch tags along with the branch in 'single' mode.
51 # The 'single' type clones only the requested branch or tag. Tags
52 # referencing commits throughout the branch history are fetched as well,
53 # and all notes. EGIT_COMMIT can safely specify only hashes
54 # in the current branch. No purging of old references is done (if you
55 # often switch branches, you may need to remove stale branches
56 # yourself). This mode is suitable for general use.
58 # The 'shallow' type clones only the newest commit on requested branch
59 # or tag. EGIT_COMMIT can only specify tags, and since the history is
60 # unavailable calls like 'git describe' will not reference prior tags.
61 # No purging of old references is done. This mode is intended mostly for
62 # embedded systems with limited disk space.
63 : ${EGIT_CLONE_TYPE:=single}
65 # @ECLASS-VARIABLE: EGIT_MIN_CLONE_TYPE
67 # 'Minimum' clone type supported by the ebuild. Takes same values
68 # as EGIT_CLONE_TYPE. When user sets a type that's 'lower' (that is,
69 # later on the list) than EGIT_MIN_CLONE_TYPE, the eclass uses
70 # EGIT_MIN_CLONE_TYPE instead.
72 # This variable is intended to be used by ebuilds only. Users are
73 # supposed to set EGIT_CLONE_TYPE instead.
75 # A common case is to use 'single' whenever the build system requires
76 # access to full branch history, or 'single+tags' when Google Code
77 # or a similar remote is used that does not support shallow clones
78 # and fetching tags along with commits. Please use sparingly, and to fix
79 # fatal errors rather than 'non-pretty versions'.
80 : ${EGIT_MIN_CLONE_TYPE:=shallow}
82 # @ECLASS-VARIABLE: EGIT3_STORE_DIR
84 # Storage directory for git sources.
86 # This is intended to be set by user in make.conf. Ebuilds must not set
89 # EGIT3_STORE_DIR=${DISTDIR}/git3-src
91 # @ECLASS-VARIABLE: EGIT_MIRROR_URI
94 # 'Top' URI to a local git mirror. If specified, the eclass will try
95 # to fetch from the local mirror instead of using the remote repository.
97 # The mirror needs to follow EGIT3_STORE_DIR structure. The directory
98 # created by eclass can be used for that purpose.
102 # EGIT_MIRROR_URI="git://mirror.lan/"
105 # @ECLASS-VARIABLE: EGIT_REPO_URI
108 # URIs to the repository, e.g. https://foo. If multiple URIs are
109 # provided, the eclass will consider the remaining URIs as fallbacks
110 # to try if the first URI does not work. For supported URI syntaxes,
111 # read the manpage for git-clone(1).
113 # URIs should be using https:// whenever possible. http:// and git://
114 # URIs are completely unsecured and their use (even if only as
115 # a fallback) renders the ebuild completely vulnerable to MITM attacks.
117 # It can be overridden via env using ${PN}_LIVE_REPO variable.
119 # Can be a whitespace-separated list or an array.
123 # EGIT_REPO_URI="https://a/b.git https://c/d.git"
126 # @ECLASS-VARIABLE: EVCS_OFFLINE
129 # If non-empty, this variable prevents any online operations.
131 # @ECLASS-VARIABLE: EVCS_UMASK
134 # Set this variable to a custom umask. This is intended to be set by
135 # users. By setting this to something like 002, it can make life easier
136 # for people who do development as non-root (but are in the portage
137 # group), and then switch over to building with FEATURES=userpriv.
138 # Or vice-versa. Shouldn't be a security issue here as anyone who has
139 # portage group write access already can screw the system over in more
142 # @ECLASS-VARIABLE: EGIT_BRANCH
145 # The branch name to check out. If unset, the upstream default (HEAD)
148 # It can be overridden via env using ${PN}_LIVE_BRANCH variable.
150 # @ECLASS-VARIABLE: EGIT_COMMIT
153 # The tag name or commit identifier to check out. If unset, newest
154 # commit from the branch will be used. Note that if set to a commit
155 # not on HEAD branch, EGIT_BRANCH needs to be set to a branch on which
156 # the commit is available.
158 # It can be overridden via env using ${PN}_LIVE_COMMIT variable.
160 # @ECLASS-VARIABLE: EGIT_COMMIT_DATE
163 # Attempt to check out the repository state for the specified timestamp.
164 # The date should be in format understood by 'git rev-list'. The commits
165 # on EGIT_BRANCH will be considered.
167 # The eclass will select the last commit with commit date preceding
168 # the specified date. When merge commits are found, only first parents
169 # will be considered in order to avoid switching into external branches
170 # (assuming that merges are done correctly). In other words, each merge
171 # will be considered alike a single commit with date corresponding
172 # to the merge commit date.
174 # It can be overridden via env using ${PN}_LIVE_COMMIT_DATE variable.
176 # @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR
178 # The directory to check the git sources out to.
180 # EGIT_CHECKOUT_DIR=${WORKDIR}/${P}
182 # @ECLASS-VARIABLE: EGIT_SUBMODULES
185 # An array of inclusive and exclusive wildcards on submodule names,
186 # stating which submodules are fetched and checked out. Exclusions
187 # start with '-', and exclude previously matched submodules.
189 # If unset, all submodules are enabled. Empty list disables all
190 # submodules. In order to use an exclude-only list, start the array
193 # Remember that wildcards need to be quoted in order to prevent filename
198 # # Disable all submodules
201 # # Include only foo and bar
202 # EGIT_SUBMODULES=( foo bar )
204 # # Use all submodules except for test-* but include test-lib
205 # EGIT_SUBMODULES=( '*' '-test-*' test-lib )
208 # @FUNCTION: _git-r3_env_setup
211 # Set the eclass variables as necessary for operation. This can involve
212 # setting EGIT_* to defaults or ${PN}_LIVE_* variables.
213 _git-r3_env_setup() {
214 debug-print-function ${FUNCNAME} "$@"
216 # check the clone type
217 case "${EGIT_CLONE_TYPE}" in
218 mirror|single+tags|single|shallow)
221 die "Invalid EGIT_CLONE_TYPE=${EGIT_CLONE_TYPE}"
223 case "${EGIT_MIN_CLONE_TYPE}" in
227 if [[ ${EGIT_CLONE_TYPE} == shallow ]]; then
228 einfo "git-r3: ebuild needs to be cloned in '\e[1msingle\e[22m' mode, adjusting"
229 EGIT_CLONE_TYPE=single
233 if [[ ${EGIT_CLONE_TYPE} == shallow || ${EGIT_CLONE_TYPE} == single ]]; then
234 einfo "git-r3: ebuild needs to be cloned in '\e[1msingle+tags\e[22m' mode, adjusting"
235 EGIT_CLONE_TYPE=single+tags
239 if [[ ${EGIT_CLONE_TYPE} != mirror ]]; then
240 einfo "git-r3: ebuild needs to be cloned in '\e[1mmirror\e[22m' mode, adjusting"
241 EGIT_CLONE_TYPE=mirror
245 die "Invalid EGIT_MIN_CLONE_TYPE=${EGIT_MIN_CLONE_TYPE}"
248 if [[ ${EGIT_SUBMODULES[@]+1} && $(declare -p EGIT_SUBMODULES) != "declare -a"* ]]
250 die 'EGIT_SUBMODULES must be an array.'
255 [[ ${esc_pn} == [0-9]* ]] && esc_pn=_${esc_pn}
257 livevar=${esc_pn}_LIVE_REPO
258 EGIT_REPO_URI=${!livevar-${EGIT_REPO_URI}}
260 && ewarn "Using ${livevar}, no support will be provided"
262 livevar=${esc_pn}_LIVE_BRANCH
263 EGIT_BRANCH=${!livevar-${EGIT_BRANCH}}
265 && ewarn "Using ${livevar}, no support will be provided"
267 livevar=${esc_pn}_LIVE_COMMIT
268 EGIT_COMMIT=${!livevar-${EGIT_COMMIT}}
270 && ewarn "Using ${livevar}, no support will be provided"
272 livevar=${esc_pn}_LIVE_COMMIT_DATE
273 EGIT_COMMIT_DATE=${!livevar-${EGIT_COMMIT_DATE}}
275 && ewarn "Using ${livevar}, no support will be provided"
277 if [[ ${EGIT_COMMIT} && ${EGIT_COMMIT_DATE} ]]; then
278 die "EGIT_COMMIT and EGIT_COMMIT_DATE can not be specified simultaneously"
281 # Migration helpers. Remove them when git-2 is removed.
283 if [[ ${EGIT_SOURCEDIR} ]]; then
284 eerror "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR. While updating"
285 eerror "your ebuild, please check whether the variable is necessary at all"
286 eerror "since the default has been changed from \${S} to \${WORKDIR}/\${P}."
287 eerror "Therefore, proper setting of S may be sufficient."
288 die "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR."
291 if [[ ${EGIT_MASTER} ]]; then
292 eerror "EGIT_MASTER has been removed. Instead, the upstream default (HEAD)"
293 eerror "is used by the eclass. Please remove the assignment or use EGIT_BRANCH"
294 eerror "as necessary."
295 die "EGIT_MASTER has been removed."
298 if [[ ${EGIT_HAS_SUBMODULES} ]]; then
299 eerror "EGIT_HAS_SUBMODULES has been removed. The eclass no longer needs"
300 eerror "to switch the clone type in order to support submodules and therefore"
301 eerror "submodules are detected and fetched automatically. If you need to"
302 eerror "disable or filter submodules, see EGIT_SUBMODULES."
303 die "EGIT_HAS_SUBMODULES is no longer necessary."
306 if [[ ${EGIT_PROJECT} ]]; then
307 eerror "EGIT_PROJECT has been removed. Instead, the eclass determines"
308 eerror "the local clone path using path in canonical EGIT_REPO_URI."
309 eerror "If the current algorithm causes issues for you, please report a bug."
310 die "EGIT_PROJECT is no longer necessary."
313 if [[ ${EGIT_BOOTSTRAP} ]]; then
314 eerror "EGIT_BOOTSTRAP has been removed. Please create proper src_prepare()"
316 die "EGIT_BOOTSTRAP has been removed."
319 if [[ ${EGIT_NOUNPACK} ]]; then
320 eerror "EGIT_NOUNPACK has been removed. The eclass no longer calls default"
321 eerror "unpack function. If necessary, please declare proper src_unpack()."
322 die "EGIT_NOUNPACK has been removed."
326 # @FUNCTION: _git-r3_set_gitdir
330 # Obtain the local repository path and set it as GIT_DIR. Creates
331 # a new repository if necessary.
333 # <repo-uri> may be used to compose the path. It should therefore be
334 # a canonical URI to the repository.
335 _git-r3_set_gitdir() {
336 debug-print-function ${FUNCNAME} "$@"
338 local repo_name=${1#*://*/}
340 # strip the trailing slash
341 repo_name=${repo_name%/}
343 # strip common prefixes to make paths more likely to match
344 # e.g. git://X/Y.git vs https://X/git/Y.git
345 # (but just one of the prefixes)
346 case "${repo_name}" in
347 # gnome.org... who else?
348 browse/*) repo_name=${repo_name#browse/};;
349 # cgit can proxy requests to git
350 cgit/*) repo_name=${repo_name#cgit/};;
352 git/*) repo_name=${repo_name#git/};;
354 gitroot/*) repo_name=${repo_name#gitroot/};;
356 p/*) repo_name=${repo_name#p/};;
358 pub/scm/*) repo_name=${repo_name#pub/scm/};;
360 # ensure a .git suffix, same reason
361 repo_name=${repo_name%.git}.git
362 # now replace all the slashes
363 repo_name=${repo_name//\//_}
365 local distdir=${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}}
366 : ${EGIT3_STORE_DIR:=${distdir}/git3-src}
368 GIT_DIR=${EGIT3_STORE_DIR}/${repo_name}
370 if [[ ! -d ${EGIT3_STORE_DIR} && ! ${EVCS_OFFLINE} ]]; then
373 mkdir -p "${EGIT3_STORE_DIR}"
374 ) || die "Unable to create ${EGIT3_STORE_DIR}"
377 addwrite "${EGIT3_STORE_DIR}"
378 if [[ ! -d ${GIT_DIR} ]]; then
379 if [[ ${EVCS_OFFLINE} ]]; then
380 eerror "A clone of the following repository is required to proceed:"
382 eerror "However, networking activity has been disabled using EVCS_OFFLINE and there"
383 eerror "is no local clone available."
384 die "No local clone of ${1}. Unable to proceed with EVCS_OFFLINE."
388 if [[ ${EVCS_UMASK} ]]; then
390 umask "${EVCS_UMASK}" || die "Bad options to umask: ${EVCS_UMASK}"
392 mkdir "${GIT_DIR}" || die
393 git init --bare || die
394 if [[ ${saved_umask} ]]; then
395 umask "${saved_umask}" || die
400 # @FUNCTION: _git-r3_set_submodules
401 # @USAGE: <file-contents>
404 # Parse .gitmodules contents passed as <file-contents>
405 # as in "$(cat .gitmodules)"). Composes a 'submodules' array that
406 # contains in order (name, URL, path) for each submodule.
407 _git-r3_set_submodules() {
408 debug-print-function ${FUNCNAME} "$@"
412 # ( name url path ... )
417 # submodule.<path>.path=<path>
418 # submodule.<path>.url=<url>
419 [[ ${l} == submodule.*.url=* ]] || continue
422 local subname=${l%%.url=*}
424 # filter out on EGIT_SUBMODULES
425 if declare -p EGIT_SUBMODULES &>/dev/null; then
427 for p in "${EGIT_SUBMODULES[@]}"; do
428 if [[ ${p} == -* ]]; then
435 [[ ${subname} == ${p} ]] && res=${l_res}
438 if [[ ! ${res} ]]; then
439 einfo "Skipping submodule \e[1m${subname}\e[22m"
444 # skip modules that have 'update = none', bug #487262.
445 local upd=$(echo "${data}" | git config -f /dev/fd/0 \
446 submodule."${subname}".update)
447 [[ ${upd} == none ]] && continue
449 # https://github.com/git/git/blob/master/refs.c#L31
450 # we are more restrictive than git itself but that should not
451 # cause any issues, #572312, #606950
452 # TODO: check escaped names for collisions
453 local enc_subname=${subname//[^a-zA-Z0-9-]/_}
457 "$(echo "${data}" | git config -f /dev/fd/0 \
458 submodule."${subname}".url || die)"
459 "$(echo "${data}" | git config -f /dev/fd/0 \
460 submodule."${subname}".path || die)"
462 done < <(echo "${data}" | git config -f /dev/fd/0 -l || die)
465 # @FUNCTION: _git-r3_set_subrepos
466 # @USAGE: <submodule-uri> <parent-repo-uri>...
469 # Create 'subrepos' array containing absolute (canonical) submodule URIs
470 # for the given <submodule-uri>. If the URI is relative, URIs will be
471 # constructed using all <parent-repo-uri>s. Otherwise, this single URI
472 # will be placed in the array.
473 _git-r3_set_subrepos() {
474 debug-print-function ${FUNCNAME} "$@"
477 subrepos=( "${@:2}" )
479 if [[ ${suburl} == ./* || ${suburl} == ../* ]]; then
480 # drop all possible trailing slashes for consistency
481 subrepos=( "${subrepos[@]%%/}" )
484 if [[ ${suburl} == ./* ]]; then
486 elif [[ ${suburl} == ../* ]]; then
489 # XXX: correctness checking
491 # drop the last path component
492 subrepos=( "${subrepos[@]%/*}" )
493 # and then the trailing slashes, again
494 subrepos=( "${subrepos[@]%%/}" )
500 # append the preprocessed path to the preprocessed URIs
501 subrepos=( "${subrepos[@]/%//${suburl}}")
503 subrepos=( "${suburl}" )
508 # @FUNCTION: _git-r3_is_local_repo
512 # Determine whether the given URI specifies a local (on-disk)
514 _git-r3_is_local_repo() {
515 debug-print-function ${FUNCNAME} "$@"
519 [[ ${uri} == file://* || ${uri} == /* ]]
522 # @FUNCTION: git-r3_fetch
523 # @USAGE: [<repo-uri> [<remote-ref> [<local-id> [<commit-date>]]]]
525 # Fetch new commits to the local clone of repository.
527 # <repo-uri> specifies the repository URIs to fetch from, as a space-
528 # -separated list. The first URI will be used as repository group
529 # identifier and therefore must be used consistently. When not
530 # specified, defaults to ${EGIT_REPO_URI}.
532 # <remote-ref> specifies the remote ref or commit id to fetch.
533 # It is preferred to use 'refs/heads/<branch-name>' for branches
534 # and 'refs/tags/<tag-name>' for tags. Other options are 'HEAD'
535 # for upstream default branch and hexadecimal commit SHA1. Defaults
536 # to the first of EGIT_COMMIT, EGIT_BRANCH or literal 'HEAD' that
537 # is set to a non-null value.
539 # <local-id> specifies the local branch identifier that will be used to
540 # locally store the fetch result. It should be unique to multiple
541 # fetches within the repository that can be performed at the same time
542 # (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT%/*}.
543 # This default should be fine unless you are fetching multiple trees
544 # from the same repository in the same ebuild.
546 # <commit-id> requests attempting to use repository state as of specific
547 # date. For more details, see EGIT_COMMIT_DATE.
549 # The fetch operation will affect the EGIT_STORE only. It will not touch
550 # the working copy, nor export any environment variables.
551 # If the repository contains submodules, they will be fetched
554 debug-print-function ${FUNCNAME} "$@"
556 # process repos first since we create repo_name from it
560 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
561 repos=( "${EGIT_REPO_URI[@]}" )
563 repos=( ${EGIT_REPO_URI} )
566 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
569 for r in "${repos[@]}"; do
570 if [[ ${r} == git:* || ${r} == http:* ]]; then
571 ewarn "git-r3: ${r%%:*} protocol is completely unsecure and may render the ebuild"
572 ewarn "easily susceptible to MITM attacks (even if used only as fallback). Please"
573 ewarn "use https instead."
579 _git-r3_set_gitdir "${repos[0]}"
581 # prepend the local mirror if applicable
582 if [[ ${EGIT_MIRROR_URI} ]]; then
584 "${EGIT_MIRROR_URI%/}/${GIT_DIR##*/}"
589 # get the default values for the common variables and override them
590 local branch_name=${EGIT_BRANCH}
591 local commit_id=${2:-${EGIT_COMMIT}}
592 local commit_date=${4:-${EGIT_COMMIT_DATE}}
594 # support new override API for EAPI 6+
595 if ! has "${EAPI:-0}" 0 1 2 3 4 5; then
596 # get the name and do some more processing:
597 # 1) kill .git suffix,
598 # 2) underscore (remaining) non-variable characters,
599 # 3) add preceding underscore if it starts with a digit,
601 local override_name=${GIT_DIR##*/}
602 override_name=${override_name%.git}
603 override_name=${override_name//[^a-zA-Z0-9_]/_}
604 override_name=${override_name^^}
610 COMMIT_DATE:commit_date
613 local localvar livevar live_warn=
614 for localvar in "${varmap[@]}"; do
615 livevar=EGIT_OVERRIDE_${localvar%:*}_${override_name}
616 localvar=${localvar#*:}
618 if [[ -n ${!livevar} ]]; then
619 [[ ${localvar} == repos ]] && repos=()
621 ewarn "Using ${livevar}=${!livevar}"
622 declare "${localvar}=${!livevar}"
626 if [[ ${live_warn} ]]; then
627 ewarn "No support will be provided."
631 # set final variables after applying overrides
632 local branch=${branch_name:+refs/heads/${branch_name}}
633 local remote_ref=${commit_id:-${branch:-HEAD}}
634 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
635 local local_ref=refs/git-r3/${local_id}/__main__
637 # try to fetch from the remote
638 local success saved_umask
639 if [[ ${EVCS_UMASK} ]]; then
641 umask "${EVCS_UMASK}" || die "Bad options to umask: ${EVCS_UMASK}"
643 for r in "${repos[@]}"; do
644 if [[ ! ${EVCS_OFFLINE} ]]; then
645 einfo "Fetching \e[1m${r}\e[22m ..."
647 local fetch_command=( git fetch "${r}" )
648 local clone_type=${EGIT_CLONE_TYPE}
650 if [[ ${r} == http://* || ${r} == https://* ]] &&
651 [[ ! ${EGIT_CURL_WARNED} ]] &&
652 ! ROOT=/ has_version 'dev-vcs/git[curl]'
654 ewarn "git-r3: fetching from HTTP(S) requested. In order to support HTTP(S),"
655 ewarn "dev-vcs/git needs to be built with USE=curl. Example solution:"
657 ewarn " echo dev-vcs/git curl >> /etc/portage/package.use"
658 ewarn " emerge -1v dev-vcs/git"
660 ewarn "HTTP(S) URIs will be skipped."
664 if [[ ${clone_type} == mirror ]]; then
667 # mirror the remote branches as local branches
668 "+refs/heads/*:refs/heads/*"
669 # pull tags explicitly in order to prune them properly
670 "+refs/tags/*:refs/tags/*"
671 # notes in case something needs them
672 "+refs/notes/*:refs/notes/*"
673 # and HEAD in case we need the default branch
674 # (we keep it in refs/git-r3 since otherwise --prune interferes)
675 "+HEAD:refs/git-r3/HEAD"
677 else # single or shallow
678 local fetch_l fetch_r
680 if [[ ${remote_ref} == HEAD ]]; then
683 elif [[ ${remote_ref} == refs/* ]]; then
684 # regular branch, tag or some other explicit ref
685 fetch_l=${remote_ref}
687 # tag or commit id...
688 # let ls-remote figure it out
689 local tagref=$(git ls-remote "${r}" "refs/tags/${remote_ref}")
691 # if it was a tag, ls-remote obtained a hash
692 if [[ ${tagref} ]]; then
694 fetch_l=refs/tags/${remote_ref}
697 # so we need to fetch the whole branch
698 if [[ ${branch} ]]; then
704 # fetching by commit in shallow mode? can't do.
705 if [[ ${clone_type} == shallow ]]; then
711 # checkout by date does not make sense in shallow mode
712 if [[ ${commit_date} && ${clone_type} == shallow ]]; then
716 if [[ ${fetch_l} == HEAD ]]; then
717 fetch_r=refs/git-r3/HEAD
723 "+${fetch_l}:${fetch_r}"
726 if [[ ${clone_type} == single+tags ]]; then
728 # pull tags explicitly as requested
729 "+refs/tags/*:refs/tags/*"
734 if [[ ${clone_type} == shallow ]]; then
735 if _git-r3_is_local_repo; then
736 # '--depth 1' causes sandbox violations with local repos
739 elif [[ ! $(git rev-parse --quiet --verify "${fetch_r}") ]]
741 # use '--depth 1' when fetching a new branch
742 fetch_command+=( --depth 1 )
744 else # non-shallow mode
745 if [[ -f ${GIT_DIR}/shallow ]]; then
746 fetch_command+=( --unshallow )
750 set -- "${fetch_command[@]}"
754 if [[ ${clone_type} == mirror || ${fetch_l} == HEAD ]]; then
755 # update our HEAD to match our remote HEAD ref
756 git symbolic-ref HEAD refs/git-r3/HEAD \
757 || die "Unable to update HEAD"
761 # now let's see what the user wants from us
762 if [[ ${commit_date} ]]; then
763 local dated_commit_id=$(
764 git rev-list --first-parent --before="${commit_date}" \
767 if [[ ${?} -ne 0 ]]; then
768 die "Listing ${remote_ref} failed (wrong ref?)."
769 elif [[ ! ${dated_commit_id} ]]; then
770 die "Unable to find commit for date ${commit_date}."
772 set -- git update-ref --no-deref "${local_ref}" "${dated_commit_id}"
775 local full_remote_ref=$(
776 git rev-parse --verify --symbolic-full-name "${remote_ref}"
779 if [[ ${full_remote_ref} ]]; then
780 # when we are given a ref, create a symbolic ref
781 # so that we preserve the actual argument
782 set -- git symbolic-ref "${local_ref}" "${full_remote_ref}"
784 # otherwise, we were likely given a commit id
785 set -- git update-ref --no-deref "${local_ref}" "${remote_ref}"
791 if [[ ${EVCS_OFFLINE} ]]; then
792 eerror "A clone of the following repository is required to proceed:"
794 eerror "However, networking activity has been disabled using EVCS_OFFLINE and the local"
795 eerror "clone does not have requested ref:"
796 eerror " ${remote_ref}"
797 die "Local clone of ${r} does not have requested ref: ${remote_ref}. Unable to proceed with EVCS_OFFLINE."
799 die "Referencing ${remote_ref} failed (wrong ref?)."
806 if [[ ${saved_umask} ]]; then
807 umask "${saved_umask}" || die
809 [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
811 # submodules can reference commits in any branch
812 # always use the 'mirror' mode to accomodate that, bug #503332
813 local EGIT_CLONE_TYPE=mirror
815 # recursively fetch submodules
816 if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
818 _git-r3_set_submodules \
819 "$(git cat-file -p "${local_ref}":.gitmodules || die)"
821 while [[ ${submodules[@]} ]]; do
822 local subname=${submodules[0]}
823 local url=${submodules[1]}
824 local path=${submodules[2]}
826 # use only submodules for which path does exist
827 # (this is in par with 'git submodule'), bug #551100
828 # note: git cat-file does not work for submodules
829 if [[ $(git ls-tree -d "${local_ref}" "${path}") ]]
831 local commit=$(git rev-parse "${local_ref}:${path}" || die)
833 if [[ ! ${commit} ]]; then
834 die "Unable to get commit id for submodule ${subname}"
838 _git-r3_set_subrepos "${url}" "${repos[@]}"
840 git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}"
843 submodules=( "${submodules[@]:3}" ) # shift
848 # @FUNCTION: git-r3_checkout
849 # @USAGE: [<repo-uri> [<checkout-path> [<local-id> [<checkout-paths>...]]]]
851 # Check the previously fetched tree to the working copy.
853 # <repo-uri> specifies the repository URIs, as a space-separated list.
854 # The first URI will be used as repository group identifier
855 # and therefore must be used consistently with git-r3_fetch.
856 # The remaining URIs are not used and therefore may be omitted.
857 # When not specified, defaults to ${EGIT_REPO_URI}.
859 # <checkout-path> specifies the path to place the checkout. It defaults
860 # to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
862 # <local-id> needs to specify the local identifier that was used
863 # for respective git-r3_fetch.
865 # If <checkout-paths> are specified, then the specified paths are passed
866 # to 'git checkout' to effect a partial checkout. Please note that such
867 # checkout will not cause the repository to switch branches,
868 # and submodules will be skipped at the moment. The submodules matching
869 # those paths might be checked out in a future version of the eclass.
871 # The checkout operation will write to the working copy, and export
872 # the repository state into the environment. If the repository contains
873 # submodules, they will be checked out recursively.
875 debug-print-function ${FUNCNAME} "$@"
880 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
881 repos=( "${EGIT_REPO_URI[@]}" )
883 repos=( ${EGIT_REPO_URI} )
886 local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
887 local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}}
888 local checkout_paths=( "${@:4}" )
891 _git-r3_set_gitdir "${repos[0]}"
893 einfo "Checking out \e[1m${repos[0]}\e[22m to \e[1m${out_dir}\e[22m ..."
895 if ! git cat-file -e refs/git-r3/"${local_id}"/__main__; then
896 die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?"
899 git symbolic-ref --quiet refs/git-r3/"${local_id}"/__main__
901 local new_commit_id=$(
902 git rev-parse --verify refs/git-r3/"${local_id}"/__main__
905 git-r3_sub_checkout() {
906 local orig_repo=${GIT_DIR}
907 local -x GIT_DIR=${out_dir}/.git
908 local -x GIT_WORK_TREE=${out_dir}
910 mkdir -p "${out_dir}" || die
912 # use git init+fetch instead of clone since the latter doesn't like
913 # non-empty directories.
915 git init --quiet || die
916 # setup 'alternates' to avoid copying objects
917 echo "${orig_repo}/objects" > "${GIT_DIR}"/objects/info/alternates || die
919 cp -R "${orig_repo}"/refs/* "${GIT_DIR}"/refs/ || die
920 if [[ -f ${orig_repo}/packed-refs ]]; then
921 cp "${orig_repo}"/packed-refs "${GIT_DIR}"/packed-refs || die
924 # (no need to copy HEAD, we will set it via checkout)
926 if [[ -f ${orig_repo}/shallow ]]; then
927 cp "${orig_repo}"/shallow "${GIT_DIR}"/ || die
930 set -- git checkout --quiet
931 if [[ ${remote_ref} ]]; then
932 set -- "${@}" "${remote_ref#refs/heads/}"
934 set -- "${@}" "${new_commit_id}"
936 if [[ ${checkout_paths[@]} ]]; then
937 set -- "${@}" -- "${checkout_paths[@]}"
940 "${@}" || die "git checkout ${remote_ref:-${new_commit_id}} failed"
943 unset -f git-r3_sub_checkout
945 local old_commit_id=$(
946 git rev-parse --quiet --verify refs/git-r3/"${local_id}"/__old__
948 if [[ ! ${old_commit_id} ]]; then
949 echo "GIT NEW branch -->"
950 echo " repository: ${repos[0]}"
951 echo " at the commit: ${new_commit_id}"
953 # diff against previous revision
954 echo "GIT update -->"
955 echo " repository: ${repos[0]}"
956 # write out message based on the revisions
957 if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
958 echo " updating from commit: ${old_commit_id}"
959 echo " to commit: ${new_commit_id}"
961 set -- git --no-pager diff --stat \
962 ${old_commit_id}..${new_commit_id}
963 if [[ ${checkout_paths[@]} ]]; then
964 set -- "${@}" -- "${checkout_paths[@]}"
968 echo " at the commit: ${new_commit_id}"
971 git update-ref --no-deref refs/git-r3/"${local_id}"/{__old__,__main__} || die
973 # recursively checkout submodules
974 if [[ -f ${out_dir}/.gitmodules && ! ${checkout_paths} ]]; then
976 _git-r3_set_submodules \
977 "$(<"${out_dir}"/.gitmodules)"
979 while [[ ${submodules[@]} ]]; do
980 local subname=${submodules[0]}
981 local url=${submodules[1]}
982 local path=${submodules[2]}
984 # use only submodules for which path does exist
985 # (this is in par with 'git submodule'), bug #551100
986 if [[ -d ${out_dir}/${path} ]]; then
988 _git-r3_set_subrepos "${url}" "${repos[@]}"
990 git-r3_checkout "${subrepos[*]}" "${out_dir}/${path}" \
991 "${local_id}/${subname}"
994 submodules=( "${submodules[@]:3}" ) # shift
998 # keep this *after* submodules
999 export EGIT_DIR=${GIT_DIR}
1000 export EGIT_VERSION=${new_commit_id}
1003 # @FUNCTION: git-r3_peek_remote_ref
1004 # @USAGE: [<repo-uri> [<remote-ref>]]
1006 # Peek the reference in the remote repository and print the matching
1007 # (newest) commit SHA1.
1009 # <repo-uri> specifies the repository URIs to fetch from, as a space-
1010 # -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
1012 # <remote-ref> specifies the remote ref to peek. It is preferred to use
1013 # 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
1014 # for tags. Alternatively, 'HEAD' may be used for upstream default
1015 # branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
1016 # 'HEAD' that is set to a non-null value.
1018 # The operation will be done purely on the remote, without using local
1019 # storage. If commit SHA1 is provided as <remote-ref>, the function will
1020 # fail due to limitations of git protocol.
1022 # On success, the function returns 0 and writes hexadecimal commit SHA1
1023 # to stdout. On failure, the function returns 1.
1024 git-r3_peek_remote_ref() {
1025 debug-print-function ${FUNCNAME} "$@"
1030 elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then
1031 repos=( "${EGIT_REPO_URI[@]}" )
1033 repos=( ${EGIT_REPO_URI} )
1036 local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
1037 local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
1039 [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
1042 for r in "${repos[@]}"; do
1043 einfo "Peeking \e[1m${remote_ref}\e[22m on \e[1m${r}\e[22m ..." >&2
1046 if [[ ${remote_ref} == refs/* || ${remote_ref} == HEAD ]]
1048 lookup_ref=${remote_ref}
1050 # ls-remote by commit is going to fail anyway,
1051 # so we may as well pass refs/tags/ABCDEF...
1052 lookup_ref=refs/tags/${remote_ref}
1055 # split on whitespace
1057 $(git ls-remote "${r}" "${lookup_ref}")
1060 if [[ ${ref[0]} ]]; then
1069 git-r3_src_fetch() {
1070 debug-print-function ${FUNCNAME} "$@"
1072 if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then
1073 ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider"
1074 ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use"
1075 ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones"
1076 ewarn "when git-2 eclass becomes deprecated."
1083 git-r3_src_unpack() {
1084 debug-print-function ${FUNCNAME} "$@"
1091 # https://bugs.gentoo.org/show_bug.cgi?id=482666
1092 git-r3_pkg_needrebuild() {
1093 debug-print-function ${FUNCNAME} "$@"
1095 local new_commit_id=$(git-r3_peek_remote_ref)
1096 [[ ${new_commit_id} && ${EGIT_VERSION} ]] || die "Lookup failed"
1098 if [[ ${EGIT_VERSION} != ${new_commit_id} ]]; then
1099 einfo "Update from \e[1m${EGIT_VERSION}\e[22m to \e[1m${new_commit_id}\e[22m"
1101 einfo "Local and remote at \e[1m${EGIT_VERSION}\e[22m"
1104 [[ ${EGIT_VERSION} != ${new_commit_id} ]]
1107 # 'export' locally until this gets into EAPI
1108 pkg_needrebuild() { git-r3_pkg_needrebuild; }