1 | # Copyright 1999-2013 Gentoo Foundation |
1 | # Copyright 1999-2014 Gentoo Foundation |
2 | # Distributed under the terms of the GNU General Public License v2 |
2 | # Distributed under the terms of the GNU General Public License v2 |
3 | # $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.15 2013/10/09 17:14:07 mgorny Exp $ |
3 | # $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.44 2014/06/20 11:40:28 mgorny Exp $ |
4 | |
4 | |
5 | # @ECLASS: git-r3.eclass |
5 | # @ECLASS: git-r3.eclass |
6 | # @MAINTAINER: |
6 | # @MAINTAINER: |
7 | # Michał Górny <mgorny@gentoo.org> |
7 | # Michał Górny <mgorny@gentoo.org> |
8 | # @BLURB: Eclass for fetching and unpacking git repositories. |
8 | # @BLURB: Eclass for fetching and unpacking git repositories. |
9 | # @DESCRIPTION: |
9 | # @DESCRIPTION: |
10 | # Third generation eclass for easing maitenance of live ebuilds using |
10 | # Third generation eclass for easing maitenance of live ebuilds using |
11 | # git as remote repository. The eclass supports lightweight (shallow) |
11 | # git as remote repository. |
12 | # clones and bare clones of submodules. |
|
|
13 | |
12 | |
14 | case "${EAPI:-0}" in |
13 | case "${EAPI:-0}" in |
15 | 0|1|2|3|4|5) |
14 | 0|1|2|3|4|5) |
16 | ;; |
15 | ;; |
17 | *) |
16 | *) |
… | |
… | |
31 | |
30 | |
32 | if [[ ! ${_INHERITED_BY_GIT_2} ]]; then |
31 | if [[ ! ${_INHERITED_BY_GIT_2} ]]; then |
33 | DEPEND=">=dev-vcs/git-1.8.2.1" |
32 | DEPEND=">=dev-vcs/git-1.8.2.1" |
34 | fi |
33 | fi |
35 | |
34 | |
|
|
35 | # @ECLASS-VARIABLE: EGIT_CLONE_TYPE |
|
|
36 | # @DESCRIPTION: |
|
|
37 | # Type of clone that should be used against the remote repository. |
|
|
38 | # This can be either of: 'mirror', 'single', 'shallow'. |
|
|
39 | # |
|
|
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. |
|
|
42 | # |
|
|
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. |
|
|
49 | # |
|
|
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. |
|
|
57 | # |
|
|
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. |
|
|
64 | # |
|
|
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} |
|
|
71 | |
|
|
72 | # @ECLASS-VARIABLE: EGIT_MIN_CLONE_TYPE |
|
|
73 | # @DESCRIPTION: |
|
|
74 | # 'Minimum' clone type supported by the ebuild. Takes same values |
|
|
75 | # as EGIT_CLONE_TYPE. When user sets a type that's 'lower' (that is, |
|
|
76 | # later on the list) than EGIT_MIN_CLONE_TYPE, the eclass uses |
|
|
77 | # EGIT_MIN_CLONE_TYPE instead. |
|
|
78 | # |
|
|
79 | # This variable is intended to be used by ebuilds only. Users are |
|
|
80 | # supposed to set EGIT_CLONE_TYPE instead. |
|
|
81 | # |
|
|
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} |
|
|
88 | |
36 | # @ECLASS-VARIABLE: EGIT3_STORE_DIR |
89 | # @ECLASS-VARIABLE: EGIT3_STORE_DIR |
37 | # @DESCRIPTION: |
90 | # @DESCRIPTION: |
38 | # Storage directory for git sources. |
91 | # Storage directory for git sources. |
39 | # |
92 | # |
|
|
93 | # This is intended to be set by user in make.conf. Ebuilds must not set |
|
|
94 | # it. |
|
|
95 | # |
40 | # EGIT3_STORE_DIR=${DISTDIR}/git3-src |
96 | # EGIT3_STORE_DIR=${DISTDIR}/git3-src |
|
|
97 | |
|
|
98 | # @ECLASS-VARIABLE: EGIT_MIRROR_URI |
|
|
99 | # @DEFAULT_UNSET |
|
|
100 | # @DESCRIPTION: |
|
|
101 | # 'Top' URI to a local git mirror. If specified, the eclass will try |
|
|
102 | # to fetch from the local mirror instead of using the remote repository. |
|
|
103 | # |
|
|
104 | # The mirror needs to follow EGIT3_STORE_DIR structure. The directory |
|
|
105 | # created by eclass can be used for that purpose. |
|
|
106 | # |
|
|
107 | # Example: |
|
|
108 | # @CODE |
|
|
109 | # EGIT_MIRROR_URI="git://mirror.lan/" |
|
|
110 | # @CODE |
41 | |
111 | |
42 | # @ECLASS-VARIABLE: EGIT_REPO_URI |
112 | # @ECLASS-VARIABLE: EGIT_REPO_URI |
43 | # @REQUIRED |
113 | # @REQUIRED |
44 | # @DESCRIPTION: |
114 | # @DESCRIPTION: |
45 | # URIs to the repository, e.g. git://foo, https://foo. If multiple URIs |
115 | # URIs to the repository, e.g. git://foo, https://foo. If multiple URIs |
… | |
… | |
81 | # @DESCRIPTION: |
151 | # @DESCRIPTION: |
82 | # The directory to check the git sources out to. |
152 | # The directory to check the git sources out to. |
83 | # |
153 | # |
84 | # EGIT_CHECKOUT_DIR=${WORKDIR}/${P} |
154 | # EGIT_CHECKOUT_DIR=${WORKDIR}/${P} |
85 | |
155 | |
86 | # @ECLASS-VARIABLE: EGIT_NONSHALLOW |
|
|
87 | # @DEFAULT_UNSET |
|
|
88 | # @DESCRIPTION: |
|
|
89 | # Disable performing shallow fetches/clones. Shallow clones have |
|
|
90 | # a fair number of limitations. Therefore, if you'd like the eclass to |
|
|
91 | # perform complete clones instead, set this to a non-null value. |
|
|
92 | # |
|
|
93 | # This variable can be set in make.conf and ebuilds. The make.conf |
|
|
94 | # value specifies user-specific default, while ebuilds may use it |
|
|
95 | # to force deep clones when the server does not support shallow clones |
|
|
96 | # (e.g. Google Code). |
|
|
97 | |
|
|
98 | # @FUNCTION: _git-r3_env_setup |
156 | # @FUNCTION: _git-r3_env_setup |
99 | # @INTERNAL |
157 | # @INTERNAL |
100 | # @DESCRIPTION: |
158 | # @DESCRIPTION: |
101 | # Set the eclass variables as necessary for operation. This can involve |
159 | # Set the eclass variables as necessary for operation. This can involve |
102 | # setting EGIT_* to defaults or ${PN}_LIVE_* variables. |
160 | # setting EGIT_* to defaults or ${PN}_LIVE_* variables. |
103 | _git-r3_env_setup() { |
161 | _git-r3_env_setup() { |
104 | debug-print-function ${FUNCNAME} "$@" |
162 | debug-print-function ${FUNCNAME} "$@" |
|
|
163 | |
|
|
164 | # check the clone type |
|
|
165 | case "${EGIT_CLONE_TYPE}" in |
|
|
166 | mirror|single+tags|single|shallow) |
|
|
167 | ;; |
|
|
168 | *) |
|
|
169 | die "Invalid EGIT_CLONE_TYPE=${EGIT_CLONE_TYPE}" |
|
|
170 | esac |
|
|
171 | case "${EGIT_MIN_CLONE_TYPE}" in |
|
|
172 | shallow) |
|
|
173 | ;; |
|
|
174 | single) |
|
|
175 | if [[ ${EGIT_CLONE_TYPE} == shallow ]]; then |
|
|
176 | einfo "git-r3: ebuild needs to be cloned in 'single' mode, adjusting" |
|
|
177 | EGIT_CLONE_TYPE=single |
|
|
178 | fi |
|
|
179 | ;; |
|
|
180 | single+tags) |
|
|
181 | if [[ ${EGIT_CLONE_TYPE} == shallow || ${EGIT_CLONE_TYPE} == single ]]; then |
|
|
182 | einfo "git-r3: ebuild needs to be cloned in 'single+tags' mode, adjusting" |
|
|
183 | EGIT_CLONE_TYPE=single+tags |
|
|
184 | fi |
|
|
185 | ;; |
|
|
186 | mirror) |
|
|
187 | if [[ ${EGIT_CLONE_TYPE} != mirror ]]; then |
|
|
188 | einfo "git-r3: ebuild needs to be cloned in 'mirror' mode, adjusting" |
|
|
189 | EGIT_CLONE_TYPE=mirror |
|
|
190 | fi |
|
|
191 | ;; |
|
|
192 | *) |
|
|
193 | die "Invalid EGIT_MIN_CLONE_TYPE=${EGIT_MIN_CLONE_TYPE}" |
|
|
194 | esac |
105 | |
195 | |
106 | local esc_pn livevar |
196 | local esc_pn livevar |
107 | esc_pn=${PN//[-+]/_} |
197 | esc_pn=${PN//[-+]/_} |
108 | |
198 | |
109 | livevar=${esc_pn}_LIVE_REPO |
199 | livevar=${esc_pn}_LIVE_REPO |
… | |
… | |
210 | GIT_DIR=${EGIT3_STORE_DIR}/${repo_name} |
300 | GIT_DIR=${EGIT3_STORE_DIR}/${repo_name} |
211 | |
301 | |
212 | if [[ ! -d ${EGIT3_STORE_DIR} ]]; then |
302 | if [[ ! -d ${EGIT3_STORE_DIR} ]]; then |
213 | ( |
303 | ( |
214 | addwrite / |
304 | addwrite / |
215 | mkdir -m0755 -p "${EGIT3_STORE_DIR}" |
305 | mkdir -m0755 -p "${EGIT3_STORE_DIR}" || die |
216 | ) || die "Unable to create ${EGIT3_STORE_DIR}" |
306 | ) || die "Unable to create ${EGIT3_STORE_DIR}" |
217 | fi |
307 | fi |
218 | |
308 | |
219 | addwrite "${EGIT3_STORE_DIR}" |
309 | addwrite "${EGIT3_STORE_DIR}" |
220 | if [[ ! -d ${GIT_DIR} ]]; then |
310 | if [[ ! -d ${GIT_DIR} ]]; then |
221 | mkdir "${GIT_DIR}" || die |
311 | mkdir "${GIT_DIR}" || die |
222 | git init --bare || die |
312 | git init --bare || die |
223 | |
|
|
224 | if [[ ! ${EGIT_NONSHALLOW} ]]; then |
|
|
225 | # avoid auto-unshallow :) |
|
|
226 | touch "${GIT_DIR}"/shallow || die |
|
|
227 | fi |
|
|
228 | fi |
313 | fi |
229 | } |
314 | } |
230 | |
315 | |
231 | # @FUNCTION: _git-r3_set_submodules |
316 | # @FUNCTION: _git-r3_set_submodules |
232 | # @USAGE: <file-contents> |
317 | # @USAGE: <file-contents> |
… | |
… | |
258 | [[ ${upd} == none ]] && continue |
343 | [[ ${upd} == none ]] && continue |
259 | |
344 | |
260 | submodules+=( |
345 | submodules+=( |
261 | "${subname}" |
346 | "${subname}" |
262 | "$(echo "${data}" | git config -f /dev/fd/0 \ |
347 | "$(echo "${data}" | git config -f /dev/fd/0 \ |
263 | submodule."${subname}".url)" |
348 | submodule."${subname}".url || die)" |
264 | "$(echo "${data}" | git config -f /dev/fd/0 \ |
349 | "$(echo "${data}" | git config -f /dev/fd/0 \ |
265 | submodule."${subname}".path)" |
350 | submodule."${subname}".path || die)" |
266 | ) |
351 | ) |
267 | done < <(echo "${data}" | git config -f /dev/fd/0 -l) |
352 | done < <(echo "${data}" | git config -f /dev/fd/0 -l || die) |
268 | } |
353 | } |
269 | |
354 | |
270 | # @FUNCTION: _git-r3_smart_fetch |
355 | # @FUNCTION: _git-r3_set_subrepos |
271 | # @USAGE: <git-fetch-args>... |
356 | # @USAGE: <submodule-uri> <parent-repo-uri>... |
|
|
357 | # @INTERNAL |
272 | # @DESCRIPTION: |
358 | # @DESCRIPTION: |
273 | # Try fetching without '--depth' and switch to '--depth 1' if that |
359 | # Create 'subrepos' array containing absolute (canonical) submodule URIs |
274 | # will involve less objects fetched. |
360 | # for the given <submodule-uri>. If the URI is relative, URIs will be |
275 | _git-r3_smart_fetch() { |
361 | # constructed using all <parent-repo-uri>s. Otherwise, this single URI |
|
|
362 | # will be placed in the array. |
|
|
363 | _git-r3_set_subrepos() { |
276 | debug-print-function ${FUNCNAME} "$@" |
364 | debug-print-function ${FUNCNAME} "$@" |
277 | |
365 | |
278 | local sed_regexp='.*Counting objects: \([0-9]*\), done\..*' |
366 | local suburl=${1} |
|
|
367 | subrepos=( "${@:2}" ) |
279 | |
368 | |
280 | # start the main fetch |
369 | if [[ ${suburl} == ./* || ${suburl} == ../* ]]; then |
281 | local cmd=( git fetch --progress "${@}" ) |
370 | # drop all possible trailing slashes for consistency |
282 | echo "${cmd[@]}" >&2 |
371 | subrepos=( "${subrepos[@]%%/}" ) |
283 | |
372 | |
284 | # we copy the output to the 'sed' pipe for parsing. whenever sed finds |
373 | while true; do |
285 | # the process count, it quits quickly to avoid delays in writing it. |
374 | if [[ ${suburl} == ./* ]]; then |
286 | # then, we start a dummy 'cat' to keep the pipe alive |
375 | suburl=${suburl:2} |
|
|
376 | elif [[ ${suburl} == ../* ]]; then |
|
|
377 | suburl=${suburl:3} |
287 | |
378 | |
288 | "${cmd[@]}" 2>&1 \ |
379 | # XXX: correctness checking |
289 | | tee >( |
|
|
290 | sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}" \ |
|
|
291 | > "${T}"/git-r3_main.count |
|
|
292 | exec cat >/dev/null |
|
|
293 | ) & |
|
|
294 | local main_pid=${!} |
|
|
295 | |
380 | |
296 | # start the helper process |
381 | # drop the last path component |
297 | _git-r3_sub_fetch() { |
382 | subrepos=( "${subrepos[@]%/*}" ) |
298 | # wait for main fetch to get object count; if the server doesn't |
383 | # and then the trailing slashes, again |
299 | # output it, we won't even launch the parallel process |
384 | subrepos=( "${subrepos[@]%%/}" ) |
300 | while [[ ! -s ${T}/git-r3_main.count ]]; do |
385 | else |
301 | sleep 0.25 |
386 | break |
|
|
387 | fi |
302 | done |
388 | done |
303 | |
389 | |
304 | # ok, let's see if parallel fetch gives us smaller count |
390 | # append the preprocessed path to the preprocessed URIs |
305 | # --dry-run will prevent it from writing to the local clone |
391 | subrepos=( "${subrepos[@]/%//${suburl}}") |
306 | # and sed should terminate git with SIGPIPE |
392 | else |
307 | local sub_count=$(git fetch --progress --dry-run --depth 1 "${@}" 2>&1 \ |
393 | subrepos=( "${suburl}" ) |
308 | | sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}") |
394 | fi |
309 | local main_count=$(<"${T}"/git-r3_main.count) |
395 | } |
310 | |
396 | |
311 | # let's be real sure that '--depth 1' will be good for us. |
397 | |
312 | # note that we have purely objects counts, and '--depth 1' |
398 | # @FUNCTION: _git-r3_is_local_repo |
313 | # may involve much bigger objects |
399 | # @USAGE: <repo-uri> |
314 | if [[ ${main_count} && ${main_count} -ge $(( sub_count * 3/2 )) ]] |
400 | # @INTERNAL |
315 | then |
401 | # @DESCRIPTION: |
316 | # signal that we want shallow fetch instead, |
402 | # Determine whether the given URI specifies a local (on-disk) |
317 | # and terminate the non-shallow fetch process |
403 | # repository. |
318 | touch "${T}"/git-r3_want_shallow || die |
404 | _git-r3_is_local_repo() { |
319 | kill ${main_pid} &>/dev/null |
405 | debug-print-function ${FUNCNAME} "$@" |
320 | exit 0 |
406 | |
|
|
407 | local uri=${1} |
|
|
408 | |
|
|
409 | [[ ${uri} == file://* || ${uri} == /* ]] |
|
|
410 | } |
|
|
411 | |
|
|
412 | # @FUNCTION: _git-r3_find_head |
|
|
413 | # @USAGE: <head-ref> |
|
|
414 | # @INTERNAL |
|
|
415 | # @DESCRIPTION: |
|
|
416 | # Given a ref to which remote HEAD was fetched, try to find |
|
|
417 | # a branch matching the commit. Expects 'git show-ref' |
|
|
418 | # or 'git ls-remote' output on stdin. |
|
|
419 | _git-r3_find_head() { |
|
|
420 | debug-print-function ${FUNCNAME} "$@" |
|
|
421 | |
|
|
422 | local head_ref=${1} |
|
|
423 | local head_hash=$(git rev-parse --verify "${1}" || die) |
|
|
424 | local matching_ref |
|
|
425 | |
|
|
426 | # TODO: some transports support peeking at symbolic remote refs |
|
|
427 | # find a way to use that rather than guessing |
|
|
428 | |
|
|
429 | # (based on guess_remote_head() in git-1.9.0/remote.c) |
|
|
430 | local h ref |
|
|
431 | while read h ref; do |
|
|
432 | # look for matching head |
|
|
433 | if [[ ${h} == ${head_hash} ]]; then |
|
|
434 | # either take the first matching ref, or master if it is there |
|
|
435 | if [[ ! ${matching_ref} || ${ref} == refs/heads/master ]]; then |
|
|
436 | matching_ref=${ref} |
321 | fi |
437 | fi |
322 | |
|
|
323 | exit 1 |
|
|
324 | } |
|
|
325 | _git-r3_sub_fetch "${@}" & |
|
|
326 | local sub_pid=${!} |
|
|
327 | |
|
|
328 | # wait for main process to terminate, either of its own |
|
|
329 | # or by signal from subprocess |
|
|
330 | wait ${main_pid} |
|
|
331 | local main_ret=${?} |
|
|
332 | |
|
|
333 | # wait for subprocess to terminate, killing it if necessary. |
|
|
334 | # if main fetch finished before it, there's no point in keeping |
|
|
335 | # it alive. if main fetch was killed by it, it's done anyway |
|
|
336 | kill ${sub_pid} &>/dev/null |
|
|
337 | wait ${sub_pid} |
|
|
338 | |
|
|
339 | # now see if subprocess wanted to tell us something... |
|
|
340 | if [[ -f ${T}/git-r3_want_shallow ]]; then |
|
|
341 | rm "${T}"/git-r3_want_shallow || die |
|
|
342 | |
|
|
343 | # if fetch finished already (wasn't killed), ignore it |
|
|
344 | [[ ${main_ret} -eq 0 ]] && return 0 |
|
|
345 | |
|
|
346 | # otherwise, restart as shallow fetch |
|
|
347 | einfo "Restarting fetch using --depth 1 to save bandwidth ..." |
|
|
348 | local cmd=( git fetch --progress --depth 1 "${@}" ) |
|
|
349 | echo "${cmd[@]}" >&2 |
|
|
350 | "${cmd[@]}" |
|
|
351 | main_ret=${?} |
|
|
352 | fi |
438 | fi |
|
|
439 | done |
353 | |
440 | |
354 | return ${main_ret} |
441 | if [[ ! ${matching_ref} ]]; then |
|
|
442 | die "Unable to find a matching branch for remote HEAD (${head_hash})" |
|
|
443 | fi |
|
|
444 | |
|
|
445 | echo "${matching_ref}" |
355 | } |
446 | } |
356 | |
447 | |
357 | # @FUNCTION: git-r3_fetch |
448 | # @FUNCTION: git-r3_fetch |
358 | # @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]] |
449 | # @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]] |
359 | # @DESCRIPTION: |
450 | # @DESCRIPTION: |
… | |
… | |
372 | # is set to a non-null value. |
463 | # is set to a non-null value. |
373 | # |
464 | # |
374 | # <local-id> specifies the local branch identifier that will be used to |
465 | # <local-id> specifies the local branch identifier that will be used to |
375 | # locally store the fetch result. It should be unique to multiple |
466 | # locally store the fetch result. It should be unique to multiple |
376 | # fetches within the repository that can be performed at the same time |
467 | # fetches within the repository that can be performed at the same time |
377 | # (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT}. |
468 | # (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT%/*}. |
378 | # This default should be fine unless you are fetching multiple trees |
469 | # This default should be fine unless you are fetching multiple trees |
379 | # from the same repository in the same ebuild. |
470 | # from the same repository in the same ebuild. |
380 | # |
471 | # |
381 | # The fetch operation will affect the EGIT_STORE only. It will not touch |
472 | # The fetch operation will affect the EGIT_STORE only. It will not touch |
382 | # the working copy, nor export any environment variables. |
473 | # the working copy, nor export any environment variables. |
383 | # If the repository contains submodules, they will be fetched |
474 | # If the repository contains submodules, they will be fetched |
384 | # recursively. |
475 | # recursively. |
385 | git-r3_fetch() { |
476 | git-r3_fetch() { |
386 | debug-print-function ${FUNCNAME} "$@" |
477 | debug-print-function ${FUNCNAME} "$@" |
|
|
478 | |
|
|
479 | [[ ${EVCS_OFFLINE} ]] && return |
387 | |
480 | |
388 | local repos |
481 | local repos |
389 | if [[ ${1} ]]; then |
482 | if [[ ${1} ]]; then |
390 | repos=( ${1} ) |
483 | repos=( ${1} ) |
391 | elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then |
484 | elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then |
… | |
… | |
394 | repos=( ${EGIT_REPO_URI} ) |
487 | repos=( ${EGIT_REPO_URI} ) |
395 | fi |
488 | fi |
396 | |
489 | |
397 | local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} |
490 | local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} |
398 | local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} |
491 | local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} |
399 | local local_id=${3:-${CATEGORY}/${PN}/${SLOT}} |
492 | local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}} |
400 | local local_ref=refs/heads/${local_id}/__main__ |
493 | local local_ref=refs/git-r3/${local_id}/__main__ |
401 | |
494 | |
402 | [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" |
495 | [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" |
403 | |
496 | |
404 | local -x GIT_DIR |
497 | local -x GIT_DIR |
405 | _git-r3_set_gitdir "${repos[0]}" |
498 | _git-r3_set_gitdir "${repos[0]}" |
|
|
499 | |
|
|
500 | # prepend the local mirror if applicable |
|
|
501 | if [[ ${EGIT_MIRROR_URI} ]]; then |
|
|
502 | repos=( |
|
|
503 | "${EGIT_MIRROR_URI%/}/${GIT_DIR##*/}" |
|
|
504 | "${repos[@]}" |
|
|
505 | ) |
|
|
506 | fi |
406 | |
507 | |
407 | # try to fetch from the remote |
508 | # try to fetch from the remote |
408 | local r success |
509 | local r success |
409 | for r in "${repos[@]}"; do |
510 | for r in "${repos[@]}"; do |
|
|
511 | einfo "Fetching ${r} ..." |
|
|
512 | |
|
|
513 | local fetch_command=( git fetch "${r}" ) |
|
|
514 | local clone_type=${EGIT_CLONE_TYPE} |
|
|
515 | |
|
|
516 | if [[ ${r} == https://* ]] && ! has_version 'dev-vcs/git[curl]'; then |
|
|
517 | eerror "git-r3: fetching from https:// requested. In order to support https," |
|
|
518 | eerror "dev-vcs/git needs to be built with USE=curl. Example solution:" |
|
|
519 | eerror |
|
|
520 | eerror " echo dev-vcs/git curl >> /etc/portage/package.use" |
|
|
521 | eerror " emerge -1v dev-vcs/git" |
|
|
522 | die "dev-vcs/git built with USE=curl required." |
|
|
523 | fi |
|
|
524 | |
|
|
525 | if [[ ${r} == https://code.google.com/* ]]; then |
|
|
526 | # Google Code has special magic on top of git that: |
|
|
527 | # 1) can't handle shallow clones at all, |
|
|
528 | # 2) fetches duplicately when tags are pulled in with branch |
|
|
529 | # so automatically switch to single+tags mode. |
|
|
530 | if [[ ${clone_type} == shallow ]]; then |
|
|
531 | einfo " Google Code does not support shallow clones" |
|
|
532 | einfo " using EGIT_CLONE_TYPE=single+tags" |
|
|
533 | clone_type=single+tags |
|
|
534 | elif [[ ${clone_type} == single ]]; then |
|
|
535 | einfo " git-r3: Google Code does not send tags properly in 'single' mode" |
|
|
536 | einfo " using EGIT_CLONE_TYPE=single+tags" |
|
|
537 | clone_type=single+tags |
|
|
538 | fi |
|
|
539 | fi |
|
|
540 | |
|
|
541 | if [[ ${clone_type} == mirror ]]; then |
|
|
542 | fetch_command+=( |
|
|
543 | --prune |
|
|
544 | # mirror the remote branches as local branches |
|
|
545 | "+refs/heads/*:refs/heads/*" |
|
|
546 | # pull tags explicitly in order to prune them properly |
|
|
547 | "+refs/tags/*:refs/tags/*" |
|
|
548 | # notes in case something needs them |
|
|
549 | "+refs/notes/*:refs/notes/*" |
|
|
550 | # and HEAD in case we need the default branch |
|
|
551 | # (we keep it in refs/git-r3 since otherwise --prune interferes) |
|
|
552 | "+HEAD:refs/git-r3/HEAD" |
|
|
553 | ) |
|
|
554 | else # single or shallow |
|
|
555 | local fetch_l fetch_r |
|
|
556 | |
|
|
557 | if [[ ${remote_ref} == HEAD ]]; then |
|
|
558 | # HEAD |
|
|
559 | fetch_l=HEAD |
|
|
560 | elif [[ ${remote_ref} == refs/heads/* ]]; then |
|
|
561 | # regular branch |
|
|
562 | fetch_l=${remote_ref} |
|
|
563 | else |
|
|
564 | # tag or commit... |
|
|
565 | # let ls-remote figure it out |
|
|
566 | local tagref=$(git ls-remote "${r}" "refs/tags/${remote_ref}") |
|
|
567 | |
|
|
568 | # if it was a tag, ls-remote obtained a hash |
|
|
569 | if [[ ${tagref} ]]; then |
|
|
570 | # tag |
|
|
571 | fetch_l=refs/tags/${remote_ref} |
|
|
572 | else |
|
|
573 | # commit |
|
|
574 | # so we need to fetch the branch |
|
|
575 | if [[ ${branch} ]]; then |
|
|
576 | fetch_l=${branch} |
|
|
577 | else |
|
|
578 | fetch_l=HEAD |
|
|
579 | fi |
|
|
580 | |
|
|
581 | # fetching by commit in shallow mode? can't do. |
|
|
582 | if [[ ${clone_type} == shallow ]]; then |
|
|
583 | clone_type=single |
|
|
584 | fi |
|
|
585 | fi |
|
|
586 | fi |
|
|
587 | |
|
|
588 | if [[ ${fetch_l} == HEAD ]]; then |
|
|
589 | fetch_r=refs/git-r3/HEAD |
|
|
590 | else |
|
|
591 | fetch_r=${fetch_l} |
|
|
592 | fi |
|
|
593 | |
|
|
594 | fetch_command+=( |
|
|
595 | "+${fetch_l}:${fetch_r}" |
|
|
596 | ) |
|
|
597 | |
|
|
598 | if [[ ${clone_type} == single+tags ]]; then |
|
|
599 | fetch_command+=( |
|
|
600 | # pull tags explicitly as requested |
|
|
601 | "+refs/tags/*:refs/tags/*" |
|
|
602 | ) |
|
|
603 | fi |
|
|
604 | fi |
|
|
605 | |
|
|
606 | if [[ ${clone_type} == shallow ]]; then |
|
|
607 | if _git-r3_is_local_repo; then |
|
|
608 | # '--depth 1' causes sandbox violations with local repos |
|
|
609 | # bug #491260 |
|
|
610 | clone_type=single |
|
|
611 | elif [[ ! $(git rev-parse --quiet --verify "${fetch_r}") ]] |
|
|
612 | then |
|
|
613 | # use '--depth 1' when fetching a new branch |
|
|
614 | fetch_command+=( --depth 1 ) |
|
|
615 | fi |
|
|
616 | else # non-shallow mode |
|
|
617 | if [[ -f ${GIT_DIR}/shallow ]]; then |
|
|
618 | fetch_command+=( --unshallow ) |
|
|
619 | fi |
|
|
620 | fi |
|
|
621 | |
|
|
622 | set -- "${fetch_command[@]}" |
|
|
623 | echo "${@}" >&2 |
|
|
624 | if "${@}"; then |
|
|
625 | if [[ ${clone_type} == mirror ]]; then |
|
|
626 | # find remote HEAD and update our HEAD properly |
|
|
627 | git symbolic-ref HEAD \ |
|
|
628 | "$(_git-r3_find_head refs/git-r3/HEAD \ |
|
|
629 | < <(git show-ref --heads || die))" \ |
|
|
630 | || die "Unable to update HEAD" |
|
|
631 | else # single or shallow |
|
|
632 | if [[ ${fetch_l} == HEAD ]]; then |
|
|
633 | # find out what branch we fetched as HEAD |
|
|
634 | local head_branch=$(_git-r3_find_head \ |
|
|
635 | refs/git-r3/HEAD \ |
|
|
636 | < <(git ls-remote --heads "${r}" || die)) |
|
|
637 | |
|
|
638 | # and move it to its regular place |
|
|
639 | git update-ref --no-deref "${head_branch}" \ |
|
|
640 | refs/git-r3/HEAD \ |
|
|
641 | || die "Unable to sync HEAD branch ${head_branch}" |
|
|
642 | git symbolic-ref HEAD "${head_branch}" \ |
|
|
643 | || die "Unable to update HEAD" |
|
|
644 | fi |
|
|
645 | fi |
|
|
646 | |
|
|
647 | # now let's see what the user wants from us |
|
|
648 | local full_remote_ref=$( |
|
|
649 | git rev-parse --verify --symbolic-full-name "${remote_ref}" |
|
|
650 | ) |
|
|
651 | |
|
|
652 | if [[ ${full_remote_ref} ]]; then |
|
|
653 | # when we are given a ref, create a symbolic ref |
|
|
654 | # so that we preserve the actual argument |
|
|
655 | set -- git symbolic-ref "${local_ref}" "${full_remote_ref}" |
|
|
656 | else |
|
|
657 | # otherwise, we were likely given a commit id |
|
|
658 | set -- git update-ref --no-deref "${local_ref}" "${remote_ref}" |
|
|
659 | fi |
|
|
660 | |
|
|
661 | echo "${@}" >&2 |
|
|
662 | if ! "${@}"; then |
|
|
663 | die "Referencing ${remote_ref} failed (wrong ref?)." |
|
|
664 | fi |
|
|
665 | |
|
|
666 | success=1 |
|
|
667 | break |
|
|
668 | fi |
|
|
669 | done |
|
|
670 | [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI" |
|
|
671 | |
|
|
672 | # submodules can reference commits in any branch |
|
|
673 | # always use the 'clone' mode to accomodate that, bug #503332 |
|
|
674 | local EGIT_CLONE_TYPE=mirror |
|
|
675 | |
|
|
676 | # recursively fetch submodules |
|
|
677 | if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then |
|
|
678 | local submodules |
|
|
679 | _git-r3_set_submodules \ |
|
|
680 | "$(git cat-file -p "${local_ref}":.gitmodules || die)" |
|
|
681 | |
|
|
682 | while [[ ${submodules[@]} ]]; do |
|
|
683 | local subname=${submodules[0]} |
|
|
684 | local url=${submodules[1]} |
|
|
685 | local path=${submodules[2]} |
|
|
686 | local commit=$(git rev-parse "${local_ref}:${path}") |
|
|
687 | |
|
|
688 | if [[ ! ${commit} ]]; then |
|
|
689 | die "Unable to get commit id for submodule ${subname}" |
|
|
690 | fi |
|
|
691 | |
|
|
692 | local subrepos |
|
|
693 | _git-r3_set_subrepos "${url}" "${repos[@]}" |
|
|
694 | |
|
|
695 | git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}" |
|
|
696 | |
|
|
697 | submodules=( "${submodules[@]:3}" ) # shift |
|
|
698 | done |
|
|
699 | fi |
|
|
700 | } |
|
|
701 | |
|
|
702 | # @FUNCTION: git-r3_checkout |
|
|
703 | # @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]] |
|
|
704 | # @DESCRIPTION: |
|
|
705 | # Check the previously fetched tree to the working copy. |
|
|
706 | # |
|
|
707 | # <repo-uri> specifies the repository URIs, as a space-separated list. |
|
|
708 | # The first URI will be used as repository group identifier |
|
|
709 | # and therefore must be used consistently with git-r3_fetch. |
|
|
710 | # The remaining URIs are not used and therefore may be omitted. |
|
|
711 | # When not specified, defaults to ${EGIT_REPO_URI}. |
|
|
712 | # |
|
|
713 | # <checkout-path> specifies the path to place the checkout. It defaults |
|
|
714 | # to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}. |
|
|
715 | # |
|
|
716 | # <local-id> needs to specify the local identifier that was used |
|
|
717 | # for respective git-r3_fetch. |
|
|
718 | # |
|
|
719 | # The checkout operation will write to the working copy, and export |
|
|
720 | # the repository state into the environment. If the repository contains |
|
|
721 | # submodules, they will be checked out recursively. |
|
|
722 | git-r3_checkout() { |
|
|
723 | debug-print-function ${FUNCNAME} "$@" |
|
|
724 | |
|
|
725 | local repos |
|
|
726 | if [[ ${1} ]]; then |
|
|
727 | repos=( ${1} ) |
|
|
728 | elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then |
|
|
729 | repos=( "${EGIT_REPO_URI[@]}" ) |
|
|
730 | else |
|
|
731 | repos=( ${EGIT_REPO_URI} ) |
|
|
732 | fi |
|
|
733 | |
|
|
734 | local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}} |
|
|
735 | local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}} |
|
|
736 | |
|
|
737 | local -x GIT_DIR |
|
|
738 | _git-r3_set_gitdir "${repos[0]}" |
|
|
739 | |
|
|
740 | einfo "Checking out ${repos[0]} to ${out_dir} ..." |
|
|
741 | |
|
|
742 | if ! git cat-file -e refs/git-r3/"${local_id}"/__main__; then |
|
|
743 | if [[ ${EVCS_OFFLINE} ]]; then |
|
|
744 | die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE." |
|
|
745 | else |
|
|
746 | die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?" |
|
|
747 | fi |
|
|
748 | fi |
|
|
749 | local remote_ref=$( |
|
|
750 | git symbolic-ref --quiet refs/git-r3/"${local_id}"/__main__ |
|
|
751 | ) |
|
|
752 | local new_commit_id=$( |
|
|
753 | git rev-parse --verify refs/git-r3/"${local_id}"/__main__ |
|
|
754 | ) |
|
|
755 | |
|
|
756 | git-r3_sub_checkout() { |
|
|
757 | local orig_repo=${GIT_DIR} |
|
|
758 | local -x GIT_DIR=${out_dir}/.git |
|
|
759 | local -x GIT_WORK_TREE=${out_dir} |
|
|
760 | |
|
|
761 | mkdir -p "${out_dir}" || die |
|
|
762 | |
|
|
763 | # use git init+fetch instead of clone since the latter doesn't like |
|
|
764 | # non-empty directories. |
|
|
765 | |
|
|
766 | git init --quiet || die |
|
|
767 | # setup 'alternates' to avoid copying objects |
|
|
768 | echo "${orig_repo}/objects" > "${GIT_DIR}"/objects/info/alternates || die |
|
|
769 | # now copy the refs |
|
|
770 | # [htn]* safely catches heads, tags, notes without complaining |
|
|
771 | # on non-existing ones, and omits internal 'git-r3' ref |
|
|
772 | cp -R "${orig_repo}"/refs/[htn]* "${GIT_DIR}"/refs/ || die |
|
|
773 | |
|
|
774 | # (no need to copy HEAD, we will set it via checkout) |
|
|
775 | |
|
|
776 | if [[ -f ${orig_repo}/shallow ]]; then |
|
|
777 | cp "${orig_repo}"/shallow "${GIT_DIR}"/ || die |
|
|
778 | fi |
|
|
779 | |
|
|
780 | set -- git checkout --quiet |
|
|
781 | if [[ ${remote_ref} ]]; then |
|
|
782 | set -- "${@}" "${remote_ref#refs/heads/}" |
|
|
783 | else |
|
|
784 | set -- "${@}" "${new_commit_id}" |
|
|
785 | fi |
|
|
786 | echo "${@}" >&2 |
|
|
787 | "${@}" || die "git checkout ${remote_ref:-${new_commit_id}} failed" |
|
|
788 | } |
|
|
789 | git-r3_sub_checkout |
|
|
790 | |
|
|
791 | local old_commit_id=$( |
|
|
792 | git rev-parse --quiet --verify refs/git-r3/"${local_id}"/__old__ |
|
|
793 | ) |
|
|
794 | if [[ ! ${old_commit_id} ]]; then |
|
|
795 | echo "GIT NEW branch -->" |
|
|
796 | echo " repository: ${repos[0]}" |
|
|
797 | echo " at the commit: ${new_commit_id}" |
|
|
798 | else |
|
|
799 | # diff against previous revision |
|
|
800 | echo "GIT update -->" |
|
|
801 | echo " repository: ${repos[0]}" |
|
|
802 | # write out message based on the revisions |
|
|
803 | if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then |
|
|
804 | echo " updating from commit: ${old_commit_id}" |
|
|
805 | echo " to commit: ${new_commit_id}" |
|
|
806 | |
|
|
807 | git --no-pager diff --stat \ |
|
|
808 | ${old_commit_id}..${new_commit_id} |
|
|
809 | else |
|
|
810 | echo " at the commit: ${new_commit_id}" |
|
|
811 | fi |
|
|
812 | fi |
|
|
813 | git update-ref --no-deref refs/git-r3/"${local_id}"/{__old__,__main__} || die |
|
|
814 | |
|
|
815 | # recursively checkout submodules |
|
|
816 | if [[ -f ${out_dir}/.gitmodules ]]; then |
|
|
817 | local submodules |
|
|
818 | _git-r3_set_submodules \ |
|
|
819 | "$(<"${out_dir}"/.gitmodules)" |
|
|
820 | |
|
|
821 | while [[ ${submodules[@]} ]]; do |
|
|
822 | local subname=${submodules[0]} |
|
|
823 | local url=${submodules[1]} |
|
|
824 | local path=${submodules[2]} |
|
|
825 | local subrepos |
|
|
826 | _git-r3_set_subrepos "${url}" "${repos[@]}" |
|
|
827 | |
|
|
828 | git-r3_checkout "${subrepos[*]}" "${out_dir}/${path}" \ |
|
|
829 | "${local_id}/${subname}" |
|
|
830 | |
|
|
831 | submodules=( "${submodules[@]:3}" ) # shift |
|
|
832 | done |
|
|
833 | fi |
|
|
834 | |
|
|
835 | # keep this *after* submodules |
|
|
836 | export EGIT_DIR=${GIT_DIR} |
|
|
837 | export EGIT_VERSION=${new_commit_id} |
|
|
838 | } |
|
|
839 | |
|
|
840 | # @FUNCTION: git-r3_peek_remote_ref |
|
|
841 | # @USAGE: [<repo-uri> [<remote-ref>]] |
|
|
842 | # @DESCRIPTION: |
|
|
843 | # Peek the reference in the remote repository and print the matching |
|
|
844 | # (newest) commit SHA1. |
|
|
845 | # |
|
|
846 | # <repo-uri> specifies the repository URIs to fetch from, as a space- |
|
|
847 | # -separated list. When not specified, defaults to ${EGIT_REPO_URI}. |
|
|
848 | # |
|
|
849 | # <remote-ref> specifies the remote ref to peek. It is preferred to use |
|
|
850 | # 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>' |
|
|
851 | # for tags. Alternatively, 'HEAD' may be used for upstream default |
|
|
852 | # branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal |
|
|
853 | # 'HEAD' that is set to a non-null value. |
|
|
854 | # |
|
|
855 | # The operation will be done purely on the remote, without using local |
|
|
856 | # storage. If commit SHA1 is provided as <remote-ref>, the function will |
|
|
857 | # fail due to limitations of git protocol. |
|
|
858 | # |
|
|
859 | # On success, the function returns 0 and writes hexadecimal commit SHA1 |
|
|
860 | # to stdout. On failure, the function returns 1. |
|
|
861 | git-r3_peek_remote_ref() { |
|
|
862 | debug-print-function ${FUNCNAME} "$@" |
|
|
863 | |
|
|
864 | local repos |
|
|
865 | if [[ ${1} ]]; then |
|
|
866 | repos=( ${1} ) |
|
|
867 | elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then |
|
|
868 | repos=( "${EGIT_REPO_URI[@]}" ) |
|
|
869 | else |
|
|
870 | repos=( ${EGIT_REPO_URI} ) |
|
|
871 | fi |
|
|
872 | |
|
|
873 | local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} |
|
|
874 | local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} |
|
|
875 | |
|
|
876 | [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" |
|
|
877 | |
|
|
878 | local r success |
|
|
879 | for r in "${repos[@]}"; do |
410 | einfo "Fetching ${remote_ref} from ${r} ..." |
880 | einfo "Peeking ${remote_ref} on ${r} ..." >&2 |
411 | |
881 | |
412 | local is_branch lookup_ref |
882 | local is_branch lookup_ref |
413 | if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] |
883 | if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] |
414 | then |
884 | then |
415 | is_branch=1 |
885 | is_branch=1 |
… | |
… | |
418 | # ls-remote by commit is going to fail anyway, |
888 | # ls-remote by commit is going to fail anyway, |
419 | # so we may as well pass refs/tags/ABCDEF... |
889 | # so we may as well pass refs/tags/ABCDEF... |
420 | lookup_ref=refs/tags/${remote_ref} |
890 | lookup_ref=refs/tags/${remote_ref} |
421 | fi |
891 | fi |
422 | |
892 | |
423 | # first, try ls-remote to see if ${remote_ref} is a real ref |
|
|
424 | # and not a commit id. if it succeeds, we can pass ${remote_ref} |
|
|
425 | # to 'fetch'. otherwise, we will just fetch everything |
|
|
426 | |
|
|
427 | # split on whitespace |
|
|
428 | local ref=( |
|
|
429 | $(git ls-remote "${r}" "${lookup_ref}" || echo __FAIL__) |
|
|
430 | ) |
|
|
431 | |
|
|
432 | # normally, ref[0] is a hash, so we can do magic strings here |
|
|
433 | [[ ${ref[0]} == __FAIL__ ]] && continue |
|
|
434 | |
|
|
435 | local nonshallow=${EGIT_NONSHALLOW} |
|
|
436 | local ref_param=() |
|
|
437 | if [[ ! ${ref[0]} ]]; then |
|
|
438 | nonshallow=1 |
|
|
439 | fi |
|
|
440 | |
|
|
441 | # 1. if we need a non-shallow clone and we have a shallow one, |
|
|
442 | # we need to unshallow it explicitly. |
|
|
443 | # 2. if we want a shallow clone, we just pass '--depth 1' |
|
|
444 | # to the first fetch in the repo. passing '--depth' |
|
|
445 | # to further requests usually results in more data being |
|
|
446 | # downloaded than without it. |
|
|
447 | # 3. if we update a shallow clone, we try without '--depth' |
|
|
448 | # first since that usually transfers less data. however, |
|
|
449 | # we use git-r3_smart_fetch that can switch into '--depth 1' |
|
|
450 | # if that looks beneficial. |
|
|
451 | |
|
|
452 | local fetch_command=( git fetch ) |
|
|
453 | if [[ ${nonshallow} ]]; then |
|
|
454 | if [[ -f ${GIT_DIR}/shallow ]]; then |
|
|
455 | ref_param+=( --unshallow ) |
|
|
456 | fi |
|
|
457 | # fetch all branches |
|
|
458 | ref_param+=( "refs/heads/*:refs/remotes/origin/*" ) |
|
|
459 | else |
|
|
460 | # 'git show-ref --heads' returns 1 when there are no branches |
|
|
461 | if ! git show-ref --heads -q; then |
|
|
462 | ref_param+=( --depth 1 ) |
|
|
463 | else |
|
|
464 | fetch_command=( _git-r3_smart_fetch ) |
|
|
465 | fi |
|
|
466 | fi |
|
|
467 | |
|
|
468 | # now, another important thing. we may only fetch a remote |
|
|
469 | # branch directly to a local branch. Otherwise, we need to fetch |
|
|
470 | # the commit and re-create the branch on top of it. |
|
|
471 | |
|
|
472 | if [[ ${ref[0]} ]]; then |
|
|
473 | if [[ ${is_branch} ]]; then |
|
|
474 | ref_param+=( -f "${remote_ref}:${local_id}/__main__" ) |
|
|
475 | else |
|
|
476 | ref_param+=( "refs/tags/${remote_ref}" ) |
|
|
477 | fi |
|
|
478 | fi |
|
|
479 | |
|
|
480 | # if ${remote_ref} is branch or tag, ${ref[@]} will contain |
|
|
481 | # the respective commit id. otherwise, it will be an empty |
|
|
482 | # array, so the following won't evaluate to a parameter. |
|
|
483 | set -- "${fetch_command[@]}" --no-tags "${r}" "${ref_param[@]}" |
|
|
484 | echo "${@}" >&2 |
|
|
485 | if "${@}"; then |
|
|
486 | if [[ ! ${is_branch} ]]; then |
|
|
487 | set -- git branch -f "${local_id}/__main__" \ |
|
|
488 | "${ref[0]:-${remote_ref}}" |
|
|
489 | echo "${@}" >&2 |
|
|
490 | if ! "${@}"; then |
|
|
491 | die "Creating branch for ${remote_ref} failed (wrong ref?)." |
|
|
492 | fi |
|
|
493 | fi |
|
|
494 | |
|
|
495 | success=1 |
|
|
496 | break |
|
|
497 | fi |
|
|
498 | done |
|
|
499 | [[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI" |
|
|
500 | |
|
|
501 | # recursively fetch submodules |
|
|
502 | if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then |
|
|
503 | local submodules |
|
|
504 | _git-r3_set_submodules \ |
|
|
505 | "$(git cat-file -p "${local_ref}":.gitmodules || die)" |
|
|
506 | |
|
|
507 | while [[ ${submodules[@]} ]]; do |
|
|
508 | local subname=${submodules[0]} |
|
|
509 | local url=${submodules[1]} |
|
|
510 | local path=${submodules[2]} |
|
|
511 | local commit=$(git rev-parse "${local_ref}:${path}") |
|
|
512 | |
|
|
513 | if [[ ! ${commit} ]]; then |
|
|
514 | die "Unable to get commit id for submodule ${subname}" |
|
|
515 | fi |
|
|
516 | |
|
|
517 | git-r3_fetch "${url}" "${commit}" "${local_id}/${subname}" |
|
|
518 | |
|
|
519 | submodules=( "${submodules[@]:3}" ) # shift |
|
|
520 | done |
|
|
521 | fi |
|
|
522 | } |
|
|
523 | |
|
|
524 | # @FUNCTION: git-r3_checkout |
|
|
525 | # @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]] |
|
|
526 | # @DESCRIPTION: |
|
|
527 | # Check the previously fetched tree to the working copy. |
|
|
528 | # |
|
|
529 | # <repo-uri> specifies the repository URIs, as a space-separated list. |
|
|
530 | # The first URI will be used as repository group identifier |
|
|
531 | # and therefore must be used consistently with git-r3_fetch. |
|
|
532 | # The remaining URIs are not used and therefore may be omitted. |
|
|
533 | # When not specified, defaults to ${EGIT_REPO_URI}. |
|
|
534 | # |
|
|
535 | # <checkout-path> specifies the path to place the checkout. It defaults |
|
|
536 | # to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}. |
|
|
537 | # |
|
|
538 | # <local-id> needs to specify the local identifier that was used |
|
|
539 | # for respective git-r3_fetch. |
|
|
540 | # |
|
|
541 | # The checkout operation will write to the working copy, and export |
|
|
542 | # the repository state into the environment. If the repository contains |
|
|
543 | # submodules, they will be checked out recursively. |
|
|
544 | git-r3_checkout() { |
|
|
545 | debug-print-function ${FUNCNAME} "$@" |
|
|
546 | |
|
|
547 | local repos |
|
|
548 | if [[ ${1} ]]; then |
|
|
549 | repos=( ${1} ) |
|
|
550 | elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then |
|
|
551 | repos=( "${EGIT_REPO_URI[@]}" ) |
|
|
552 | else |
|
|
553 | repos=( ${EGIT_REPO_URI} ) |
|
|
554 | fi |
|
|
555 | |
|
|
556 | local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}} |
|
|
557 | local local_id=${3:-${CATEGORY}/${PN}/${SLOT}} |
|
|
558 | |
|
|
559 | local -x GIT_DIR GIT_WORK_TREE |
|
|
560 | _git-r3_set_gitdir "${repos[0]}" |
|
|
561 | GIT_WORK_TREE=${out_dir} |
|
|
562 | mkdir -p "${GIT_WORK_TREE}" |
|
|
563 | |
|
|
564 | einfo "Checking out ${repos[0]} to ${out_dir} ..." |
|
|
565 | |
|
|
566 | if ! git cat-file -e refs/heads/"${local_id}"/__main__ |
|
|
567 | then |
|
|
568 | if [[ ${EVCS_OFFLINE} ]]; then |
|
|
569 | die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE." |
|
|
570 | else |
|
|
571 | die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?" |
|
|
572 | fi |
|
|
573 | fi |
|
|
574 | |
|
|
575 | set -- git checkout -f "${local_id}"/__main__ . |
|
|
576 | echo "${@}" >&2 |
|
|
577 | "${@}" || die "git checkout ${local_id}/__main__ failed" |
|
|
578 | |
|
|
579 | # diff against previous revision (if any) |
|
|
580 | local new_commit_id=$(git rev-parse --verify "${local_id}"/__main__) |
|
|
581 | local old_commit_id=$( |
|
|
582 | git rev-parse --verify "${local_id}"/__old__ 2>/dev/null |
|
|
583 | ) |
|
|
584 | |
|
|
585 | if [[ ! ${old_commit_id} ]]; then |
|
|
586 | echo "GIT NEW branch -->" |
|
|
587 | echo " repository: ${repos[0]}" |
|
|
588 | echo " at the commit: ${new_commit_id}" |
|
|
589 | else |
|
|
590 | echo "GIT update -->" |
|
|
591 | echo " repository: ${repos[0]}" |
|
|
592 | # write out message based on the revisions |
|
|
593 | if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then |
|
|
594 | echo " updating from commit: ${old_commit_id}" |
|
|
595 | echo " to commit: ${new_commit_id}" |
|
|
596 | |
|
|
597 | git --no-pager diff --stat \ |
|
|
598 | ${old_commit_id}..${new_commit_id} |
|
|
599 | else |
|
|
600 | echo " at the commit: ${new_commit_id}" |
|
|
601 | fi |
|
|
602 | fi |
|
|
603 | git branch -f "${local_id}"/{__old__,__main__} || die |
|
|
604 | |
|
|
605 | # recursively checkout submodules |
|
|
606 | if [[ -f ${GIT_WORK_TREE}/.gitmodules ]]; then |
|
|
607 | local submodules |
|
|
608 | _git-r3_set_submodules \ |
|
|
609 | "$(<"${GIT_WORK_TREE}"/.gitmodules)" |
|
|
610 | |
|
|
611 | while [[ ${submodules[@]} ]]; do |
|
|
612 | local subname=${submodules[0]} |
|
|
613 | local url=${submodules[1]} |
|
|
614 | local path=${submodules[2]} |
|
|
615 | |
|
|
616 | git-r3_checkout "${url}" "${GIT_WORK_TREE}/${path}" \ |
|
|
617 | "${local_id}/${subname}" |
|
|
618 | |
|
|
619 | submodules=( "${submodules[@]:3}" ) # shift |
|
|
620 | done |
|
|
621 | fi |
|
|
622 | |
|
|
623 | # keep this *after* submodules |
|
|
624 | export EGIT_DIR=${GIT_DIR} |
|
|
625 | export EGIT_VERSION=${new_commit_id} |
|
|
626 | } |
|
|
627 | |
|
|
628 | # @FUNCTION: git-r3_peek_remote_ref |
|
|
629 | # @USAGE: [<repo-uri> [<remote-ref>]] |
|
|
630 | # @DESCRIPTION: |
|
|
631 | # Peek the reference in the remote repository and print the matching |
|
|
632 | # (newest) commit SHA1. |
|
|
633 | # |
|
|
634 | # <repo-uri> specifies the repository URIs to fetch from, as a space- |
|
|
635 | # -separated list. When not specified, defaults to ${EGIT_REPO_URI}. |
|
|
636 | # |
|
|
637 | # <remote-ref> specifies the remote ref to peek. It is preferred to use |
|
|
638 | # 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>' |
|
|
639 | # for tags. Alternatively, 'HEAD' may be used for upstream default |
|
|
640 | # branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal |
|
|
641 | # 'HEAD' that is set to a non-null value. |
|
|
642 | # |
|
|
643 | # The operation will be done purely on the remote, without using local |
|
|
644 | # storage. If commit SHA1 is provided as <remote-ref>, the function will |
|
|
645 | # fail due to limitations of git protocol. |
|
|
646 | # |
|
|
647 | # On success, the function returns 0 and writes hexadecimal commit SHA1 |
|
|
648 | # to stdout. On failure, the function returns 1. |
|
|
649 | git-r3_peek_remote_ref() { |
|
|
650 | debug-print-function ${FUNCNAME} "$@" |
|
|
651 | |
|
|
652 | local repos |
|
|
653 | if [[ ${1} ]]; then |
|
|
654 | repos=( ${1} ) |
|
|
655 | elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then |
|
|
656 | repos=( "${EGIT_REPO_URI[@]}" ) |
|
|
657 | else |
|
|
658 | repos=( ${EGIT_REPO_URI} ) |
|
|
659 | fi |
|
|
660 | |
|
|
661 | local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} |
|
|
662 | local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} |
|
|
663 | |
|
|
664 | [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" |
|
|
665 | |
|
|
666 | local r success |
|
|
667 | for r in "${repos[@]}"; do |
|
|
668 | einfo "Peeking ${remote_ref} on ${r} ..." >&2 |
|
|
669 | |
|
|
670 | local is_branch lookup_ref |
|
|
671 | if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] |
|
|
672 | then |
|
|
673 | is_branch=1 |
|
|
674 | lookup_ref=${remote_ref} |
|
|
675 | else |
|
|
676 | # ls-remote by commit is going to fail anyway, |
|
|
677 | # so we may as well pass refs/tags/ABCDEF... |
|
|
678 | lookup_ref=refs/tags/${remote_ref} |
|
|
679 | fi |
|
|
680 | |
|
|
681 | # split on whitespace |
893 | # split on whitespace |
682 | local ref=( |
894 | local ref=( |
683 | $(git ls-remote "${r}" "${lookup_ref}") |
895 | $(git ls-remote "${r}" "${lookup_ref}") |
684 | ) |
896 | ) |
685 | |
897 | |
… | |
… | |
692 | return 1 |
904 | return 1 |
693 | } |
905 | } |
694 | |
906 | |
695 | git-r3_src_fetch() { |
907 | git-r3_src_fetch() { |
696 | debug-print-function ${FUNCNAME} "$@" |
908 | debug-print-function ${FUNCNAME} "$@" |
697 | |
|
|
698 | [[ ${EVCS_OFFLINE} ]] && return |
|
|
699 | |
909 | |
700 | if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then |
910 | if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then |
701 | ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider" |
911 | ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider" |
702 | ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use" |
912 | ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use" |
703 | ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones" |
913 | ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones" |