Alexey Neyman <sti...@att.net> писал в своём письме Fri, 19 Mar 2010 02:26:28 +0300:

...

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
-------------------------------------------------------------------------

OK, I think I got it. It couldn't find "apr_err", because PyErr_Occurred returns the exception _type_, and I'm pretty sure that the SystemError is due to not clearing the exception (although I don't know for sure, since I switched to PyErr_Fetch, and that automatically clears it). Please test with this version, which works for me:

static svn_error_t *callback_exception_error(void)
{
  PyObject *svn_module = NULL, *svn_exc = NULL;
  PyObject *message = NULL, *apr_err = NULL;
  PyObject *exc, *exc_type, *exc_traceback;
  svn_error_t *rv = NULL;

  PyErr_Fetch(&exc_type, &exc, &exc_traceback);

  if ((svn_module = PyImport_ImportModule("svn.core")) == NULL)
    goto finished;
  if ((svn_exc = PyObject_GetAttrString(svn_module, "SubversionException"))
      == NULL)
    goto finished;

  if (PyErr_GivenExceptionMatches(exc_type, svn_exc))
    {
      Py_DECREF(exc_type);
      Py_DECREF(exc_traceback);
    }
  else
    {
      PyErr_Restore(exc_type, exc, exc_traceback);
      goto finished;
    }

  if ((apr_err = PyObject_GetAttrString(exc, "apr_err")) == NULL)
    goto finished;
  if ((message = PyObject_GetAttrString(exc, "message")) == NULL)
    goto finished;

  Py_DECREF(exc);

  /* A possible improvement here would be to convert the whole
     SubversionException chain. */
  if (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(svn_exc);
  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");
}

Cheers,
Roman.

Reply via email to