On Thursday 18 March 2010 03:50:35 pm Роман Донченко wrote:
> Alexey Neyman <stilor_at_att.net> писал в своём письме Thu, 18 Mar 2010
>
> 21:51:53 +0300:
> > On Wednesday 17 March 2010 04:59:34 pm Роман Донченко wrote:
> >> Alexey Neyman <stilor_at_att.net> писал в своём письме Wed, 17 Mar 2010
> >>
> >> 00:05:01 +0300:
> >> > Hi all,
> >> >
> >> > The svn_repos_history2() function allows the history_func() to
> >> > return a special error, SVN_ERR_CEASE_INVOCATION, to stop the
> >> > search. This is not supported in Python bindings, though: attempt
> >> > to return core.SVN_ERR_CEASE_INVOCATION from the history receiver
> >> > results in an exception:
> >> >
> >> > def history_lookup(path, rev, pool):
> >> > return core.SVN_ERR_CEASE_INVOCATION
> >> >
> >> > repos.svn_repos_history2(..., history_lookup, ...)
> >> >
> >> > svn.core.SubversionException: ('Python callback returned an
> >> > invalid object', 20014)
> >> >
> >> > Indeed, svn_swig_py_repos_history_func() only expects a return of
> >> > None. This patch allows the callback to return
> >> > core.SVN_ERR_CEASE_INVOCATION. Currently, this is only used in
> >> > svn_repos_history2() - apparently, it's the only function that
> >> > supports SVN_ERR_CEASE_INVOCATION. However, there is a FIXME at
> >> > least in copyfrom_info_receiver() in libsvn_client/log.c, stating
> >> > that other callbacks may eventually be able to return
> >> > SVN_ERR_CEASE_INVOCATION as well.
> >>
> >> Good idea, but I think that the callback should signal an error the
> >> same way the Subversion functions do it - namely, by throwing
> >> core.SubversionException. The wrapper would then translate the
> >> exception's fields into an svn_error_t. It looks like tweaking
> >> callback_exception_error is the most obvious way to do that. You
> >> don't even have to special-case SVN_ERR_CEASE_INVOCATION, just copy
> >> whatever code the exception had into the error.
> >
> > I think that may be beyond my current knowledge of Python's C API...
> > I tried that:
> >
> > /* Return a Subversion error about a failed callback. */
> > static svn_error_t *callback_exception_error(void)
> > {
> > PyObject *err = PyErr_Occurred();
> > PyObject *svn_module, *exc_class;
> > PyObject *message, *apr_err;
> >
> > if ((svn_module = PyImport_ImportModule((char *)"svn.core")) ==
> > NULL) goto finished;
> > if ((exc_class = PyObject_GetAttrString(svn_module,
> > (char *)"SubversionException")) == NULL)
> > goto finished;
> > if (PyErr_GivenExceptionMatches(exc_class, err))
> > {
> > message = PyObject_GetAttrString(err, (char *)"message");
> > apr_err = PyObject_GetAttrString(err, (char *)"apr_err");
> > if (message && apr_err && PyString_Check(message)
> > && PyInt_Check(apr_err))
> > {
> > return svn_error_create(PyInt_AsLong(apr_err), NULL,
> > PyString_AsString(message));
> > }
> > }
> >
> > finished:
> > return svn_error_create(SVN_ERR_SWIG_PY_EXCEPTION_SET, NULL,
> > "Python callback raised an exception");
> > }
> >
> > First, it cannot find "apr_err" in the instance of
> > core.Subversion_Exception; PyObject_GetAttrString(err, (char
> > *)"apr_err") returns NULL.
> >
> > And, it produces the following error:
> >
> > SystemError: NULL result without error in PyObject_Call
> >
> > Can you help? What's wrong with that code?
>
> Hmm. How are you testing this? I'd write a test script, but I'm short
> on time, and you probably already have one. 8=]
Yes, please use the attached pre-commit script. Then:
$ svnadmin create /tmp/c.repo
$ cp <...this attachment...> /tmp/c.repo/hooks/pre-commit
$ svn mkdir -m "1" file:///tmp/c.repo/trunk
$ svn cp -m "2" file:///tmp/c.repo/trunk file:///tmp/c.repo/copied-dir
$ svn mkdir -m "3" file:///tmp/c.repo/copied-dir/newdir
With stock 1.6.6, it produces the following traceback:
-------------------------------------------------------------------------
svn: Commit blocked by pre-commit hook (exit code 1) with output:
Traceback (most recent call last):
File "/tmp/c.repo/hooks/pre-commit", line 35, in <module>
core.run_app(verify, sys.argv[1], sys.argv[2])
File "/usr/local/lib/svn-python/svn/core.py", line 281, in run_app
return func(application_pool, *args, **kw)
File "/tmp/c.repo/hooks/pre-commit", line 31, in verify
repos.svn_repos_replay2(txn_root, "", -1, True, e_ptr, e_baton, None,
pool)
File "/usr/local/lib/svn-python/libsvn/repos.py", line 311, in
svn_repos_replay2
return apply(_repos.svn_repos_replay2, args)
File "/tmp/c.repo/hooks/pre-commit", line 22, in open_directory
repos.svn_repos_history2(self.fs_ptr, path, history_lookup, None, 0,
self.base_rev, True, self.pool)
File "/usr/local/lib/svn-python/libsvn/repos.py", line 407, in
svn_repos_history2
return apply(_repos.svn_repos_history2, args)
File "/tmp/c.repo/hooks/pre-commit", line 21, in history_lookup
raise core.SubversionException(apr_err=core.SVN_ERR_CEASE_INVOCATION,
message="Hi from history_lookup")
svn.core.SubversionException: ('Hi from history_lookup', 200021)
-------------------------------------------------------------------------
Changed to the following code (difference from previous version is that it
Py_DECREF's everything):
-------------------------------------------------------------------------
static svn_error_t *callback_exception_error(void)
{
PyObject *err = PyErr_Occurred();
PyObject *svn_module = NULL, *exc_class = NULL;
PyObject *message = NULL, *apr_err = NULL;
svn_error_t *rv = NULL;
if ((svn_module = PyImport_ImportModule((char *)"svn.core")) == NULL)
goto finished;
if ((exc_class = PyObject_GetAttrString(svn_module,
(char *)"SubversionException")) == NULL)
goto finished;
if (PyErr_GivenExceptionMatches(exc_class, err))
{
apr_err = PyObject_GetAttrString(err, (char *)"apr_err");
message = PyObject_GetAttrString(err, (char *)"message");
if (message && apr_err && PyString_Check(message) &&
PyInt_Check(apr_err))
rv = svn_error_create(PyInt_AsLong(apr_err), NULL,
PyString_AsString(message));
}
finished:
Py_XDECREF(svn_module);
Py_XDECREF(exc_class);
Py_XDECREF(apr_err);
Py_XDECREF(message);
return rv ? rv : svn_error_create(SVN_ERR_SWIG_PY_EXCEPTION_SET, NULL,
"Python callback raised an exception");
}
-------------------------------------------------------------------------
With this, pre-commit produces this traceback:
-------------------------------------------------------------------------
svn: Commit blocked by pre-commit hook (exit code 1) with output:
Traceback (most recent call last):
File "/tmp/c.repo/hooks/pre-commit", line 35, in <module>
core.run_app(verify, sys.argv[1], sys.argv[2])
File "/usr/local/lib/svn-python/svn/core.py", line 281, in run_app
return func(application_pool, *args, **kw)
File "/tmp/c.repo/hooks/pre-commit", line 31, in verify
repos.svn_repos_replay2(txn_root, "", -1, True, e_ptr, e_baton, None,
pool)
File "/usr/local/lib/svn-python/libsvn/repos.py", line 311, in
svn_repos_replay2
return apply(_repos.svn_repos_replay2, args)
SystemError: NULL result without error in PyObject_Call
-------------------------------------------------------------------------
Hope that helps.
Regards,
Alexey.
Received on 2010-03-19 00:26:59 CET