diff -r c61d96e72e6f -r d0b7dac5325c thirdparty/google_appengine/google/appengine/dist/_library.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/thirdparty/google_appengine/google/appengine/dist/_library.py Fri Jun 19 16:13:32 2009 +0200 @@ -0,0 +1,281 @@ +#!/usr/bin/env python +# +# Copyright 2007 Google Inc. +# +# 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. +# + +"""Code to exist off of google.appengine.dist. + +Kept in a separate file from the __init__ module for testing purposes. +""" + + +__all__ = ['use_library'] + + +import distutils.version +import os +import sys + +server_software = os.getenv('SERVER_SOFTWARE') +USING_SDK = not server_software or server_software.startswith('Dev') +del server_software + +if not USING_SDK: + import google + this_version = os.path.dirname(os.path.dirname(google.__file__)) + versions = os.path.dirname(this_version) + PYTHON_LIB = os.path.dirname(versions) + del google, this_version, versions +else: + PYTHON_LIB = '/base/python_lib' + +installed = {} + + +def SetAllowedModule(_): + pass + + +class UnacceptableVersionError(Exception): + """Raised when a version of a package that is unacceptable is requested.""" + pass + + +def DjangoVersion(): + """Discover the version of Django installed. + + Returns: + A distutils.version.LooseVersion. + """ + import django + return distutils.version.LooseVersion('.'.join(map(str, django.VERSION))) + + +def PylonsVersion(): + """Discover the version of Pylons installed. + + Returns: + A distutils.version.LooseVersion. + """ + import pylons + return distutils.version.LooseVersion(pylons.__version__) + + +PACKAGES = { + 'django': (DjangoVersion, + {'1.0': None, '0.96': None}), + + + + + + + + '_test': (lambda: distutils.version.LooseVersion('1.0'), {'1.0': None}), + '_testpkg': (lambda: distutils.version.LooseVersion('1.0'), + {'1.0': set([('_test', '1.0')])}), + } + + +def EqualVersions(version, baseline): + """Test that a version is acceptable as compared to the baseline. + + Meant to be used to compare version numbers as returned by a package itself + and not user input. + + Args: + version: distutils.version.LooseVersion. + The version that is being checked. + baseline: distutils.version.LooseVersion. + The version that one hopes version compares equal to. + + Returns: + A bool indicating whether the versions are considered equal. + """ + baseline_tuple = baseline.version + truncated_tuple = version.version[:len(baseline_tuple)] + if truncated_tuple == baseline_tuple: + return True + else: + return False + + +def AllowInstalledLibrary(name, desired): + """Allow the use of a package without performing a version check. + + Needed to clear a package's dependencies in case the dependencies need to be + imported in order to perform a version check. The version check is skipped on + the dependencies because the assumption is that the package that triggered + the call would not be installed without the proper dependencies (which might + be a different version than what the package explicitly requires). + + Args: + name: Name of package. + desired: Desired version. + + Raises: + UnacceptableVersion Error if the installed version of a package is + unacceptable. + """ + if name == 'django' and desired != '0.96': + tail = os.path.join('lib', 'django') + sys.path[:] = [dirname + for dirname in sys.path + if not dirname.endswith(tail)] + CallSetAllowedModule(name, desired) + dependencies = PACKAGES[name][1][desired] + if dependencies: + for dep_name, dep_version in dependencies: + AllowInstalledLibrary(dep_name, dep_version) + installed[name] = desired, False + + +def CheckInstalledLibrary(name, desired): + """Check that the library and its dependencies are installed. + + Args: + name: Name of the library that should be installed. + desired: The desired version. + + Raises: + UnacceptableVersionError if the installed version of a package is + unacceptable. + """ + dependencies = PACKAGES[name][1][desired] + if dependencies: + for dep_name, dep_version in dependencies: + AllowInstalledLibrary(dep_name, dep_version) + CheckInstalledVersion(name, desired, explicit=True) + + +def CheckInstalledVersion(name, desired, explicit): + """Check that the installed version of a package is acceptable. + + Args: + name: Name of package. + desired: Desired version string. + explicit: Explicitly requested by the user or implicitly because of a + dependency. + + Raises: + UnacceptableVersionError if the installed version of a package is + unacceptable. + """ + CallSetAllowedModule(name, desired) + find_version = PACKAGES[name][0] + installed_version = find_version() + desired_version = distutils.version.LooseVersion(desired) + if not EqualVersions(installed_version, desired_version): + raise UnacceptableVersionError( + '%s %s was requested, but %s is already in use' % + (name, desired_version, installed_version)) + installed[name] = desired, explicit + + +def CallSetAllowedModule(name, desired): + """Helper to call SetAllowedModule(name), after special-casing Django.""" + if name == 'django' and desired != '0.96': + tail = os.path.join('lib', 'django') + sys.path[:] = [dirname + for dirname in sys.path + if not dirname.endswith(tail)] + SetAllowedModule(name) + + +def CreatePath(name, version): + """Create the path to a package.""" + package_dir = '%s-%s' % (name, version) + return os.path.join(PYTHON_LIB, 'versions', 'third_party', package_dir) + + +def RemoveLibrary(name): + """Remove a library that has been installed.""" + installed_version, _ = installed[name] + path = CreatePath(name, installed_version) + try: + sys.path.remove(path) + except ValueError: + pass + del installed[name] + + +def AddLibrary(name, version, explicit): + """Add a library to sys.path and 'installed'.""" + sys.path.insert(1, CreatePath(name, version)) + installed[name] = version, explicit + + +def InstallLibrary(name, version, explicit=True): + """Install a package. + + If the installation is explicit then the user made the installation request, + not a package as a dependency. Explicit installation leads to stricter + version checking. + + Args: + name: Name of the requested package (already validated as available). + version: The desired version (already validated as available). + explicit: Explicitly requested by the user or implicitly because of a + dependency. + """ + installed_version, explicitly_installed = installed.get(name, [None] * 2) + if name in sys.modules: + if explicit: + CheckInstalledVersion(name, version, explicit=True) + return + elif installed_version: + if version == installed_version: + return + if explicit: + if explicitly_installed: + raise ValueError('%s %s requested, but %s already in use' % + (name, version, installed_version)) + RemoveLibrary(name) + else: + version_ob = distutils.version.LooseVersion(version) + installed_ob = distutils.version.LooseVersion(installed_version) + if version_ob <= installed_ob: + return + else: + RemoveLibrary(name) + AddLibrary(name, version, explicit) + dep_details = PACKAGES[name][1][version] + if not dep_details: + return + for dep_name, dep_version in dep_details: + InstallLibrary(dep_name, dep_version, explicit=False) + + +def use_library(name, version): + """Specify a third-party package to use. + + Args: + name: Name of package to use. + version: Version of the package to use (string). + """ + if name not in PACKAGES: + raise ValueError('%s is not a supported package' % name) + versions = PACKAGES[name][1].keys() + if version not in versions: + raise ValueError('%s is not a supported version for %s; ' + 'supported versions are %s' % (version, name, versions)) + if USING_SDK: + CheckInstalledLibrary(name, version) + else: + InstallLibrary(name, version, explicit=True) + + +if not USING_SDK: + InstallLibrary('django', '0.96', explicit=False)