2 # Setup file for subvertpy
3 # Copyright (C) 2005-2008 Jelmer Vernooij <jelmer@samba.org>
5 from distutils.core import setup
6 from distutils.extension import Extension
7 from distutils.command.install_lib import install_lib
8 from distutils import log
13 # Build instructions for Windows:
14 # * Install the SVN dev kit ZIP for Windows from
15 # http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91
16 # At time of writing, this was svn-win32-1.4.6_dev.zip
17 # * Find the SVN binary ZIP file with the binaries for your dev kit.
18 # At time of writing, this was svn-win32-1.4.6.zip
19 # Unzip this in the *same directory* as the dev kit - README.txt will be
20 # overwritten, but that is all. This is the default location the .ZIP file
21 # will suggest (ie, the directory embedded in both .zip files are the same)
22 # * Set SVN_DEV to point at this directory.
23 # * Install the APR BDB and INTL packages - see README.txt from the devkit
24 # * Set SVN_BDB and SVN_LIBINTL to point at these dirs.
26 # To install into a particular bzr location, use:
27 # % python setup.py install --install-lib=c:\root\of\bazaar
29 class CommandException(Exception):
30 """Encapsulate exit status of apr-config execution"""
31 def __init__(self, msg, cmd, arg, status, val):
32 self.message = msg % (cmd, val)
33 Exception.__init__(self, self.message)
38 return os.WIFEXITED(self.status) and os.WEXITSTATUS(self.status) == 127
41 def run_cmd(cmd, arg):
42 """Run specified command with given arguments, handling status"""
43 f = os.popen("'%s' %s" % (cmd, arg))
44 dir = f.read().rstrip("\n")
48 if os.WIFEXITED(status):
49 code = os.WEXITSTATUS(status)
52 raise CommandException("%s exited with status %d",
53 cmd, arg, status, code)
54 if os.WIFSIGNALED(status):
55 signal = os.WTERMSIG(status)
56 raise CommandException("%s killed by signal %d",
57 cmd, arg, status, signal)
58 raise CommandException("%s terminated abnormally (%d)",
59 cmd, arg, status, status)
63 apr_config_cmd = os.getenv("APR_CONFIG")
64 if apr_config_cmd is None:
65 cmds = ["apr-1-config", "/usr/local/apr/bin/apr-1-config",
66 "/opt/local/bin/apr-1-config", ]
69 res = run_cmd(cmd, arg)
72 except CommandException, e:
76 raise Exception("apr-config not found."
77 " Please set APR_CONFIG environment variable")
79 res = run_cmd(apr_config_cmd, arg)
84 """Determine the APR header file location."""
85 includedir = apr_config("--includedir")
86 if not os.path.isdir(includedir):
87 raise Exception("APR development headers not found")
92 """Determine the Subversion header file location."""
93 if "SVN_HEADER_PATH" in os.environ and "SVN_LIBRARY_PATH" in os.environ:
94 return ([os.getenv("SVN_HEADER_PATH")], [os.getenv("SVN_LIBRARY_PATH")], [])
95 svn_prefix = os.getenv("SVN_PREFIX")
96 if svn_prefix is None:
97 basedirs = ["/usr/local", "/usr"]
98 for basedir in basedirs:
99 includedir = os.path.join(basedir, "include/subversion-1")
100 if os.path.isdir(includedir):
103 if svn_prefix is not None:
104 return ([os.path.join(svn_prefix, "include/subversion-1")],
105 [os.path.join(svn_prefix, "lib")], [])
106 raise Exception("Subversion development files not found. "
107 "Please set SVN_PREFIX or (SVN_LIBRARY_PATH and SVN_HEADER_PATH) environment variable. ")
109 def is_keychain_provider_available():
111 Checks for the availability of the Keychain simple authentication provider in Subversion by compiling a simple test program.
113 abd = apr_build_data()
114 sbd = svn_build_data()
115 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', '-']
116 (gcc_in, gcc_out, gcc_err) = os.popen3(gcc_command_args)
118 #include <svn_auth.h>
119 int main(int argc, const char* arv[]) {
120 svn_auth_get_keychain_simple_provider(NULL, NULL);
125 return (gcc_out.close() is None)
127 class VersionQuery(object):
128 def __init__(self, filename):
129 self.filename = filename
130 f = file(filename, "rU")
136 def grep(self, what):
137 m = re.search(r"^#define\s+%s\s+(\d+)\s*$" % (what,), self.text, re.MULTILINE)
139 raise Exception, "Definition for %s was not found in file %s." % (what, self.filename)
140 return int(m.group(1))
142 # Windows versions - we use environment variables to locate the directories
143 # and hard-code a list of libraries.
145 def get_apr_version():
146 apr_version_file = os.path.join(os.environ["SVN_DEV"], r"include\apr\apr_version.h")
147 if not os.path.isfile(apr_version_file):
149 "Please check that your SVN_DEV location is correct.\n"
150 "Unable to find required apr\\apr_version.h file.")
151 query = VersionQuery(apr_version_file)
152 return query.grep("APR_MAJOR_VERSION"), query.grep("APR_MINOR_VERSION"), query.grep("APR_PATCH_VERSION")
154 def get_svn_version():
155 svn_version_file = os.path.join(os.environ["SVN_DEV"], r"include\svn_version.h")
156 if not os.path.isfile(svn_version_file):
158 "Please check that your SVN_DEV location is correct.\n"
159 "Unable to find required svn_version.h file.")
160 query = VersionQuery(svn_version_file)
161 return query.grep("SVN_VER_MAJOR"), query.grep("SVN_VER_MINOR"), query.grep("SVN_VER_PATCH")
163 # just clobber the functions above we can't use
164 # for simplicitly, everything is done in the 'svn' one
165 def apr_build_data():
168 def svn_build_data():
169 # environment vars for the directories we need.
170 svn_dev_dir = os.environ.get("SVN_DEV")
171 if not svn_dev_dir or not os.path.isdir(svn_dev_dir):
173 "Please set SVN_DEV to the location of the svn development "
174 "packages.\nThese can be downloaded from:\n"
175 "http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91")
176 svn_bdb_dir = os.environ.get("SVN_BDB")
177 if not svn_bdb_dir or not os.path.isdir(svn_bdb_dir):
179 "Please set SVN_BDB to the location of the svn BDB packages "
180 "- see README.txt in the SV_DEV dir")
181 svn_libintl_dir = os.environ.get("SVN_LIBINTL")
182 if not svn_libintl_dir or not os.path.isdir(svn_libintl_dir):
184 "Please set SVN_LIBINTL to the location of the svn libintl "
185 "packages - see README.txt in the SV_DEV dir")
187 svn_version = get_svn_version()
188 apr_version = get_apr_version()
192 os.path.join(svn_dev_dir, r"include\apr"),
193 os.path.join(svn_dev_dir, r"include\apr-utils"),
194 os.path.join(svn_dev_dir, r"include\apr-iconv"),
196 os.path.join(svn_dev_dir, "include"),
199 os.path.join(svn_dev_dir, "lib"),
200 os.path.join(svn_dev_dir, "lib", "apr"),
201 os.path.join(svn_dev_dir, "lib", "apr-iconv"),
202 os.path.join(svn_dev_dir, "lib", "apr-util"),
203 os.path.join(svn_dev_dir, "lib", "neon"),
204 os.path.join(svn_bdb_dir, "lib"),
205 os.path.join(svn_libintl_dir, "lib"),
207 aprlibs = """libapr libapriconv libaprutil""".split()
208 if apr_version[0] == 1:
209 aprlibs = [aprlib + "-1" for aprlib in aprlibs]
210 elif apr_version[0] > 1:
212 "You have apr version %d.%d.%d.\n"
213 "This setup only knows how to build with 0.*.* or 1.*.*." % apr_version)
214 libs = """libneon libsvn_subr-1 libsvn_client-1 libsvn_ra-1
215 libsvn_ra_dav-1 libsvn_ra_local-1 libsvn_ra_svn-1
216 libsvn_repos-1 libsvn_wc-1 libsvn_delta-1 libsvn_diff-1
217 libsvn_fs-1 libsvn_repos-1 libsvn_fs_fs-1 libsvn_fs_base-1
220 advapi32 shell32 ws2_32 zlibstat
222 if svn_version >= (1,5,0):
223 # Since 1.5.0 libsvn_ra_dav-1 was removed
224 libs.remove("libsvn_ra_dav-1")
226 return includes, lib_dirs, aprlibs+libs,
228 (apr_includedir, ) = apr_build_data()
229 (svn_includedirs, svn_libdirs, extra_libs) = svn_build_data()
231 def SvnExtension(name, *args, **kwargs):
232 kwargs["include_dirs"] = [apr_includedir] + svn_includedirs
233 kwargs["library_dirs"] = svn_libdirs
235 # on windows, just ignore and overwrite the libraries!
236 kwargs["libraries"] = extra_libs
237 # APR needs WIN32 defined.
238 kwargs["define_macros"] = [("WIN32", None)]
239 if sys.platform == 'darwin':
240 # on Mac OS X, we need to check for Keychain availability
241 if is_keychain_provider_available():
242 if "define_macros" not in kwargs:
243 kwargs["define_macros"] = []
244 kwargs["define_macros"].extend((('DARWIN', None), ('SVN_KEYCHAIN_PROVIDER_AVAILABLE', '1')))
245 return Extension(name, *args, **kwargs)
248 # On Windows, we install the apr binaries too.
249 class install_lib_with_dlls(install_lib):
251 # return a list of of (FQ-in-name, relative-out-name) tuples.
253 apr_bins = [libname + ".dll" for libname in extra_libs if libname.startswith("libapr")]
254 if get_svn_version() >= (1,5,0):
255 # Since 1.5.0 these libraries became shared
256 apr_bins += """libsvn_client-1.dll libsvn_delta-1.dll libsvn_diff-1.dll
257 libsvn_fs-1.dll libsvn_ra-1.dll libsvn_repos-1.dll
258 libsvn_subr-1.dll libsvn_wc-1.dll libsasl.dll""".split()
259 apr_bins += """intl3_svn.dll libdb44.dll libeay32.dll ssleay32.dll""".split()
260 look_dirs = os.environ.get("PATH","").split(os.pathsep)
261 look_dirs.insert(0, os.path.join(os.environ["SVN_DEV"], "bin"))
264 for look in look_dirs:
265 f = os.path.join(look, bin)
266 if os.path.isfile(f):
267 target = os.path.join(self.install_dir, "bzrlib",
268 "plugins", "svn", bin)
269 ret.append((f, target))
272 log.warn("Could not find required DLL %r to include", bin)
273 log.debug("(looked in %s)", look_dirs)
277 install_lib.run(self)
280 # On Windows we package up the apr dlls with the plugin.
281 for s, d in self._get_dlls():
284 def get_outputs(self):
285 ret = install_lib.get_outputs()
287 ret.extend([info[1] for info in self._get_dlls()])
291 def source_path(filename):
292 source_code_dir = os.path.dirname(__file__)
293 return os.path.join(source_code_dir, "subvertpy", filename)
296 def subvertpy_modules(basemodule):
298 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"]),
299 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"]),
300 SvnExtension("%s.repos" % basemodule, [source_path(n) for n in "repos.c", "util.c"], libraries=["svn_repos-1", "svn_subr-1"]),
301 SvnExtension("%s.wc" % basemodule, [source_path(n) for n in "wc.c", "util.c", "editor.c"], libraries=["svn_wc-1", "svn_subr-1"])
305 subvertpy_version = (0, 6, 0)
306 subvertpy_version_string = ".".join(map(str, subvertpy_version))
309 if __name__ == "__main__":
310 setup(name='subvertpy',
311 description='Alternative Python bindings for Subversion',
312 keywords='plugin svn',
313 version=subvertpy_version_string,
314 url='http://samba.org/~jelmer/subvertpy',
315 download_url="http://samba.org/~jelmer/subvertpy/subvertpy-%s.tar.gz" % subvertpy_version_string,
316 license='GPLv2 or later',
317 author='Jelmer Vernooij',
318 author_email='jelmer@samba.org',
320 Alternative Python bindings for Subversion, split out from bzr-svn. The goal is to have complete, portable and "Pythonic" Python bindings.
322 packages=['subvertpy', 'subvertpy.tests'],
323 ext_modules=subvertpy_modules("subvertpy"),
324 cmdclass = { 'install_lib': install_lib_with_dlls },