Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:maw:bzr
subversion
jelmer-python-bindings.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File jelmer-python-bindings.patch of Package subversion
#! /bin/sh /usr/share/dpatch/dpatch-run ## jelmer-python-bindings by <peter@p12n.org> ## ## DP: Updates to python bindings from Jelmer Vernooij. This is stuff ## DP: he needs for his svn<->bzr bridge, backported from trunk. ## DP: ## DP: Patch was pulled from Ubuntu edgy, then edited rather heavily: ## DP: (a) ported to 1.4.2, (b) removed lots of indentation fixing ## DP: noise, (c) reverted some duplicate adds. @DPATCH@ Index: subversion/bindings/swig/include/apr.swg --- a/subversion/bindings/swig/include/apr.swg +++ b/subversion/bindings/swig/include/apr.swg @@ -146,14 +146,24 @@ /* ----------------------------------------------------------------------- create an OUTPUT argument defn for an apr_hash_t ** which is storing + dirent values +*/ +%typemap(python,in,numinputs=0) apr_hash_t **DIRENTHASH = apr_hash_t **OUTPUT; +%typemap(python,argout,fragment="t_output_helper") apr_hash_t **DIRENTHASH { + $result = t_output_helper($result, + svn_swig_py_convert_hash(*$1, + SWIGTYPE_p_svn_dirent_t, + NULL)); +} + +/* ----------------------------------------------------------------------- + create an OUTPUT argument defn for an apr_hash_t ** which is storing property values */ %typemap(python,in,numinputs=0) apr_hash_t **PROPHASH = apr_hash_t **OUTPUT; -%typemap(python,argout) apr_hash_t **PROPHASH { - /* toss prior result, get new result from the hash */ - Py_DECREF($result); - $result = svn_swig_py_prophash_to_dict(*$1); +%typemap(python,argout,fragment="t_output_helper") apr_hash_t **PROPHASH { + $result = t_output_helper($result, svn_swig_py_prophash_to_dict(*$1)); } %typemap(perl5,in,numinputs=0) apr_hash_t **PROPHASH = apr_hash_t **OUTPUT; Index: subversion/bindings/swig/include/proxy_apr.swg --- a/subversion/bindings/swig/include/proxy_apr.swg +++ b/subversion/bindings/swig/include/proxy_apr.swg @@ -159,6 +159,28 @@ del self._parent_pool if hasattr(self, "_is_valid"): del self._is_valid + + # Clear out any pool-owned references inserted by typemaps + if hasattr(self, "_owned_refs"): + del self._owned_refs + + def _add_owned_ref(self, ref): + """Add a new 'owned' reference -- i.e. a Python object contained in a C + structure allocated in this pool. Used by the typemaps to manage + reference counting semantics.""" + if not hasattr(self, "_owned_refs"): + self._owned_refs = {} + if self._owned_refs.has_key(ref): + self._owned_refs[ref] += 1 + else: + self._owned_refs[ref] = 1 + + def _remove_owned_ref(self, ref): + """Remove an existing 'owned' reference. Also used by typemaps.""" + if hasattr(self, "_owned_refs") and self._owned_refs.has_key(ref): + self._owned_refs[ref] -= 1 + if self._owned_refs[ref] == 0: + del self._owned_refs[ref] def __del__(self): """Automatically destroy memory pools, if necessary""" Index: subversion/bindings/swig/include/svn_types.swg --- a/subversion/bindings/swig/include/svn_types.swg +++ b/subversion/bindings/swig/include/svn_types.swg @@ -444,6 +444,12 @@ svn_swig_rb_set_baton($result, (VALUE)$2); }; +%typemap(python, in) (svn_commit_callback2_t callback, void *callback_baton) +{ + $1 = svn_swig_py_commit_callback2; + $2 = (void *)$input; +} + /* ----------------------------------------------------------------------- Callback: svn_cancel_func_t */ @@ -519,6 +525,29 @@ $1 = svn_swig_rb_make_stream($input); } +%typemap(python, in) (svn_commit_callback_t callback, void *callback_baton) +{ + $1 = svn_swig_py_commit_callback; + $2 = (void *)$input; +} + +/* ----------------------------------------------------------------------- + Mapper to automatically turn Python objects into void* batons on assignment +*/ + +%typemap(python, in) void *PY_AS_VOID (PyObject *newRef) { + newRef = $input; + if ($input == Py_None) { + $1 = newRef = NULL; + } else { + newRef = $input; + $1 = (void *)$input; + } + if (svn_swig_py_pool_set_owned_ref(obj0, (PyObject *)arg1->$1_name, newRef)) { + SWIG_fail; + } +} + /* ----------------------------------------------------------------------- Wrap the digest output for functions populating digests. */ Index: subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c --- a/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c +++ b/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c @@ -104,6 +104,8 @@ static PyObject *_global_svn_swig_py_pool = NULL; static char assertValid[] = "assert_valid"; static char parentPool[] = "_parent_pool"; +static char addOwnedRef[] = "_add_owned_ref"; +static char removeOwnedRef[] = "_remove_owned_ref"; static char wrap[] = "_wrap"; static char unwrap[] = "_unwrap"; static char setParentPool[] = "set_parent_pool"; @@ -166,6 +168,51 @@ return 0; } + +/* Get the parent pool of a proxy object, or return the global application + * pool if one is not set. Returns a BORROWED reference! */ +static PyObject *proxy_get_pool(PyObject *proxy) +{ + PyObject *result; + if (PyObject_HasAttrString(proxy, parentPool)) + { + result = PyObject_GetAttrString(proxy, parentPool); + Py_DECREF(result); + } + else + { + result = _global_svn_swig_py_pool; + } + return result; +} + +/* Change an 'owned reference' allocated in a pool from oldRef to newRef. + * If oldRef is non-NULL and present in the parent pool of proxy, it is removed. + */ +int svn_swig_py_pool_set_owned_ref(PyObject *proxy, PyObject *oldRef, + PyObject *newRef) +{ + PyObject *temp; + PyObject *py_pool = proxy_get_pool(proxy); + + if (oldRef != NULL) + { + temp = PyObject_CallMethod(py_pool, removeOwnedRef, objectTuple, oldRef); + if (temp == NULL) + return 1; + else + Py_DECREF(temp); + } + if (newRef != NULL) + { + temp = PyObject_CallMethod(py_pool, addOwnedRef, objectTuple, newRef); + if (temp == NULL) + return 1; + else + Py_DECREF(temp); + } + return 0; +} /* Wrapper for SWIG_TypeQuery */ #define svn_swig_TypeQuery(x) SWIG_TypeQuery(x) @@ -239,14 +286,9 @@ } Py_DECREF(result); } - if (py_pool != NULL) { - if (PyObject_HasAttrString(input, parentPool)) { - *py_pool = PyObject_GetAttrString(input, parentPool); - Py_DECREF(*py_pool); - } else { - *py_pool = _global_svn_swig_py_pool; - } - } + if (py_pool != NULL) + *py_pool = proxy_get_pool((PyObject *) input); + if (PyObject_HasAttrString(input, unwrap)) { input = PyObject_CallMethod(input, unwrap, emptyTuple); if (input == NULL) { @@ -486,6 +528,52 @@ return convert_hash(hash, convert_svn_string_t, NULL, NULL); } +static PyObject *proparray_to_dict(const apr_array_header_t *array) +{ + PyObject *dict = PyDict_New(); + int i; + + if (dict == NULL) + return NULL; + + for (i = 0; i < array->nelts; ++i) + { + svn_prop_t prop; + PyObject *py_key, *py_value; + + prop = APR_ARRAY_IDX(array, i, svn_prop_t); + + py_key = PyString_FromString(prop.name); + if (py_key == NULL) + goto error; + + if (prop.value == NULL) + { + py_value = Py_None; + Py_INCREF(Py_None); + } + else + { + py_value = PyString_FromStringAndSize((void *)prop.value->data, + prop.value->len); + if (py_value == NULL) + { + Py_DECREF(py_key); + goto error; + } + } + + PyDict_SetItem(dict, py_key, py_value); + } + + return dict; + + error: + Py_DECREF(dict); + return NULL; + +} + PyObject *svn_swig_py_locationhash_to_dict(apr_hash_t *hash) { @@ -552,6 +640,8 @@ DECLARE_SWIG_CONSTRUCTOR(auth_ssl_server_cert_info, svn_auth_ssl_server_cert_info_dup) DECLARE_SWIG_CONSTRUCTOR(info, svn_info_dup) +DECLARE_SWIG_CONSTRUCTOR(commit_info, svn_commit_info_dup) +DECLARE_SWIG_CONSTRUCTOR(wc_notify, svn_wc_dup_notify) static PyObject *convert_log_changed_path(void *value, void *ctx, PyObject *py_pool) @@ -1444,6 +1534,15 @@ return err; } +static svn_error_t * +close_handler_pyio(void *baton) +{ + PyObject *py_io = baton; + Py_DECREF(py_io); + return SVN_NO_ERROR; +} + + svn_stream_t * svn_swig_py_make_stream(PyObject *py_io, apr_pool_t *pool) { @@ -1454,9 +1553,11 @@ * bindings, and we will be finished with the py_io object before we return * to python. I.e. DO NOT STORE AWAY THE RESULTING svn_stream_t * for use * over multiple calls into the bindings. */ + Py_INCREF(py_io); stream = svn_stream_create(py_io, pool); svn_stream_set_read(stream, read_handler_pyio); svn_stream_set_write(stream, write_handler_pyio); + svn_stream_set_close(stream, close_handler_pyio); return stream; } @@ -1504,6 +1605,41 @@ } +void svn_swig_py_notify_func2(void *baton, + const svn_wc_notify_t *notify, + apr_pool_t *pool) +{ + PyObject *function = baton; + PyObject *result; + svn_error_t *err = SVN_NO_ERROR; + + if (function == NULL || function == Py_None) + return; + + svn_swig_py_acquire_py_lock(); + + if ((result = PyObject_CallFunction(function, + (char *)"(O&O&)", + make_ob_wc_notify, notify, + make_ob_pool, pool)) == NULL) + { + err = callback_exception_error(); + } + else + { + /* The callback shouldn't be returning anything. */ + if (result != Py_None) + err = callback_bad_return_error("Not None"); + Py_DECREF(result); + } + + /* Our error has no place to go. :-( */ + if (err) + svn_error_clear(err); + + svn_swig_py_release_py_lock(); +} + void svn_swig_py_status_func(void *baton, const char *path, svn_wc_status_t *status) @@ -2138,3 +2274,377 @@ *cred = creds; return err; } + +/* svn_ra_callbacks_t */ +static svn_error_t * +ra_callbacks_open_tmp_file(apr_file_t **fp, + void *callback_baton, + apr_pool_t *pool) +{ + PyObject *callbacks = (PyObject *)callback_baton; + PyObject *result; + svn_error_t *err = SVN_NO_ERROR; + + svn_swig_py_acquire_py_lock(); + + if ((result = PyObject_CallMethod(callbacks, + "open_tmp_file", + (char *)"O&", + make_ob_pool, pool)) == NULL) + { + err = callback_exception_error(); + } + else if (result == Py_None) + { + *fp = NULL; + } + else + { + *fp = svn_swig_py_make_file(result, pool); + if (*fp == NULL) + { + err = callback_exception_error(); + } + } + + Py_XDECREF(result); + svn_swig_py_release_py_lock(); + return err; +} + +void +svn_swig_py_setup_ra_callbacks(svn_ra_callbacks2_t **callbacks, + void **baton, + PyObject *py_callbacks, + apr_pool_t *pool) +{ + svn_error_t *err = svn_ra_create_callbacks(callbacks, pool); + PyObject *py_auth_baton; + + if (err) + { + svn_swig_py_svn_exception(err); + return; + } + + (*callbacks)->open_tmp_file = ra_callbacks_open_tmp_file; + + py_auth_baton = PyObject_GetAttrString(py_callbacks, "auth_baton"); + + if (svn_swig_ConvertPtrString(py_auth_baton, + (void **)&((*callbacks)->auth_baton), + "svn_auth_baton_t *")) + { + err = type_conversion_error("svn_auth_baton_t *"); + svn_swig_py_svn_exception(err); + Py_DECREF(py_auth_baton); + return; + } + + Py_XDECREF(py_auth_baton); + + *baton = py_callbacks; +} + +svn_error_t *svn_swig_py_commit_callback2(const svn_commit_info_t *commit_info, + void *baton, + apr_pool_t *pool) +{ + PyObject *receiver = baton; + PyObject *result; + svn_error_t *err = SVN_NO_ERROR; + + if ((receiver == NULL) || (receiver == Py_None)) + return SVN_NO_ERROR; + + svn_swig_py_acquire_py_lock(); + + if ((result = PyObject_CallFunction(receiver, + (char *)"O&O&", + make_ob_commit_info, commit_info, + make_ob_pool, pool)) == NULL) + { + err = callback_exception_error(); + } + else + { + if (result != Py_None) + err = callback_bad_return_error("Not None"); + Py_DECREF(result); + } + + svn_swig_py_release_py_lock(); + + return err; +} + +svn_error_t *svn_swig_py_commit_callback(svn_revnum_t new_revision, + const char *date, + const char *author, + void *baton) +{ + PyObject *receiver = baton; + PyObject *result; + svn_error_t *err = SVN_NO_ERROR; + + if ((receiver == NULL) || (receiver == Py_None)) + return SVN_NO_ERROR; + + svn_swig_py_acquire_py_lock(); + + if ((result = PyObject_CallFunction(receiver, + (char *)"lss", + new_revision, date, author)) == NULL) + { + err = callback_exception_error(); + } + else + { + if (result != Py_None) + err = callback_bad_return_error("Not None"); + Py_DECREF(result); + } + + svn_swig_py_release_py_lock(); + + return err; +} + +svn_error_t *svn_swig_py_ra_file_rev_handler_func( + void *baton, + const char *path, + svn_revnum_t rev, + apr_hash_t *rev_props, + svn_txdelta_window_handler_t *delta_handler, + void **delta_baton, + apr_array_header_t *prop_diffs, + apr_pool_t *pool) +{ + PyObject *handler = baton; + PyObject *result, *py_rev_props = NULL, *py_prop_diffs = NULL; + svn_error_t *err = SVN_NO_ERROR; + + if ((handler == NULL) || (handler == Py_None)) + return SVN_NO_ERROR; + + svn_swig_py_acquire_py_lock(); + + py_rev_props = svn_swig_py_prophash_to_dict(rev_props); + if (py_rev_props == NULL) + { + err = type_conversion_error("apr_hash_t *"); + goto error; + } + + py_prop_diffs = proparray_to_dict(prop_diffs); + + if (py_prop_diffs == NULL) + { + err = type_conversion_error("apr_array_header_t *"); + goto error; + } + + if ((result = PyObject_CallFunction(handler, + (char *)"slOOO&", + path, rev, py_rev_props, py_prop_diffs, + make_ob_pool, pool)) == NULL) + { + err = callback_exception_error(); + } + else + { + if (result != Py_None) + err = callback_bad_return_error("Not None"); + + /* FIXME: Support returned TxDeltaWindow object and + * set delta_handler and delta_baton */ + *delta_handler = NULL; + *delta_baton = NULL; + + Py_XDECREF(result); + } + +error: + + Py_XDECREF(py_rev_props); + Py_XDECREF(py_prop_diffs); + + svn_swig_py_release_py_lock(); + + return err; +} + +static svn_error_t *reporter_set_path(void *report_baton, + const char *path, + svn_revnum_t revision, + svn_boolean_t start_empty, + const char *lock_token, + apr_pool_t *pool) +{ + svn_error_t *err = SVN_NO_ERROR; + PyObject *py_reporter = report_baton, *result; + + if (py_reporter == NULL || py_reporter == Py_None) + return SVN_NO_ERROR; + + svn_swig_py_acquire_py_lock(); + + if ((result = PyObject_CallMethod(py_reporter, + (char *)"set_path", + (char *)"slbsO&", + path, revision, + start_empty, lock_token, + make_ob_pool, pool)) == NULL) + { + err = callback_exception_error(); + } + else if (result != Py_None) + { + err = callback_bad_return_error("Not None"); + } + + Py_XDECREF(result); + + svn_swig_py_release_py_lock(); + + return err; +} + +static svn_error_t *reporter_delete_path(void *report_baton, + const char *path, + apr_pool_t *pool) +{ + svn_error_t *err = SVN_NO_ERROR; + PyObject *py_reporter = report_baton, *result; + + if (py_reporter == NULL || py_reporter == Py_None) + return SVN_NO_ERROR; + + svn_swig_py_acquire_py_lock(); + + if ((result = PyObject_CallMethod(py_reporter, + (char *)"delete_path", + (char *)"sO&", + path, + make_ob_pool, pool)) == NULL) + { + err = callback_exception_error(); + } + else if (result != Py_None) + { + err = callback_bad_return_error("Not None"); + } + + Py_XDECREF(result); + + svn_swig_py_release_py_lock(); + + return err; +} + +static svn_error_t *reporter_link_path(void *report_baton, + const char *path, + const char *url, + svn_revnum_t revision, + svn_boolean_t start_empty, + const char *lock_token, + apr_pool_t *pool) +{ + svn_error_t *err = SVN_NO_ERROR; + PyObject *py_reporter = report_baton, *result; + + if (py_reporter == NULL || py_reporter == Py_None) + return SVN_NO_ERROR; + + svn_swig_py_acquire_py_lock(); + + if ((result = PyObject_CallMethod(py_reporter, + (char *)"link_path", + (char *)"sslbsO&", + path, url, revision, + start_empty, lock_token, + make_ob_pool, pool)) == NULL) + { + err = callback_exception_error(); + } + else if (result != Py_None) + { + err = callback_bad_return_error("Not None"); + } + + Py_XDECREF(result); + + svn_swig_py_release_py_lock(); + + return err; +} + +static svn_error_t *reporter_finish_report(void *report_baton, + apr_pool_t *pool) +{ + svn_error_t *err = SVN_NO_ERROR; + + PyObject *py_reporter = report_baton, *result; + + if (py_reporter == NULL || py_reporter == Py_None) + return SVN_NO_ERROR; + + svn_swig_py_acquire_py_lock(); + + if ((result = PyObject_CallMethod(py_reporter, + (char *)"finish_report", + (char *)"O&", + make_ob_pool, pool)) == NULL) + { + err = callback_exception_error(); + } + else if (result != Py_None) + { + err = callback_bad_return_error("Not None"); + } + + Py_XDECREF(result); + + svn_swig_py_release_py_lock(); + + return err; +} + +static svn_error_t *reporter_abort_report(void *report_baton, + apr_pool_t *pool) +{ + svn_error_t *err = SVN_NO_ERROR; + + PyObject *py_reporter = report_baton, *result; + + if (py_reporter == NULL || py_reporter == Py_None) + return SVN_NO_ERROR; + + svn_swig_py_acquire_py_lock(); + + if ((result = PyObject_CallMethod(py_reporter, + (char *)"abort_report", + (char *)"O&", + make_ob_pool, pool)) == NULL) + { + err = callback_exception_error(); + } + else if (result != Py_None) + { + err = callback_bad_return_error("Not None"); + } + + Py_XDECREF(result); + + svn_swig_py_release_py_lock(); + + return err; +} + +const svn_ra_reporter2_t swig_py_ra_reporter2 = { + reporter_set_path, + reporter_delete_path, + reporter_link_path, + reporter_finish_report, + reporter_abort_report +}; Index: subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h --- a/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h +++ b/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h @@ -79,6 +79,9 @@ SVN_SWIG_SWIGUTIL_EXPORT void svn_swig_get_application_pool(PyObject **py_pool, apr_pool_t **pool); +/* Set a Python 'owned' reference on the pool of the given proxy object */ +int svn_swig_py_pool_set_owned_ref(PyObject *proxy, PyObject *oldRef, PyObject *newRef); + /*** SWIG Wrappers ***/ @@ -198,6 +201,11 @@ svn_wc_notify_state_t prop_state, svn_revnum_t revision); +SVN_SWIG_SWIGUTIL_EXPORT +void svn_swig_py_notify_func2(void *baton, + const svn_wc_notify_t *notify, + apr_pool_t *pool); + /* a status function that executes a Python function that is passed in via the baton argument */ SVN_SWIG_SWIGUTIL_EXPORT @@ -256,6 +264,13 @@ const svn_info_t *info, apr_pool_t *pool); +/* thunked info receiver function */ +SVN_SWIG_SWIGUTIL_EXPORT +svn_error_t *svn_swig_py_info_receiver_func(void *py_receiver, + const char *path, + const svn_info_t *info, + apr_pool_t *pool); + /* thunked blame receiver function */ SVN_SWIG_SWIGUTIL_EXPORT svn_error_t *svn_swig_py_client_blame_receiver_func(void *baton, @@ -310,6 +325,45 @@ svn_boolean_t may_save, apr_pool_t *pool); +SVN_SWIG_SWIGUTIL_EXPORT +void +svn_swig_py_setup_ra_callbacks(svn_ra_callbacks2_t **callbacks, + void **baton, + PyObject *py_callbacks, + apr_pool_t *pool); +SVN_SWIG_SWIGUTIL_EXPORT +svn_error_t *svn_swig_py_commit_callback2(const svn_commit_info_t *commit_info, + void *baton, + apr_pool_t *pool); + +SVN_SWIG_SWIGUTIL_EXPORT +svn_error_t *svn_swig_py_commit_callback(svn_revnum_t new_revision, + const char *date, + const char *author, + void *baton); + + +SVN_SWIG_SWIGUTIL_EXPORT +svn_error_t *svn_swig_py_ra_file_rev_handler_func( + void *baton, + const char *path, + svn_revnum_t rev, + apr_hash_t *rev_props, + svn_txdelta_window_handler_t *delta_handler, + void **delta_baton, + apr_array_header_t *prop_diffs, + apr_pool_t *pool); + +SVN_SWIG_SWIGUTIL_EXPORT +extern const svn_ra_reporter2_t swig_py_ra_reporter2; + +SVN_SWIG_SWIGUTIL_EXPORT +void +svn_swig_py_setup_ra_callbacks(svn_ra_callbacks2_t **callbacks, + void **baton, + PyObject *py_callbacks, + apr_pool_t *pool); + #ifdef __cplusplus } #endif /* __cplusplus */ Index: subversion/bindings/swig/python/tests/client.py --- a/subversion/bindings/swig/python/tests/client.py +++ b/subversion/bindings/swig/python/tests/client.py @@ -1,9 +1,9 @@ -import unittest, os +import unittest, os, tempfile, types -from svn import core, repos, fs, delta, client +from svn import core, repos, fs, delta, client, wc from trac.versioncontrol.tests.svn_fs import SubversionRepositoryTestSetup, \ - REPOS_PATH, REPOS_URL + REPOS_PATH from urllib import pathname2url class SubversionRepositoryTestCase(unittest.TestCase): @@ -19,6 +19,7 @@ ] self.client_ctx.auth_baton = core.svn_auth_open(providers) + self.repos_url = "file://" + pathname2url(REPOS_PATH) def info_receiver(self, path, info, pool): """Squirrel away the output from 'svn info' so that the unit tests @@ -26,22 +27,80 @@ self.path = path self.info = info + def test_checkout(self): + """Test svn_client_checkout2.""" + + rev = core.svn_opt_revision_t() + rev.kind = core.svn_opt_revision_head + + path = os.path.join(tempfile.gettempdir(), 'checkout') + + self.assertRaises(ValueError, client.checkout2, + self.repos_url, path, None, None, True, True, + self.client_ctx) + + client.checkout2(self.repos_url, path, rev, rev, True, True, + self.client_ctx) + def test_info(self): """Test scope of get_logs callbacks""" # Run info revt = core.svn_opt_revision_t() revt.kind = core.svn_opt_revision_head - client.info(REPOS_URL, revt, revt, self.info_receiver, + repos_url = "file://" + pathname2url(REPOS_PATH) + client.info(repos_url, revt, revt, self.info_receiver, False, self.client_ctx) # Check output from running info. This also serves to verify that # the internal 'info' object is still valid self.assertEqual(self.path, os.path.basename(REPOS_PATH)) self.info.assert_valid() - self.assertEqual(self.info.URL, REPOS_URL) - self.assertEqual(self.info.repos_root_URL, REPOS_URL) + self.assertEqual(self.info.URL, repos_url) + self.assertEqual(self.info.repos_root_URL, repos_url) + + + def test_uuid_from_url(self): + """Test svn_client_uuid_from_url on a file:// URL""" + self.assert_(isinstance( + client.uuid_from_url(self.repos_url, self.client_ctx), + types.StringTypes)) + def test_url_from_path(self): + """Test svn_client_url_from_path for a file:// URL""" + self.assertEquals(client.url_from_path(self.repos_url), self.repos_url) + + rev = core.svn_opt_revision_t() + rev.kind = core.svn_opt_revision_head + + path = os.path.join(tempfile.gettempdir(), 'url_from_path') + + client.checkout2(self.repos_url, path, rev, rev, True, True, + self.client_ctx) + + self.assertEquals(client.url_from_path(path), self.repos_url) + + def test_uuid_from_path(self): + """Test svn_client_uuid_from_path.""" + rev = core.svn_opt_revision_t() + rev.kind = core.svn_opt_revision_head + + path = os.path.join(tempfile.gettempdir(), 'uuid_from_path') + + client.checkout2(self.repos_url, path, rev, rev, True, True, + self.client_ctx) + + wc_adm = wc.adm_open3(None, path, False, 0, None) + + self.assertEquals(client.uuid_from_path(path, wc_adm, self.client_ctx), + client.uuid_from_url(self.repos_url, self.client_ctx)) + + self.assert_(isinstance(client.uuid_from_path(path, wc_adm, + self.client_ctx), types.StringTypes)) + + def test_open_ra_session(self): + """Test svn_client_open_ra_session().""" + client.open_ra_session(self.repos_url, self.client_ctx) def suite(): return unittest.makeSuite(SubversionRepositoryTestCase, 'test', Index: subversion/bindings/swig/python/tests/ra.py --- a/subversion/bindings/swig/python/tests/ra.py +++ b/subversion/bindings/swig/python/tests/ra.py @@ -0,0 +1,136 @@ +import unittest, os + +from svn import core, repos, fs, delta, client, ra + +from trac.versioncontrol.tests.svn_fs import SubversionRepositoryTestSetup, \ + REPOS_PATH +from urllib import pathname2url + +class SubversionRepositoryTestCase(unittest.TestCase): + """Test cases for the Subversion repository layer""" + + def setUp(self): + """Load a Subversion repository""" + + ra.initialize() + + self.repos_url = "file://" + pathname2url(REPOS_PATH) + + # Open repository directly for cross-checking + self.repos = repos.open(REPOS_PATH) + self.fs = repos.fs(self.repos) + + callbacks = ra.callbacks2_t() + + self.ra_ctx = ra.open2(self.repos_url, callbacks, None, None) + + def test_get_repos_root(self): + root = ra.get_repos_root(self.ra_ctx) + self.assertEqual(root,self.repos_url) + + def test_get_uuid(self): + ra_uuid = ra.get_uuid(self.ra_ctx) + fs_uuid = fs.get_uuid(self.fs) + self.assertEqual(ra_uuid,fs_uuid) + + def test_get_lastest_revnum(self): + ra_revnum = ra.get_latest_revnum(self.ra_ctx) + fs_revnum = fs.youngest_rev(self.fs) + self.assertEqual(ra_revnum,fs_revnum) + + def test_get_dir(self): + (dirents,_,props) = ra.get_dir(self.ra_ctx, '', 1) + self.assert_(dirents.has_key('trunk')) + self.assert_(dirents.has_key('branches')) + self.assert_(dirents.has_key('tags')) + self.assertEqual(dirents['trunk'].kind, core.svn_node_dir) + self.assertEqual(dirents['branches'].kind, core.svn_node_dir) + self.assertEqual(dirents['tags'].kind, core.svn_node_dir) + self.assert_(props.has_key(core.SVN_PROP_ENTRY_UUID)) + self.assert_(props.has_key(core.SVN_PROP_ENTRY_LAST_AUTHOR)) + + (dirents,_,_) = ra.get_dir(self.ra_ctx, 'trunk', 1) + + self.assertEqual(dirents, {}) + + (dirents,_,_) = ra.get_dir(self.ra_ctx, 'trunk', 10) + + self.assert_(dirents.has_key('README2.txt')) + self.assertEqual(dirents['README2.txt'].kind,core.svn_node_file) + + def test_commit(self): + def my_callback(revision, date, author, baton): + self.assertEqual(info.revision, fs.youngest_rev(self.fs)) + + editor, edit_baton = ra.get_commit_editor(self.ra_ctx, "foobar", my_callback, None, False) + root = delta.editor_invoke_open_root(editor, edit_baton, 4) + child = delta.editor_invoke_add_directory(editor, "bla", root, None, 0) + delta.editor_invoke_close_edit(editor, edit_baton) + + def test_commit(self): + def my_callback(revision, date, author): + self.assertEqual(revision, fs.youngest_rev(self.fs)) + + editor, edit_baton = ra.get_commit_editor(self.ra_ctx, "foobar", my_callback, None, False) + root = delta.editor_invoke_open_root(editor, edit_baton, 4) + child = delta.editor_invoke_add_directory(editor, "blah", root, None, 0) + delta.editor_invoke_close_edit(editor, edit_baton) + + def test_commit(self): + def my_callback(revision, date, author): + self.assertEqual(revision, fs.youngest_rev(self.fs)) + + editor, edit_baton = ra.get_commit_editor(self.ra_ctx, "foobar", my_callback, None, False) + root = delta.editor_invoke_open_root(editor, edit_baton, 4) + child = delta.editor_invoke_add_directory(editor, "blah", root, None, 0) + delta.editor_invoke_close_edit(editor, edit_baton) + + def test_get_locations(self): + locations = ra.get_locations(self.ra_ctx, "/trunk/README.txt", 2, range(1,5)) + self.assertEqual(locations, { + 2: '/trunk/README.txt', + 3: '/trunk/README.txt', + 4: '/trunk/README.txt'}) + + def test_get_file_revs(self): + def rev_handler(path, rev, rev_props, prop_diffs, pool): + self.assert_(rev == 2 or rev == 3) + self.assertEqual(path, "/trunk/README.txt") + if rev == 2: + self.assertEqual(rev_props, { + 'svn:log': 'Added README.', + 'svn:author': 'john', + 'svn:date': '2005-04-01T13:12:18.216267Z' + }) + self.assertEqual(prop_diffs, {}) + elif rev == 3: + self.assertEqual(rev_props, { + 'svn:log': 'Fixed README.\n', + 'svn:author': 'kate', + 'svn:date': '2005-04-01T13:24:58.234643Z' + }) + self.assertEqual(prop_diffs, {'svn:mime-type': 'text/plain', 'svn:eol-style': 'native'}) + + ra.get_file_revs(self.ra_ctx, "trunk/README.txt", 0, 10, rev_handler) + + def test_update(self): + class TestEditor(delta.Editor): + pass + + editor = TestEditor() + + e_ptr, e_baton = delta.make_editor(editor) + + reporter, reporter_baton = ra.do_update(self.ra_ctx, 10, "", True, e_ptr, e_baton) + + ra.reporter2_invoke_set_path(reporter, reporter_baton, "", 0, True, None) + + ra.reporter2_invoke_finish_report(reporter, reporter_baton) + +def suite(): + return unittest.makeSuite(SubversionRepositoryTestCase, 'test', + suiteClass=SubversionRepositoryTestSetup) + +if __name__ == '__main__': + runner = unittest.TextTestRunner() + runner.run(suite()) Index: subversion/bindings/swig/python/tests/run_all.py --- a/subversion/bindings/swig/python/tests/run_all.py +++ b/subversion/bindings/swig/python/tests/run_all.py @@ -18,6 +18,8 @@ import pool import repository import client +import ra +import wc import trac.versioncontrol.tests # Run all tests @@ -27,6 +29,8 @@ suite = unittest.TestSuite() suite.addTest(client.suite()) suite.addTest(pool.suite()) + suite.addTest(ra.suite()) + suite.addTest(wc.suite()) suite.addTest(repository.suite()) suite.addTest(trac.versioncontrol.tests.suite()); return suite Index: subversion/bindings/swig/python/tests/wc.py --- a/subversion/bindings/swig/python/tests/wc.py +++ b/subversion/bindings/swig/python/tests/wc.py @@ -0,0 +1,175 @@ +import unittest, os, tempfile +import shutil + +from svn import core, repos, wc, client +from libsvn.core import SubversionException + +from trac.versioncontrol.tests.svn_fs import SubversionRepositoryTestSetup, \ + REPOS_PATH +from urllib import pathname2url + +class SubversionRepositoryTestCase(unittest.TestCase): + """Test cases for the Subversion working copy layer""" + + def setUp(self): + """Load a Subversion repository""" + + self.repos_url = "file://" + pathname2url(REPOS_PATH) + + # Open repository directly for cross-checking + self.repos = repos.open(REPOS_PATH) + self.fs = repos.fs(self.repos) + + self.path = tempfile.mktemp() + + client_ctx = client.create_context() + + rev = core.svn_opt_revision_t() + rev.kind = core.svn_opt_revision_head + + client.checkout2(self.repos_url, self.path, rev, rev, True, True, + client_ctx) + + self.wc = wc.adm_open3(None, self.path, True, -1, None) + + def test_entry(self): + wc_entry = wc.entry(self.path, self.wc, True) + + def test_lock(self): + lock = wc.add_lock(self.path, core.svn_lock_create(core.Pool()), self.wc) + self.assertEqual(True, wc.adm_locked(self.wc)) + self.assertEqual(True, wc.locked(self.path)) + wc.remove_lock(self.path, self.wc) + + def test_version(self): + wc.version() + + def test_access_path(self): + self.assertEqual(self.path, wc.adm_access_path(self.wc)) + + def test_is_adm_dir(self): + self.assert_(wc.is_adm_dir(".svn")) + self.assert_(not wc.is_adm_dir(".foosvn")) + + def test_get_adm_dir(self): + self.assert_(isinstance(wc.get_adm_dir(), basestring)) + + def test_set_adm_dir(self): + self.assertRaises(SubversionException, wc.set_adm_dir, ".foobar") + self.assert_(wc.is_adm_dir(".svn")) + self.assert_(not wc.is_adm_dir("_svn")) + self.assert_(not wc.is_adm_dir(".foobar")) + wc.set_adm_dir("_svn") + self.assert_(wc.is_adm_dir("_svn")) + self.assertEqual("_svn", wc.get_adm_dir()) + wc.set_adm_dir(".svn") + self.assert_(not wc.is_adm_dir("_svn")) + self.assertEqual(".svn", wc.get_adm_dir()) + + def test_init_traversal_info(self): + wc.init_traversal_info() + + def test_crawl_revisions2(self): + infos = [] + set_paths = [] + + def notify(info, pool): + infos.append(info) + + class MyReporter: + def __init__(self): + self._finished_report = False + + def abort_report(self, pool): + pass + + def finish_report(self, pool): + self._finished_report = True + + def set_path(self, path, revision, start_empty, lock_token, pool): + set_paths.append(path) + + def link_path(self, path, url, revision, start_empty, lock_token, + pool): + pass + + def delete_path(self, path, pool): + pass + + # Remove trunk/README.txt + readme_path = os.path.join(self.path, "trunk", "README.txt") + self.assert_(os.path.exists(readme_path)) + os.remove(readme_path) + + # Restore trunk/README.txt using crawl_revision2 + info = wc.init_traversal_info() + reporter = MyReporter() + wc.crawl_revisions2(self.path, self.wc, reporter, + True, True, False, notify, info) + + # Check that the report finished + self.assert_(reporter._finished_report) + self.assertEqual([''], set_paths) + self.assertEqual(1, len(infos)) + + # Check content of infos object + [info] = infos + self.assertEqual(readme_path, info.path) + self.assertEqual(core.svn_node_file, info.kind) + self.assertEqual(-1, info.revision) + + def test_create_notify(self): + wc.create_notify(self.path, wc.notify_add) + + def test_check_wc(self): + self.assert_(wc.check_wc(self.path) > 0) + + def test_get_ancestry(self): + self.assertEqual([self.repos_url, 12], + wc.get_ancestry(self.path, self.wc)) + + def test_status(self): + wc.status2(self.path, self.wc) + + def test_is_normal_prop(self): + self.failIf(wc.is_normal_prop('svn:wc:foo:bar')) + self.failIf(wc.is_normal_prop('svn:entry:foo:bar')) + self.assert_(wc.is_normal_prop('svn:foo:bar')) + self.assert_(wc.is_normal_prop('foreign:foo:bar')) + + def test_is_wc_prop(self): + self.assert_(wc.is_wc_prop('svn:wc:foo:bar')) + self.failIf(wc.is_wc_prop('svn:entry:foo:bar')) + self.failIf(wc.is_wc_prop('svn:foo:bar')) + self.failIf(wc.is_wc_prop('foreign:foo:bar')) + + def test_is_entry_prop(self): + self.assert_(wc.is_entry_prop('svn:entry:foo:bar')) + self.failIf(wc.is_entry_prop('svn:wc:foo:bar')) + self.failIf(wc.is_entry_prop('svn:foo:bar')) + self.failIf(wc.is_entry_prop('foreign:foo:bar')) + + def test_get_pristine_copy_path(self): + self.assertEqual( + wc.get_pristine_copy_path(os.path.join(self.path, 'foo')), + os.path.join(self.path, wc.get_adm_dir(), 'text-base', 'foo.svn-base')) + + def test_get_ignores(self): + self.assert_(isinstance(wc.get_ignores(None, self.wc), list)) + + def test_entries_read(self): + entries = wc.entries_read(self.wc, True) + + self.assertEqual(['', 'tags', 'branches', 'trunk'], entries.keys()) + + def tearDown(self): + wc.adm_close(self.wc) + shutil.rmtree(self.path) + +def suite(): + return unittest.makeSuite(SubversionRepositoryTestCase, 'test', + suiteClass=SubversionRepositoryTestSetup) + +if __name__ == '__main__': + runner = unittest.TextTestRunner() + runner.run(suite()) Index: subversion/bindings/swig/svn_client.i --- a/subversion/bindings/swig/svn_client.i +++ b/subversion/bindings/swig/svn_client.i @@ -25,6 +25,7 @@ #endif %include typemaps.i +%include constraints.i %include svn_global.swg %import core.i @@ -49,6 +50,11 @@ svn_client_ctx_t ** }; +%apply Pointer NONNULL { + const svn_opt_revision_t *revision, + const svn_opt_revision_t *peg_revision +}; + %apply const apr_array_header_t *STRINGLIST { const apr_array_header_t *targets, const apr_array_header_t *diff_options @@ -71,6 +77,16 @@ #ifdef SWIGPYTHON %apply svn_stream_t *WRAPPED_STREAM { svn_stream_t * }; + +/* members of svn_client_ctx_t */ +%apply void *PY_AS_VOID { + void *notify_baton, + void *log_msg_baton, + void *cancel_baton, + void *notify_baton2, + void *log_msg_baton2, + void *progress_baton +}; #endif /* ----------------------------------------------------------------------- @@ -240,6 +256,18 @@ } /* ----------------------------------------------------------------------- + Callback: svn_info_receiver_t + svn_client_info() +*/ + +%typemap(python, in) (svn_info_receiver_t receiver, + void *receiver_baton) { + $1 = svn_swig_py_info_receiver_func; + $2 = (void *)$input; +} + + +/* ----------------------------------------------------------------------- We use 'svn_wc_status_t *' in some custom code, but it isn't in the API anywhere. Thus, SWIG doesn't generate a typemap entry for it. by adding a simple declaration here, SWIG will insert a name for it. @@ -498,6 +526,15 @@ %include svn_time_h.swg %include svn_client_h.swg +#ifdef SWIGPYTHON + +/* provide Python with access to some thunks. */ +%constant svn_cancel_func_t svn_swig_py_cancel_func; +%constant svn_client_get_commit_log2_t svn_swig_py_get_commit_log_func; +%constant svn_wc_notify_func2_t svn_swig_py_notify_func; + +#endif + #ifdef SWIGRUBY %inline %{ static VALUE Index: subversion/bindings/swig/svn_delta.i --- a/subversion/bindings/swig/svn_delta.i +++ b/subversion/bindings/swig/svn_delta.i @@ -47,7 +47,8 @@ const char *error_info, const char *copyfrom_path, const char *copy_path, - const char *base_checksum + const char *base_checksum, + const char *text_checksum }; #ifdef SWIGPYTHON @@ -148,6 +149,17 @@ #endif %} +#ifdef SWIGPYTHON +%inline %{ +svn_error_t *svn_delta_invoke_txdelta_window_handler ( + svn_txdelta_window_handler_t handler, + svn_txdelta_window_t *window, void *baton) { + return handler(window, baton); +} +%} +#endif + + /* ----------------------------------------------------------------------- handle svn_txdelta_window_t::ops */ Index: subversion/bindings/swig/svn_ra.i --- a/subversion/bindings/swig/svn_ra.i +++ b/subversion/bindings/swig/svn_ra.i @@ -25,6 +25,7 @@ #endif %include typemaps.i +%include constraints.i %include svn_global.swg %import apr.swg @@ -49,10 +50,12 @@ const svn_ra_reporter2_t **reporter, void **report_baton, svn_dirent_t **dirent, - svn_lock_t **lock + svn_lock_t **lock, + const svn_delta_editor_t ** }; %apply apr_hash_t **PROPHASH { apr_hash_t **props }; +%apply apr_hash_t **DIRENTHASH { apr_hash_t **dirents }; %apply const char *MAY_BE_NULL { const char *comment, @@ -120,6 +123,11 @@ svn_swig_rb_setup_ra_callbacks(&$1, &$2, $input, _global_pool); } +%typemap(python, in) (const svn_ra_callbacks2_t *callbacks, + void *callback_baton) { + svn_swig_py_setup_ra_callbacks(&$1, &$2, $input, _global_pool); +} + %typemap(perl5, in) apr_hash_t *config { $1 = svn_swig_pl_objs_to_hash_by_name ($input, "svn_config_t *", _global_pool); @@ -142,6 +150,18 @@ $1 = svn_swig_rb_hash_to_apr_hash_revnum($input, _global_pool); } +%typemap(python, in) (svn_ra_file_rev_handler_t handler, void *handler_baton) +{ + $1 = svn_swig_py_ra_file_rev_handler_func; + $2 = (void *)$input; +} + +%typemap(python, in) (const svn_ra_reporter2_t *reporter, void *report_baton) +{ + $1 = (svn_ra_reporter2_t *)&swig_py_ra_reporter2; + $2 = (void *)$input; +} + /* ----------------------------------------------------------------------- */ %{ Index: subversion/bindings/swig/svn_wc.i --- a/subversion/bindings/swig/svn_wc.i +++ b/subversion/bindings/swig/svn_wc.i @@ -226,6 +226,18 @@ } } +%typemap(python, in, numinputs=0) + apr_array_header_t **patterns (apr_array_header_t *temp) +{ + $1 = &temp; +} +%typemap(python, argout, fragment="t_output_helper") + apr_array_header_t **patterns +{ + $result = t_output_helper($result, + svn_swig_py_array_to_list(*$1)); +} + /* ----------------------------------------------------------------------- Callback: svn_wc_notify_func_t svn_client_ctx_t @@ -272,6 +284,11 @@ $2 = $input; /* our function is the baton. */ } +%typemap(python,in) (svn_wc_notify_func2_t notify_func, void *notify_baton) { + $1 = svn_swig_py_notify_func2; + $2 = $input; /* our function is the baton. */ +} + %typemap(perl5,in) (svn_wc_status_func_t status_func, void *status_baton) { $1 = svn_swig_pl_status_func; $2 = $input; /* our function is the baton. */
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor