Created
October 9, 2012 15:54
-
-
Save roowe/3859695 to your computer and use it in GitHub Desktop.
git wrap for portage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Copyright 1999-2012 Gentoo Foundation | |
# Distributed under the terms of the GNU General Public License v2 | |
# $Header: /var/cvsroot/gentoo-x86/eclass/git-2.eclass,v 1.29 2012/04/03 10:32:09 pacho Exp $ | |
# @ECLASS: git-2.eclass | |
# @MAINTAINER: | |
# Michał Górny <mgorny@gentoo.org> | |
# Donnie Berkholz <dberkholz@gentoo.org> | |
# @BLURB: Eclass for fetching and unpacking git repositories. | |
# @DESCRIPTION: | |
# Eclass for easing maitenance of live ebuilds using git as remote repository. | |
# Eclass support working with git submodules and branching. | |
# This eclass support all EAPIs | |
EXPORT_FUNCTIONS src_unpack | |
DEPEND="dev-vcs/git" | |
# @ECLASS-VARIABLE: EGIT_SOURCEDIR | |
# @DESCRIPTION: | |
# This variable specifies destination where the cloned | |
# data are copied to. | |
# | |
# EGIT_SOURCEDIR="${S}" | |
# @ECLASS-VARIABLE: EGIT_STORE_DIR | |
# @DESCRIPTION: | |
# Storage directory for git sources. | |
# | |
# EGIT_STORE_DIR="${DISTDIR}/egit-src" | |
# @ECLASS-VARIABLE: EGIT_HAS_SUBMODULES | |
# @DEFAULT_UNSET | |
# @DESCRIPTION: | |
# If non-empty this variable enables support for git submodules in our | |
# checkout. Also this makes the checkout to be non-bare for now. | |
# @ECLASS-VARIABLE: EGIT_OPTIONS | |
# @DEFAULT_UNSET | |
# @DESCRIPTION: | |
# Variable specifying additional options for fetch command. | |
# @ECLASS-VARIABLE: EGIT_MASTER | |
# @DESCRIPTION: | |
# Variable for specifying master branch. | |
# Usefull when upstream don't have master branch or name it differently. | |
# | |
# EGIT_MASTER="master" | |
# @ECLASS-VARIABLE: EGIT_PROJECT | |
# @DESCRIPTION: | |
# Variable specifying name for the folder where we check out the git | |
# repository. Value of this variable should be unique in the | |
# EGIT_STORE_DIR as otherwise you would override another repository. | |
# | |
# EGIT_PROJECT="${EGIT_REPO_URI##*/}" | |
# @ECLASS-VARIABLE: EGIT_DIR | |
# @DESCRIPTION: | |
# Directory where we want to store the git data. | |
# This variable should not be overriden. | |
# | |
# EGIT_DIR="${EGIT_STORE_DIR}/${EGIT_PROJECT}" | |
# @ECLASS-VARIABLE: EGIT_REPO_URI | |
# @REQUIRED | |
# @DEFAULT_UNSET | |
# @DESCRIPTION: | |
# URI for the repository | |
# e.g. http://foo, git://bar | |
# | |
# Support multiple values: | |
# EGIT_REPO_URI="git://a/b.git http://c/d.git" | |
# @ECLASS-VARIABLE: EVCS_OFFLINE | |
# @DEFAULT_UNSET | |
# @DESCRIPTION: | |
# If non-empty this variable prevents performance of any online | |
# operations. | |
# @ECLASS-VARIABLE: EGIT_BRANCH | |
# @DESCRIPTION: | |
# Variable containing branch name we want to check out. | |
# It can be overriden via env using packagename_LIVE_BRANCH | |
# variable. | |
# | |
# EGIT_BRANCH="${EGIT_MASTER}" | |
# @ECLASS-VARIABLE: EGIT_COMMIT | |
# @DESCRIPTION: | |
# Variable containing commit hash/tag we want to check out. | |
# It can be overriden via env using packagename_LIVE_COMMIT | |
# variable. | |
# | |
# EGIT_COMMIT="${EGIT_BRANCH}" | |
# @ECLASS-VARIABLE: EGIT_REPACK | |
# @DEFAULT_UNSET | |
# @DESCRIPTION: | |
# If non-empty this variable specifies that repository will be repacked to | |
# save space. However this can take a REALLY LONG time with VERY big | |
# repositories. | |
# @ECLASS-VARIABLE: EGIT_PRUNE | |
# @DEFAULT_UNSET | |
# @DESCRIPTION: | |
# If non-empty this variable enables pruning all loose objects on each fetch. | |
# This is useful if upstream rewinds and rebases branches often. | |
# @ECLASS-VARIABLE: EGIT_NONBARE | |
# @DEFAULT_UNSET | |
# @DESCRIPTION: | |
# If non-empty this variable specifies that all checkouts will be done using | |
# non bare repositories. This is useful if you can't operate with bare | |
# checkouts for some reason. | |
# @ECLASS-VARIABLE: EGIT_NOUNPACK | |
# @DEFAULT_UNSET | |
# @DESCRIPTION: | |
# If non-empty this variable bans unpacking of ${A} content into the srcdir. | |
# Default behaviour is to unpack ${A} content. | |
# @FUNCTION: git-2_init_variables | |
# @INTERNAL | |
# @DESCRIPTION: | |
# Internal function initializing all git variables. | |
# We define it in function scope so user can define | |
# all the variables before and after inherit. | |
git-2_init_variables() { | |
debug-print-function ${FUNCNAME} "$@" | |
local esc_pn liverepo livebranch livecommit | |
esc_pn=${PN//[-+]/_} | |
: ${EGIT_SOURCEDIR="${S}"} | |
: ${EGIT_STORE_DIR:="${PORTAGE_ACTUAL_DISTDIR-${DISTDIR}}/egit-src"} | |
: ${EGIT_HAS_SUBMODULES:=} | |
: ${EGIT_OPTIONS:=} | |
: ${EGIT_MASTER:=master} | |
liverepo=${esc_pn}_LIVE_REPO | |
EGIT_REPO_URI=${!liverepo:-${EGIT_REPO_URI}} | |
[[ ${EGIT_REPO_URI} ]] || die "EGIT_REPO_URI must have some value" | |
: ${EVCS_OFFLINE:=} | |
livebranch=${esc_pn}_LIVE_BRANCH | |
[[ ${!livebranch} ]] && ewarn "QA: using \"${esc_pn}_LIVE_BRANCH\" variable, you won't get any support" | |
EGIT_BRANCH=${!livebranch:-${EGIT_BRANCH:-${EGIT_MASTER}}} | |
livecommit=${esc_pn}_LIVE_COMMIT | |
[[ ${!livecommit} ]] && ewarn "QA: using \"${esc_pn}_LIVE_COMMIT\" variable, you won't get any support" | |
EGIT_COMMIT=${!livecommit:-${EGIT_COMMIT:-${EGIT_BRANCH}}} | |
: ${EGIT_REPACK:=} | |
: ${EGIT_PRUNE:=} | |
} | |
# @FUNCTION: git-2_submodules | |
# @INTERNAL | |
# @DESCRIPTION: | |
# Internal function wrapping the submodule initialisation and update. | |
git-2_submodules() { | |
debug-print-function ${FUNCNAME} "$@" | |
if [[ ${EGIT_HAS_SUBMODULES} ]]; then | |
if [[ ${EVCS_OFFLINE} ]]; then | |
# for submodules operations we need to be online | |
debug-print "${FUNCNAME}: not updating submodules in offline mode" | |
return 1 | |
fi | |
debug-print "${FUNCNAME}: working in \"${1}\"" | |
pushd "${EGIT_DIR}" > /dev/null | |
debug-print "${FUNCNAME}: git submodule init" | |
git submodule init || die | |
debug-print "${FUNCNAME}: git submodule sync" | |
git submodule sync || die | |
debug-print "${FUNCNAME}: git submodule update" | |
git submodule update || die | |
popd > /dev/null | |
fi | |
} | |
# @FUNCTION: git-2_branch | |
# @INTERNAL | |
# @DESCRIPTION: | |
# Internal function that changes branch for the repo based on EGIT_COMMIT and | |
# EGIT_BRANCH variables. | |
git-2_branch() { | |
debug-print-function ${FUNCNAME} "$@" | |
local branchname src | |
debug-print "${FUNCNAME}: working in \"${EGIT_SOURCEDIR}\"" | |
pushd "${EGIT_SOURCEDIR}" > /dev/null | |
local branchname=branch-${EGIT_BRANCH} src=origin/${EGIT_BRANCH} | |
if [[ ${EGIT_COMMIT} != ${EGIT_BRANCH} ]]; then | |
branchname=tree-${EGIT_COMMIT} | |
src=${EGIT_COMMIT} | |
fi | |
debug-print "${FUNCNAME}: git checkout -b ${branchname} ${src}" | |
git checkout -b ${branchname} ${src} \ | |
|| die "${FUNCNAME}: changing the branch failed" | |
popd > /dev/null | |
} | |
# @FUNCTION: git-2_gc | |
# @INTERNAL | |
# @DESCRIPTION: | |
# Internal function running garbage collector on checked out tree. | |
git-2_gc() { | |
debug-print-function ${FUNCNAME} "$@" | |
local args | |
if [[ ${EGIT_REPACK} || ${EGIT_PRUNE} ]]; then | |
pushd "${EGIT_DIR}" > /dev/null | |
ebegin "Garbage collecting the repository" | |
[[ ${EGIT_PRUNE} ]] && args='--prune' | |
debug-print "${FUNCNAME}: git gc ${args}" | |
git gc ${args} | |
eend $? | |
popd > /dev/null | |
fi | |
} | |
# @FUNCTION: git-2_prepare_storedir | |
# @INTERNAL | |
# @DESCRIPTION: | |
# Internal function preparing directory where we are going to store SCM | |
# repository. | |
git-2_prepare_storedir() { | |
debug-print-function ${FUNCNAME} "$@" | |
local clone_dir | |
# initial clone, we have to create master git storage directory and play | |
# nicely with sandbox | |
if [[ ! -d ${EGIT_STORE_DIR} ]]; then | |
debug-print "${FUNCNAME}: Creating git main storage directory" | |
addwrite / | |
mkdir -m 775 -p "${EGIT_STORE_DIR}" \ | |
|| die "${FUNCNAME}: can't mkdir \"${EGIT_STORE_DIR}\"" | |
fi | |
# allow writing into EGIT_STORE_DIR | |
addwrite "${EGIT_STORE_DIR}" | |
# calculate git.eclass store dir for data | |
# We will try to clone the old repository, | |
# and we will remove it if we don't need it anymore. | |
EGIT_OLD_CLONE= | |
if [[ ${EGIT_STORE_DIR} == */egit-src ]]; then | |
local old_store_dir=${EGIT_STORE_DIR/%egit-src/git-src} | |
local old_location=${old_store_dir}/${EGIT_PROJECT:-${PN}} | |
if [[ -d ${old_location} ]]; then | |
EGIT_OLD_CLONE=${old_location} | |
# required to remove the old clone | |
addwrite "${old_store_dir}" | |
fi | |
fi | |
# calculate the proper store dir for data | |
# If user didn't specify the EGIT_DIR, we check if he did specify | |
# the EGIT_PROJECT or get the folder name from EGIT_REPO_URI. | |
EGIT_REPO_URI=${EGIT_REPO_URI%/} | |
if [[ ! ${EGIT_DIR} ]]; then | |
if [[ ${EGIT_PROJECT} ]]; then | |
clone_dir=${EGIT_PROJECT} | |
else | |
local strippeduri=${EGIT_REPO_URI%/.git} | |
clone_dir=${strippeduri##*/} | |
fi | |
EGIT_DIR=${EGIT_STORE_DIR}/${clone_dir} | |
if [[ ${EGIT_OLD_CLONE} && ! -d ${EGIT_DIR} ]]; then | |
elog "${FUNCNAME}: ${CATEGORY}/${PF} will be cloned from old location." | |
elog "It will be necessary to rebuild the package to fetch updates." | |
EGIT_REPO_URI="${EGIT_OLD_CLONE} ${EGIT_REPO_URI}" | |
fi | |
fi | |
export EGIT_DIR=${EGIT_DIR} | |
debug-print "${FUNCNAME}: Storing the repo into \"${EGIT_DIR}\"." | |
} | |
# @FUNCTION: git-2_move_source | |
# @INTERNAL | |
# @DESCRIPTION: | |
# Internal function moving sources from the EGIT_DIR to EGIT_SOURCEDIR dir. | |
git-2_move_source() { | |
debug-print-function ${FUNCNAME} "$@" | |
debug-print "${FUNCNAME}: ${MOVE_COMMAND} \"${EGIT_DIR}\" \"${EGIT_SOURCEDIR}\"" | |
pushd "${EGIT_DIR}" > /dev/null | |
mkdir -p "${EGIT_SOURCEDIR}" \ | |
|| die "${FUNCNAME}: failed to create ${EGIT_SOURCEDIR}" | |
${MOVE_COMMAND} "${EGIT_SOURCEDIR}" \ | |
|| die "${FUNCNAME}: sync to \"${EGIT_SOURCEDIR}\" failed" | |
popd > /dev/null | |
} | |
# @FUNCTION: git-2_initial_clone | |
# @INTERNAL | |
# @DESCRIPTION: | |
# Internal function running initial clone on specified repo_uri. | |
git-2_initial_clone() { | |
debug-print-function ${FUNCNAME} "$@" | |
local repo_uri | |
EGIT_REPO_URI_SELECTED="" | |
for repo_uri in ${EGIT_REPO_URI}; do | |
debug-print "${FUNCNAME}: git clone ${EGIT_LOCAL_OPTIONS} \"${repo_uri}\" \"${EGIT_DIR}\"" | |
if git clone ${EGIT_LOCAL_OPTIONS} "${repo_uri}" "${EGIT_DIR}"; then | |
# global variable containing the repo_name we will be using | |
debug-print "${FUNCNAME}: EGIT_REPO_URI_SELECTED=\"${repo_uri}\"" | |
EGIT_REPO_URI_SELECTED="${repo_uri}" | |
break | |
fi | |
done | |
[[ ${EGIT_REPO_URI_SELECTED} ]] \ | |
|| die "${FUNCNAME}: can't fetch from ${EGIT_REPO_URI}" | |
} | |
# @FUNCTION: git-2_update_repo | |
# @INTERNAL | |
# @DESCRIPTION: | |
# Internal function running update command on specified repo_uri. | |
git-2_update_repo() { | |
debug-print-function ${FUNCNAME} "$@" | |
local repo_uri | |
if [[ ${EGIT_LOCAL_NONBARE} ]]; then | |
# checkout master branch and drop all other local branches | |
git checkout ${EGIT_MASTER} || die "${FUNCNAME}: can't checkout master branch ${EGIT_MASTER}" | |
for x in $(git branch | grep -v "* ${EGIT_MASTER}" | tr '\n' ' '); do | |
debug-print "${FUNCNAME}: git branch -D ${x}" | |
git branch -D ${x} > /dev/null | |
done | |
fi | |
EGIT_REPO_URI_SELECTED="" | |
for repo_uri in ${EGIT_REPO_URI}; do | |
# git urls might change, so reset it | |
git config remote.origin.url "${repo_uri}" | |
debug-print "${EGIT_UPDATE_CMD}" | |
if ${EGIT_UPDATE_CMD} > /dev/null; then | |
# global variable containing the repo_name we will be using | |
debug-print "${FUNCNAME}: EGIT_REPO_URI_SELECTED=\"${repo_uri}\"" | |
EGIT_REPO_URI_SELECTED="${repo_uri}" | |
break | |
fi | |
done | |
[[ ${EGIT_REPO_URI_SELECTED} ]] \ | |
|| die "${FUNCNAME}: can't update from ${EGIT_REPO_URI}" | |
} | |
# @FUNCTION: git-2_fetch | |
# @INTERNAL | |
# @DESCRIPTION: | |
# Internal function fetching repository from EGIT_REPO_URI and storing it in | |
# specified EGIT_STORE_DIR. | |
git-2_fetch() { | |
debug-print-function ${FUNCNAME} "$@" | |
local oldsha cursha repo_type | |
[[ ${EGIT_LOCAL_NONBARE} ]] && repo_type="non-bare repository" || repo_type="bare repository" | |
if [[ ! -d ${EGIT_DIR} ]]; then | |
git-2_initial_clone | |
pushd "${EGIT_DIR}" > /dev/null | |
cursha=$(git rev-parse ${UPSTREAM_BRANCH}) | |
echo "GIT NEW clone -->" | |
echo " repository: ${EGIT_REPO_URI_SELECTED}" | |
echo " at the commit: ${cursha}" | |
popd > /dev/null | |
elif [[ ${EVCS_OFFLINE} ]]; then | |
pushd "${EGIT_DIR}" > /dev/null | |
cursha=$(git rev-parse ${UPSTREAM_BRANCH}) | |
echo "GIT offline update -->" | |
echo " repository: $(git config remote.origin.url)" | |
echo " at the commit: ${cursha}" | |
popd > /dev/null | |
else | |
pushd "${EGIT_DIR}" > /dev/null | |
oldsha=$(git rev-parse ${UPSTREAM_BRANCH}) | |
git-2_update_repo | |
cursha=$(git rev-parse ${UPSTREAM_BRANCH}) | |
# fetch updates | |
echo "GIT update -->" | |
echo " repository: ${EGIT_REPO_URI_SELECTED}" | |
# write out message based on the revisions | |
if [[ "${oldsha}" != "${cursha}" ]]; then | |
echo " updating from commit: ${oldsha}" | |
echo " to commit: ${cursha}" | |
else | |
echo " at the commit: ${cursha}" | |
fi | |
# print nice statistic of what was changed | |
git --no-pager diff --stat ${oldsha}..${UPSTREAM_BRANCH} | |
popd > /dev/null | |
fi | |
# export the version the repository is at | |
export EGIT_VERSION="${cursha}" | |
# log the repo state | |
[[ ${EGIT_COMMIT} != ${EGIT_BRANCH} ]] \ | |
&& echo " commit: ${EGIT_COMMIT}" | |
echo " branch: ${EGIT_BRANCH}" | |
echo " storage directory: \"${EGIT_DIR}\"" | |
echo " checkout type: ${repo_type}" | |
# Cleanup after git.eclass | |
if [[ ${EGIT_OLD_CLONE} ]]; then | |
einfo "${FUNCNAME}: removing old clone in ${EGIT_OLD_CLONE}." | |
rm -rf "${EGIT_OLD_CLONE}" | |
fi | |
} | |
# @FUNCTION: git_bootstrap | |
# @INTERNAL | |
# @DESCRIPTION: | |
# Internal function that runs bootstrap command on unpacked source. | |
git-2_bootstrap() { | |
debug-print-function ${FUNCNAME} "$@" | |
# @ECLASS-VARIABLE: EGIT_BOOTSTRAP | |
# @DESCRIPTION: | |
# Command to be executed after checkout and clone of the specified | |
# repository. | |
# enviroment the package will fail if there is no update, thus in | |
# combination with --keep-going it would lead in not-updating | |
# pakcages that are up-to-date. | |
if [[ ${EGIT_BOOTSTRAP} ]]; then | |
pushd "${EGIT_SOURCEDIR}" > /dev/null | |
einfo "Starting bootstrap" | |
if [[ -f ${EGIT_BOOTSTRAP} ]]; then | |
# we have file in the repo which we should execute | |
debug-print "${FUNCNAME}: bootstraping with file \"${EGIT_BOOTSTRAP}\"" | |
if [[ -x ${EGIT_BOOTSTRAP} ]]; then | |
eval "./${EGIT_BOOTSTRAP}" \ | |
|| die "${FUNCNAME}: bootstrap script failed" | |
else | |
eerror "\"${EGIT_BOOTSTRAP}\" is not executable." | |
eerror "Report upstream, or bug ebuild maintainer to remove bootstrap command." | |
die "\"${EGIT_BOOTSTRAP}\" is not executable" | |
fi | |
else | |
# we execute some system command | |
debug-print "${FUNCNAME}: bootstraping with commands \"${EGIT_BOOTSTRAP}\"" | |
eval "${EGIT_BOOTSTRAP}" \ | |
|| die "${FUNCNAME}: bootstrap commands failed" | |
fi | |
einfo "Bootstrap finished" | |
popd > /dev/null | |
fi | |
} | |
# @FUNCTION: git-2_migrate_repository | |
# @INTERNAL | |
# @DESCRIPTION: | |
# Internal function migrating between bare and normal checkout repository. | |
# This is based on usage of EGIT_SUBMODULES, at least until they | |
# start to work with bare checkouts sanely. | |
# This function also set some global variables that differ between | |
# bare and non-bare checkout. | |
git-2_migrate_repository() { | |
debug-print-function ${FUNCNAME} "$@" | |
local bare returnstate | |
# first find out if we have submodules | |
# or user explicitly wants us to use non-bare clones | |
if ! [[ ${EGIT_HAS_SUBMODULES} || ${EGIT_NONBARE} ]]; then | |
bare=1 | |
fi | |
# test if we already have some repo and if so find out if we have | |
# to migrate the data | |
if [[ -d ${EGIT_DIR} ]]; then | |
if [[ ${bare} && -d ${EGIT_DIR}/.git ]]; then | |
debug-print "${FUNCNAME}: converting \"${EGIT_DIR}\" to bare copy" | |
ebegin "Converting \"${EGIT_DIR}\" from non-bare to bare copy" | |
mv "${EGIT_DIR}/.git" "${EGIT_DIR}.bare" | |
export GIT_DIR="${EGIT_DIR}.bare" | |
git config core.bare true > /dev/null | |
returnstate=$? | |
unset GIT_DIR | |
rm -rf "${EGIT_DIR}" | |
mv "${EGIT_DIR}.bare" "${EGIT_DIR}" | |
eend ${returnstate} | |
elif [[ ! ${bare} && ! -d ${EGIT_DIR}/.git ]]; then | |
debug-print "${FUNCNAME}: converting \"${EGIT_DIR}\" to non-bare copy" | |
ebegin "Converting \"${EGIT_DIR}\" from bare to non-bare copy" | |
git clone -l "${EGIT_DIR}" "${EGIT_DIR}.nonbare" > /dev/null | |
returnstate=$? | |
rm -rf "${EGIT_DIR}" | |
mv "${EGIT_DIR}.nonbare" "${EGIT_DIR}" | |
eend ${returnstate} | |
fi | |
fi | |
if [[ ${returnstate} -ne 0 ]]; then | |
debug-print "${FUNCNAME}: converting \"${EGIT_DIR}\" failed, removing to start from scratch" | |
# migration failed, remove the EGIT_DIR to play it safe | |
einfo "Migration failed, removing \"${EGIT_DIR}\" to start from scratch." | |
rm -rf "${EGIT_DIR}" | |
fi | |
# set various options to work with both targets | |
if [[ ${bare} ]]; then | |
debug-print "${FUNCNAME}: working in bare repository for \"${EGIT_DIR}\"" | |
EGIT_LOCAL_OPTIONS+="${EGIT_OPTIONS} --bare" | |
MOVE_COMMAND="git clone -l -s -n ${EGIT_DIR// /\\ }" | |
EGIT_UPDATE_CMD="tsocks git fetch -t -f -u origin ${EGIT_BRANCH}:${EGIT_BRANCH}" | |
UPSTREAM_BRANCH="${EGIT_BRANCH}" | |
EGIT_LOCAL_NONBARE= | |
else | |
debug-print "${FUNCNAME}: working in bare repository for non-bare \"${EGIT_DIR}\"" | |
MOVE_COMMAND="cp -pPR ." | |
EGIT_LOCAL_OPTIONS="${EGIT_OPTIONS}" | |
EGIT_UPDATE_CMD="tsocks git pull -f -u ${EGIT_OPTIONS}" | |
UPSTREAM_BRANCH="origin/${EGIT_BRANCH}" | |
EGIT_LOCAL_NONBARE="true" | |
fi | |
} | |
# @FUNCTION: git-2_cleanup | |
# @INTERNAL | |
# @DESCRIPTION: | |
# Internal function cleaning up all the global variables | |
# that are not required after the unpack has been done. | |
git-2_cleanup() { | |
debug-print-function ${FUNCNAME} "$@" | |
# Here we can unset only variables that are GLOBAL | |
# defined by the eclass, BUT NOT subject to change | |
# by user (like EGIT_PROJECT). | |
# If ebuild writer polutes his environment it is | |
# his problem only. | |
unset EGIT_DIR | |
unset MOVE_COMMAND | |
unset EGIT_LOCAL_OPTIONS | |
unset EGIT_UPDATE_CMD | |
unset UPSTREAM_BRANCH | |
unset EGIT_LOCAL_NONBARE | |
} | |
# @FUNCTION: git-2_src_unpack | |
# @DESCRIPTION: | |
# Default git src_unpack function. | |
git-2_src_unpack() { | |
debug-print-function ${FUNCNAME} "$@" | |
git-2_init_variables | |
git-2_prepare_storedir | |
git-2_migrate_repository | |
git-2_fetch "$@" | |
git-2_gc | |
git-2_submodules | |
git-2_move_source | |
git-2_branch | |
git-2_bootstrap | |
git-2_cleanup | |
echo ">>> Unpacked to ${EGIT_SOURCEDIR}" | |
# Users can specify some SRC_URI and we should | |
# unpack the files too. | |
if [[ ! ${EGIT_NOUNPACK} ]]; then | |
if has ${EAPI:-0} 0 1; then | |
[[ ${A} ]] && unpack ${A} | |
else | |
default_src_unpack | |
fi | |
fi | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Copyright 1999-2012 Gentoo Foundation | |
# Distributed under the terms of the GNU General Public License v2 | |
# $Header: /var/cvsroot/gentoo-x86/eclass/git.eclass,v 1.59 2012/09/27 16:35:41 axs Exp $ | |
# @DEPRECATED | |
# This eclass has been superseded by git-2 eclass. | |
# Please modify your ebuilds to use that one instead. | |
# @ECLASS: git.eclass | |
# @MAINTAINER: | |
# Donnie Berkholz <dberkholz@gentoo.org> | |
# @BLURB: Fetching and unpacking of git repositories | |
# @DESCRIPTION: | |
# The git eclass provides functions to fetch, patch and bootstrap | |
# software sources from git repositories and is based on the subversion eclass. | |
# It is necessary to define at least the EGIT_REPO_URI variable. | |
# @THANKS TO: | |
# Fernando J. Pereda <ferdy@gentoo.org> | |
inherit eutils | |
EGIT="git.eclass" | |
# We DEPEND on a not too ancient git version | |
DEPEND=">=dev-vcs/git-1.6" | |
EXPORTED_FUNCTIONS="src_unpack" | |
case "${EAPI:-0}" in | |
2|3|4|5) EXPORTED_FUNCTIONS="${EXPORTED_FUNCTIONS} src_prepare" ;; | |
1|0) ;; | |
*) die "EAPI=${EAPI} is not supported" ;; | |
esac | |
EXPORT_FUNCTIONS ${EXPORTED_FUNCTIONS} | |
# define some nice defaults but only if nothing is set already | |
: ${HOMEPAGE:=http://git-scm.com/} | |
# @ECLASS-VARIABLE: EGIT_QUIET | |
# @DESCRIPTION: | |
# Set to non-empty value to supress some eclass messages. | |
: ${EGIT_QUIET:=${ESCM_QUIET}} | |
# @ECLASS-VARIABLE: EGIT_STORE_DIR | |
# @DESCRIPTION: | |
# Storage directory for git sources. | |
# Can be redefined. | |
: ${EGIT_STORE_DIR:="${PORTAGE_ACTUAL_DISTDIR-${DISTDIR}}/git-src"} | |
# @ECLASS-VARIABLE: EGIT_UNPACK_DIR | |
# @DESCRIPTION: | |
# Directory to unpack git sources in. | |
# @ECLASS-VARIABLE: EGIT_HAS_SUBMODULES | |
# @DESCRIPTION: | |
# Set this to non-empty value to enable submodule support (slower). | |
: ${EGIT_HAS_SUBMODULES:=} | |
# @ECLASS-VARIABLE: EGIT_FETCH_CMD | |
# @DESCRIPTION: | |
# Command for cloning the repository. | |
: ${EGIT_FETCH_CMD:="tsocks git clone"} | |
# @ECLASS-VARIABLE: EGIT_UPDATE_CMD | |
# @DESCRIPTION: | |
# Git fetch command. | |
if [[ -n ${EGIT_HAS_SUBMODULES} ]]; then | |
EGIT_UPDATE_CMD="tsocks git pull -f -u" | |
else | |
EGIT_UPDATE_CMD="tsocks git fetch -f -u" | |
fi | |
# @ECLASS-VARIABLE: EGIT_DIFFSTAT_CMD | |
# @DESCRIPTION: | |
# Git command for diffstat. | |
EGIT_DIFFSTAT_CMD="git --no-pager diff --stat" | |
# @ECLASS-VARIABLE: EGIT_OPTIONS | |
# @DESCRIPTION: | |
# This variable value is passed to clone and fetch. | |
: ${EGIT_OPTIONS:=} | |
# @ECLASS-VARIABLE: EGIT_MASTER | |
# @DESCRIPTION: | |
# Variable for specifying master branch. | |
# Usefull when upstream don't have master branch. | |
: ${EGIT_MASTER:=master} | |
# @ECLASS-VARIABLE: EGIT_REPO_URI | |
# @DESCRIPTION: | |
# URI for the repository | |
# e.g. http://foo, git://bar | |
# Supported protocols: | |
# http:// | |
# https:// | |
# git:// | |
# git+ssh:// | |
# rsync:// | |
# ssh:// | |
eval X="\$${PN//[-+]/_}_LIVE_REPO" | |
if [[ ${X} = "" ]]; then | |
: ${EGIT_REPO_URI:=} | |
else | |
EGIT_REPO_URI="${X}" | |
fi | |
# @ECLASS-VARIABLE: EGIT_PROJECT | |
# @DESCRIPTION: | |
# Project name, it must be unique across EGIT_STORE_DIR. | |
# Git eclass will check out the git repository into ${EGIT_STORE_DIR}/${EGIT_PROJECT}/${EGIT_REPO_URI##*/} | |
# Default is ${PN}. | |
: ${EGIT_PROJECT:=${PN}} | |
# @ECLASS-VARIABLE: EGIT_BOOTSTRAP | |
# @DESCRIPTION: | |
# bootstrap script or command like autogen.sh or etc... | |
: ${EGIT_BOOTSTRAP:=} | |
# @ECLASS-VARIABLE: EGIT_OFFLINE | |
# @DESCRIPTION: | |
# Set this variable to a non-empty value to disable the automatic updating of | |
# an GIT source tree. This is intended to be set outside the git source | |
# tree by users. | |
: ${EGIT_OFFLINE:=${ESCM_OFFLINE}} | |
# @ECLASS-VARIABLE: EGIT_PATCHES | |
# @DESCRIPTION: | |
# Similar to PATCHES array from base.eclass | |
# Only difference is that this patches are applied before bootstrap. | |
# Please take note that this variable should be bash array. | |
# @ECLASS-VARIABLE: EGIT_BRANCH | |
# @DESCRIPTION: | |
# git eclass can fetch any branch in git_fetch(). | |
eval X="\$${PN//[-+]/_}_LIVE_BRANCH" | |
if [[ "${X}" = "" ]]; then | |
: ${EGIT_BRANCH:=master} | |
else | |
EGIT_BRANCH="${X}" | |
fi | |
# @ECLASS-VARIABLE: EGIT_COMMIT | |
# @DESCRIPTION: | |
# git eclass can checkout any commit. | |
eval X="\$${PN//[-+]/_}_LIVE_COMMIT" | |
if [[ "${X}" = "" ]]; then | |
: ${EGIT_COMMIT:=${EGIT_BRANCH}} | |
else | |
EGIT_COMMIT="${X}" | |
fi | |
# @ECLASS-VARIABLE: EGIT_REPACK | |
# @DESCRIPTION: | |
# Set to non-empty value to repack objects to save disk space. However this can | |
# take a long time with VERY big repositories. | |
: ${EGIT_REPACK:=} | |
# @ECLASS-VARIABLE: EGIT_PRUNE | |
# @DESCRIPTION: | |
# Set to non-empty value to prune loose objects on each fetch. This is useful | |
# if upstream rewinds and rebases branches often. | |
: ${EGIT_PRUNE:=} | |
# @FUNCTION: git_submodules | |
# @DESCRIPTION: | |
# Internal function wrapping the submodule initialisation and update | |
git_submodules() { | |
if [[ -n ${EGIT_HAS_SUBMODULES} ]]; then | |
debug-print "git submodule init" | |
git submodule init | |
debug-print "git submodule sync" | |
git submodule sync | |
debug-print "git submodule update" | |
git submodule update | |
fi | |
} | |
# @FUNCTION: git_branch | |
# @DESCRIPTION: | |
# Internal function that changes branch for the repo based on EGIT_TREE and | |
# EGIT_BRANCH variables. | |
git_branch() { | |
local branchname=branch-${EGIT_BRANCH} src=origin/${EGIT_BRANCH} | |
if [[ "${EGIT_COMMIT}" != "${EGIT_BRANCH}" ]]; then | |
branchname=tree-${EGIT_COMMIT} | |
src=${EGIT_COMMIT} | |
fi | |
debug-print "git checkout -b ${branchname} ${src}" | |
git checkout -b ${branchname} ${src} &> /dev/null | |
unset branchname src | |
} | |
# @FUNCTION: git_fetch | |
# @DESCRIPTION: | |
# Gets repository from EGIT_REPO_URI and store it in specified EGIT_STORE_DIR | |
git_fetch() { | |
debug-print-function ${FUNCNAME} "$@" | |
eqawarn "git.eclass is deprecated." | |
eqawarn "Please update your ebuilds to use git-2 instead. For details, see" | |
eqawarn "http://archives.gentoo.org/gentoo-dev/msg_b7ba363cae580845819ae3501fb157e9.xml" | |
local GIT_DIR EGIT_CLONE_DIR oldsha1 cursha1 extra_clone_opts upstream_branch | |
[[ -z ${EGIT_HAS_SUBMODULES} ]] && export GIT_DIR | |
# choose if user wants elog or just einfo. | |
if [[ -n ${EGIT_QUIET} ]]; then | |
elogcmd="einfo" | |
else | |
elogcmd="elog" | |
fi | |
# If we have same branch and the tree we can do --depth 1 clone | |
# which outputs into really smaller data transfers. | |
# Sadly we can do shallow copy for now because quite a few packages need .git | |
# folder. | |
#[[ ${EGIT_COMMIT} = ${EGIT_BRANCH} ]] && \ | |
# EGIT_FETCH_CMD="${EGIT_FETCH_CMD} --depth 1" | |
if [[ -n ${EGIT_TREE} ]] ; then | |
EGIT_COMMIT=${EGIT_TREE} | |
ewarn "QA: Usage of deprecated EGIT_TREE variable detected." | |
ewarn "QA: Use EGIT_COMMIT variable instead." | |
fi | |
# EGIT_REPO_URI is empty. | |
[[ -z ${EGIT_REPO_URI} ]] && die "${EGIT}: EGIT_REPO_URI is empty." | |
# check for the protocol or pull from a local repo. | |
if [[ -z ${EGIT_REPO_URI%%:*} ]] ; then | |
case ${EGIT_REPO_URI%%:*} in | |
git*|http|https|rsync|ssh) ;; | |
*) die "${EGIT}: protocol for fetch from "${EGIT_REPO_URI%:*}" is not yet implemented in eclass." ;; | |
esac | |
fi | |
# initial clone, we have to create master git storage directory and play | |
# nicely with sandbox | |
if [[ ! -d ${EGIT_STORE_DIR} ]] ; then | |
debug-print "${FUNCNAME}: initial clone. creating git directory" | |
addwrite / | |
mkdir -m 775 -p "${EGIT_STORE_DIR}" \ | |
|| die "${EGIT}: can't mkdir ${EGIT_STORE_DIR}." | |
export SANDBOX_WRITE="${SANDBOX_WRITE%%:/}" | |
fi | |
cd -P "${EGIT_STORE_DIR}" || die "${EGIT}: can't chdir to ${EGIT_STORE_DIR}" | |
EGIT_STORE_DIR=${PWD} | |
# allow writing into EGIT_STORE_DIR | |
addwrite "${EGIT_STORE_DIR}" | |
[[ -z ${EGIT_REPO_URI##*/} ]] && EGIT_REPO_URI="${EGIT_REPO_URI%/}" | |
EGIT_CLONE_DIR="${EGIT_PROJECT}" | |
debug-print "${FUNCNAME}: EGIT_OPTIONS = \"${EGIT_OPTIONS}\"" | |
GIT_DIR="${EGIT_STORE_DIR}/${EGIT_CLONE_DIR}" | |
# we also have to remove all shallow copied repositories | |
# and fetch them again | |
if [[ -e "${GIT_DIR}/shallow" ]]; then | |
rm -rf "${GIT_DIR}" | |
einfo "The ${EGIT_CLONE_DIR} was shallow copy. Refetching." | |
fi | |
# repack from bare copy to normal one | |
if [[ -n ${EGIT_HAS_SUBMODULES} ]] && [[ -d ${GIT_DIR} && ! -d ${GIT_DIR}/.git ]]; then | |
rm -rf "${GIT_DIR}" | |
einfo "The ${EGIT_CLONE_DIR} was bare copy. Refetching." | |
fi | |
if [[ -z ${EGIT_HAS_SUBMODULES} ]] && [[ -d ${GIT_DIR} && -d ${GIT_DIR}/.git ]]; then | |
rm -rf "${GIT_DIR}" | |
einfo "The ${EGIT_CLONE_DIR} was not a bare copy. Refetching." | |
fi | |
if [[ -n ${EGIT_HAS_SUBMODULES} ]]; then | |
upstream_branch=origin/${EGIT_BRANCH} | |
else | |
upstream_branch=${EGIT_BRANCH} | |
extra_clone_opts=--bare | |
fi | |
if [[ ! -d ${GIT_DIR} ]] ; then | |
# first clone | |
${elogcmd} "GIT NEW clone -->" | |
${elogcmd} " repository: ${EGIT_REPO_URI}" | |
debug-print "${EGIT_FETCH_CMD} ${extra_clone_opts} ${EGIT_OPTIONS} \"${EGIT_REPO_URI}\" ${GIT_DIR}" | |
${EGIT_FETCH_CMD} ${extra_clone_opts} ${EGIT_OPTIONS} "${EGIT_REPO_URI}" ${GIT_DIR} \ | |
|| die "${EGIT}: can't fetch from ${EGIT_REPO_URI}." | |
pushd "${GIT_DIR}" &> /dev/null | |
cursha1=$(git rev-parse ${upstream_branch}) | |
${elogcmd} " at the commit: ${cursha1}" | |
git_submodules | |
popd &> /dev/null | |
elif [[ -n ${EGIT_OFFLINE} ]] ; then | |
pushd "${GIT_DIR}" &> /dev/null | |
cursha1=$(git rev-parse ${upstream_branch}) | |
${elogcmd} "GIT offline update -->" | |
${elogcmd} " repository: ${EGIT_REPO_URI}" | |
${elogcmd} " at the commit: ${cursha1}" | |
popd &> /dev/null | |
else | |
pushd "${GIT_DIR}" &> /dev/null | |
# Git urls might change, so unconditionally set it here | |
git config remote.origin.url "${EGIT_REPO_URI}" | |
# fetch updates | |
${elogcmd} "GIT update -->" | |
${elogcmd} " repository: ${EGIT_REPO_URI}" | |
oldsha1=$(git rev-parse ${upstream_branch}) | |
if [[ -n ${EGIT_HAS_SUBMODULES} ]]; then | |
debug-print "${EGIT_UPDATE_CMD} ${EGIT_OPTIONS}" | |
# fix branching | |
git checkout ${EGIT_MASTER} | |
for x in $(git branch |grep -v "* ${EGIT_MASTER}" |tr '\n' ' '); do | |
git branch -D ${x} | |
done | |
${EGIT_UPDATE_CMD} ${EGIT_OPTIONS} \ | |
|| die "${EGIT}: can't update from ${EGIT_REPO_URI}." | |
else | |
debug-print "${EGIT_UPDATE_CMD} ${EGIT_OPTIONS} origin ${EGIT_BRANCH}:${EGIT_BRANCH}" | |
${EGIT_UPDATE_CMD} ${EGIT_OPTIONS} origin ${EGIT_BRANCH}:${EGIT_BRANCH} \ | |
|| die "${EGIT}: can't update from ${EGIT_REPO_URI}." | |
fi | |
git_submodules | |
cursha1=$(git rev-parse ${upstream_branch}) | |
# write out message based on the revisions | |
if [[ "${oldsha1}" != "${cursha1}" ]]; then | |
${elogcmd} " updating from commit: ${oldsha1}" | |
${elogcmd} " to commit: ${cursha1}" | |
else | |
${elogcmd} " at the commit: ${cursha1}" | |
# @ECLASS-VARIABLE: LIVE_FAIL_FETCH_IF_REPO_NOT_UPDATED | |
# @DESCRIPTION: | |
# If this variable is set to TRUE in make.conf or somewhere in | |
# enviroment the package will fail if there is no update, thus in | |
# combination with --keep-going it would lead in not-updating | |
# pakcages that are up-to-date. | |
# TODO: this can lead to issues if more projects/packages use same repo | |
[[ ${LIVE_FAIL_FETCH_IF_REPO_NOT_UPDATED} = true ]] && \ | |
debug-print "${FUNCNAME}: Repository \"${EGIT_REPO_URI}\" is up-to-date. Skipping." && \ | |
die "${EGIT}: Repository \"${EGIT_REPO_URI}\" is up-to-date. Skipping." | |
fi | |
${EGIT_DIFFSTAT_CMD} ${oldsha1}..${upstream_branch} | |
popd &> /dev/null | |
fi | |
pushd "${GIT_DIR}" &> /dev/null | |
if [[ -n ${EGIT_REPACK} ]] || [[ -n ${EGIT_PRUNE} ]]; then | |
ebegin "Garbage collecting the repository" | |
local args | |
[[ -n ${EGIT_PRUNE} ]] && args='--prune' | |
git gc ${args} | |
eend $? | |
fi | |
popd &> /dev/null | |
# export the git version | |
export EGIT_VERSION="${cursha1}" | |
# log the repo state | |
[[ "${EGIT_COMMIT}" != "${EGIT_BRANCH}" ]] && ${elogcmd} " commit: ${EGIT_COMMIT}" | |
${elogcmd} " branch: ${EGIT_BRANCH}" | |
${elogcmd} " storage directory: \"${GIT_DIR}\"" | |
if [[ -n ${EGIT_HAS_SUBMODULES} ]]; then | |
pushd "${GIT_DIR}" &> /dev/null | |
debug-print "rsync -rlpgo . \"${EGIT_UNPACK_DIR:-${S}}\"" | |
time rsync -rlpgo . "${EGIT_UNPACK_DIR:-${S}}" | |
popd &> /dev/null | |
else | |
unset GIT_DIR | |
debug-print "git clone -l -s -n \"${EGIT_STORE_DIR}/${EGIT_CLONE_DIR}\" \"${EGIT_UNPACK_DIR:-${S}}\"" | |
git clone -l -s -n "${EGIT_STORE_DIR}/${EGIT_CLONE_DIR}" "${EGIT_UNPACK_DIR:-${S}}" | |
fi | |
pushd "${EGIT_UNPACK_DIR:-${S}}" &> /dev/null | |
git_branch | |
# submodules always reqire net (thanks to branches changing) | |
[[ -z ${EGIT_OFFLINE} ]] && git_submodules | |
popd &> /dev/null | |
echo ">>> Unpacked to ${EGIT_UNPACK_DIR:-${S}}" | |
} | |
# @FUNCTION: git_bootstrap | |
# @DESCRIPTION: | |
# Runs bootstrap command if EGIT_BOOTSTRAP variable contains some value | |
# Remember that what ever gets to the EGIT_BOOTSTRAP variable gets evaled by bash. | |
git_bootstrap() { | |
debug-print-function ${FUNCNAME} "$@" | |
if [[ -n ${EGIT_BOOTSTRAP} ]] ; then | |
pushd "${S}" > /dev/null | |
einfo "Starting bootstrap" | |
if [[ -f ${EGIT_BOOTSTRAP} ]]; then | |
# we have file in the repo which we should execute | |
debug-print "$FUNCNAME: bootstraping with file \"${EGIT_BOOTSTRAP}\"" | |
if [[ -x ${EGIT_BOOTSTRAP} ]]; then | |
eval "./${EGIT_BOOTSTRAP}" \ | |
|| die "${EGIT}: bootstrap script failed" | |
else | |
eerror "\"${EGIT_BOOTSTRAP}\" is not executable." | |
eerror "Report upstream, or bug ebuild maintainer to remove bootstrap command." | |
die "${EGIT}: \"${EGIT_BOOTSTRAP}\" is not executable." | |
fi | |
else | |
# we execute some system command | |
debug-print "$FUNCNAME: bootstraping with commands \"${EGIT_BOOTSTRAP}\"" | |
eval "${EGIT_BOOTSTRAP}" \ | |
|| die "${EGIT}: bootstrap commands failed." | |
fi | |
einfo "Bootstrap finished" | |
popd > /dev/null | |
fi | |
} | |
# @FUNCTION: git_apply_patches | |
# @DESCRIPTION: | |
# Apply patches from EGIT_PATCHES bash array. | |
# Preferred is using the variable as bash array but for now it allows to write | |
# it also as normal space separated string list. (This part of code should be | |
# removed when all ebuilds get converted on bash array). | |
git_apply_patches() { | |
debug-print-function ${FUNCNAME} "$@" | |
pushd "${EGIT_UNPACK_DIR:-${S}}" > /dev/null | |
if [[ ${#EGIT_PATCHES[@]} -gt 1 ]] ; then | |
for i in "${EGIT_PATCHES[@]}"; do | |
debug-print "$FUNCNAME: git_autopatch: patching from ${i}" | |
epatch "${i}" | |
done | |
elif [[ -n ${EGIT_PATCHES} ]]; then | |
# no need for loop if space separated string is passed. | |
debug-print "$FUNCNAME: git_autopatch: patching from ${EGIT_PATCHES}" | |
epatch "${EGIT_PATCHES}" | |
fi | |
popd > /dev/null | |
} | |
# @FUNCTION: git_src_unpack | |
# @DESCRIPTION: | |
# src_upack function, calls src_prepare one if EAPI!=2. | |
git_src_unpack() { | |
debug-print-function ${FUNCNAME} "$@" | |
git_fetch || die "${EGIT}: unknown problem in git_fetch()." | |
has src_prepare ${EXPORTED_FUNCTIONS} || git_src_prepare | |
} | |
# @FUNCTION: git_src_prepare | |
# @DESCRIPTION: | |
# src_prepare function for git stuff. Patches, bootstrap... | |
git_src_prepare() { | |
debug-print-function ${FUNCNAME} "$@" | |
git_apply_patches | |
git_bootstrap | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment