1 |
# Copyright 1999-2009 Gentoo Foundation |
2 |
# Distributed under the terms of the GNU General Public License v2 |
3 |
# $Header: /var/cvsroot/gentoo-x86/eclass/git.eclass,v 1.46 2010/07/26 02:51:33 reavertm Exp $ |
4 |
|
5 |
# @ECLASS: git.eclass |
6 |
# @MAINTAINER: |
7 |
# Tomas Chvatal <scarabeus@gentoo.org> |
8 |
# Donnie Berkholz <dberkholz@gentoo.org> |
9 |
# @BLURB: This eclass provides functions for fetch and unpack git repositories |
10 |
# @DESCRIPTION: |
11 |
# The eclass is based on subversion eclass. |
12 |
# If you use this eclass, the ${S} is ${WORKDIR}/${P}. |
13 |
# It is necessary to define the EGIT_REPO_URI variable at least. |
14 |
# @THANKS TO: |
15 |
# Fernando J. Pereda <ferdy@gentoo.org> |
16 |
|
17 |
inherit eutils |
18 |
|
19 |
EGIT="git.eclass" |
20 |
|
21 |
# We DEPEND on at least a bit recent git version |
22 |
DEPEND=">=dev-vcs/git-1.6" |
23 |
|
24 |
EXPORTED_FUNCTIONS="src_unpack" |
25 |
case "${EAPI:-0}" in |
26 |
3|2) EXPORTED_FUNCTIONS="${EXPORTED_FUNCTIONS} src_prepare" ;; |
27 |
1|0) ;; |
28 |
:) DEPEND="EAPI-UNSUPPORTED" ;; |
29 |
esac |
30 |
EXPORT_FUNCTIONS ${EXPORTED_FUNCTIONS} |
31 |
|
32 |
# define some nice defaults but only if nothing is set already |
33 |
: ${HOMEPAGE:=http://git-scm.com/} |
34 |
|
35 |
# @ECLASS-VARIABLE: EGIT_QUIET |
36 |
# @DESCRIPTION: |
37 |
# Set to non-empty value to supress some eclass messages. |
38 |
: ${EGIT_QUIET:=${ESCM_QUIET}} |
39 |
|
40 |
# @ECLASS-VARIABLE: EGIT_STORE_DIR |
41 |
# @DESCRIPTION: |
42 |
# Storage directory for git sources. |
43 |
# Can be redefined. |
44 |
: ${EGIT_STORE_DIR:="${PORTAGE_ACTUAL_DISTDIR-${DISTDIR}}/git-src"} |
45 |
|
46 |
# @ECLASS-VARIABLE: EGIT_HAS_SUBMODULES |
47 |
# @DESCRIPTION: |
48 |
# Set this to non-empty value to enable submodule support (slower). |
49 |
: ${EGIT_HAS_SUBMODULES:=} |
50 |
|
51 |
# @ECLASS-VARIABLE: EGIT_FETCH_CMD |
52 |
# @DESCRIPTION: |
53 |
# Command for cloning the repository. |
54 |
: ${EGIT_FETCH_CMD:="git clone"} |
55 |
|
56 |
# @ECLASS-VARIABLE: EGIT_UPDATE_CMD |
57 |
# @DESCRIPTION: |
58 |
# Git fetch command. |
59 |
if [[ -n ${EGIT_HAS_SUBMODULES} ]]; then |
60 |
EGIT_UPDATE_CMD="git pull -f -u" |
61 |
else |
62 |
EGIT_UPDATE_CMD="git fetch -f -u" |
63 |
fi |
64 |
|
65 |
# @ECLASS-VARIABLE: EGIT_DIFFSTAT_CMD |
66 |
# @DESCRIPTION: |
67 |
# Git command for diffstat. |
68 |
EGIT_DIFFSTAT_CMD="git --no-pager diff --stat" |
69 |
|
70 |
# @ECLASS-VARIABLE: EGIT_OPTIONS |
71 |
# @DESCRIPTION: |
72 |
# This variable value is passed to clone and fetch. |
73 |
: ${EGIT_OPTIONS:=} |
74 |
|
75 |
# @ECLASS-VARIABLE: EGIT_MASTER |
76 |
# @DESCRIPTION: |
77 |
# Variable for specifying master branch. |
78 |
# Usefull when upstream don't have master branch. |
79 |
: ${EGIT_MASTER:=master} |
80 |
|
81 |
# @ECLASS-VARIABLE: EGIT_REPO_URI |
82 |
# @DESCRIPTION: |
83 |
# URI for the repository |
84 |
# e.g. http://foo, git://bar |
85 |
# Supported protocols: |
86 |
# http:// |
87 |
# https:// |
88 |
# git:// |
89 |
# git+ssh:// |
90 |
# rsync:// |
91 |
# ssh:// |
92 |
eval X="\$${PN//[-+]/_}_LIVE_REPO" |
93 |
if [[ ${X} = "" ]]; then |
94 |
: ${EGIT_REPO_URI:=} |
95 |
else |
96 |
EGIT_REPO_URI="${X}" |
97 |
fi |
98 |
# @ECLASS-VARIABLE: EGIT_PROJECT |
99 |
# @DESCRIPTION: |
100 |
# Project name of your ebuild. |
101 |
# Git eclass will check out the git repository like: |
102 |
# ${EGIT_STORE_DIR}/${EGIT_PROJECT}/${EGIT_REPO_URI##*/} |
103 |
# so if you define EGIT_REPO_URI as http://git.collab.net/repo/git or |
104 |
# http://git.collab.net/repo/git. and PN is subversion-git. |
105 |
# it will check out like: |
106 |
# ${EGIT_STORE_DIR}/subversion |
107 |
: ${EGIT_PROJECT:=${PN/-git}} |
108 |
|
109 |
# @ECLASS-VARIABLE: EGIT_BOOTSTRAP |
110 |
# @DESCRIPTION: |
111 |
# bootstrap script or command like autogen.sh or etc... |
112 |
: ${EGIT_BOOTSTRAP:=} |
113 |
|
114 |
# @ECLASS-VARIABLE: EGIT_OFFLINE |
115 |
# @DESCRIPTION: |
116 |
# Set this variable to a non-empty value to disable the automatic updating of |
117 |
# an GIT source tree. This is intended to be set outside the git source |
118 |
# tree by users. |
119 |
: ${EGIT_OFFLINE:=${ESCM_OFFLINE}} |
120 |
|
121 |
# @ECLASS-VARIABLE: EGIT_PATCHES |
122 |
# @DESCRIPTION: |
123 |
# Similar to PATCHES array from base.eclass |
124 |
# Only difference is that this patches are applied before bootstrap. |
125 |
# Please take note that this variable should be bash array. |
126 |
|
127 |
# @ECLASS-VARIABLE: EGIT_BRANCH |
128 |
# @DESCRIPTION: |
129 |
# git eclass can fetch any branch in git_fetch(). |
130 |
eval X="\$${PN//[-+]/_}_LIVE_BRANCH" |
131 |
if [[ "${X}" = "" ]]; then |
132 |
: ${EGIT_BRANCH:=master} |
133 |
else |
134 |
EGIT_BRANCH="${X}" |
135 |
fi |
136 |
|
137 |
# @ECLASS-VARIABLE: EGIT_COMMIT |
138 |
# @DESCRIPTION: |
139 |
# git eclass can checkout any commit. |
140 |
eval X="\$${PN//[-+]/_}_LIVE_COMMIT" |
141 |
if [[ "${X}" = "" ]]; then |
142 |
: ${EGIT_COMMIT:=${EGIT_BRANCH}} |
143 |
else |
144 |
EGIT_COMMIT="${X}" |
145 |
fi |
146 |
|
147 |
# @ECLASS-VARIABLE: EGIT_REPACK |
148 |
# @DESCRIPTION: |
149 |
# Set to non-empty value to repack objects to save disk space. However this can |
150 |
# take a long time with VERY big repositories. |
151 |
: ${EGIT_REPACK:=} |
152 |
|
153 |
# @ECLASS-VARIABLE: EGIT_PRUNE |
154 |
# @DESCRIPTION: |
155 |
# Set to non-empty value to prune loose objects on each fetch. This is useful |
156 |
# if upstream rewinds and rebases branches often. |
157 |
: ${EGIT_PRUNE:=} |
158 |
|
159 |
# @FUNCTION: git_submodules |
160 |
# @DESCRIPTION: |
161 |
# Internal function wrapping the submodule initialisation and update |
162 |
git_submodules() { |
163 |
if [[ -n ${EGIT_HAS_SUBMODULES} ]]; then |
164 |
debug-print "git submodule init" |
165 |
git submodule init |
166 |
debug-print "git submodule update" |
167 |
git submodule update |
168 |
fi |
169 |
} |
170 |
|
171 |
# @FUNCTION: git_branch |
172 |
# @DESCRIPTION: |
173 |
# Internal function that changes branch for the repo based on EGIT_TREE and |
174 |
# EGIT_BRANCH variables. |
175 |
git_branch() { |
176 |
local branchname=branch-${EGIT_BRANCH} src=origin/${EGIT_BRANCH} |
177 |
if [[ "${EGIT_COMMIT}" != "${EGIT_BRANCH}" ]]; then |
178 |
branchname=tree-${EGIT_COMMIT} |
179 |
src=${EGIT_COMMIT} |
180 |
fi |
181 |
debug-print "git checkout -b ${branchname} ${src}" |
182 |
git checkout -b ${branchname} ${src} &> /dev/null |
183 |
|
184 |
unset branchname src |
185 |
} |
186 |
|
187 |
# @FUNCTION: git_fetch |
188 |
# @DESCRIPTION: |
189 |
# Gets repository from EGIT_REPO_URI and store it in specified EGIT_STORE_DIR |
190 |
git_fetch() { |
191 |
debug-print-function ${FUNCNAME} "$@" |
192 |
|
193 |
local GIT_DIR EGIT_CLONE_DIR oldsha1 cursha1 extra_clone_opts upstream_branch |
194 |
[[ -z ${EGIT_HAS_SUBMODULES} ]] && export GIT_DIR |
195 |
|
196 |
# choose if user wants elog or just einfo. |
197 |
if [[ -n ${EGIT_QUIET} ]]; then |
198 |
elogcmd="einfo" |
199 |
else |
200 |
elogcmd="elog" |
201 |
fi |
202 |
|
203 |
# If we have same branch and the tree we can do --depth 1 clone |
204 |
# which outputs into really smaller data transfers. |
205 |
# Sadly we can do shallow copy for now because quite a few packages need .git |
206 |
# folder. |
207 |
#[[ ${EGIT_COMMIT} = ${EGIT_BRANCH} ]] && \ |
208 |
# EGIT_FETCH_CMD="${EGIT_FETCH_CMD} --depth 1" |
209 |
if [[ -n ${EGIT_TREE} ]] ; then |
210 |
EGIT_COMMIT=${EGIT_TREE} |
211 |
ewarn "QA: Usage of deprecated EGIT_TREE variable detected." |
212 |
ewarn "QA: Use EGIT_COMMIT variable instead." |
213 |
fi |
214 |
|
215 |
# EGIT_REPO_URI is empty. |
216 |
[[ -z ${EGIT_REPO_URI} ]] && die "${EGIT}: EGIT_REPO_URI is empty." |
217 |
|
218 |
# check for the protocol or pull from a local repo. |
219 |
if [[ -z ${EGIT_REPO_URI%%:*} ]] ; then |
220 |
case ${EGIT_REPO_URI%%:*} in |
221 |
git*|http|https|rsync|ssh) ;; |
222 |
*) die "${EGIT}: protocol for fetch from "${EGIT_REPO_URI%:*}" is not yet implemented in eclass." ;; |
223 |
esac |
224 |
fi |
225 |
|
226 |
# initial clone, we have to create master git storage directory and play |
227 |
# nicely with sandbox |
228 |
if [[ ! -d ${EGIT_STORE_DIR} ]] ; then |
229 |
debug-print "${FUNCNAME}: initial clone. creating git directory" |
230 |
addwrite / |
231 |
mkdir -p "${EGIT_STORE_DIR}" \ |
232 |
|| die "${EGIT}: can't mkdir ${EGIT_STORE_DIR}." |
233 |
export SANDBOX_WRITE="${SANDBOX_WRITE%%:/}" |
234 |
fi |
235 |
|
236 |
cd -P "${EGIT_STORE_DIR}" || die "${EGIT}: can't chdir to ${EGIT_STORE_DIR}" |
237 |
EGIT_STORE_DIR=${PWD} |
238 |
|
239 |
# allow writing into EGIT_STORE_DIR |
240 |
addwrite "${EGIT_STORE_DIR}" |
241 |
|
242 |
[[ -z ${EGIT_REPO_URI##*/} ]] && EGIT_REPO_URI="${EGIT_REPO_URI%/}" |
243 |
EGIT_CLONE_DIR="${EGIT_PROJECT}" |
244 |
|
245 |
debug-print "${FUNCNAME}: EGIT_OPTIONS = \"${EGIT_OPTIONS}\"" |
246 |
|
247 |
GIT_DIR="${EGIT_STORE_DIR}/${EGIT_CLONE_DIR}" |
248 |
# we also have to remove all shallow copied repositories |
249 |
# and fetch them again |
250 |
if [[ -e "${GIT_DIR}/shallow" ]]; then |
251 |
rm -rf "${GIT_DIR}" |
252 |
einfo "The ${EGIT_CLONE_DIR} was shallow copy. Refetching." |
253 |
fi |
254 |
# repack from bare copy to normal one |
255 |
if [[ -n ${EGIT_HAS_SUBMODULES} ]] && [[ -d ${GIT_DIR} && ! -d ${GIT_DIR}/.git ]]; then |
256 |
rm -rf "${GIT_DIR}" |
257 |
einfo "The ${EGIT_CLONE_DIR} was bare copy. Refetching." |
258 |
fi |
259 |
if [[ -z ${EGIT_HAS_SUBMODULES} ]] && [[ -d ${GIT_DIR} && -d ${GIT_DIR}/.git ]]; then |
260 |
rm -rf "${GIT_DIR}" |
261 |
einfo "The ${EGIT_CLONE_DIR} was not a bare copy. Refetching." |
262 |
fi |
263 |
|
264 |
if [[ -n ${EGIT_HAS_SUBMODULES} ]]; then |
265 |
upstream_branch=origin/${EGIT_BRANCH} |
266 |
else |
267 |
upstream_branch=${EGIT_BRANCH} |
268 |
extra_clone_opts=--bare |
269 |
fi |
270 |
|
271 |
if [[ ! -d ${GIT_DIR} ]] ; then |
272 |
# first clone |
273 |
${elogcmd} "GIT NEW clone -->" |
274 |
${elogcmd} " repository: ${EGIT_REPO_URI}" |
275 |
|
276 |
debug-print "${EGIT_FETCH_CMD} ${extra_clone_opts} ${EGIT_OPTIONS} \"${EGIT_REPO_URI}\" ${GIT_DIR}" |
277 |
${EGIT_FETCH_CMD} ${extra_clone_opts} ${EGIT_OPTIONS} "${EGIT_REPO_URI}" ${GIT_DIR} \ |
278 |
|| die "${EGIT}: can't fetch from ${EGIT_REPO_URI}." |
279 |
|
280 |
pushd "${GIT_DIR}" &> /dev/null |
281 |
cursha1=$(git rev-parse ${upstream_branch}) |
282 |
${elogcmd} " at the commit: ${cursha1}" |
283 |
|
284 |
git_submodules |
285 |
popd &> /dev/null |
286 |
elif [[ -n ${EGIT_OFFLINE} ]] ; then |
287 |
pushd "${GIT_DIR}" &> /dev/null |
288 |
cursha1=$(git rev-parse ${upstream_branch}) |
289 |
${elogcmd} "GIT offline update -->" |
290 |
${elogcmd} " repository: ${EGIT_REPO_URI}" |
291 |
${elogcmd} " at the commit: ${cursha1}" |
292 |
popd &> /dev/null |
293 |
else |
294 |
pushd "${GIT_DIR}" &> /dev/null |
295 |
# Git urls might change, so unconditionally set it here |
296 |
git config remote.origin.url "${EGIT_REPO_URI}" |
297 |
|
298 |
# fetch updates |
299 |
${elogcmd} "GIT update -->" |
300 |
${elogcmd} " repository: ${EGIT_REPO_URI}" |
301 |
|
302 |
oldsha1=$(git rev-parse ${upstream_branch}) |
303 |
|
304 |
if [[ -n ${EGIT_HAS_SUBMODULES} ]]; then |
305 |
debug-print "${EGIT_UPDATE_CMD} ${EGIT_OPTIONS}" |
306 |
# fix branching |
307 |
git checkout ${EGIT_MASTER} |
308 |
for x in $(git branch |grep -v "* ${EGIT_MASTER}" |tr '\n' ' '); do |
309 |
git branch -D ${x} |
310 |
done |
311 |
${EGIT_UPDATE_CMD} ${EGIT_OPTIONS} \ |
312 |
|| die "${EGIT}: can't update from ${EGIT_REPO_URI}." |
313 |
else |
314 |
debug-print "${EGIT_UPDATE_CMD} ${EGIT_OPTIONS} origin ${EGIT_BRANCH}:${EGIT_BRANCH}" |
315 |
${EGIT_UPDATE_CMD} ${EGIT_OPTIONS} origin ${EGIT_BRANCH}:${EGIT_BRANCH} \ |
316 |
|| die "${EGIT}: can't update from ${EGIT_REPO_URI}." |
317 |
fi |
318 |
|
319 |
git_submodules |
320 |
cursha1=$(git rev-parse ${upstream_branch}) |
321 |
|
322 |
# write out message based on the revisions |
323 |
if [[ "${oldsha1}" != "${cursha1}" ]]; then |
324 |
${elogcmd} " updating from commit: ${oldsha1}" |
325 |
${elogcmd} " to commit: ${cursha1}" |
326 |
else |
327 |
${elogcmd} " at the commit: ${cursha1}" |
328 |
# @ECLASS_VARIABLE: LIVE_FAIL_FETCH_IF_REPO_NOT_UPDATED |
329 |
# @DESCRIPTION: |
330 |
# If this variable is set to TRUE in make.conf or somewhere in |
331 |
# enviroment the package will fail if there is no update, thus in |
332 |
# combination with --keep-going it would lead in not-updating |
333 |
# pakcages that are up-to-date. |
334 |
# TODO: this can lead to issues if more projects/packages use same repo |
335 |
[[ ${LIVE_FAIL_FETCH_IF_REPO_NOT_UPDATED} = true ]] && \ |
336 |
debug-print "${FUNCNAME}: Repository \"${EGIT_REPO_URI}\" is up-to-date. Skipping." && \ |
337 |
die "${EGIT}: Repository \"${EGIT_REPO_URI}\" is up-to-date. Skipping." |
338 |
fi |
339 |
${EGIT_DIFFSTAT_CMD} ${oldsha1}..${upstream_branch} |
340 |
popd &> /dev/null |
341 |
fi |
342 |
|
343 |
pushd "${GIT_DIR}" &> /dev/null |
344 |
if [[ -n ${EGIT_REPACK} ]] || [[ -n ${EGIT_PRUNE} ]]; then |
345 |
ebegin "Garbage collecting the repository" |
346 |
local args |
347 |
[[ -n ${EGIT_PRUNE} ]] && args='--prune' |
348 |
git gc ${args} |
349 |
eend $? |
350 |
fi |
351 |
popd &> /dev/null |
352 |
|
353 |
# export the git version |
354 |
export EGIT_VERSION="${cursha1}" |
355 |
|
356 |
# log the repo state |
357 |
[[ "${EGIT_COMMIT}" != "${EGIT_BRANCH}" ]] && ${elogcmd} " commit: ${EGIT_COMMIT}" |
358 |
${elogcmd} " branch: ${EGIT_BRANCH}" |
359 |
${elogcmd} " storage directory: \"${GIT_DIR}\"" |
360 |
|
361 |
if [[ -n ${EGIT_HAS_SUBMODULES} ]]; then |
362 |
pushd "${GIT_DIR}" &> /dev/null |
363 |
debug-print "rsync -rlpgo . \"${S}\"" |
364 |
time rsync -rlpgo . "${S}" |
365 |
popd &> /dev/null |
366 |
else |
367 |
unset GIT_DIR |
368 |
debug-print "git clone -l -s -n \"${EGIT_STORE_DIR}/${EGIT_CLONE_DIR}\" \"${S}\"" |
369 |
git clone -l -s -n "${EGIT_STORE_DIR}/${EGIT_CLONE_DIR}" "${S}" |
370 |
fi |
371 |
|
372 |
pushd "${S}" &> /dev/null |
373 |
git_branch |
374 |
# submodules always reqire net (thanks to branches changing) |
375 |
[[ -z ${EGIT_OFFLINE} ]] && git_submodules |
376 |
popd &> /dev/null |
377 |
|
378 |
echo ">>> Unpacked to ${S}" |
379 |
} |
380 |
|
381 |
# @FUNCTION: git_bootstrap |
382 |
# @DESCRIPTION: |
383 |
# Runs bootstrap command if EGIT_BOOTSTRAP variable contains some value |
384 |
# Remember that what ever gets to the EGIT_BOOTSTRAP variable gets evaled by bash. |
385 |
git_bootstrap() { |
386 |
debug-print-function ${FUNCNAME} "$@" |
387 |
|
388 |
if [[ -n ${EGIT_BOOTSTRAP} ]] ; then |
389 |
pushd "${S}" > /dev/null |
390 |
einfo "Starting bootstrap" |
391 |
|
392 |
if [[ -f ${EGIT_BOOTSTRAP} ]]; then |
393 |
# we have file in the repo which we should execute |
394 |
debug-print "$FUNCNAME: bootstraping with file \"${EGIT_BOOTSTRAP}\"" |
395 |
|
396 |
if [[ -x ${EGIT_BOOTSTRAP} ]]; then |
397 |
eval "./${EGIT_BOOTSTRAP}" \ |
398 |
|| die "${EGIT}: bootstrap script failed" |
399 |
else |
400 |
eerror "\"${EGIT_BOOTSTRAP}\" is not executable." |
401 |
eerror "Report upstream, or bug ebuild maintainer to remove bootstrap command." |
402 |
die "${EGIT}: \"${EGIT_BOOTSTRAP}\" is not executable." |
403 |
fi |
404 |
else |
405 |
# we execute some system command |
406 |
debug-print "$FUNCNAME: bootstraping with commands \"${EGIT_BOOTSTRAP}\"" |
407 |
|
408 |
eval "${EGIT_BOOTSTRAP}" \ |
409 |
|| die "${EGIT}: bootstrap commands failed." |
410 |
|
411 |
fi |
412 |
|
413 |
einfo "Bootstrap finished" |
414 |
popd > /dev/null |
415 |
fi |
416 |
} |
417 |
|
418 |
# @FUNCTION: git_apply_patches |
419 |
# @DESCRIPTION: |
420 |
# Apply patches from EGIT_PATCHES bash array. |
421 |
# Preferred is using the variable as bash array but for now it allows to write |
422 |
# it also as normal space separated string list. (This part of code should be |
423 |
# removed when all ebuilds get converted on bash array). |
424 |
git_apply_patches() { |
425 |
debug-print-function ${FUNCNAME} "$@" |
426 |
|
427 |
pushd "${S}" > /dev/null |
428 |
if [[ ${#EGIT_PATCHES[@]} -gt 1 ]] ; then |
429 |
for i in "${EGIT_PATCHES[@]}"; do |
430 |
debug-print "$FUNCNAME: git_autopatch: patching from ${i}" |
431 |
epatch "${i}" |
432 |
done |
433 |
elif [[ -n ${EGIT_PATCHES} ]]; then |
434 |
# no need for loop if space separated string is passed. |
435 |
debug-print "$FUNCNAME: git_autopatch: patching from ${EGIT_PATCHES}" |
436 |
epatch "${EGIT_PATCHES}" |
437 |
fi |
438 |
|
439 |
popd > /dev/null |
440 |
} |
441 |
|
442 |
# @FUNCTION: git_src_unpack |
443 |
# @DESCRIPTION: |
444 |
# src_upack function, calls src_prepare one if EAPI!=2. |
445 |
git_src_unpack() { |
446 |
debug-print-function ${FUNCNAME} "$@" |
447 |
|
448 |
git_fetch || die "${EGIT}: unknown problem in git_fetch()." |
449 |
|
450 |
has src_prepare ${EXPORTED_FUNCTIONS} || git_src_prepare |
451 |
} |
452 |
|
453 |
# @FUNCTION: git_src_prepare |
454 |
# @DESCRIPTION: |
455 |
# src_prepare function for git stuff. Patches, bootstrap... |
456 |
git_src_prepare() { |
457 |
debug-print-function ${FUNCNAME} "$@" |
458 |
|
459 |
git_apply_patches |
460 |
git_bootstrap |
461 |
} |