merge fixes from ronny.
[jelmer/subvertpy.git] / setup.py
index 6e3303361b02c9a01368d7e37a1af3a7b3775380..37a2e2cff379223df3b005037a93e24f630d5969 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
-# Setup file for bzr-svn
-# Copyright (C) 2005-2008 Jelmer Vernooij <jelmer@samba.org>
+# Setup file for subvertpy
+# Copyright (C) 2005-2009 Jelmer Vernooij <jelmer@samba.org>
 
 from distutils.core import setup
 from distutils.extension import Extension
@@ -8,6 +8,7 @@ from distutils.command.install_lib import install_lib
 from distutils import log
 import sys
 import os
+import re
 
 # Build instructions for Windows:
 # * Install the SVN dev kit ZIP for Windows from
@@ -21,21 +22,19 @@ import os
 # * Set SVN_DEV to point at this directory.
 # * Install the APR BDB and INTL packages - see README.txt from the devkit
 # * Set SVN_BDB and SVN_LIBINTL to point at these dirs.
-#
-#  To install into a particular bzr location, use:
-#  % python setup.py install --install-lib=c:\root\of\bazaar
 
 class CommandException(Exception):
     """Encapsulate exit status of apr-config execution"""
     def __init__(self, msg, cmd, arg, status, val):
         self.message = msg % (cmd, val)
-        super(CommandException, self).__init__(self.message)
+        Exception.__init__(self, self.message)
         self.cmd = cmd
         self.arg = arg
         self.status = status
     def not_found(self):
         return os.WIFEXITED(self.status) and os.WEXITSTATUS(self.status) == 127
 
+
 def run_cmd(cmd, arg):
     """Run specified command with given arguments, handling status"""
     f = os.popen("'%s' %s" % (cmd, arg))
@@ -56,11 +55,12 @@ def run_cmd(cmd, arg):
     raise CommandException("%s terminated abnormally (%d)",
                            cmd, arg, status, status)
 
+
 def apr_config(arg):
     apr_config_cmd = os.getenv("APR_CONFIG")
     if apr_config_cmd is None:
-        cmds = ["apr-config", "apr-1-config", "/usr/local/apr/bin/apr-config",
-                "/usr/local/bin/apr-config"]
+        cmds = ["apr-1-config", "/usr/local/apr/bin/apr-1-config", 
+                "/opt/local/bin/apr-1-config", ]
         for cmd in cmds:
             try:
                 res = run_cmd(cmd, arg)
@@ -76,13 +76,14 @@ def apr_config(arg):
         res = run_cmd(apr_config_cmd, arg)
     return res
 
+
 def apr_build_data():
     """Determine the APR header file location."""
     includedir = apr_config("--includedir")
     if not os.path.isdir(includedir):
         raise Exception("APR development headers not found")
-    ldflags = filter(lambda x: x != "", apr_config("--link-ld").split(" "))
-    return (includedir, ldflags)
+    return (includedir,)
+
 
 def svn_build_data():
     """Determine the Subversion header file location."""
@@ -102,13 +103,64 @@ def svn_build_data():
     raise Exception("Subversion development files not found. "
                     "Please set SVN_PREFIX or (SVN_LIBRARY_PATH and SVN_HEADER_PATH) environment variable. ")
 
+def is_keychain_provider_available():
+    """
+    Checks for the availability of the Keychain simple authentication provider in Subversion by compiling a simple test program.
+    """
+    abd = apr_build_data()
+    sbd = svn_build_data()
+    gcc_command_args = ['gcc'] + ['-I' + inc for inc in sbd[0]] + ['-L' + lib for lib in sbd[1]] + ['-I' + abd[0], '-lsvn_subr-1', '-x', 'c', '-']
+    (gcc_in, gcc_out, gcc_err) = os.popen3(gcc_command_args)
+    gcc_in.write("""
+#include <svn_auth.h>
+int main(int argc, const char* arv[]) {
+    svn_auth_get_keychain_simple_provider(NULL, NULL);
+}
+""")
+    gcc_in.close()
+    gcc_out.read()
+    return (gcc_out.close() is None)
+
+class VersionQuery(object):
+    def __init__(self, filename):
+        self.filename = filename
+        f = file(filename, "rU")
+        try:
+            self.text = f.read()
+        finally:
+            f.close()
+
+    def grep(self, what):
+        m = re.search(r"^#define\s+%s\s+(\d+)\s*$" % (what,), self.text, re.MULTILINE)
+        if not m:
+            raise Exception, "Definition for %s was not found in file %s." % (what, self.filename)
+        return int(m.group(1))
+
 # Windows versions - we use environment variables to locate the directories
 # and hard-code a list of libraries.
 if os.name == "nt":
+    def get_apr_version():
+        apr_version_file = os.path.join(os.environ["SVN_DEV"], r"include\apr\apr_version.h")
+        if not os.path.isfile(apr_version_file):
+            raise Exception(
+                "Please check that your SVN_DEV location is correct.\n"
+                "Unable to find required apr\\apr_version.h file.")
+        query = VersionQuery(apr_version_file)
+        return query.grep("APR_MAJOR_VERSION"), query.grep("APR_MINOR_VERSION"), query.grep("APR_PATCH_VERSION")
+
+    def get_svn_version():
+        svn_version_file = os.path.join(os.environ["SVN_DEV"], r"include\svn_version.h")
+        if not os.path.isfile(svn_version_file):
+            raise Exception(
+                "Please check that your SVN_DEV location is correct.\n"
+                "Unable to find required svn_version.h file.")
+        query = VersionQuery(svn_version_file)
+        return query.grep("SVN_VER_MAJOR"), query.grep("SVN_VER_MINOR"), query.grep("SVN_VER_PATCH")
+
     # just clobber the functions above we can't use
     # for simplicitly, everything is done in the 'svn' one
     def apr_build_data():
-        return '.', ''
+        return '.', 
 
     def svn_build_data():
         # environment vars for the directories we need.
@@ -129,10 +181,13 @@ if os.name == "nt":
                 "Please set SVN_LIBINTL to the location of the svn libintl "
                 "packages - see README.txt in the SV_DEV dir")
 
+        svn_version = get_svn_version()
+        apr_version = get_apr_version()
+
         includes = [
             # apr dirs.
             os.path.join(svn_dev_dir, r"include\apr"),
-            os.path.join(svn_dev_dir, r"include\apr-utils"),
+            os.path.join(svn_dev_dir, r"include\apr-util"),
             os.path.join(svn_dev_dir, r"include\apr-iconv"),
             # svn dirs.
             os.path.join(svn_dev_dir, "include"), 
@@ -146,8 +201,14 @@ if os.name == "nt":
             os.path.join(svn_bdb_dir, "lib"),
             os.path.join(svn_libintl_dir, "lib"),
         ]
-        libs = """libapr libapriconv libaprutil libneon
-                  libsvn_subr-1 libsvn_client-1 libsvn_ra-1
+        aprlibs = """libapr libapriconv libaprutil""".split()
+        if apr_version[0] == 1:
+            aprlibs = [aprlib + "-1" for aprlib in aprlibs]
+        elif apr_version[0] > 1:
+            raise Exception(
+                "You have apr version %d.%d.%d.\n"
+                "This setup only knows how to build with 0.*.* or 1.*.*." % apr_version)
+        libs = """libneon libsvn_subr-1 libsvn_client-1 libsvn_ra-1
                   libsvn_ra_dav-1 libsvn_ra_local-1 libsvn_ra_svn-1
                   libsvn_repos-1 libsvn_wc-1 libsvn_delta-1 libsvn_diff-1
                   libsvn_fs-1 libsvn_repos-1 libsvn_fs_fs-1 libsvn_fs_base-1
@@ -155,29 +216,44 @@ if os.name == "nt":
                   libdb44 xml
                   advapi32 shell32 ws2_32 zlibstat
                """.split()
+        if svn_version >= (1,5,0):
+            # Since 1.5.0 libsvn_ra_dav-1 was removed
+            libs.remove("libsvn_ra_dav-1")
 
-        return includes, lib_dirs, libs,
+        return includes, lib_dirs, aprlibs+libs,
 
-(apr_includedir, apr_ldflags) = apr_build_data()
+(apr_includedir, ) = apr_build_data()
 (svn_includedirs, svn_libdirs, extra_libs) = svn_build_data()
 
 def SvnExtension(name, *args, **kwargs):
-    kwargs["include_dirs"] = [apr_includedir] + svn_includedirs
+    kwargs["include_dirs"] = [apr_includedir] + svn_includedirs + ["subvertpy"]
     kwargs["library_dirs"] = svn_libdirs
-    kwargs["extra_link_args"] = apr_ldflags
     if os.name == 'nt':
         # on windows, just ignore and overwrite the libraries!
         kwargs["libraries"] = extra_libs
         # APR needs WIN32 defined.
         kwargs["define_macros"] = [("WIN32", None)]
-    return Extension("bzrlib.plugins.svn.%s" % name, *args, **kwargs)
+    if sys.platform == 'darwin':
+        # on Mac OS X, we need to check for Keychain availability
+        if is_keychain_provider_available():
+            if "define_macros" not in kwargs:
+                kwargs["define_macros"] = []
+            kwargs["define_macros"].extend((('DARWIN', None), ('SVN_KEYCHAIN_PROVIDER_AVAILABLE', '1')))
+    return Extension(name, *args, **kwargs)
+
 
 # On Windows, we install the apr binaries too.
 class install_lib_with_dlls(install_lib):
     def _get_dlls(self):
         # return a list of of (FQ-in-name, relative-out-name) tuples.
         ret = []
-        apr_bins = "libaprutil.dll libapriconv.dll libapr.dll".split()
+        apr_bins = [libname + ".dll" for libname in extra_libs if libname.startswith("libapr")]
+        if get_svn_version() >= (1,5,0):
+            # Since 1.5.0 these libraries became shared
+            apr_bins += """libsvn_client-1.dll libsvn_delta-1.dll libsvn_diff-1.dll
+                           libsvn_fs-1.dll libsvn_ra-1.dll libsvn_repos-1.dll
+                           libsvn_subr-1.dll libsvn_wc-1.dll libsasl.dll""".split()
+        apr_bins += """intl3_svn.dll libdb44.dll libeay32.dll ssleay32.dll""".split()
         look_dirs = os.environ.get("PATH","").split(os.pathsep)
         look_dirs.insert(0, os.path.join(os.environ["SVN_DEV"], "bin"))
     
@@ -185,8 +261,7 @@ class install_lib_with_dlls(install_lib):
             for look in look_dirs:
                 f = os.path.join(look, bin)
                 if os.path.isfile(f):
-                    target = os.path.join(self.install_dir, "bzrlib",
-                                          "plugins", "svn", bin)
+                    target = os.path.join(self.install_dir, "subvertpy", bin)
                     ret.append((f, target))
                     break
             else:
@@ -203,35 +278,44 @@ class install_lib_with_dlls(install_lib):
                 self.copy_file(s, d)
 
     def get_outputs(self):
-        ret = install_lib.get_outputs()
+        ret = install_lib.get_outputs(self)
         if os.name == 'nt':
             ret.extend([info[1] for info in self._get_dlls()])
         return ret
 
-setup(name='bzr-svn',
-      description='Support for Subversion branches in Bazaar',
-      keywords='plugin bzr svn',
-      version='0.4.11',
-      url='http://bazaar-vcs.org/BzrForeignBranches/Subversion',
-      download_url='http://bazaar-vcs.org/BzrSvn',
-      license='GPL',
-      author='Jelmer Vernooij',
-      author_email='jelmer@samba.org',
-      long_description="""
-      This plugin adds support for branching off and 
-      committing to Subversion repositories from 
-      Bazaar.
-      """,
-      package_dir={'bzrlib.plugins.svn':'.', 
-                   'bzrlib.plugins.svn.tests':'tests'},
-      packages=['bzrlib.plugins.svn', 
-                'bzrlib.plugins.svn.mapping3', 
-                'bzrlib.plugins.svn.tests'],
-      ext_modules=[
-          SvnExtension("client", ["client.c", "editor.c", "util.c", "ra.c", "wc.c"], libraries=["svn_client-1", "svn_subr-1"]), 
-          SvnExtension("ra", ["ra.c", "util.c", "editor.c"], libraries=["svn_ra-1", "svn_delta-1", "svn_subr-1"]),
-          SvnExtension("repos", ["repos.c", "util.c"], libraries=["svn_repos-1", "svn_subr-1"]),
-          SvnExtension("wc", ["wc.c", "util.c", "editor.c"], libraries=["svn_wc-1", "svn_subr-1"]),
-          ],
-      cmdclass = { 'install_lib': install_lib_with_dlls },
-      )
+
+def source_path(filename):
+    return os.path.join("subvertpy", filename)
+
+
+def subvertpy_modules(basemodule):
+    return [
+        SvnExtension("%s.client" % basemodule, [source_path(n) for n in "client.c", "editor.c", "util.c", "_ra.c", "wc.c"], libraries=["svn_client-1", "svn_subr-1"]), 
+        SvnExtension("%s._ra" % basemodule, [source_path(n) for n in "_ra.c", "util.c", "editor.c"], libraries=["svn_ra-1", "svn_delta-1", "svn_subr-1"]),
+        SvnExtension("%s.repos" % basemodule, [source_path(n) for n in "repos.c", "util.c"], libraries=["svn_repos-1", "svn_subr-1"]),
+        SvnExtension("%s.wc" % basemodule, [source_path(n) for n in "wc.c", "util.c", "editor.c"], libraries=["svn_wc-1", "svn_subr-1"])
+        ]
+
+
+subvertpy_version = (0, 7, 3)
+subvertpy_version_string = ".".join(map(str, subvertpy_version))
+
+
+if __name__ == "__main__":
+    setup(name='subvertpy',
+          description='Alternative Python bindings for Subversion',
+          keywords='plugin svn',
+          version=subvertpy_version_string,
+          url='http://samba.org/~jelmer/subvertpy',
+          download_url="http://samba.org/~jelmer/subvertpy/subvertpy-%s.tar.gz" % subvertpy_version_string,
+          license='LGPLv2.1 or later',
+          author='Jelmer Vernooij',
+          author_email='jelmer@samba.org',
+          long_description="""
+          Alternative Python bindings for Subversion, split out from bzr-svn. The goal is to have complete, portable and "Pythonic" Python bindings. 
+          """,
+          packages=['subvertpy', 'subvertpy.tests'],
+          ext_modules=subvertpy_modules("subvertpy"),
+          scripts=['bin/subvertpy-fast-export'],
+          cmdclass = { 'install_lib': install_lib_with_dlls },
+          )