1 |
# Copyright 1999-2013 Gentoo Foundation |
2 |
# Distributed under the terms of the GNU General Public License v2 |
3 |
# $Header: /var/cvsroot/gentoo-x86/eclass/git-r3.eclass,v 1.10 2013/09/26 12:38:38 mgorny Exp $ |
4 |
|
5 |
# @ECLASS: git-r3.eclass |
6 |
# @MAINTAINER: |
7 |
# Michał Górny <mgorny@gentoo.org> |
8 |
# @BLURB: Eclass for fetching and unpacking git repositories. |
9 |
# @DESCRIPTION: |
10 |
# Third generation eclass for easing maitenance of live ebuilds using |
11 |
# git as remote repository. The eclass supports lightweight (shallow) |
12 |
# clones and bare clones of submodules. |
13 |
|
14 |
case "${EAPI:-0}" in |
15 |
0|1|2|3|4|5) |
16 |
;; |
17 |
*) |
18 |
die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" |
19 |
;; |
20 |
esac |
21 |
|
22 |
if [[ ! ${_GIT_R3} ]]; then |
23 |
|
24 |
inherit eutils |
25 |
|
26 |
fi |
27 |
|
28 |
EXPORT_FUNCTIONS src_unpack |
29 |
|
30 |
if [[ ! ${_GIT_R3} ]]; then |
31 |
|
32 |
# @ECLASS-VARIABLE: EGIT3_STORE_DIR |
33 |
# @DESCRIPTION: |
34 |
# Storage directory for git sources. |
35 |
# |
36 |
# EGIT3_STORE_DIR=${DISTDIR}/git3-src |
37 |
|
38 |
# @ECLASS-VARIABLE: EGIT_REPO_URI |
39 |
# @REQUIRED |
40 |
# @DESCRIPTION: |
41 |
# URIs to the repository, e.g. git://foo, https://foo. If multiple URIs |
42 |
# are provided, the eclass will consider them as fallback URIs to try |
43 |
# if the first URI does not work. |
44 |
# |
45 |
# It can be overriden via env using ${PN}_LIVE_REPO variable. |
46 |
# |
47 |
# Can be a whitespace-separated list or an array. |
48 |
# |
49 |
# Example: |
50 |
# @CODE |
51 |
# EGIT_REPO_URI="git://a/b.git https://c/d.git" |
52 |
# @CODE |
53 |
|
54 |
# @ECLASS-VARIABLE: EVCS_OFFLINE |
55 |
# @DEFAULT_UNSET |
56 |
# @DESCRIPTION: |
57 |
# If non-empty, this variable prevents any online operations. |
58 |
|
59 |
# @ECLASS-VARIABLE: EGIT_BRANCH |
60 |
# @DEFAULT_UNSET |
61 |
# @DESCRIPTION: |
62 |
# The branch name to check out. If unset, the upstream default (HEAD) |
63 |
# will be used. |
64 |
# |
65 |
# It can be overriden via env using ${PN}_LIVE_BRANCH variable. |
66 |
|
67 |
# @ECLASS-VARIABLE: EGIT_COMMIT |
68 |
# @DEFAULT_UNSET |
69 |
# @DESCRIPTION: |
70 |
# The tag name or commit identifier to check out. If unset, newest |
71 |
# commit from the branch will be used. If set, EGIT_BRANCH will |
72 |
# be ignored. |
73 |
# |
74 |
# It can be overriden via env using ${PN}_LIVE_COMMIT variable. |
75 |
|
76 |
# @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR |
77 |
# @DESCRIPTION: |
78 |
# The directory to check the git sources out to. |
79 |
# |
80 |
# EGIT_CHECKOUT_DIR=${WORKDIR}/${P} |
81 |
|
82 |
# @ECLASS-VARIABLE: EGIT_NONSHALLOW |
83 |
# @DEFAULT_UNSET |
84 |
# @DESCRIPTION: |
85 |
# Disable performing shallow fetches/clones. Shallow clones have |
86 |
# a fair number of limitations. Therefore, if you'd like the eclass to |
87 |
# perform complete clones instead, set this to a non-null value. |
88 |
# |
89 |
# This variable can be set in make.conf and ebuilds. The make.conf |
90 |
# value specifies user-specific default, while ebuilds may use it |
91 |
# to force deep clones when the server does not support shallow clones |
92 |
# (e.g. Google Code). |
93 |
|
94 |
# @FUNCTION: _git-r3_env_setup |
95 |
# @INTERNAL |
96 |
# @DESCRIPTION: |
97 |
# Set the eclass variables as necessary for operation. This can involve |
98 |
# setting EGIT_* to defaults or ${PN}_LIVE_* variables. |
99 |
_git-r3_env_setup() { |
100 |
debug-print-function ${FUNCNAME} "$@" |
101 |
|
102 |
local esc_pn livevar |
103 |
esc_pn=${PN//[-+]/_} |
104 |
|
105 |
livevar=${esc_pn}_LIVE_REPO |
106 |
EGIT_REPO_URI=${!livevar:-${EGIT_REPO_URI}} |
107 |
[[ ${!livevar} ]] \ |
108 |
&& ewarn "Using ${livevar}, no support will be provided" |
109 |
|
110 |
livevar=${esc_pn}_LIVE_BRANCH |
111 |
EGIT_BRANCH=${!livevar:-${EGIT_BRANCH}} |
112 |
[[ ${!livevar} ]] \ |
113 |
&& ewarn "Using ${livevar}, no support will be provided" |
114 |
|
115 |
livevar=${esc_pn}_LIVE_COMMIT |
116 |
EGIT_COMMIT=${!livevar:-${EGIT_COMMIT}} |
117 |
[[ ${!livevar} ]] \ |
118 |
&& ewarn "Using ${livevar}, no support will be provided" |
119 |
|
120 |
# Migration helpers. Remove them when git-2 is removed. |
121 |
|
122 |
if [[ ${EGIT_SOURCEDIR} ]]; then |
123 |
eerror "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR. While updating" |
124 |
eerror "your ebuild, please check whether the variable is necessary at all" |
125 |
eerror "since the default has been changed from \${S} to \${WORKDIR}/\${P}." |
126 |
eerror "Therefore, proper setting of S may be sufficient." |
127 |
die "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR." |
128 |
fi |
129 |
|
130 |
if [[ ${EGIT_MASTER} ]]; then |
131 |
eerror "EGIT_MASTER has been removed. Instead, the upstream default (HEAD)" |
132 |
eerror "is used by the eclass. Please remove the assignment or use EGIT_BRANCH" |
133 |
eerror "as necessary." |
134 |
die "EGIT_MASTER has been removed." |
135 |
fi |
136 |
|
137 |
if [[ ${EGIT_HAS_SUBMODULES} ]]; then |
138 |
eerror "EGIT_HAS_SUBMODULES has been removed. The eclass no longer needs" |
139 |
eerror "to switch the clone type in order to support submodules and therefore" |
140 |
eerror "submodules are detected and fetched automatically." |
141 |
die "EGIT_HAS_SUBMODULES is no longer necessary." |
142 |
fi |
143 |
|
144 |
if [[ ${EGIT_PROJECT} ]]; then |
145 |
eerror "EGIT_PROJECT has been removed. Instead, the eclass determines" |
146 |
eerror "the local clone path using path in canonical EGIT_REPO_URI." |
147 |
eerror "If the current algorithm causes issues for you, please report a bug." |
148 |
die "EGIT_PROJECT is no longer necessary." |
149 |
fi |
150 |
|
151 |
if [[ ${EGIT_BOOTSTRAP} ]]; then |
152 |
eerror "EGIT_BOOTSTRAP has been removed. Please create proper src_prepare()" |
153 |
eerror "instead." |
154 |
die "EGIT_BOOTSTRAP has been removed." |
155 |
fi |
156 |
|
157 |
if [[ ${EGIT_NOUNPACK} ]]; then |
158 |
eerror "EGIT_NOUNPACK has been removed. The eclass no longer calls default" |
159 |
eerror "unpack function. If necessary, please declare proper src_unpack()." |
160 |
die "EGIT_NOUNPACK has been removed." |
161 |
fi |
162 |
} |
163 |
|
164 |
# @FUNCTION: _git-r3_set_gitdir |
165 |
# @USAGE: <repo-uri> |
166 |
# @INTERNAL |
167 |
# @DESCRIPTION: |
168 |
# Obtain the local repository path and set it as GIT_DIR. Creates |
169 |
# a new repository if necessary. |
170 |
# |
171 |
# <repo-uri> may be used to compose the path. It should therefore be |
172 |
# a canonical URI to the repository. |
173 |
_git-r3_set_gitdir() { |
174 |
debug-print-function ${FUNCNAME} "$@" |
175 |
|
176 |
local repo_name=${1#*://*/} |
177 |
|
178 |
# strip the trailing slash |
179 |
repo_name=${repo_name%/} |
180 |
|
181 |
# strip common prefixes to make paths more likely to match |
182 |
# e.g. git://X/Y.git vs https://X/git/Y.git |
183 |
# (but just one of the prefixes) |
184 |
case "${repo_name}" in |
185 |
# gnome.org... who else? |
186 |
browse/*) repo_name=${repo_name#browse/};; |
187 |
# cgit can proxy requests to git |
188 |
cgit/*) repo_name=${repo_name#cgit/};; |
189 |
# pretty common |
190 |
git/*) repo_name=${repo_name#git/};; |
191 |
# gentoo.org |
192 |
gitroot/*) repo_name=${repo_name#gitroot/};; |
193 |
# google code, sourceforge |
194 |
p/*) repo_name=${repo_name#p/};; |
195 |
# kernel.org |
196 |
pub/scm/*) repo_name=${repo_name#pub/scm/};; |
197 |
esac |
198 |
# ensure a .git suffix, same reason |
199 |
repo_name=${repo_name%.git}.git |
200 |
# now replace all the slashes |
201 |
repo_name=${repo_name//\//_} |
202 |
|
203 |
local distdir=${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}} |
204 |
: ${EGIT3_STORE_DIR:=${distdir}/git3-src} |
205 |
|
206 |
GIT_DIR=${EGIT3_STORE_DIR}/${repo_name} |
207 |
|
208 |
if [[ ! -d ${EGIT3_STORE_DIR} ]]; then |
209 |
( |
210 |
addwrite / |
211 |
mkdir -m0755 -p "${EGIT3_STORE_DIR}" |
212 |
) || die "Unable to create ${EGIT3_STORE_DIR}" |
213 |
fi |
214 |
|
215 |
addwrite "${EGIT3_STORE_DIR}" |
216 |
if [[ ! -d ${GIT_DIR} ]]; then |
217 |
mkdir "${GIT_DIR}" || die |
218 |
git init --bare || die |
219 |
|
220 |
if [[ ! ${EGIT_NONSHALLOW} ]]; then |
221 |
# avoid auto-unshallow :) |
222 |
touch "${GIT_DIR}"/shallow || die |
223 |
fi |
224 |
fi |
225 |
} |
226 |
|
227 |
# @FUNCTION: _git-r3_set_submodules |
228 |
# @USAGE: <file-contents> |
229 |
# @INTERNAL |
230 |
# @DESCRIPTION: |
231 |
# Parse .gitmodules contents passed as <file-contents> |
232 |
# as in "$(cat .gitmodules)"). Composes a 'submodules' array that |
233 |
# contains in order (name, URL, path) for each submodule. |
234 |
_git-r3_set_submodules() { |
235 |
debug-print-function ${FUNCNAME} "$@" |
236 |
|
237 |
local data=${1} |
238 |
|
239 |
# ( name url path ... ) |
240 |
submodules=() |
241 |
|
242 |
local l |
243 |
while read l; do |
244 |
# submodule.<path>.path=<path> |
245 |
# submodule.<path>.url=<url> |
246 |
[[ ${l} == submodule.*.url=* ]] || continue |
247 |
|
248 |
l=${l#submodule.} |
249 |
local subname=${l%%.url=*} |
250 |
|
251 |
submodules+=( |
252 |
"${subname}" |
253 |
"$(echo "${data}" | git config -f /dev/fd/0 \ |
254 |
submodule."${subname}".url)" |
255 |
"$(echo "${data}" | git config -f /dev/fd/0 \ |
256 |
submodule."${subname}".path)" |
257 |
) |
258 |
done < <(echo "${data}" | git config -f /dev/fd/0 -l) |
259 |
} |
260 |
|
261 |
# @FUNCTION: _git-r3_smart_fetch |
262 |
# @USAGE: <git-fetch-args>... |
263 |
# @DESCRIPTION: |
264 |
# Try fetching without '--depth' and switch to '--depth 1' if that |
265 |
# will involve less objects fetched. |
266 |
_git-r3_smart_fetch() { |
267 |
debug-print-function ${FUNCNAME} "$@" |
268 |
|
269 |
local sed_regexp='.*Counting objects: \([0-9]*\), done\..*' |
270 |
|
271 |
# start the main fetch |
272 |
local cmd=( git fetch --progress "${@}" ) |
273 |
echo "${cmd[@]}" >&2 |
274 |
|
275 |
# we copy the output to the 'sed' pipe for parsing. whenever sed finds |
276 |
# the process count, it quits quickly to avoid delays in writing it. |
277 |
# then, we start a dummy 'cat' to keep the pipe alive |
278 |
|
279 |
"${cmd[@]}" 2>&1 \ |
280 |
| tee >( |
281 |
sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}" \ |
282 |
> "${T}"/git-r3_main.count |
283 |
exec cat >/dev/null |
284 |
) & |
285 |
local main_pid=${!} |
286 |
|
287 |
# start the helper process |
288 |
_git-r3_sub_fetch() { |
289 |
# wait for main fetch to get object count; if the server doesn't |
290 |
# output it, we won't even launch the parallel process |
291 |
while [[ ! -s ${T}/git-r3_main.count ]]; do |
292 |
sleep 0.25 |
293 |
done |
294 |
|
295 |
# ok, let's see if parallel fetch gives us smaller count |
296 |
# --dry-run will prevent it from writing to the local clone |
297 |
# and sed should terminate git with SIGPIPE |
298 |
local sub_count=$(git fetch --progress --dry-run --depth 1 "${@}" 2>&1 \ |
299 |
| sed -n -e "/${sed_regexp}/{s/${sed_regexp}/\1/p;q}") |
300 |
local main_count=$(<"${T}"/git-r3_main.count) |
301 |
|
302 |
# let's be real sure that '--depth 1' will be good for us. |
303 |
# note that we have purely objects counts, and '--depth 1' |
304 |
# may involve much bigger objects |
305 |
if [[ ${main_count} && ${main_count} -ge $(( sub_count * 3/2 )) ]] |
306 |
then |
307 |
# signal that we want shallow fetch instead, |
308 |
# and terminate the non-shallow fetch process |
309 |
touch "${T}"/git-r3_want_shallow || die |
310 |
kill ${main_pid} &>/dev/null |
311 |
exit 0 |
312 |
fi |
313 |
|
314 |
exit 1 |
315 |
} |
316 |
_git-r3_sub_fetch "${@}" & |
317 |
local sub_pid=${!} |
318 |
|
319 |
# wait for main process to terminate, either of its own |
320 |
# or by signal from subprocess |
321 |
wait ${main_pid} |
322 |
local main_ret=${?} |
323 |
|
324 |
# wait for subprocess to terminate, killing it if necessary. |
325 |
# if main fetch finished before it, there's no point in keeping |
326 |
# it alive. if main fetch was killed by it, it's done anyway |
327 |
kill ${sub_pid} &>/dev/null |
328 |
wait ${sub_pid} |
329 |
|
330 |
# now see if subprocess wanted to tell us something... |
331 |
if [[ -f ${T}/git-r3_want_shallow ]]; then |
332 |
rm "${T}"/git-r3_want_shallow || die |
333 |
|
334 |
# if fetch finished already (wasn't killed), ignore it |
335 |
[[ ${main_ret} -eq 0 ]] && return 0 |
336 |
|
337 |
# otherwise, restart as shallow fetch |
338 |
einfo "Restarting fetch using --depth 1 to save bandwidth ..." |
339 |
local cmd=( git fetch --progress --depth 1 "${@}" ) |
340 |
echo "${cmd[@]}" >&2 |
341 |
"${cmd[@]}" |
342 |
main_ret=${?} |
343 |
fi |
344 |
|
345 |
return ${main_ret} |
346 |
} |
347 |
|
348 |
# @FUNCTION: git-r3_fetch |
349 |
# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]] |
350 |
# @DESCRIPTION: |
351 |
# Fetch new commits to the local clone of repository. |
352 |
# |
353 |
# <repo-uri> specifies the repository URIs to fetch from, as a space- |
354 |
# -separated list. The first URI will be used as repository group |
355 |
# identifier and therefore must be used consistently. When not |
356 |
# specified, defaults to ${EGIT_REPO_URI}. |
357 |
# |
358 |
# <remote-ref> specifies the remote ref or commit id to fetch. |
359 |
# It is preferred to use 'refs/heads/<branch-name>' for branches |
360 |
# and 'refs/tags/<tag-name>' for tags. Other options are 'HEAD' |
361 |
# for upstream default branch and hexadecimal commit SHA1. Defaults |
362 |
# to the first of EGIT_COMMIT, EGIT_BRANCH or literal 'HEAD' that |
363 |
# is set to a non-null value. |
364 |
# |
365 |
# <local-id> specifies the local branch identifier that will be used to |
366 |
# locally store the fetch result. It should be unique to multiple |
367 |
# fetches within the repository that can be performed at the same time |
368 |
# (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT}. |
369 |
# This default should be fine unless you are fetching multiple trees |
370 |
# from the same repository in the same ebuild. |
371 |
# |
372 |
# The fetch operation will affect the EGIT_STORE only. It will not touch |
373 |
# the working copy, nor export any environment variables. |
374 |
# If the repository contains submodules, they will be fetched |
375 |
# recursively. |
376 |
git-r3_fetch() { |
377 |
debug-print-function ${FUNCNAME} "$@" |
378 |
|
379 |
local repos |
380 |
if [[ ${1} ]]; then |
381 |
repos=( ${1} ) |
382 |
elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then |
383 |
repos=( "${EGIT_REPO_URI[@]}" ) |
384 |
else |
385 |
repos=( ${EGIT_REPO_URI} ) |
386 |
fi |
387 |
|
388 |
local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} |
389 |
local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} |
390 |
local local_id=${3:-${CATEGORY}/${PN}/${SLOT}} |
391 |
local local_ref=refs/heads/${local_id}/__main__ |
392 |
|
393 |
[[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" |
394 |
|
395 |
local -x GIT_DIR |
396 |
_git-r3_set_gitdir "${repos[0]}" |
397 |
|
398 |
# try to fetch from the remote |
399 |
local r success |
400 |
for r in "${repos[@]}"; do |
401 |
einfo "Fetching ${remote_ref} from ${r} ..." |
402 |
|
403 |
local is_branch lookup_ref |
404 |
if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] |
405 |
then |
406 |
is_branch=1 |
407 |
lookup_ref=${remote_ref} |
408 |
else |
409 |
# ls-remote by commit is going to fail anyway, |
410 |
# so we may as well pass refs/tags/ABCDEF... |
411 |
lookup_ref=refs/tags/${remote_ref} |
412 |
fi |
413 |
|
414 |
# first, try ls-remote to see if ${remote_ref} is a real ref |
415 |
# and not a commit id. if it succeeds, we can pass ${remote_ref} |
416 |
# to 'fetch'. otherwise, we will just fetch everything |
417 |
|
418 |
# split on whitespace |
419 |
local ref=( |
420 |
$(git ls-remote "${r}" "${lookup_ref}" || echo __FAIL__) |
421 |
) |
422 |
|
423 |
# normally, ref[0] is a hash, so we can do magic strings here |
424 |
[[ ${ref[0]} == __FAIL__ ]] && continue |
425 |
|
426 |
local nonshallow=${EGIT_NONSHALLOW} |
427 |
local ref_param=() |
428 |
if [[ ! ${ref[0]} ]]; then |
429 |
nonshallow=1 |
430 |
fi |
431 |
|
432 |
# 1. if we need a non-shallow clone and we have a shallow one, |
433 |
# we need to unshallow it explicitly. |
434 |
# 2. if we want a shallow clone, we just pass '--depth 1' |
435 |
# to the first fetch in the repo. passing '--depth' |
436 |
# to further requests usually results in more data being |
437 |
# downloaded than without it. |
438 |
# 3. if we update a shallow clone, we try without '--depth' |
439 |
# first since that usually transfers less data. however, |
440 |
# we use git-r3_smart_fetch that can switch into '--depth 1' |
441 |
# if that looks beneficial. |
442 |
|
443 |
local fetch_command=( git fetch ) |
444 |
if [[ ${nonshallow} ]]; then |
445 |
if [[ -f ${GIT_DIR}/shallow ]]; then |
446 |
ref_param+=( --unshallow ) |
447 |
fi |
448 |
else |
449 |
# 'git show-ref --heads' returns 1 when there are no branches |
450 |
if ! git show-ref --heads -q; then |
451 |
ref_param+=( --depth 1 ) |
452 |
else |
453 |
fetch_command=( _git-r3_smart_fetch ) |
454 |
fi |
455 |
fi |
456 |
|
457 |
# now, another important thing. we may only fetch a remote |
458 |
# branch directly to a local branch. Otherwise, we need to fetch |
459 |
# the commit and re-create the branch on top of it. |
460 |
|
461 |
if [[ ${ref[0]} ]]; then |
462 |
if [[ ${is_branch} ]]; then |
463 |
ref_param+=( -f "${remote_ref}:${local_id}/__main__" ) |
464 |
else |
465 |
ref_param+=( "refs/tags/${remote_ref}" ) |
466 |
fi |
467 |
fi |
468 |
|
469 |
# if ${remote_ref} is branch or tag, ${ref[@]} will contain |
470 |
# the respective commit id. otherwise, it will be an empty |
471 |
# array, so the following won't evaluate to a parameter. |
472 |
set -- "${fetch_command[@]}" --no-tags "${r}" "${ref_param[@]}" |
473 |
echo "${@}" >&2 |
474 |
if "${@}"; then |
475 |
if [[ ! ${is_branch} ]]; then |
476 |
set -- git branch -f "${local_id}/__main__" \ |
477 |
"${ref[0]:-${remote_ref}}" |
478 |
echo "${@}" >&2 |
479 |
if ! "${@}"; then |
480 |
die "Creating branch for ${remote_ref} failed (wrong ref?)." |
481 |
fi |
482 |
fi |
483 |
|
484 |
success=1 |
485 |
break |
486 |
fi |
487 |
done |
488 |
[[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI" |
489 |
|
490 |
# recursively fetch submodules |
491 |
if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then |
492 |
local submodules |
493 |
_git-r3_set_submodules \ |
494 |
"$(git cat-file -p "${local_ref}":.gitmodules || die)" |
495 |
|
496 |
while [[ ${submodules[@]} ]]; do |
497 |
local subname=${submodules[0]} |
498 |
local url=${submodules[1]} |
499 |
local path=${submodules[2]} |
500 |
local commit=$(git rev-parse "${local_ref}:${path}") |
501 |
|
502 |
if [[ ! ${commit} ]]; then |
503 |
die "Unable to get commit id for submodule ${subname}" |
504 |
fi |
505 |
|
506 |
git-r3_fetch "${url}" "${commit}" "${local_id}/${subname}" |
507 |
|
508 |
submodules=( "${submodules[@]:3}" ) # shift |
509 |
done |
510 |
fi |
511 |
} |
512 |
|
513 |
# @FUNCTION: git-r3_checkout |
514 |
# @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]] |
515 |
# @DESCRIPTION: |
516 |
# Check the previously fetched tree to the working copy. |
517 |
# |
518 |
# <repo-uri> specifies the repository URIs, as a space-separated list. |
519 |
# The first URI will be used as repository group identifier |
520 |
# and therefore must be used consistently with git-r3_fetch. |
521 |
# The remaining URIs are not used and therefore may be omitted. |
522 |
# When not specified, defaults to ${EGIT_REPO_URI}. |
523 |
# |
524 |
# <checkout-path> specifies the path to place the checkout. It defaults |
525 |
# to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}. |
526 |
# |
527 |
# <local-id> needs to specify the local identifier that was used |
528 |
# for respective git-r3_fetch. |
529 |
# |
530 |
# The checkout operation will write to the working copy, and export |
531 |
# the repository state into the environment. If the repository contains |
532 |
# submodules, they will be checked out recursively. |
533 |
git-r3_checkout() { |
534 |
debug-print-function ${FUNCNAME} "$@" |
535 |
|
536 |
local repos |
537 |
if [[ ${1} ]]; then |
538 |
repos=( ${1} ) |
539 |
elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then |
540 |
repos=( "${EGIT_REPO_URI[@]}" ) |
541 |
else |
542 |
repos=( ${EGIT_REPO_URI} ) |
543 |
fi |
544 |
|
545 |
local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}} |
546 |
local local_id=${3:-${CATEGORY}/${PN}/${SLOT}} |
547 |
|
548 |
local -x GIT_DIR GIT_WORK_TREE |
549 |
_git-r3_set_gitdir "${repos[0]}" |
550 |
GIT_WORK_TREE=${out_dir} |
551 |
mkdir -p "${GIT_WORK_TREE}" |
552 |
|
553 |
einfo "Checking out ${repos[0]} to ${out_dir} ..." |
554 |
|
555 |
if ! git cat-file -e refs/heads/"${local_id}"/__main__ |
556 |
then |
557 |
if [[ ${EVCS_OFFLINE} ]]; then |
558 |
die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE." |
559 |
else |
560 |
die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?" |
561 |
fi |
562 |
fi |
563 |
|
564 |
set -- git checkout -f "${local_id}"/__main__ . |
565 |
echo "${@}" >&2 |
566 |
"${@}" || die "git checkout ${local_id}/__main__ failed" |
567 |
|
568 |
# diff against previous revision (if any) |
569 |
local new_commit_id=$(git rev-parse --verify "${local_id}"/__main__) |
570 |
local old_commit_id=$( |
571 |
git rev-parse --verify "${local_id}"/__old__ 2>/dev/null |
572 |
) |
573 |
|
574 |
if [[ ! ${old_commit_id} ]]; then |
575 |
echo "GIT NEW branch -->" |
576 |
echo " repository: ${repos[0]}" |
577 |
echo " at the commit: ${new_commit_id}" |
578 |
else |
579 |
echo "GIT update -->" |
580 |
echo " repository: ${repos[0]}" |
581 |
# write out message based on the revisions |
582 |
if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then |
583 |
echo " updating from commit: ${old_commit_id}" |
584 |
echo " to commit: ${new_commit_id}" |
585 |
|
586 |
git --no-pager diff --stat \ |
587 |
${old_commit_id}..${new_commit_id} |
588 |
else |
589 |
echo " at the commit: ${new_commit_id}" |
590 |
fi |
591 |
fi |
592 |
git branch -f "${local_id}"/{__old__,__main__} || die |
593 |
|
594 |
# recursively checkout submodules |
595 |
if [[ -f ${GIT_WORK_TREE}/.gitmodules ]]; then |
596 |
local submodules |
597 |
_git-r3_set_submodules \ |
598 |
"$(<"${GIT_WORK_TREE}"/.gitmodules)" |
599 |
|
600 |
while [[ ${submodules[@]} ]]; do |
601 |
local subname=${submodules[0]} |
602 |
local url=${submodules[1]} |
603 |
local path=${submodules[2]} |
604 |
|
605 |
git-r3_checkout "${url}" "${GIT_WORK_TREE}/${path}" \ |
606 |
"${local_id}/${subname}" |
607 |
|
608 |
submodules=( "${submodules[@]:3}" ) # shift |
609 |
done |
610 |
fi |
611 |
|
612 |
# keep this *after* submodules |
613 |
export EGIT_DIR=${GIT_DIR} |
614 |
export EGIT_VERSION=${new_commit_id} |
615 |
} |
616 |
|
617 |
# @FUNCTION: git-r3_peek_remote_ref |
618 |
# @USAGE: [<repo-uri> [<remote-ref>]] |
619 |
# @DESCRIPTION: |
620 |
# Peek the reference in the remote repository and print the matching |
621 |
# (newest) commit SHA1. |
622 |
# |
623 |
# <repo-uri> specifies the repository URIs to fetch from, as a space- |
624 |
# -separated list. When not specified, defaults to ${EGIT_REPO_URI}. |
625 |
# |
626 |
# <remote-ref> specifies the remote ref to peek. It is preferred to use |
627 |
# 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>' |
628 |
# for tags. Alternatively, 'HEAD' may be used for upstream default |
629 |
# branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal |
630 |
# 'HEAD' that is set to a non-null value. |
631 |
# |
632 |
# The operation will be done purely on the remote, without using local |
633 |
# storage. If commit SHA1 is provided as <remote-ref>, the function will |
634 |
# fail due to limitations of git protocol. |
635 |
# |
636 |
# On success, the function returns 0 and writes hexadecimal commit SHA1 |
637 |
# to stdout. On failure, the function returns 1. |
638 |
git-r3_peek_remote_ref() { |
639 |
debug-print-function ${FUNCNAME} "$@" |
640 |
|
641 |
local repos |
642 |
if [[ ${1} ]]; then |
643 |
repos=( ${1} ) |
644 |
elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then |
645 |
repos=( "${EGIT_REPO_URI[@]}" ) |
646 |
else |
647 |
repos=( ${EGIT_REPO_URI} ) |
648 |
fi |
649 |
|
650 |
local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} |
651 |
local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} |
652 |
|
653 |
[[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" |
654 |
|
655 |
local r success |
656 |
for r in "${repos[@]}"; do |
657 |
einfo "Peeking ${remote_ref} on ${r} ..." >&2 |
658 |
|
659 |
local is_branch lookup_ref |
660 |
if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] |
661 |
then |
662 |
is_branch=1 |
663 |
lookup_ref=${remote_ref} |
664 |
else |
665 |
# ls-remote by commit is going to fail anyway, |
666 |
# so we may as well pass refs/tags/ABCDEF... |
667 |
lookup_ref=refs/tags/${remote_ref} |
668 |
fi |
669 |
|
670 |
# split on whitespace |
671 |
local ref=( |
672 |
$(git ls-remote "${r}" "${lookup_ref}") |
673 |
) |
674 |
|
675 |
if [[ ${ref[0]} ]]; then |
676 |
echo "${ref[0]}" |
677 |
return 0 |
678 |
fi |
679 |
done |
680 |
|
681 |
return 1 |
682 |
} |
683 |
|
684 |
git-r3_src_fetch() { |
685 |
debug-print-function ${FUNCNAME} "$@" |
686 |
|
687 |
[[ ${EVCS_OFFLINE} ]] && return |
688 |
|
689 |
if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then |
690 |
ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider" |
691 |
ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use" |
692 |
ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones" |
693 |
ewarn "when git-2 eclass becomes deprecated." |
694 |
fi |
695 |
|
696 |
_git-r3_env_setup |
697 |
git-r3_fetch |
698 |
} |
699 |
|
700 |
git-r3_src_unpack() { |
701 |
debug-print-function ${FUNCNAME} "$@" |
702 |
|
703 |
_git-r3_env_setup |
704 |
git-r3_src_fetch |
705 |
git-r3_checkout |
706 |
} |
707 |
|
708 |
# https://bugs.gentoo.org/show_bug.cgi?id=482666 |
709 |
git-r3_pkg_outofdate() { |
710 |
debug-print-function ${FUNCNAME} "$@" |
711 |
|
712 |
local new_commit_id=$(git-r3_peek_remote_ref) |
713 |
ewarn "old: ${EGIT_VERSION}" |
714 |
ewarn "new: ${new_commit_id}" |
715 |
[[ ${new_commit_id} && ${old_commit_id} ]] || return 2 |
716 |
|
717 |
[[ ${EGIT_VERSION} != ${new_commit_id} ]] |
718 |
} |
719 |
|
720 |
_GIT_R3=1 |
721 |
fi |