1 |
# Copyright 1999-2014 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.40 2014/03/24 21:32:31 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. |
12 |
|
13 |
case "${EAPI:-0}" in |
14 |
0|1|2|3|4|5) |
15 |
;; |
16 |
*) |
17 |
die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" |
18 |
;; |
19 |
esac |
20 |
|
21 |
if [[ ! ${_GIT_R3} ]]; then |
22 |
|
23 |
inherit eutils |
24 |
|
25 |
fi |
26 |
|
27 |
EXPORT_FUNCTIONS src_unpack |
28 |
|
29 |
if [[ ! ${_GIT_R3} ]]; then |
30 |
|
31 |
if [[ ! ${_INHERITED_BY_GIT_2} ]]; then |
32 |
DEPEND=">=dev-vcs/git-1.8.2.1" |
33 |
fi |
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 |
|
89 |
# @ECLASS-VARIABLE: EGIT3_STORE_DIR |
90 |
# @DESCRIPTION: |
91 |
# Storage directory for git sources. |
92 |
# |
93 |
# This is intended to be set by user in make.conf. Ebuilds must not set |
94 |
# it. |
95 |
# |
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 |
111 |
|
112 |
# @ECLASS-VARIABLE: EGIT_REPO_URI |
113 |
# @REQUIRED |
114 |
# @DESCRIPTION: |
115 |
# URIs to the repository, e.g. git://foo, https://foo. If multiple URIs |
116 |
# are provided, the eclass will consider them as fallback URIs to try |
117 |
# if the first URI does not work. |
118 |
# |
119 |
# It can be overriden via env using ${PN}_LIVE_REPO variable. |
120 |
# |
121 |
# Can be a whitespace-separated list or an array. |
122 |
# |
123 |
# Example: |
124 |
# @CODE |
125 |
# EGIT_REPO_URI="git://a/b.git https://c/d.git" |
126 |
# @CODE |
127 |
|
128 |
# @ECLASS-VARIABLE: EVCS_OFFLINE |
129 |
# @DEFAULT_UNSET |
130 |
# @DESCRIPTION: |
131 |
# If non-empty, this variable prevents any online operations. |
132 |
|
133 |
# @ECLASS-VARIABLE: EGIT_BRANCH |
134 |
# @DEFAULT_UNSET |
135 |
# @DESCRIPTION: |
136 |
# The branch name to check out. If unset, the upstream default (HEAD) |
137 |
# will be used. |
138 |
# |
139 |
# It can be overriden via env using ${PN}_LIVE_BRANCH variable. |
140 |
|
141 |
# @ECLASS-VARIABLE: EGIT_COMMIT |
142 |
# @DEFAULT_UNSET |
143 |
# @DESCRIPTION: |
144 |
# The tag name or commit identifier to check out. If unset, newest |
145 |
# commit from the branch will be used. If set, EGIT_BRANCH will |
146 |
# be ignored. |
147 |
# |
148 |
# It can be overriden via env using ${PN}_LIVE_COMMIT variable. |
149 |
|
150 |
# @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR |
151 |
# @DESCRIPTION: |
152 |
# The directory to check the git sources out to. |
153 |
# |
154 |
# EGIT_CHECKOUT_DIR=${WORKDIR}/${P} |
155 |
|
156 |
# @FUNCTION: _git-r3_env_setup |
157 |
# @INTERNAL |
158 |
# @DESCRIPTION: |
159 |
# Set the eclass variables as necessary for operation. This can involve |
160 |
# setting EGIT_* to defaults or ${PN}_LIVE_* variables. |
161 |
_git-r3_env_setup() { |
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 |
195 |
|
196 |
local esc_pn livevar |
197 |
esc_pn=${PN//[-+]/_} |
198 |
|
199 |
livevar=${esc_pn}_LIVE_REPO |
200 |
EGIT_REPO_URI=${!livevar:-${EGIT_REPO_URI}} |
201 |
[[ ${!livevar} ]] \ |
202 |
&& ewarn "Using ${livevar}, no support will be provided" |
203 |
|
204 |
livevar=${esc_pn}_LIVE_BRANCH |
205 |
EGIT_BRANCH=${!livevar:-${EGIT_BRANCH}} |
206 |
[[ ${!livevar} ]] \ |
207 |
&& ewarn "Using ${livevar}, no support will be provided" |
208 |
|
209 |
livevar=${esc_pn}_LIVE_COMMIT |
210 |
EGIT_COMMIT=${!livevar:-${EGIT_COMMIT}} |
211 |
[[ ${!livevar} ]] \ |
212 |
&& ewarn "Using ${livevar}, no support will be provided" |
213 |
|
214 |
# Migration helpers. Remove them when git-2 is removed. |
215 |
|
216 |
if [[ ${EGIT_SOURCEDIR} ]]; then |
217 |
eerror "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR. While updating" |
218 |
eerror "your ebuild, please check whether the variable is necessary at all" |
219 |
eerror "since the default has been changed from \${S} to \${WORKDIR}/\${P}." |
220 |
eerror "Therefore, proper setting of S may be sufficient." |
221 |
die "EGIT_SOURCEDIR has been replaced by EGIT_CHECKOUT_DIR." |
222 |
fi |
223 |
|
224 |
if [[ ${EGIT_MASTER} ]]; then |
225 |
eerror "EGIT_MASTER has been removed. Instead, the upstream default (HEAD)" |
226 |
eerror "is used by the eclass. Please remove the assignment or use EGIT_BRANCH" |
227 |
eerror "as necessary." |
228 |
die "EGIT_MASTER has been removed." |
229 |
fi |
230 |
|
231 |
if [[ ${EGIT_HAS_SUBMODULES} ]]; then |
232 |
eerror "EGIT_HAS_SUBMODULES has been removed. The eclass no longer needs" |
233 |
eerror "to switch the clone type in order to support submodules and therefore" |
234 |
eerror "submodules are detected and fetched automatically." |
235 |
die "EGIT_HAS_SUBMODULES is no longer necessary." |
236 |
fi |
237 |
|
238 |
if [[ ${EGIT_PROJECT} ]]; then |
239 |
eerror "EGIT_PROJECT has been removed. Instead, the eclass determines" |
240 |
eerror "the local clone path using path in canonical EGIT_REPO_URI." |
241 |
eerror "If the current algorithm causes issues for you, please report a bug." |
242 |
die "EGIT_PROJECT is no longer necessary." |
243 |
fi |
244 |
|
245 |
if [[ ${EGIT_BOOTSTRAP} ]]; then |
246 |
eerror "EGIT_BOOTSTRAP has been removed. Please create proper src_prepare()" |
247 |
eerror "instead." |
248 |
die "EGIT_BOOTSTRAP has been removed." |
249 |
fi |
250 |
|
251 |
if [[ ${EGIT_NOUNPACK} ]]; then |
252 |
eerror "EGIT_NOUNPACK has been removed. The eclass no longer calls default" |
253 |
eerror "unpack function. If necessary, please declare proper src_unpack()." |
254 |
die "EGIT_NOUNPACK has been removed." |
255 |
fi |
256 |
} |
257 |
|
258 |
# @FUNCTION: _git-r3_set_gitdir |
259 |
# @USAGE: <repo-uri> |
260 |
# @INTERNAL |
261 |
# @DESCRIPTION: |
262 |
# Obtain the local repository path and set it as GIT_DIR. Creates |
263 |
# a new repository if necessary. |
264 |
# |
265 |
# <repo-uri> may be used to compose the path. It should therefore be |
266 |
# a canonical URI to the repository. |
267 |
_git-r3_set_gitdir() { |
268 |
debug-print-function ${FUNCNAME} "$@" |
269 |
|
270 |
local repo_name=${1#*://*/} |
271 |
|
272 |
# strip the trailing slash |
273 |
repo_name=${repo_name%/} |
274 |
|
275 |
# strip common prefixes to make paths more likely to match |
276 |
# e.g. git://X/Y.git vs https://X/git/Y.git |
277 |
# (but just one of the prefixes) |
278 |
case "${repo_name}" in |
279 |
# gnome.org... who else? |
280 |
browse/*) repo_name=${repo_name#browse/};; |
281 |
# cgit can proxy requests to git |
282 |
cgit/*) repo_name=${repo_name#cgit/};; |
283 |
# pretty common |
284 |
git/*) repo_name=${repo_name#git/};; |
285 |
# gentoo.org |
286 |
gitroot/*) repo_name=${repo_name#gitroot/};; |
287 |
# google code, sourceforge |
288 |
p/*) repo_name=${repo_name#p/};; |
289 |
# kernel.org |
290 |
pub/scm/*) repo_name=${repo_name#pub/scm/};; |
291 |
esac |
292 |
# ensure a .git suffix, same reason |
293 |
repo_name=${repo_name%.git}.git |
294 |
# now replace all the slashes |
295 |
repo_name=${repo_name//\//_} |
296 |
|
297 |
local distdir=${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}} |
298 |
: ${EGIT3_STORE_DIR:=${distdir}/git3-src} |
299 |
|
300 |
GIT_DIR=${EGIT3_STORE_DIR}/${repo_name} |
301 |
|
302 |
if [[ ! -d ${EGIT3_STORE_DIR} ]]; then |
303 |
( |
304 |
addwrite / |
305 |
mkdir -m0755 -p "${EGIT3_STORE_DIR}" || die |
306 |
) || die "Unable to create ${EGIT3_STORE_DIR}" |
307 |
fi |
308 |
|
309 |
addwrite "${EGIT3_STORE_DIR}" |
310 |
if [[ ! -d ${GIT_DIR} ]]; then |
311 |
mkdir "${GIT_DIR}" || die |
312 |
git init --bare || die |
313 |
fi |
314 |
} |
315 |
|
316 |
# @FUNCTION: _git-r3_set_submodules |
317 |
# @USAGE: <file-contents> |
318 |
# @INTERNAL |
319 |
# @DESCRIPTION: |
320 |
# Parse .gitmodules contents passed as <file-contents> |
321 |
# as in "$(cat .gitmodules)"). Composes a 'submodules' array that |
322 |
# contains in order (name, URL, path) for each submodule. |
323 |
_git-r3_set_submodules() { |
324 |
debug-print-function ${FUNCNAME} "$@" |
325 |
|
326 |
local data=${1} |
327 |
|
328 |
# ( name url path ... ) |
329 |
submodules=() |
330 |
|
331 |
local l |
332 |
while read l; do |
333 |
# submodule.<path>.path=<path> |
334 |
# submodule.<path>.url=<url> |
335 |
[[ ${l} == submodule.*.url=* ]] || continue |
336 |
|
337 |
l=${l#submodule.} |
338 |
local subname=${l%%.url=*} |
339 |
|
340 |
# skip modules that have 'update = none', bug #487262. |
341 |
local upd=$(echo "${data}" | git config -f /dev/fd/0 \ |
342 |
submodule."${subname}".update) |
343 |
[[ ${upd} == none ]] && continue |
344 |
|
345 |
submodules+=( |
346 |
"${subname}" |
347 |
"$(echo "${data}" | git config -f /dev/fd/0 \ |
348 |
submodule."${subname}".url || die)" |
349 |
"$(echo "${data}" | git config -f /dev/fd/0 \ |
350 |
submodule."${subname}".path || die)" |
351 |
) |
352 |
done < <(echo "${data}" | git config -f /dev/fd/0 -l || die) |
353 |
} |
354 |
|
355 |
# @FUNCTION: _git-r3_is_local_repo |
356 |
# @USAGE: <repo-uri> |
357 |
# @INTERNAL |
358 |
# @DESCRIPTION: |
359 |
# Determine whether the given URI specifies a local (on-disk) |
360 |
# repository. |
361 |
_git-r3_is_local_repo() { |
362 |
debug-print-function ${FUNCNAME} "$@" |
363 |
|
364 |
local uri=${1} |
365 |
|
366 |
[[ ${uri} == file://* || ${uri} == /* ]] |
367 |
} |
368 |
|
369 |
# @FUNCTION: _git-r3_find_head |
370 |
# @USAGE: <head-ref> |
371 |
# @INTERNAL |
372 |
# @DESCRIPTION: |
373 |
# Given a ref to which remote HEAD was fetched, try to find |
374 |
# a branch matching the commit. Expects 'git show-ref' |
375 |
# or 'git ls-remote' output on stdin. |
376 |
_git-r3_find_head() { |
377 |
debug-print-function ${FUNCNAME} "$@" |
378 |
|
379 |
local head_ref=${1} |
380 |
local head_hash=$(git rev-parse --verify "${1}" || die) |
381 |
local matching_ref |
382 |
|
383 |
# TODO: some transports support peeking at symbolic remote refs |
384 |
# find a way to use that rather than guessing |
385 |
|
386 |
# (based on guess_remote_head() in git-1.9.0/remote.c) |
387 |
local h ref |
388 |
while read h ref; do |
389 |
# look for matching head |
390 |
if [[ ${h} == ${head_hash} ]]; then |
391 |
# either take the first matching ref, or master if it is there |
392 |
if [[ ! ${matching_ref} || ${ref} == refs/heads/master ]]; then |
393 |
matching_ref=${ref} |
394 |
fi |
395 |
fi |
396 |
done |
397 |
|
398 |
if [[ ! ${matching_ref} ]]; then |
399 |
die "Unable to find a matching branch for remote HEAD (${head_hash})" |
400 |
fi |
401 |
|
402 |
echo "${matching_ref}" |
403 |
} |
404 |
|
405 |
# @FUNCTION: git-r3_fetch |
406 |
# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]] |
407 |
# @DESCRIPTION: |
408 |
# Fetch new commits to the local clone of repository. |
409 |
# |
410 |
# <repo-uri> specifies the repository URIs to fetch from, as a space- |
411 |
# -separated list. The first URI will be used as repository group |
412 |
# identifier and therefore must be used consistently. When not |
413 |
# specified, defaults to ${EGIT_REPO_URI}. |
414 |
# |
415 |
# <remote-ref> specifies the remote ref or commit id to fetch. |
416 |
# It is preferred to use 'refs/heads/<branch-name>' for branches |
417 |
# and 'refs/tags/<tag-name>' for tags. Other options are 'HEAD' |
418 |
# for upstream default branch and hexadecimal commit SHA1. Defaults |
419 |
# to the first of EGIT_COMMIT, EGIT_BRANCH or literal 'HEAD' that |
420 |
# is set to a non-null value. |
421 |
# |
422 |
# <local-id> specifies the local branch identifier that will be used to |
423 |
# locally store the fetch result. It should be unique to multiple |
424 |
# fetches within the repository that can be performed at the same time |
425 |
# (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT%/*}. |
426 |
# This default should be fine unless you are fetching multiple trees |
427 |
# from the same repository in the same ebuild. |
428 |
# |
429 |
# The fetch operation will affect the EGIT_STORE only. It will not touch |
430 |
# the working copy, nor export any environment variables. |
431 |
# If the repository contains submodules, they will be fetched |
432 |
# recursively. |
433 |
git-r3_fetch() { |
434 |
debug-print-function ${FUNCNAME} "$@" |
435 |
|
436 |
[[ ${EVCS_OFFLINE} ]] && return |
437 |
|
438 |
local repos |
439 |
if [[ ${1} ]]; then |
440 |
repos=( ${1} ) |
441 |
elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then |
442 |
repos=( "${EGIT_REPO_URI[@]}" ) |
443 |
else |
444 |
repos=( ${EGIT_REPO_URI} ) |
445 |
fi |
446 |
|
447 |
local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} |
448 |
local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} |
449 |
local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}} |
450 |
local local_ref=refs/git-r3/${local_id}/__main__ |
451 |
|
452 |
[[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" |
453 |
|
454 |
local -x GIT_DIR |
455 |
_git-r3_set_gitdir "${repos[0]}" |
456 |
|
457 |
# prepend the local mirror if applicable |
458 |
if [[ ${EGIT_MIRROR_URI} ]]; then |
459 |
repos=( |
460 |
"${EGIT_MIRROR_URI%/}/${GIT_DIR##*/}" |
461 |
"${repos[@]}" |
462 |
) |
463 |
fi |
464 |
|
465 |
# try to fetch from the remote |
466 |
local r success |
467 |
for r in "${repos[@]}"; do |
468 |
einfo "Fetching ${r} ..." |
469 |
|
470 |
local fetch_command=( git fetch "${r}" ) |
471 |
local clone_type=${EGIT_CLONE_TYPE} |
472 |
|
473 |
if [[ ${r} == https://code.google.com/* ]]; then |
474 |
# Google Code has special magic on top of git that: |
475 |
# 1) can't handle shallow clones at all, |
476 |
# 2) fetches duplicately when tags are pulled in with branch |
477 |
# so automatically switch to single+tags mode. |
478 |
if [[ ${clone_type} == shallow ]]; then |
479 |
einfo " Google Code does not support shallow clones" |
480 |
einfo " using EGIT_CLONE_TYPE=single+tags" |
481 |
clone_type=single+tags |
482 |
elif [[ ${clone_type} == single ]]; then |
483 |
einfo " git-r3: Google Code does not send tags properly in 'single' mode" |
484 |
einfo " using EGIT_CLONE_TYPE=single+tags" |
485 |
clone_type=single+tags |
486 |
fi |
487 |
fi |
488 |
|
489 |
if [[ ${clone_type} == mirror ]]; then |
490 |
fetch_command+=( |
491 |
--prune |
492 |
# mirror the remote branches as local branches |
493 |
"+refs/heads/*:refs/heads/*" |
494 |
# pull tags explicitly in order to prune them properly |
495 |
"+refs/tags/*:refs/tags/*" |
496 |
# notes in case something needs them |
497 |
"+refs/notes/*:refs/notes/*" |
498 |
# and HEAD in case we need the default branch |
499 |
# (we keep it in refs/git-r3 since otherwise --prune interferes) |
500 |
"+HEAD:refs/git-r3/HEAD" |
501 |
) |
502 |
else # single or shallow |
503 |
local fetch_l fetch_r |
504 |
|
505 |
if [[ ${remote_ref} == HEAD ]]; then |
506 |
# HEAD |
507 |
fetch_l=HEAD |
508 |
elif [[ ${remote_ref} == refs/heads/* ]]; then |
509 |
# regular branch |
510 |
fetch_l=${remote_ref} |
511 |
else |
512 |
# tag or commit... |
513 |
# let ls-remote figure it out |
514 |
local tagref=$(git ls-remote "${r}" "refs/tags/${remote_ref}") |
515 |
|
516 |
# if it was a tag, ls-remote obtained a hash |
517 |
if [[ ${tagref} ]]; then |
518 |
# tag |
519 |
fetch_l=refs/tags/${remote_ref} |
520 |
else |
521 |
# commit |
522 |
# so we need to fetch the branch |
523 |
if [[ ${branch} ]]; then |
524 |
fetch_l=${branch} |
525 |
else |
526 |
fetch_l=HEAD |
527 |
fi |
528 |
|
529 |
# fetching by commit in shallow mode? can't do. |
530 |
if [[ ${clone_type} == shallow ]]; then |
531 |
clone_type=single |
532 |
fi |
533 |
fi |
534 |
fi |
535 |
|
536 |
if [[ ${fetch_l} == HEAD ]]; then |
537 |
fetch_r=refs/git-r3/HEAD |
538 |
else |
539 |
fetch_r=${fetch_l} |
540 |
fi |
541 |
|
542 |
fetch_command+=( |
543 |
"+${fetch_l}:${fetch_r}" |
544 |
) |
545 |
|
546 |
if [[ ${clone_type} == single+tags ]]; then |
547 |
fetch_command+=( |
548 |
# pull tags explicitly as requested |
549 |
"+refs/tags/*:refs/tags/*" |
550 |
) |
551 |
fi |
552 |
fi |
553 |
|
554 |
if [[ ${clone_type} == shallow ]]; then |
555 |
if _git-r3_is_local_repo; then |
556 |
# '--depth 1' causes sandbox violations with local repos |
557 |
# bug #491260 |
558 |
clone_type=single |
559 |
elif [[ ! $(git rev-parse --quiet --verify "${fetch_r}") ]] |
560 |
then |
561 |
# use '--depth 1' when fetching a new branch |
562 |
fetch_command+=( --depth 1 ) |
563 |
fi |
564 |
else # non-shallow mode |
565 |
if [[ -f ${GIT_DIR}/shallow ]]; then |
566 |
fetch_command+=( --unshallow ) |
567 |
fi |
568 |
fi |
569 |
|
570 |
set -- "${fetch_command[@]}" |
571 |
echo "${@}" >&2 |
572 |
if "${@}"; then |
573 |
if [[ ${clone_type} == mirror ]]; then |
574 |
# find remote HEAD and update our HEAD properly |
575 |
git symbolic-ref HEAD \ |
576 |
"$(_git-r3_find_head refs/git-r3/HEAD \ |
577 |
< <(git show-ref --heads || die))" \ |
578 |
|| die "Unable to update HEAD" |
579 |
else # single or shallow |
580 |
if [[ ${fetch_l} == HEAD ]]; then |
581 |
# find out what branch we fetched as HEAD |
582 |
local head_branch=$(_git-r3_find_head \ |
583 |
refs/git-r3/HEAD \ |
584 |
< <(git ls-remote --heads "${r}" || die)) |
585 |
|
586 |
# and move it to its regular place |
587 |
git update-ref --no-deref "${head_branch}" \ |
588 |
refs/git-r3/HEAD \ |
589 |
|| die "Unable to sync HEAD branch ${head_branch}" |
590 |
git symbolic-ref HEAD "${head_branch}" \ |
591 |
|| die "Unable to update HEAD" |
592 |
fi |
593 |
fi |
594 |
|
595 |
# now let's see what the user wants from us |
596 |
local full_remote_ref=$( |
597 |
git rev-parse --verify --symbolic-full-name "${remote_ref}" |
598 |
) |
599 |
|
600 |
if [[ ${full_remote_ref} ]]; then |
601 |
# when we are given a ref, create a symbolic ref |
602 |
# so that we preserve the actual argument |
603 |
set -- git symbolic-ref "${local_ref}" "${full_remote_ref}" |
604 |
else |
605 |
# otherwise, we were likely given a commit id |
606 |
set -- git update-ref --no-deref "${local_ref}" "${remote_ref}" |
607 |
fi |
608 |
|
609 |
echo "${@}" >&2 |
610 |
if ! "${@}"; then |
611 |
die "Referencing ${remote_ref} failed (wrong ref?)." |
612 |
fi |
613 |
|
614 |
success=1 |
615 |
break |
616 |
fi |
617 |
done |
618 |
[[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI" |
619 |
|
620 |
# submodules can reference commits in any branch |
621 |
# always use the 'clone' mode to accomodate that, bug #503332 |
622 |
local EGIT_CLONE_TYPE=mirror |
623 |
|
624 |
# recursively fetch submodules |
625 |
if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then |
626 |
local submodules |
627 |
_git-r3_set_submodules \ |
628 |
"$(git cat-file -p "${local_ref}":.gitmodules || die)" |
629 |
|
630 |
while [[ ${submodules[@]} ]]; do |
631 |
local subname=${submodules[0]} |
632 |
local url=${submodules[1]} |
633 |
local path=${submodules[2]} |
634 |
local commit=$(git rev-parse "${local_ref}:${path}") |
635 |
|
636 |
if [[ ! ${commit} ]]; then |
637 |
die "Unable to get commit id for submodule ${subname}" |
638 |
fi |
639 |
if [[ ${url} == ./* || ${url} == ../* ]]; then |
640 |
local subrepos=( "${repos[@]/%//${url}}" ) |
641 |
else |
642 |
local subrepos=( "${url}" ) |
643 |
fi |
644 |
|
645 |
git-r3_fetch "${subrepos[*]}" "${commit}" "${local_id}/${subname}" |
646 |
|
647 |
submodules=( "${submodules[@]:3}" ) # shift |
648 |
done |
649 |
fi |
650 |
} |
651 |
|
652 |
# @FUNCTION: git-r3_checkout |
653 |
# @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]] |
654 |
# @DESCRIPTION: |
655 |
# Check the previously fetched tree to the working copy. |
656 |
# |
657 |
# <repo-uri> specifies the repository URIs, as a space-separated list. |
658 |
# The first URI will be used as repository group identifier |
659 |
# and therefore must be used consistently with git-r3_fetch. |
660 |
# The remaining URIs are not used and therefore may be omitted. |
661 |
# When not specified, defaults to ${EGIT_REPO_URI}. |
662 |
# |
663 |
# <checkout-path> specifies the path to place the checkout. It defaults |
664 |
# to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}. |
665 |
# |
666 |
# <local-id> needs to specify the local identifier that was used |
667 |
# for respective git-r3_fetch. |
668 |
# |
669 |
# The checkout operation will write to the working copy, and export |
670 |
# the repository state into the environment. If the repository contains |
671 |
# submodules, they will be checked out recursively. |
672 |
git-r3_checkout() { |
673 |
debug-print-function ${FUNCNAME} "$@" |
674 |
|
675 |
local repos |
676 |
if [[ ${1} ]]; then |
677 |
repos=( ${1} ) |
678 |
elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then |
679 |
repos=( "${EGIT_REPO_URI[@]}" ) |
680 |
else |
681 |
repos=( ${EGIT_REPO_URI} ) |
682 |
fi |
683 |
|
684 |
local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}} |
685 |
local local_id=${3:-${CATEGORY}/${PN}/${SLOT%/*}} |
686 |
|
687 |
local -x GIT_DIR |
688 |
_git-r3_set_gitdir "${repos[0]}" |
689 |
|
690 |
einfo "Checking out ${repos[0]} to ${out_dir} ..." |
691 |
|
692 |
if ! git cat-file -e refs/git-r3/"${local_id}"/__main__; then |
693 |
if [[ ${EVCS_OFFLINE} ]]; then |
694 |
die "No local clone of ${repos[0]}. Unable to work with EVCS_OFFLINE." |
695 |
else |
696 |
die "Logic error: no local clone of ${repos[0]}. git-r3_fetch not used?" |
697 |
fi |
698 |
fi |
699 |
local remote_ref=$( |
700 |
git symbolic-ref --quiet refs/git-r3/"${local_id}"/__main__ |
701 |
) |
702 |
local new_commit_id=$( |
703 |
git rev-parse --verify refs/git-r3/"${local_id}"/__main__ |
704 |
) |
705 |
|
706 |
git-r3_sub_checkout() { |
707 |
local orig_repo=${GIT_DIR} |
708 |
local -x GIT_DIR=${out_dir}/.git |
709 |
local -x GIT_WORK_TREE=${out_dir} |
710 |
|
711 |
mkdir -p "${out_dir}" || die |
712 |
|
713 |
# use git init+fetch instead of clone since the latter doesn't like |
714 |
# non-empty directories. |
715 |
|
716 |
git init --quiet || die |
717 |
# setup 'alternates' to avoid copying objects |
718 |
echo "${orig_repo}/objects" > "${GIT_DIR}"/objects/info/alternates || die |
719 |
# now copy the refs |
720 |
# [htn]* safely catches heads, tags, notes without complaining |
721 |
# on non-existing ones, and omits internal 'git-r3' ref |
722 |
cp -R "${orig_repo}"/refs/[htn]* "${GIT_DIR}"/refs/ || die |
723 |
|
724 |
# (no need to copy HEAD, we will set it via checkout) |
725 |
|
726 |
if [[ -f ${orig_repo}/shallow ]]; then |
727 |
cp "${orig_repo}"/shallow "${GIT_DIR}"/ || die |
728 |
fi |
729 |
|
730 |
set -- git checkout --quiet |
731 |
if [[ ${remote_ref} ]]; then |
732 |
set -- "${@}" "${remote_ref#refs/heads/}" |
733 |
else |
734 |
set -- "${@}" "${new_commit_id}" |
735 |
fi |
736 |
echo "${@}" >&2 |
737 |
"${@}" || die "git checkout ${remote_ref:-${new_commit_id}} failed" |
738 |
} |
739 |
git-r3_sub_checkout |
740 |
|
741 |
local old_commit_id=$( |
742 |
git rev-parse --quiet --verify refs/git-r3/"${local_id}"/__old__ |
743 |
) |
744 |
if [[ ! ${old_commit_id} ]]; then |
745 |
echo "GIT NEW branch -->" |
746 |
echo " repository: ${repos[0]}" |
747 |
echo " at the commit: ${new_commit_id}" |
748 |
else |
749 |
# diff against previous revision |
750 |
echo "GIT update -->" |
751 |
echo " repository: ${repos[0]}" |
752 |
# write out message based on the revisions |
753 |
if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then |
754 |
echo " updating from commit: ${old_commit_id}" |
755 |
echo " to commit: ${new_commit_id}" |
756 |
|
757 |
git --no-pager diff --stat \ |
758 |
${old_commit_id}..${new_commit_id} |
759 |
else |
760 |
echo " at the commit: ${new_commit_id}" |
761 |
fi |
762 |
fi |
763 |
git update-ref --no-deref refs/git-r3/"${local_id}"/{__old__,__main__} || die |
764 |
|
765 |
# recursively checkout submodules |
766 |
if [[ -f ${out_dir}/.gitmodules ]]; then |
767 |
local submodules |
768 |
_git-r3_set_submodules \ |
769 |
"$(<"${out_dir}"/.gitmodules)" |
770 |
|
771 |
while [[ ${submodules[@]} ]]; do |
772 |
local subname=${submodules[0]} |
773 |
local url=${submodules[1]} |
774 |
local path=${submodules[2]} |
775 |
|
776 |
if [[ ${url} == ./* || ${url} == ../* ]]; then |
777 |
url=${repos[0]%%/}/${url} |
778 |
fi |
779 |
|
780 |
git-r3_checkout "${url}" "${out_dir}/${path}" \ |
781 |
"${local_id}/${subname}" |
782 |
|
783 |
submodules=( "${submodules[@]:3}" ) # shift |
784 |
done |
785 |
fi |
786 |
|
787 |
# keep this *after* submodules |
788 |
export EGIT_DIR=${GIT_DIR} |
789 |
export EGIT_VERSION=${new_commit_id} |
790 |
} |
791 |
|
792 |
# @FUNCTION: git-r3_peek_remote_ref |
793 |
# @USAGE: [<repo-uri> [<remote-ref>]] |
794 |
# @DESCRIPTION: |
795 |
# Peek the reference in the remote repository and print the matching |
796 |
# (newest) commit SHA1. |
797 |
# |
798 |
# <repo-uri> specifies the repository URIs to fetch from, as a space- |
799 |
# -separated list. When not specified, defaults to ${EGIT_REPO_URI}. |
800 |
# |
801 |
# <remote-ref> specifies the remote ref to peek. It is preferred to use |
802 |
# 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>' |
803 |
# for tags. Alternatively, 'HEAD' may be used for upstream default |
804 |
# branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal |
805 |
# 'HEAD' that is set to a non-null value. |
806 |
# |
807 |
# The operation will be done purely on the remote, without using local |
808 |
# storage. If commit SHA1 is provided as <remote-ref>, the function will |
809 |
# fail due to limitations of git protocol. |
810 |
# |
811 |
# On success, the function returns 0 and writes hexadecimal commit SHA1 |
812 |
# to stdout. On failure, the function returns 1. |
813 |
git-r3_peek_remote_ref() { |
814 |
debug-print-function ${FUNCNAME} "$@" |
815 |
|
816 |
local repos |
817 |
if [[ ${1} ]]; then |
818 |
repos=( ${1} ) |
819 |
elif [[ $(declare -p EGIT_REPO_URI) == "declare -a"* ]]; then |
820 |
repos=( "${EGIT_REPO_URI[@]}" ) |
821 |
else |
822 |
repos=( ${EGIT_REPO_URI} ) |
823 |
fi |
824 |
|
825 |
local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}} |
826 |
local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}} |
827 |
|
828 |
[[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset" |
829 |
|
830 |
local r success |
831 |
for r in "${repos[@]}"; do |
832 |
einfo "Peeking ${remote_ref} on ${r} ..." >&2 |
833 |
|
834 |
local is_branch lookup_ref |
835 |
if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]] |
836 |
then |
837 |
is_branch=1 |
838 |
lookup_ref=${remote_ref} |
839 |
else |
840 |
# ls-remote by commit is going to fail anyway, |
841 |
# so we may as well pass refs/tags/ABCDEF... |
842 |
lookup_ref=refs/tags/${remote_ref} |
843 |
fi |
844 |
|
845 |
# split on whitespace |
846 |
local ref=( |
847 |
$(git ls-remote "${r}" "${lookup_ref}") |
848 |
) |
849 |
|
850 |
if [[ ${ref[0]} ]]; then |
851 |
echo "${ref[0]}" |
852 |
return 0 |
853 |
fi |
854 |
done |
855 |
|
856 |
return 1 |
857 |
} |
858 |
|
859 |
git-r3_src_fetch() { |
860 |
debug-print-function ${FUNCNAME} "$@" |
861 |
|
862 |
if [[ ! ${EGIT3_STORE_DIR} && ${EGIT_STORE_DIR} ]]; then |
863 |
ewarn "You have set EGIT_STORE_DIR but not EGIT3_STORE_DIR. Please consider" |
864 |
ewarn "setting EGIT3_STORE_DIR for git-r3.eclass. It is recommended to use" |
865 |
ewarn "a different directory than EGIT_STORE_DIR to ease removing old clones" |
866 |
ewarn "when git-2 eclass becomes deprecated." |
867 |
fi |
868 |
|
869 |
_git-r3_env_setup |
870 |
git-r3_fetch |
871 |
} |
872 |
|
873 |
git-r3_src_unpack() { |
874 |
debug-print-function ${FUNCNAME} "$@" |
875 |
|
876 |
_git-r3_env_setup |
877 |
git-r3_src_fetch |
878 |
git-r3_checkout |
879 |
} |
880 |
|
881 |
# https://bugs.gentoo.org/show_bug.cgi?id=482666 |
882 |
git-r3_pkg_outofdate() { |
883 |
debug-print-function ${FUNCNAME} "$@" |
884 |
|
885 |
local new_commit_id=$(git-r3_peek_remote_ref) |
886 |
ewarn "old: ${EGIT_VERSION}" |
887 |
ewarn "new: ${new_commit_id}" |
888 |
[[ ${new_commit_id} && ${old_commit_id} ]] || return 2 |
889 |
|
890 |
[[ ${EGIT_VERSION} != ${new_commit_id} ]] |
891 |
} |
892 |
|
893 |
_GIT_R3=1 |
894 |
fi |