Index: subversion/bindings/swig/include/svn_types.swg =================================================================== --- subversion/bindings/swig/include/svn_types.swg (revision 1880203) +++ subversion/bindings/swig/include/svn_types.swg (working copy) @@ -427,6 +427,10 @@ Specify how svn_error_t returns are turned into exceptions. */ #ifdef SWIGPYTHON +%{ +#define svn_error_t_with_attrs svn_error_t +%} + %typemap(out) svn_error_t * { if ($1 != NULL) { if ($1->apr_err != SVN_ERR_SWIG_PY_EXCEPTION_SET) @@ -438,6 +442,10 @@ Py_INCREF(Py_None); $result = Py_None; } + +%typemap(out) svn_error_t_with_attrs * (svn_error_t * _global_err) { + _global_err = $1; +} #endif #ifdef SWIGPERL Index: subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c =================================================================== --- subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c (revision 1880203) +++ subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c (working copy) @@ -411,10 +411,11 @@ /*** Custom SubversionException stuffs. ***/ -void svn_swig_py_svn_exception(svn_error_t *error_chain) +void svn_swig_py_build_svn_exception( + PyObject **exc_class, PyObject **exc_ob,svn_error_t *error_chain) { PyObject *args_list, *args, *apr_err_ob, *message_ob, *file_ob, *line_ob; - PyObject *svn_module, *exc_class, *exc_ob; + PyObject *svn_module; svn_error_t *err; if (error_chain == NULL) @@ -422,7 +423,7 @@ /* Start with no references. */ args_list = args = apr_err_ob = message_ob = file_ob = line_ob = NULL; - svn_module = exc_class = exc_ob = NULL; + svn_module = *exc_class = *exc_ob = NULL; if ((args_list = PyList_New(0)) == NULL) goto finished; @@ -481,16 +482,13 @@ /* Create the exception object chain. */ if ((svn_module = PyImport_ImportModule((char *)"svn.core")) == NULL) goto finished; - if ((exc_class = PyObject_GetAttrString(svn_module, - (char *)"SubversionException")) == NULL) - goto finished; - if ((exc_ob = PyObject_CallMethod(exc_class, (char *)"_new_from_err_list", - (char *)"O", args_list)) == NULL) - goto finished; + if ((*exc_class = PyObject_GetAttrString(svn_module, + (char *)"SubversionException")) != NULL) + { + *exc_ob = PyObject_CallMethod(*exc_class, (char *)"_new_from_err_list", + (char *)"O", args_list); + } - /* Raise the exception. */ - PyErr_SetObject(exc_class, exc_ob); - finished: /* Release any references. */ Py_XDECREF(args_list); @@ -500,6 +498,18 @@ Py_XDECREF(file_ob); Py_XDECREF(line_ob); Py_XDECREF(svn_module); +} + +void svn_swig_py_svn_exception(svn_error_t *error_chain) +{ + PyObject *exc_class, *exc_ob; + + svn_swig_py_build_svn_exception(&exc_class, &exc_ob, error_chain); + /* Raise the exception. */ + if (exc_class != NULL && exc_ob != NULL) + { + PyErr_SetObject(exc_class, exc_ob); + } Py_XDECREF(exc_class); Py_XDECREF(exc_ob); } Index: subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h =================================================================== --- subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h (revision 1880203) +++ subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h (working copy) @@ -101,6 +101,11 @@ /*** Functions to expose a custom SubversionException ***/ +/* get a subversion exception class object and its instance built from + error_chain but not raise immediately. cunsume the error. */ +void svn_swig_py_build_svn_exception( + PyObject **exc_class, PyObject **exc_ob, svn_error_t *error_chain); + /* raise a subversion exception, created from a normal subversion error. consume the error. */ void svn_swig_py_svn_exception(svn_error_t *err); Index: subversion/bindings/swig/svn_fs.i =================================================================== --- subversion/bindings/swig/svn_fs.i (revision 1880203) +++ subversion/bindings/swig/svn_fs.i (working copy) @@ -104,12 +104,60 @@ FIXME: Do the Perl and Ruby bindings need to do something similar? */ #ifdef SWIGPYTHON -%typemap(argout) (const char **conflict_p, svn_revnum_t *new_rev) { - /* this is always Py_None */ - Py_DECREF($result); - /* build the result tuple */ - $result = Py_BuildValue("zi", *$1, (long)*$2); +%typemap(argout) (const char **conflict_p, svn_revnum_t *new_rev) + (PyObject *exc_class, PyObject *exc_ob, + PyObject* conflict_ob, PyObject* rev_ob) { + if (_global_err != NULL) + { + if (_global_err->apr_err == SVN_ERR_SWIG_PY_EXCEPTION_SET) + { + svn_error_clear(_global_err); + } + else + { + svn_swig_py_build_svn_exception(&exc_class, &exc_ob, _global_err); + if (*$1 == NULL) + { + Py_INCREF(Py_None); + conflict_ob = Py_None; + } + else + { + conflict_ob = PyBytes_FromString((const char *)*$1); + } + PyObject_SetAttrString(exc_ob, "conflict_p", conflict_ob); + rev_ob = PyInt_FromLong((long)*$2); + PyObject_SetAttrString(exc_ob, "new_rev", rev_ob); + /* Raise the exception. */ + PyErr_SetObject(exc_class, exc_ob); + Py_XDECREF(exc_class); + Py_XDECREF(exc_ob); + Py_DECREF(conflict_ob); + Py_DECREF(rev_ob); + SWIG_fail; + } + $result = NULL; + } + else + { + /* build the result tuple */ + $result = Py_BuildValue( +%#if PY_VERSION_HEX >= 0x03000000 + "yi", +%#else + "zi", +%#endif + *$1, (long)*$2); + } } + +svn_error_t_with_attrs * +svn_fs_commit_txn(const char **conflict_p, + svn_revnum_t *new_rev, + svn_fs_txn_t *txn, + apr_pool_t *pool); +%ignore svn_fs_commit_txn; + #endif /* Ruby fixups for functions not following the pool convention. */ Index: subversion/bindings/swig/svn_repos.i =================================================================== --- subversion/bindings/swig/svn_repos.i (revision 1880203) +++ subversion/bindings/swig/svn_repos.i (working copy) @@ -109,6 +109,75 @@ #endif /* ----------------------------------------------------------------------- + Fix the return value for svn_repos_fs_commit_txn(). If the conflict + result is NULL, then %append_output() is passed Py_None, but that goofs + up because that is *also* the marker for "I haven't started assembling + a multi-valued return yet" which means the second return value + (new_rev) will not cause a 2-tuple to be manufactured. + + The answer is to explicitly create a 2-tuple return value. + + FIXME: Do the Perl and Ruby bindings need to do something similar? +*/ +#ifdef SWIGPYTHON +%typemap(argout) (const char **conflict_p, svn_repos_t *repos, + svn_revnum_t *new_rev) + (PyObject *exc_class, PyObject *exc_ob, + PyObject* conflict_ob, PyObject* rev_ob) { + if (_global_err != NULL) + { + if (_global_err->apr_err == SVN_ERR_SWIG_PY_EXCEPTION_SET) + { + svn_error_clear(_global_err); + } + else + { + svn_swig_py_build_svn_exception(&exc_class, &exc_ob, _global_err); + if (*$1 == NULL) + { + Py_INCREF(Py_None); + conflict_ob = Py_None; + } + else + { + conflict_ob = PyBytes_FromString((const char *)*$1); + } + PyObject_SetAttrString(exc_ob, "conflict_p", conflict_ob); + rev_ob = PyInt_FromLong((long)*$3); + PyObject_SetAttrString(exc_ob, "new_rev", rev_ob); + /* Raise the exception. */ + PyErr_SetObject(exc_class, exc_ob); + Py_XDECREF(exc_class); + Py_XDECREF(exc_ob); + Py_DECREF(conflict_ob); + Py_DECREF(rev_ob); + SWIG_fail; + } + $result = NULL; + } + else + { + /* build the result tuple */ + $result = Py_BuildValue( +%#if PY_VERSION_HEX >= 0x03000000 + "yi", +%#else + "zi", +%#endif + *$1, (long)*$3); + } +} + +svn_error_t_with_attrs * +svn_repos_fs_commit_txn(const char **conflict_p, + svn_repos_t *repos, + svn_revnum_t *new_rev, + svn_fs_txn_t *txn, + apr_pool_t *pool); +%ignore svn_repos_fs_commit_txn; + +#endif +/* ----------------------------------------------------------------------- handle svn_repos_get_committed_info(). */ #ifdef SWIGRUBY