Revision 5137 committed a workaround for what appears to be a problem
with our Python SWIG bindings. I'm describing it here in the hopes
that someone with more experience will say "Oh, yes, you just need to
do *this* and it will work the way you expect."
The problem is described in this comment in cvs2svn.py:
def _commit_internal(txn):
### FIXME:
#
# There's some disagreement between C and Python as to how the
# return parameters from commit_txn() are to be handled.
#
# In C, svn_fs_commit_txn() returns two parameters by reference:
# conflict_p and new_rev. If there is no conflict, then
# *conflict_p is set to NULL.
#
# In Python, the equivalent would be for fs.commit_txn(txn) to
# return a sequence. For example, if the commit results in new
# revision 3, then
#
# conflict, new_rev = fs.commit_txn(txn)
#
# should return (None, 3), setting conflict and new_rev to those
# values respectively.
#
# However, that's not what happens. Looking at the generated
# file subversion/bindings/swig/python/svn_fs.c, you can see
# that in a successful commit, _wrap_svn_fs_commit_txn() calls
# t_output_helper() twice in succession: the first time to
# stuff the conflict information ('arg1') into the Python
# resultobj, the second time to append the new revision ('arg2')
# onto that resultobj.
#
# The conflict information is NULL, of course, which gets
# converted to None by SWIG_NewPointerObj() before it is passed
# to t_output_helper(). The problem is that t_output_helper()
# is a bit lazy about how it uses None. It seems it can't
# distinguish between "there's nothing in this result list" and
# "there's a single None in this result list", see this code:
#
# if (!target) {
# target = o;
# } else if (target == Py_None) {
# Py_DECREF(Py_None);
# target = o;
# } else {
# if (!PyTuple_Check(target)) {
# o2 = target;
# target = PyTuple_New(1);
# PyTuple_SetItem(target, 0, o2);
#
# When t_output_helper() receives a None in the first call,
# 'target' ('resultobj' in the caller) is already None, so
# the code goes to the middle 'else if', replaces target with
# None, and returns it.
#
# Now comes the second call, which should append new_rev to the
# resultobj. But resultobj is still None, so the code goes
# again to the middle 'else if', replaces target with the new
# revision (a Python number object), and returns target.
#
# So the end result is that _wrap_svn_fs_commit_txn() returns
# just new_rev, not the list (None, new_rev).
#
# This is probably a bug, but I don't yet know if it's a bug in
# SWIG itself, or in our use of SWIG. The logic below is a
# workaround until we get it fixed.
commit_result = fs.commit_txn(txn)
if type(commit_result) == type(()):
if commit_result[0] == None:
print "_commit_internal: yo, the bug is fixed, update this code"
sys.exit(1)
else:
conflicts = commit_result[0]
new_rev = commit_result[1]
elif type(commit_result) == type(0):
conflicts = None
new_rev = commit_result
else:
print "Unexpected type for commit result:", str(commit_result)
sys.exit(1)
if conflicts:
print 'Exiting due to conflicts:', str(conflicts)
sys.exit(1)
return new_rev
Any ideas?
Note that you need to run 'make swig-py' first to generate
subversion/bindings/swig/python/svn_fs.c.
-Karl
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Thu Feb 27 21:38:03 2003