[prev in list] [next in list] [prev in thread] [next in thread]
List: gentoo-dev
Subject: Re: [gentoo-dev] git-r3: initial draft for review [v3]
From: Michał Górny <mgorny () gentoo ! org>
Date: 2013-08-31 20:59:43
Message-ID: 20130831225943.42f66018 () gentoo ! org
[Download RAW message or body]
[Attachment #2 (multipart/mixed)]
A few more changes.
1. Added EGIT_CHECKOUT_DIR to control the place where stuff is checked
out.
2. Moved the defaults from src_fetch() and src_unpack()
into git-r3_fetch() and git-r3_checkout(). This makes using them
easier, like:
git-r3_fetch http://repo1
git-r3_fetch http://repo2
git-r3_checkout http://repo1
git-r3_checkout http://repo2 ${S}/foo
3. Added prototype pkg_isuptodate() function [bug 482666 [1]].
(I will update it when we decide on how the func should be named :))
As an additional testing tool, I attached the version of git-r3
converted to git-2 compatible API. IOW, a drop-in replacement that you
could use to test the new eclass internals with API almost fully
compatible with the old one.
[1]:https://bugs.gentoo.org/show_bug.cgi?id=482666
--
Best regards,
Michał Górny
[Attachment #5 (text/x-patch)]
diff --git a/gx86/eclass/git-r3.eclass b/gx86/eclass/git-r3.eclass
index d56c818..84c04c7 100644
--- a/gx86/eclass/git-r3.eclass
+++ b/gx86/eclass/git-r3.eclass
@@ -71,6 +71,12 @@ if [[ ! ${_GIT_R3} ]]; then
#
# It can be overriden via env using ${PN}_LIVE_COMMIT variable.
+# @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR
+# @DESCRIPTION:
+# The directory to check the git sources out to.
+#
+# EGIT_CHECKOUT_DIR=${WORKDIR}/${P}
+
# @ECLASS-VARIABLE: EGIT_NONSHALLOW
# @DEFAULT_UNSET
# @DESCRIPTION:
@@ -94,8 +100,6 @@ _git-r3_env_setup() {
livevar=${esc_pn}_LIVE_REPO
EGIT_REPO_URI=${!livevar:-${EGIT_REPO_URI}}
- [[ ${EGIT_REPO_URI} ]] \
- || die "EGIT_REPO_URI must be set to a non-empty value"
[[ ${!livevar} ]] \
&& ewarn "Using ${livevar}, no support will be provided"
@@ -209,26 +213,44 @@ _git-r3_set_submodules() {
}
# @FUNCTION: git-r3_fetch
-# @USAGE: <repo-uri> <remote-ref> <local-id>
+# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]]
# @DESCRIPTION:
-# Fetch new commits to the local clone of repository. <repo-uri> follows
-# the syntax of EGIT_REPO_URI and may list multiple (fallback) URIs.
-# <remote-ref> specifies the remote ref to fetch (branch, tag
-# or commit). <local-id> specifies an identifier that needs to uniquely
-# identify the fetch operation in case multiple parallel merges used
-# the git repo. <local-id> usually involves using CATEGORY, PN and SLOT.
+# Fetch new commits to the local clone of repository.
+#
+# <repo-uri> specifies the repository URIs to fetch from, as a space-
+# -separated list. The first URI will be used as repository group
+# identifier and therefore must be used consistently. When not
+# specified, defaults to ${EGIT_REPO_URI}.
#
-# The fetch operation will only affect the local storage. It will not
-# touch the working copy. If the repository contains submodules, they
-# will be fetched recursively as well.
+# <remote-ref> specifies the remote ref or commit id to fetch.
+# It is preferred to use 'refs/heads/<branch-name>' for branches
+# and 'refs/tags/<tag-name>' for tags. Other options are 'HEAD'
+# for upstream default branch and hexadecimal commit SHA1. Defaults
+# to the first of EGIT_COMMIT, EGIT_BRANCH or literal 'HEAD' that
+# is set to a non-null value.
+#
+# <local-id> specifies the local branch identifier that will be used to
+# locally store the fetch result. It should be unique to multiple
+# fetches within the repository that can be performed at the same time
+# (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT}.
+# This default should be fine unless you are fetching multiple trees
+# from the same repository in the same ebuild.
+#
+# The fetch operation will affect the EGIT_STORE only. It will not touch
+# the working copy, nor export any environment variables.
+# If the repository contains submodules, they will be fetched
+# recursively.
git-r3_fetch() {
debug-print-function ${FUNCNAME} "$@"
- local repos=( ${1} )
- local remote_ref=${2}
- local local_id=${3}
+ local repos=( ${1:-${EGIT_REPO_URI}} )
+ local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
+ local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
+ local local_id=${3:-${CATEGORY}/${PN}/${SLOT}}
local local_ref=refs/heads/${local_id}/__main__
+ [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
+
local -x GIT_DIR
_git-r3_set_gitdir ${repos[0]}
@@ -282,7 +304,7 @@ git-r3_fetch() {
if [[ ${is_branch} ]]; then
ref_param+=( -f "${remote_ref}:${local_id}/__main__" )
else
- ref_param+=( "${remote_ref}" )
+ ref_param+=( "refs/tags/${remote_ref}" )
fi
fi
@@ -331,22 +353,31 @@ git-r3_fetch() {
}
# @FUNCTION: git-r3_checkout
-# @USAGE: <repo-uri> <local-id> <path>
+# @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
# @DESCRIPTION:
-# Check the previously fetched commit out to <path> (usually
-# ${WORKDIR}/${P}). <repo-uri> follows the syntax of EGIT_REPO_URI
-# and will be used to re-construct the local storage path. <local-id>
-# is the unique identifier used for the fetch operation and will
-# be used to obtain the proper commit.
+# Check the previously fetched tree to the working copy.
+#
+# <repo-uri> specifies the repository URIs, as a space-separated list.
+# The first URI will be used as repository group identifier
+# and therefore must be used consistently with git-r3_fetch.
+# The remaining URIs are not used and therefore may be omitted.
+# When not specified, defaults to ${EGIT_REPO_URI}.
+#
+# <checkout-path> specifies the path to place the checkout. It defaults
+# to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
#
-# If the repository contains submodules, they will be checked out
-# recursively as well.
+# <local-id> needs to specify the local identifier that was used
+# for respective git-r3_fetch.
+#
+# The checkout operation will write to the working copy, and export
+# the repository state into the environment. If the repository contains
+# submodules, they will be checked out recursively.
git-r3_checkout() {
debug-print-function ${FUNCNAME} "$@"
- local repos=( ${1} )
- local local_id=${2}
- local out_dir=${3}
+ local repos=( ${1:-${EGIT_REPO_URI}} )
+ local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
+ local local_id=${3:-${CATEGORY}/${PN}/${SLOT}}
local -x GIT_DIR GIT_WORK_TREE
_git-r3_set_gitdir ${repos[0]}
@@ -396,8 +427,8 @@ git-r3_checkout() {
local url=${submodules[1]}
local path=${submodules[2]}
- git-r3_checkout "${url}" "${local_id}/${subname}" \
- "${GIT_WORK_TREE}/${path}"
+ git-r3_checkout "${url}" "${GIT_WORK_TREE}/${path}" \
+ "${local_id}/${subname}"
submodules=( "${submodules[@]:3}" ) # shift
done
@@ -408,16 +439,72 @@ git-r3_checkout() {
export EGIT_VERSION=${new_commit_id}
}
+# @FUNCTION: git-r3_peek_remote_ref
+# @USAGE: [<repo-uri> [<remote-ref>]]
+# @DESCRIPTION:
+# Peek the reference in the remote repository and print the matching
+# (newest) commit SHA1.
+#
+# <repo-uri> specifies the repository URIs to fetch from, as a space-
+# -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
+#
+# <remote-ref> specifies the remote ref to peek. It is preferred to use
+# 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
+# for tags. Alternatively, 'HEAD' may be used for upstream default
+# branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
+# 'HEAD' that is set to a non-null value.
+#
+# The operation will be done purely on the remote, without using local
+# storage. If commit SHA1 is provided as <remote-ref>, the function will
+# fail due to limitations of git protocol.
+#
+# On success, the function returns 0 and writes hexadecimal commit SHA1
+# to stdout. On failure, the function returns 1.
+git-r3_peek_remote_ref() {
+ debug-print-function ${FUNCNAME} "$@"
+
+ local repos=( ${1:-${EGIT_REPO_URI}} )
+ local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
+ local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
+
+ [[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
+
+ local r success
+ for r in ${repos[@]}; do
+ einfo "Peeking ${remote_ref} on ${r} ..." >&2
+
+ local is_branch lookup_ref
+ if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
+ then
+ is_branch=1
+ lookup_ref=${remote_ref}
+ else
+ # ls-remote by commit is going to fail anyway,
+ # so we may as well pass refs/tags/ABCDEF...
+ lookup_ref=refs/tags/${remote_ref}
+ fi
+
+ # split on whitespace
+ local ref=(
+ $(git ls-remote "${r}" "${lookup_ref}")
+ )
+
+ if [[ ${ref[0]} ]]; then
+ echo "${ref[0]}"
+ return 0
+ fi
+ done
+
+ return 1
+}
+
git-r3_src_fetch() {
debug-print-function ${FUNCNAME} "$@"
[[ ${EVCS_OFFLINE} ]] && return
_git-r3_env_setup
- local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
- git-r3_fetch "${EGIT_REPO_URI}" \
- "${EGIT_COMMIT:-${branch:-HEAD}}" \
- ${CATEGORY}/${PN}/${SLOT}
+ git-r3_fetch
}
git-r3_src_unpack() {
@@ -425,9 +512,16 @@ git-r3_src_unpack() {
_git-r3_env_setup
git-r3_src_fetch
- git-r3_checkout "${EGIT_REPO_URI}" \
- ${CATEGORY}/${PN}/${SLOT} \
- "${WORKDIR}/${P}"
+ git-r3_checkout
+}
+
+git-r3_pkg_isuptodate() {
+ debug-print-function ${FUNCNAME} "$@"
+
+ local new_commit_id=$(git-r3_peek_remote_ref)
+ ewarn "old: ${EGIT_VERSION}"
+ ewarn "new: ${new_commit_id}"
+ [[ ! ${new_commit_id} || ${EGIT_VERSION} == ${new_commit_id} ]]
}
_GIT_R3=1
[Attachment #6 (text/plain)]
# Copyright 1999-2013 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $
# @ECLASS: git-r3.eclass
# @MAINTAINER:
# Michał Górny <mgorny@gentoo.org>
# @BLURB: Eclass for fetching and unpacking git repositories.
# @DESCRIPTION:
# Third generation eclass for easing maitenance of live ebuilds using
# git as remote repository. Eclass supports lightweight (shallow)
# clones, local object deduplication and submodules.
case "${EAPI:-0}" in
0|1|2|3|4|5)
;;
*)
die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
;;
esac
if [[ ! ${_GIT_R3} ]]; then
inherit eutils
fi
EXPORT_FUNCTIONS src_unpack
if [[ ! ${_GIT_R3} ]]; then
# @ECLASS-VARIABLE: EGIT_STORE_DIR
# @DESCRIPTION:
# Storage directory for git sources.
#
# EGIT_STORE_DIR=${DISTDIR}/git3-src
# @ECLASS-VARIABLE: EGIT_REPO_URI
# @REQUIRED
# @DESCRIPTION:
# URIs to the repository, e.g. git://foo, https://foo. If multiple URIs
# are provided, the eclass will consider them as fallback URIs to try
# if the first URI does not work.
#
# It can be overriden via env using ${PN}_LIVE_REPO variable.
#
# Example:
# @CODE
# EGIT_REPO_URI="git://a/b.git https://c/d.git"
# @CODE
# @ECLASS-VARIABLE: EVCS_OFFLINE
# @DEFAULT_UNSET
# @DESCRIPTION:
# If non-empty, this variable prevents any online operations.
# @ECLASS-VARIABLE: EGIT_BRANCH
# @DEFAULT_UNSET
# @DESCRIPTION:
# The branch name to check out. If unset, the upstream default (HEAD)
# will be used.
#
# It can be overriden via env using ${PN}_LIVE_BRANCH variable.
# @ECLASS-VARIABLE: EGIT_COMMIT
# @DEFAULT_UNSET
# @DESCRIPTION:
# The tag name or commit identifier to check out. If unset, newest
# commit from the branch will be used. If set, EGIT_BRANCH will
# be ignored.
#
# It can be overriden via env using ${PN}_LIVE_COMMIT variable.
# @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR
# @DESCRIPTION:
# The directory to check the git sources out to.
#
# EGIT_CHECKOUT_DIR=${WORKDIR}/${P}
# @ECLASS-VARIABLE: EGIT_NONSHALLOW
# @DEFAULT_UNSET
# @DESCRIPTION:
# Disable performing shallow fetches/clones. Shallow clones have
# a fair number of limitations. Therefore, if you'd like the eclass to
# perform complete clones instead, set this to a non-null value.
#
# This variable is to be set in make.conf. Ebuilds are not allowed
# to set it.
# @FUNCTION: _git-r3_env_setup
# @INTERNAL
# @DESCRIPTION:
# Set the eclass variables as necessary for operation. This can involve
# setting EGIT_* to defaults or ${PN}_LIVE_* variables.
_git-r3_env_setup() {
debug-print-function ${FUNCNAME} "$@"
local esc_pn livevar
esc_pn=${PN//[-+]/_}
livevar=${esc_pn}_LIVE_REPO
EGIT_REPO_URI=${!livevar:-${EGIT_REPO_URI}}
[[ ${!livevar} ]] \
&& ewarn "Using ${livevar}, no support will be provided"
livevar=${esc_pn}_LIVE_BRANCH
EGIT_BRANCH=${!livevar:-${EGIT_BRANCH}}
[[ ${!livevar} ]] \
&& ewarn "Using ${livevar}, no support will be provided"
livevar=${esc_pn}_LIVE_COMMIT
EGIT_COMMIT=${!livevar:-${EGIT_COMMIT}}
[[ ${!livevar} ]] \
&& ewarn "Using ${livevar}, no support will be provided"
# git-2 unsupported cruft
local v
for v in EGIT_{SOURCEDIR,MASTER,HAS_SUBMODULES,PROJECT} \
EGIT_{NOUNPACK,BOOTSTRAP}
do
[[ ${!v} ]] && die "${v} is not supported."
done
}
# @FUNCTION: _git-r3_set_gitdir
# @USAGE: <repo-uri>
# @INTERNAL
# @DESCRIPTION:
# Obtain the local repository path and set it as GIT_DIR. Creates
# a new repository if necessary.
#
# <repo-uri> may be used to compose the path. It should therefore be
# a canonical URI to the repository.
_git-r3_set_gitdir() {
debug-print-function ${FUNCNAME} "$@"
local repo_name=${1#*://*/}
# strip common prefixes to make paths more likely to match
# e.g. git://X/Y.git vs https://X/git/Y.git
# (but just one of the prefixes)
case "${repo_name}" in
# cgit can proxy requests to git
cgit/*) repo_name=${repo_name#cgit/};;
# pretty common
git/*) repo_name=${repo_name#git/};;
# gentoo.org
gitroot/*) repo_name=${repo_name#gitroot/};;
# google code, sourceforge
p/*) repo_name=${repo_name#p/};;
# kernel.org
pub/scm/*) repo_name=${repo_name#pub/scm/};;
esac
# ensure a .git suffix, same reason
repo_name=${repo_name%.git}.git
# now replace all the slashes
repo_name=${repo_name//\//_}
local distdir=${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}}
: ${EGIT_STORE_DIR:=${distdir}/git3-src}
GIT_DIR=${EGIT_STORE_DIR}/${repo_name}
if [[ ! -d ${EGIT_STORE_DIR} ]]; then
(
addwrite /
mkdir -m0755 -p "${EGIT_STORE_DIR}"
) || die "Unable to create ${EGIT_STORE_DIR}"
fi
addwrite "${EGIT_STORE_DIR}"
if [[ ! -d ${GIT_DIR} ]]; then
mkdir "${GIT_DIR}" || die
git init --bare || die
# avoid auto-unshallow :)
touch "${GIT_DIR}"/shallow || die
fi
}
# @FUNCTION: _git-r3_set_submodules
# @USAGE: <file-contents>
# @INTERNAL
# @DESCRIPTION:
# Parse .gitmodules contents passed as <file-contents>
# as in "$(cat .gitmodules)"). Composes a 'submodules' array that
# contains in order (name, URL, path) for each submodule.
_git-r3_set_submodules() {
debug-print-function ${FUNCNAME} "$@"
local data=${1}
# ( name url path ... )
submodules=()
local l
while read l; do
# submodule.<path>.path=<path>
# submodule.<path>.url=<url>
[[ ${l} == submodule.*.url=* ]] || continue
l=${l#submodule.}
local subname=${l%%.url=*}
submodules+=(
"${subname}"
"$(echo "${data}" | git config -f /dev/fd/0 \
submodule."${subname}".url)"
"$(echo "${data}" | git config -f /dev/fd/0 \
submodule."${subname}".path)"
)
done < <(echo "${data}" | git config -f /dev/fd/0 -l)
}
# @FUNCTION: git-r3_fetch
# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]]
# @DESCRIPTION:
# Fetch new commits to the local clone of repository.
#
# <repo-uri> specifies the repository URIs to fetch from, as a space-
# -separated list. The first URI will be used as repository group
# identifier and therefore must be used consistently. When not
# specified, defaults to ${EGIT_REPO_URI}.
#
# <remote-ref> specifies the remote ref or commit id to fetch.
# It is preferred to use 'refs/heads/<branch-name>' for branches
# and 'refs/tags/<tag-name>' for tags. Other options are 'HEAD'
# for upstream default branch and hexadecimal commit SHA1. Defaults
# to the first of EGIT_COMMIT, EGIT_BRANCH or literal 'HEAD' that
# is set to a non-null value.
#
# <local-id> specifies the local branch identifier that will be used to
# locally store the fetch result. It should be unique to multiple
# fetches within the repository that can be performed at the same time
# (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT}.
# This default should be fine unless you are fetching multiple trees
# from the same repository in the same ebuild.
#
# The fetch operation will affect the EGIT_STORE only. It will not touch
# the working copy, nor export any environment variables.
# If the repository contains submodules, they will be fetched
# recursively.
git-r3_fetch() {
debug-print-function ${FUNCNAME} "$@"
local repos=( ${1:-${EGIT_REPO_URI}} )
local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
local local_id=${3:-${CATEGORY}/${PN}/${SLOT}}
local local_ref=refs/heads/${local_id}/__main__
[[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
local -x GIT_DIR
_git-r3_set_gitdir ${repos[0]}
# try to fetch from the remote
local r success
for r in ${repos[@]}; do
einfo "Fetching ${remote_ref} from ${r} ..."
local is_branch lookup_ref
if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
then
is_branch=1
lookup_ref=${remote_ref}
else
# ls-remote by commit is going to fail anyway,
# so we may as well pass refs/tags/ABCDEF...
lookup_ref=refs/tags/${remote_ref}
fi
# first, try ls-remote to see if ${remote_ref} is a real ref
# and not a commit id. if it succeeds, we can pass ${remote_ref}
# to 'fetch'. otherwise, we will just fetch everything
# split on whitespace
local ref=(
$(git ls-remote "${r}" "${lookup_ref}")
)
# now, another important thing. we may only fetch a remote
# branch directly to a local branch. Otherwise, we need to fetch
# the commit and re-create the branch on top of it.
local ref_param=()
if [[ ! ${ref[0]} ]]; then
local EGIT_NONSHALLOW=1
fi
if [[ ! -f ${GIT_DIR}/shallow ]]; then
# if it's a complete repo, fetch it as-is
:
elif [[ ${EGIT_NONSHALLOW} ]]; then
# if it's a shallow clone but we need complete,
# unshallow it
ref_param+=( --unshallow )
else
# otherwise, just fetch as shallow
ref_param+=( --depth 1 )
fi
if [[ ${ref[0]} ]]; then
if [[ ${is_branch} ]]; then
ref_param+=( -f "${remote_ref}:${local_id}/__main__" )
else
ref_param+=( "refs/tags/${remote_ref}" )
fi
fi
# if ${remote_ref} is branch or tag, ${ref[@]} will contain
# the respective commit id. otherwise, it will be an empty
# array, so the following won't evaluate to a parameter.
set -- git fetch --no-tags "${r}" "${ref_param[@]}"
echo "${@}" >&2
if "${@}"; then
if [[ ! ${is_branch} ]]; then
set -- git branch -f "${local_id}/__main__" \
"${ref[0]:-${remote_ref}}"
echo "${@}" >&2
if ! "${@}"; then
die "Creating branch for ${remote_ref} failed (wrong ref?)."
fi
fi
success=1
break
fi
done
[[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
# recursively fetch submodules
if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
local submodules
_git-r3_set_submodules \
"$(git cat-file -p "${local_ref}":.gitmodules || die)"
while [[ ${submodules[@]} ]]; do
local subname=${submodules[0]}
local url=${submodules[1]}
local path=${submodules[2]}
local commit=$(git rev-parse "${local_ref}:${path}")
if [[ ! ${commit} ]]; then
die "Unable to get commit id for submodule ${subname}"
fi
git-r3_fetch "${url}" "${commit}" "${local_id}/${subname}"
submodules=( "${submodules[@]:3}" ) # shift
done
fi
}
# @FUNCTION: git-r3_checkout
# @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
# @DESCRIPTION:
# Check the previously fetched tree to the working copy.
#
# <repo-uri> specifies the repository URIs, as a space-separated list.
# The first URI will be used as repository group identifier
# and therefore must be used consistently with git-r3_fetch.
# The remaining URIs are not used and therefore may be omitted.
# When not specified, defaults to ${EGIT_REPO_URI}.
#
# <checkout-path> specifies the path to place the checkout. It defaults
# to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
#
# <local-id> needs to specify the local identifier that was used
# for respective git-r3_fetch.
#
# The checkout operation will write to the working copy, and export
# the repository state into the environment. If the repository contains
# submodules, they will be checked out recursively.
git-r3_checkout() {
debug-print-function ${FUNCNAME} "$@"
local repos=( ${1:-${EGIT_REPO_URI}} )
local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
local local_id=${3:-${CATEGORY}/${PN}/${SLOT}}
local -x GIT_DIR GIT_WORK_TREE
_git-r3_set_gitdir ${repos[0]}
GIT_WORK_TREE=${out_dir}
einfo "Checking out ${repos[0]} to ${out_dir} ..."
mkdir -p "${GIT_WORK_TREE}"
set -- git checkout -f "${local_id}"/__main__ .
echo "${@}" >&2
"${@}" || die "git checkout ${local_id}/__main__ failed"
# diff against previous revision (if any)
local new_commit_id=$(git rev-parse --verify "${local_id}"/__main__)
local old_commit_id=$(
git rev-parse --verify "${local_id}"/__old__ 2>/dev/null
)
if [[ ! ${old_commit_id} ]]; then
echo "GIT NEW branch -->"
echo " repository: ${repos[0]}"
echo " at the commit: ${new_commit_id}"
else
echo "GIT update -->"
echo " repository: ${repos[0]}"
# write out message based on the revisions
if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
echo " updating from commit: ${old_commit_id}"
echo " to commit: ${new_commit_id}"
git --no-pager diff --color --stat \
${old_commit_id}..${new_commit_id}
else
echo " at the commit: ${new_commit_id}"
fi
fi
git branch -f "${local_id}"/{__old__,__main__} || die
# recursively checkout submodules
if [[ -f ${GIT_WORK_TREE}/.gitmodules ]]; then
local submodules
_git-r3_set_submodules \
"$(cat "${GIT_WORK_TREE}"/.gitmodules)"
while [[ ${submodules[@]} ]]; do
local subname=${submodules[0]}
local url=${submodules[1]}
local path=${submodules[2]}
git-r3_checkout "${url}" "${GIT_WORK_TREE}/${path}" \
"${local_id}/${subname}"
submodules=( "${submodules[@]:3}" ) # shift
done
fi
# keep this *after* submodules
export EGIT_DIR=${GIT_DIR}
export EGIT_VERSION=${new_commit_id}
}
# @FUNCTION: git-r3_peek_remote_ref
# @USAGE: [<repo-uri> [<remote-ref>]]
# @DESCRIPTION:
# Peek the reference in the remote repository and print the matching
# (newest) commit SHA1.
#
# <repo-uri> specifies the repository URIs to fetch from, as a space-
# -separated list. When not specified, defaults to ${EGIT_REPO_URI}.
#
# <remote-ref> specifies the remote ref to peek. It is preferred to use
# 'refs/heads/<branch-name>' for branches and 'refs/tags/<tag-name>'
# for tags. Alternatively, 'HEAD' may be used for upstream default
# branch. Defaults to the first of EGIT_COMMIT, EGIT_BRANCH or literal
# 'HEAD' that is set to a non-null value.
#
# The operation will be done purely on the remote, without using local
# storage. If commit SHA1 is provided as <remote-ref>, the function will
# fail due to limitations of git protocol.
#
# On success, the function returns 0 and writes hexadecimal commit SHA1
# to stdout. On failure, the function returns 1.
git-r3_peek_remote_ref() {
debug-print-function ${FUNCNAME} "$@"
local repos=( ${1:-${EGIT_REPO_URI}} )
local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
[[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
local r success
for r in ${repos[@]}; do
einfo "Peeking ${remote_ref} on ${r} ..." >&2
local is_branch lookup_ref
if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
then
is_branch=1
lookup_ref=${remote_ref}
else
# ls-remote by commit is going to fail anyway,
# so we may as well pass refs/tags/ABCDEF...
lookup_ref=refs/tags/${remote_ref}
fi
# split on whitespace
local ref=(
$(git ls-remote "${r}" "${lookup_ref}")
)
if [[ ${ref[0]} ]]; then
echo "${ref[0]}"
return 0
fi
done
return 1
}
git-r3_src_fetch() {
debug-print-function ${FUNCNAME} "$@"
[[ ${EVCS_OFFLINE} ]] && return
_git-r3_env_setup
git-r3_fetch
}
git-r3_src_unpack() {
debug-print-function ${FUNCNAME} "$@"
_git-r3_env_setup
git-r3_src_fetch
git-r3_checkout
}
git-r3_pkg_isuptodate() {
debug-print-function ${FUNCNAME} "$@"
local new_commit_id=$(git-r3_peek_remote_ref)
ewarn "old: ${EGIT_VERSION}"
ewarn "new: ${new_commit_id}"
[[ ! ${new_commit_id} || ${EGIT_VERSION} == ${new_commit_id} ]]
}
_GIT_R3=1
fi
[Attachment #7 (text/plain)]
# Copyright 1999-2013 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $
# @ECLASS: git-r3.eclass
# @MAINTAINER:
# Michał Górny <mgorny@gentoo.org>
# @BLURB: Eclass for fetching and unpacking git repositories.
# @DESCRIPTION:
# Third generation eclass for easing maitenance of live ebuilds using
# git as remote repository. Eclass supports lightweight (shallow)
# clones, local object deduplication and submodules.
case "${EAPI:-0}" in
0|1|2|3|4|5)
;;
*)
die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
;;
esac
if [[ ! ${_GIT_R3} ]]; then
inherit eutils
fi
EXPORT_FUNCTIONS src_unpack
if [[ ! ${_GIT_R3} ]]; then
# @ECLASS-VARIABLE: EGIT_STORE_DIR
# @DESCRIPTION:
# Storage directory for git sources.
#
# EGIT_STORE_DIR=${DISTDIR}/git3-src
# @ECLASS-VARIABLE: EGIT_REPO_URI
# @REQUIRED
# @DESCRIPTION:
# URIs to the repository, e.g. git://foo, https://foo. If multiple URIs
# are provided, the eclass will consider them as fallback URIs to try
# if the first URI does not work.
#
# It can be overriden via env using ${PN}_LIVE_REPO variable.
#
# Example:
# @CODE
# EGIT_REPO_URI="git://a/b.git https://c/d.git"
# @CODE
# @ECLASS-VARIABLE: EVCS_OFFLINE
# @DEFAULT_UNSET
# @DESCRIPTION:
# If non-empty, this variable prevents any online operations.
# @ECLASS-VARIABLE: EGIT_BRANCH
# @DEFAULT_UNSET
# @DESCRIPTION:
# The branch name to check out. If unset, the upstream default (HEAD)
# will be used.
#
# It can be overriden via env using ${PN}_LIVE_BRANCH variable.
# @ECLASS-VARIABLE: EGIT_COMMIT
# @DEFAULT_UNSET
# @DESCRIPTION:
# The tag name or commit identifier to check out. If unset, newest
# commit from the branch will be used. If set, EGIT_BRANCH will
# be ignored.
#
# It can be overriden via env using ${PN}_LIVE_COMMIT variable.
# @ECLASS-VARIABLE: EGIT_CHECKOUT_DIR
# @DESCRIPTION:
# The directory to check the git sources out to.
#
# EGIT_CHECKOUT_DIR=${WORKDIR}/${P}
# @ECLASS-VARIABLE: EGIT_NONSHALLOW
# @DEFAULT_UNSET
# @DESCRIPTION:
# Disable performing shallow fetches/clones. Shallow clones have
# a fair number of limitations. Therefore, if you'd like the eclass to
# perform complete clones instead, set this to a non-null value.
#
# This variable is to be set in make.conf. Ebuilds are not allowed
# to set it.
# @FUNCTION: _git-r3_env_setup
# @INTERNAL
# @DESCRIPTION:
# Set the eclass variables as necessary for operation. This can involve
# setting EGIT_* to defaults or ${PN}_LIVE_* variables.
_git-r3_env_setup() {
debug-print-function ${FUNCNAME} "$@"
local esc_pn livevar
esc_pn=${PN//[-+]/_}
livevar=${esc_pn}_LIVE_REPO
EGIT_REPO_URI=${!livevar:-${EGIT_REPO_URI}}
[[ ${!livevar} ]] \
&& ewarn "Using ${livevar}, no support will be provided"
livevar=${esc_pn}_LIVE_BRANCH
EGIT_BRANCH=${!livevar:-${EGIT_BRANCH}}
[[ ${!livevar} ]] \
&& ewarn "Using ${livevar}, no support will be provided"
livevar=${esc_pn}_LIVE_COMMIT
EGIT_COMMIT=${!livevar:-${EGIT_COMMIT}}
[[ ${!livevar} ]] \
&& ewarn "Using ${livevar}, no support will be provided"
# git-2 compat
: ${EGIT_BRANCH:=${EGIT_MASTER}}
: ${EGIT_CHECKOUT_DIR:=${EGIT_SOURCEDIR}}
[[ ${EGIT_BOOTSTRAP} ]] && die "EGIT_BOOTSTRAP not supported."
}
# @FUNCTION: _git-r3_set_gitdir
# @USAGE: <repo-uri>
# @INTERNAL
# @DESCRIPTION:
# Obtain the local repository path and set it as GIT_DIR. Creates
# a new repository if necessary.
#
# <repo-uri> may be used to compose the path. It should therefore be
# a canonical URI to the repository.
_git-r3_set_gitdir() {
debug-print-function ${FUNCNAME} "$@"
local repo_name=${1#*://*/}
# strip common prefixes to make paths more likely to match
# e.g. git://X/Y.git vs https://X/git/Y.git
# (but just one of the prefixes)
case "${repo_name}" in
# cgit can proxy requests to git
cgit/*) repo_name=${repo_name#cgit/};;
# pretty common
git/*) repo_name=${repo_name#git/};;
# gentoo.org
gitroot/*) repo_name=${repo_name#gitroot/};;
# google code, sourceforge
p/*) repo_name=${repo_name#p/};;
# kernel.org
pub/scm/*) repo_name=${repo_name#pub/scm/};;
esac
# ensure a .git suffix, same reason
repo_name=${repo_name%.git}.git
# now replace all the slashes
repo_name=${repo_name//\//_}
local distdir=${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}}
: ${EGIT_STORE_DIR:=${distdir}/git3-src}
GIT_DIR=${EGIT_STORE_DIR}/${repo_name}
if [[ ! -d ${EGIT_STORE_DIR} ]]; then
(
addwrite /
mkdir -m0755 -p "${EGIT_STORE_DIR}"
) || die "Unable to create ${EGIT_STORE_DIR}"
fi
addwrite "${EGIT_STORE_DIR}"
if [[ ! -d ${GIT_DIR} ]]; then
mkdir "${GIT_DIR}" || die
git init --bare || die
# avoid auto-unshallow :)
touch "${GIT_DIR}"/shallow || die
fi
}
# @FUNCTION: _git-r3_set_submodules
# @USAGE: <file-contents>
# @INTERNAL
# @DESCRIPTION:
# Parse .gitmodules contents passed as <file-contents>
# as in "$(cat .gitmodules)"). Composes a 'submodules' array that
# contains in order (name, URL, path) for each submodule.
_git-r3_set_submodules() {
debug-print-function ${FUNCNAME} "$@"
local data=${1}
# ( name url path ... )
submodules=()
local l
while read l; do
# submodule.<path>.path=<path>
# submodule.<path>.url=<url>
[[ ${l} == submodule.*.url=* ]] || continue
l=${l#submodule.}
local subname=${l%%.url=*}
submodules+=(
"${subname}"
"$(echo "${data}" | git config -f /dev/fd/0 \
submodule."${subname}".url)"
"$(echo "${data}" | git config -f /dev/fd/0 \
submodule."${subname}".path)"
)
done < <(echo "${data}" | git config -f /dev/fd/0 -l)
}
# @FUNCTION: git-r3_fetch
# @USAGE: [<repo-uri> [<remote-ref> [<local-id>]]]
# @DESCRIPTION:
# Fetch new commits to the local clone of repository.
#
# <repo-uri> specifies the repository URIs to fetch from, as a space-
# -separated list. The first URI will be used as repository group
# identifier and therefore must be used consistently. When not
# specified, defaults to ${EGIT_REPO_URI}.
#
# <remote-ref> specifies the remote ref or commit id to fetch.
# It is preferred to use 'refs/heads/<branch-name>' for branches
# and 'refs/tags/<tag-name>' for tags. Other options are 'HEAD'
# for upstream default branch and hexadecimal commit SHA1. Defaults
# to the first of EGIT_COMMIT, EGIT_BRANCH or literal 'HEAD' that
# is set to a non-null value.
#
# <local-id> specifies the local branch identifier that will be used to
# locally store the fetch result. It should be unique to multiple
# fetches within the repository that can be performed at the same time
# (including parallel merges). It defaults to ${CATEGORY}/${PN}/${SLOT}.
# This default should be fine unless you are fetching multiple trees
# from the same repository in the same ebuild.
#
# The fetch operation will affect the EGIT_STORE only. It will not touch
# the working copy, nor export any environment variables.
# If the repository contains submodules, they will be fetched
# recursively.
git-r3_fetch() {
debug-print-function ${FUNCNAME} "$@"
local repos=( ${1:-${EGIT_REPO_URI}} )
local branch=${EGIT_BRANCH:+refs/heads/${EGIT_BRANCH}}
local remote_ref=${2:-${EGIT_COMMIT:-${branch:-HEAD}}}
local local_id=${3:-${CATEGORY}/${PN}/${SLOT}}
local local_ref=refs/heads/${local_id}/__main__
[[ ${repos[@]} ]] || die "No URI provided and EGIT_REPO_URI unset"
local -x GIT_DIR
_git-r3_set_gitdir ${repos[0]}
# try to fetch from the remote
local r success
for r in ${repos[@]}; do
einfo "Fetching ${remote_ref} from ${r} ..."
local is_branch lookup_ref
if [[ ${remote_ref} == refs/heads/* || ${remote_ref} == HEAD ]]
then
is_branch=1
lookup_ref=${remote_ref}
else
# ls-remote by commit is going to fail anyway,
# so we may as well pass refs/tags/ABCDEF...
lookup_ref=refs/tags/${remote_ref}
fi
# first, try ls-remote to see if ${remote_ref} is a real ref
# and not a commit id. if it succeeds, we can pass ${remote_ref}
# to 'fetch'. otherwise, we will just fetch everything
# split on whitespace
local ref=(
$(git ls-remote "${r}" "${lookup_ref}")
)
# now, another important thing. we may only fetch a remote
# branch directly to a local branch. Otherwise, we need to fetch
# the commit and re-create the branch on top of it.
local ref_param=()
if [[ ! ${ref[0]} ]]; then
local EGIT_NONSHALLOW=1
fi
if [[ ! -f ${GIT_DIR}/shallow ]]; then
# if it's a complete repo, fetch it as-is
:
elif [[ ${EGIT_NONSHALLOW} ]]; then
# if it's a shallow clone but we need complete,
# unshallow it
ref_param+=( --unshallow )
else
# otherwise, just fetch as shallow
ref_param+=( --depth 1 )
fi
if [[ ${ref[0]} ]]; then
if [[ ${is_branch} ]]; then
ref_param+=( -f "${remote_ref}:${local_id}/__main__" )
else
ref_param+=( "refs/tags/${remote_ref}" )
fi
fi
# if ${remote_ref} is branch or tag, ${ref[@]} will contain
# the respective commit id. otherwise, it will be an empty
# array, so the following won't evaluate to a parameter.
set -- git fetch --no-tags "${r}" "${ref_param[@]}"
echo "${@}" >&2
if "${@}"; then
if [[ ! ${is_branch} ]]; then
set -- git branch -f "${local_id}/__main__" \
"${ref[0]:-${remote_ref}}"
echo "${@}" >&2
if ! "${@}"; then
die "Creating branch for ${remote_ref} failed (wrong ref?)."
fi
fi
success=1
break
fi
done
[[ ${success} ]] || die "Unable to fetch from any of EGIT_REPO_URI"
# recursively fetch submodules
if git cat-file -e "${local_ref}":.gitmodules &>/dev/null; then
local submodules
_git-r3_set_submodules \
"$(git cat-file -p "${local_ref}":.gitmodules || die)"
while [[ ${submodules[@]} ]]; do
local subname=${submodules[0]}
local url=${submodules[1]}
local path=${submodules[2]}
local commit=$(git rev-parse "${local_ref}:${path}")
if [[ ! ${commit} ]]; then
die "Unable to get commit id for submodule ${subname}"
fi
git-r3_fetch "${url}" "${commit}" "${local_id}/${subname}"
submodules=( "${submodules[@]:3}" ) # shift
done
fi
}
# @FUNCTION: git-r3_checkout
# @USAGE: [<repo-uri> [<checkout-path> [<local-id>]]]
# @DESCRIPTION:
# Check the previously fetched tree to the working copy.
#
# <repo-uri> specifies the repository URIs, as a space-separated list.
# The first URI will be used as repository group identifier
# and therefore must be used consistently with git-r3_fetch.
# The remaining URIs are not used and therefore may be omitted.
# When not specified, defaults to ${EGIT_REPO_URI}.
#
# <checkout-path> specifies the path to place the checkout. It defaults
# to ${EGIT_CHECKOUT_DIR} if set, otherwise to ${WORKDIR}/${P}.
#
# <local-id> needs to specify the local identifier that was used
# for respective git-r3_fetch.
#
# The checkout operation will write to the working copy, and export
# the repository state into the environment. If the repository contains
# submodules, they will be checked out recursively.
git-r3_checkout() {
debug-print-function ${FUNCNAME} "$@"
local repos=( ${1:-${EGIT_REPO_URI}} )
local out_dir=${2:-${EGIT_CHECKOUT_DIR:-${WORKDIR}/${P}}}
local local_id=${3:-${CATEGORY}/${PN}/${SLOT}}
local -x GIT_DIR GIT_WORK_TREE
_git-r3_set_gitdir ${repos[0]}
GIT_WORK_TREE=${out_dir}
einfo "Checking out ${repos[0]} to ${out_dir} ..."
mkdir -p "${GIT_WORK_TREE}"
set -- git checkout -f "${local_id}"/__main__ .
echo "${@}" >&2
"${@}" || die "git checkout ${local_id}/__main__ failed"
# diff against previous revision (if any)
local new_commit_id=$(git rev-parse --verify "${local_id}"/__main__)
local old_commit_id=$(
git rev-parse --verify "${local_id}"/__old__ 2>/dev/null
)
if [[ ! ${old_commit_id} ]]; then
echo "GIT NEW branch -->"
echo " repository: ${repos[0]}"
echo " at the commit: ${new_commit_id}"
else
echo "GIT update -->"
echo " repository: ${repos[0]}"
# write out message based on the revisions
if [[ "${old_commit_id}" != "${new_commit_id}" ]]; then
echo " updating from commit: ${old_commit_id}"
echo " to commit: ${new_commit_id}"
git --no-pager diff --color --stat \
${old_commit_id}..${new_commit_id}
else
echo " at the commit: ${new_commit_id}"
fi
fi
git branch -f "${local_id}"/{__old__,__main__} || die
# recursively checkout submodules
if [[ -f ${GIT_WORK_TREE}/.gitmodules ]]; then
local submodules
_git-r3_set_submodules \
"$(cat "${GIT_WORK_TREE}"/.gitmodules)"
while [[ ${submodules[@]} ]]; do
local subname=${submodules[0]}
local url=${submodules[1]}
local path=${submodules[2]}
git-r3_checkout "${url}" "${GIT_WORK_TREE}/${path}" \
"${local_id}/${subname}"
submodules=( "${submodules[@]:3}" ) # shift
done
fi
# keep this *after* submodules
export EGIT_DIR=${GIT_DIR}
export EGIT_VERSION=${new_commit_id}
}
git-r3_src_fetch() {
debug-print-function ${FUNCNAME} "$@"
[[ ${EVCS_OFFLINE} ]] && return
_git-r3_env_setup
git-r3_fetch
}
git-2_src_unpack() {
debug-print-function ${FUNCNAME} "$@"
_git-r3_env_setup
git-r3_src_fetch
git-r3_checkout
}
_GIT_R3=1
fi
["signature.asc" (application/pgp-signature)]
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic