#!/bin/bash
# A simple script to checkout or update a svn or git repo as source service
#
# (C) 2010 by Adrian Schröter <adrian@suse.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# See http://www.gnu.org/licenses/gpl-2.0.html for full license text.
SERVICE='tar_scm'
set_default_params () {
MYSCM=""
MYURL=""
#MYVERSION="_auto_"
MYVERSION="222"
MYFORMAT=""
MYPREFIX=""
MYFILENAME=""
MYREVISION=""
MYPACKAGEMETA=""
# MYHISTORYDEPTH=""
INCLUDES=""
}
get_config_options () {
# config options for this host ?
if [ -f /etc/obs/services/$SERVICE ]; then
. /etc/obs/services/$SERVICE
fi
# config options for this user ?
if [ -f "$HOME"/.obs/$SERVICE ]; then
. "$HOME"/.obs/$SERVICE
fi
}
parse_params () {
while test $# -gt 0; do
case $1 in
*-scm)
MYSCM="$2"
shift
;;
*-url)
MYURL="$2"
CI_PRO_NAME=${MYURL%%/*}
TEMP_URL="$MYURL"
MYURL=$TEMP_URL
shift
;;
*-subdir)
MYSUBDIR="$2"
shift
;;
*-revision)
MYREVISION="$2"
shift
;;
*-version)
MYVERSION="$2"
shift
;;
*-include)
INCLUDES="$INCLUDES $2"
shift
;;
*-versionformat)
MYFORMAT="$2"
shift
;;
*-versionprefix)
MYPREFIX="$2"
shift
;;
*-exclude)
EXCLUDES="$EXCLUDES --exclude=${2#/}"
shift
;;
*-filename)
MYFILENAME="${2#/}"
shift
;;
*-package-meta)
MYPACKAGEMETA="${2#/}"
shift
;;
*-outdir)
MYOUTDIR="$2"
shift
;;
*-history-depth)
echo "history-depth parameter is obsolete and will be ignored"
shift
;;
*-project)
MYPROJECT="$2"
shift
;;
*-package)
MYPACKAGE="$2"
shift
;;
*-extract)
shift
;;
*)
echo "Unknown parameter: $1"
echo 'Usage: $SERVICE --scm $SCM --url $URL [--subdir $SUBDIR] [--revision $REVISION] [--version $VERSION] [--include $INCLUDE]* [--exclude $EXCLUDE]* [--versionformat $FORMAT] [--versionprefix $PREFIX] [--filename $FILENAME] [--package-meta $META] --outdir $OUT'
exit 1
;;
esac
shift
done
}
error () {
echo "ERROR: $*"
exit 1
}
debug () {
[ -n "$DEBUG_TAR_SCM" ] && echo "$*"
}
safe_run () {
if ! "$@"; then
error "$* failed; aborting!"
fi
}
sanitise_params () {
TAR_VERSION="$MYVERSION"
if [ -z "$MYSCM" ]; then
error "no scm is given via --scm parameter (git/svn/hg/bzr)!"
fi
if [ -z "$MYURL" ]; then
error "no checkout URL is given via --url parameter!"
fi
if [ -z "$MYOUTDIR" ]; then
error "no output directory is given via --outdir parameter!"
fi
if [ -z "$MYPROJECT" ]; then
error "no project is given via --project parameter!"
fi
if [ -z "$MYPACKAGE" ]; then
error "no package is given via --package parameter!"
fi
FILE="$MYFILENAME"
WD_VERSION="$MYVERSION"
if [ -z "$MYPACKAGEMETA" ]; then
EXCLUDES="$EXCLUDES --exclude=.svn"
fi
# if [ "$MYHISTORYDEPTH" == "full" ]; then
# MYHISTORYDEPTH="999999999"
# fi
}
detect_default_filename_param () {
if [ -n "$FILE" ]; then
return
fi
case "$MYSCM" in
git)
FILE="${MYURL%/}"
FILE="${FILE##*/}"
FILE="${FILE%.git}"
FILE="${FILE#*@*:}"
;;
svn|hg|bzr)
FILE="${MYURL%/}"
FILE="${FILE##*/}"
;;
local)
FILE="temp_dir"
;;
*)
error "unknown SCM '$MYSCM'"
esac
}
fetch_upstream () {
TOHASH="$MYURL"
[ "$MYSCM" = 'svn' ] && TOHASH="$TOHASH/$MYSUBDIR"
HASH=`echo "$TOHASH" | sha256sum | cut -d\ -f 1`
REPOCACHE=
CACHEDIRECTORY=/tmp/local_code/xdf
if [ -n "$CACHEDIRECTORY" ]; then
REPOCACHEINCOMING="$CACHEDIRECTORY/incoming"
REPOCACHEROOT="$CACHEDIRECTORY/repo"
REPOCACHE="$REPOCACHEROOT/$MYPROJECT/$MYPACKAGE"
REPOURLCACHE="$CACHEDIRECTORY/repourl/$HASH"
fi
debug "check local cache if configured"
if [ -n "$CACHEDIRECTORY" -a -d "$REPOCACHE/" ]; then
debug "cache hit: $REPOCACHE"
check_cache
else
if [ -n "$CACHEDIRECTORY" ]; then
debug "cache miss: $REPOCACHE/"
else
debug "cache not enabled"
fi
calc_dir_to_clone_to
debug "new $MYSCM checkout to $CLONE_TO"
initial_clone
if [ -n "$CACHEDIRECTORY" ]; then
#cache_repo
REPOPATH="$REPOCACHE"
else
REPOPATH="$MYOUTDIR/$FILE"
fi
if [ "$TAR_VERSION" == "_auto_" -o -n "$MYFORMAT" ]; then
detect_version
fi
#exit 22
fi
}
calc_dir_to_clone_to () {
if [ -n "$CACHEDIRECTORY" ]; then
if [ ! -d REPOCACHE ]; then
mkdir -p "$REPOCACHE"
fi
safe_run cd "$REPOCACHE"
# Use dry-run mode because git/hg refuse to clone into
# an empty directory on SLES11
#debug mktemp -u -d "tmp.XXXXXXXXXX"
#CLONE_TO=`mktemp -u -d "tmp.XXXXXXXXXX"`
CLONE_TO="$REPOCACHE"
else
CLONE_TO="$FILE"
fi
}
initial_clone () {
echo "Fetching from $MYURL ..."
case "$MYSCM" in
git)
# Clone with full depth; so that the revision can be found if specified
safe_run git clone "$MYURL" "$CLONE_TO"
;;
svn)
args=
[ -n "$MYREVISION" ] && args="-r$MYREVISION"
if [[ $(svn --version --quiet) > "1.5.99" ]]; then
TRUST_SERVER_CERT="--trust-server-cert"
fi
safe_run svn checkout --non-interactive $TRUST_SERVER_CERT \
$args "$MYURL/$MYSUBDIR" "$CLONE_TO"
MYSUBDIR= # repo root is subdir
;;
local)
echo "xdffff: $MYURL ---- $CLONE_TO --- `pwd`"
safe_run cp -av $MYURL/* ./
if [ -d "$MYURL/.svn" ]; then
safe_run cp -av $MYURL/.svn ./
fi
;;
hg)
safe_run hg clone "$MYURL" "$CLONE_TO"
;;
bzr)
args=
[ -n "$MYREVISION" ] && args="-r $MYREVISION"
safe_run bzr checkout $args "$MYURL" "$CLONE_TO"
;;
*)
error "unknown SCM '$MYSCM'"
esac
}
cache_repo () {
if [ -e "$REPOCACHE" ]; then
error "Somebody else beat us to populating the cache for $MYURL ($REPOCACHE)"
else
# FIXME: small race window here; do source services need to be thread-safe?
if [ ! -d $REPOCACHE ]; then
mkdir -p $REPOCACHE
fi
debug mv2 "$CLONE_TO" "$REPOCACHE"
safe_run mv "$CLONE_TO" "$REPOCACHE"
echo "$MYURL" > "$REPOURLCACHE"
echo "Cached $MYURL at $REPOCACHE"
fi
}
check_cache () {
if [ -d "$MYURL/.svn" ]; then
new_version=`LC_ALL=C svn info "$MYURL" | sed -n 's,^Last Changed Rev: \(.*\),\1,p'`
else
new_version="new_version"
fi
if echo "$MYURL" | grep '/$' &> /dev/null; then
new_version="new_version"
fi
if [ -d "$REPOCACHE/.svn" ]; then
old_version=`LC_ALL=C svn info "$REPOCACHE" | sed -n 's,^Last Changed Rev: \(.*\),\1,p'`
else
old_version="old_version"
fi
#echo "xdf: $new_version $old_version"
#if [ "$new_version" != "$old_version" ]; then
echo "The code has changed for $MYPROJECT/$MYPACKAGE"
rm -rf "$REPOCACHE"
calc_dir_to_clone_to
debug "new $MYSCM checkout to $CLONE_TO"
initial_clone
if [ -n "$CACHEDIRECTORY" ]; then
#cache_repo
REPOPATH="$REPOCACHE"
else
REPOPATH="$MYOUTDIR/$FILE"
fi
safe_run cd "$REPOPATH"
switch_to_revision
if [ "$TAR_VERSION" == "_auto_" -o -n "$MYFORMAT" ]; then
detect_version
fi
#else
# echo "No code is changed, so exit 22"
# exit 22
#fi
}
update_cache () {
safe_run cd "$REPOCACHE"
case "$MYSCM" in
git)
safe_run git fetch
;;
svn)
args=
[ -n "$MYREVISION" ] && args="-r$MYREVISION"
safe_run svn update $args > svnupdate_info
isupdate=`cat svnupdate_info | wc -l`
if [ $isupdate -eq 1 ]; then
rm -f svnupdate_info
echo "There is no code update, so exit 22"
exit 22
fi
MYSUBDIR= # repo root is subdir
;;
hg)
if ! out=`hg pull`; then
if [[ "$out" == *'no changes found'* ]]; then
# Contrary to the docs, hg pull returns exit code 1 when
# there are no changes to pull, but we don't want to treat
# this as an error.
:
else
error "hg pull failed; aborting!"
fi
fi
;;
bzr)
args=
[ -n "$MYREVISION" ] && args="-r$MYREVISION"
safe_run bzr update $args
;;
*)
error "unknown SCM '$MYSCM'"
esac
}
switch_to_revision () {
case "$MYSCM" in
git)
safe_run git checkout "$MYREVISION"
if git branch | grep -q '^\* (no branch)$'; then
echo "$MYREVISION does not refer to a branch, not attempting git pull"
else
safe_run git pull
fi
;;
svn|bzr|local)
: # should have already happened via checkout or update
;;
hg)
safe_run hg update "$MYREVISION"
;;
# bzr)
# safe_run bzr update
# if [ -n "$MYREVISION" ]; then
# safe_run bzr revert -r "$MYREVISION"
# fi
# ;;
*)
error "unknown SCM '$MYSCM'"
esac
}
detect_version () {
if [ -z "$MYFORMAT" ]; then
case "$MYSCM" in
git)
MYFORMAT="%at"
;;
hg)
MYFORMAT="{rev}"
;;
svn|bzr)
MYFORMAT="%r"
;;
*)
error "unknown SCM '$MYSCM'"
;;
esac
fi
safe_run cd "$REPOPATH"
if [ -n "$MYFORMAT" ];then
MYPREFIX="$MYFORMAT"
else
get_version
fi
TAR_VERSION="$MYPREFIX$version"
}
get_version () {
case "$MYSCM" in
git)
#version=`safe_run git show --pretty=format:"$MYFORMAT" | head -n 1`
version=`safe_run git log -n1 --pretty=format:"$MYFORMAT"`
;;
svn)
#rev=`LC_ALL=C safe_run svn info | awk '/^Revision:/ { print $2 }'`
rev=`LC_ALL=C safe_run svn info | sed -n 's,^Last Changed Rev: \(.*\),\1,p'`
version="${MYFORMAT//%r/$rev}"
;;
hg)
rev=`safe_run hg id -n`
version=`safe_run hg log -l1 -r$rev --template "$MYFORMAT"`
;;
bzr)
#safe_run bzr log -l1 ...
rev=`safe_run bzr revno`
version="${MYFORMAT//%r/$rev}"
;;
*)
error "unknown SCM '$MYSCM'"
esac
}
prep_tree_for_tar () {
if [ ! -e "$REPOPATH/$MYSUBDIR" ]; then
error "directory does not exist: $REPOPATH/$MYSUBDIR"
fi
if [ -z "$TAR_VERSION" ]; then
TAR_BASENAME="$FILE"
else
TAR_BASENAME="${FILE}-${TAR_VERSION}"
fi
MYINCLUDES=""
for INC in $INCLUDES; do
MYINCLUDES="$MYINCLUDES $INC"
done
if [ -z "$MYINCLUDES" ]; then
MYINCLUDES="*"
fi
safe_run cd "$MYOUTDIR"
if [ -n "$CACHEDIRECTORY" ]; then
debug cp -a "$REPOPATH/$MYSUBDIR" "$TAR_BASENAME"
safe_run cp -a "$REPOPATH/$MYSUBDIR" "$TAR_BASENAME"
else
debug mv3 "$REPOPATH/$MYSUBDIR" "$TAR_BASENAME"
safe_run mv "$REPOPATH/$MYSUBDIR" "$TAR_BASENAME"
fi
}
create_tar () {
safe_run cd "$TAR_BASENAME"
TARFILE="${TAR_BASENAME}.tar.bz2"
TARPATH="$MYOUTDIR/$TARFILE"
for INC in $MYINCLUDES; do
if [ "$INC" = ".$MYSCM" ]; then
continue
fi
if echo "$EXCLUDES" | grep -w $INC >/dev/null
then
continue
fi
if [ -d $INC ]; then
#safe_run tar jcf "$MYOUTDIR/$INC.tar.bz2" --exclude=.$MYSCM --exclude=.svn $INC
safe_run tar Pcf "$MYOUTDIR/$INC.tar" --exclude=.$MYSCM --exclude=.svn $INC
continue
fi
safe_run cp $INC "$MYOUTDIR/"
done
echo "Created $TARFILE"
safe_run cd "$MYOUTDIR"
}
cleanup () {
debug rm -rf "$TAR_BASENAME" "$FILE"
#rm -rf "$TAR_BASENAME" "$FILE"
rm -rf "$TAR_BASENAME"
}
main () {
set_default_params
#xdf
DEBUG_TAR_SCM=1
if [ -z "$DEBUG_TAR_SCM" ]; then
get_config_options
else
# We're in test-mode, so don't let any local site-wide
# or per-user config impact the test suite.
:
fi
parse_params "$@"
sanitise_params
SRCDIR=$(pwd)
cd "$MYOUTDIR"
#echo "$SRCDIR $MYOUTDIR"
detect_default_filename_param
#xdf
#LOGFILE=/srv/local_code/xdf/log/$MYPROJECT/$MYPACKAGE
#mkdir -p "/srv/local_code/xdf/log/$MYPROJECT"
lockfile=$LOGFILE".lock"
if [ -f $lockfile ]; then
mypid=`cat $lockfile`
# while ps -p $mypid -o comm= &> /dev/null
# do
# sleep 10
# mypid=`cat $lockfile`
# done
rm -f $lockfile
fi
touch $lockfile
echo "$$" > $lockfile
#exec 6>&1
#exec > $LOGFILE
echo "$@"
echo "myurl === $MYURL"
fetch_upstream
prep_tree_for_tar
create_tar
cleanup
rm -f $lockfile
}
main "$@"
exit 0