From c1bc9c2d10e1109ffd6d1543cb9b57c6a9412b92 Mon Sep 17 00:00:00 2001 From: Cyrus Daboo Date: Wed, 22 Jul 2015 20:12:33 +0000 Subject: [PATCH] Fix issue with virtualenv being locked to specific system Python versions. git-svn-id: https://svn.calendarserver.org/repository/calendarserver/CalendarServer/branches/release/CalendarServer-6.2-dev@14987 e27351fd-9f3e-4f54-a53b-843176b1656c --- support/Apple.make | 23 ++++++++++++------- support/python-wrapper.c | 47 +++++++++++++++++++++++++++++++++++++++ support/undo-virtualenv | 48 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 8 deletions(-) create mode 100644 support/python-wrapper.c create mode 100755 support/undo-virtualenv diff --git a/support/Apple.make b/support/Apple.make index 50e9c3051..153e3c543 100644 --- a/support/Apple.make +++ b/support/Apple.make @@ -58,6 +58,12 @@ CS_GROUP = _calendar build:: $(BuildDirectory)/$(Project) +build:: build-wrapper +build-wrapper: $(BuildDirectory)/python-wrapper + +$(BuildDirectory)/python-wrapper: $(Sources)/support/python-wrapper.c + $(CC) $(Sources)/support/python-wrapper.c -o $(BuildDirectory)/python-wrapper + install:: install-python install-python:: build @# @@ -85,18 +91,15 @@ install-python:: build @# @# Set up a virtual environment in Server.app; we'll install into that. @# That creates a self-contained environment which has specific version of - @# (almost) all of our dependancies in it. + @# (almost) all of our dependencies in it. @# Use --system-site-packages so that we use the packages provided by the @# OS, such as PyObjC. - @# Use --always-copy because we want copies of, not links to, the system - @# python, as Server.app is an independent product train. @# @echo "Creating virtual environment..."; $(_v) $(RMDIR) "$(DSTROOT)$(CS_VIRTUALENV)"; $(_v) PYTHONPATH="$(BuildDirectory)/pytools/lib" \ "$(PYTHON)" -m virtualenv \ --system-site-packages \ - --always-copy \ "$(DSTROOT)$(CS_VIRTUALENV)"; @# @# Use the pip in the virtual environment (as opposed to pip in the OS) to @@ -135,14 +138,18 @@ install-python:: build $(_v) perl -i -pe "s|#PATH|export PYTHON=$(CS_VIRTUALENV)/bin/python;|" "$(DSTROOT)$(CS_VIRTUALENV)/bin/caldavd"; @echo "Stripping binaries..."; $(_v) find "$(DSTROOT)$(CS_VIRTUALENV)" -type f -name "*.so" -print0 | xargs -0 $(STRIP) -Sx; - @echo "Updating install location of Python library..."; - $(_v) find "$(DSTROOT)$(CS_VIRTUALENV)/bin" -type f -name "python*" -print0 | \ - xargs -0 -n 1 install_name_tool -change "@executable_path/../.Python" "$(CS_VIRTUALENV)/.Python"; - $(_v) install_name_tool -id "$(CS_VIRTUALENV)/.Python" "$(DSTROOT)$(CS_VIRTUALENV)/.Python"; @echo "Putting comments into empty files..."; $(_v) find "$(DSTROOT)$(CS_VIRTUALENV)" -type f -size 0 -name "*.py" -exec sh -c 'printf "# empty\n" > {}' ";"; $(_v) find "$(DSTROOT)$(CS_VIRTUALENV)" -type f -size 0 -name "*.h" -exec sh -c 'printf "/* empty */\n" > {}' ";"; + @# + @# Undo virtualenv so we use the python-wrapper + @# + @echo "Undo virtualenv..."; + $(_v) cp "$(BuildDirectory)/python-wrapper" "$(DSTROOT)$(CS_VIRTUALENV)/bin" + $(_v) $(STRIP) -Sx "$(DSTROOT)$(CS_VIRTUALENV)/bin/python-wrapper" + $(_v) "$(Sources)/support/undo-virtualenv" "$(DSTROOT)$(CS_VIRTUALENV)" + install:: install-config install-config:: $(_v) $(INSTALL_DIRECTORY) "$(DSTROOT)$(SIPP)$(ETCDIR)$(CALDAVDSUBDIR)"; diff --git a/support/python-wrapper.c b/support/python-wrapper.c new file mode 100644 index 000000000..8bf427853 --- /dev/null +++ b/support/python-wrapper.c @@ -0,0 +1,47 @@ +// +// python-wrapper.c +// +// Copyright © 2015 Apple Inc. All rights reserved. +// + +#include +#include +#include +#include + +const char* python = "/usr/bin/python2.7"; +const char* bin = "/Applications/Server.app/Contents/ServerRoot/Library/CalendarServer/bin"; +const char* site = "/Applications/Server.app/Contents/ServerRoot/Library/CalendarServer/lib/python2.7/site-packages"; + +// Prepend a path to the named environment variable +int prependToPath(const char* name, const char* prepend) { + const char* old_value = getenv(name); + char* new_value = NULL; + if (old_value == NULL) { + // No existing value - set to the prepend value + size_t max_length = strlen(prepend) + 1; + new_value = malloc(max_length); + strlcpy(new_value, prepend, max_length); + } else { + // Existing value - so prepend with a ":" in between + size_t max_length = strlen(old_value) + strlen(prepend) + 2; + new_value = malloc(max_length); + strlcpy(new_value, prepend, max_length); + strlcat(new_value, ":", max_length); + strlcat(new_value, old_value, max_length); + } + setenv(name, new_value, 1); + free(new_value); + return 0; +} + +int main(int argc, const char * argv[]) { + + // Update PATH and PYTHONPATH + prependToPath("PATH", bin); + prependToPath("PYTHONPATH", site); + + // Launch real python + argv[0] = python; + return execvp(python, (char* const*)argv); +} diff --git a/support/undo-virtualenv b/support/undo-virtualenv new file mode 100755 index 000000000..22a75418d --- /dev/null +++ b/support/undo-virtualenv @@ -0,0 +1,48 @@ +#!/bin/sh + +## +# Copyright (c) 2015 Apple Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## + +set -e +set -u + +base="${1}"; +if [ $# == 1 ]; then + appbase="/Applications/Server.app/Contents/ServerRoot/Library/CalendarServer"; +else + appbase="${2}"; +fi; + +# Remove python binaries +rm -f "${base}/bin/python"; +rm -f "${base}/bin/python2"; +rm -f "${base}/bin/python2.7"; + +# Remove unused virtualenv files +rm -f "${base}/.Python"; +rm -f "${base}/include/python2.7"; +rm -f "${base}/lib/python2.7/"*.py*; +rm -f "${base}/lib/python2.7/config"; +rm -rf "${base}/lib/python2.7/distutils"; +rm -f "${base}/lib/python2.7/encodings"; +rm -f "${base}/lib/python2.7/lib-dynload"; +rm -f "${base}/lib/python2.7/orig-prefix.txt"; + +# Create links +cd "${base}/bin" +ln -s "python-wrapper" "python"; +ln -s "python-wrapper" "python2"; +ln -s "python-wrapper" "python2.7";