1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/dist/tools/git/git-cache
Koen Zandberg 96cad82910
dist/tools: Use bash instead of sh where needed
A number of scripts use features from bash such as `local` which are not
in the POSIX spec. This breaks on systems where sh is not symlinked to
bash.

This patch changes the interpreter indicated by the hashbang to bash for
those scripts
2020-10-30 12:12:10 +01:00

290 lines
7.3 KiB
Bash
Executable File

#!/bin/bash -e
[ "$GIT_CACHE_VERBOSE" != "1" ] && Q=-q
git_cache() {
git -C "${GIT_CACHE_DIR}" $*
}
git_cache_initialized() {
local _git_dir="$(git_cache rev-parse --git-dir 2>/dev/null)"
test "$_git_dir" = "." -o "$_git_dir" = ".git"
}
init() {
git_cache_initialized || {
mkdir -p "${GIT_CACHE_DIR}"
git_cache init --bare
git_cache config core.compression 1
}
}
startswith() {
case "$1" in
"${2}"*)
return 0
;;
*)
return 1
esac
}
add() {
local repo="$1"
_locked "$GIT_CACHE_DIR/$name.addlock" _add "$repo"
}
_add() {
local repo="$1"
local name="$(_remote_name $repo)"
if ! is_cached "$repo"; then
git_cache remote add "$name" "$repo"
git_cache config --add remote.${name}.fetch "+refs/tags/*:refs/tags/${name}/*"
else
echo "git-cache: $url already in cache"
fi
}
if [ "$(uname)" = Darwin ]; then
_locked() {
local lockfile="$1"
shift
while ! shlock -p $$ -f $lockfile; do
sleep 0.2
done
$*
rm $lockfile
}
else
_locked() {
local lockfile="$1"
shift
(
flock -w 600 9 || exit 1
$*
) 9>"$lockfile"
}
fi
update() {
local REMOTE=${1}
if [ -n "$REMOTE" ]; then
local REMOTES=$(_remote_name $REMOTE)
else
local REMOTES="$(git_cache remote show)"
fi
for remote in $REMOTES; do
echo "git-cache: updating remote $remote"
_locked "$GIT_CACHE_DIR/$remote.lock" git_cache --namespace $remote fetch $Q -n $remote
done
}
is_cached() {
local url="$1"
local REMOTES="$(git_cache remote show)"
for remote in $REMOTES; do
[ "$(git_cache ls-remote --get-url $remote)" = "$url" ] && return 0
done
return 1
}
list() {
local REMOTES="$(git_cache remote show)"
for remote in $REMOTES; do
echo "$(git_cache ls-remote --get-url $remote)"
done
}
drop() {
local REMOTE=${1}
[ -z "$REMOTE" ] && {
echo "usage: git cache drop <url>"
exit 1
}
local REMOTES="$(git_cache remote show)"
for remote in $REMOTES; do
[ "$(git_cache ls-remote --get-url $remote)" = "$REMOTE" ] && {
git_cache remote remove $remote
break
}
done
}
_check_commit() {
git_cache cat-file -e ${1}^{commit} 2>/dev/null
}
_remote_name() {
echo "$*" | git hash-object --stdin
}
_tag_to_sha1() {
local out="$(git_cache log -n 1 --pretty=oneline $1 -- 2>/dev/null || true)"
[ -n "$out" ] && echo $out | cut -f 1 -d" "
}
_check_tag_or_commit() {
local SHA1=$1
local REMOTE_NAME=$2
if _check_commit $SHA1 ; then
local tag=commit$SHA1-$$
git_cache tag $tag $SHA1 2> /dev/null || true # ignore possibly already existing tag
echo "$tag"
elif _tag_to_sha1 ${REMOTE_NAME}/$SHA1 > /dev/null; then
echo "${REMOTE_NAME}/$SHA1"
fi
}
clone() {
local REMOTE="${1}"
local SHA1="${2}"
local REMOTE_NAME="$(_remote_name $REMOTE)"
local TARGET_PATH="${3}"
[ -z "$TARGET_PATH" ] && TARGET_PATH="$(basename $REMOTE)"
# make sure git won't ask for credentials
export GIT_TERMINAL_PROMPT=0
if git_cache_initialized; then
if ! is_cached "$REMOTE"; then
echo "git cache: auto-adding $REMOTE"
add "$REMOTE"
fi
local pull=0
if startswith "$SHA1" "pull/"; then
pull=1
fi
if [ $pull -eq 0 ]; then
local tag="$(_check_tag_or_commit $SHA1 $REMOTE_NAME)"
if [ -z "$tag" ]; then
# commit / tag not in cache, try updating repo
update "$REMOTE"
tag="$(_check_tag_or_commit $SHA1 $REMOTE_NAME)"
fi
else
local tag="remotes/$REMOTE_NAME/master"
if [ -z "$(_tag_to_sha1 $tag)" ]; then
update "$REMOTE"
fi
tag="$(_check_tag_or_commit $(_tag_to_sha1 $tag) $REMOTE_NAME)"
if [ -z "$tag" ]; then
echo "git-cache: cannot checkout master branch of $REMOTE"
false
fi
fi
if [ -n "$tag" ]; then
echo "git-cache: cloning from cache. tag=$tag"
git -c advice.detachedHead=false clone $Q --reference "${GIT_CACHE_DIR}" --shared "${GIT_CACHE_DIR}" "${TARGET_PATH}" --branch $tag
# rename tags from <remote-hash>/* to *
git -C "${TARGET_PATH}" fetch $Q origin "refs/tags/${REMOTE_NAME}/*:refs/tags/*"
# remove all commit* and <remote-hash>/* tags
git -C "${TARGET_PATH}" tag -l \
| grep -P '(^[a-f0-9]{40}/|^commit[a-f0-9]{40}(-\d+)?$)' \
| xargs git -C "${TARGET_PATH}" tag -d > /dev/null
# cleanup possibly created helper tag
case $tag in
commit*)
git_cache tag -d $tag 2>&1 > /dev/null || true
;;
esac
if [ $pull -eq 1 ]; then
git -C "${TARGET_PATH}" fetch $Q $REMOTE $SHA1:$SHA1
git -C "${TARGET_PATH}" checkout $Q $SHA1
fi
else
echo "git-cache: trying checkout from source"
git clone $Q --reference "${GIT_CACHE_DIR}" --shared "${REMOTE}" "${TARGET_PATH}"
git -c advice.detachedHead=false -C "${TARGET_PATH}" checkout $Q $SHA1
fi
else
git clone "${REMOTE}" "${TARGET_PATH}"
git -c advice.detachedHead=false -C "${TARGET_PATH}" checkout $SHA1
fi
}
cleanup() {
git_cache tag -l \
| grep -P '(^commit[a-f0-9]{40}(-\d+)?$)' \
| xargs git -C "${GIT_CACHE_DIR}" tag -d > /dev/null
}
usage() {
echo "git cache uses a bare git repository containing all objects from multiple"
echo "upstream git repositories."
echo ""
echo "usage:"
echo ""
echo " git cache init initialize git cache"
echo " git cache add <url> add repository <url>"
echo " git cache list list cached repositories"
echo " git cache drop <url> drop repo from cache"
echo " git cache update [<url>] fetch repo <url> (or all)"
echo " git cache clone <url> <SHA1> clone repository <url> from cache"
echo " git cache show-path print's the path that can be used as "
echo " '--reference' parameter"
echo " git cache cleanup cleanup dangling temporary tags"
echo " (appear if git-cache gets inter-"
echo " rupted, but are harmless)"
echo ""
echo "To retrieve objects from cache (will use remote repository if needed):"
echo ' git clone --reference $(git cache show-path) <repo>'
}
[ $# -eq 0 ] && {
usage
exit 1
}
ACTION=$1
shift 1
GIT_CACHE_DIR=${GIT_CACHE_DIR:-${HOME}/.gitcache}
case $ACTION in
init)
init $*
;;
add)
add $*
;;
update)
update $*
;;
list)
list $*
;;
drop)
drop $*
;;
show-path)
echo ${GIT_CACHE_DIR}
;;
clone)
clone $*
;;
cleanup)
cleanup
;;
*)
usage
;;
esac