You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ri...@apache.org on 2024/12/06 13:59:08 UTC
svn commit: r1922345 [2/10] - in /subversion/branches/pristine-checksum-kind: ./ .github/ build/ build/ac-macros/ build/cmake/ build/generator/ build/generator/swig/ build/generator/templates/ build/hudson/ contrib/client-side/ contrib/client-side/svn_...
Modified: subversion/branches/pristine-checksum-kind/contrib/client-side/svn_load_dirs/svn_load_dirs.pl.in
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/contrib/client-side/svn_load_dirs/svn_load_dirs.pl.in?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/contrib/client-side/svn_load_dirs/svn_load_dirs.pl.in (original)
+++ subversion/branches/pristine-checksum-kind/contrib/client-side/svn_load_dirs/svn_load_dirs.pl.in Fri Dec 6 13:59:05 2024
@@ -1239,6 +1239,15 @@ while (defined (my $load_dir = &get_next
# get the incorrect information. So always append @BASE
# and any preceding @'s will be treated normally and the
# correct information will be retrieved.
+
+ # first make sure that the file has the eol-style property
+ # else svn 1.9 will error when it is not found
+ my @proplist = read_from_process($svn,
+ 'proplist',
+ '--quiet',
+ "$upd_file\@BASE");
+ next unless grep(/svn:eol-style/, @proplist);
+
my @command = ($svn,
'propget',
'svn:eol-style',
Modified: subversion/branches/pristine-checksum-kind/contrib/hook-scripts/check-mime-type.pl
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/contrib/hook-scripts/check-mime-type.pl?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/contrib/hook-scripts/check-mime-type.pl (original)
+++ subversion/branches/pristine-checksum-kind/contrib/hook-scripts/check-mime-type.pl Fri Dec 6 13:59:05 2024
@@ -1,28 +1,36 @@
#!/usr/bin/env perl
# ====================================================================
-# commit-mime-type-check.pl: check that every added file has the
-# svn:mime-type property set and every added file with a mime-type
-# matching text/* also has svn:eol-style set. If any file fails this
-# test the user is sent a verbose error message suggesting solutions and
-# the commit is aborted.
+# check-mime-type.pl: check that every added or property-modified file
+# has the svn:mime-type property set and every added or property-modified
+# file with a mime-type matching text/* also has svn:eol-style set.
+# If any file fails this test the user is sent a verbose error message
+# suggesting solutions and the commit is aborted.
#
-# Usage: commit-mime-type-check.pl REPOS TXN-NAME
+# Usage: check-mime-type.pl REPOS TXN-NAME
# ====================================================================
-# Most of commit-mime-type-check.pl was taken from
+# Most of check-mime-type.pl was taken from
# commit-access-control.pl, Revision 9986, 2004-06-14 16:29:22 -0400.
# ====================================================================
-# Copyright (c) 2000-2004 CollabNet. All rights reserved.
+# Copyright (c) 2000-2009 CollabNet. All rights reserved.
+# Copyright (c) 2010-2020 Apache Software Foundation (ASF).
+# ====================================================================
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution. The terms
-# are also available at http://subversion.tigris.org/license.html.
-# If newer versions of this license are posted there, you may use a
-# newer version instead, at your option.
+# http://www.apache.org/licenses/LICENSE-2.0
#
-# This software consists of voluntary contributions made by many
-# individuals. For exact contribution history, see the revision
-# history and logs, available at http://subversion.tigris.org/.
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
# ====================================================================
# Turn on warnings the best way depending on the Perl version.
@@ -40,6 +48,12 @@ use Carp;
######################################################################
# Configuration section.
+# Toggle: Check files of mime-type text/* for svn:eol-style property.
+my $check_text_eol = 1;
+
+# Toggle: Check property-modified files too.
+my $check_prop_modified_files = 0;
+
# Svnlook path.
my $svnlook = "/usr/bin/svnlook";
@@ -100,19 +114,28 @@ my $tmp_dir = '/tmp';
chdir($tmp_dir)
or die "$0: cannot chdir `$tmp_dir': $!\n";
-# Figure out what files have added using svnlook.
-my @files_added;
+# Figure out what files have been added/property-modified using svnlook.
+my $regex_files_to_check;
+if ($check_prop_modified_files)
+ {
+ $regex_files_to_check = qr/^(?:A.|.U) (.*[^\/])$/;
+ }
+else
+ {
+ $regex_files_to_check = qr/^A. (.*[^\/])$/;
+ }
+my @files_to_check;
foreach my $line (&read_from_process($svnlook, 'changed', $repos, '-t', $txn))
{
- # Add only files that were added to @files_added
- if ($line =~ /^A. (.*[^\/])$/)
+ # Add only files that were added/property-modified to @files_to_check
+ if ($line =~ /$regex_files_to_check/)
{
- push(@files_added, $1);
+ push(@files_to_check, $1);
}
}
my @errors;
-foreach my $path ( @files_added )
+foreach my $path ( @files_to_check )
{
my $mime_type;
my $eol_style;
@@ -168,7 +191,7 @@ foreach my $path ( @files_added )
{
push @errors, "$path : svn:mime-type is not set";
}
- elsif ($mime_type =~ /^text\// and not $eol_style)
+ elsif ($check_text_eol and $mime_type =~ /^text\// and not $eol_style)
{
push @errors, "$path : svn:mime-type=$mime_type but svn:eol-style is not set";
}
@@ -179,20 +202,30 @@ foreach my $path ( @files_added )
# and will not see this verbose message more than once.
if (@errors)
{
+ my $addition1 = '';
+ my $addition2 = '';
+ my $addition3 = '';
+ if ($check_prop_modified_files)
+ {
+ $addition1 = '/property-modified';
+ }
+ if ($check_text_eol)
+ {
+ $addition2 = " In addition text files must have the svn:eol-style property set.\n";
+ $addition3 = " svn propset svn:eol-style native path/of/file\n";
+ }
warn "$0:\n\n",
join("\n", @errors), "\n\n",
- <<EOS;
-
- Every added file must have the svn:mime-type property set. In
- addition text files must have the svn:eol-style property set.
+ <<"EOS";
+ Every added$addition1 file must have the svn:mime-type property set.
+$addition2
For binary files try running
svn propset svn:mime-type application/octet-stream path/of/file
For text files try
svn propset svn:mime-type text/plain path/of/file
- svn propset svn:eol-style native path/of/file
-
+$addition3
You may want to consider uncommenting the auto-props section
in your ~/.subversion/config file. Read the Subversion book
(https://svnbook.red-bean.com/), Chapter 7, Properties section,
Modified: subversion/branches/pristine-checksum-kind/contrib/server-side/fsfsverify.py
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/contrib/server-side/fsfsverify.py?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/contrib/server-side/fsfsverify.py (original)
+++ subversion/branches/pristine-checksum-kind/contrib/server-side/fsfsverify.py Fri Dec 6 13:59:05 2024
@@ -726,7 +726,10 @@ class NodeRev(object):
self.text = TextRep(rev, offset, length, size, digest,
contentType, currentRev, self, sha1, uniquifier)
elif field == 'props':
- (rev, offset, length, size, digest) = value.split(' ')
+ if len(value.split(' ')) == 5:
+ (rev, offset, length, size, digest) = value.split(' ')
+ else:
+ (rev, offset, length, size, digest, sha1, uniquifier) = value.split(' ')
rev = int(rev)
offset = int(offset)
length = int(length)
Modified: subversion/branches/pristine-checksum-kind/gen-make.py
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/gen-make.py?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/gen-make.py (original)
+++ subversion/branches/pristine-checksum-kind/gen-make.py Fri Dec 6 13:59:05 2024
@@ -47,6 +47,7 @@ sys.path.insert(0, os.path.join('build',
sys.path.insert(1, 'build')
gen_modules = {
+ 'cmake' : ('gen_cmake', 'CMake build system'),
'make' : ('gen_make', 'Makefiles for POSIX systems'),
'vcproj' : ('gen_vcnet_vcproj', 'VC.Net project files'),
}
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/javahl/README
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/javahl/README?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/javahl/README (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/javahl/README Fri Dec 6 13:59:05 2024
@@ -39,7 +39,7 @@ jar file with --with-junit when running
has been tested. JUnit can be downloaded from https://junit.org/ .)
-MacOS X:
+MacOS:
After building libsvnjavahl.dylib, you must rename it to
libsvnjavahl.jnilib. Make install-javahl creates a symbolic
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/INSTALL
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/INSTALL?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/INSTALL (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/INSTALL Fri Dec 6 13:59:05 2024
@@ -92,6 +92,9 @@ Step 1: [Optional] Install a suitable ve
(See https://sourceforge.net/p/swig/news/2016/06/swig-3010-released/)
- For Perl 5.16 and later, SWIG 2.0.8 or later is required.
- For Ruby bindings, SWIG 3.0.8 is not supported.
+ (See https://github.com/swig/swig/issues/602)
+ - For Ruby bindings, SWIG 4.2.0 is broken.
+ (See https://github.com/swig/swig/issues/2751)
* Perhaps your distribution packages a suitable version of SWIG.
If so, install it and skip to the last bullet point of this
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/include/svn_containers.swg
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/include/svn_containers.swg?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/include/svn_containers.swg (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/include/svn_containers.swg Fri Dec 6 13:59:05 2024
@@ -299,7 +299,7 @@
$1 = svn_swig_rb_hash_to_apr_hash_svn_string($input, _global_pool);
_global_pool = NULL;
if (!NIL_P(rb_pool)) {
- if (NIL_P($1)) {
+ if ($1 == NULL) {
svn_swig_rb_destroy_pool(rb_pool);
} else {
svn_swig_rb_set_pool_for_no_swig_type($input, rb_pool);
@@ -310,7 +310,7 @@
%typemap(out) apr_hash_t *PROPHASH
{
- %append_output(svn_swig_rb_apr_hash_to_hash_svn_string($1));
+ $result = svn_swig_rb_apr_hash_to_hash_svn_string($1);
}
#endif
@@ -326,10 +326,8 @@
#ifdef SWIGRUBY
%typemap(out) apr_hash_t *CHANGED_PATH_HASH
{
- VALUE rb_changed_path_hash;
- rb_changed_path_hash =
+ $result =
svn_swig_rb_apr_hash_to_hash_swig_type($1, "svn_log_changed_path_t *");
- %append_output(rb_changed_path_hash);
}
%apply apr_hash_t *CHANGED_PATH_HASH {
@@ -373,7 +371,7 @@
svn_swig_rb_hash_to_apr_hash_string($input, _global_pool);
_global_pool = NULL;
if (!NIL_P(rb_pool)) {
- if (NIL_P($1)) {
+ if ($1 == NULL) {
svn_swig_rb_destroy_pool(rb_pool);
} else {
svn_swig_rb_set_pool_for_no_swig_type($input, rb_pool);
@@ -760,7 +758,7 @@
%typemap(out) apr_array_header_t *PROP_LIST
{
- %append_output(svn_swig_rb_prop_apr_array_to_hash_prop($1));
+ $result = svn_swig_rb_prop_apr_array_to_hash_prop($1);
}
%typemap(in) apr_array_header_t *PROP_LIST_MAY_BE_NULL
@@ -778,7 +776,7 @@
%typemap(out) apr_array_header_t *PROP_LIST_MAY_BE_NULL
{
- %append_output($1 ? svn_swig_rb_prop_apr_array_to_hash_prop($1) : Qnil);
+ $result = $1 ? svn_swig_rb_prop_apr_array_to_hash_prop($1) : Qnil;
}
%apply apr_array_header_t *PROP_LIST {
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/include/svn_types.swg
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/include/svn_types.swg?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/include/svn_types.swg (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/include/svn_types.swg Fri Dec 6 13:59:05 2024
@@ -435,8 +435,8 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se
svn_error_clear($1);
SWIG_fail;
}
- Py_INCREF(Py_None);
- $result = Py_None;
+ Py_XDECREF($result);
+ $result = PyList_New(0);
}
%typemap(out) svn_error_t * SVN_ERR_WITH_ATTRS (apr_status_t apr_err,
@@ -470,11 +470,31 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se
SWIG_fail;
}
}
- else
- {
- Py_INCREF(Py_None);
- $result = Py_None;
+ Py_XDECREF($result);
+ $result = PyList_New(0);
+}
+
+%typemap(ret) svn_error_t * {
+ if ($result == NULL) {
+ $result = Py_None;
+ Py_INCREF($result);
+ }
+ else {
+ switch (PyList_Size($result)) {
+ case 0:
+ $result = Py_None;
+ Py_INCREF($result);
+ break;
+ case 1:
+ {
+ PyObject *tmp = $result;
+ $result = PyList_GetItem(tmp, 0);
+ Py_INCREF($result);
+ Py_DECREF(tmp);
+ }
+ break;
}
+ }
}
%typemap(ret) svn_error_t * SVN_ERR_WITH_ATTRS {
@@ -486,6 +506,7 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se
Py_XDECREF($result);
SWIG_fail;
}
+ $typemap(ret, svn_error_t *);
}
#endif
@@ -511,14 +532,29 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se
#endif
#ifdef SWIGRUBY
-%typemap(out) svn_error_t *
+%typemap(out) svn_error_t * (VALUE *svn_presult = NULL)
{
if ($1) {
svn_swig_rb_destroy_pool(_global_svn_swig_rb_pool);
svn_swig_rb_pop_pool(_global_svn_swig_rb_pool);
svn_swig_rb_handle_svn_error($1);
}
- $result = Qnil;
+ $result = rb_ary_new();
+ svn_presult = &$result;
+}
+
+%typemap(ret) svn_error_t *
+{
+ if (TYPE(*svn_presult) == T_ARRAY) {
+ switch (rb_array_len(*svn_presult)) {
+ case 0:
+ *svn_presult = Qnil;
+ break;
+ case 1:
+ *svn_presult = rb_ary_entry(*svn_presult, 0);
+ break;
+ }
+ }
}
#endif
@@ -1262,7 +1298,7 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se
if (NIL_P($input)) {
$1 = NULL;
} else if (RSTRING_LEN($input) != APR_MD5_DIGESTSIZE) {
- rb_raise(rb_eArgError, "digest size (%d) must be %d",
+ rb_raise(rb_eArgError, "digest size (%" PRIuSIZE ") must be %d",
RSTRING_LEN($input), APR_MD5_DIGESTSIZE);
} else {
$1 = ($1_ltype)StringValuePtr($input);
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/perl/native/t/5delta-compat.t
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/perl/native/t/5delta-compat.t?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/perl/native/t/5delta-compat.t (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/perl/native/t/5delta-compat.t Fri Dec 6 13:59:05 2024
@@ -43,3 +43,4 @@ SVN::TxDelta::send_txstream($txstream, @
# TEST
is($result, $tgttext, 'delta self test');
+close $aresult;
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/perl/native/t/5delta.t
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/perl/native/t/5delta.t?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/perl/native/t/5delta.t (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/perl/native/t/5delta.t Fri Dec 6 13:59:05 2024
@@ -45,3 +45,5 @@ is($result, $tgttext, 'delta self test')
# TEST
is("$md5", 'a22b3dadcbddac48d2f1eae3ec5fb86a', 'md5 matched');
+
+close $aresult;
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/perl/native/t/6ra.t
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/perl/native/t/6ra.t?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/perl/native/t/6ra.t (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/perl/native/t/6ra.t Fri Dec 6 13:59:05 2024
@@ -278,7 +278,9 @@ sub apply_textdelta {
or die "error opening in-memory file to store Subversion update: $!";
open my $in_fh, '<', \''
or die "error opening in-memory file for delta source: $!";
- return [ SVN::TxDelta::apply($in_fh, $out_fh, undef, "$baton", $pool) ];
+ my $result = [SVN::TxDelta::apply($in_fh, $out_fh, undef, "$baton", $pool)];
+ close $out_fh;
+ return $result;
}
sub close_edit {
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.c Fri Dec 6 13:59:05 2024
@@ -1783,44 +1783,97 @@ static svn_error_t *type_conversion_erro
/*** Editor Wrapping ***/
-/* this baton is used for the editor, directory, and file batons. */
-typedef struct item_baton {
- PyObject *editor; /* the editor handling the callbacks */
- PyObject *baton; /* the dir/file baton (or NULL for edit baton) */
- apr_pool_t *pool; /* top-level pool */
-} item_baton;
-
-static item_baton *make_baton(apr_pool_t *pool,
- PyObject *editor,
- PyObject *baton)
-{
- item_baton *newb = apr_palloc(pool, sizeof(*newb));
-
- /* Note: We steal the caller's reference to 'baton'. */
- Py_INCREF(editor);
- newb->editor = editor;
- newb->baton = baton;
- newb->pool = pool;
+static PyObject *
+make_baton(apr_pool_t *pool, PyObject *parent, PyObject *baton)
+{
+ PyObject *newb;
+ newb = PyObject_CallMethod(parent, "make_decendant", "O&O",
+ make_ob_pool, pool, baton);
+ /* We always borrow the reference in ancestor's dict during the C API
+ processing, so that we never leak the reference even the API aborted
+ by some error */
+ Py_XDECREF(newb);
return newb;
}
-static svn_error_t *close_baton(void *baton,
- const char *method)
+/* Get 'editor' and 'baton' from _ItemBaton instance. The caller
+ should be within a Python thread lock. */
+static svn_error_t *
+unwrap_item_baton(PyObject **editor, PyObject **baton, PyObject *item_baton)
{
- item_baton *ib = baton;
+ svn_error_t *err;
+
+ if ((*editor = PyObject_GetAttrString(item_baton, "editor")) == NULL)
+ {
+ err = callback_exception_error();
+ *baton = NULL;
+ goto finished;
+ }
+ if ((*baton = PyObject_GetAttrString(item_baton, "baton")) == NULL)
+ {
+ Py_CLEAR(*editor);
+ err = callback_exception_error();
+ goto finished;
+ }
+ err = SVN_NO_ERROR;
+ finished:
+ Py_XDECREF(*editor);
+ Py_XDECREF(*baton);
+ return err;
+}
+
+/* Get 'editor', 'baton', 'pool' from _ItemBaton instance. The caller
+ should be within a Python thread lock. */
+static svn_error_t *
+unwrap_item_baton_with_pool(PyObject **editor, PyObject **baton,
+ PyObject **py_pool, PyObject *item_baton)
+{
+ svn_error_t *err;
+
+ if ((err = unwrap_item_baton(editor, baton, item_baton)) != SVN_NO_ERROR)
+ {
+ *py_pool = NULL;
+ goto finished;
+ }
+ if ((*py_pool = PyObject_GetAttrString(item_baton, "pool")) == NULL)
+ {
+ err = callback_exception_error();
+ *editor = NULL;
+ *baton = NULL;
+ goto finished;
+ }
+ err = SVN_NO_ERROR;
+ finished:
+ Py_XDECREF(*py_pool);
+ return err;
+}
+
+static svn_error_t *
+close_baton(void *baton, const char *method, svn_boolean_t without_item)
+{
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = baton;
PyObject *result;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
+ if (without_item)
+ {
+ baton_item = NULL;
+ }
/* If there is no baton object, then it is an edit_baton, and we should
not bother to pass an object. Note that we still shove a NULL onto
the stack, but the format specified just won't reference it. */
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)method,
- ib->baton ? (char *)"(O)" : NULL,
- ib->baton)) == NULL)
+ if ((result = PyObject_CallMethod(editor, (char *)method,
+ baton_item ? (char *)"(O)" : NULL,
+ baton_item)) == NULL)
{
err = callback_exception_error();
goto finished;
@@ -1829,19 +1882,24 @@ static svn_error_t *close_baton(void *ba
/* there is no return value, so just toss this object (probably Py_None) */
Py_DECREF(result);
- /* Release the editor object */
- Py_DECREF(ib->editor);
-
- /* We're now done with the baton. Since there isn't really a free, all
- we need to do is note that its objects are no longer referenced by
- the baton. */
- Py_XDECREF(ib->baton);
-
-#ifdef SVN_DEBUG
- ib->editor = ib->baton = NULL;
-#endif
-
- err = SVN_NO_ERROR;
+ /* We're now done with the baton. Release it from ancestor's dict */
+ if (PyObject_HasAttrString(ib, "release_self"))
+ {
+ /* Get reference for ib, because following function call remove
+ ib object from ancestor's dict, which we borrow the reference */
+ Py_INCREF(ib);
+ result = PyObject_CallMethod(ib, "release_self", NULL, NULL);
+ /* Now we can release the reference safely */
+ Py_DECREF(ib);
+ if (result == NULL)
+ {
+ err = callback_exception_error();
+ goto finished;
+ }
+ /* there is no return value, so just toss this object
+ (probably Py_None) */
+ Py_DECREF(result);
+ }
finished:
svn_swig_py_release_py_lock();
@@ -1852,14 +1910,19 @@ static svn_error_t *set_target_revision(
svn_revnum_t target_revision,
apr_pool_t *pool)
{
- item_baton *ib = edit_baton;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = edit_baton;
PyObject *result;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"set_target_revision",
+ if ((result = PyObject_CallMethod(editor, (char *)"set_target_revision",
(char *)"l", target_revision)) == NULL)
{
err = callback_exception_error();
@@ -1880,14 +1943,19 @@ static svn_error_t *open_root(void *edit
apr_pool_t *dir_pool,
void **root_baton)
{
- item_baton *ib = edit_baton;
- PyObject *result;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = edit_baton;
+ PyObject *result = NULL;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"open_root",
+ if ((result = PyObject_CallMethod(editor, (char *)"open_root",
(char *)"lO&", base_revision,
make_ob_pool, dir_pool)) == NULL)
{
@@ -1895,11 +1963,15 @@ static svn_error_t *open_root(void *edit
goto finished;
}
- /* make_baton takes our 'result' reference */
- *root_baton = make_baton(dir_pool, ib->editor, result);
+ if ((*root_baton = make_baton(dir_pool, ib, result)) == NULL)
+ {
+ err = callback_exception_error();
+ goto finished;
+ }
err = SVN_NO_ERROR;
finished:
+ Py_XDECREF(result);
svn_swig_py_release_py_lock();
return err;
}
@@ -1909,16 +1981,21 @@ static svn_error_t *delete_entry(const c
void *parent_baton,
apr_pool_t *pool)
{
- item_baton *ib = parent_baton;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = parent_baton;
PyObject *result;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"delete_entry",
+ if ((result = PyObject_CallMethod(editor, (char *)"delete_entry",
(char *)SVN_SWIG_BYTES_FMT "lOO&",
- path, revision, ib->baton,
+ path, revision, baton_item,
make_ob_pool, pool)) == NULL)
{
err = callback_exception_error();
@@ -1941,20 +2018,25 @@ static svn_error_t *add_directory(const
apr_pool_t *dir_pool,
void **child_baton)
{
- item_baton *ib = parent_baton;
- PyObject *result;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = parent_baton;
+ PyObject *result = NULL;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"add_directory",
+ if ((result = PyObject_CallMethod(editor, (char *)"add_directory",
#if IS_PY3
(char *)"yOylO&",
#else
(char *)"sOslO&",
#endif
- path, ib->baton,
+ path, baton_item,
copyfrom_path, copyfrom_revision,
make_ob_pool, dir_pool)) == NULL)
{
@@ -1962,11 +2044,15 @@ static svn_error_t *add_directory(const
goto finished;
}
- /* make_baton takes our 'result' reference */
- *child_baton = make_baton(dir_pool, ib->editor, result);
+ if ((*child_baton = make_baton(dir_pool, ib, result)) == NULL)
+ {
+ err = callback_exception_error();
+ goto finished;
+ }
err = SVN_NO_ERROR;
finished:
+ Py_XDECREF(result);
svn_swig_py_release_py_lock();
return err;
}
@@ -1977,27 +2063,36 @@ static svn_error_t *open_directory(const
apr_pool_t *dir_pool,
void **child_baton)
{
- item_baton *ib = parent_baton;
- PyObject *result;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = parent_baton;
+ PyObject *result = NULL;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"open_directory",
+ if ((result = PyObject_CallMethod(editor, (char *)"open_directory",
(char *)SVN_SWIG_BYTES_FMT "OlO&",
- path, ib->baton, base_revision,
+ path, baton_item, base_revision,
make_ob_pool, dir_pool)) == NULL)
{
err = callback_exception_error();
goto finished;
}
- /* make_baton takes our 'result' reference */
- *child_baton = make_baton(dir_pool, ib->editor, result);
+ if ((*child_baton = make_baton(dir_pool, ib, result)) == NULL)
+ {
+ err = callback_exception_error();
+ goto finished;
+ }
err = SVN_NO_ERROR;
finished:
+ Py_XDECREF(result);
svn_swig_py_release_py_lock();
return err;
}
@@ -2007,20 +2102,25 @@ static svn_error_t *change_dir_prop(void
const svn_string_t *value,
apr_pool_t *pool)
{
- item_baton *ib = dir_baton;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = dir_baton;
PyObject *result;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"change_dir_prop",
+ if ((result = PyObject_CallMethod(editor, (char *)"change_dir_prop",
#if IS_PY3
(char *)"Oyy#O&",
#else
(char *)"Oss#O&",
#endif
- ib->baton, name,
+ baton_item, name,
value ? value->data : NULL,
(Py_ssize_t) (value ? value->len : 0),
make_ob_pool, pool)) == NULL)
@@ -2041,7 +2141,7 @@ static svn_error_t *change_dir_prop(void
static svn_error_t *close_directory(void *dir_baton,
apr_pool_t *pool)
{
- return close_baton(dir_baton, "close_directory");
+ return close_baton(dir_baton, "close_directory", FALSE);
}
static svn_error_t *add_file(const char *path,
@@ -2051,20 +2151,25 @@ static svn_error_t *add_file(const char
apr_pool_t *file_pool,
void **file_baton)
{
- item_baton *ib = parent_baton;
- PyObject *result;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = parent_baton;
+ PyObject *result = NULL;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"add_file",
+ if ((result = PyObject_CallMethod(editor, (char *)"add_file",
#if IS_PY3
(char *)"yOylO&",
#else
(char *)"sOslO&",
#endif
- path, ib->baton,
+ path, baton_item,
copyfrom_path, copyfrom_revision,
make_ob_pool, file_pool)) == NULL)
{
@@ -2072,12 +2177,16 @@ static svn_error_t *add_file(const char
goto finished;
}
- /* make_baton takes our 'result' reference */
- *file_baton = make_baton(file_pool, ib->editor, result);
+ if ((*file_baton = make_baton(file_pool, ib, result)) == NULL)
+ {
+ err = callback_exception_error();
+ goto finished;
+ }
err = SVN_NO_ERROR;
finished:
+ Py_XDECREF(result);
svn_swig_py_release_py_lock();
return err;
}
@@ -2088,27 +2197,36 @@ static svn_error_t *open_file(const char
apr_pool_t *file_pool,
void **file_baton)
{
- item_baton *ib = parent_baton;
- PyObject *result;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = parent_baton;
+ PyObject *result = NULL;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"open_file",
+ if ((result = PyObject_CallMethod(editor, (char *)"open_file",
(char *)SVN_SWIG_BYTES_FMT "OlO&",
- path, ib->baton, base_revision,
+ path, baton_item, base_revision,
make_ob_pool, file_pool)) == NULL)
{
err = callback_exception_error();
goto finished;
}
- /* make_baton takes our 'result' reference */
- *file_baton = make_baton(file_pool, ib->editor, result);
+ if ((*file_baton = make_baton(file_pool, ib, result)) == NULL)
+ {
+ err = callback_exception_error();
+ goto finished;
+ }
err = SVN_NO_ERROR;
finished:
+ Py_XDECREF(result);
svn_swig_py_release_py_lock();
return err;
}
@@ -2116,12 +2234,19 @@ static svn_error_t *open_file(const char
static svn_error_t *window_handler(svn_txdelta_window_t *window,
void *baton)
{
- PyObject *handler = baton;
- PyObject *result;
- svn_error_t *err;
+ PyObject *editor = NULL, *handler = NULL;
+ PyObject *ib = baton;
+ PyObject *result = NULL;
+ int is_last_call = FALSE;
+ svn_error_t *err = SVN_NO_ERROR;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &handler, ib)) != SVN_NO_ERROR)
+ {
+ is_last_call = TRUE;
+ goto finished;
+ }
if (window == NULL)
{
/* the last call; it closes the handler */
@@ -2129,9 +2254,8 @@ static svn_error_t *window_handler(svn_t
/* invoke the handler with None for the window */
/* ### python doesn't have 'const' on the format */
result = PyObject_CallFunction(handler, (char *)"O", Py_None);
+ is_last_call = TRUE;
- /* we no longer need to refer to the handler object */
- Py_DECREF(handler);
}
else
{
@@ -2144,14 +2268,40 @@ static svn_error_t *window_handler(svn_t
if (result == NULL)
{
err = callback_exception_error();
+ is_last_call = TRUE;
goto finished;
}
-
- /* there is no return value, so just toss this object (probably Py_None) */
- Py_DECREF(result);
- err = SVN_NO_ERROR;
+ else
+ {
+ /* there is no return value, so just toss this object
+ (probably Py_None) */
+ Py_DECREF(result);
+ err = SVN_NO_ERROR;
+ }
finished:
+ if (is_last_call)
+ {
+ /* now we should release the handler object */
+ if (PyObject_HasAttrString(ib, "release_self"))
+ {
+ /* Get reference for ib, because following function call remove
+ ib object from ancestor's dict, which we borrow the reference */
+ Py_INCREF(ib);
+ result = PyObject_CallMethod(ib, "release_self", NULL, NULL);
+ /* Now we can release the reference safely */
+ Py_DECREF(ib);
+ if (result == NULL)
+ {
+ if (err == SVN_NO_ERROR)
+ {
+ err = callback_exception_error();
+ }
+ }
+ Py_XDECREF(result);
+ }
+ }
+
svn_swig_py_release_py_lock();
return err;
}
@@ -2162,20 +2312,25 @@ static svn_error_t *apply_textdelta(void
svn_txdelta_window_handler_t *handler,
void **h_baton)
{
- item_baton *ib = file_baton;
- PyObject *result;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = file_baton;
+ PyObject *result = NULL;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"apply_textdelta",
+ if ((result = PyObject_CallMethod(editor, (char *)"apply_textdelta",
#if IS_PY3
(char *)"(Oy)",
#else
(char *)"(Os)",
#endif
- ib->baton,
+ baton_item,
base_checksum)) == NULL)
{
err = callback_exception_error();
@@ -2187,22 +2342,26 @@ static svn_error_t *apply_textdelta(void
in Python. */
if (result == Py_None)
{
- Py_DECREF(result);
-
*handler = svn_delta_noop_window_handler;
*h_baton = NULL;
}
else
{
- /* return the thunk for invoking the handler. the baton takes our
- 'result' reference, which is the handler. */
+ /* return the thunk for invoking the handler. the baton creates
+ new reference of our 'result' reference, which is the handler,
+ so we release it even if no error. */
*handler = window_handler;
- *h_baton = result;
+ if ((*h_baton = make_baton(pool, ib, result)) == NULL)
+ {
+ err = callback_exception_error();
+ goto finished;
+ }
}
err = SVN_NO_ERROR;
finished:
+ Py_XDECREF(result);
svn_swig_py_release_py_lock();
return err;
}
@@ -2212,20 +2371,25 @@ static svn_error_t *change_file_prop(voi
const svn_string_t *value,
apr_pool_t *pool)
{
- item_baton *ib = file_baton;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = file_baton;
PyObject *result;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"change_file_prop",
+ if ((result = PyObject_CallMethod(editor, (char *)"change_file_prop",
#if IS_PY3
(char *)"Oyy#O&",
#else
(char *)"Oss#O&",
#endif
- ib->baton, name,
+ baton_item, name,
value ? value->data : NULL,
(Py_ssize_t) (value ? value->len : 0),
make_ob_pool, pool)) == NULL)
@@ -2247,20 +2411,25 @@ static svn_error_t *close_file(void *fil
const char *text_checksum,
apr_pool_t *pool)
{
- item_baton *ib = file_baton;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = file_baton;
PyObject *result;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"close_file",
+ if ((result = PyObject_CallMethod(editor, (char *)"close_file",
#if IS_PY3
(char *)"(Oy)",
#else
(char *)"(Os)",
#endif
- ib->baton,
+ baton_item,
text_checksum)) == NULL)
{
err = callback_exception_error();
@@ -2270,14 +2439,24 @@ static svn_error_t *close_file(void *fil
/* there is no return value, so just toss this object (probably Py_None) */
Py_DECREF(result);
- /* We're now done with the baton. Since there isn't really a free, all
- we need to do is note that its objects are no longer referenced by
- the baton. */
- Py_XDECREF(ib->baton);
-
-#ifdef SVN_DEBUG
- ib->editor = ib->baton = NULL;
-#endif
+ /* We're now done with the baton. Release it from ancestor's dict */
+ if (PyObject_HasAttrString(ib, "release_self"))
+ {
+ /* Get reference for ib, because following function call remove
+ ib object from ancestor's dict, which we borrow the reference */
+ Py_INCREF(ib);
+ result = PyObject_CallMethod(ib, "release_self", NULL, NULL);
+ /* Now we can release the reference safely */
+ Py_DECREF(ib);
+ if (result == NULL)
+ {
+ err = callback_exception_error();
+ goto finished;
+ }
+ /* there is no return value, so just toss this object
+ (probably Py_None) */
+ Py_DECREF(result);
+ }
err = SVN_NO_ERROR;
@@ -2289,18 +2468,16 @@ static svn_error_t *close_file(void *fil
static svn_error_t *close_edit(void *edit_baton,
apr_pool_t *pool)
{
- return close_baton(edit_baton, "close_edit");
+ return close_baton(edit_baton, "close_edit", TRUE);
}
static svn_error_t *abort_edit(void *edit_baton,
apr_pool_t *pool)
{
- return close_baton(edit_baton, "abort_edit");
+ return close_baton(edit_baton, "abort_edit", TRUE);
}
void svn_swig_py_make_editor(const svn_delta_editor_t **editor,
- void **edit_baton,
- PyObject *py_editor,
apr_pool_t *pool)
{
svn_delta_editor_t *thunk_editor = svn_delta_default_editor(pool);
@@ -2321,7 +2498,6 @@ void svn_swig_py_make_editor(const svn_d
thunk_editor->abort_edit = abort_edit;
*editor = thunk_editor;
- *edit_baton = make_baton(pool, py_editor, NULL);
}
@@ -2331,14 +2507,19 @@ static svn_error_t *parse_fn3_magic_head
void *parse_baton,
apr_pool_t *pool)
{
- item_baton *ib = parse_baton;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = parse_baton;
PyObject *result;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"magic_header_record",
+ if ((result = PyObject_CallMethod(editor, (char *)"magic_header_record",
(char *)"lO&", version,
make_ob_pool, pool)) == NULL)
{
@@ -2360,14 +2541,19 @@ static svn_error_t *parse_fn3_uuid_recor
void *parse_baton,
apr_pool_t *pool)
{
- item_baton *ib = parse_baton;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = parse_baton;
PyObject *result;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"uuid_record",
+ if ((result = PyObject_CallMethod(editor, (char *)"uuid_record",
(char *)SVN_SWIG_BYTES_FMT "O&", uuid,
make_ob_pool, pool)) == NULL)
{
@@ -2390,14 +2576,19 @@ static svn_error_t *parse_fn3_new_revisi
void *parse_baton,
apr_pool_t *pool)
{
- item_baton *ib = parse_baton;
- PyObject *result;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = parse_baton;
+ PyObject *result = NULL;
PyObject *tmp;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
- if ((result = PyObject_CallMethod(ib->editor, (char *)"new_revision_record",
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
+ if ((result = PyObject_CallMethod(editor, (char *)"new_revision_record",
(char *)"O&O&",
svn_swig_py_stringhash_to_dict, headers,
make_ob_pool, pool)) == NULL) {
@@ -2405,11 +2596,15 @@ static svn_error_t *parse_fn3_new_revisi
goto finished;
}
- /* make_baton takes our 'result' reference */
- *revision_baton = make_baton(pool, ib->editor, result);
+ if ((*revision_baton = make_baton(pool, ib, result)) == NULL)
+ {
+ err = callback_exception_error();
+ goto finished;
+ }
err = SVN_NO_ERROR;
finished:
+ Py_XDECREF(result);
svn_swig_py_release_py_lock();
return err;
}
@@ -2420,26 +2615,35 @@ static svn_error_t *parse_fn3_new_node_r
void *revision_baton,
apr_pool_t *pool)
{
- item_baton *ib = revision_baton;
- PyObject *result;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = revision_baton;
+ PyObject *result = NULL;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
- if ((result = PyObject_CallMethod(ib->editor, (char *)"new_node_record",
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
+ if ((result = PyObject_CallMethod(editor, (char *)"new_node_record",
(char *)"O&OO&",
svn_swig_py_stringhash_to_dict, headers,
- ib->baton,
+ baton_item,
make_ob_pool, pool)) == NULL) {
err = callback_exception_error();
goto finished;
}
- /* make_baton takes our 'result' reference */
- *node_baton = make_baton(pool, ib->editor, result);
+ if ((*node_baton = make_baton(pool, ib, result)) == NULL)
+ {
+ err = callback_exception_error();
+ goto finished;
+ }
err = SVN_NO_ERROR;
finished:
+ Py_XDECREF(result);
svn_swig_py_release_py_lock();
return err;
}
@@ -2449,20 +2653,25 @@ static svn_error_t *parse_fn3_set_revisi
const char *name,
const svn_string_t *value)
{
- item_baton *ib = revision_baton;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = revision_baton;
PyObject *result;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"set_revision_property",
+ if ((result = PyObject_CallMethod(editor, (char *)"set_revision_property",
#if IS_PY3
(char *)"Oyy#",
#else
(char *)"Oss#",
#endif
- ib->baton, name,
+ baton_item, name,
value ? value->data : NULL,
(Py_ssize_t) (value ? value->len : 0)))
== NULL)
@@ -2485,20 +2694,25 @@ static svn_error_t *parse_fn3_set_node_p
const char *name,
const svn_string_t *value)
{
- item_baton *ib = node_baton;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = node_baton;
PyObject *result;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"set_node_property",
+ if ((result = PyObject_CallMethod(editor, (char *)"set_node_property",
#if IS_PY3
(char *)"Oyy#",
#else
(char *)"Oss#",
#endif
- ib->baton, name,
+ baton_item, name,
value ? value->data : NULL,
(Py_ssize_t) (value ? value->len : 0)))
== NULL)
@@ -2520,16 +2734,21 @@ static svn_error_t *parse_fn3_set_node_p
static svn_error_t *parse_fn3_delete_node_property(void *node_baton,
const char *name)
{
- item_baton *ib = node_baton;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = node_baton;
PyObject *result;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"delete_node_property",
+ if ((result = PyObject_CallMethod(editor, (char *)"delete_node_property",
(char *)"O" SVN_SWIG_BYTES_FMT,
- ib->baton, name)) == NULL)
+ baton_item, name)) == NULL)
{
err = callback_exception_error();
goto finished;
@@ -2547,15 +2766,20 @@ static svn_error_t *parse_fn3_delete_nod
static svn_error_t *parse_fn3_remove_node_props(void *node_baton)
{
- item_baton *ib = node_baton;
+ PyObject *editor = NULL, *baton_item = NULL;
+ PyObject *ib = node_baton;
PyObject *result;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton(&editor, &baton_item, ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"remove_node_props",
- (char *)"(O)", ib->baton)) == NULL)
+ if ((result = PyObject_CallMethod(editor, (char *)"remove_node_props",
+ (char *)"(O)", baton_item)) == NULL)
{
err = callback_exception_error();
goto finished;
@@ -2574,15 +2798,22 @@ static svn_error_t *parse_fn3_remove_nod
static svn_error_t *parse_fn3_set_fulltext(svn_stream_t **stream,
void *node_baton)
{
- item_baton *ib = node_baton;
+ PyObject *editor = NULL, *baton_item = NULL, *py_pool = NULL;
+ PyObject *ib = node_baton;
PyObject *result = NULL;
+ apr_pool_t *pool;
svn_error_t *err = SVN_NO_ERROR;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton_with_pool(&editor, &baton_item, &py_pool,
+ ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"set_fulltext",
- (char *)"(O)", ib->baton)) == NULL)
+ if ((result = PyObject_CallMethod(editor, (char *)"set_fulltext",
+ (char *)"(O)", baton_item)) == NULL)
{
err = callback_exception_error();
goto finished;
@@ -2595,9 +2826,15 @@ static svn_error_t *parse_fn3_set_fullte
}
else
{
+ if (svn_swig_ConvertPtrString(py_pool, (void **)&pool,
+ "apr_pool_t *") == -1)
+ {
+ err = type_conversion_error("apr_pool_t *");
+ goto finished;
+ }
/* create a stream from the IO object. it will increment the
reference on the 'result'. */
- *stream = svn_swig_py_make_stream(result, ib->pool);
+ *stream = svn_swig_py_make_stream(result, pool);
if (*stream == NULL)
{
err = callback_exception_error();
@@ -2614,19 +2851,26 @@ finished:
}
-static svn_error_t *parse_fn3_apply_textdelta(svn_txdelta_window_handler_t *handler,
- void **handler_baton,
- void *node_baton)
+static svn_error_t *
+parse_fn3_apply_textdelta(svn_txdelta_window_handler_t *handler,
+ void **handler_baton,
+ void *node_baton)
{
- item_baton *ib = node_baton;
- PyObject *result;
+ PyObject *editor = NULL, *baton_item = NULL, *py_pool = NULL;
+ PyObject *ib = node_baton;
+ PyObject *result = NULL;
svn_error_t *err;
svn_swig_py_acquire_py_lock();
+ if ((err = unwrap_item_baton_with_pool(&editor, &baton_item, &py_pool,
+ ib)) != SVN_NO_ERROR)
+ {
+ goto finished;
+ }
/* ### python doesn't have 'const' on the method name and format */
- if ((result = PyObject_CallMethod(ib->editor, (char *)"apply_textdelta",
- (char *)"(O)", ib->baton)) == NULL)
+ if ((result = PyObject_CallMethod(editor, (char *)"apply_textdelta",
+ (char *)"(O)", baton_item)) == NULL)
{
err = callback_exception_error();
goto finished;
@@ -2637,22 +2881,33 @@ static svn_error_t *parse_fn3_apply_text
in Python. */
if (result == Py_None)
{
- Py_DECREF(result);
-
*handler = svn_delta_noop_window_handler;
*handler_baton = NULL;
}
else
{
- /* return the thunk for invoking the handler. the baton takes our
- 'result' reference, which is the handler. */
+ apr_pool_t *pool;
+ /* return the thunk for invoking the handler. the baton creates
+ new reference of our 'result' reference, which is the handler,
+ so we release it even if no error. */
*handler = window_handler;
- *handler_baton = result;
+ if (svn_swig_ConvertPtrString(py_pool, (void **)&pool,
+ "apr_pool_t *") == -1)
+ {
+ err = type_conversion_error("apr_pool_t *");
+ goto finished;
+ }
+ if ((*handler_baton = make_baton(pool, ib, result)) == NULL)
+ {
+ err = callback_exception_error();
+ goto finished;
+ }
}
err = SVN_NO_ERROR;
finished:
+ Py_XDECREF(result);
svn_swig_py_release_py_lock();
return err;
}
@@ -2660,13 +2915,13 @@ static svn_error_t *parse_fn3_apply_text
static svn_error_t *parse_fn3_close_node(void *node_baton)
{
- return close_baton(node_baton, "close_node");
+ return close_baton(node_baton, "close_node", FALSE);
}
static svn_error_t *parse_fn3_close_revision(void *revision_baton)
{
- return close_baton(revision_baton, "close_revision");
+ return close_baton(revision_baton, "close_revision", FALSE);
}
@@ -2686,26 +2941,11 @@ static const svn_repos_parse_fns3_t thun
parse_fn3_close_revision
};
-static apr_status_t
-svn_swig_py_parse_fns3_destroy(void *parse_baton)
-{
- close_baton(parse_baton, "_close_dumpstream");
- return APR_SUCCESS;
-}
-
void svn_swig_py_make_parse_fns3(const svn_repos_parse_fns3_t **parse_fns3,
- void **parse_baton,
- PyObject *py_parse_fns3,
apr_pool_t *pool)
{
*parse_fns3 = &thunk_parse_fns3_vtable;
- *parse_baton = make_baton(pool, py_parse_fns3, NULL);
-
- /* Dump stream vtable does not provide a method which is called right before
- the end of the parsing (similar to close_edit/abort_edit in delta editor).
- Thus, register a pool clean-up routine to release this parse baton. */
- apr_pool_cleanup_register(pool, *parse_baton, svn_swig_py_parse_fns3_destroy,
- apr_pool_cleanup_null);
+ return;
}
@@ -2951,7 +3191,7 @@ void svn_swig_py_notify_func(void *baton
svn_swig_py_acquire_py_lock();
/* As caller can't understand Python context and we can't notify if
- Python call back function raise exception to caller, we must catch it
+ Python callback function raise exception to caller, we must catch it
if it is occurred, and restore error indicator */
PyErr_Fetch(&exc_type, &exc, &exc_traceback);
@@ -3001,7 +3241,7 @@ void svn_swig_py_notify_func2(void *bato
svn_swig_py_acquire_py_lock();
/* As caller can't understand Python context and we can't notify if
- Python call back function raise exception to caller, we must catch it
+ Python callback function raise exception to caller, we must catch it
if it is occurred, and restore error indicator */
PyErr_Fetch(&exc_type, &exc, &exc_traceback);
@@ -3044,7 +3284,7 @@ void svn_swig_py_status_func(void *baton
svn_swig_py_acquire_py_lock();
/* As caller can't understand Python context and we can't notify if
- Python call back function raise exception to caller, we must catch it
+ Python callback function raise exception to caller, we must catch it
if it is occurred, and restore error indicator */
PyErr_Fetch(&exc_type, &exc, &exc_traceback);
@@ -3193,7 +3433,7 @@ void svn_swig_py_status_func2(void *bato
svn_swig_py_acquire_py_lock();
/* As caller can't understand Python context and we can't notify if
- Python call back function raise exception to caller, we must catch it
+ Python callback function raise exception to caller, we must catch it
if it is occurred, and restore error indicator */
PyErr_Fetch(&exc_type, &exc, &exc_traceback);
@@ -4478,7 +4718,7 @@ ra_callbacks_progress_func(apr_off_t pro
svn_swig_py_acquire_py_lock();
/* As caller can't understand Python context and we can't notify if
- Python call back function raise exception to caller, we must catch it
+ Python callback function raise exception to caller, we must catch it
if it is occurred, and restore error indicator */
PyErr_Fetch(&exc_type, &exc, &exc_traceback);
@@ -5389,7 +5629,7 @@ svn_swig_py_config_enumerator2(const cha
svn_swig_py_acquire_py_lock();
/* As caller can't understand Python context and we can't notify if
- Python call back function raise exception to caller, we must catch it
+ Python callback function raise exception to caller, we must catch it
if it is occurred, and restore error indicator */
PyErr_Fetch(&exc_type, &exc, &exc_traceback);
@@ -5447,7 +5687,7 @@ svn_swig_py_config_section_enumerator2(c
svn_swig_py_acquire_py_lock();
/* As caller can't understand Python context and we can't notify if
- Python call back function raise exception to caller, we must catch it
+ Python callback function raise exception to caller, we must catch it
if it is occurred, and restore error indicator */
PyErr_Fetch(&exc_type, &exc, &exc_traceback);
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/libsvn_swig_py/swigutil_py.h Fri Dec 6 13:59:05 2024
@@ -275,14 +275,10 @@ svn_swig_py_unwrap_struct_ptr(PyObject *
/* make an editor that "thunks" from C callbacks up to Python */
void svn_swig_py_make_editor(const svn_delta_editor_t **editor,
- void **edit_baton,
- PyObject *py_editor,
apr_pool_t *pool);
/* make a parse vtable that "thunks" from C callbacks up to Python */
void svn_swig_py_make_parse_fns3(const svn_repos_parse_fns3_t **parse_fns3,
- void **parse_baton,
- PyObject *py_parse_fns3,
apr_pool_t *pool);
apr_file_t *svn_swig_py_make_file(PyObject *py_file,
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/svn/delta.py
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/svn/delta.py?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/svn/delta.py (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/svn/delta.py Fri Dec 6 13:59:05 2024
@@ -77,5 +77,6 @@ class Editor:
pass
-def make_editor(editor, pool=None):
- return svn_swig_py_make_editor(editor, pool)
+def make_editor(editor, pool=None, baton=None):
+ from libsvn.delta import _AncBaton
+ return svn_swig_py_make_editor(pool), _AncBaton(editor, pool, baton)
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/svn/fs.py
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/svn/fs.py?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/svn/fs.py (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/svn/fs.py Fri Dec 6 13:59:05 2024
@@ -23,35 +23,8 @@
# under the License.
######################################################################
+import errno
from libsvn.fs import *
-
-######################################################################
-# Any adjustment of SWIG generated wrapper functions on svn.fs module
-# should be placed before adding alternative names for them.
-
-# fs.commit_txn() should return a 2-tupple of conflict_p and new_rev.
-# However if conflict_p is None, SWIG generated wrapper function
-# libsvn.fs.svn_fs_commit_txn returns an integer value of new_rev.
-# This is a bug of SWIG generated wrapper function, so we fix it here.
-#
-# (There was discussion about this behavior because C API
-# svn_fs_commit_txn() always set NULL to conflict_p if it returns
-# SVN_NO_ERROR and so it seems to be reasonable that fs.commit_txn()
-# returns only rev_new value. However for compatibility, we decided
-# that fs.commit_txn always returns 2-tuple if it does not raises
-# an exception.)
-
-_svn_fs_commit_txn = svn_fs_commit_txn
-
-def svn_fs_commit_txn(*args):
- r"""svn_fs_commit_txn(svn_fs_txn_t txn, apr_pool_t pool) -> svn_error_t"""
- ret = _svn_fs_commit_txn(*args)
- if not isinstance(ret, tuple):
- ret = (None, ret)
- return ret
-
-######################################################################
-
from svn.core import _unprefix_names, Pool, _as_list
_unprefix_names(locals(), 'svn_fs_')
_unprefix_names(locals(), 'SVN_FS_')
@@ -158,6 +131,18 @@ class FileDiff:
return self.tempfile1, self.tempfile2
def get_pipe(self):
+ """Perform diff and return a file object from which the output can
+ be read.
+
+ When DIFFOPTIONS is None (the default), use svn's internal diff.
+
+ With any other DIFFOPTIONS, exec the external diff found on PATH,
+ passing it DIFFOPTIONS. On Windows, exec diff.exe rather than
+ diff. If a diff utility is not installed or found on PATH, throws
+ FileNotFoundError. Caveat: On some systems, including Windows, an
+ external diff may not be available unless installed and added to
+ PATH manually.
+ """
self.get_files()
# If diffoptions were provided, then the diff command needs to be
@@ -170,8 +155,17 @@ class FileDiff:
+ [self.tempfile1, self.tempfile2]
# open the pipe, and return the file object for reading from the child.
- p = _subprocess.Popen(cmd, stdout=_subprocess.PIPE, bufsize=-1,
- close_fds=_sys.platform != "win32")
+ try:
+ p = _subprocess.Popen(cmd, stdout=_subprocess.PIPE, bufsize=-1,
+ close_fds=_sys.platform != "win32")
+ # When removing Python 2 support: Change to FileNotFoundError and
+ # remove check for ENOENT (FileNotFoundError "Corresponds to errno
+ # ENOENT" according to documentation)
+ except OSError as err:
+ if err.errno == errno.ENOENT:
+ err.strerror = "External diff command not found in PATH"
+ raise err
+
return _PopenStdoutWrapper(p)
else:
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/svn/repos.py
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/svn/repos.py?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/svn/repos.py (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/svn/repos.py Fri Dec 6 13:59:05 2024
@@ -336,5 +336,16 @@ class ParseFns3:
pass
-def make_parse_fns3(parse_fns3, pool=None):
- return svn_swig_py_make_parse_fns3(parse_fns3, pool)
+def make_parse_fns3(parse_fns3, pool=None, baton=None):
+ from libsvn.delta import _AncBaton
+
+ class _ParseBaton(_AncBaton):
+ # Drive _close_dumpstream method when the instance is deleted.
+ # For backward compatibility before Subversion 1.15, we call it even if
+ # the instance would not be used by C API, or the C API would cause
+ # some error.
+ def __del__(self):
+ self.editor._close_dumpstream()
+
+ parse_baton = _ParseBaton(parse_fns3, pool, baton)
+ return svn_swig_py_make_parse_fns3(pool), parse_baton
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/client.py
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/client.py?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/client.py (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/client.py Fri Dec 6 13:59:05 2024
@@ -172,7 +172,9 @@ class SubversionClientTestCase(unittest.
path = self.temper.alloc_empty_dir('-checkout')
- self.assertRaises(ValueError, client.checkout2,
+ # TypeError is raised since SWIG 4.3.0
+ self.assertRaises((ValueError, TypeError), r'Received a NULL pointer',
+ client.checkout2,
self.repos_uri, path, None, None, True, True,
self.client_ctx)
@@ -579,7 +581,9 @@ class SubversionClientTestCase(unittest.
path = self.temper.alloc_empty_dir('-update')
- self.assertRaises(ValueError, client.checkout2,
+ # TypeError is raised since SWIG 4.3.0
+ self.assertRaises((ValueError, TypeError), r'Received a NULL pointer',
+ client.checkout2,
self.repos_uri, path, None, None, True, True,
self.client_ctx)
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/core.py
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/core.py?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/core.py (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/core.py Fri Dec 6 13:59:05 2024
@@ -348,6 +348,35 @@ class SubversionCoreTestCase(unittest.Te
finally:
svn.core.svn_stream_close(stream)
+ def test_svn_rangelist_diff(self):
+ """
+ SWIG incorrectly handles return values when the first %append_output() is
+ invoked with a list instance. svn.core.svn_rangelist_diff() is in the case.
+ We test whether the workaround for it is working.
+ """
+
+ def from_args(start, end, inheritable):
+ instance = svn.core.svn_merge_range_t()
+ instance.start = start
+ instance.end = end
+ instance.inheritable = inheritable
+ return instance
+
+ def to_args(instance):
+ return [instance.start, instance.end, instance.inheritable]
+
+ def map_list(f, iterator):
+ return list(map(f, iterator))
+
+ from_ = [from_args(4, 5, True), from_args(9, 13, True)]
+ to = [from_args(7, 11, True)]
+ rv = svn.core.svn_rangelist_diff(from_, to, True)
+ self.assertIsInstance(rv, (list, tuple))
+ deleted, added = rv
+ self.assertEqual([[7, 9, True]], map_list(to_args, added))
+ self.assertEqual([[4, 5, True], [11, 13, True]],
+ map_list(to_args, deleted))
+
def suite():
return unittest.defaultTestLoader.loadTestsFromTestCase(
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/delta.py
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/delta.py?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/delta.py (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/delta.py Fri Dec 6 13:59:05 2024
@@ -21,6 +21,7 @@
import unittest, setup_path
import os
import tempfile
+import weakref
import svn.delta
import svn.core
from sys import version_info # For Python version check
@@ -117,6 +118,19 @@ class DeltaTestCase(unittest.TestCase):
# Check that the ops inherit the window's pool
self.assertEqual(window.ops[0]._parent_pool, window._parent_pool)
+ def testMakeEditorLeak(self):
+ """Issue 4916, check ref-count leak on svn.delta.make_editor()"""
+ pool = svn.core.Pool()
+ editor = svn.delta.Editor()
+ editor_ref = weakref.ref(editor)
+ e_ptr, e_baton = svn.delta.make_editor(editor, pool)
+ del e_ptr, e_baton
+ self.assertNotEqual(editor_ref(), None)
+ del pool
+ self.assertNotEqual(editor_ref(), None)
+ del editor
+ self.assertEqual(editor_ref(), None)
+
def suite():
return unittest.defaultTestLoader.loadTestsFromTestCase(DeltaTestCase)
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/fs.py
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/fs.py?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/fs.py (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/fs.py Fri Dec 6 13:59:05 2024
@@ -308,6 +308,9 @@ class SubversionFSTestCase(unittest.Test
try:
diffout, differr = Popen(["diff"], stdin=PIPE, stderr=PIPE).communicate()
+ # When removing Python 2 support: Change to FileNotFoundError and
+ # remove check for ENOENT (FileNotFoundError "Corresponds to errno
+ # ENOENT" according to documentation)
except OSError as err:
if err.errno == errno.ENOENT:
self.skipTest("'diff' command not present")
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/repository.py
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/repository.py?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/repository.py (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/repository.py Fri Dec 6 13:59:05 2024
@@ -18,11 +18,11 @@
# under the License.
#
#
-import unittest, setup_path, os, sys
+import unittest, setup_path, os, sys, weakref
from sys import version_info # For Python version check
from io import BytesIO
from svn import core, repos, fs, delta
-from svn.core import SubversionException
+from svn.core import SubversionException, Pool
import utils
class ChangeReceiver(delta.Editor):
@@ -40,9 +40,20 @@ class ChangeReceiver(delta.Editor):
return textdelta_handler
class DumpStreamParser(repos.ParseFns3):
- def __init__(self):
+ def __init__(self, stream=None, pool=None):
repos.ParseFns3.__init__(self)
+ self.stream = stream
self.ops = []
+ # for leak checking only. If the parse_fns3 object holds some proxy
+ # object allocated from 'pool' or the 'pool' itself, the 'pool' is not
+ # destroyed until the parse_fns3 object is removed.
+ self.pool = pool
+ def _close_dumpstream(self):
+ if self.stream:
+ self.stream.close()
+ self.stream = None
+ if self.pool:
+ self.pool = None
def magic_header_record(self, version, pool=None):
self.ops.append((b"magic-header", version))
def uuid_record(self, uuid, pool=None):
@@ -74,6 +85,76 @@ class DumpStreamParser(repos.ParseFns3):
self.ops.append((b"set-fulltext", node_baton[0], node_baton[1]))
return None
+class BatonCollector(repos.ChangeCollector):
+ """A ChangeCollector with collecting batons, too"""
+ def __init__(self, fs_ptr, root, pool=None, notify_cb=None):
+ repos.ChangeCollector.__init__(self, fs_ptr, root, pool, notify_cb)
+ self.batons = []
+ self.close_called = False
+ self.abort_called = False
+
+ def open_root(self, base_revision, dir_pool=None):
+ bt = repos.ChangeCollector.open_root(self, base_revision, dir_pool)
+ self.batons.append((b'dir baton', b'', bt, sys.getrefcount(bt)))
+ return bt
+
+ def add_directory(self, path, parent_baton,
+ copyfrom_path, copyfrom_revision, dir_pool=None):
+ bt = repos.ChangeCollector.add_directory(self, path, parent_baton,
+ copyfrom_path,
+ copyfrom_revision,
+ dir_pool)
+ self.batons.append((b'dir baton', path, bt, sys.getrefcount(bt)))
+ return bt
+
+ def open_directory(self, path, parent_baton, base_revision,
+ dir_pool=None):
+ bt = repos.ChangeCollector.open_directory(self, path, parent_baton,
+ base_revision, dir_pool)
+ self.batons.append((b'dir baton', path, bt, sys.getrefcount(bt)))
+ return bt
+
+ def add_file(self, path, parent_baton,
+ copyfrom_path, copyfrom_revision, file_pool=None):
+ bt = repos.ChangeCollector.add_file(self, path, parent_baton,
+ copyfrom_path, copyfrom_revision,
+ file_pool)
+ self.batons.append((b'file baton', path, bt, sys.getrefcount(bt)))
+ return bt
+
+ def open_file(self, path, parent_baton, base_revision, file_pool=None):
+ bt = repos.ChangeCollector.open_file(self, path, parent_baton,
+ base_revision, file_pool)
+ self.batons.append((b'file baton', path, bt, sys.getrefcount(bt)))
+ return bt
+
+ def close_edit(self, pool=None):
+ self.close_called = True
+ return
+
+ def abort_edit(self, pool=None):
+ self.abort_called = True
+ return
+
+class BatonCollectorErrorOnClose(BatonCollector):
+ """Same as BatonCollector, but raises an Exception when close the
+ file/dir specified by error_path"""
+ def __init__(self, fs_ptr, root, pool=None, notify_cb=None, error_path=b''):
+ BatonCollector.__init__(self, fs_ptr, root, pool, notify_cb)
+ self.error_path = error_path
+
+ def close_directory(self, dir_baton):
+ if dir_baton[0] == self.error_path:
+ raise SubversionException('A Dummy Exception!', core.SVN_ERR_BASE)
+ else:
+ BatonCollector.close_directory(self, dir_baton)
+
+ def close_file(self, file_baton, text_checksum):
+ if file_baton[0] == self.error_path:
+ raise SubversionException('A Dummy Exception!', core.SVN_ERR_BASE)
+ else:
+ return BatonCollector.close_file(self, file_baton, text_checksum)
+
def _authz_callback(root, path, pool):
"A dummy authz callback which always returns success."
@@ -175,13 +256,15 @@ class SubversionRepositoryTestCase(unitt
def is_cancelled():
self.cancel_calls += 1
return None
+ pool = Pool()
+ subpool = Pool(pool)
dump_path = os.path.join(os.path.dirname(sys.argv[0]),
"trac/versioncontrol/tests/svnrepos.dump")
stream = open(dump_path, 'rb')
- dsp = DumpStreamParser()
- ptr, baton = repos.make_parse_fns3(dsp)
+ dsp = DumpStreamParser(stream, subpool)
+ dsp_ref = weakref.ref(dsp)
+ ptr, baton = repos.make_parse_fns3(dsp, subpool)
repos.parse_dumpstream3(stream, ptr, baton, False, is_cancelled)
- stream.close()
self.assertEqual(self.cancel_calls, 76)
expected_list = [
(b"magic-header", 2),
@@ -226,6 +309,13 @@ class SubversionRepositoryTestCase(unitt
# the comparison list gets too long.
self.assertEqual(dsp.ops[:len(expected_list)], expected_list)
+ # _close_dumpstream should be invoked after 'baton' is removed.
+ self.assertEqual(False, stream.closed)
+ del ptr, baton, subpool, dsp
+ self.assertEqual(True, stream.closed)
+ # Issue SVN-4918
+ self.assertEqual(None, dsp_ref())
+
def test_parse_fns3_invalid_set_fulltext(self):
class DumpStreamParserSubclass(DumpStreamParser):
def set_fulltext(self, node_baton):
@@ -241,6 +331,33 @@ class SubversionRepositoryTestCase(unitt
finally:
stream.close()
+ def test_parse_fns3_apply_textdelta_handler_refcount(self):
+ handler = lambda node_baton: None
+ handler_ref = weakref.ref(handler)
+
+ class ParseFns3(repos.ParseFns3):
+ def __init__(self, handler):
+ self.called = set()
+ self.handler = handler
+ def apply_textdelta(self, node_baton):
+ self.called.add('apply_textdelta')
+ return self.handler
+
+ dumpfile = os.path.join(os.path.dirname(__file__), 'data',
+ 'repository-deltas.dump')
+ pool = Pool()
+ subpool = Pool(pool)
+ parser = ParseFns3(handler)
+ ptr, baton = repos.make_parse_fns3(parser, subpool)
+ with open(dumpfile, "rb") as stream:
+ repos.parse_dumpstream3(stream, ptr, baton, False, None)
+ del ptr, baton, stream
+
+ self.assertIn('apply_textdelta', parser.called)
+ self.assertNotEqual(None, handler_ref())
+ del parser, handler, subpool, ParseFns3
+ self.assertEqual(None, handler_ref())
+
def test_get_logs(self):
"""Test scope of get_logs callbacks"""
logs = []
@@ -290,6 +407,79 @@ class SubversionRepositoryTestCase(unitt
repos.dir_delta(prev_root, b'', b'', this_root, b'', e_ptr, e_baton,
_authz_callback, 1, 1, 0, 0)
+ def test_delta_editor_leak_with_change_collector(self):
+ pool = Pool()
+ subpool = Pool(pool)
+ root = fs.revision_root(self.fs, self.rev, subpool)
+ editor = repos.ChangeCollector(self.fs, root, subpool)
+ editor_ref = weakref.ref(editor)
+ e_ptr, e_baton = delta.make_editor(editor, subpool)
+ repos.replay(root, e_ptr, e_baton, subpool)
+
+ fs.close_root(root)
+ del root
+ self.assertNotEqual(None, editor_ref())
+
+ del e_ptr, e_baton, editor
+ del subpool
+ self.assertEqual(None, editor_ref())
+
+ def test_replay_batons_refcounts(self):
+ """Issue SVN-4917: check ref-count of batons created and used in callbacks"""
+ root = fs.revision_root(self.fs, self.rev)
+ editor = BatonCollector(self.fs, root)
+ e_ptr, e_baton = delta.make_editor(editor)
+ repos.replay(root, e_ptr, e_baton)
+ for baton in editor.batons:
+ self.assertEqual(sys.getrefcount(baton[2]), 2,
+ "leak on baton %s after replay without errors"
+ % repr(baton))
+ del e_baton
+ self.assertEqual(sys.getrefcount(e_ptr), 2,
+ "leak on editor baton after replay without errors")
+
+ editor = BatonCollectorErrorOnClose(self.fs, root,
+ error_path=b'branches/v1x')
+ e_ptr, e_baton = delta.make_editor(editor)
+ self.assertRaises(SubversionException, repos.replay, root, e_ptr, e_baton)
+ batons = editor.batons
+ # As svn_repos_replay calls neither close_edit callback nor abort_edit
+ # if an error has occurred during processing, references of Python objects
+ # in descendant batons may live until e_baton is deleted.
+ del e_baton
+ for baton in batons:
+ self.assertEqual(sys.getrefcount(baton[2]), 2,
+ "leak on baton %s after replay with an error"
+ % repr(baton))
+ self.assertEqual(sys.getrefcount(e_ptr), 2,
+ "leak on editor baton after replay with an error")
+
+ def test_delta_editor_apply_textdelta_handler_refcount(self):
+ handler = lambda textdelta: None
+ handler_ref = weakref.ref(handler)
+
+ class Editor(delta.Editor):
+ def __init__(self, handler):
+ self.called = set()
+ self.handler = handler
+ def apply_textdelta(self, file_baton, base_checksum, pool=None):
+ self.called.add('apply_textdelta')
+ return self.handler
+
+ pool = Pool()
+ subpool = Pool(pool)
+ root = fs.revision_root(self.fs, 3) # change of trunk/README.txt
+ editor = Editor(handler)
+ e_ptr, e_baton = delta.make_editor(editor, subpool)
+ repos.replay(root, e_ptr, e_baton, subpool)
+ del e_ptr, e_baton
+
+ self.assertIn('apply_textdelta', editor.called)
+ self.assertNotEqual(None, handler_ref())
+ del root, editor, handler, Editor
+ del subpool
+ self.assertEqual(None, handler_ref())
+
def test_retrieve_and_change_rev_prop(self):
"""Test playing with revprops"""
self.assertEqual(repos.fs_revision_prop(self.repos, self.rev, b"svn:log",
Modified: subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/wc.py
URL: http://svn.apache.org/viewvc/subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/wc.py?rev=1922345&r1=1922344&r2=1922345&view=diff
==============================================================================
--- subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/wc.py (original)
+++ subversion/branches/pristine-checksum-kind/subversion/bindings/swig/python/tests/wc.py Fri Dec 6 13:59:05 2024
@@ -180,9 +180,9 @@ class SubversionWorkingCopyTestCase(unit
self.assertTrue(target.startswith(self.path))
def test_status_editor_callback_exception(self):
- """test case for status_editor call back not to be crashed by Python exception"""
+ """test case for status_editor callback not to be crashed by Python exception"""
def status_func(target, status):
- # Note: exception with in this call back doesn't propagate to
+ # Note: exception with in this callback doesn't propagate to
# the caller
raise AssertionError('intentional exception')