#!/bin/bash
set -e
set -u
wd="$(cd "$(dirname "$0")" && pwd)";
verbose="";
do_get="true";
do_setup="true";
do_run="true";
force_setup="false";
disable_setup="false";
print_path="false";
install="";
daemonize="-X";
kill="false";
restart="false";
plugin_name="caldav";
service_type="Single";
read_key="";
profile="";
reactor="";
usage ()
{
program="$(basename "$0")";
if [ "${1--}" != "-" ]; then echo "$@"; echo; fi;
echo "Usage: ${program} [-hvgsfnpdkrR] [-K key] [-iI dst] [-t type] [-S statsdirectory] [-P plugin]";
echo "Options:";
echo " -h Print this help and exit";
echo " -v Be verbose";
echo " -g Get dependencies only; don't run setup or run the server.";
echo " -s Run setup only; don't run server";
echo " -f Force setup to run";
echo " -n Do not run setup";
echo " -p Print PYTHONPATH value for server and exit";
echo " -d Run caldavd as a daemon";
echo " -k Stop caldavd";
echo " -r Restart caldavd";
echo " -K Print value of configuration key and exit";
echo " -i Perform a system install into dst; implies -s";
echo " -I Perform a home install into dst; implies -s";
echo " -t Select the server process type (Master, Slave or Combined) [${service_type}]";
echo " -S Write a pstats object for each process to the given directory when the server is stopped.";
echo " -P Select the twistd plugin name [${plugin_name}]";
echo " -R Twisted Reactor plugin to execute [${reactor}]";
if [ "${1-}" == "-" ]; then return 0; fi;
exit 64;
}
while getopts 'hvgsfnpdkrK:i:I:t:S:P:R:' option; do
case "$option" in
'?') usage; ;;
'h') usage -; exit 0; ;;
'v') verbose="-v"; ;;
'f') force_setup="true"; ;;
'k') kill="true"; ;;
'r') restart="true"; ;;
'd') daemonize=""; ;;
'P') plugin_name="${OPTARG}"; ;;
'R') reactor="-R ${OPTARG}"; ;;
't') service_type="${OPTARG}"; ;;
'K') read_key="${OPTARG}"; ;;
'S') profile="-p ${OPTARG}"; ;;
'g') do_get="true" ; do_setup="false"; do_run="false"; ;;
's') do_get="true" ; do_setup="true" ; do_run="false"; ;;
'p') do_get="false"; do_setup="false"; do_run="false"; print_path="true"; ;;
'i') do_get="true" ; do_setup="true" ; do_run="false"; install="${OPTARG}"; install_flag="--root="; ;;
'I') do_get="true" ; do_setup="true" ; do_run="false"; install="${wd}/build/dst"; install_flag="--root="; install_home="${OPTARG}"; ;;
esac;
done;
shift $((${OPTIND} - 1));
if [ $
py_version ()
{
local python="$1"; shift;
echo "$("${python}" -c "from distutils.sysconfig import get_python_version; print get_python_version()")";
}
try_python ()
{
local python="$1"; shift;
if [ -z "${python}" ]; then return 1; fi;
if ! type "${python}" > /dev/null 2>&1; then return 1; fi;
local py_version="$(py_version "${python}")";
if [ "${py_version/./}" -lt "24" ]; then return 1; fi;
return 0;
}
for v in "" "2.5" "2.4"; do
for p in \
"${PYTHON:=}" \
"python${v}" \
"/usr/local/bin/python${v}" \
"/usr/local/python/bin/python${v}" \
"/usr/local/python${v}/bin/python${v}" \
"/opt/bin/python${v}" \
"/opt/python/bin/python${v}" \
"/opt/python${v}/bin/python${v}" \
"/Library/Frameworks/Python.framework/Versions/${v}/bin/python" \
"/opt/local/bin/python${v}" \
"/sw/bin/python${v}" \
;
do
if try_python "${p}"; then python="${p}"; break; fi;
done;
if [ -n "${python:-}" ]; then break; fi;
done;
if [ -z "${python:-}" ]; then
echo "No suitable python found.";
exit 1;
fi;
if [ -z "${caldav:-}" ]; then
caldav="${wd}";
fi;
if [ -z "${caldavd_wrapper_command:-}" ]; then
if [ "$(uname -s)" == "Darwin" ] && [ "$(uname -r | cut -d . -f 1)" -ge 9 ]; then
caldavd_wrapper_command="launchctl bsexec /";
else
caldavd_wrapper_command="";
fi;
fi;
top="$(cd "${caldav}/.." && pwd -L)"
patches="${caldav}/lib-patches";
twisted="${top}/Twisted";
dav="${twisted}/twisted/web2/dav"
if [ -z "${config:-}" ]; then
config="${wd}/conf/caldavd-dev.plist";
fi;
conf_read_key ()
{
local key="$1"; shift;
tr '\n' ' ' < "${config}" \
| xpath "/plist/dict/*[preceding-sibling::key[1]='${key}'" 2>/dev/null \
| sed -n 's|^<[^<][^<]*>\([^<]*\)</[^<][^<]*>.*$|\1|p';
}
if [ -n "${read_key}" ]; then
conf_read_key "${read_key}";
exit $?;
fi;
if "${kill}" || "${restart}"; then
pidfile="$(conf_read_key "PIDFile")";
if [ ! -r "${pidfile}" ]; then
echo "Unreadable PID file: ${pidfile}";
exit 1;
fi;
pid="$(cat "${pidfile}" | head -1)";
if [ -z "${pid}" ]; then
echo "No PID in PID file: ${pidfile}";
exit 1;
fi;
echo "Killing process ${pid}";
kill -TERM "${pid}";
if ! "${restart}"; then
exit 0;
fi;
fi;
if [ -z "${PYTHONPATH:-}" ]; then
user_python_path="";
else
user_python_path=":${PYTHONPATH}";
fi;
py_platform="$("${python}" -c "from distutils.util import get_platform; print get_platform()")";
py_version="$(py_version "${python}")";
py_platform_libdir="lib.${py_platform}-${py_version}";
if [ -n "${install}" ] && ! echo "${install}" | grep '^/' > /dev/null; then
install="$(pwd)/${install}";
fi;
svn_uri_base="$(svn info "${caldav}" --xml 2>/dev/null | sed -n 's|^.*<root>\(.*\)</root>.*$|\1|p')";
if [ -z "${svn_uri_base}" ]; then
svn_uri_base="http://svn.calendarserver.org/repository/calendarserver";
fi;
export PYTHONPATH="${caldav}";
run () {
if "${print_path}"; then
echo "${PYTHONPATH}";
exit 0;
fi;
if "${do_run}"; then
if [ ! -f "${config}" ]; then
echo "Missing config file: ${config}";
echo "You might want to start by copying the test configuration:";
echo " cp conf/caldavd-test.plist conf/caldavd-dev.plist";
exit 1;
fi;
cd "${wd}";
if [ ! -d "${wd}/logs" ]; then
mkdir "${wd}/logs";
fi;
exec ${caldavd_wrapper_command} \
"${caldav}/bin/caldavd" ${daemonize} \
-f "${config}" \
-T "${twisted}/bin/twistd" \
-P "${plugin_name}" \
-t "${service_type}" \
${reactor} \
${profile};
cd /;
fi;
}
apply_patches () {
local name="$1"; shift;
local path="$1"; shift;
if [ -d "${patches}/${name}" ]; then
echo "";
echo "Applying patches to ${name} in ${path}...";
cd "${path}";
find "${patches}/${name}" \
-type f \
-name '*.patch' \
-print \
-exec patch -p0 --forward -i '{}' ';';
cd /;
fi;
echo ""
echo "Removing build directory ${path}/build..."
rm -rf "${path}/build";
echo "Removing pyc files from ${path}..."
find "${path}" -type f -name '*.pyc' -print0 | xargs -0 rm -f;
}
www_get () {
if ! "${do_get}"; then return 0; fi;
local name="$1"; shift;
local path="$1"; shift;
local url="$1"; shift;
local ext="$(echo "${url}" | sed 's|^.*\.\([^.]*\)$|\1|')";
case "${ext}" in
gz|tgz) decompress="gzip -d -c"; ;;
bz2) decompress="bzip2 -d -c"; ;;
tar) decompress="cat"; ;;
*)
echo "Unknown extension: ${ext}";
exit 1;
;;
esac;
if "${force_setup}" || [ ! -d "${path}" ]; then
echo "";
echo "Downloading ${name}...";
rm -rf "${path}";
cd "$(dirname "${path}")";
curl "${url}" | ${decompress} | tar xvf -;
apply_patches "${name}" "${path}";
cd /;
fi;
}
svn_get () {
if ! "${do_get}"; then return 0; fi;
local name="$1"; shift;
local path="$1"; shift;
local uri="$1"; shift;
local revision="$1"; shift;
if [ -d "${path}" ]; then
wc_uri="$(svn info --xml "${path}" 2> /dev/null | sed -n 's|^.*<url>\(.*\)</url>.*$|\1|p')";
if "${force_setup}"; then
if [ "${wc_uri}" != "${uri}" ]; then
echo "";
echo "Current working copy (${path}) is from the wrong URI: ${wc_uri} != ${uri}";
rm -rf "${path}";
svn_get "${name}" "${path}" "${uri}" "${revision}";
return $?;
fi;
echo "";
echo "Reverting ${name}...";
svn revert -R "${path}";
echo "Updating ${name}...";
svn update -r "${revision}" "${path}";
apply_patches "${name}" "${path}";
else
if ! "${print_path}"; then
if [ "${wc_uri}" != "${uri}" ]; then
echo "";
echo "Current working copy (${path}) is from the wrong URI: ${wc_uri} != ${uri}";
echo "Performing repository switch for ${name}...";
svn switch -r "${revision}" "${uri}" "${path}";
apply_patches "${name}" "${path}";
else
svnversion="$(svnversion "${path}")";
if [ "${svnversion%%[M:]*}" != "${revision}" ]; then
echo "";
echo "Updating ${name}...";
svn update -r "${revision}" "${path}";
apply_patches "${name}" "${path}";
fi;
fi;
fi;
fi;
else
echo "Checking out ${name}...";
svn checkout -r "${revision}" "${uri}@${revision}" "${path}";
apply_patches "${name}" "${path}";
fi;
}
py_build () {
local name="$1"; shift;
local path="$1"; shift;
local optional="$1"; shift;
if "${do_setup}" && (
"${force_setup}" || [ ! -d "${path}/build/${py_platform_libdir}" ]
); then
echo "";
echo "Building ${name}...";
cd "${path}";
if ! "${python}" ./setup.py build --build-lib "build/${py_platform_libdir}" "$@"; then
if "${optional}"; then
echo "WARNING: ${name} failed to build.";
echo "WARNING: ${name} is not required to run the server; continuing without it.";
else
return $?;
fi;
fi;
cd /;
fi;
}
py_install () {
local name="$1"; shift;
local path="$1"; shift;
if [ -n "${install}" ]; then
echo "";
echo "Installing ${name}...";
cd "${path}";
"${python}" ./setup.py install "${install_flag}${install}";
cd /;
fi;
}
py_have_module () {
local module="$1"; shift;
PYTHONPATH="" "${python}" -c "import ${module}" > /dev/null 2>&1;
}
put_setuptools () {
local where="$1"; shift;
if "${do_get}"; then
cp "${caldav}/support/setuptools-0.6c8-py2.5.egg" "${where}/";
fi;
}
if ! py_have_module zope.interface; then
zope="${top}/zope.interface-3.3.0";
www_get "Zope Interface" "${zope}" http://www.zope.org/Products/ZopeInterface/3.3.0/zope.interface-3.3.0.tar.gz;
py_build "Zope Interface" "${zope}" false;
py_install "Zope Interface" "${zope}";
export PYTHONPATH="${PYTHONPATH}:${zope}/build/${py_platform_libdir}";
fi;
if ! py_have_module xml.dom.ext; then
xml="${top}/PyXML-0.8.4";
www_get "PyXML" "${xml}" http://easynews.dl.sourceforge.net/sourceforge/pyxml/PyXML-0.8.4.tar.gz;
py_build "PyXML" "${xml}" false;
py_install "PyXML" "${xml}";
export PYTHONPATH="${PYTHONPATH}:${xml}/build/${py_platform_libdir}";
fi;
if ! py_have_module OpenSSL; then
ssl="${top}/pyOpenSSL-0.6";
www_get "PyOpenSSL" "${ssl}" http://easynews.dl.sourceforge.net/sourceforge/pyopenssl/pyOpenSSL-0.6.tar.gz;
py_build "PyOpenSSL" "${ssl}" false;
py_install "PyOpenSSL" "${ssl}";
export PYTHONPATH="${PYTHONPATH}:${ssl}/build/${py_platform_libdir}";
fi;
if type krb5-config > /dev/null; then
if ! py_have_module kerberos; then
kerberos="${top}/PyKerberos";
svn_get "PyKerberos" "${kerberos}" "${svn_uri_base}/PyKerberos/trunk" 1541;
py_build "PyKerberos" "${kerberos}" false; py_install "PyKerberos" "${kerberos}";
export PYTHONPATH="${PYTHONPATH}:${kerberos}/build/${py_platform_libdir}";
fi;
fi;
if [ "$(uname -s)" == "Darwin" ]; then
if ! py_have_module opendirectory; then
opendirectory="${top}/PyOpenDirectory";
svn_get "PyOpenDirectory" "${opendirectory}" "${svn_uri_base}/PyOpenDirectory/trunk" 1964;
py_build "PyOpenDirectory" "${opendirectory}" false;
py_install "PyOpenDirectory" "${opendirectory}";
export PYTHONPATH="${PYTHONPATH}:${opendirectory}/build/${py_platform_libdir}";
fi;
fi;
xattr="${top}/xattr";
svn_get "xattr" "${xattr}" http://svn.red-bean.com/bob/xattr/releases/xattr-0.5 1013;
put_setuptools "${xattr}";
py_build "xattr" "${xattr}" false;
py_install "xattr" "${xattr}";
export PYTHONPATH="${PYTHONPATH}:${xattr}/build/${py_platform_libdir}";
if ! py_have_module ctypes; then
ctypes="${top}/ctypes-1.0.0"
www_get "ctypes" "${ctypes}" http://easynews.dl.sourceforge.net/sourceforge/ctypes/ctypes-1.0.0.tar.gz;
py_build "ctypes" "${ctypes}" true;
py_install "ctypes" "${ctypes}";
export PYTHONPATH="${PYTHONPATH}:${ctypes}/build/${py_platform_libdir}";
fi;
if ! py_have_module select26; then
select26="${top}/select26-0.1a3"
www_get "select26" "${select26}" http://pypi.python.org/packages/source/s/select26/select26-0.1a3.tar.gz;
py_build "select26" "${select26}" true;
py_install "select26" "${select26}";
export PYTHONPATH="${PYTHONPATH}:${select26}/build/${py_platform_libdir}";
fi;
case "${USER}" in
wsanchez)
proto="svn+ssh";
;;
*)
proto="svn";
;;
esac;
svn_uri="${proto}://svn.twistedmatrix.com/svn/Twisted/branches/dav-acl-1608-4";
svn_get "Twisted" "${twisted}" "${svn_uri}" 19773;
py_install "Twisted" "${twisted}";
export PYTHONPATH="${PYTHONPATH}:${twisted}";
if [ -n "${install}" ]; then
echo "";
echo "Installing Twisted.web2...";
cd "${twisted}";
"${python}" ./twisted/web2/topfiles/setup.py install "${install_flag}${install}";
cd /;
fi;
if ! py_have_module dateutil; then
dateutil="${top}/python-dateutil-1.2";
www_get "dateutil" "${dateutil}" http://labix.org/download/python-dateutil/python-dateutil-1.2.tar.bz2;
py_install "dateutil" "${dateutil}";
export PYTHONPATH="${PYTHONPATH}:${dateutil}";
fi;
if ! py_have_module sqlite3 && ! py_have_module pysqlite2; then
pysqlite="${top}/pysqlite-2.3.2";
www_get "PySQLite" "${pysqlite}" http://initd.org/pub/software/pysqlite/releases/2.3/2.3.2/pysqlite-2.3.2.tar.gz;
py_build "PySQLite" "${pysqlite}" false;
py_install "PySQLite" "${pysqlite}";
export PYTHONPATH="${PYTHONPATH}:${pysqlite}/build/${py_platform_libdir}";
fi;
if ! py_have_module pydirector; then
pydirector="${top}/pydirector-1.0.0";
www_get "PyDirector" "${pydirector}" http://easynews.dl.sourceforge.net/sourceforge/pythondirector/pydirector-1.0.0.tar.gz;
put_setuptools "${pydirector}";
py_build "PyDirector" "${pydirector}" false;
py_install "PyDirector" "${pydirector}";
export PYTHONPATH="${PYTHONPATH}:${pydirector}/build/${py_platform_libdir}";
fi;
py_install "Calendar Server" "${caldav}";
if [ -n "${install_home:-}" ]; then
py_prefix="$("${python}" -c "import sys; print sys.prefix;")";
py_libdir="$("${python}" -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1);")";
install -d "${install_home}";
install -d "${install_home}/bin";
install -d "${install_home}/conf";
install -d "${install_home}/lib/python";
rsync -av "${install}${py_prefix}/bin/" "${install_home}/bin/";
rsync -av "${install}${py_libdir}/" "${install_home}/lib/python/";
rsync -av "${install}${py_prefix}/caldavd/" "${install_home}/caldavd/";
rm -rf "${install}";
fi;
export PYTHONPATH="${PYTHONPATH}${user_python_path}";
run;