summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrej Shadura <andrew.shadura@collabora.co.uk>2020-01-18 16:34:23 +0100
committerAndrej Shadura <andrew.shadura@collabora.co.uk>2020-01-18 16:34:23 +0100
commit3ffd22a8af524ebe47f02ab4ae091e5e57951b1d (patch)
tree3b633ee3e8b2ab5150d16ac08aa26befe904e0f0
parent2ae17de0cd7dc785fc908fed8e636a20a1d599fc (diff)
parent70c6b83ca2d46cebe258174cd3c4b131d5cc82a9 (diff)
Update upstream source from tag 'upstream/0.10.2_git20191228+2423bf1'
Update to upstream version '0.10.2~git20191228+2423bf1' with Debian dir 86dbb455d49537fc4349d277d4055e0ea536d4c8
-rw-r--r--.bzrignore10
-rw-r--r--.gitignore15
-rw-r--r--.hgignore7
-rw-r--r--.testr.conf4
-rw-r--r--.travis.yml51
-rw-r--r--Makefile11
-rw-r--r--NEWS13
-rw-r--r--PKG-INFO24
-rw-r--r--appveyor.yml96
-rw-r--r--build.cmd21
-rw-r--r--setup.cfg2
-rwxr-xr-xsetup.py39
-rw-r--r--subvertpy/__init__.py4
-rw-r--r--subvertpy/_ra.c127
-rw-r--r--subvertpy/client.c938
-rw-r--r--subvertpy/editor.c29
-rw-r--r--subvertpy/properties.py10
-rw-r--r--subvertpy/ra_svn.py11
-rw-r--r--subvertpy/repos.c11
-rw-r--r--subvertpy/subr.c130
-rw-r--r--subvertpy/tests/__init__.py42
-rw-r--r--subvertpy/tests/test_client.py6
-rw-r--r--subvertpy/tests/test_marshall.py16
-rw-r--r--subvertpy/tests/test_ra.py4
-rw-r--r--subvertpy/tests/test_repos.py5
-rw-r--r--subvertpy/tests/test_subr.py64
-rw-r--r--subvertpy/tests/test_wc.py364
-rw-r--r--subvertpy/util.c452
-rw-r--r--subvertpy/util.h18
-rw-r--r--subvertpy/wc.c3767
-rw-r--r--subvertpy/wc.h21
-rw-r--r--subvertpy/wc_adm.c2237
-rw-r--r--tox.ini9
33 files changed, 5544 insertions, 3014 deletions
diff --git a/.bzrignore b/.bzrignore
new file mode 100644
index 00000000..befb80e5
--- /dev/null
+++ b/.bzrignore
@@ -0,0 +1,10 @@
+build
+_trial_temp
+dist
+MANIFEST
+.coverage
+tags
+.testrepository
+.noseids
+apidocs
+.pybuild
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..f38e1928
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+build
+_trial_temp
+dist
+sdist
+MANIFEST
+.coverage
+tags
+.testrepository
+.noseids
+apidocs
+*.pyc
+*.so
+*~
+.tox/
+.pybuild
diff --git a/.hgignore b/.hgignore
new file mode 100644
index 00000000..dc39b7a5
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,7 @@
+syntax: glob
+build
+_trial_temp
+dist
+MANIFEST
+.coverage
+tags
diff --git a/.testr.conf b/.testr.conf
new file mode 100644
index 00000000..7d0aa966
--- /dev/null
+++ b/.testr.conf
@@ -0,0 +1,4 @@
+[DEFAULT]
+test_command=PYTHONPATH=. python -m subunit.run $IDOPTION $LISTOPT subvertpy.tests.test_suite
+test_id_option=--load-list $IDFILE
+test_list_option=--list
diff --git a/.travis.yml b/.travis.yml
index 33c6526d..a10ec6b3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,12 +1,41 @@
-sudo: required
-language: generic
-
-services:
- - docker
-
+language: python
+dist: xenial
+addons:
+ apt:
+ update: true
+ packages: libapr1-dev libaprutil1-dev libdb5.3-dev liblz4-dev libsasl2-dev libperl-dev libserf-dev libsqlite3-dev libtool python-all-dev libneon27-gnutls-dev libutf8proc-dev
+python:
+ - "2.7"
+ - "3.4"
+ - "3.5"
+ - "3.6"
+ - "3.7"
+ - "3.8"
+env:
+ - SVN_VERSION=1.13.0
+ - SVN_VERSION=1.12.2
+ - SVN_VERSION=1.11.1
+ - SVN_VERSION=1.10.6
+ SVN_OPTIONS="--with-lz4=internal"
+ - SVN_VERSION=1.9.7
+ - SVN_VERSION=1.8.19
+ - SVN_VERSION=1.7.19
+ - SVN_VERSION=1.6.21
+ - SVN_VERSION=1.5.9
script:
- - wget -O- http://travis.debian.net/script.sh | sh -
-
-branches:
- except:
- - /^debian\/\d/
+ - make check
+ - make style
+install:
+ - travis_retry pip install -U pip coverage codecov flake8
+before_install:
+ - wget https://archive.apache.org/dist/subversion/subversion-${SVN_VERSION}.tar.gz
+ - tar xvfz subversion-${SVN_VERSION}.tar.gz
+ - cd subversion-${SVN_VERSION}
+ - ./configure ${SVN_OPTIONS}
+ - make
+ - sudo make install
+ - sudo ldconfig -v
+ - cd ..
+after_success:
+ - python -m coverage combine
+ - codecov
diff --git a/Makefile b/Makefile
index bad12947..90e7cb0e 100644
--- a/Makefile
+++ b/Makefile
@@ -12,6 +12,9 @@ all: build build-inplace
build::
$(SETUP) build
+build-nodeprecated:
+ $(MAKE) build CFLAGS+=-Wno-deprecated-declarations
+
build-inplace::
$(SETUP) build_ext --inplace
@@ -24,6 +27,12 @@ check:: build-inplace
gdb-check::
$(MAKE) check DEBUGGER="gdb --args"
+valgrind-check-python3:
+ PYTHONMALLOC=malloc $(MAKE) check PYTHON=python DEBUGGER="valgrind --suppressions=/usr/lib/valgrind/python3.supp"
+
+valgrind-check-python2:
+ PYTHONMALLOC=malloc $(MAKE) check PYTHON=python3 DEBUGGER="valgrind --suppressions=/usr/lib/valgrind/python.supp"
+
check-one::
$(MAKE) check TEST_OPTIONS=-f
@@ -35,4 +44,4 @@ pydoctor:
$(PYDOCTOR) $(PYDOCTOR_OPTIONS) --introspect-c-modules -c subvertpy.cfg --make-html
style:
- $(FLAKE8) --exclude=build,.git,build-pypy,.tox
+ $(FLAKE8)
diff --git a/NEWS b/NEWS
index 1ebd49b4..e9eb9ba3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,16 @@
+0.11.0 UNRELEASED
+
+ API CHANGES
+
+ * ``subvertpy.wc.WorkingCopy`` has been renamed to
+ `` subvertpy.wc.Adm``. (Jelmer Vernooij)
+
+ * ``subvertpy.client.mkdir``, ``subvertpy.client.copy``,
+ ``subvertpy.client.delete``, ``subvertpy.client.commit``
+ no longer return the resulting commit but call an
+ optional callback with commit info.
+ (Jelmer Vernooij)
+
0.10.1 2017-07-19
BUG FIXES
diff --git a/PKG-INFO b/PKG-INFO
deleted file mode 100644
index 3fd6ebc0..00000000
--- a/PKG-INFO
+++ /dev/null
@@ -1,24 +0,0 @@
-Metadata-Version: 1.1
-Name: subvertpy
-Version: 0.10.1
-Summary: Alternative Python bindings for Subversion
-Home-page: https://jelmer.uk/subvertpy
-Author: Jelmer Vernooij
-Author-email: jelmer@jelmer.uk
-License: LGPLv2.1 or later
-Download-URL: https://jelmer.uk/subvertpy/subvertpy-0.10.1.tar.gz
-Description:
- Alternative Python bindings for Subversion. The goal is to have
- complete, portable and "Pythonic" Python bindings.
-
-Keywords: svn subvertpy subversion bindings
-Platform: UNKNOWN
-Classifier: Development Status :: 4 - Beta
-Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: Implementation :: CPython
-Classifier: Operating System :: POSIX
-Classifier: Topic :: Software Development :: Version Control
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 00000000..c401fb86
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,96 @@
+environment:
+
+ matrix:
+
+ - PYTHON: "C:\\Python27"
+ PYTHON_VERSION: "2.7.x"
+ PYTHON_ARCH: "32"
+
+ - PYTHON: "C:\\Python27-x64"
+ PYTHON_VERSION: "2.7.x"
+ PYTHON_ARCH: "64"
+
+ - PYTHON: "C:\\Python33"
+ PYTHON_VERSION: "3.3.x"
+ PYTHON_ARCH: "32"
+
+ - PYTHON: "C:\\Python33-x64"
+ PYTHON_VERSION: "3.3.x"
+ PYTHON_ARCH: "64"
+ DISTUTILS_USE_SDK: "1"
+
+ - PYTHON: "C:\\Python34"
+ PYTHON_VERSION: "3.4.x"
+ PYTHON_ARCH: "32"
+
+ - PYTHON: "C:\\Python34-x64"
+ PYTHON_VERSION: "3.4.x"
+ PYTHON_ARCH: "64"
+ DISTUTILS_USE_SDK: "1"
+
+ - PYTHON: "C:\\Python35"
+ PYTHON_VERSION: "3.5.x"
+ PYTHON_ARCH: "32"
+
+ - PYTHON: "C:\\Python35-x64"
+ PYTHON_VERSION: "3.5.x"
+ PYTHON_ARCH: "64"
+
+ - PYTHON: "C:\\Python36"
+ PYTHON_VERSION: "3.6.x"
+ PYTHON_ARCH: "32"
+
+ - PYTHON: "C:\\Python36-x64"
+ PYTHON_VERSION: "3.6.x"
+ PYTHON_ARCH: "64"
+
+install:
+ # If there is a newer build queued for the same PR, cancel this one.
+ # The AppVeyor 'rollout builds' option is supposed to serve the same
+ # purpose but it is problematic because it tends to cancel builds pushed
+ # directly to master instead of just PR builds (or the converse).
+ # credits: JuliaLang developers.
+ - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
+ https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
+ Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
+ throw "There are newer queued builds for this pull request, failing early." }
+ - ECHO "Filesystem root:"
+ - ps: "ls \"C:/\""
+
+ - ECHO "Installed SDKs:"
+ - ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\""
+
+ # Install Python (from the official .msi of http://python.org) and pip when
+ # not already installed.
+ - ps: if (-not(Test-Path($env:PYTHON))) { & appveyor\install.ps1 }
+
+ # Prepend newly installed Python to the PATH of this build (this cannot be
+ # done from inside the powershell script as it would require to restart
+ # the parent CMD process).
+ - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
+
+ # Check that we have the expected version and architecture for Python
+ - "build.cmd %PYTHON%\\python.exe --version"
+ - "build.cmd %PYTHON%\\python.exe -c \"import struct; print(struct.calcsize('P') * 8)\""
+
+ # Install setuptools/wheel so that we can e.g. use bdist_wheel
+ - "pip install setuptools wheel"
+
+ - "build.cmd %PYTHON%\\python.exe setup.py develop"
+
+build_script:
+ # Build the compiled extension
+ - "build.cmd %PYTHON%\\python.exe setup.py build"
+
+test_script:
+ - "build.cmd %PYTHON%\\python.exe setup.py test"
+
+after_test:
+ - "build.cmd %PYTHON%\\python.exe setup.py bdist_wheel"
+ # http://stackoverflow.com/questions/43255455/unicode-character-causing-error-with-bdist-wininst-on-python-3-but-not-python-2
+ # - "python setup.py bdist_wininst"
+ - "build.cmd %PYTHON%\\python.exe setup.py bdist_msi"
+ - ps: "ls dist"
+
+artifacts:
+ - path: dist\*
diff --git a/build.cmd b/build.cmd
new file mode 100644
index 00000000..23df2b69
--- /dev/null
+++ b/build.cmd
@@ -0,0 +1,21 @@
+@echo off
+:: To build extensions for 64 bit Python 3, we need to configure environment
+:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of:
+:: MS Windows SDK for Windows 7 and .NET Framework 4
+::
+:: More details at:
+:: https://github.com/cython/cython/wiki/CythonExtensionsOnWindows
+
+IF "%DISTUTILS_USE_SDK%"=="1" (
+ ECHO Configuring environment to build with MSVC on a 64bit architecture
+ ECHO Using Windows SDK 7.1
+ "C:\Program Files\Microsoft SDKs\Windows\v7.1\Setup\WindowsSdkVer.exe" -q -version:v7.1
+ CALL "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 /release
+ SET MSSdk=1
+ REM Need the following to allow tox to see the SDK compiler
+ SET TOX_TESTENV_PASSENV=DISTUTILS_USE_SDK MSSdk INCLUDE LIB
+) ELSE (
+ ECHO Using default MSVC build environment
+)
+
+CALL %*
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 00000000..d62bc256
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,2 @@
+[flake8]
+exclude = build,.git,build-pypy,.tox,subversion-*
diff --git a/setup.py b/setup.py
index 44b9ec9f..0fc21245 100755
--- a/setup.py
+++ b/setup.py
@@ -396,7 +396,8 @@ def subvertpy_modules():
SvnExtension(
"subvertpy.client",
[source_path(n)
- for n in ("client.c", "editor.c", "util.c", "_ra.c", "wc.c")],
+ for n in ("client.c", "editor.c", "util.c", "_ra.c", "wc.c",
+ "wc_adm.c")],
libraries=["svn_client-1", "svn_subr-1", "svn_ra-1", "svn_wc-1"]),
SvnExtension(
"subvertpy._ra",
@@ -407,12 +408,18 @@ def subvertpy_modules():
libraries=["svn_repos-1", "svn_subr-1", "svn_fs-1"]),
SvnExtension(
"subvertpy.wc",
- [source_path(n) for n in ("wc.c", "util.c", "editor.c")],
- libraries=["svn_wc-1", "svn_subr-1"])
+ [source_path(n) for n in
+ ["wc.c", "wc_adm.c", "util.c", "editor.c"]],
+ libraries=["svn_wc-1", "svn_subr-1"]),
+ SvnExtension(
+ "subvertpy.subr",
+ [source_path(n)
+ for n in ["util.c", "subr.c"]],
+ libraries=["svn_subr-1"]),
]
-subvertpy_version = (0, 10, 1)
+subvertpy_version = (0, 11, 0)
subvertpy_version_string = ".".join(map(str, subvertpy_version))
@@ -422,15 +429,31 @@ if __name__ == "__main__":
keywords='svn subvertpy subversion bindings',
version=subvertpy_version_string,
url='https://jelmer.uk/subvertpy',
- download_url="https://jelmer.uk/subvertpy/subvertpy-%s.tar.gz" % (
+ download_url="https://jelmer.uk/subvertpy/tarball/subvertpy-%s/" % (
subvertpy_version_string, ),
license='LGPLv2.1 or later',
author='Jelmer Vernooij',
author_email='jelmer@jelmer.uk',
long_description="""
- Alternative Python bindings for Subversion. The goal is to have
- complete, portable and "Pythonic" Python bindings.
- """,
+Alternative Python bindings for Subversion. The goal is to have
+complete, portable and "Pythonic" Python bindings.
+
+Bindings are provided for the working copy, client, delta, remote access and
+repository APIs. A hookable server side implementation of the custom Subversion
+protocol (svn_ra) is also provided.
+
+Differences with similar packages
+---------------------------------
+subvertpy covers more of the APIs than python-svn. It provides a more
+"Pythonic" API than python-subversion, which wraps the Subversion C API pretty
+much directly. Neither provide a hookable server-side.
+
+Dependencies
+------------
+Subvertpy depends on Python 2.7 or 3.5, and Subversion 1.4 or later. It should
+work on Windows as well as most POSIX-based platforms (including Linux, BSDs
+and Mac OS X).
+""",
packages=['subvertpy', 'subvertpy.tests'],
ext_modules=subvertpy_modules(),
scripts=['bin/subvertpy-fast-export'],
diff --git a/subvertpy/__init__.py b/subvertpy/__init__.py
index 6b0762de..89c1effd 100644
--- a/subvertpy/__init__.py
+++ b/subvertpy/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2006-2008 Jelmer Vernooij <jelmer@jelmer.uk>
+# Copyright (C) 2006-2017 Jelmer Vernooij <jelmer@jelmer.uk>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
@@ -17,7 +17,7 @@
"""Python bindings for Subversion."""
__author__ = "Jelmer Vernooij <jelmer@jelmer.uk>"
-__version__ = (0, 10, 1)
+__version__ = (0, 11, 0)
NODE_DIR = 2
NODE_FILE = 1
diff --git a/subvertpy/_ra.c b/subvertpy/_ra.c
index 4c14131a..0757ac17 100644
--- a/subvertpy/_ra.c
+++ b/subvertpy/_ra.c
@@ -901,6 +901,16 @@ static PyObject *ra_get_repos_root(PyObject *self)
*/
static PyObject *ra_get_url(PyObject *self, void *closure)
{
+ RemoteAccessObject *ra = (RemoteAccessObject *)self;
+
+ return PyUnicode_FromString(ra->url);
+}
+
+/**
+ * Obtain the URL of this repository.
+ */
+static PyObject *ra_get_session_url(PyObject *self)
+{
const char *url;
apr_pool_t *temp_pool;
PyObject *r;
@@ -927,6 +937,8 @@ static PyObject *ra_get_url(PyObject *self, void *closure)
#endif
}
+
+
static PyObject *ra_do_update(PyObject *self, PyObject *args)
{
svn_revnum_t revision_to_update_to;
@@ -1038,16 +1050,17 @@ static PyObject *ra_do_switch(PyObject *self, PyObject *args)
bool recurse;
bool send_copyfrom_args = false;
bool ignore_ancestry = true;
- char *switch_url;
+ const char *switch_url;
PyObject *update_editor;
const REPORTER_T *reporter;
void *report_baton;
apr_pool_t *temp_pool, *result_pool;
ReporterObject *ret;
+ PyObject *py_switch_url;
svn_error_t *err;
- if (!PyArg_ParseTuple(args, "lsbsO|bb:do_switch", &revision_to_update_to, &update_target,
- &recurse, &switch_url, &update_editor, &send_copyfrom_args, &ignore_ancestry))
+ if (!PyArg_ParseTuple(args, "lsbOO|bb:do_switch", &revision_to_update_to, &update_target,
+ &recurse, &py_switch_url, &update_editor, &send_copyfrom_args, &ignore_ancestry))
return NULL;
if (ra_check_busy(ra))
return NULL;
@@ -1058,6 +1071,13 @@ static PyObject *ra_do_switch(PyObject *self, PyObject *args)
return NULL;
}
+ switch_url = py_object_to_svn_uri(py_switch_url, temp_pool);
+ if (switch_url == NULL) {
+ apr_pool_destroy(temp_pool);
+ ra->busy = false;
+ return NULL;
+ }
+
result_pool = Pool(NULL);
if (result_pool == NULL) {
apr_pool_destroy(temp_pool);
@@ -1338,23 +1358,19 @@ static PyObject *get_commit_editor(PyObject *self, PyObject *args, PyObject *kwa
hash_lock_tokens = NULL;
} else {
Py_ssize_t idx = 0;
+ char *key, *val;
PyObject *k, *v;
hash_lock_tokens = apr_hash_make(pool);
while (PyDict_Next(lock_tokens, &idx, &k, &v)) {
- if (!PyBytes_Check(k)) {
- PyErr_SetString(PyExc_TypeError, "token not bytes");
+ key = py_object_to_svn_string(k, pool);
+ if (key == NULL) {
goto fail_prep;
}
- apr_hash_set(hash_lock_tokens, PyBytes_AsString(k),
- PyBytes_Size(k), PyBytes_AsString(v));
+ val = apr_pmemdup(pool, PyBytes_AsString(v), PyBytes_Size(v));
+ apr_hash_set(hash_lock_tokens, key, strlen(key), val);
}
}
- if (!PyDict_Check(revprops)) {
- PyErr_SetString(PyExc_TypeError, "Expected dictionary with revision properties");
- goto fail_prep;
- }
-
if (ra_check_busy(ra))
goto fail_prep;
@@ -1363,7 +1379,7 @@ static PyObject *get_commit_editor(PyObject *self, PyObject *args, PyObject *kwa
#if ONLY_SINCE_SVN(1, 5)
hash_revprops = prop_dict_to_hash(pool, revprops);
if (hash_revprops == NULL) {
- goto fail_prep2;
+ goto fail_prep;
}
Py_BEGIN_ALLOW_THREADS
err = svn_ra_get_commit_editor3(ra->ra, &editor,
@@ -1371,21 +1387,26 @@ static PyObject *get_commit_editor(PyObject *self, PyObject *args, PyObject *kwa
hash_revprops, py_commit_callback,
commit_callback, hash_lock_tokens, keep_locks, pool);
#else
+ if (!PyDict_Check(revprops)) {
+ PyErr_SetString(PyExc_TypeError, "props should be dictionary");
+ goto fail_prep;
+ }
+
/* Check that revprops has only one member named SVN_PROP_REVISION_LOG */
if (PyDict_Size(revprops) != 1) {
PyErr_SetString(PyExc_ValueError, "Only svn:log can be set with Subversion 1.4");
- goto fail_prep2;
+ goto fail_prep;
}
py_log_msg = PyDict_GetItemString(revprops, SVN_PROP_REVISION_LOG);
if (py_log_msg == NULL) {
PyErr_SetString(PyExc_ValueError, "Only svn:log can be set with Subversion 1.4.");
- goto fail_prep2;
+ goto fail_prep;
}
log_msg = py_object_to_svn_string(py_log_msg, pool);
if (log_msg == NULL) {
- goto fail_prep2;
+ goto fail_prep;
}
Py_BEGIN_ALLOW_THREADS
@@ -1399,17 +1420,16 @@ static PyObject *get_commit_editor(PyObject *self, PyObject *args, PyObject *kwa
if (err != NULL) {
handle_svn_error(err);
svn_error_clear(err);
- goto fail_prep2;
+ goto fail_prep;
}
Py_INCREF(ra);
return new_editor_object(NULL, editor, edit_baton, pool,
&Editor_Type, ra_done_handler, ra, commit_callback);
-fail_prep2:
+fail_prep:
Py_DECREF(commit_callback);
ra->busy = false;
-fail_prep:
apr_pool_destroy(pool);
fail_pool:
return NULL;
@@ -1424,8 +1444,10 @@ static PyObject *ra_change_rev_prop(PyObject *self, PyObject *args)
int vallen, oldvallen = -2;
apr_pool_t *temp_pool;
svn_string_t *val_string;
+#if ONLY_SINCE_SVN(1, 7)
const svn_string_t *old_val_string;
const svn_string_t *const *old_val_string_p;
+#endif
if (!PyArg_ParseTuple(args, "lss#|z#:change_rev_prop", &rev, &name, &value,
&vallen, &oldvalue, &oldvallen))
@@ -1475,18 +1497,14 @@ static PyObject *ra_get_dir(PyObject *self, PyObject *args, PyObject *kwargs)
{
apr_pool_t *temp_pool;
apr_hash_t *dirents;
- apr_hash_index_t *idx;
apr_hash_t *props;
svn_revnum_t fetch_rev;
- const char *key;
RemoteAccessObject *ra = (RemoteAccessObject *)self;
- svn_dirent_t *dirent;
- apr_ssize_t klen;
const char *path;
PyObject *py_path;
svn_revnum_t revision = -1;
unsigned int dirent_fields = 0;
- PyObject *py_dirents, *py_props;
+ PyObject *py_dirents = NULL, *py_props;
char *kwnames[] = { "path", "revision", "fields", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|lI:get_dir", kwnames,
@@ -1517,45 +1535,21 @@ static PyObject *ra_get_dir(PyObject *self, PyObject *args, PyObject *kwargs)
py_dirents = Py_None;
Py_INCREF(py_dirents);
} else {
- py_dirents = PyDict_New();
+ py_dirents = dirent_hash_to_dict(dirents, dirent_fields, temp_pool);
if (py_dirents == NULL) {
goto fail;
}
- idx = apr_hash_first(temp_pool, dirents);
- while (idx != NULL) {
- PyObject *item, *pykey;
- apr_hash_this(idx, (const void **)&key, &klen, (void **)&dirent);
- item = py_dirent(dirent, dirent_fields);
- if (item == NULL) {
- goto fail_dirents;
- }
- if (key == NULL) {
- pykey = Py_None;
- Py_INCREF(pykey);
- } else {
- pykey = PyUnicode_FromString((char *)key);
- }
- if (PyDict_SetItem(py_dirents, pykey, item) != 0) {
- Py_DECREF(item);
- Py_DECREF(pykey);
- goto fail_dirents;
- }
- Py_DECREF(pykey);
- Py_DECREF(item);
- idx = apr_hash_next(idx);
- }
}
py_props = prop_hash_to_dict(props);
if (py_props == NULL) {
- goto fail_dirents;
+ goto fail;
}
apr_pool_destroy(temp_pool);
return Py_BuildValue("(NlN)", py_dirents, fetch_rev, py_props);
-fail_dirents:
- Py_DECREF(py_dirents);
fail:
+ Py_XDECREF(py_dirents);
apr_pool_destroy(temp_pool);
return NULL;
}
@@ -1617,12 +1611,13 @@ static PyObject *ra_get_file(PyObject *self, PyObject *args)
static PyObject *ra_get_lock(PyObject *self, PyObject *args)
{
- char *path;
+ const char *path;
RemoteAccessObject *ra = (RemoteAccessObject *)self;
- svn_lock_t *lock;
+ svn_lock_t *lock = NULL;
+ PyObject *py_path;
apr_pool_t *temp_pool;
- if (!PyArg_ParseTuple(args, "s:get_lock", &path))
+ if (!PyArg_ParseTuple(args, "O:get_lock", &py_path))
return NULL;
if (ra_check_busy(ra))
@@ -1631,10 +1626,22 @@ static PyObject *ra_get_lock(PyObject *self, PyObject *args)
temp_pool = Pool(NULL);
if (temp_pool == NULL)
return NULL;
+
+ path = py_object_to_svn_relpath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
RUN_RA_WITH_POOL(temp_pool, ra,
svn_ra_get_lock(ra->ra, &lock, path, temp_pool));
apr_pool_destroy(temp_pool);
- return wrap_lock(lock);
+
+ if (lock == NULL) {
+ Py_RETURN_NONE;
+ } else {
+ return wrap_lock(lock);
+ }
}
static PyObject *ra_check_path(PyObject *self, PyObject *args)
@@ -2239,12 +2246,15 @@ static int ra_set_progress_func(PyObject *self, PyObject *value, void *closure)
static PyGetSetDef ra_getsetters[] = {
{ "progress_func", NULL, ra_set_progress_func, NULL },
+ { "url", ra_get_url, NULL, NULL },
{ NULL }
};
#include "_ra_iter_log.c"
static PyMethodDef ra_methods[] = {
+ { "get_session_url", (PyCFunction)ra_get_session_url, METH_NOARGS,
+ "S.get_session_url() -> url" },
{ "get_file_revs", ra_get_file_revs, METH_VARARGS,
"S.get_file_revs(path, start_rev, end_revs, handler)" },
{ "get_locations", ra_get_locations, METH_VARARGS,
@@ -2308,9 +2318,6 @@ static PyMethodDef ra_methods[] = {
{ "get_repos_root", (PyCFunction)ra_get_repos_root, METH_NOARGS,
"S.get_repos_root() -> url\n"
"Return the URL to the root of the repository." },
- { "get_url", (PyCFunction)ra_get_url, METH_NOARGS,
- "S.get_url() -> url\n"
- "Return the URL of the repository." },
{ "get_log", (PyCFunction)ra_get_log, METH_VARARGS|METH_KEYWORDS,
"S.get_log(callback, paths, start, end, limit=0, "
"discover_changed_paths=False, strict_node_history=True, "
@@ -2350,8 +2357,6 @@ static PyMethodDef ra_methods[] = {
static PyMemberDef ra_members[] = {
{ "busy", T_BYTE, offsetof(RemoteAccessObject, busy), READONLY,
"Whether this connection is in use at the moment" },
- { "url", T_STRING, offsetof(RemoteAccessObject, url), READONLY,
- "URL this connection is to" },
{ "corrected_url", T_STRING, offsetof(RemoteAccessObject, corrected_url), READONLY,
"Corrected URL" },
{ NULL, }
@@ -3321,7 +3326,9 @@ static PyObject *get_platform_specific_client_providers(PyObject *self)
return pylist;
#else
PyObject *pylist = PyList_New(0);
+#if defined(WIN32) || defined(__CYGWIN__) || defined(SVN_KEYCHAIN_PROVIDER_AVAILABLE)
PyObject *provider = NULL;
+#endif
if (pylist == NULL) {
Py_DECREF(pylist);
diff --git a/subvertpy/client.c b/subvertpy/client.c
index 04b9ae57..30f804e6 100644
--- a/subvertpy/client.c
+++ b/subvertpy/client.c
@@ -70,15 +70,35 @@ typedef struct {
apr_pool_t *pool;
} InfoObject;
+#define INVOKE_COMMIT_CALLBACK(pool, commit_info, callback) \
+ { \
+ PyObject *ret; \
+ PyObject *py_commit_info = py_commit_info_tuple(commit_info); \
+ if (py_commit_info == NULL) { \
+ apr_pool_destroy(pool); \
+ return NULL; \
+ } \
+ if (callback != Py_None) { \
+ ret = PyObject_CallFunction(callback, "O", py_commit_info); \
+ } else { \
+ ret = Py_None; \
+ Py_INCREF(ret); \
+ } \
+ Py_DECREF(py_commit_info); \
+ if (ret == NULL) { \
+ apr_pool_destroy(pool); \
+ return NULL; \
+ } \
+ } \
+
+
static int client_set_auth(PyObject *self, PyObject *auth, void *closure);
static int client_set_config(PyObject *self, PyObject *auth, void *closure);
-static bool client_check_path(const char *path, apr_pool_t *scratch_pool)
-{
- return svn_path_is_canonical(path, scratch_pool);
-}
-
-static bool client_path_list_to_apr_array(apr_pool_t *pool, PyObject *l, apr_array_header_t **ret)
+static bool client_list_to_apr_array(
+ apr_pool_t *pool, PyObject *l,
+ const char *(*convert)(PyObject*, apr_pool_t *),
+ apr_array_header_t **ret)
{
int i;
const char *path;
@@ -88,22 +108,17 @@ static bool client_path_list_to_apr_array(apr_pool_t *pool, PyObject *l, apr_arr
}
if (PyUnicode_Check(l) || PyBytes_Check(l)) {
*ret = apr_array_make(pool, 1, sizeof(char *));
- path = py_object_to_svn_string(l, pool);
+ path = convert(l, pool);
if (path == NULL) {
return false;
}
- if (!client_check_path(path, pool)) {
- PyErr_SetString(PyExc_ValueError, "Expected canonical path or URL");
- return false;
- }
APR_ARRAY_PUSH(*ret, const char *) = path;
} else if (PyList_Check(l)) {
*ret = apr_array_make(pool, PyList_Size(l), sizeof(char *));
for (i = 0; i < PyList_GET_SIZE(l); i++) {
PyObject *item = PyList_GET_ITEM(l, i);
- path = py_object_to_svn_string(item, pool);
- if (!client_check_path(path, pool)) {
- PyErr_SetString(PyExc_ValueError, "Expected canonical path or URL");
+ path = convert(item, pool);
+ if (path == NULL) {
return false;
}
APR_ARRAY_PUSH(*ret, const char *) = path;
@@ -142,6 +157,9 @@ static bool to_opt_revision(PyObject *arg, svn_opt_revision_t *ret)
char *text;
if (PyUnicode_Check(arg)) {
arg = PyUnicode_AsUTF8String(arg);
+ if (arg == NULL) {
+ return false;
+ }
} else {
Py_INCREF(arg);
}
@@ -437,7 +455,7 @@ static svn_error_t *py_log_msg_func2(const char **log_msg, const char **tmp_file
return NULL;
}
-static PyObject *py_commit_info_tuple(svn_commit_info_t *ci)
+static PyObject *py_commit_info_tuple(const svn_commit_info_t *ci)
{
if (ci == NULL)
Py_RETURN_NONE;
@@ -741,27 +759,79 @@ static PyObject *client_checkout(PyObject *self, PyObject *args, PyObject *kwarg
return PyLong_FromLong(result_rev);
}
+#if ONLY_SINCE_SVN(1, 7)
+static svn_error_t *py_commit_callback2(const svn_commit_info_t *commit_info,
+ void *callback, apr_pool_t *pool) {
+ PyObject *py_callback = callback;
+ PyObject *py_commit_info;
+ PyObject *ret;
+
+ PyGILState_STATE state = PyGILState_Ensure();
+
+ py_commit_info = py_commit_info_tuple(commit_info);
+
+ if (py_commit_info == NULL) {
+ PyGILState_Release(state);
+ return py_svn_error();
+ }
+
+ if (py_callback != Py_None) {
+ ret = PyObject_CallFunction(py_callback, "O", py_commit_info);
+ } else {
+ ret = Py_None;
+ Py_INCREF(ret);
+ }
+ Py_DECREF(py_commit_info);
+
+ PyGILState_Release(state);
+
+ if (ret == NULL) {
+ return py_svn_error();
+ }
+
+ return NULL;
+}
+#endif
+
static PyObject *client_commit(PyObject *self, PyObject *args, PyObject *kwargs)
{
PyObject *targets;
ClientObject *client = (ClientObject *)self;
bool recurse=true, keep_locks=true;
apr_pool_t *temp_pool;
+#if ONLY_BEFORE_SVN(1, 8)
svn_commit_info_t *commit_info = NULL;
- PyObject *ret;
+#endif
apr_array_header_t *apr_targets;
+ bool include_file_externals = false;
+ bool include_dir_externals = false;
+ bool keep_changelist = false;
+ bool commit_as_operations = false;
+ const apr_array_header_t *changelists = NULL;
PyObject *revprops = Py_None;
- char *kwnames[] = { "targets", "recurse", "keep_locks", "revprops", NULL };
+ PyObject *callback = Py_None;
+ char *kwnames[] = {
+ "targets", "recurse", "keep_locks", "revprops",
+ "keep_changelist", "commit_as_operations", "include_file_externals",
+ "include_dir_externals", "callback", NULL };
#if ONLY_SINCE_SVN(1, 5)
apr_hash_t *hash_revprops;
#endif
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|bbO", kwnames, &targets, &recurse, &keep_locks, &revprops))
+ /* TODO(jelmer): Support changelists */
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|bbObbbbO", kwnames,
+ &targets, &recurse, &keep_locks,
+ &revprops, &keep_changelist,
+ &commit_as_operations,
+ &include_file_externals,
+ &include_dir_externals,
+ &callback)) {
return NULL;
+ }
temp_pool = Pool(NULL);
if (temp_pool == NULL) {
return NULL;
}
- if (!client_path_list_to_apr_array(temp_pool, targets, &apr_targets)) {
+ if (!client_list_to_apr_array(temp_pool, targets, py_object_to_svn_path_or_url, &apr_targets)) {
apr_pool_destroy(temp_pool);
return NULL;
}
@@ -772,9 +842,16 @@ static PyObject *client_commit(PyObject *self, PyObject *args, PyObject *kwargs)
return NULL;
}
-
-#if ONLY_SINCE_SVN(1, 5)
if (revprops != Py_None) {
+#if ONLY_BEFORE_SVN(1, 5)
+ if (PyDict_Size(revprops) > 0) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "Setting revision properties only supported on svn >= 1.5");
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+#endif
+
hash_revprops = prop_dict_to_hash(temp_pool, revprops);
if (hash_revprops == NULL) {
apr_pool_destroy(temp_pool);
@@ -784,26 +861,36 @@ static PyObject *client_commit(PyObject *self, PyObject *args, PyObject *kwargs)
hash_revprops = NULL;
}
- /* FIXME: Support keep_changelist and changelists */
- RUN_SVN_WITH_POOL(temp_pool, svn_client_commit4(&commit_info,
- apr_targets, recurse?svn_depth_infinity:svn_depth_files,
- keep_locks, false, NULL, hash_revprops,
- client->client, temp_pool));
+#if ONLY_SINCE_SVN(1, 8)
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_commit6(
+ apr_targets, recurse?svn_depth_infinity:svn_depth_files,
+ keep_locks, keep_changelist, commit_as_operations,
+ include_file_externals, include_dir_externals, changelists,
+ hash_revprops, py_commit_callback2, callback, client->client, temp_pool));
+#elif ONLY_SINCE_SVN(1, 5)
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_commit4(
+ &commit_info, apr_targets, recurse?svn_depth_infinity:svn_depth_files,
+ keep_locks, keep_changelist, changelists, hash_revprops,
+ client->client, temp_pool));
#else
- if (revprops != Py_None && PyDict_Size(revprops) > 0) {
- PyErr_SetString(PyExc_NotImplementedError,
- "Setting revision properties only supported on svn >= 1.5");
+ if (commit_as_operations) {
+ PyErr_SetString(PyExc_NotImplementedError, "commit_as_operations only support on svn >= 1.8");
apr_pool_destroy(temp_pool);
return NULL;
}
+
RUN_SVN_WITH_POOL(temp_pool, svn_client_commit3(&commit_info,
apr_targets,
recurse, keep_locks, client->client, temp_pool));
#endif
- ret = py_commit_info_tuple(commit_info);
+
+#if ONLY_BEFORE_SVN(1, 8)
+ INVOKE_COMMIT_CALLBACK(temp_pool, commit_info, callback);
+#endif
+
apr_pool_destroy(temp_pool);
- return ret;
+ Py_RETURN_NONE;
}
static PyObject *client_export(PyObject *self, PyObject *args, PyObject *kwargs)
@@ -812,10 +899,10 @@ static PyObject *client_export(PyObject *self, PyObject *args, PyObject *kwargs)
char *kwnames[] = { "from", "to", "rev", "peg_rev", "recurse", "ignore_externals", "overwrite", "native_eol", "ignore_keywords", NULL };
svn_revnum_t result_rev;
svn_opt_revision_t c_peg_rev, c_rev;
- PyObject *py_from, *py_to;
+ PyObject *py_from, *py_to;
const char *from, *to;
apr_pool_t *temp_pool;
- char *native_eol = NULL;
+ char *native_eol = NULL;
PyObject *peg_rev=Py_None, *rev=Py_None;
bool recurse=true, ignore_externals=false, overwrite=false, ignore_keywords=false;
@@ -831,27 +918,27 @@ static PyObject *client_export(PyObject *self, PyObject *args, PyObject *kwargs)
if (temp_pool == NULL)
return NULL;
- from = py_object_to_svn_string(py_from, temp_pool);
- if (from == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
+ from = py_object_to_svn_string(py_from, temp_pool);
+ if (from == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
- to = py_object_to_svn_dirent(py_to, temp_pool);
- if (to == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
+ to = py_object_to_svn_dirent(py_to, temp_pool);
+ if (to == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
#if ONLY_SINCE_SVN(1, 7)
- RUN_SVN_WITH_POOL(temp_pool, svn_client_export5(&result_rev, from, to,
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_export5(&result_rev, from, to,
&c_peg_rev, &c_rev, overwrite, ignore_externals, ignore_keywords,
recurse?svn_depth_infinity:svn_depth_files,
native_eol, client->client, temp_pool));
#elif ONLY_SINCE_SVN(1, 5)
RUN_SVN_WITH_POOL(temp_pool, svn_client_export4(&result_rev, from, to,
&c_peg_rev, &c_rev, overwrite, ignore_externals,
- recurse?svn_depth_infinity:svn_depth_files,
+ recurse?svn_depth_infinity:svn_depth_files,
native_eol, client->client, temp_pool));
#else
RUN_SVN_WITH_POOL(temp_pool, svn_client_export3(&result_rev, from, to,
@@ -864,148 +951,160 @@ static PyObject *client_export(PyObject *self, PyObject *args, PyObject *kwargs)
static PyObject *client_cat(PyObject *self, PyObject *args, PyObject *kwargs)
{
- ClientObject *client = (ClientObject *)self;
- char *kwnames[] = { "path", "output_stream", "revision", "peg_revision", NULL };
- char *path;
- PyObject *peg_rev=Py_None, *rev=Py_None;
- svn_opt_revision_t c_peg_rev, c_rev;
- apr_pool_t *temp_pool;
- svn_stream_t *stream;
- bool expand_keywords = true;
- PyObject *py_stream, *py_path, *ret;
- apr_hash_t *props = NULL;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|OOb", kwnames, &py_path, &py_stream, &rev, &peg_rev, &expand_keywords))
- return NULL;
-
- if (!to_opt_revision(rev, &c_rev))
- return NULL;
- if (!to_opt_revision(peg_rev, &c_peg_rev))
- return NULL;
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_string(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
- stream = new_py_stream(temp_pool, py_stream);
- if (stream == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
+ ClientObject *client = (ClientObject *)self;
+ char *kwnames[] = { "path", "output_stream", "revision", "peg_revision", NULL };
+ char *path;
+ PyObject *peg_rev=Py_None, *rev=Py_None;
+ svn_opt_revision_t c_peg_rev, c_rev;
+ apr_pool_t *temp_pool;
+ svn_stream_t *stream;
+ bool expand_keywords = true;
+ PyObject *py_stream, *py_path, *ret;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|OOb", kwnames, &py_path, &py_stream, &rev, &peg_rev, &expand_keywords))
+ return NULL;
+
+ if (!to_opt_revision(rev, &c_rev))
+ return NULL;
+ if (!to_opt_revision(peg_rev, &c_peg_rev))
+ return NULL;
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_string(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ stream = new_py_stream(temp_pool, py_stream);
+ if (stream == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
#if ONLY_SINCE_SVN(1, 9)
- RUN_SVN_WITH_POOL(temp_pool, svn_client_cat3(
- &props, stream, path, &c_peg_rev, &c_rev, expand_keywords,
- client->client, temp_pool, temp_pool));
-
- ret = prop_hash_to_dict(props);
- if (ret == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
+ {
+ apr_hash_t *props = NULL;
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_cat3(
+ &props, stream, path, &c_peg_rev, &c_rev, expand_keywords,
+ client->client, temp_pool, temp_pool));
+
+ ret = prop_hash_to_dict(props);
+ if (ret == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ }
#else
- if (!expand_keywords) {
- PyErr_SetString(PyExc_NotImplementedError,
- "expand_keywords=false only supported with svn >= 1.9");
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- RUN_SVN_WITH_POOL(temp_pool, svn_client_cat2(stream, path,
- &c_peg_rev, &c_rev, client->client, temp_pool));
-
- ret = Py_None;
- Py_INCREF(ret);
+ if (!expand_keywords) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "expand_keywords=false only supported with svn >= 1.9");
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_cat2(stream, path,
+ &c_peg_rev, &c_rev, client->client, temp_pool));
+ ret = Py_None;
+ Py_INCREF(ret);
#endif
- apr_pool_destroy(temp_pool);
- return ret;
+ apr_pool_destroy(temp_pool);
+ return ret;
}
static PyObject *client_delete(PyObject *self, PyObject *args)
{
- PyObject *paths;
- bool force=false, keep_local=false;
- apr_pool_t *temp_pool;
- svn_commit_info_t *commit_info = NULL;
- PyObject *ret, *py_revprops;
- apr_array_header_t *apr_paths;
- ClientObject *client = (ClientObject *)self;
- apr_hash_t *hash_revprops;
-
- if (!PyArg_ParseTuple(args, "O|bbO", &paths, &force, &keep_local, &py_revprops))
- return NULL;
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL)
- return NULL;
- if (!client_path_list_to_apr_array(temp_pool, paths, &apr_paths)) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
- if (py_revprops != Py_None) {
- hash_revprops = prop_dict_to_hash(temp_pool, py_revprops);
- if (hash_revprops == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- } else {
- hash_revprops = NULL;
- }
+ PyObject *paths;
+ bool force=false, keep_local=false;
+ apr_pool_t *temp_pool;
+#if ONLY_BEFORE_SVN(1, 7)
+ svn_commit_info_t *commit_info = NULL;
+#endif
+ PyObject *py_revprops = Py_None;
+ apr_array_header_t *apr_paths;
+ ClientObject *client = (ClientObject *)self;
+ apr_hash_t *hash_revprops;
+ PyObject *callback = Py_None;
-#if ONLY_SINCE_SVN(1, 5)
- RUN_SVN_WITH_POOL(temp_pool, svn_client_delete3(
- &commit_info, apr_paths, force, keep_local, hash_revprops, client->client, temp_pool));
+ if (!PyArg_ParseTuple(args, "O|bbOO", &paths, &force, &keep_local, &py_revprops, &callback))
+ return NULL;
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL)
+ return NULL;
+ if (!client_list_to_apr_array(temp_pool, paths, py_object_to_svn_path_or_url, &apr_paths)) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ if (py_revprops != Py_None) {
+ hash_revprops = prop_dict_to_hash(temp_pool, py_revprops);
+ if (hash_revprops == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ } else {
+ hash_revprops = NULL;
+ }
+
+#if ONLY_SINCE_SVN(1, 7)
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_delete4(
+ apr_paths, force, keep_local, hash_revprops, py_commit_callback2, callback, client->client, temp_pool));
+#elif ONLY_SINCE_SVN(1, 5)
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_delete3(
+ &commit_info, apr_paths, force, keep_local, hash_revprops, client->client, temp_pool));
#else
- if (hash_revprops != NULL) {
- PyErr_SetString(PyExc_NotImplementedError,
+ if (hash_revprops != NULL) {
+ PyErr_SetString(PyExc_NotImplementedError,
"revprops not supported against svn 1.4");
- apr_pool_destroy(temp_pool);
- return NULL;
- }
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
- if (keep_local) {
- PyErr_SetString(PyExc_NotImplementedError,
+ if (keep_local) {
+ PyErr_SetString(PyExc_NotImplementedError,
"keep_local not supported against svn 1.4");
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- RUN_SVN_WITH_POOL(temp_pool, svn_client_delete2(
- &commit_info, apr_paths, force, client->client, temp_pool));
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_delete2(
+ &commit_info, apr_paths, force, client->client, temp_pool));
#endif
- ret = py_commit_info_tuple(commit_info);
+#if ONLY_BEFORE_SVN(1, 7)
+ INVOKE_COMMIT_CALLBACK(temp_pool, commit_info, callback);
+#endif
- apr_pool_destroy(temp_pool);
+ apr_pool_destroy(temp_pool);
- return ret;
+ Py_RETURN_NONE;
}
-static PyObject *client_mkdir(PyObject *self, PyObject *args)
+static PyObject *client_mkdir(PyObject *self, PyObject *args, PyObject *kwargs)
{
PyObject *paths, *revprops = NULL;
bool make_parents = false;
apr_pool_t *temp_pool;
+#if ONLY_BEFORE_SVN(1, 7)
svn_commit_info_t *commit_info = NULL;
- PyObject *ret;
+#endif
apr_array_header_t *apr_paths;
apr_hash_t *hash_revprops;
ClientObject *client = (ClientObject *)self;
+ PyObject *callback = Py_None;
+ char *kwnames[] = { "path", "make_parents", "revprops", "callback", NULL };
- if (!PyArg_ParseTuple(args, "O|bO", &paths, &make_parents, &revprops))
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|bOO", kwnames, &paths, &make_parents, &revprops, &callback))
return NULL;
temp_pool = Pool(NULL);
if (temp_pool == NULL)
return NULL;
- if (!client_path_list_to_apr_array(temp_pool, paths, &apr_paths)) {
+ if (!client_list_to_apr_array(temp_pool, paths, py_object_to_svn_path_or_url, &apr_paths)) {
apr_pool_destroy(temp_pool);
return NULL;
}
@@ -1027,9 +1126,15 @@ static PyObject *client_mkdir(PyObject *self, PyObject *args)
hash_revprops = NULL;
}
+#if ONLY_SINCE_SVN(1, 7)
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_mkdir4(apr_paths,
+ make_parents?TRUE:FALSE, hash_revprops, py_commit_callback2, callback,
+ client->client, temp_pool));
+#else
RUN_SVN_WITH_POOL(temp_pool, svn_client_mkdir3(&commit_info,
apr_paths,
make_parents?TRUE:FALSE, hash_revprops, client->client, temp_pool));
+#endif
#else
if (make_parents) {
PyErr_SetString(PyExc_ValueError,
@@ -1049,29 +1154,37 @@ static PyObject *client_mkdir(PyObject *self, PyObject *args)
client->client, temp_pool));
#endif
- ret = py_commit_info_tuple(commit_info);
+#if ONLY_BEFORE_SVN(1, 7)
+ INVOKE_COMMIT_CALLBACK(temp_pool, commit_info, callback);
+#endif
apr_pool_destroy(temp_pool);
- return ret;
+ Py_RETURN_NONE;
}
-
-
static PyObject *client_copy(PyObject *self, PyObject *args, PyObject *kwargs)
{
char *src_path, *dst_path;
PyObject *src_rev = Py_None;
+#if ONLY_BEFORE_SVN(1, 7)
svn_commit_info_t *commit_info = NULL;
+#endif
apr_pool_t *temp_pool;
svn_opt_revision_t c_src_rev;
bool copy_as_child = true, make_parents = false;
- PyObject *ret;
apr_hash_t *revprops;
bool ignore_externals = false;
+ bool metadata_only = false;
ClientObject *client = (ClientObject *)self;
+ PyObject *callback = Py_None;
+ bool pin_externals = false;
+#if ONLY_SINCE_SVN(1, 9)
+ apr_hash_t *pinned_externals = NULL;
+#endif
char *kwnames[] = { "src_path", "dst_path", "src_rev", "copy_as_child",
- "make_parents", "ignore_externals", "revprpos", NULL };
+ "make_parents", "ignore_externals", "revprops", "metadata_only",
+ "pin_externals", "callback", NULL };
#if ONLY_SINCE_SVN(1, 4)
PyObject *py_revprops = Py_None;
@@ -1081,9 +1194,10 @@ static PyObject *client_copy(PyObject *self, PyObject *args, PyObject *kwargs)
svn_client_copy_source_t src;
#endif
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss|ObbbO", kwnames,
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss|ObbbObbO", kwnames,
&src_path, &dst_path, &src_rev, &copy_as_child, &make_parents,
- &ignore_externals, &py_revprops))
+ &ignore_externals, &py_revprops, &metadata_only, &pin_externals,
+ &callback))
return NULL;
if (!to_opt_revision(src_rev, &c_src_rev))
return NULL;
@@ -1129,6 +1243,21 @@ static PyObject *client_copy(PyObject *self, PyObject *args, PyObject *kwargs)
return NULL;
}
#endif
+#if ONLY_BEFORE_SVN(1, 9)
+ if (metadata_only) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "metadata_only not supported in svn < 1.9");
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ if (pin_externals) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "pin_externals not supported in svn < 1.9");
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ // TODO(jelmer): Set pinned_externals
+#endif
#if ONLY_SINCE_SVN(1, 5)
src.path = src_path;
src.revision = src.peg_revision = &c_src_rev;
@@ -1138,9 +1267,20 @@ static PyObject *client_copy(PyObject *self, PyObject *args, PyObject *kwargs)
apr_pool_destroy(temp_pool);
return NULL;
}
- APR_ARRAY_IDX(src_paths, 0, svn_client_copy_source_t *) = &src;
+ APR_ARRAY_PUSH(src_paths, svn_client_copy_source_t *) = &src;
#endif
-#if ONLY_SINCE_SVN(1, 6)
+#if ONLY_SINCE_SVN(1, 9)
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_copy7(src_paths,
+ dst_path, copy_as_child, make_parents,
+ ignore_externals, metadata_only, pin_externals,
+ pinned_externals, revprops, py_commit_callback2,
+ callback, client->client, temp_pool));
+#elif ONLY_SINCE_SVN(1, 7)
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_copy6(src_paths,
+ dst_path, copy_as_child, make_parents,
+ ignore_externals, revprops, py_commit_callback2, callback,
+ client->client, temp_pool));
+#elif ONLY_SINCE_SVN(1, 6)
RUN_SVN_WITH_POOL(temp_pool, svn_client_copy5(&commit_info, src_paths,
dst_path, copy_as_child, make_parents,
ignore_externals, revprops, client->client, temp_pool));
@@ -1152,9 +1292,12 @@ static PyObject *client_copy(PyObject *self, PyObject *args, PyObject *kwargs)
RUN_SVN_WITH_POOL(temp_pool, svn_client_copy2(&commit_info, src_path,
&c_src_rev, dst_path, client->client, temp_pool));
#endif
- ret = py_commit_info_tuple(commit_info);
+#if ONLY_BEFORE_SVN(1, 7)
+ INVOKE_COMMIT_CALLBACK(temp_pool, commit_info, callback);
+#endif
apr_pool_destroy(temp_pool);
- return ret;
+
+ Py_RETURN_NONE;
}
static PyObject *client_propset(PyObject *self, PyObject *args)
@@ -1227,13 +1370,13 @@ static PyObject *client_propget(PyObject *self, PyObject *args)
bool recurse = false;
char *propname;
apr_pool_t *temp_pool;
- char *target;
+ const char *target;
PyObject *peg_revision = Py_None;
PyObject *revision;
ClientObject *client = (ClientObject *)self;
- PyObject *ret;
+ PyObject *ret, *py_target;
- if (!PyArg_ParseTuple(args, "ssO|Ob", &propname, &target, &peg_revision,
+ if (!PyArg_ParseTuple(args, "sOO|Ob", &propname, &py_target, &peg_revision,
&revision, &recurse))
return NULL;
if (!to_opt_revision(peg_revision, &c_peg_rev))
@@ -1243,14 +1386,19 @@ static PyObject *client_propget(PyObject *self, PyObject *args)
temp_pool = Pool(NULL);
if (temp_pool == NULL)
return NULL;
+ target = py_object_to_svn_abspath(py_target, temp_pool);
+ if (target == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
#if ONLY_SINCE_SVN(1, 8)
/* FIXME: Support changelists */
/* FIXME: Support actual_revnum */
/* FIXME: Support depth properly */
- /* FIXME: Support inherited_props */
+ /* FIXME: Support inherited_props */
RUN_SVN_WITH_POOL(temp_pool,
svn_client_propget5(&hash_props, NULL,
- propname, target,
+ propname, target,
&c_peg_rev, &c_rev, NULL, recurse?svn_depth_infinity:svn_depth_files,
NULL, client->client, temp_pool, temp_pool));
#elif ONLY_SINCE_SVN(1, 5)
@@ -1332,39 +1480,39 @@ static PyObject *client_proplist(PyObject *self, PyObject *args,
}
- RUN_SVN_WITH_POOL(temp_pool,
- svn_client_proplist2(&props, target, &c_peg_rev, &c_rev,
- (depth == svn_depth_infinity),
- client->client, temp_pool));
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_client_proplist2(&props, target, &c_peg_rev, &c_rev,
+ (depth == svn_depth_infinity),
+ client->client, temp_pool));
- for (i = 0; i < props->nelts; i++) {
- svn_client_proplist_item_t *item;
- PyObject *prop_dict, *value;
+ for (i = 0; i < props->nelts; i++) {
+ svn_client_proplist_item_t *item;
+ PyObject *prop_dict, *value;
- item = APR_ARRAY_IDX(props, i, svn_client_proplist_item_t *);
+ item = APR_ARRAY_IDX(props, i, svn_client_proplist_item_t *);
- prop_dict = prop_hash_to_dict(item->prop_hash);
- if (prop_dict == NULL) {
- apr_pool_destroy(temp_pool);
- Py_DECREF(prop_list);
- return NULL;
- }
+ prop_dict = prop_hash_to_dict(item->prop_hash);
+ if (prop_dict == NULL) {
+ apr_pool_destroy(temp_pool);
+ Py_DECREF(prop_list);
+ return NULL;
+ }
- value = Py_BuildValue("(sO)", item->node_name, prop_dict);
- if (value == NULL) {
- apr_pool_destroy(temp_pool);
- Py_DECREF(prop_list);
- Py_DECREF(prop_dict);
- return NULL;
- }
- if (PyList_Append(prop_list, value) != 0) {
- apr_pool_destroy(temp_pool);
- Py_DECREF(prop_list);
- Py_DECREF(prop_dict);
- Py_DECREF(value);
- return NULL;
- }
- Py_DECREF(value);
+ value = Py_BuildValue("(sO)", item->node_name, prop_dict);
+ if (value == NULL) {
+ apr_pool_destroy(temp_pool);
+ Py_DECREF(prop_list);
+ Py_DECREF(prop_dict);
+ return NULL;
+ }
+ if (PyList_Append(prop_list, value) != 0) {
+ apr_pool_destroy(temp_pool);
+ Py_DECREF(prop_list);
+ Py_DECREF(prop_dict);
+ Py_DECREF(value);
+ return NULL;
+ }
+ Py_DECREF(value);
}
apr_pool_destroy(temp_pool);
@@ -1415,50 +1563,77 @@ static PyObject *client_update(PyObject *self, PyObject *args, PyObject *kwargs)
PyObject *ret;
int i = 0;
ClientObject *client = (ClientObject *)self;
- bool allow_unver_obstructions = false,
- depth_is_sticky = false;
- char *kwnames[] =
- { "path", "revision", "recurse", "ignore_externals", "depth_is_sticky",
- "allow_unver_obstructions", NULL };
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Obbbb", kwnames,
- &paths, &rev, &recurse, &ignore_externals,
- &depth_is_sticky, &allow_unver_obstructions))
- return NULL;
-
- if (!to_opt_revision(rev, &c_rev))
- return NULL;
- temp_pool = Pool(NULL);
- if (temp_pool == NULL)
- return NULL;
- if (!client_path_list_to_apr_array(temp_pool, paths, &apr_paths)) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-#if ONLY_SINCE_SVN(1, 5)
- RUN_SVN_WITH_POOL(temp_pool, svn_client_update3(&result_revs,
- apr_paths, &c_rev, recurse?svn_depth_infinity:svn_depth_files,
- depth_is_sticky?TRUE:FALSE, ignore_externals, allow_unver_obstructions?TRUE:FALSE,
- client->client, temp_pool));
+ bool allow_unver_obstructions = false;
+ bool depth_is_sticky = false;
+ bool adds_as_modification = true;
+ bool make_parents = false;
+ char *kwnames[] =
+ { "path", "revision", "recurse", "ignore_externals", "depth_is_sticky",
+ "allow_unver_obstructions", "adds_as_modification", "make_parents",
+ NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Obbbbb", kwnames,
+ &paths, &rev, &recurse, &ignore_externals,
+ &depth_is_sticky, &allow_unver_obstructions, &adds_as_modification,
+ &make_parents))
+ return NULL;
+
+ if (!to_opt_revision(rev, &c_rev))
+ return NULL;
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL)
+ return NULL;
+ if (!client_list_to_apr_array(temp_pool, paths, py_object_to_svn_path_or_url, &apr_paths)) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+#if ONLY_BEFORE_SVN(1, 7)
+ if (!adds_as_modification) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "!adds_as_modification not supported before svn 1.7");
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ if (make_parents) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "make_parents not supported before svn 1.7");
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+#endif
+
+#if ONLY_SINCE_SVN(1, 7)
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_update4(&result_revs,
+ apr_paths, &c_rev, recurse?svn_depth_infinity:svn_depth_files,
+ depth_is_sticky?TRUE:FALSE, ignore_externals, allow_unver_obstructions?TRUE:FALSE,
+ adds_as_modification?TRUE:FALSE, make_parents?TRUE:FALSE,
+ client->client, temp_pool));
+#elif ONLY_SINCE_SVN(1, 5)
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_update3(&result_revs,
+ apr_paths, &c_rev, recurse?svn_depth_infinity:svn_depth_files,
+ depth_is_sticky?TRUE:FALSE, ignore_externals, allow_unver_obstructions?TRUE:FALSE,
+ client->client, temp_pool));
#else
- RUN_SVN_WITH_POOL(temp_pool, svn_client_update2(&result_revs,
- apr_paths, &c_rev,
- recurse, ignore_externals, client->client, temp_pool));
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_update2(&result_revs,
+ apr_paths, &c_rev,
+ recurse, ignore_externals, client->client, temp_pool));
#endif
- ret = PyList_New(result_revs->nelts);
- if (ret == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- for (i = 0; i < result_revs->nelts; i++) {
- ret_rev = APR_ARRAY_IDX(result_revs, i, svn_revnum_t);
- if (PyList_SetItem(ret, i, PyLong_FromLong(ret_rev)) != 0) {
- Py_DECREF(ret);
- return NULL;
- }
- }
- apr_pool_destroy(temp_pool);
- return ret;
+ ret = PyList_New(result_revs->nelts);
+ if (ret == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ for (i = 0; i < result_revs->nelts; i++) {
+ ret_rev = APR_ARRAY_IDX(result_revs, i, svn_revnum_t);
+ if (PyList_SetItem(ret, i, PyLong_FromLong(ret_rev)) != 0) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+ }
+ apr_pool_destroy(temp_pool);
+ return ret;
}
static PyObject *client_list(PyObject *self, PyObject *args, PyObject *kwargs)
@@ -1700,17 +1875,17 @@ static PyObject *client_log(PyObject *self, PyObject *args, PyObject *kwargs)
}
#endif
- if (!client_path_list_to_apr_array(temp_pool, paths, &apr_paths)) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
+ if (!client_list_to_apr_array(temp_pool, paths, py_object_to_svn_path_or_url, &apr_paths)) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
- if (revprops) {
- if (!string_list_to_apr_array(temp_pool, revprops, &apr_revprops)) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- }
+ if (revprops) {
+ if (!string_list_to_apr_array(temp_pool, revprops, &apr_revprops)) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ }
#if ONLY_SINCE_SVN(1, 6)
revision_range.start = c_start_rev;
@@ -1803,11 +1978,11 @@ static PyObject *client_info(PyObject *self, PyObject *args, PyObject *kwargs)
Py_BEGIN_ALLOW_THREADS;
#if ONLY_SINCE_SVN(1, 7)
/* FIXME: Support changelists */
- err = svn_client_info3(path, &c_peg_rev, &c_rev, depth, fetch_excluded?TRUE:FALSE,
- fetch_actual_only?TRUE:FALSE, NULL,
- info_receiver,
- entry_dict,
- client->client, temp_pool);
+ err = svn_client_info3(path, &c_peg_rev, &c_rev, depth, fetch_excluded?TRUE:FALSE,
+ fetch_actual_only?TRUE:FALSE, NULL,
+ info_receiver,
+ entry_dict,
+ client->client, temp_pool);
#elif ONLY_SINCE_SVN(1, 5)
/* FIXME: Support changelists */
err = svn_client_info2(path, &c_peg_rev, &c_rev, info_receiver, entry_dict,
@@ -1834,16 +2009,81 @@ static PyObject *client_info(PyObject *self, PyObject *args, PyObject *kwargs)
return entry_dict;
}
+static PyObject *client_lock(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ char *kwnames[] = {
+ "targets", "comment", "steal_lock",
+ NULL,
+ };
+ apr_array_header_t *targets;
+ apr_pool_t *temp_pool;
+ char *comment;
+ bool steal_lock = false;
+ ClientObject *client = (ClientObject *)self;
+ PyObject *py_targets;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|zb", kwnames,
+ &py_targets, &comment, &steal_lock))
+ return NULL;
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL)
+ return NULL;
+
+ if (!client_list_to_apr_array(temp_pool, py_targets, py_object_to_svn_path_or_url, &targets)) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_lock(targets, comment, steal_lock, client->client, temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *client_unlock(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ char *kwnames[] = {
+ "targets", "break_lock",
+ NULL,
+ };
+ apr_array_header_t *targets;
+ apr_pool_t *temp_pool;
+ bool break_lock = false;
+ ClientObject *client = (ClientObject *)self;
+ PyObject *py_targets;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|b", kwnames,
+ &py_targets, &break_lock))
+ return NULL;
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL)
+ return NULL;
+
+ if (!client_list_to_apr_array(temp_pool, py_targets, py_object_to_svn_path_or_url, &targets)) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_client_unlock(targets, break_lock, client->client, temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
static PyMethodDef client_methods[] = {
{ "add", (PyCFunction)client_add, METH_VARARGS|METH_KEYWORDS,
"S.add(path, recursive=True, force=False, no_ignore=False, no_autoprops=False)" },
{ "checkout", (PyCFunction)client_checkout, METH_VARARGS|METH_KEYWORDS,
"S.checkout(url, path, rev=None, peg_rev=None, recurse=True, ignore_externals=False, allow_unver_obstructions=False)" },
- { "export", (PyCFunction)client_export, METH_VARARGS|METH_KEYWORDS,
- "S.export(from, to, rev=None, peg_rev=None, recurse=True, ignore_externals=False, overwrite=False, native_eol=None)" },
+ { "export", (PyCFunction)client_export, METH_VARARGS|METH_KEYWORDS,
+ "S.export(from, to, rev=None, peg_rev=None, recurse=True, ignore_externals=False, overwrite=False, native_eol=None)" },
{ "cat", (PyCFunction)client_cat, METH_VARARGS|METH_KEYWORDS,
"S.cat(path, output_stream, revision=None, peg_revision=None)" },
- { "commit", (PyCFunction)client_commit, METH_VARARGS|METH_KEYWORDS, "S.commit(targets, recurse=True, keep_locks=True, revprops=None) -> (revnum, date, author)" },
+ { "commit", (PyCFunction)client_commit, METH_VARARGS|METH_KEYWORDS, "S.commit(targets, recurse=True, keep_locks=True, revprops=None, keep_changelist=False, commit_as_operations=False, include_file_externals=False, include_dir_externals=False, callback=None) -> (revnum, date, author)" },
{ "delete", client_delete, METH_VARARGS, "S.delete(paths, force=False)" },
{ "copy", (PyCFunction)client_copy, METH_VARARGS|METH_KEYWORDS, "S.copy(src_path, dest_path, srv_rev=None)" },
{ "propset", client_propset, METH_VARARGS, "S.propset(name, value, target, recurse=True, skip_checks=False)" },
@@ -1853,11 +2093,15 @@ static PyMethodDef client_methods[] = {
{ "update", (PyCFunction)client_update, METH_VARARGS|METH_KEYWORDS, "S.update(path, rev=None, recurse=True, ignore_externals=False) -> list of revnums" },
{ "list", (PyCFunction)client_list, METH_VARARGS|METH_KEYWORDS, "S.list(path, peg_revision, depth, dirents=ra.DIRENT_ALL, revision=None) -> list of directory entries" },
{ "diff", (PyCFunction)client_diff, METH_VARARGS|METH_KEYWORDS, "S.diff(rev1, rev2, path1=None, path2=None, relative_to_dir=None, diffopts=[], encoding=\"utf-8\", ignore_ancestry=True, no_diff_deleted=True, ignore_content_type=False) -> unified diff as a string" },
- { "mkdir", (PyCFunction)client_mkdir, METH_VARARGS|METH_KEYWORDS, "S.mkdir(paths, make_parents=False, revprops=None) -> (revnum, date, author)" },
+ { "mkdir", (PyCFunction)client_mkdir, METH_VARARGS|METH_KEYWORDS, "S.mkdir(paths, make_parents=False, revprops=None, callback=None)" },
{ "log", (PyCFunction)client_log, METH_VARARGS|METH_KEYWORDS,
"S.log(callback, paths, start_rev=None, end_rev=None, limit=0, peg_revision=None, discover_changed_paths=False, strict_node_history=False, include_merged_revisions=False, revprops=None)" },
{ "info", (PyCFunction)client_info, METH_VARARGS|METH_KEYWORDS,
"S.info(path, revision=None, peg_revision=None, depth=DEPTH_EMPTY) -> dict of info entries" },
+ { "lock", (PyCFunction)client_lock, METH_VARARGS,
+ "S.lock(targets, comment, steal_lock=False)" },
+ { "unlock", (PyCFunction)client_unlock, METH_VARARGS,
+ "S.lock(targets, break_lock=False)" },
{ NULL, }
};
@@ -1871,34 +2115,34 @@ static PyGetSetDef client_getset[] = {
static PyObject *get_default_ignores(PyObject *self)
{
- apr_array_header_t *patterns;
- apr_pool_t *pool;
- int i = 0;
- ConfigObject *configobj = (ConfigObject *)self;
- PyObject *ret;
-
- pool = Pool(NULL);
- if (pool == NULL)
- return NULL;
- RUN_SVN_WITH_POOL(pool, svn_wc_get_default_ignores(&patterns, configobj->config, pool));
- ret = PyList_New(patterns->nelts);
- for (i = 0; i < patterns->nelts; i++) {
- PyObject *item = PyBytes_FromString(APR_ARRAY_IDX(patterns, i, char *));
- if (item == NULL) {
- apr_pool_destroy(pool);
- Py_DECREF(item);
- Py_DECREF(ret);
- return NULL;
- }
+ apr_array_header_t *patterns;
+ apr_pool_t *pool;
+ int i = 0;
+ ConfigObject *configobj = (ConfigObject *)self;
+ PyObject *ret;
+
+ pool = Pool(NULL);
+ if (pool == NULL)
+ return NULL;
+ RUN_SVN_WITH_POOL(pool, svn_wc_get_default_ignores(&patterns, configobj->config, pool));
+ ret = PyList_New(patterns->nelts);
+ for (i = 0; i < patterns->nelts; i++) {
+ PyObject *item = PyBytes_FromString(APR_ARRAY_IDX(patterns, i, char *));
+ if (item == NULL) {
+ apr_pool_destroy(pool);
+ Py_DECREF(item);
+ Py_DECREF(ret);
+ return NULL;
+ }
if (PyList_SetItem(ret, i, item) != 0) {
- apr_pool_destroy(pool);
- Py_DECREF(item);
- Py_DECREF(ret);
- return NULL;
- }
- }
- apr_pool_destroy(pool);
- return ret;
+ apr_pool_destroy(pool);
+ Py_DECREF(item);
+ Py_DECREF(ret);
+ return NULL;
+ }
+ }
+ apr_pool_destroy(pool);
+ return ret;
}
static PyMethodDef config_methods[] = {
@@ -2134,7 +2378,7 @@ static PyMemberDef wc_info_members[] = {
static void wcinfo_dealloc(PyObject *self)
{
- PyObject_Del(self);
+ PyObject_Del(self);
}
PyTypeObject WCInfo_Type = {
@@ -2302,9 +2546,9 @@ static PyObject *get_config(PyObject *self, PyObject *args)
*/
static PyObject *version(PyObject *self)
{
- const svn_version_t *ver = svn_client_version();
- return Py_BuildValue("(iiis)", ver->major, ver->minor,
- ver->patch, ver->tag);
+ const svn_version_t *ver = svn_client_version();
+ return Py_BuildValue("(iiis)", ver->major, ver->minor,
+ ver->patch, ver->tag);
}
SVN_VERSION_DEFINE(svn_api_version);
@@ -2316,96 +2560,96 @@ SVN_VERSION_DEFINE(svn_api_version);
*/
static PyObject *api_version(PyObject *self)
{
- const svn_version_t *ver = &svn_api_version;
- return Py_BuildValue("(iiis)", ver->major, ver->minor,
- ver->patch, ver->tag);
+ const svn_version_t *ver = &svn_api_version;
+ return Py_BuildValue("(iiis)", ver->major, ver->minor,
+ ver->patch, ver->tag);
}
static PyMethodDef client_mod_methods[] = {
- { "get_config", get_config, METH_VARARGS, "get_config(config_dir=None) -> config" },
- { "api_version", (PyCFunction)api_version, METH_NOARGS,
- "api_version() -> (major, minor, patch, tag)\n\n"
- "Version of libsvn_client Subvertpy was compiled against."
- },
- { "version", (PyCFunction)version, METH_NOARGS,
- "version() -> (major, minor, patch, tag)\n\n"
- "Version of libsvn_wc currently used."
- },
- { NULL }
+ { "get_config", get_config, METH_VARARGS, "get_config(config_dir=None) -> config" },
+ { "api_version", (PyCFunction)api_version, METH_NOARGS,
+ "api_version() -> (major, minor, patch, tag)\n\n"
+ "Version of libsvn_client Subvertpy was compiled against."
+ },
+ { "version", (PyCFunction)version, METH_NOARGS,
+ "version() -> (major, minor, patch, tag)\n\n"
+ "Version of libsvn_wc currently used."
+ },
+ { NULL }
};
static PyObject *
moduleinit(void)
{
- PyObject *mod;
+ PyObject *mod;
- if (PyType_Ready(&Client_Type) < 0)
- return NULL;
+ if (PyType_Ready(&Client_Type) < 0)
+ return NULL;
- if (PyType_Ready(&Config_Type) < 0)
- return NULL;
+ if (PyType_Ready(&Config_Type) < 0)
+ return NULL;
- if (PyType_Ready(&ConfigItem_Type) < 0)
- return NULL;
+ if (PyType_Ready(&ConfigItem_Type) < 0)
+ return NULL;
- if (PyType_Ready(&Info_Type) < 0)
- return NULL;
+ if (PyType_Ready(&Info_Type) < 0)
+ return NULL;
- if (PyType_Ready(&WCInfo_Type) < 0)
- return NULL;
+ if (PyType_Ready(&WCInfo_Type) < 0)
+ return NULL;
- /* Make sure APR is initialized */
- apr_initialize();
+ /* Make sure APR is initialized */
+ apr_initialize();
#if PY_MAJOR_VERSION >= 3
- static struct PyModuleDef moduledef = {
- PyModuleDef_HEAD_INIT,
- "client", /* m_name */
- "Client methods", /* m_doc */
- -1, /* m_size */
- client_mod_methods, /* m_methods */
- NULL, /* m_reload */
- NULL, /* m_traverse */
- NULL, /* m_clear*/
- NULL, /* m_free */
- };
- mod = PyModule_Create(&moduledef);
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "client", /* m_name */
+ "Client methods", /* m_doc */
+ -1, /* m_size */
+ client_mod_methods, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear*/
+ NULL, /* m_free */
+ };
+ mod = PyModule_Create(&moduledef);
#else
- mod = Py_InitModule3("client", client_mod_methods, "Client methods");
+ mod = Py_InitModule3("client", client_mod_methods, "Client methods");
#endif
- if (mod == NULL)
- return NULL;
+ if (mod == NULL)
+ return NULL;
- Py_INCREF(&Client_Type);
- PyModule_AddObject(mod, "Client", (PyObject *)&Client_Type);
+ Py_INCREF(&Client_Type);
+ PyModule_AddObject(mod, "Client", (PyObject *)&Client_Type);
- PyModule_AddObject(mod, "depth_empty",
- (PyObject *)PyLong_FromLong(svn_depth_empty));
- PyModule_AddObject(mod, "depth_files",
- (PyObject *)PyLong_FromLong(svn_depth_files));
- PyModule_AddObject(mod, "depth_immediates",
- (PyObject *)PyLong_FromLong(svn_depth_immediates));
- PyModule_AddObject(mod, "depth_infinity",
- (PyObject *)PyLong_FromLong(svn_depth_infinity));
+ PyModule_AddObject(mod, "depth_empty",
+ (PyObject *)PyLong_FromLong(svn_depth_empty));
+ PyModule_AddObject(mod, "depth_files",
+ (PyObject *)PyLong_FromLong(svn_depth_files));
+ PyModule_AddObject(mod, "depth_immediates",
+ (PyObject *)PyLong_FromLong(svn_depth_immediates));
+ PyModule_AddObject(mod, "depth_infinity",
+ (PyObject *)PyLong_FromLong(svn_depth_infinity));
- Py_INCREF(&Config_Type);
- PyModule_AddObject(mod, "Config", (PyObject *)&Config_Type);
+ Py_INCREF(&Config_Type);
+ PyModule_AddObject(mod, "Config", (PyObject *)&Config_Type);
- return mod;
+ return mod;
}
#if PY_MAJOR_VERSION >= 3
PyMODINIT_FUNC
PyInit_client(void)
{
- return moduleinit();
+ return moduleinit();
}
#else
PyMODINIT_FUNC
initclient(void)
{
- moduleinit();
+ moduleinit();
}
#endif
diff --git a/subvertpy/editor.c b/subvertpy/editor.c
index b425de0c..71b543a5 100644
--- a/subvertpy/editor.c
+++ b/subvertpy/editor.c
@@ -397,15 +397,15 @@ static PyObject *py_dir_editor_delete_entry(PyObject *self, PyObject *args)
static PyObject *py_dir_editor_add_directory(PyObject *self, PyObject *args)
{
- PyObject *py_path;
+ PyObject *py_path, *py_copyfrom_path = Py_None;
const char *path;
- char *copyfrom_path = NULL;
+ const char *copyfrom_path = NULL;
svn_revnum_t copyfrom_rev = -1;
void *child_baton;
EditorObject *editor = (EditorObject *)self;
apr_pool_t *subpool;
- if (!PyArg_ParseTuple(args, "O|zl", &py_path, &copyfrom_path, &copyfrom_rev))
+ if (!PyArg_ParseTuple(args, "O|Ol", &py_path, &py_copyfrom_path, &copyfrom_rev))
return NULL;
if (editor->done) {
@@ -423,6 +423,13 @@ static PyObject *py_dir_editor_add_directory(PyObject *self, PyObject *args)
return NULL;
}
+ if (py_copyfrom_path != Py_None) {
+ copyfrom_path = py_object_to_svn_uri(py_copyfrom_path, editor->pool);
+ if (copyfrom_path == NULL) {
+ return NULL;
+ }
+ }
+
RUN_SVN(editor->editor->add_directory(
path, editor->baton,
copyfrom_path == NULL?NULL:svn_uri_canonicalize(copyfrom_path, editor->pool),
@@ -563,14 +570,14 @@ static PyObject *py_dir_editor_absent_directory(PyObject *self, PyObject *args)
static PyObject *py_dir_editor_add_file(PyObject *self, PyObject *args)
{
const char *path;
- char *copy_path=NULL;
- PyObject *py_path;
+ const char *copy_path=NULL;
+ PyObject *py_path, *py_copy_path = Py_None;
svn_revnum_t copy_rev=-1;
void *file_baton = NULL;
EditorObject *editor = (EditorObject *)self;
apr_pool_t *subpool;
- if (!PyArg_ParseTuple(args, "O|zl", &py_path, &copy_path, &copy_rev))
+ if (!PyArg_ParseTuple(args, "O|Ol", &py_path, &py_copy_path, &copy_rev))
return NULL;
if (editor->done) {
@@ -588,9 +595,15 @@ static PyObject *py_dir_editor_add_file(PyObject *self, PyObject *args)
return NULL;
}
+ if (py_copy_path != Py_None) {
+ copy_path = py_object_to_svn_uri(py_copy_path, editor->pool);
+ if (copy_path == NULL) {
+ return NULL;
+ }
+ }
+
RUN_SVN(editor->editor->add_file(path, editor->baton,
- copy_path == NULL?NULL:svn_uri_canonicalize(copy_path, editor->pool),
- copy_rev, editor->pool, &file_baton));
+ copy_path, copy_rev, editor->pool, &file_baton));
subpool = Pool(NULL);
if (subpool == NULL)
diff --git a/subvertpy/properties.py b/subvertpy/properties.py
index 567f60cc..8f256f5f 100644
--- a/subvertpy/properties.py
+++ b/subvertpy/properties.py
@@ -85,10 +85,10 @@ def parse_externals_description(base_url, val):
def is_url(u):
return ("://" in u)
ret = {}
- for l in val.splitlines():
- if l == "" or l[0] == "#":
+ for line in val.splitlines():
+ if line == "" or line[0] == "#":
continue
- pts = l.rsplit(None, 3)
+ pts = line.rsplit(None, 3)
if len(pts) == 4:
if pts[0] == "-r": # -r X URL DIR
revno = int(pts[1])
@@ -137,8 +137,8 @@ def parse_mergeinfo_property(text):
:param text: Property contents
"""
ret = {}
- for l in text.splitlines():
- (path, ranges) = l.rsplit(":", 1)
+ for line in text.splitlines():
+ (path, ranges) = line.rsplit(":", 1)
assert path.startswith("/")
ret[path] = []
for range in ranges.split(","):
diff --git a/subvertpy/ra_svn.py b/subvertpy/ra_svn.py
index 3e61e283..eae6a311 100644
--- a/subvertpy/ra_svn.py
+++ b/subvertpy/ra_svn.py
@@ -502,19 +502,20 @@ class SVNClient(SVNConnection):
host, port, socket.AF_UNSPEC,
socket.SOCK_STREAM, 0, 0)
self._socket = None
- err = RuntimeError('no addresses for %s:%s' % (host, port))
+ last_err = RuntimeError('no addresses for %s:%s' % (host, port))
for (family, socktype, proto, canonname, sockaddr) in sockaddrs:
try:
self._socket = socket.socket(family, socktype, proto)
self._socket.connect(sockaddr)
except socket.error as err:
+ last_err = err
if self._socket is not None:
self._socket.close()
self._socket = None
continue
break
if self._socket is None:
- raise err
+ raise last_err
self._socket.setblocking(True)
return (self._socket.recv, self._socket.send)
@@ -745,7 +746,7 @@ class SVNClient(SVNConnection):
self.send_msg([literal("switch"), args])
self._recv_ack()
return Reporter(self, update_editor)
- except:
+ except BaseException:
self.busy = False
raise
@@ -766,7 +767,7 @@ class SVNClient(SVNConnection):
self.send_msg([literal("update"), args])
self._recv_ack()
return Reporter(self, update_editor)
- except:
+ except BaseException:
self.busy = False
raise
@@ -787,7 +788,7 @@ class SVNClient(SVNConnection):
self.send_msg([literal("diff"), args])
self._recv_ack()
return Reporter(self, diff_editor)
- except:
+ except BaseException:
self.busy = False
raise
diff --git a/subvertpy/repos.c b/subvertpy/repos.c
index e6a41c15..61006ab8 100644
--- a/subvertpy/repos.c
+++ b/subvertpy/repos.c
@@ -39,7 +39,7 @@ typedef struct {
static PyObject *repos_create(PyObject *self, PyObject *args)
{
- char *path;
+ const char *path;
PyObject *config=Py_None, *fs_config=Py_None, *py_path;
svn_repos_t *repos = NULL;
apr_pool_t *pool;
@@ -64,7 +64,7 @@ static PyObject *repos_create(PyObject *self, PyObject *args)
return NULL;
}
- path = py_object_to_svn_string(py_path, pool);
+ path = py_object_to_svn_dirent(py_path, pool);
if (path == NULL) {
apr_pool_destroy(pool);
return NULL;
@@ -499,6 +499,7 @@ static PyObject *repos_verify(RepositoryObject *self, PyObject *args)
Py_RETURN_NONE;
}
+#if ONLY_SINCE_SVN(1, 6)
static svn_error_t *py_pack_notify(void *baton, apr_int64_t shard, svn_fs_pack_notify_action_t action, apr_pool_t *pool)
{
PyObject *ret;
@@ -510,9 +511,11 @@ static svn_error_t *py_pack_notify(void *baton, apr_int64_t shard, svn_fs_pack_n
Py_DECREF(ret);
return NULL;
}
+#endif
static PyObject *repos_pack(RepositoryObject *self, PyObject *args)
{
+#if ONLY_SINCE_SVN(1, 6)
apr_pool_t *temp_pool;
PyObject *notify_func = Py_None;
if (!PyArg_ParseTuple(args, "|O", &notify_func))
@@ -526,6 +529,10 @@ static PyObject *repos_pack(RepositoryObject *self, PyObject *args)
apr_pool_destroy(temp_pool);
Py_RETURN_NONE;
+#else
+ PyErr_SetString(PyExc_NotImplementedError, "pack_fs is only supported in Subversion >= 1.6");
+ return NULL;
+#endif
}
static PyMethodDef repos_methods[] = {
diff --git a/subvertpy/subr.c b/subvertpy/subr.c
new file mode 100644
index 00000000..6bf2aa26
--- /dev/null
+++ b/subvertpy/subr.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright © 2017 Jelmer Vernooij <jelmer@jelmer.uk>
+ * -*- coding: utf-8 -*-
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include <Python.h>
+#include <apr_general.h>
+#include <svn_path.h>
+#include <stdbool.h>
+#include <apr_md5.h>
+#include <apr_sha1.h>
+
+#include "util.h"
+
+static PyObject *py_uri_canonicalize(PyObject *self, PyObject *args)
+{
+ const char *uri;
+ PyObject *py_uri, *ret;
+ apr_pool_t *pool;
+
+ if (!PyArg_ParseTuple(args, "O", &py_uri))
+ return NULL;
+
+ pool = Pool(NULL);
+ uri = py_object_to_svn_uri(py_uri, pool);
+ ret = PyUnicode_FromString(uri);
+ apr_pool_destroy(pool);
+
+ return ret;
+}
+
+static PyObject *py_dirent_canonicalize(PyObject *self, PyObject *args)
+{
+ const char *dirent;
+ PyObject *py_dirent, *ret;
+ apr_pool_t *pool;
+
+ if (!PyArg_ParseTuple(args, "O", &py_dirent))
+ return NULL;
+
+ pool = Pool(NULL);
+ dirent = py_object_to_svn_dirent(py_dirent, pool);
+ ret = PyUnicode_FromString(dirent);
+ apr_pool_destroy(pool);
+
+ return ret;
+}
+
+static PyObject *py_abspath(PyObject *self, PyObject *args)
+{
+ const char *path;
+ PyObject *py_path, *ret;
+ apr_pool_t *pool;
+
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
+
+ pool = Pool(NULL);
+ path = py_object_to_svn_abspath(py_path, pool);
+ ret = PyUnicode_FromString(path);
+ apr_pool_destroy(pool);
+
+ return ret;
+}
+
+static PyMethodDef subr_methods[] = {
+ { "uri_canonicalize", py_uri_canonicalize, METH_VARARGS, "uri_canonicalize(uri) -> uri\n"
+ "Canonicalize a URI."},
+ { "dirent_canonicalize", py_dirent_canonicalize, METH_VARARGS, "dirent_canonicalize(dirent) -> dirent\n"
+ "Canonicalize a dirent path."},
+ { "abspath", py_abspath, METH_VARARGS, "abspath(path) -> path\n"
+ "Return the absolute version of a path."},
+ { NULL }
+};
+
+static PyObject *
+moduleinit(void)
+{
+ PyObject *mod;
+
+ apr_initialize();
+
+#if PY_MAJOR_VERSION >= 3
+ static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "subr", /* m_name */
+ "subr", /* m_doc */
+ -1, /* m_size */
+ subr_methods, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear*/
+ NULL, /* m_free */
+ };
+ mod = PyModule_Create(&moduledef);
+#else
+ mod = Py_InitModule3("subr", subr_methods, "Subversion subr");
+#endif
+ if (mod == NULL)
+ return NULL;
+
+ return mod;
+}
+
+#if PY_MAJOR_VERSION >= 3
+PyMODINIT_FUNC
+PyInit_subr(void)
+{
+ return moduleinit();
+}
+#else
+PyMODINIT_FUNC
+initsubr(void)
+{
+ moduleinit();
+}
+#endif
diff --git a/subvertpy/tests/__init__.py b/subvertpy/tests/__init__.py
index 7fb1e008..71b35763 100644
--- a/subvertpy/tests/__init__.py
+++ b/subvertpy/tests/__init__.py
@@ -198,6 +198,13 @@ class TestCommitEditor(TestDirEditor):
TestDirEditor.close(self)
self.editor.close()
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, exc_tb):
+ self.close()
+ return False
+
class SubversionTestCase(TestCaseInTempDir):
"""A test case that provides the ability to build Subversion
@@ -237,19 +244,13 @@ class SubversionTestCase(TestCaseInTempDir):
if sys.platform == 'win32':
revprop_hook = os.path.join(
abspath, "hooks", "pre-revprop-change.bat")
- f = open(revprop_hook, 'w')
- try:
+ with open(revprop_hook, 'w') as f:
f.write("exit 0\n")
- finally:
- f.close()
else:
revprop_hook = os.path.join(
abspath, "hooks", "pre-revprop-change")
- f = open(revprop_hook, 'w')
- try:
+ with open(revprop_hook, 'w') as f:
f.write("#!/bin/sh\n")
- finally:
- f.close()
os.chmod(revprop_hook, os.stat(revprop_hook).st_mode | 0o111)
if sys.platform == 'win32':
@@ -305,6 +306,12 @@ class SubversionTestCase(TestCaseInTempDir):
"""Resolve a conflict set on a local path."""
self.client_ctx.resolve(path, depth, choice)
+ def client_lock(self, path, comment="A comment", steal_lock=False):
+ self.client_ctx.lock(path, comment, steal_lock)
+
+ def client_unlock(self, path, steal_lock=False):
+ self.client_ctx.unlock(path, steal_lock)
+
def client_commit(self, dir, message=None, recursive=True):
"""Commit current changes in specified working copy.
@@ -313,10 +320,14 @@ class SubversionTestCase(TestCaseInTempDir):
olddir = os.path.abspath('.')
self.next_message = message
os.chdir(dir)
- info = self.client_ctx.commit(["."], recursive, False)
+ info = []
+
+ def add_info(*args):
+ info.append(args)
+ self.client_ctx.commit(["."], recursive, False, callback=add_info)
os.chdir(olddir)
- assert info is not None
- return info
+ assert len(info) == 1
+ return info[0]
def client_add(self, relpath, recursive=True):
"""Add specified files to working copy.
@@ -334,7 +345,6 @@ class SubversionTestCase(TestCaseInTempDir):
:return: Dictionary
"""
r = ra.RemoteAccess(url)
- assert isinstance(url, str)
ret = {}
def rcvr(orig_paths, rev, revprops, has_children=None):
@@ -343,7 +353,7 @@ class SubversionTestCase(TestCaseInTempDir):
revprops.get(properties.PROP_REVISION_AUTHOR),
revprops.get(properties.PROP_REVISION_DATE),
revprops.get(properties.PROP_REVISION_LOG))
- r.get_log(rcvr, [""], start_revnum, stop_revnum, 0, True, True,
+ r.get_log(rcvr, [u""], start_revnum, stop_revnum, 0, True, True,
revprops=[properties.PROP_REVISION_AUTHOR,
properties.PROP_REVISION_DATE,
properties.PROP_REVISION_LOG])
@@ -392,11 +402,8 @@ class SubversionTestCase(TestCaseInTempDir):
os.makedirs(os.path.dirname(name))
except OSError:
pass
- f = open(name, 'wb')
- try:
+ with open(name, 'wb') as f:
f.write(content)
- finally:
- f.close()
def make_client(self, repospath, clientpath, allow_revprop_changes=True):
"""Create a repository and a checkout. Return the checkout.
@@ -442,6 +449,7 @@ def test_suite():
'ra',
'repos',
'server',
+ 'subr',
'wc',
]
module_names = ['subvertpy.tests.test_' + name for name in names]
diff --git a/subvertpy/tests/test_client.py b/subvertpy/tests/test_client.py
index a1a0534d..7fa04c6e 100644
--- a/subvertpy/tests/test_client.py
+++ b/subvertpy/tests/test_client.py
@@ -217,7 +217,7 @@ class TestClient(SubversionTestCase):
self.client.log_msg_func = lambda c: commit_msg_1
self.client.commit(["dc"])
commit_1_dt = datetime.utcnow()
- self.client.log(cb, "dc/foo")
+ self.client.log(cb, "dc/foo", start_rev="HEAD", end_rev=1)
self.assertEqual(1, len(log_entries))
self.assertEqual(None, log_entries[0]["changed_paths"])
self.assertEqual(1, log_entries[0]["revision"])
@@ -232,7 +232,9 @@ class TestClient(SubversionTestCase):
self.client.commit(["dc"])
commit_2_dt = datetime.utcnow()
log_entries = []
- self.client.log(cb, "dc/foo", discover_changed_paths=True)
+ self.client.log(
+ cb, "dc/foo", start_rev="HEAD", end_rev=1,
+ discover_changed_paths=True)
self.assertEqual(2, len(log_entries))
self.assertLogEntryChangedPathsEquals(["/foo", "/bar"], log_entries[0])
self.assertEqual(2, log_entries[0]["revision"])
diff --git a/subvertpy/tests/test_marshall.py b/subvertpy/tests/test_marshall.py
index 751276f2..47d659dc 100644
--- a/subvertpy/tests/test_marshall.py
+++ b/subvertpy/tests/test_marshall.py
@@ -28,20 +28,20 @@ from subvertpy.tests import TestCase
class TestMarshalling(TestCase):
def test_literal_txt(self):
- l = literal("foo")
- self.assertEqual("foo", l.txt)
+ line = literal("foo")
+ self.assertEqual("foo", line.txt)
def test_literal_str(self):
- l = literal("foo bar")
- self.assertEqual("foo bar", l.__str__())
+ line = literal("foo bar")
+ self.assertEqual("foo bar", line.__str__())
def test_literal_rep(self):
- l = literal("foo bar")
- self.assertEqual("foo bar", l.__repr__())
+ line = literal("foo bar")
+ self.assertEqual("foo bar", line.__repr__())
def test_marshall_error(self):
- e = MarshallError("bla bla")
- self.assertEqual("bla bla", e.__str__())
+ err = MarshallError("bla bla")
+ self.assertEqual("bla bla", err.__str__())
def test_marshall_int(self):
self.assertEqual(b"1 ", marshall(1))
diff --git a/subvertpy/tests/test_ra.py b/subvertpy/tests/test_ra.py
index 51ad42b3..cafa7479 100644
--- a/subvertpy/tests/test_ra.py
+++ b/subvertpy/tests/test_ra.py
@@ -85,9 +85,9 @@ class TestRemoteAccess(SubversionTestCase):
def test_get_url(self):
if ra.api_version() < (1, 5):
- self.assertRaises(NotImplementedError, self.ra.get_url)
+ self.assertRaises(NotImplementedError, self.ra.get_session_url)
else:
- self.assertEqual(self.repos_url, self.ra.get_url())
+ self.assertEqual(self.repos_url, self.ra.get_session_url())
def test_reparent(self):
self.ra.reparent(self.repos_url)
diff --git a/subvertpy/tests/test_repos.py b/subvertpy/tests/test_repos.py
index ed5f2067..d748df91 100644
--- a/subvertpy/tests/test_repos.py
+++ b/subvertpy/tests/test_repos.py
@@ -117,7 +117,10 @@ class TestRepository(TestCaseInTempDir):
def test_pack_fs(self):
r = repos.create(os.path.join(self.test_dir, "foo"))
- r.pack_fs()
+ if repos.api_version() < (1, 6):
+ self.assertRaises(NotImplementedError, r.pack_fs)
+ else:
+ r.pack_fs()
def test_paths_changed(self):
repos.create(os.path.join(self.test_dir, "foo"))
diff --git a/subvertpy/tests/test_subr.py b/subvertpy/tests/test_subr.py
new file mode 100644
index 00000000..c471e65f
--- /dev/null
+++ b/subvertpy/tests/test_subr.py
@@ -0,0 +1,64 @@
+# Copyright (C) 2017 Jelmer Vernooij <jelmer@jelmer.uk>
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""Subversion subr library tests."""
+
+import os
+from unittest import TestCase
+
+from subvertpy.subr import (
+ uri_canonicalize,
+ dirent_canonicalize,
+ abspath,
+ )
+
+
+class UriCanonicalizeTests(TestCase):
+
+ def test_canonicalize(self):
+ self.assertEqual(
+ 'https://www.example.com',
+ uri_canonicalize('https://www.example.com/'))
+ self.assertEqual(
+ 'https://www.example.com(bla)',
+ uri_canonicalize('https://www.example.com(bla)'))
+ self.assertEqual(
+ 'https://www.example.com/(bla)',
+ uri_canonicalize('https://www.example.com/(bla%29'))
+
+
+class DirentCanonicalizeTests(TestCase):
+
+ def test_canonicalize(self):
+ self.assertEqual(
+ '/foo/bar',
+ dirent_canonicalize('/foo/bar'))
+ self.assertEqual(
+ '/foo/bar',
+ dirent_canonicalize('/foo//bar'))
+
+
+class AbspathTests(TestCase):
+
+ def test_abspath(self):
+ self.assertEqual(
+ '/foo/bar',
+ abspath('/foo//bar'))
+ self.assertEqual(
+ os.path.join(os.getcwd(), 'bar'),
+ abspath('bar'))
+ self.assertEqual(
+ os.path.join(os.getcwd(), 'bar', 'foo'),
+ abspath('bar/foo'))
diff --git a/subvertpy/tests/test_wc.py b/subvertpy/tests/test_wc.py
index 940cfc6e..a501aee1 100644
--- a/subvertpy/tests/test_wc.py
+++ b/subvertpy/tests/test_wc.py
@@ -15,12 +15,13 @@
"""Subversion ra library tests."""
+import hashlib
from io import BytesIO
import os
-from unittest import SkipTest
import subvertpy
from subvertpy import (
+ NODE_DIR,
NODE_FILE,
wc,
)
@@ -42,16 +43,16 @@ class VersionTest(TestCase):
self.assertTrue(wc.api_version() <= wc.version())
-class WorkingCopyTests(TestCase):
+class AdmTests(TestCase):
def test_get_adm_dir(self):
- self.assertEqual(b".svn", wc.get_adm_dir())
+ self.assertEqual(".svn", wc.get_adm_dir())
def test_set_adm_dir(self):
old_dir_name = wc.get_adm_dir()
try:
wc.set_adm_dir(b"_svn")
- self.assertEqual(b"_svn", wc.get_adm_dir())
+ self.assertEqual("_svn", wc.get_adm_dir())
finally:
wc.set_adm_dir(old_dir_name)
@@ -68,11 +69,11 @@ class WorkingCopyTests(TestCase):
if wc.api_version() < (1, 5):
self.assertRaises(
NotImplementedError, wc.match_ignore_list, "foo", [])
- return # Skip test
- self.assertTrue(wc.match_ignore_list("foo", ["f*"]))
- self.assertTrue(wc.match_ignore_list("foo", ["foo"]))
- self.assertFalse(wc.match_ignore_list("foo", []))
- self.assertFalse(wc.match_ignore_list("foo", ["bar"]))
+ else:
+ self.assertTrue(wc.match_ignore_list("foo", ["f*"]))
+ self.assertTrue(wc.match_ignore_list("foo", ["foo"]))
+ self.assertFalse(wc.match_ignore_list("foo", []))
+ self.assertFalse(wc.match_ignore_list("foo", ["bar"]))
class WcTests(SubversionTestCase):
@@ -88,52 +89,64 @@ class WcTests(SubversionTestCase):
self.assertEqual((0, 0, 0, 0), ret)
-class AdmTests(SubversionTestCase):
-
- def setUp(self):
- super(AdmTests, self).setUp()
- if getattr(wc, "WorkingCopy", None) is None:
- raise SkipTest(
- "Subversion 1.7 API for WorkingCopy not yet supported")
+class AdmObjTests(SubversionTestCase):
def test_has_binary_prop(self):
self.make_client("repos", "checkout")
self.build_tree({"checkout/bar": b"\x00 \x01"})
self.client_add('checkout/bar')
- adm = wc.WorkingCopy(None, "checkout")
- path = os.path.join(self.test_dir, "checkout/bar")
- self.assertFalse(adm.has_binary_prop(path))
+ self.client_set_prop('checkout/bar', 'svn:mime-type', 'text/bar')
+ adm = wc.Adm(None, "checkout")
+ self.assertFalse(adm.has_binary_prop("checkout/bar"))
adm.close()
+ def test_with(self):
+ self.make_client("repos", "checkout")
+ self.build_tree({"checkout/bar": b"\x00 \x01"})
+ self.client_add('checkout/bar')
+ self.client_set_prop('checkout/bar', 'svn:mime-type', 'text/bar')
+ with wc.Adm(None, "checkout") as adm:
+ self.assertFalse(adm.has_binary_prop("checkout/bar"))
+
def test_get_ancestry(self):
repos_url = self.make_client("repos", "checkout")
self.build_tree({"checkout/bar": b"\x00 \x01"})
self.client_add('checkout/bar')
- adm = wc.WorkingCopy(None, "checkout")
+ adm = wc.Adm(None, "checkout")
self.assertEqual(("%s/bar" % repos_url, 0),
adm.get_ancestry("checkout/bar"))
adm.close()
def test_maybe_set_repos_root(self):
repos_url = self.make_client("repos", "checkout")
- adm = wc.WorkingCopy(None, "checkout")
+ adm = wc.Adm(None, "checkout")
adm.maybe_set_repos_root(
os.path.join(self.test_dir, "checkout"), repos_url)
adm.close()
def test_add_repos_file(self):
self.make_client("repos", "checkout")
- adm = wc.WorkingCopy(None, "checkout", True)
- adm.add_repos_file("checkout/bar", BytesIO(b"basecontents"),
- BytesIO(b"contents"), {}, {})
- self.assertEqual(b"basecontents",
- wc.get_pristine_contents("checkout/bar").read())
+ adm = wc.Adm(None, "checkout", True)
+ if wc.api_version() < (1, 6):
+ self.assertRaises(
+ NotImplementedError,
+ adm.add_repos_file, "checkout/bar",
+ BytesIO(b"basecontents"), BytesIO(b"contents"), {}, {})
+ else:
+ adm.add_repos_file("checkout/bar", BytesIO(b"basecontents"),
+ BytesIO(b"contents"), {}, {})
+ if wc.api_version() >= (1, 7):
+ self.skipTest("TODO: doesn't yet work with svn >= 1.7")
+ self.assertEqual(b"basecontents",
+ wc.get_pristine_contents("checkout/bar").read())
def test_mark_missing_deleted(self):
+ if wc.api_version() >= (1, 7):
+ self.skipTest("TODO: doesn't yet work with svn >= 1.7")
self.make_client("repos", "checkout")
self.build_tree({"checkout/bar": b"\x00 \x01"})
self.client_add('checkout/bar')
- adm = wc.WorkingCopy(None, "checkout", True)
+ adm = wc.Adm(None, "checkout", True)
os.remove("checkout/bar")
adm.mark_missing_deleted("checkout/bar")
self.assertFalse(os.path.exists("checkout/bar"))
@@ -142,25 +155,27 @@ class AdmTests(SubversionTestCase):
self.make_client("repos", "checkout")
self.build_tree({"checkout/bar": b"\x00 \x01"})
self.client_add('checkout/bar')
- adm = wc.WorkingCopy(None, "checkout", True)
+ adm = wc.Adm(None, "checkout", True)
adm.remove_from_revision_control("bar")
self.assertTrue(os.path.exists("checkout/bar"))
def test_relocate(self):
self.make_client("repos", "checkout")
- adm = wc.WorkingCopy(None, "checkout", True)
+ adm = wc.Adm(None, "checkout", True)
adm.relocate("checkout", "file://", "http://")
def test_translated_stream(self):
+ self.skipTest("TODO: doesn't yet work")
self.make_client("repos", "checkout")
self.build_tree({"checkout/bar": b"My id: $Id$"})
self.client_add('checkout/bar')
self.client_set_prop("checkout/bar", "svn:keywords", "Id\n")
self.client_commit("checkout", "foo")
- adm = wc.WorkingCopy(None, "checkout", True)
- path = os.path.join(self.test_dir, "checkout/bar")
- stream = adm.translated_stream(path, path, wc.TRANSLATE_TO_NF)
- self.assertTrue(stream.read().startswith(b"My id: $Id: "))
+ adm = wc.Adm(None, "checkout", True)
+ stream = adm.translated_stream(
+ 'checkout/bar', 'checkout/bar', wc.TRANSLATE_TO_NF)
+ body = stream.read()
+ self.assertTrue(body.startswith(b"My id: $Id: "), body)
def test_text_modified(self):
self.make_client("repos", "checkout")
@@ -168,7 +183,7 @@ class AdmTests(SubversionTestCase):
self.client_add('checkout/bar')
self.client_set_prop("checkout/bar", "svn:keywords", "Id\n")
self.client_commit("checkout", "foo")
- adm = wc.WorkingCopy(None, "checkout")
+ adm = wc.Adm(None, "checkout")
self.assertFalse(adm.text_modified("checkout/bar"))
self.build_tree({"checkout/bar": b"gambon"})
self.assertTrue(adm.text_modified("checkout/bar", True))
@@ -179,7 +194,7 @@ class AdmTests(SubversionTestCase):
self.client_add('checkout/bar')
self.client_set_prop("checkout/bar", "svn:keywords", "Id\n")
self.client_commit("checkout", "foo")
- adm = wc.WorkingCopy(None, "checkout", True)
+ adm = wc.Adm(None, "checkout", True)
self.assertFalse(adm.props_modified("checkout/bar"))
adm.prop_set("aprop", "avalue", "checkout/bar")
self.assertTrue(adm.props_modified("checkout/bar"))
@@ -188,37 +203,35 @@ class AdmTests(SubversionTestCase):
self.make_client("repos", "checkout")
self.build_tree({"checkout/bar": b"file"})
self.client_add('checkout/bar')
- adm = wc.WorkingCopy(None, "checkout", True)
+ adm = wc.Adm(None, "checkout", True)
adm.prop_set("aprop", "avalue", "checkout/bar")
- self.assertEqual(adm.prop_get("aprop", "checkout/bar"), "avalue")
+ self.assertEqual(adm.prop_get("aprop", "checkout/bar"), b"avalue")
adm.prop_set("aprop", None, "checkout/bar")
self.assertEqual(adm.prop_get("aprop", "checkout/bar"), None)
def test_committed_queue(self):
- if getattr(wc, "CommittedQueue", None) is None:
- raise SkipTest("CommittedQueue not available")
cq = wc.CommittedQueue()
self.make_client("repos", "checkout")
- adm = wc.WorkingCopy(None, "checkout", True)
+ adm = wc.Adm(None, "checkout", True)
adm.process_committed_queue(cq, 1, "2010-05-31T08:49:22.430000Z",
"jelmer")
def test_entry_not_found(self):
self.make_client("repos", "checkout")
- adm = wc.WorkingCopy(None, "checkout")
+ adm = wc.Adm(None, "checkout")
self.assertRaises(KeyError, adm.entry, "bar")
def test_entry(self):
self.make_client("repos", "checkout")
self.build_tree({"checkout/bar": b"\x00 \x01"})
self.client_add('checkout/bar')
- adm = wc.WorkingCopy(None, "checkout")
+ adm = wc.Adm(None, "checkout")
entry = adm.entry("checkout/bar")
self.assertEqual("bar", entry.name)
self.assertEqual(NODE_FILE, entry.kind)
self.assertEqual(0, entry.revision)
self.client_commit("checkout", "msg")
- adm = wc.WorkingCopy(None, "checkout")
+ adm = wc.Adm(None, "checkout")
entry = adm.entry("checkout/bar")
self.assertEqual("bar", entry.name)
self.assertEqual(NODE_FILE, entry.kind)
@@ -233,7 +246,7 @@ class AdmTests(SubversionTestCase):
self.make_client("repos", ".")
self.build_tree({"bar": None})
self.client_add('bar')
- adm = wc.WorkingCopy(None, ".")
+ adm = wc.Adm(None, ".")
self.assertTrue(adm.is_wc_root(self.test_dir))
self.assertFalse(adm.is_wc_root(os.path.join(self.test_dir, "bar")))
@@ -241,23 +254,33 @@ class AdmTests(SubversionTestCase):
self.make_client("repos", "checkout")
self.build_tree({"checkout/bar": b"text"})
self.client_add('checkout/bar')
- adm = wc.WorkingCopy(None, "checkout")
- self.assertEqual(wc.STATUS_ADDED, adm.status('bar').status)
+ adm = wc.Adm(None, "checkout")
+ self.assertEqual(
+ wc.STATUS_ADDED,
+ adm.status('checkout/bar').status)
self.client_commit("checkout", "foo")
- adm = wc.WorkingCopy(None, "checkout")
- self.assertEqual(wc.STATUS_NORMAL, adm.status('bar').status)
+ adm = wc.Adm(None, "checkout")
+ self.assertEqual(
+ wc.STATUS_NORMAL,
+ adm.status('checkout/bar').status)
def test_transmit_text_deltas(self):
+ if wc.api_version() >= (1, 7):
+ self.skipTest("TODO: doesn't yet work with svn >= 1.7")
self.make_client("repos", ".")
self.build_tree({"bar": b"blala"})
self.client_add('bar')
- adm = wc.WorkingCopy(None, ".", True)
+ adm = wc.Adm(None, ".", True)
class Editor(object):
"""Editor"""
def __init__(self):
self._windows = []
+ self._prop = {}
+
+ def change_prop(self, name, value):
+ self._prop[name] = value
def apply_textdelta(self, checksum):
def window_handler(window):
@@ -267,47 +290,120 @@ class AdmTests(SubversionTestCase):
def close(self):
pass
editor = Editor()
- (tmpfile, digest) = adm.transmit_text_deltas("bar", True, editor)
+ (tmpfile, md5_digest) = adm.transmit_text_deltas("bar", True, editor)
self.assertEqual(editor._windows,
[(0, 0, 5, 0, [(2, 0, 5)], b'blala'), None])
self.assertIsInstance(tmpfile, str)
- self.assertEqual(16, len(digest))
+ self.assertEqual(16, len(md5_digest))
+ self.assertEqual(hashlib.md5(b'blala').digest(), md5_digest)
bar = adm.entry("bar")
self.assertEqual(-1, bar.cmt_rev)
self.assertEqual(0, bar.revision)
+ self.assertIn(bar.checksum, (None, hashlib.md5(b'blala').hexdigest()))
cq = wc.CommittedQueue()
- cq.queue("bar", adm)
+ cq.queue("bar", adm, wcprop_changes=editor._prop,
+ md5_digest=md5_digest)
adm.process_committed_queue(cq, 1, "2010-05-31T08:49:22.430000Z",
"jelmer")
bar = adm.entry("bar")
self.assertEqual("bar", bar.name)
self.assertEqual(NODE_FILE, bar.kind)
self.assertEqual(wc.SCHEDULE_NORMAL, bar.schedule)
- self.assertIs(None, bar.checksum)
+ self.assertIn(bar.checksum, (None, hashlib.md5(b'blala').hexdigest()))
self.assertEqual(1, bar.cmt_rev)
self.assertEqual(1, bar.revision)
def test_process_committed_queue(self):
+ if wc.api_version() >= (1, 7):
+ self.skipTest("TODO: doesn't yet work with svn >= 1.7")
self.make_client("repos", "checkout")
- self.build_tree({"checkout/bar": b"la"})
+ self.build_tree({"checkout/bar": b"blala"})
self.client_add('checkout/bar')
- adm = wc.WorkingCopy(None, "checkout", True)
+ adm = wc.Adm(None, "checkout", True)
+
+ class Editor(object):
+ """Editor"""
+
+ def __init__(self):
+ self._windows = []
+ self._prop = {}
+
+ def change_prop(self, name, value):
+ self._prop[name] = value
+
+ def apply_textdelta(self, checksum):
+ def window_handler(window):
+ self._windows.append(window)
+ return window_handler
+
+ def close(self):
+ pass
+
+ editor = Editor()
+ (tmpfile, md5_digest) = adm.transmit_text_deltas(
+ "checkout/bar", True, editor)
+ self.assertEqual(editor._windows,
+ [(0, 0, 5, 0, [(2, 0, 5)], b'blala'), None])
+ self.assertIsInstance(tmpfile, str)
+ self.assertEqual(16, len(md5_digest))
+ self.assertEqual(hashlib.md5(b'blala').digest(), md5_digest)
+
cq = wc.CommittedQueue()
- cq.queue(os.path.join(self.test_dir, "checkout/bar"), adm)
+ cq.queue("checkout/bar", adm, wcprop_changes=editor._prop,
+ md5_digest=md5_digest)
adm.process_committed_queue(cq, 1, "2010-05-31T08:49:22.430000Z",
"jelmer")
bar = adm.entry("checkout/bar")
self.assertEqual("bar", bar.name)
self.assertEqual(NODE_FILE, bar.kind)
- self.assertEqual(wc.SCHEDULE_ADD, bar.schedule)
+ self.assertEqual(wc.SCHEDULE_NORMAL, bar.schedule)
+
+ def test_process_committed(self):
+ if wc.api_version() >= (1, 7):
+ self.skipTest("TODO: doesn't yet work with svn >= 1.7")
+ self.make_client("repos", ".")
+ self.build_tree({"bar": b"la"})
+ self.client_add('bar')
+ adm = wc.Adm(None, ".", True)
+
+ class Editor(object):
+ """Editor"""
+
+ def __init__(self):
+ self._windows = []
+
+ def apply_textdelta(self, checksum):
+ def window_handler(window):
+ self._windows.append(window)
+ return window_handler
+
+ def close(self):
+ pass
+ editor = Editor()
+ (tmpfile, digest) = adm.transmit_text_deltas("bar", True, editor)
+ self.assertEqual(editor._windows,
+ [(0, 0, 2, 0, [(2, 0, 2)], b'la'), None])
+ self.assertIsInstance(tmpfile, str)
+ self.assertEqual(16, len(digest))
+ self.assertEqual(hashlib.md5(b'la').digest(), digest)
+ bar = adm.entry("bar")
+ self.assertEqual(-1, bar.cmt_rev)
+ self.assertEqual(0, bar.revision)
+
+ adm.process_committed(
+ "bar", False, 1, "2010-05-31T08:49:22.430000Z", "jelmer")
+ bar = adm.entry("bar")
+ self.assertEqual("bar", bar.name)
+ self.assertEqual(NODE_FILE, bar.kind)
+ self.assertEqual(wc.SCHEDULE_NORMAL, bar.schedule)
def test_probe_try(self):
self.make_client("repos", "checkout")
self.build_tree({"checkout/bar": b"la"})
self.client_add('checkout/bar')
- adm = wc.WorkingCopy(None, "checkout", True)
+ adm = wc.Adm(None, "checkout", True)
try:
self.assertIs(None, adm.probe_try(self.test_dir))
except subvertpy.SubversionException as e:
@@ -315,5 +411,155 @@ class AdmTests(SubversionTestCase):
if num != subvertpy.ERR_WC_NOT_WORKING_COPY:
raise
self.assertEqual(
- "checkout",
+ os.path.abspath("checkout"),
adm.probe_try(os.path.join("checkout", "bar")).access_path())
+
+ def test_lock(self):
+ if wc.api_version() >= (1, 9):
+ self.skipTest("TODO: doesn't yet work with svn >= 1.9")
+ self.make_client("repos", "checkout")
+ self.build_tree({"checkout/bar": b"la"})
+ self.client_add('checkout/bar')
+ adm = wc.Adm(None, "checkout", True)
+ lock = wc.Lock()
+ lock.token = b"blah"
+ adm.add_lock("checkout", lock)
+ adm.remove_lock("checkout")
+
+
+class ContextTests(SubversionTestCase):
+
+ def setUp(self):
+ super(ContextTests, self).setUp()
+ if wc.api_version() < (1, 7):
+ self.skipTest("context API not available on Subversion < 1.7")
+
+ def test_create(self):
+ context = wc.Context()
+ self.assertIsInstance(context, wc.Context)
+
+ def test_locked(self):
+ context = wc.Context()
+ self.make_client("repos", "checkout")
+ self.assertEqual((False, False), context.locked("checkout"))
+
+ def test_check_wc(self):
+ context = wc.Context()
+ self.make_client("repos", "checkout")
+ self.assertIsInstance(context.check_wc("checkout"), int)
+
+ def test_text_modified(self):
+ context = wc.Context()
+ self.make_client("repos", "checkout")
+ with open('checkout/bla.txt', 'w') as f:
+ f.write("modified")
+ self.client_add("checkout/bla.txt")
+ self.assertTrue(context.text_modified("checkout/bla.txt"))
+
+ def test_props_modified(self):
+ context = wc.Context()
+ self.make_client("repos", "checkout")
+ with open('checkout/bla.txt', 'w') as f:
+ f.write("modified")
+ self.client_add("checkout/bla.txt")
+ self.assertFalse(context.props_modified("checkout/bla.txt"))
+
+ def test_conflicted(self):
+ context = wc.Context()
+ self.make_client("repos", "checkout")
+ with open('checkout/bla.txt', 'w') as f:
+ f.write("modified")
+ self.client_add("checkout/bla.txt")
+ self.assertEqual(
+ (False, False, False),
+ context.conflicted("checkout/bla.txt"))
+
+ def test_crawl_revisions(self):
+ context = wc.Context()
+ self.make_client("repos", "checkout")
+ with open('checkout/bla.txt', 'w') as f:
+ f.write("modified")
+ self.client_add("checkout/bla.txt")
+ ret = []
+
+ class Reporter(object):
+ def set_path(self, *args):
+ ret.append(args)
+
+ def finish(self):
+ pass
+ context.crawl_revisions("checkout", Reporter())
+
+ self.assertEqual(ret, [('', 0, 0, None, 3)])
+
+ def test_get_update_editor(self):
+ self.make_client("repos", "checkout")
+ context = wc.Context()
+ editor = context.get_update_editor("checkout", "")
+ editor.close()
+
+ def test_status(self):
+ self.make_client("repos", "checkout")
+ context = wc.Context()
+ status = context.status("checkout")
+ self.assertEqual(NODE_DIR, status.kind)
+
+ def test_walk_status(self):
+ self.make_client("repos", "checkout")
+ with open('checkout/bla.txt', 'w') as f:
+ f.write("modified")
+ self.client_add("checkout/bla.txt")
+ context = wc.Context()
+ result = {}
+ context.walk_status("checkout", result.__setitem__)
+ self.assertEqual(
+ set(result.keys()),
+ {os.path.abspath("checkout"),
+ os.path.abspath("checkout/bla.txt")})
+
+ def test_locking(self):
+ if wc.api_version() >= (1, 7):
+ self.skipTest("TODO: doesn't yet work with svn >= 1.7")
+ self.make_client("repos", "checkout")
+ with open('checkout/bla.txt', 'w') as f:
+ f.write("modified")
+ self.client_add("checkout/bla.txt")
+ context = wc.Context()
+ lock = wc.Lock(token=b'foo')
+ self.assertEqual((False, False), context.locked("checkout"))
+ context.add_lock("checkout/", lock)
+ self.assertEqual((True, True), context.locked("checkout"))
+ context.remove_lock("checkout/", lock)
+
+ def test_add_from_disk(self):
+ if wc.api_version() >= (1, 7):
+ self.skipTest("TODO: doesn't yet work with svn >= 1.7")
+ self.make_client("repos", "checkout")
+ with open('checkout/bla.txt', 'w') as f:
+ f.write("modified")
+ context = wc.Context()
+ lock = wc.Lock(token=b'foo')
+ lock.path = os.path.abspath('checkout')+"/"
+ context.add_lock("checkout", lock)
+ context.add_from_disk('checkout/bla.txt')
+ context.remove_lock("checkout", lock)
+
+ def test_get_prop_diffs(self):
+ self.make_client("repos", "checkout")
+ context = wc.Context()
+ (orig_props, propdelta) = context.get_prop_diffs("checkout")
+ self.assertEqual({}, orig_props)
+ self.assertEqual([], propdelta)
+
+ def test_process_committed_queue(self):
+ if wc.api_version() >= (1, 7):
+ self.skipTest("TODO: doesn't yet work with svn >= 1.7")
+ self.make_client("repos", "checkout")
+ adm = wc.Context()
+ self.build_tree({"checkout/bar": b"blala"})
+ self.client_add('checkout/bar')
+ adm.add_lock("checkout", wc.Lock(token=b'foo'))
+ cq = wc.CommittedQueue()
+ cq.queue("checkout/bar", adm)
+ adm.process_committed_queue(cq, 1, "2010-05-31T08:49:22.430000Z",
+ "jelmer")
diff --git a/subvertpy/util.c b/subvertpy/util.c
index 49c68899..5d679838 100644
--- a/subvertpy/util.c
+++ b/subvertpy/util.c
@@ -44,10 +44,21 @@ void PyErr_SetAprStatus(apr_status_t status)
#if ONLY_BEFORE_SVN(1, 7)
const char *
-svn_uri_canonicalize(const char *uri,
+_svn_uri_canonicalize(const char *uri,
apr_pool_t *result_pool)
{
- return svn_path_canonicalize(uri, result_pool);
+ uri = svn_path_canonicalize(uri, result_pool);
+
+ if (uri == NULL) {
+ return NULL;
+ }
+
+ uri = svn_path_uri_decode(uri, result_pool);
+ if (uri == NULL) {
+ return NULL;
+ }
+
+ return svn_path_uri_autoescape(uri, result_pool);
}
const char *
@@ -57,85 +68,132 @@ svn_relpath_canonicalize(const char *relpath,
return svn_path_canonicalize(relpath, result_pool);
}
+const char *
+svn_dirent_canonicalize(const char *dirent,
+ apr_pool_t *result_pool)
+{
+ return svn_path_canonicalize(dirent, result_pool);
+}
+
#endif
-const char *py_object_to_svn_dirent(PyObject *obj, apr_pool_t *pool)
+const char *py_object_to_svn_path_or_url(PyObject *obj, apr_pool_t *pool)
{
- const char *ret;
- PyObject *bytes_obj = NULL;
+ const char *ret;
+
+ if (PyUnicode_Check(obj)) {
+ obj = PyUnicode_AsUTF8String(obj);
+ if (obj == NULL) {
+ return NULL;
+ }
+ } else {
+ Py_INCREF(obj);
+ }
- if (PyUnicode_Check(obj)) {
- bytes_obj = obj = PyUnicode_AsUTF8String(obj);
- if (obj == NULL) {
- return NULL;
- }
- }
+ if (!PyBytes_Check(obj)) {
+ PyErr_SetString(PyExc_TypeError,
+ "URIs need to be UTF-8 bytestrings or unicode strings");
+ Py_DECREF(obj);
+ return NULL;
+ }
- if (PyBytes_Check(obj)) {
-#if ONLY_SINCE_SVN(1, 7)
- ret = svn_dirent_canonicalize(PyBytes_AsString(obj), pool);
-#else
- ret = svn_path_canonicalize(PyBytes_AsString(obj), pool);
-#endif
- Py_XDECREF(bytes_obj);
- return ret;
- } else {
- PyErr_SetString(PyExc_TypeError,
- "URIs need to be UTF-8 bytestrings or unicode strings");
- Py_XDECREF(bytes_obj);
- return NULL;
- }
+ ret = PyBytes_AsString(obj);
+ if (svn_path_is_url(ret)) {
+ ret = svn_uri_canonicalize(ret, pool);
+ } else {
+ ret = svn_dirent_canonicalize(ret, pool);
+ }
+
+ Py_DECREF(obj);
+ return ret;
}
-char *py_object_to_svn_string(PyObject *obj, apr_pool_t *pool)
+const char *py_object_to_svn_abspath(PyObject *obj, apr_pool_t *pool)
{
- char *ret;
- PyObject *bytes_obj = NULL;
+ const char *ret;
+
+ if (PyUnicode_Check(obj)) {
+ obj = PyUnicode_AsUTF8String(obj);
+ if (obj == NULL) {
+ return NULL;
+ }
+ } else {
+ Py_INCREF(obj);
+ }
- if (PyUnicode_Check(obj)) {
- bytes_obj = obj = PyUnicode_AsUTF8String(obj);
- if (obj == NULL) {
- return NULL;
- }
- }
+ if (!PyBytes_Check(obj)) {
+ PyErr_SetString(PyExc_TypeError,
+ "URIs need to be UTF-8 bytestrings or unicode strings");
+ Py_DECREF(obj);
+ return NULL;
+ }
- if (PyBytes_Check(obj)) {
- ret = apr_pstrdup(pool, PyBytes_AsString(obj));
- Py_XDECREF(bytes_obj);
- return ret;
- } else {
- PyErr_SetString(PyExc_TypeError,
- "URIs need to be UTF-8 bytestrings or unicode strings");
- Py_XDECREF(bytes_obj);
- return NULL;
- }
+ ret = PyBytes_AsString(obj);
+ ret = apr_pstrdup(pool, ret);
+ Py_DECREF(obj);
+ if (ret == NULL) {
+ return NULL;
+ }
+ if (svn_dirent_is_absolute(ret)) {
+ return svn_dirent_canonicalize(ret, pool);
+ } else {
+ const char *absolute;
+ RUN_SVN(svn_dirent_get_absolute(&absolute, ret, pool))
+ return svn_dirent_canonicalize(absolute, pool);
+ }
}
-const char *py_object_to_svn_uri(PyObject *obj, apr_pool_t *pool)
+const char *py_object_to_svn_dirent(PyObject *obj, apr_pool_t *pool)
{
- const char *ret;
- PyObject *bytes_obj = NULL;
+ const char *ret;
+
+ if (PyUnicode_Check(obj)) {
+ obj = PyUnicode_AsUTF8String(obj);
+ if (obj == NULL) {
+ return NULL;
+ }
+ } else {
+ Py_INCREF(obj);
+ }
- if (PyUnicode_Check(obj)) {
- bytes_obj = obj = PyUnicode_AsUTF8String(obj);
- if (obj == NULL) {
- return NULL;
- }
- }
+ if (PyBytes_Check(obj)) {
+ ret = svn_dirent_canonicalize(PyBytes_AsString(obj), pool);
+ Py_DECREF(obj);
+ return ret;
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "URIs need to be UTF-8 bytestrings or unicode strings");
+ Py_DECREF(obj);
+ return NULL;
+ }
+}
- if (PyBytes_Check(obj)) {
- ret = svn_uri_canonicalize(PyBytes_AsString(obj), pool);
- Py_XDECREF(bytes_obj);
- return ret;
- } else {
- PyErr_SetString(PyExc_TypeError,
- "URIs need to be UTF-8 bytestrings or unicode strings");
- Py_XDECREF(bytes_obj);
- return NULL;
- }
+char *py_object_to_svn_string(PyObject *obj, apr_pool_t *pool)
+{
+ char *ret;
+
+ if (PyUnicode_Check(obj)) {
+ obj = PyUnicode_AsUTF8String(obj);
+ if (obj == NULL) {
+ return NULL;
+ }
+ } else {
+ Py_INCREF(obj);
+ }
+
+ if (PyBytes_Check(obj)) {
+ ret = apr_pstrdup(pool, PyBytes_AsString(obj));
+ Py_DECREF(obj);
+ return ret;
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "URIs need to be UTF-8 bytestrings or unicode strings");
+ Py_DECREF(obj);
+ return NULL;
+ }
}
-const char *py_object_to_svn_relpath(PyObject *obj, apr_pool_t *pool)
+const char *py_object_to_svn_uri(PyObject *obj, apr_pool_t *pool)
{
const char *ret;
@@ -145,72 +203,97 @@ const char *py_object_to_svn_relpath(PyObject *obj, apr_pool_t *pool)
return NULL;
}
} else {
- Py_INCREF(obj);
- }
+ Py_INCREF(obj);
+ }
if (PyBytes_Check(obj)) {
- ret = svn_relpath_canonicalize(PyBytes_AsString(obj), pool);
+ ret = svn_uri_canonicalize(PyBytes_AsString(obj), pool);
Py_DECREF(obj);
return ret;
} else {
PyErr_SetString(PyExc_TypeError,
- "relative paths need to be UTF-8 bytestrings or unicode strings");
+ "URIs need to be UTF-8 bytestrings or unicode strings");
Py_DECREF(obj);
return NULL;
}
}
+const char *py_object_to_svn_relpath(PyObject *obj, apr_pool_t *pool)
+{
+ const char *ret;
+
+ if (PyUnicode_Check(obj)) {
+ obj = PyUnicode_AsUTF8String(obj);
+ if (obj == NULL) {
+ return NULL;
+ }
+ } else {
+ Py_INCREF(obj);
+ }
+
+ if (PyBytes_Check(obj)) {
+ ret = svn_relpath_canonicalize(PyBytes_AsString(obj), pool);
+ Py_DECREF(obj);
+ return ret;
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "relative paths need to be UTF-8 bytestrings or unicode strings");
+ Py_DECREF(obj);
+ return NULL;
+ }
+}
+
apr_pool_t *Pool(apr_pool_t *parent)
{
- apr_status_t status;
- apr_pool_t *ret;
- ret = NULL;
- status = apr_pool_create(&ret, parent);
- if (status != 0) {
- PyErr_SetAprStatus(status);
- return NULL;
- }
- return ret;
+ apr_status_t status;
+ apr_pool_t *ret;
+ ret = NULL;
+ status = apr_pool_create(&ret, parent);
+ if (status != 0) {
+ PyErr_SetAprStatus(status);
+ return NULL;
+ }
+ return ret;
}
PyTypeObject *PyErr_GetSubversionExceptionTypeObject(void)
{
- PyObject *coremod, *excobj;
- coremod = PyImport_ImportModule("subvertpy");
+ PyObject *coremod, *excobj;
+ coremod = PyImport_ImportModule("subvertpy");
- if (coremod == NULL) {
- return NULL;
- }
+ if (coremod == NULL) {
+ return NULL;
+ }
- excobj = PyObject_GetAttrString(coremod, "SubversionException");
- Py_DECREF(coremod);
+ excobj = PyObject_GetAttrString(coremod, "SubversionException");
+ Py_DECREF(coremod);
- if (excobj == NULL) {
- PyErr_BadInternalCall();
- return NULL;
- }
+ if (excobj == NULL) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
- return (PyTypeObject *)excobj;
+ return (PyTypeObject *)excobj;
}
PyTypeObject *PyErr_GetGaiExceptionTypeObject(void)
{
- PyObject *socketmod, *excobj;
- socketmod = PyImport_ImportModule("socket");
+ PyObject *socketmod, *excobj;
+ socketmod = PyImport_ImportModule("socket");
- if (socketmod == NULL) {
- return NULL;
- }
+ if (socketmod == NULL) {
+ return NULL;
+ }
- excobj = PyObject_GetAttrString(socketmod, "gaierror");
- Py_DECREF(socketmod);
+ excobj = PyObject_GetAttrString(socketmod, "gaierror");
+ Py_DECREF(socketmod);
- if (excobj == NULL) {
- PyErr_BadInternalCall();
- return NULL;
- }
+ if (excobj == NULL) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
- return (PyTypeObject *)excobj;
+ return (PyTypeObject *)excobj;
}
PyObject *PyErr_NewSubversionException(svn_error_t *error)
@@ -229,9 +312,7 @@ PyObject *PyErr_NewSubversionException(svn_error_t *error)
if (error->child != NULL) {
PyTypeObject *cls = PyErr_GetSubversionExceptionTypeObject();
PyObject *args = PyErr_NewSubversionException(error->child);
- child = cls->tp_new(cls, args, NULL);
- if (cls->tp_init != NULL)
- cls->tp_init(child, args, NULL);
+ child = PyObject_CallObject((PyObject *)cls, args);
Py_DECREF(cls);
Py_DECREF(args);
} else {
@@ -240,7 +321,7 @@ PyObject *PyErr_NewSubversionException(svn_error_t *error)
}
#if ONLY_SINCE_SVN(1, 4)
- message = svn_err_best_message(error, buf, sizeof(buf));
+ message = svn_err_best_message(error, buf, sizeof(buf)-1);
#else
message = error->message;
#endif
@@ -436,14 +517,12 @@ PyObject *prop_hash_to_dict(apr_hash_t *props)
py_key = Py_None;
Py_INCREF(py_key);
} else {
- py_key = PyUnicode_FromString(key);
+ py_key = PyUnicode_FromStringAndSize(key, klen);
}
if (PyDict_SetItem(py_props, py_key, py_val) != 0) {
Py_DECREF(py_key);
Py_DECREF(py_val);
- Py_DECREF(py_props);
- apr_pool_destroy(pool);
- return NULL;
+ goto fail_item;
}
Py_DECREF(py_key);
Py_DECREF(py_val);
@@ -478,17 +557,11 @@ apr_hash_t *prop_dict_to_hash(apr_pool_t *pool, PyObject *py_props)
}
while (PyDict_Next(py_props, &idx, &k, &v)) {
- char *key;
- if (PyUnicode_Check(k)) {
- k = PyUnicode_AsUTF8String(k);
- } else {
- Py_INCREF(k);
- }
+ char *key, *val;
+ Py_ssize_t val_size;
- if (!PyBytes_Check(k)) {
- PyErr_SetString(PyExc_TypeError,
- "property name should be unicode or byte string");
- Py_DECREF(k);
+ key = py_object_to_svn_string(k, pool);
+ if (key == NULL) {
return NULL;
}
@@ -498,39 +571,26 @@ apr_hash_t *prop_dict_to_hash(apr_pool_t *pool, PyObject *py_props)
Py_INCREF(v);
}
- if (!PyBytes_Check(v)) {
- PyErr_SetString(PyExc_TypeError,
- "property value should be unicode or byte string");
- Py_DECREF(k);
- Py_DECREF(v);
+ if (PyBytes_AsStringAndSize(v, &val, &val_size) == -1) {
return NULL;
}
- key = apr_pmemdup(pool, PyBytes_AsString(k), PyBytes_Size(k));
- if (key == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "property value should be unicode or byte string");
- Py_DECREF(k);
- Py_DECREF(v);
- return NULL;
- }
+ val_string = svn_string_ncreate(val, val_size, pool);
- val_string = svn_string_ncreate(PyBytes_AsString(v),
- PyBytes_Size(v), pool);
- apr_hash_set(hash_props, key, PyBytes_Size(k), val_string);
- Py_DECREF(k);
Py_DECREF(v);
+
+ apr_hash_set(hash_props, key, strlen(key), val_string);
}
return hash_props;
}
#if PY_MAJOR_VERSION >= 3
-#define SOURCEPATH_FORMAT3 "(Czl)"
-#define SOURCEPATH_FORMAT4 "(Czli)"
+#define SOURCEPATH_FORMAT3 "(CNl)"
+#define SOURCEPATH_FORMAT4 "(CNli)"
#else
-#define SOURCEPATH_FORMAT3 "(czl)"
-#define SOURCEPATH_FORMAT4 "(czli)"
+#define SOURCEPATH_FORMAT3 "(cNl)"
+#define SOURCEPATH_FORMAT4 "(cNli)"
#endif
PyObject *pyify_changed_paths(apr_hash_t *changed_paths, bool node_kind, apr_pool_t *pool)
@@ -551,13 +611,21 @@ PyObject *pyify_changed_paths(apr_hash_t *changed_paths, bool node_kind, apr_poo
}
for (idx = apr_hash_first(pool, changed_paths); idx != NULL;
idx = apr_hash_next(idx)) {
+ PyObject *py_copyfrom_path, *py_key;
+
apr_hash_this(idx, (const void **)&key, &klen, (void **)&val);
+ if (val->copyfrom_path == NULL) {
+ py_copyfrom_path = Py_None;
+ Py_INCREF(Py_None);
+ } else {
+ py_copyfrom_path = PyUnicode_FromString(val->copyfrom_path);
+ }
if (node_kind) {
- pyval = Py_BuildValue(SOURCEPATH_FORMAT4, val->action, val->copyfrom_path,
+ pyval = Py_BuildValue(SOURCEPATH_FORMAT4, val->action, py_copyfrom_path,
val->copyfrom_rev,
svn_node_unknown);
} else {
- pyval = Py_BuildValue(SOURCEPATH_FORMAT3, val->action, val->copyfrom_path,
+ pyval = Py_BuildValue(SOURCEPATH_FORMAT3, val->action, py_copyfrom_path,
val->copyfrom_rev);
}
if (pyval == NULL) {
@@ -570,11 +638,21 @@ PyObject *pyify_changed_paths(apr_hash_t *changed_paths, bool node_kind, apr_poo
Py_DECREF(py_changed_paths);
return NULL;
}
- if (PyDict_SetItemString(py_changed_paths, key, pyval) != 0) {
+
+ py_key = PyUnicode_FromString(key);
+ if (py_key == NULL) {
+ Py_DECREF(pyval);
+ Py_DECREF(py_changed_paths);
+ return NULL;
+ }
+
+ if (PyDict_SetItem(py_changed_paths, py_key, pyval) != 0) {
Py_DECREF(py_changed_paths);
+ Py_DECREF(py_key);
Py_DECREF(pyval);
return NULL;
}
+ Py_DECREF(py_key);
Py_DECREF(pyval);
}
}
@@ -601,8 +679,15 @@ PyObject *pyify_changed_paths2(apr_hash_t *changed_paths, apr_pool_t *pool)
}
for (idx = apr_hash_first(pool, changed_paths); idx != NULL;
idx = apr_hash_next(idx)) {
+ PyObject *py_key, *py_copyfrom_path;
apr_hash_this(idx, (const void **)&key, &klen, (void **)&val);
- pyval = Py_BuildValue(SOURCEPATH_FORMAT4, val->action, val->copyfrom_path,
+ if (val->copyfrom_path == NULL) {
+ py_copyfrom_path = Py_None;
+ Py_INCREF(Py_None);
+ } else {
+ py_copyfrom_path = PyUnicode_FromString(val->copyfrom_path);
+ }
+ pyval = Py_BuildValue(SOURCEPATH_FORMAT4, val->action, py_copyfrom_path,
val->copyfrom_rev, val->node_kind);
if (pyval == NULL) {
Py_DECREF(py_changed_paths);
@@ -614,11 +699,20 @@ PyObject *pyify_changed_paths2(apr_hash_t *changed_paths, apr_pool_t *pool)
Py_DECREF(pyval);
return NULL;
}
- if (PyDict_SetItemString(py_changed_paths, key, pyval) != 0) {
+ py_key = PyUnicode_FromString(key);
+ if (py_key == NULL) {
+ Py_DECREF(py_changed_paths);
Py_DECREF(pyval);
+ return NULL;
+ }
+
+ if (PyDict_SetItem(py_changed_paths, py_key, pyval) != 0) {
+ Py_DECREF(pyval);
+ Py_DECREF(py_key);
Py_DECREF(py_changed_paths);
return NULL;
}
+ Py_DECREF(py_key);
Py_DECREF(pyval);
}
}
@@ -840,6 +934,7 @@ static apr_hash_t *get_default_config(void)
pool = Pool(NULL);
RUN_SVN_WITH_POOL(pool,
svn_config_get_config(&default_config, NULL, pool));
+ /* TODO(jelmer): Deal with pool */
initialised = true;
}
@@ -1068,3 +1163,70 @@ PyTypeObject Stream_Type = {
.tp_new = stream_init, /* tp_new tp_new */
};
+
+PyObject *dirent_hash_to_dict(apr_hash_t *dirents, unsigned int dirent_fields, apr_pool_t *temp_pool)
+{
+ svn_dirent_t *dirent;
+ apr_ssize_t klen;
+ const char *key;
+ apr_hash_index_t *idx;
+ PyObject *py_dirents = PyDict_New();
+
+ if (py_dirents == NULL) {
+ return NULL;
+ }
+ idx = apr_hash_first(temp_pool, dirents);
+ while (idx != NULL) {
+ PyObject *item, *pykey;
+ apr_hash_this(idx, (const void **)&key, &klen, (void **)&dirent);
+ item = py_dirent(dirent, dirent_fields);
+ if (item == NULL) {
+ Py_DECREF(py_dirents);
+ return NULL;
+ }
+ if (key == NULL) {
+ pykey = Py_None;
+ Py_INCREF(pykey);
+ } else {
+ pykey = PyUnicode_FromStringAndSize(key, klen);
+ }
+ if (PyDict_SetItem(py_dirents, pykey, item) != 0) {
+ Py_DECREF(item);
+ Py_DECREF(pykey);
+ Py_DECREF(py_dirents);
+ return NULL;
+ }
+ Py_DECREF(pykey);
+ Py_DECREF(item);
+ idx = apr_hash_next(idx);
+ }
+ return py_dirents;
+}
+
+PyObject *propchanges_to_list(const apr_array_header_t *propchanges)
+{
+ int i;
+ svn_prop_t el;
+ PyObject *py_propchanges = PyList_New(propchanges->nelts);
+ PyObject *pyval;
+ if (py_propchanges == NULL) {
+ return NULL;
+ }
+ for (i = 0; i < propchanges->nelts; i++) {
+ el = APR_ARRAY_IDX(propchanges, i, svn_prop_t);
+ if (el.value != NULL)
+ pyval = Py_BuildValue("(sz#)", el.name, el.value->data, el.value->len);
+ else
+ pyval = Py_BuildValue("(sO)", el.name, Py_None);
+ if (pyval == NULL) {
+ Py_DECREF(py_propchanges);
+ return NULL;
+ }
+ if (PyList_SetItem(py_propchanges, i, pyval) != 0) {
+ Py_DECREF(py_propchanges);
+ return NULL;
+ }
+ }
+
+ return py_propchanges;
+}
diff --git a/subvertpy/util.h b/subvertpy/util.h
index bbbcf9b3..3ed0545b 100644
--- a/subvertpy/util.h
+++ b/subvertpy/util.h
@@ -21,6 +21,7 @@
#define _SUBVERTPY_UTIL_H_
#include <svn_version.h>
+#include <svn_io.h> /* for svn_stream_t */
#if SVN_VER_MAJOR != 1
#error "only svn 1.x is supported"
@@ -48,7 +49,7 @@ apr_hash_t *prop_dict_to_hash(apr_pool_t *pool, PyObject *py_props);
svn_error_t *py_svn_log_wrapper(
void *baton, apr_hash_t *changed_paths, long revision, const char *author,
const char *date, const char *message, apr_pool_t *pool);
-svn_error_t *py_svn_error(void);
+__attribute__((warn_unused_result)) svn_error_t *py_svn_error(void);
void PyErr_SetSubversionException(svn_error_t *error);
PyTypeObject *PyErr_GetSubversionExceptionTypeObject(void);
@@ -86,6 +87,7 @@ PyObject *PyErr_NewSubversionException(svn_error_t *error);
apr_hash_t *config_hash_from_object(PyObject *config, apr_pool_t *pool);
void PyErr_SetAprStatus(apr_status_t status);
PyObject *py_dirent(const svn_dirent_t *dirent, int dirent_fields);
+PyObject *dirent_hash_to_dict(apr_hash_t *dirents, unsigned int dirent_fields, apr_pool_t *temp_pool);
PyObject *PyOS_tmpfile(void);
PyObject *pyify_changed_paths(apr_hash_t *changed_paths, bool node_kind, apr_pool_t *pool);
bool pyify_log_message(
@@ -139,18 +141,28 @@ extern PyTypeObject Stream_Type;
#if ONLY_BEFORE_SVN(1, 7)
const char *
-svn_uri_canonicalize(const char *uri,
+_svn_uri_canonicalize(const char *uri,
apr_pool_t *result_pool);
const char *
svn_relpath_canonicalize(const char *relpath,
apr_pool_t *result_pool);
+
+const char *
+svn_dirent_canonicalize(const char *dirent,
+ apr_pool_t *result_pool);
+#define svn_uri_canonicalize _svn_uri_canonicalize
+#define svn_dirent_get_absolute svn_path_get_absolute
+#define svn_dirent_is_absolute svn_path_is_url
#endif
const char *py_object_to_svn_uri(PyObject *obj, apr_pool_t *pool);
const char *py_object_to_svn_dirent(PyObject *obj, apr_pool_t *pool);
const char *py_object_to_svn_relpath(PyObject *obj, apr_pool_t *pool);
+const char *py_object_to_svn_path_or_url(PyObject *obj, apr_pool_t *pool);
char *py_object_to_svn_string(PyObject *obj, apr_pool_t *pool);
-#define py_object_from_svn_abspath PyBytes_FromString
+const char *py_object_to_svn_abspath(PyObject *obj, apr_pool_t *pool);
+#define py_object_from_svn_abspath PyUnicode_FromString
+PyObject *propchanges_to_list(const apr_array_header_t *propchanges);
#if PY_MAJOR_VERSION >= 3
#define PyRepr_FromFormat PyUnicode_FromFormat
diff --git a/subvertpy/wc.c b/subvertpy/wc.c
index 7a635b25..4b6350c4 100644
--- a/subvertpy/wc.c
+++ b/subvertpy/wc.c
@@ -25,6 +25,7 @@
#include <stdbool.h>
#include <apr_md5.h>
#include <apr_sha1.h>
+#include <fcntl.h>
#include "util.h"
#include "editor.h"
@@ -34,59 +35,51 @@
#define T_BOOL T_BYTE
#endif
-#if ONLY_SINCE_SVN(1, 5)
-#define REPORTER_T svn_ra_reporter3_t
-#else
-#define REPORTER_T svn_ra_reporter2_t
-#endif
-
-static PyTypeObject Entry_Type;
-static PyTypeObject Status_Type;
-static PyTypeObject Adm_Type;
+typedef struct {
+ PyObject_HEAD
+ svn_lock_t lock;
+ apr_pool_t *pool;
+} LockObject;
-static PyObject *py_entry(const svn_wc_entry_t *entry);
-static PyObject *py_status(const svn_wc_status2_t *status);
+#if ONLY_SINCE_SVN(1, 7)
+typedef struct {
+ PyObject_VAR_HEAD
+ apr_pool_t *pool;
+ svn_wc_context_t *context;
+} ContextObject;
+static PyTypeObject Context_Type;
+#endif
#if ONLY_BEFORE_SVN(1, 5)
struct svn_wc_committed_queue_t
{
- apr_pool_t *pool;
- apr_array_header_t *queue;
- svn_boolean_t have_recursive;
+ apr_pool_t *pool;
+ apr_array_header_t *queue;
+ svn_boolean_t have_recursive;
};
-#if SVN_VER_MINOR < 5
-typedef struct svn_wc_committed_queue_t svn_wc_committed_queue_t;
-#endif
-
typedef struct
{
- const char *path;
- svn_wc_adm_access_t *adm_access;
- svn_boolean_t recurse;
- svn_boolean_t remove_lock;
- apr_array_header_t *wcprop_changes;
- unsigned char *digest;
+ const char *path;
+ svn_wc_adm_access_t *adm_access;
+ svn_boolean_t recurse;
+ svn_boolean_t remove_lock;
+ apr_array_header_t *wcprop_changes;
+ unsigned char *digest;
} committed_queue_item_t;
-#if SVN_VER_MINOR < 5
-static
-#endif
svn_wc_committed_queue_t *svn_wc_committed_queue_create(apr_pool_t *pool)
{
- svn_wc_committed_queue_t *q;
+ svn_wc_committed_queue_t *q;
- q = apr_palloc(pool, sizeof(*q));
- q->pool = pool;
- q->queue = apr_array_make(pool, 1, sizeof(committed_queue_item_t *));
- q->have_recursive = FALSE;
+ q = apr_palloc(pool, sizeof(*q));
+ q->pool = pool;
+ q->queue = apr_array_make(pool, 1, sizeof(committed_queue_item_t *));
+ q->have_recursive = FALSE;
- return q;
+ return q;
}
-#if SVN_VER_MINOR < 5
-static
-#endif
svn_error_t *svn_wc_queue_committed(svn_wc_committed_queue_t **queue,
const char *path,
svn_wc_adm_access_t *adm_access,
@@ -122,129 +115,159 @@ svn_error_t *svn_wc_queue_committed(svn_wc_committed_queue_t **queue,
#endif
typedef struct {
- PyObject_VAR_HEAD
- apr_pool_t *pool;
- svn_wc_committed_queue_t *queue;
+ PyObject_VAR_HEAD
+ apr_pool_t *pool;
+ svn_wc_committed_queue_t *queue;
} CommittedQueueObject;
-static PyTypeObject CommittedQueue_Type;
-
-#if ONLY_SINCE_SVN(1, 5)
-static svn_error_t *py_ra_report_set_path(void *baton, const char *path, svn_revnum_t revision, svn_depth_t depth, int start_empty, const char *lock_token, apr_pool_t *pool)
-{
- PyObject *self = (PyObject *)baton, *py_lock_token, *ret;
- PyGILState_STATE state = PyGILState_Ensure();
- if (lock_token == NULL) {
- py_lock_token = Py_None;
- Py_INCREF(py_lock_token);
- } else {
- py_lock_token = PyBytes_FromString(lock_token);
- }
- ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision, start_empty, py_lock_token, depth);
- Py_DECREF(py_lock_token);
- CB_CHECK_PYRETVAL(ret);
- Py_DECREF(ret);
- PyGILState_Release(state);
- return NULL;
-}
-
-static svn_error_t *py_ra_report_link_path(void *report_baton, const char *path, const char *url, svn_revnum_t revision, svn_depth_t depth, int start_empty, const char *lock_token, apr_pool_t *pool)
-{
- PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token;
- PyGILState_STATE state = PyGILState_Ensure();
- if (lock_token == NULL) {
- py_lock_token = Py_None;
- Py_INCREF(py_lock_token);
- } else {
- py_lock_token = PyBytes_FromString(lock_token);
- }
- ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision, start_empty, py_lock_token, depth);
- Py_DECREF(py_lock_token);
- CB_CHECK_PYRETVAL(ret);
- Py_DECREF(ret);
- PyGILState_Release(state);
- return NULL;
-}
-
-#else
-static svn_error_t *py_ra_report_set_path(void *baton, const char *path, svn_revnum_t revision, int start_empty, const char *lock_token, apr_pool_t *pool)
+svn_wc_committed_queue_t *PyObject_GetCommittedQueue(PyObject *obj)
{
- PyObject *self = (PyObject *)baton, *py_lock_token, *ret;
- PyGILState_STATE state = PyGILState_Ensure();
- if (lock_token == NULL) {
- py_lock_token = Py_None;
- Py_INCREF(py_lock_token);
- } else {
- py_lock_token = PyBytes_FromString(lock_token);
- }
- ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision, start_empty, py_lock_token, svn_depth_infinity);
- CB_CHECK_PYRETVAL(ret);
- Py_DECREF(ret);
- PyGILState_Release(state);
- return NULL;
+ return ((CommittedQueueObject *)obj)->queue;
}
-static svn_error_t *py_ra_report_link_path(void *report_baton, const char *path, const char *url, svn_revnum_t revision, int start_empty, const char *lock_token, apr_pool_t *pool)
-{
- PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token;
- PyGILState_STATE state = PyGILState_Ensure();
- if (lock_token == NULL) {
- py_lock_token = Py_None;
- Py_INCREF(py_lock_token);
- } else {
- py_lock_token = PyBytes_FromString(lock_token);
- }
- ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision, start_empty, py_lock_token, svn_depth_infinity);
- CB_CHECK_PYRETVAL(ret);
- Py_DECREF(ret);
- PyGILState_Release(state);
- return NULL;
+#if ONLY_SINCE_SVN(1, 5)
+static svn_error_t *py_ra_report3_set_path(void *baton, const char *path,
+ svn_revnum_t revision,
+ svn_depth_t depth, int start_empty,
+ const char *lock_token, apr_pool_t *pool)
+{
+ PyObject *self = (PyObject *)baton, *py_lock_token, *ret;
+ PyGILState_STATE state = PyGILState_Ensure();
+ if (lock_token == NULL) {
+ py_lock_token = Py_None;
+ Py_INCREF(py_lock_token);
+ } else {
+ py_lock_token = PyBytes_FromString(lock_token);
+ }
+ ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision,
+ start_empty, py_lock_token, depth);
+ Py_DECREF(py_lock_token);
+ CB_CHECK_PYRETVAL(ret);
+ Py_DECREF(ret);
+ PyGILState_Release(state);
+ return NULL;
+}
+
+static svn_error_t *py_ra_report3_link_path(void *report_baton,
+ const char *path, const char *url,
+ svn_revnum_t revision,
+ svn_depth_t depth, int start_empty,
+ const char *lock_token, apr_pool_t *pool)
+{
+ PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token;
+ PyGILState_STATE state = PyGILState_Ensure();
+ if (lock_token == NULL) {
+ py_lock_token = Py_None;
+ Py_INCREF(py_lock_token);
+ } else {
+ py_lock_token = PyBytes_FromString(lock_token);
+ }
+ ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision,
+ start_empty, py_lock_token, depth);
+ Py_DECREF(py_lock_token);
+ CB_CHECK_PYRETVAL(ret);
+ Py_DECREF(ret);
+ PyGILState_Release(state);
+ return NULL;
}
-
#endif
-static svn_error_t *py_ra_report_delete_path(void *baton, const char *path, apr_pool_t *pool)
-{
- PyObject *self = (PyObject *)baton, *ret;
- PyGILState_STATE state = PyGILState_Ensure();
- ret = PyObject_CallMethod(self, "delete_path", "s", path);
- CB_CHECK_PYRETVAL(ret);
- Py_DECREF(ret);
- PyGILState_Release(state);
- return NULL;
+static svn_error_t *py_ra_report2_set_path(void *baton, const char *path,
+ svn_revnum_t revision,
+ int start_empty, const char *lock_token,
+ apr_pool_t *pool)
+{
+ PyObject *self = (PyObject *)baton, *py_lock_token, *ret;
+ PyGILState_STATE state = PyGILState_Ensure();
+ if (lock_token == NULL) {
+ py_lock_token = Py_None;
+ Py_INCREF(py_lock_token);
+ } else {
+ py_lock_token = PyBytes_FromString(lock_token);
+ }
+ ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision,
+ start_empty, py_lock_token, svn_depth_infinity);
+ CB_CHECK_PYRETVAL(ret);
+ Py_DECREF(ret);
+ PyGILState_Release(state);
+ return NULL;
+}
+
+static svn_error_t *py_ra_report2_link_path(void *report_baton,
+ const char *path, const char *url,
+ svn_revnum_t revision,
+ int start_empty,
+ const char *lock_token,
+ apr_pool_t *pool)
+{
+ PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token;
+ PyGILState_STATE state = PyGILState_Ensure();
+ if (lock_token == NULL) {
+ py_lock_token = Py_None;
+ Py_INCREF(py_lock_token);
+ } else {
+ py_lock_token = PyBytes_FromString(lock_token);
+ }
+ ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision,
+ start_empty, py_lock_token, svn_depth_infinity);
+ CB_CHECK_PYRETVAL(ret);
+ Py_DECREF(ret);
+ PyGILState_Release(state);
+ return NULL;
+}
+
+static svn_error_t *py_ra_report_delete_path(void *baton, const char *path,
+ apr_pool_t *pool)
+{
+ PyObject *self = (PyObject *)baton, *ret;
+ PyGILState_STATE state = PyGILState_Ensure();
+ ret = PyObject_CallMethod(self, "delete_path", "s", path);
+ CB_CHECK_PYRETVAL(ret);
+ Py_DECREF(ret);
+ PyGILState_Release(state);
+ return NULL;
}
static svn_error_t *py_ra_report_finish(void *baton, apr_pool_t *pool)
{
- PyObject *self = (PyObject *)baton, *ret;
- PyGILState_STATE state = PyGILState_Ensure();
- ret = PyObject_CallMethod(self, "finish", "");
- CB_CHECK_PYRETVAL(ret);
- Py_DECREF(ret);
- PyGILState_Release(state);
- return NULL;
+ PyObject *self = (PyObject *)baton, *ret;
+ PyGILState_STATE state = PyGILState_Ensure();
+ ret = PyObject_CallMethod(self, "finish", "");
+ CB_CHECK_PYRETVAL(ret);
+ Py_DECREF(ret);
+ PyGILState_Release(state);
+ return NULL;
}
static svn_error_t *py_ra_report_abort(void *baton, apr_pool_t *pool)
{
- PyObject *self = (PyObject *)baton, *ret;
- PyGILState_STATE state = PyGILState_Ensure();
- ret = PyObject_CallMethod(self, "abort", "");
- CB_CHECK_PYRETVAL(ret);
- Py_DECREF(ret);
- PyGILState_Release(state);
- return NULL;
+ PyObject *self = (PyObject *)baton, *ret;
+ PyGILState_STATE state = PyGILState_Ensure();
+ ret = PyObject_CallMethod(self, "abort", "");
+ CB_CHECK_PYRETVAL(ret);
+ Py_DECREF(ret);
+ PyGILState_Release(state);
+ return NULL;
}
-static const REPORTER_T py_ra_reporter = {
- py_ra_report_set_path,
- py_ra_report_delete_path,
- py_ra_report_link_path,
- py_ra_report_finish,
- py_ra_report_abort,
+#if ONLY_SINCE_SVN(1, 5)
+const svn_ra_reporter3_t py_ra_reporter3 = {
+ py_ra_report3_set_path,
+ py_ra_report_delete_path,
+ py_ra_report3_link_path,
+ py_ra_report_finish,
+ py_ra_report_abort,
};
+#endif
+const svn_ra_reporter2_t py_ra_reporter2 = {
+ py_ra_report2_set_path,
+ py_ra_report_delete_path,
+ py_ra_report2_link_path,
+ py_ra_report_finish,
+ py_ra_report_abort,
+};
/**
@@ -273,57 +296,6 @@ static PyObject *api_version(PyObject *self)
ver->patch, ver->tag);
}
-static svn_error_t *py_wc_found_entry(const char *path, const svn_wc_entry_t *entry, void *walk_baton, apr_pool_t *pool)
-{
- PyObject *fn, *ret;
- PyObject *callbacks = (PyObject *)walk_baton;
- PyGILState_STATE state = PyGILState_Ensure();
- if (PyTuple_Check(callbacks)) {
- fn = PyTuple_GET_ITEM(callbacks, 0);
- } else {
- fn = (PyObject *)walk_baton;
- }
- ret = PyObject_CallFunction(fn, "sO", path, py_entry(entry));
- CB_CHECK_PYRETVAL(ret);
- Py_DECREF(ret);
- PyGILState_Release(state);
- return NULL;
-}
-
-#if ONLY_SINCE_SVN(1, 5)
-
-svn_error_t *py_wc_handle_error(const char *path, svn_error_t *err, void *walk_baton, apr_pool_t *pool)
-{
- PyObject *fn, *ret;
- PyObject *py_err;
- PyGILState_STATE state;
- PyObject *callbacks = (PyObject *)walk_baton;
- if (PyTuple_Check(callbacks)) {
- fn = PyTuple_GET_ITEM(callbacks, 1);
- } else {
- return err;
- }
- state = PyGILState_Ensure();
- py_err = PyErr_NewSubversionException(err);
- ret = PyObject_CallFunction(fn, "sO", path, py_err);
- CB_CHECK_PYRETVAL(ret);
- Py_DECREF(ret);
- PyGILState_Release(state);
- Py_DECREF(py_err);
- return NULL;
-}
-
-static svn_wc_entry_callbacks2_t py_wc_entry_callbacks2 = {
- py_wc_found_entry,
- py_wc_handle_error,
-};
-#else
-static svn_wc_entry_callbacks_t py_wc_entry_callbacks = {
- py_wc_found_entry
-};
-
-#endif
-
void py_wc_notify_func(void *baton, const svn_wc_notify_t *notify, apr_pool_t *pool)
{
@@ -332,877 +304,16 @@ void py_wc_notify_func(void *baton, const svn_wc_notify_t *notify, apr_pool_t *p
return;
if (notify->err != NULL) {
+ PyGILState_STATE state = PyGILState_Ensure();
PyObject *excval = PyErr_NewSubversionException(notify->err);
ret = PyObject_CallFunction(func, "O", excval);
Py_DECREF(excval);
Py_XDECREF(ret);
/* If ret was NULL, the cancel func should abort the operation. */
+ PyGILState_Release(state);
}
}
-
-typedef struct {
- PyObject_VAR_HEAD
- apr_pool_t *pool;
- svn_wc_entry_t entry;
-} EntryObject;
-
-static void entry_dealloc(PyObject *self)
-{
- apr_pool_destroy(((EntryObject *)self)->pool);
- PyObject_Del(self);
-}
-
-static PyMemberDef entry_members[] = {
- { "name", T_STRING, offsetof(EntryObject, entry.name), READONLY,
- "Name of the file"},
- { "copyfrom_url", T_STRING, offsetof(EntryObject, entry.copyfrom_url), READONLY,
- "Copyfrom location" },
- { "copyfrom_rev", T_LONG, offsetof(EntryObject, entry.copyfrom_rev), READONLY,
- "Copyfrom revision" },
- { "uuid", T_STRING, offsetof(EntryObject, entry.uuid), READONLY,
- "UUID of repository" },
- { "url", T_STRING, offsetof(EntryObject, entry.url), READONLY,
- "URL in repository" },
- { "repos", T_STRING, offsetof(EntryObject, entry.repos), READONLY,
- "Canonical repository URL" },
- { "schedule", T_INT, offsetof(EntryObject, entry.schedule), READONLY,
- "Scheduling (add, replace, delete, etc)" },
- { "kind", T_INT, offsetof(EntryObject, entry.kind), READONLY,
- "Kind of file (file, dir, etc)" },
- { "revision", T_LONG, offsetof(EntryObject, entry.revision), READONLY,
- "Base revision", },
- { "cmt_rev", T_LONG, offsetof(EntryObject, entry.cmt_rev), READONLY,
- "Last revision this was changed" },
- { "checksum", T_STRING, offsetof(EntryObject, entry.checksum), READONLY,
- "Hex MD5 checksum for the untranslated text base file" },
- { "cmt_date", T_LONG, offsetof(EntryObject, entry.cmt_date), READONLY,
- "Last date this was changed" },
- { "cmt_author", T_STRING, offsetof(EntryObject, entry.cmt_author), READONLY,
- "Last commit author of this item" },
- { NULL, }
-};
-
-static PyTypeObject Entry_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "wc.Entry", /* const char *tp_name; For printing, in format "<module>.<name>" */
- sizeof(EntryObject),
- 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
-
- /* Methods to implement standard operations */
-
- entry_dealloc, /* destructor tp_dealloc; */
- NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
- NULL, /* cmpfunc tp_compare; */
- NULL, /* reprfunc tp_repr; */
-
- /* Method suites for standard classes */
-
- NULL, /* PyNumberMethods *tp_as_number; */
- NULL, /* PySequenceMethods *tp_as_sequence; */
- NULL, /* PyMappingMethods *tp_as_mapping; */
-
- /* More standard operations (here for binary compatibility) */
-
- NULL, /* hashfunc tp_hash; */
- NULL, /* ternaryfunc tp_call; */
- NULL, /* reprfunc tp_str; */
- NULL, /* getattrofunc tp_getattro; */
- NULL, /* setattrofunc tp_setattro; */
-
- /* Functions to access object as input/output buffer */
- NULL, /* PyBufferProcs *tp_as_buffer; */
-
- /* Flags to define presence of optional/expanded features */
- 0, /* long tp_flags; */
-
- NULL, /* const char *tp_doc; Documentation string */
-
- /* Assigned meaning in release 2.0 */
- /* call function for all accessible objects */
- NULL, /* traverseproc tp_traverse; */
-
- /* delete references to contained objects */
- NULL, /* inquiry tp_clear; */
-
- /* Assigned meaning in release 2.1 */
- /* rich comparisons */
- NULL, /* richcmpfunc tp_richcompare; */
-
- /* weak reference enabler */
- 0, /* Py_ssize_t tp_weaklistoffset; */
-
- /* Added in release 2.2 */
- /* Iterators */
- NULL, /* getiterfunc tp_iter; */
- NULL, /* iternextfunc tp_iternext; */
-
- /* Attribute descriptor and subclassing stuff */
- NULL, /* struct PyMethodDef *tp_methods; */
- entry_members, /* struct PyMemberDef *tp_members; */
-
-};
-
-static PyObject *py_entry(const svn_wc_entry_t *entry)
-{
- EntryObject *ret;
-
- ret = PyObject_New(EntryObject, &Entry_Type);
- if (ret == NULL)
- return NULL;
-
- ret->pool = Pool(NULL);
- if (ret->pool == NULL)
- return NULL;
- ret->entry = *svn_wc_entry_dup(entry, ret->pool);
- return (PyObject *)ret;
-}
-
-typedef struct {
- PyObject_VAR_HEAD
- apr_pool_t *pool;
- svn_wc_status2_t status;
- PyObject *entry;
-} StatusObject;
-
-static void status_dealloc(PyObject *self)
-{
- apr_pool_destroy(((StatusObject *)self)->pool);
- Py_XDECREF(((StatusObject *)self)->entry);
- PyObject_Del(self);
-}
-
-static PyMemberDef status_members[] = {
- { "entry", T_OBJECT, offsetof(StatusObject, entry), READONLY,
- "Can be NULL if not under version control." },
- { "locked", T_BOOL, offsetof(StatusObject, status.locked), READONLY,
- "a directory can be 'locked' if a working copy update was interrupted." },
- { "copied", T_BOOL, offsetof(StatusObject, status.copied), READONLY,
- "a file or directory can be 'copied' if it's scheduled for addition-with-history (or part of a subtree that is scheduled as such.)." },
- { "switched", T_BOOL, offsetof(StatusObject, status.switched), READONLY,
- "a file or directory can be 'switched' if the switch command has been used." },
- { "url", T_STRING, offsetof(StatusObject, status.url), READONLY,
- "URL (actual or expected) in repository" },
- { "revision", T_LONG, offsetof(StatusObject, status.ood_last_cmt_rev), READONLY,
- "Set to the youngest committed revision, or SVN_INVALID_REVNUM if not out of date.", },
- { "kind", T_INT, offsetof(StatusObject, status.ood_kind), READONLY,
- "Set to the node kind of the youngest commit, or svn_node_none if not out of date.", },
- { "status", T_INT, offsetof(StatusObject, status.text_status), READONLY,
- "The status of the entry.", },
- { NULL, }
-};
-
-static PyTypeObject Status_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "wc.Status", /* const char *tp_name; For printing, in format "<module>.<name>" */
- sizeof(StatusObject),
- 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
-
- /* Methods to implement standard operations */
-
- status_dealloc, /* destructor tp_dealloc; */
- NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
- NULL, /* cmpfunc tp_compare; */
- NULL, /* reprfunc tp_repr; */
-
- /* Method suites for standard classes */
-
- NULL, /* PyNumberMethods *tp_as_number; */
- NULL, /* PySequenceMethods *tp_as_sequence; */
- NULL, /* PyMappingMethods *tp_as_mapping; */
-
- /* More standard operations (here for binary compatibility) */
-
- NULL, /* hashfunc tp_hash; */
- NULL, /* ternaryfunc tp_call; */
- NULL, /* reprfunc tp_str; */
- NULL, /* getattrofunc tp_getattro; */
- NULL, /* setattrofunc tp_setattro; */
-
- /* Functions to access object as input/output buffer */
- NULL, /* PyBufferProcs *tp_as_buffer; */
-
- /* Flags to define presence of optional/expanded features */
- 0, /* long tp_flags; */
-
- "Working copy status object", /* const char *tp_doc; Documentation string */
-
- /* Assigned meaning in release 2.0 */
- /* call function for all accessible objects */
- NULL, /* traverseproc tp_traverse; */
-
- /* delete references to contained objects */
- NULL, /* inquiry tp_clear; */
-
- /* Assigned meaning in release 2.1 */
- /* rich comparisons */
- NULL, /* richcmpfunc tp_richcompare; */
-
- /* weak reference enabler */
- 0, /* Py_ssize_t tp_weaklistoffset; */
-
- /* Added in release 2.2 */
- /* Iterators */
- NULL, /* getiterfunc tp_iter; */
- NULL, /* iternextfunc tp_iternext; */
-
- /* Attribute descriptor and subclassing stuff */
- NULL, /* struct PyMethodDef *tp_methods; */
- status_members, /* struct PyMemberDef *tp_members; */
-
-};
-
-static PyObject *py_status(const svn_wc_status2_t *status)
-{
- StatusObject *ret;
- svn_wc_status2_t *dup_status;
-
- ret = PyObject_New(StatusObject, &Status_Type);
- if (ret == NULL)
- return NULL;
-
- ret->pool = Pool(NULL);
- if (ret->pool == NULL) {
- PyObject_Del(ret);
- return NULL;
- }
-
- dup_status = svn_wc_dup_status2(status, ret->pool);
- if (dup_status == NULL)
- {
- PyErr_NoMemory();
- return NULL;
- }
- ret->status = *dup_status;
-
- ret->entry = py_entry(ret->status.entry);
- return (PyObject *)ret;
-}
-
-typedef struct {
- PyObject_VAR_HEAD
- svn_wc_adm_access_t *adm;
- apr_pool_t *pool;
-} AdmObject;
-
-#define ADM_CHECK_CLOSED(adm_obj) \
- if (adm_obj->adm == NULL) { \
- PyErr_SetString(PyExc_RuntimeError, "WorkingCopy instance already closed"); \
- return NULL; \
- }
-
-static PyObject *adm_init(PyTypeObject *self, PyObject *args, PyObject *kwargs)
-{
- PyObject *associated, *py_path;
- const char *path;
- bool write_lock=false;
- int depth=0;
- svn_wc_adm_access_t *parent_wc;
- svn_error_t *err;
- AdmObject *ret;
- char *kwnames[] = { "associated", "path", "write_lock", "depth", NULL };
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bi", kwnames,
- &associated, &py_path, &write_lock, &depth))
- return NULL;
-
- ret = PyObject_New(AdmObject, &Adm_Type);
- if (ret == NULL)
- return NULL;
-
- ret->pool = Pool(NULL);
- if (ret->pool == NULL) {
- return NULL;
- }
- if (associated == Py_None) {
- parent_wc = NULL;
- } else {
- parent_wc = ((AdmObject *)associated)->adm;
- }
-
- path = py_object_to_svn_dirent(py_path, ret->pool);
- if (path == NULL) {
- Py_DECREF(ret);
- return NULL;
- }
-
- Py_BEGIN_ALLOW_THREADS
- err = svn_wc_adm_open3(&ret->adm, parent_wc,
- path,
- write_lock, depth, py_cancel_check, NULL,
- ret->pool);
- Py_END_ALLOW_THREADS
-
- if (err != NULL) {
- handle_svn_error(err);
- svn_error_clear(err);
- Py_DECREF(ret);
- return NULL;
- }
-
- return (PyObject *)ret;
-}
-
-static PyObject *adm_access_path(PyObject *self)
-{
- AdmObject *admobj = (AdmObject *)self;
- ADM_CHECK_CLOSED(admobj);
- return py_object_from_svn_abspath(svn_wc_adm_access_path(admobj->adm));
-}
-
-static PyObject *adm_locked(PyObject *self)
-{
- AdmObject *admobj = (AdmObject *)self;
- ADM_CHECK_CLOSED(admobj);
- return PyBool_FromLong(svn_wc_adm_locked(admobj->adm));
-}
-
-static PyObject *adm_prop_get(PyObject *self, PyObject *args)
-{
- char *name;
- const char *path;
- AdmObject *admobj = (AdmObject *)self;
- const svn_string_t *value;
- apr_pool_t *temp_pool;
- PyObject *ret, *py_path;
-
- if (!PyArg_ParseTuple(args, "sO", &name, &py_path))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_get(&value, name, path, admobj->adm, temp_pool));
- if (value == NULL || value->data == NULL) {
- ret = Py_None;
- Py_INCREF(ret);
- } else {
- ret = PyBytes_FromStringAndSize(value->data, value->len);
- }
- apr_pool_destroy(temp_pool);
- return ret;
-}
-
-static PyObject *adm_prop_set(PyObject *self, PyObject *args)
-{
- char *name, *value;
- const char *path;
- AdmObject *admobj = (AdmObject *)self;
- bool skip_checks=false;
- apr_pool_t *temp_pool;
- int vallen;
- svn_string_t *cvalue;
- PyObject *py_path;
- PyObject *notify_func = Py_None;
-
- if (!PyArg_ParseTuple(args, "sz#O|bO", &name, &value, &vallen, &py_path, &skip_checks,
- &notify_func))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
- if (value == NULL) {
- cvalue = NULL;
- } else {
- cvalue = svn_string_ncreate(value, vallen, temp_pool);
- }
-#if ONLY_SINCE_SVN(1, 6)
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_set3(name, cvalue, path, admobj->adm,
- skip_checks, py_wc_notify_func, (void *)notify_func,
- temp_pool));
-#else
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_set2(name, cvalue, path, admobj->adm,
- skip_checks, temp_pool));
-#endif
- apr_pool_destroy(temp_pool);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *adm_entries_read(PyObject *self, PyObject *args)
-{
- apr_hash_t *entries;
- AdmObject *admobj = (AdmObject *)self;
- apr_pool_t *temp_pool;
- bool show_hidden=false;
- apr_hash_index_t *idx;
- const char *key;
- apr_ssize_t klen;
- svn_wc_entry_t *entry;
- PyObject *py_entries, *obj;
-
- if (!PyArg_ParseTuple(args, "|b", &show_hidden))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL)
- return NULL;
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_entries_read(&entries, admobj->adm,
- show_hidden, temp_pool));
- py_entries = PyDict_New();
- if (py_entries == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- idx = apr_hash_first(temp_pool, entries);
- while (idx != NULL) {
- apr_hash_this(idx, (const void **)&key, &klen, (void **)&entry);
- if (entry == NULL) {
- obj = Py_None;
- Py_INCREF(obj);
- } else {
- obj = py_entry(entry);
- }
- PyDict_SetItemString(py_entries, key, obj);
- Py_DECREF(obj);
- idx = apr_hash_next(idx);
- }
- apr_pool_destroy(temp_pool);
- return py_entries;
-}
-
-static PyObject *adm_walk_entries(PyObject *self, PyObject *args)
-{
- const char *path;
- PyObject *callbacks;
- bool show_hidden=false;
- apr_pool_t *temp_pool;
- AdmObject *admobj = (AdmObject *)self;
- svn_depth_t depth = svn_depth_infinity;
- PyObject *py_path;
-
- if (!PyArg_ParseTuple(args, "OO|bi", &py_path, &callbacks, &show_hidden, &depth))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
-#if ONLY_SINCE_SVN(1, 5)
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_walk_entries3(
- path, admobj->adm,
- &py_wc_entry_callbacks2, (void *)callbacks,
- depth, show_hidden, py_cancel_check, NULL,
- temp_pool));
-#else
- if (depth != svn_depth_infinity) {
- PyErr_SetString(PyExc_NotImplementedError,
- "depth != infinity not supported for svn < 1.5");
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_walk_entries2(
- path, admobj->adm,
- &py_wc_entry_callbacks, (void *)callbacks,
- show_hidden, py_cancel_check, NULL,
- temp_pool));
-#endif
- apr_pool_destroy(temp_pool);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *adm_entry(PyObject *self, PyObject *args)
-{
- const char *path;
- PyObject *py_path;
- bool show_hidden=false;
- apr_pool_t *temp_pool;
- AdmObject *admobj = (AdmObject *)self;
- const svn_wc_entry_t *entry;
- PyObject *ret;
-
- if (!PyArg_ParseTuple(args, "O|b", &py_path, &show_hidden))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_entry(&entry, path, admobj->adm, show_hidden, temp_pool));
-
- if (entry == NULL) {
- PyErr_Format(PyExc_KeyError, "No such entry '%s'", path);
- ret = NULL;
- } else {
- ret = py_entry(entry);
- }
-
- apr_pool_destroy(temp_pool);
- return ret;
-}
-
-static PyObject *adm_get_prop_diffs(PyObject *self, PyObject *args)
-{
- const char *path;
- apr_pool_t *temp_pool;
- apr_array_header_t *propchanges;
- apr_hash_t *original_props;
- PyObject *py_path;
- AdmObject *admobj = (AdmObject *)self;
- svn_prop_t el;
- int i;
- PyObject *py_propchanges, *py_orig_props, *pyval;
-
- if (!PyArg_ParseTuple(args, "O", &py_path))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_prop_diffs(&propchanges, &original_props,
- path, admobj->adm, temp_pool));
- py_propchanges = PyList_New(propchanges->nelts);
- if (py_propchanges == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- for (i = 0; i < propchanges->nelts; i++) {
- el = APR_ARRAY_IDX(propchanges, i, svn_prop_t);
- if (el.value != NULL)
- pyval = Py_BuildValue("(sz#)", el.name, el.value->data, el.value->len);
- else
- pyval = Py_BuildValue("(sO)", el.name, Py_None);
- if (pyval == NULL) {
- apr_pool_destroy(temp_pool);
- Py_DECREF(py_propchanges);
- return NULL;
- }
- if (PyList_SetItem(py_propchanges, i, pyval) != 0) {
- Py_DECREF(py_propchanges);
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- }
- py_orig_props = prop_hash_to_dict(original_props);
- apr_pool_destroy(temp_pool);
- if (py_orig_props == NULL) {
- Py_DECREF(py_propchanges);
- return NULL;
- }
- return Py_BuildValue("(NN)", py_propchanges, py_orig_props);
-}
-
-static PyObject *adm_add(PyObject *self, PyObject *args, PyObject *kwargs)
-{
- const char *path;
- char *copyfrom_url=NULL;
- svn_revnum_t copyfrom_rev=-1;
- char *kwnames[] = { "path", "copyfrom_url", "copyfrom_rev", "notify_func", "depth", NULL };
- PyObject *notify_func=Py_None, *py_path;
- AdmObject *admobj = (AdmObject *)self;
- apr_pool_t *temp_pool;
- svn_depth_t depth = svn_depth_infinity;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|zlOi", kwnames, &py_path,
- &copyfrom_url, &copyfrom_rev, &notify_func, &depth))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
-#if ONLY_SINCE_SVN(1, 6)
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_add3(
- path, admobj->adm,
- depth, svn_uri_canonicalize(copyfrom_url, temp_pool),
- copyfrom_rev, py_cancel_check, NULL,
- py_wc_notify_func,
- (void *)notify_func,
- temp_pool));
-#else
- if (depth != svn_depth_infinity) {
- PyErr_SetString(PyExc_NotImplementedError, "depth != infinity not supported on svn < 1.6");
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_add2(
- path, admobj->adm, copyfrom_url,
- copyfrom_rev, py_cancel_check,
- py_wc_notify_func,
- (void *)notify_func,
- temp_pool));
-#endif
- apr_pool_destroy(temp_pool);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *adm_copy(PyObject *self, PyObject *args)
-{
- AdmObject *admobj = (AdmObject *)self;
- char *src, *dst;
- PyObject *notify_func=Py_None;
- apr_pool_t *temp_pool;
-
- if (!PyArg_ParseTuple(args, "ss|O", &src, &dst, &notify_func))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL)
- return NULL;
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_copy2(src, admobj->adm, dst,
- py_cancel_check, NULL,
- py_wc_notify_func, (void *)notify_func,
- temp_pool));
- apr_pool_destroy(temp_pool);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *adm_delete(PyObject *self, PyObject *args, PyObject *kwargs)
-{
- AdmObject *admobj = (AdmObject *)self;
- apr_pool_t *temp_pool;
- char *kwnames[] = { "path", "notify_func", "keep_local",
- NULL };
- const char *path;
- PyObject *py_path;
- PyObject *notify_func=Py_None;
- bool keep_local = false;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Ob:delete", kwnames,
- &py_path, &notify_func, &keep_local))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
-#if ONLY_SINCE_SVN(1, 5)
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_delete3(path, admobj->adm,
- py_cancel_check, NULL,
- py_wc_notify_func, (void *)notify_func,
- keep_local,
- temp_pool));
-#else
- if (keep_local) {
- PyErr_SetString(PyExc_NotImplementedError,
- "keep_local not supported on Subversion < 1.5");
- return NULL;
- }
-
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_delete2(path, admobj->adm,
- py_cancel_check, NULL,
- py_wc_notify_func, (void *)notify_func,
- temp_pool));
-#endif
- apr_pool_destroy(temp_pool);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *adm_crawl_revisions(PyObject *self, PyObject *args, PyObject *kwargs)
-{
- const char *path;
- PyObject *reporter;
- bool restore_files=true, recurse=true, use_commit_times=true;
- PyObject *notify_func=Py_None;
- apr_pool_t *temp_pool;
- AdmObject *admobj = (AdmObject *)self;
- svn_wc_traversal_info_t *traversal_info;
- bool depth_compatibility_trick = false;
- bool honor_depth_exclude = false;
- char *kwnames[] = { "path", "reporter", "restore_files", "recurse", "use_commit_times", "notify_func", "depth_compatibility_trick", "honor_depth_exclude,", NULL };
- PyObject *py_path;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bbbObb", kwnames, &py_path,
- &reporter, &restore_files, &recurse, &use_commit_times,
- &notify_func, &depth_compatibility_trick, &honor_depth_exclude))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- traversal_info = svn_wc_init_traversal_info(temp_pool);
-#if ONLY_SINCE_SVN(1, 6)
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions4(path, admobj->adm,
- &py_ra_reporter, (void *)reporter,
- restore_files, recurse?svn_depth_infinity:svn_depth_files,
- honor_depth_exclude?TRUE:FALSE,
- depth_compatibility_trick?TRUE:FALSE, use_commit_times,
- py_wc_notify_func, (void *)notify_func,
- traversal_info, temp_pool));
-#elif ONLY_SINCE_SVN(1, 5)
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions3(path, admobj->adm,
- &py_ra_reporter, (void *)reporter,
- restore_files, recurse?svn_depth_infinity:svn_depth_files,
- depth_compatibility_trick, use_commit_times,
- py_wc_notify_func, (void *)notify_func,
- traversal_info, temp_pool));
-#else
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions2(path, admobj->adm,
- &py_ra_reporter, (void *)reporter,
- restore_files, recurse, use_commit_times,
- py_wc_notify_func, (void *)notify_func,
- traversal_info, temp_pool));
-#endif
- apr_pool_destroy(temp_pool);
-
- Py_RETURN_NONE;
-}
-
-static void wc_done_handler(void *self)
-{
- AdmObject *admobj = (AdmObject *)self;
-
- Py_DECREF(admobj);
-}
-
-static PyObject *adm_get_update_editor(PyObject *self, PyObject *args)
-{
- char *target;
- bool use_commit_times=true, recurse=true;
- PyObject * notify_func=Py_None;
- char *diff3_cmd=NULL;
- const svn_delta_editor_t *editor;
- AdmObject *admobj = (AdmObject *)self;
- void *edit_baton;
- apr_pool_t *pool;
- svn_revnum_t *latest_revnum;
- svn_error_t *err;
- bool allow_unver_obstructions = false;
- bool depth_is_sticky = false;
-
- if (!PyArg_ParseTuple(args, "s|bbOzbb", &target, &use_commit_times,
- &recurse, &notify_func, &diff3_cmd, &depth_is_sticky,
- &allow_unver_obstructions))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- pool = Pool(NULL);
- if (pool == NULL)
- return NULL;
- latest_revnum = (svn_revnum_t *)apr_palloc(pool, sizeof(svn_revnum_t));
- Py_BEGIN_ALLOW_THREADS
-#if ONLY_SINCE_SVN(1, 5)
- /* FIXME: Support all values of depth */
- /* FIXME: Support fetch_func */
- /* FIXME: Support conflict func */
- err = svn_wc_get_update_editor3(latest_revnum, admobj->adm, target,
- use_commit_times, recurse?svn_depth_infinity:svn_depth_files,
- depth_is_sticky?TRUE:FALSE, allow_unver_obstructions?TRUE:FALSE,
- py_wc_notify_func, (void *)notify_func,
- py_cancel_check, NULL,
- NULL, NULL, NULL, NULL,
- diff3_cmd, NULL, &editor, &edit_baton,
- NULL, pool);
-#else
- if (allow_unver_obstructions) {
- PyErr_SetString(PyExc_NotImplementedError,
- "allow_unver_obstructions is not supported in svn < 1.5");
- apr_pool_destroy(pool);
- PyEval_RestoreThread(_save);
- return NULL;
- }
- if (depth_is_sticky) {
- PyErr_SetString(PyExc_NotImplementedError,
- "depth_is_sticky is not supported in svn < 1.5");
- apr_pool_destroy(pool);
- PyEval_RestoreThread(_save);
- return NULL;
- }
- err = svn_wc_get_update_editor2(latest_revnum, admobj->adm, target,
- use_commit_times, recurse, py_wc_notify_func, (void *)notify_func,
- py_cancel_check, NULL, diff3_cmd, &editor, &edit_baton,
- NULL, pool);
-#endif
- Py_END_ALLOW_THREADS
- if (err != NULL) {
- handle_svn_error(err);
- svn_error_clear(err);
- apr_pool_destroy(pool);
- return NULL;
- }
- Py_INCREF(admobj);
- return new_editor_object(NULL, editor, edit_baton, pool, &Editor_Type,
- wc_done_handler, admobj, NULL);
-}
-
-static bool py_dict_to_wcprop_changes(PyObject *dict, apr_pool_t *pool, apr_array_header_t **ret)
+bool py_dict_to_wcprop_changes(PyObject *dict, apr_pool_t *pool, apr_array_header_t **ret)
{
PyObject *key, *val;
Py_ssize_t idx;
@@ -1240,384 +351,62 @@ static bool py_dict_to_wcprop_changes(PyObject *dict, apr_pool_t *pool, apr_arra
return true;
}
-static PyObject *adm_has_binary_prop(PyObject *self, PyObject *args)
-{
- const char *path;
- svn_boolean_t binary;
- AdmObject *admobj = (AdmObject *)self;
- apr_pool_t *temp_pool;
- PyObject *py_path;
-
- if (!PyArg_ParseTuple(args, "O", &py_path))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_has_binary_prop(&binary, path, admobj->adm, temp_pool));
-
- apr_pool_destroy(temp_pool);
-
- return PyBool_FromLong(binary);
-}
-
-static PyObject *adm_process_committed(PyObject *self, PyObject *args, PyObject *kwargs)
-{
- const char *path;
- char *rev_date = NULL, *rev_author = NULL;
- bool recurse, remove_lock = false;
- unsigned char *digest = NULL;
- svn_revnum_t new_revnum;
- PyObject *py_wcprop_changes = Py_None, *py_path;
- apr_array_header_t *wcprop_changes = NULL;
- AdmObject *admobj = (AdmObject *)self;
- apr_pool_t *temp_pool;
- int digest_len;
- bool remove_changelist = false;
- char *kwnames[] = { "path", "recurse", "new_revnum", "rev_date", "rev_author",
- "wcprop_changes", "remove_lock", "digest", "remove_changelist", NULL };
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oblzz|Obz#b", kwnames,
- &py_path, &recurse, &new_revnum, &rev_date,
- &rev_author, &py_wcprop_changes,
- &remove_lock, &digest, &digest_len, &remove_changelist))
- return NULL;
-
- PyErr_WarnEx(PyExc_DeprecationWarning, "process_committed is deprecated. Use process_committed_queue instead.", 2);
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
- if (!py_dict_to_wcprop_changes(py_wcprop_changes, temp_pool, &wcprop_changes)) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
#if ONLY_SINCE_SVN(1, 6)
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed4(
- path, admobj->adm, recurse, new_revnum,
- rev_date, rev_author, wcprop_changes,
- remove_lock, remove_changelist?TRUE:FALSE, digest, temp_pool));
-#else
- if (remove_changelist) {
- PyErr_SetString(PyExc_NotImplementedError, "remove_changelist only supported in svn < 1.6");
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(path, admobj->adm, recurse, new_revnum,
- rev_date, rev_author, wcprop_changes,
- remove_lock, digest, temp_pool));
-#endif
-
- apr_pool_destroy(temp_pool);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *adm_close(PyObject *self)
-{
- AdmObject *admobj = (AdmObject *)self;
- if (admobj->adm != NULL) {
-#if ONLY_SINCE_SVN(1, 6)
- apr_pool_t *temp_pool = Pool(NULL);
- Py_BEGIN_ALLOW_THREADS
- svn_wc_adm_close2(admobj->adm, temp_pool);
- apr_pool_destroy(temp_pool);
-#else
- Py_BEGIN_ALLOW_THREADS
- svn_wc_adm_close(admobj->adm);
-#endif
- Py_END_ALLOW_THREADS
- admobj->adm = NULL;
- }
-
- Py_RETURN_NONE;
-}
-
-static void adm_dealloc(PyObject *self)
-{
- apr_pool_destroy(((AdmObject *)self)->pool);
- PyObject_Del(self);
-}
-
-static PyObject *adm_repr(PyObject *self)
-{
- AdmObject *admobj = (AdmObject *)self;
-
- if (admobj->adm == NULL) {
- return PyRepr_FromFormat("<wc.WorkingCopy (closed) at 0x%p>", admobj);
- } else {
- return PyRepr_FromFormat("<wc.WorkingCopy at '%s'>",
- svn_wc_adm_access_path(admobj->adm));
- }
-}
-
-static PyObject *adm_remove_lock(PyObject *self, PyObject *args)
-{
- const char *path;
- PyObject *py_path;
- AdmObject *admobj = (AdmObject *)self;
- apr_pool_t *temp_pool;
-
- if (!PyArg_ParseTuple(args, "O", &py_path))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_remove_lock(path, admobj->adm, temp_pool))
-
- apr_pool_destroy(temp_pool);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *get_ancestry(PyObject *self, PyObject *args)
-{
- const char *path;
- char *url;
- svn_revnum_t rev;
- apr_pool_t *temp_pool;
- PyObject *py_path;
- AdmObject *admobj = (AdmObject *)self;
-
- if (!PyArg_ParseTuple(args, "O", &py_path))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_ancestry(&url, &rev, path, admobj->adm, temp_pool));
-
- apr_pool_destroy(temp_pool);
-
- return Py_BuildValue("(si)", url, rev);
-}
-
-static PyObject *maybe_set_repos_root(PyObject *self, PyObject *args)
-{
- char *path, *repos;
- apr_pool_t *temp_pool;
- AdmObject *admobj = (AdmObject *)self;
-
- if (!PyArg_ParseTuple(args, "ss", &path, &repos))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL)
- return NULL;
-
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_maybe_set_repos_root(admobj->adm, path, repos, temp_pool));
-
- Py_RETURN_NONE;
-}
-
-static PyObject *add_repos_file(PyObject *self, PyObject *args, PyObject *kwargs)
-{
- char *kwnames[] = { "dst_path", "new_base_contents", "new_contents",
- "new_base_props", "new_props", "copyfrom_url", "copyfrom_rev",
- "notify", NULL };
- AdmObject *admobj = (AdmObject *)self;
- apr_pool_t *temp_pool;
- char *dst_path, *copyfrom_url = NULL;
- svn_revnum_t copyfrom_rev = -1;
- PyObject *py_new_base_contents, *py_new_contents, *py_new_base_props,
- *py_new_props, *notify = Py_None;
- svn_stream_t *new_contents, *new_base_contents;
- apr_hash_t *new_props, *new_base_props;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sOOOO|zlO", kwnames,
- &dst_path, &py_new_base_contents, &py_new_contents, &py_new_base_props,
- &py_new_props, &copyfrom_url, &copyfrom_rev, &notify))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL)
- return NULL;
-
- new_base_props = prop_dict_to_hash(temp_pool, py_new_base_props);
-
- new_props = prop_dict_to_hash(temp_pool, py_new_props);
-
- new_base_contents = new_py_stream(temp_pool, py_new_base_contents);
-
- new_contents = new_py_stream(temp_pool, py_new_contents);
-
-#if ONLY_SINCE_SVN(1, 6)
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_add_repos_file3(dst_path, admobj->adm,
- new_base_contents,
- new_contents,
- new_base_props,
- new_props,
- copyfrom_url, copyfrom_rev,
- py_cancel_check, NULL,
- py_wc_notify_func, notify, temp_pool));
-#else
- PyErr_SetString(PyExc_NotImplementedError,
- "add_repos_file3 not supported on svn < 1.6");
- apr_pool_destroy(temp_pool);
-#endif
-
- apr_pool_destroy(temp_pool);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *mark_missing_deleted(PyObject *self, PyObject *args)
-{
- const char *path;
- AdmObject *admobj = (AdmObject *)self;
- apr_pool_t *temp_pool;
- PyObject *py_path;
-
- if (!PyArg_ParseTuple(args, "O", &py_path))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_mark_missing_deleted(path, admobj->adm, temp_pool));
-
- apr_pool_destroy(temp_pool);
-
- Py_RETURN_NONE;
-}
-
-static PyObject *remove_from_revision_control(PyObject *self, PyObject *args)
-{
- char *name;
- bool destroy_wf = false, instant_error = false;
- AdmObject *admobj = (AdmObject *)self;
- apr_pool_t *temp_pool;
-
- if (!PyArg_ParseTuple(args, "s|bb", &name, &destroy_wf, &instant_error))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL)
- return NULL;
-
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_remove_from_revision_control(admobj->adm, name,
- destroy_wf?TRUE:FALSE, instant_error?TRUE:FALSE, py_cancel_check, NULL, temp_pool));
-
- apr_pool_destroy(temp_pool);
-
- Py_RETURN_NONE;
-}
-
-#if ONLY_SINCE_SVN(1, 6)
-static svn_error_t *wc_validator3(void *baton, const char *uuid, const char *url, const char *root_url, apr_pool_t *pool)
+svn_error_t *wc_validator3(void *baton, const char *uuid, const char *url, const char *root_url, apr_pool_t *pool)
{
PyObject *py_validator = baton, *ret;
+ PyGILState_STATE state;
if (py_validator == Py_None) {
return NULL;
}
-
+ state = PyGILState_Ensure();
ret = PyObject_CallFunction(py_validator, "sss", uuid, url, root_url);
if (ret == NULL) {
+ PyGILState_Release(state);
return py_svn_error();
}
Py_DECREF(ret);
+ PyGILState_Release(state);
return NULL;
}
-#else
+#endif
-static svn_error_t *wc_validator2(void *baton, const char *uuid, const char *url, svn_boolean_t root, apr_pool_t *pool)
+svn_error_t *wc_validator2(void *baton, const char *uuid, const char *url, svn_boolean_t root, apr_pool_t *pool)
{
PyObject *py_validator = baton, *ret;
+ PyGILState_STATE state;
if (py_validator == Py_None) {
return NULL;
}
+ state = PyGILState_Ensure();
ret = PyObject_CallFunction(py_validator, "ssO", uuid, url, Py_None);
if (ret == NULL) {
+ PyGILState_Release(state);
return py_svn_error();
}
Py_DECREF(ret);
+ PyGILState_Release(state);
return NULL;
}
-#endif
-
-static PyObject *relocate(PyObject *self, PyObject *args)
+static PyObject *get_actual_target(PyObject *self, PyObject *args)
{
const char *path;
- char *from, *to;
- AdmObject *admobj = (AdmObject *)self;
+ const char *anchor = NULL, *target = NULL;
apr_pool_t *temp_pool;
- bool recurse = true;
- PyObject *py_validator = Py_None, *py_path;
+ PyObject *ret, *py_path;
- if (!PyArg_ParseTuple(args, "Oss|bO:relocate", &py_path, &from, &to, &recurse,
- &py_validator))
+ if (!PyArg_ParseTuple(args, "O", &py_path))
return NULL;
- ADM_CHECK_CLOSED(admobj);
-
temp_pool = Pool(NULL);
if (temp_pool == NULL) {
return NULL;
@@ -1629,392 +418,276 @@ static PyObject *relocate(PyObject *self, PyObject *args)
return NULL;
}
-#if ONLY_SINCE_SVN(1, 6)
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate3(path, admobj->adm, from, to, recurse?TRUE:FALSE, wc_validator3, py_validator, temp_pool));
-#else
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate2(path, admobj->adm, from, to, recurse?TRUE:FALSE, wc_validator2, py_validator, temp_pool));
-#endif
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_get_actual_target(path,
+ &anchor, &target, temp_pool));
+
+ ret = Py_BuildValue("(ss)", anchor, target);
apr_pool_destroy(temp_pool);
- Py_RETURN_NONE;
+ return ret;
}
-static PyObject *crop_tree(PyObject *self, PyObject *args)
+/**
+ * Determine the revision status of a specified working copy.
+ *
+ * :return: Tuple with minimum and maximum revnums found, whether the
+ * working copy was switched and whether it was modified.
+ */
+static PyObject *revision_status(PyObject *self, PyObject *args, PyObject *kwargs)
{
- char *target;
- svn_depth_t depth;
- PyObject *notify;
+ char *kwnames[] = { "wc_path", "trail_url", "committed", NULL };
+ const char *wc_path;
+ char *trail_url=NULL;
+ bool committed=false;
+ PyObject *ret, *py_wc_path;
+ svn_wc_revision_status_t *revstatus;
apr_pool_t *temp_pool;
- AdmObject *admobj = (AdmObject *)self;
- if (!PyArg_ParseTuple(args, "si|O", &target, &depth, &notify))
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|zb", kwnames, &py_wc_path,
+ &trail_url, &committed))
return NULL;
- ADM_CHECK_CLOSED(admobj);
-
-#if ONLY_SINCE_SVN(1, 6)
temp_pool = Pool(NULL);
- if (temp_pool == NULL)
+ if (temp_pool == NULL) {
return NULL;
+ }
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_crop_tree(admobj->adm,
- target, depth, py_wc_notify_func, notify,
- py_cancel_check, NULL, temp_pool));
-
+ wc_path = py_object_to_svn_dirent(py_wc_path, temp_pool);
+ if (wc_path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_revision_status(
+ &revstatus, wc_path, trail_url,
+ committed, py_cancel_check, NULL, temp_pool));
+ ret = Py_BuildValue("(llbb)", revstatus->min_rev, revstatus->max_rev,
+ revstatus->switched, revstatus->modified);
apr_pool_destroy(temp_pool);
-
- Py_RETURN_NONE;
-#else
- PyErr_SetString(PyExc_NotImplementedError,
- "crop_tree only available on subversion < 1.6");
- return NULL;
-#endif
+ return ret;
}
-static PyObject *translated_stream(PyObject *self, PyObject *args)
+static PyObject *is_normal_prop(PyObject *self, PyObject *args)
{
- char *path, *versioned_file;
- StreamObject *ret;
- svn_stream_t *stream;
- AdmObject *admobj = (AdmObject *)self;
- apr_pool_t *stream_pool;
- int flags;
-
- if (!PyArg_ParseTuple(args, "ssi", &path, &versioned_file, &flags))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
-#if ONLY_SINCE_SVN(1, 5)
- stream_pool = Pool(NULL);
- if (stream_pool == NULL)
- return NULL;
-
- RUN_SVN_WITH_POOL(stream_pool,
- svn_wc_translated_stream(&stream, path, versioned_file, admobj->adm,
- flags, stream_pool));
+ char *name;
- ret = PyObject_New(StreamObject, &Stream_Type);
- if (ret == NULL)
+ if (!PyArg_ParseTuple(args, "s", &name))
return NULL;
- ret->pool = stream_pool;
- ret->closed = FALSE;
- ret->stream = stream;
-
- return (PyObject *)ret;
-#else
- PyErr_SetString(PyExc_NotImplementedError,
- "translated_stream() is only available on Subversion >= 1.5");
- return NULL;
-#endif
+ return PyBool_FromLong(svn_wc_is_normal_prop(name));
}
-static PyObject *adm_text_modified(PyObject *self, PyObject *args)
+static PyObject *is_adm_dir(PyObject *self, PyObject *args)
{
- const char *path;
- bool force_comparison = false;
- apr_pool_t *temp_pool;
+ const char *name;
+ PyObject *py_name;
+ apr_pool_t *pool;
svn_boolean_t ret;
- AdmObject *admobj = (AdmObject *)self;
- PyObject *py_path;
- if (!PyArg_ParseTuple(args, "O|b", &py_path, &force_comparison))
+ if (!PyArg_ParseTuple(args, "O", &py_name))
return NULL;
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
+ pool = Pool(NULL);
+ if (pool == NULL)
return NULL;
- }
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
+ name = py_object_to_svn_string(py_name, pool);
+ if (name == NULL) {
+ return NULL;
+ }
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_text_modified_p(&ret, path, force_comparison?TRUE:FALSE, admobj->adm,
- temp_pool));
+ ret = svn_wc_is_adm_dir(name, pool);
- apr_pool_destroy(temp_pool);
+ apr_pool_destroy(pool);
return PyBool_FromLong(ret);
}
-static PyObject *adm_props_modified(PyObject *self, PyObject *args)
+static PyObject *is_wc_prop(PyObject *self, PyObject *args)
{
- const char *path;
- apr_pool_t *temp_pool;
- svn_boolean_t ret;
- AdmObject *admobj = (AdmObject *)self;
- PyObject *py_path;
+ char *name;
- if (!PyArg_ParseTuple(args, "O", &py_path))
+ if (!PyArg_ParseTuple(args, "s", &name))
return NULL;
- ADM_CHECK_CLOSED(admobj);
+ return PyBool_FromLong(svn_wc_is_wc_prop(name));
+}
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
+static PyObject *is_entry_prop(PyObject *self, PyObject *args)
+{
+ char *name;
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
+ if (!PyArg_ParseTuple(args, "s", &name))
return NULL;
- }
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_props_modified_p(&ret, path, admobj->adm, temp_pool));
-
- apr_pool_destroy(temp_pool);
+ return PyBool_FromLong(svn_wc_is_entry_prop(name));
+}
- return PyBool_FromLong(ret);
+static PyObject *get_adm_dir(PyObject *self)
+{
+ apr_pool_t *pool;
+ PyObject *ret;
+ const char *dir;
+ pool = Pool(NULL);
+ if (pool == NULL)
+ return NULL;
+ dir = svn_wc_get_adm_dir(pool);
+ ret = py_object_from_svn_abspath(dir);
+ apr_pool_destroy(pool);
+ return ret;
}
-static PyObject *adm_process_committed_queue(PyObject *self, PyObject *args)
+static PyObject *set_adm_dir(PyObject *self, PyObject *args)
{
apr_pool_t *temp_pool;
- AdmObject *admobj = (AdmObject *)self;
- svn_revnum_t revnum;
- char *date, *author;
- CommittedQueueObject *py_queue;
+ char *name;
+ PyObject *py_name;
- if (!PyArg_ParseTuple(args, "O!lss", &CommittedQueue_Type, &py_queue,
- &revnum, &date, &author))
+ if (!PyArg_ParseTuple(args, "O", &py_name))
return NULL;
- ADM_CHECK_CLOSED(admobj);
-
temp_pool = Pool(NULL);
if (temp_pool == NULL)
return NULL;
-
-#if ONLY_SINCE_SVN(1, 5)
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed_queue(py_queue->queue, admobj->adm, revnum, date, author, temp_pool));
-#else
- {
- int i;
- for (i = 0; i < py_queue->queue->queue->nelts; i++) {
- committed_queue_item_t *cqi = APR_ARRAY_IDX(py_queue->queue->queue, i,
- committed_queue_item_t *);
-
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(cqi->path, admobj->adm,
- cqi->recurse, revnum, date, author, cqi->wcprop_changes,
- cqi->remove_lock, cqi->digest, temp_pool));
- }
+ name = py_object_to_svn_string(py_name, temp_pool);
+ if (name == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
}
-#endif
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_set_adm_dir(name, temp_pool));
apr_pool_destroy(temp_pool);
-
Py_RETURN_NONE;
}
-static PyObject *get_actual_target(PyObject *self, PyObject *args)
+static PyObject *get_pristine_copy_path(PyObject *self, PyObject *args)
{
+ apr_pool_t *pool;
+ const char *pristine_path;
const char *path;
- const char *anchor = NULL, *target = NULL;
- apr_pool_t *temp_pool;
- PyObject *ret, *py_path;
+ PyObject *py_path;
+ PyObject *ret;
if (!PyArg_ParseTuple(args, "O", &py_path))
return NULL;
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
+ pool = Pool(NULL);
+ if (pool == NULL)
return NULL;
- }
- path = py_object_to_svn_dirent(py_path, temp_pool);
+ path = py_object_to_svn_abspath(py_path, pool);
if (path == NULL) {
- apr_pool_destroy(temp_pool);
+ apr_pool_destroy(pool);
return NULL;
}
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_get_actual_target(path,
- &anchor, &target, temp_pool));
-
- ret = Py_BuildValue("(ss)", anchor, target);
-
- apr_pool_destroy(temp_pool);
-
+ PyErr_WarnEx(PyExc_DeprecationWarning, "get_pristine_copy_path is deprecated. Use get_pristine_contents instead.", 2);
+ RUN_SVN_WITH_POOL(pool,
+ svn_wc_get_pristine_copy_path(path,
+ &pristine_path, pool));
+ ret = py_object_from_svn_abspath(pristine_path);
+ apr_pool_destroy(pool);
return ret;
}
-static PyObject *is_wc_root(PyObject *self, PyObject *args)
+static PyObject *get_pristine_contents(PyObject *self, PyObject *args)
{
const char *path;
- svn_boolean_t wc_root;
apr_pool_t *temp_pool;
- AdmObject *admobj = (AdmObject *)self;
PyObject *py_path;
+#if ONLY_SINCE_SVN(1, 6)
+ StreamObject *ret;
+ apr_pool_t *stream_pool;
+ svn_stream_t *stream;
+#else
+#if PY_MAJOR_VERSION >= 3
+ int fd;
+#endif
+ PyObject *ret;
+ const char *pristine_path;
+#endif
if (!PyArg_ParseTuple(args, "O", &py_path))
return NULL;
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
+#if ONLY_SINCE_SVN(1, 6)
+ stream_pool = Pool(NULL);
+ if (stream_pool == NULL)
return NULL;
- }
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
+ temp_pool = Pool(stream_pool);
+ if (temp_pool == NULL) {
+ apr_pool_destroy(stream_pool);
return NULL;
}
-
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_is_wc_root(&wc_root, path, admobj->adm, temp_pool));
-
- apr_pool_destroy(temp_pool);
-
- return PyBool_FromLong(wc_root);
-}
-
-static PyObject *transmit_text_deltas(PyObject *self, PyObject *args)
-{
- const char *path;
- const char *tempfile;
- bool fulltext;
- PyObject *editor_obj, *py_digest, *py_path;
- unsigned char digest[APR_MD5_DIGESTSIZE];
- apr_pool_t *temp_pool;
- AdmObject *admobj = (AdmObject *)self;
- PyObject *ret;
-
- if (!PyArg_ParseTuple(args, "ObO", &py_path, &fulltext, &editor_obj))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
+#else
temp_pool = Pool(NULL);
if (temp_pool == NULL) {
return NULL;
}
+#endif
- path = py_object_to_svn_dirent(py_path, temp_pool);
+ path = py_object_to_svn_abspath(py_path, temp_pool);
if (path == NULL) {
apr_pool_destroy(temp_pool);
return NULL;
}
- Py_INCREF(editor_obj);
-
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_transmit_text_deltas2(&tempfile, digest,
- path, admobj->adm, fulltext?TRUE:FALSE,
- &py_editor, editor_obj, temp_pool));
-
- py_digest = PyBytes_FromStringAndSize((char *)digest, APR_MD5_DIGESTSIZE);
- if (py_digest == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
- ret = Py_BuildValue("sN", tempfile, py_digest);
- if (ret == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
+#if ONLY_SINCE_SVN(1, 6)
+ RUN_SVN_WITH_POOL(stream_pool, svn_wc_get_pristine_contents(&stream, path, stream_pool, temp_pool));
apr_pool_destroy(temp_pool);
- return ret;
-}
-
-static PyObject *transmit_prop_deltas(PyObject *self, PyObject *args)
-{
- const char *path;
- PyObject *editor_obj;
- apr_pool_t *temp_pool;
- AdmObject *admobj = (AdmObject *)self;
- PyObject *py_path;
- EntryObject *py_entry;
+ if (stream == NULL) {
+ apr_pool_destroy(stream_pool);
+ Py_RETURN_NONE;
+ }
- if (!PyArg_ParseTuple(args, "OO!O", &py_path, &Entry_Type, &py_entry, &editor_obj))
+ ret = PyObject_New(StreamObject, &Stream_Type);
+ if (ret == NULL)
return NULL;
- ADM_CHECK_CLOSED(admobj);
+ ret->pool = stream_pool;
+ ret->closed = FALSE;
+ ret->stream = stream;
+ return (PyObject *)ret;
+#else
temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
+ if (temp_pool == NULL)
return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_pristine_copy_path(path, &pristine_path, temp_pool));
+#if PY_MAJOR_VERSION >= 3
+ fd = open(pristine_path, O_RDONLY);
+ if (fd < 0) {
+ PyErr_SetFromErrno(PyExc_IOError);
apr_pool_destroy(temp_pool);
return NULL;
}
-
- Py_INCREF(editor_obj);
-
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_transmit_prop_deltas(path,
- admobj->adm, &(py_entry->entry), &py_editor, editor_obj, NULL, temp_pool));
-
+ ret = PyFile_FromFd(fd, pristine_path, "rb", -1, NULL, NULL, NULL, true);
+#else
+ ret = PyFile_FromString((char *)pristine_path, "rb");
+#endif
apr_pool_destroy(temp_pool);
-
- Py_RETURN_NONE;
+ return ret;
+#endif
}
-static PyObject *retrieve(PyObject *self, PyObject *args)
+static PyObject *ensure_adm(PyObject *self, PyObject *args, PyObject *kwargs)
{
const char *path;
- svn_wc_adm_access_t *result;
+ char *uuid, *url = NULL;
PyObject *py_path;
- AdmObject *admobj = (AdmObject *)self, *ret;
+ char *repos = NULL;
+ long rev = -1;
apr_pool_t *pool;
+ char *kwnames[] = { "path", "uuid", "url", "repos", "rev", "depth", NULL };
+ int depth = svn_depth_infinity;
- if (!PyArg_ParseTuple(args, "O", &py_path))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- pool = Pool(NULL);
- if (pool == NULL)
- return NULL;
-
- path = py_object_to_svn_dirent(py_path, pool);
- if (path == NULL) {
- apr_pool_destroy(pool);
- return NULL;
- }
-
- RUN_SVN_WITH_POOL(pool, svn_wc_adm_retrieve(&result, admobj->adm,
- path, pool));
-
- ret = PyObject_New(AdmObject, &Adm_Type);
- if (ret == NULL)
- return NULL;
-
- ret->pool = pool;
- ret->adm = result;
-
- return (PyObject *)ret;
-}
-
-static PyObject *probe_retrieve(PyObject *self, PyObject *args)
-{
- const char *path;
- svn_wc_adm_access_t *result;
- AdmObject *admobj = (AdmObject *)self, *ret;
- apr_pool_t *pool;
- PyObject *py_path;
-
- if (!PyArg_ParseTuple(args, "O", &py_path))
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oss|sli", kwnames,
+ &py_path, &uuid, &url, &repos, &rev, &depth))
return NULL;
- ADM_CHECK_CLOSED(admobj);
-
pool = Pool(NULL);
if (pool == NULL) {
return NULL;
@@ -2026,34 +699,35 @@ static PyObject *probe_retrieve(PyObject *self, PyObject *args)
return NULL;
}
- RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_retrieve(&result, admobj->adm,
- path, pool));
-
- ret = PyObject_New(AdmObject, &Adm_Type);
- if (ret == NULL)
+#if ONLY_SINCE_SVN(1, 5)
+ RUN_SVN_WITH_POOL(pool,
+ svn_wc_ensure_adm3(path,
+ uuid, url, repos, rev, depth, pool));
+#else
+ if (depth != svn_depth_infinity) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "depth != infinity not supported with svn < 1.5");
+ apr_pool_destroy(pool);
return NULL;
-
- ret->pool = pool;
- ret->adm = result;
-
- return (PyObject *)ret;
+ }
+ RUN_SVN_WITH_POOL(pool,
+ svn_wc_ensure_adm2(path,
+ uuid, url, repos, rev, pool));
+#endif
+ apr_pool_destroy(pool);
+ Py_RETURN_NONE;
}
-static PyObject *probe_try(PyObject *self, PyObject *args)
+static PyObject *check_wc(PyObject *self, PyObject *args)
{
const char *path;
- svn_wc_adm_access_t *result = NULL;
- AdmObject *admobj = (AdmObject *)self, *ret;
apr_pool_t *pool;
- int levels_to_lock = -1;
- bool writelock = false;
+ int wc_format;
PyObject *py_path;
- if (!PyArg_ParseTuple(args, "O|bi", &py_path, &writelock, &levels_to_lock))
+ if (!PyArg_ParseTuple(args, "O", &py_path))
return NULL;
- ADM_CHECK_CLOSED(admobj);
-
pool = Pool(NULL);
if (pool == NULL) {
return NULL;
@@ -2065,47 +739,23 @@ static PyObject *probe_try(PyObject *self, PyObject *args)
return NULL;
}
- RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_try3(&result, admobj->adm,
- path, writelock, levels_to_lock,
- py_cancel_check, NULL, pool));
-
- if (result == NULL) {
- apr_pool_destroy(pool);
- Py_RETURN_NONE;
- }
-
- ret = PyObject_New(AdmObject, &Adm_Type);
- if (ret == NULL)
- return NULL;
-
- ret->pool = pool;
- ret->adm = result;
-
- return (PyObject *)ret;
+ RUN_SVN_WITH_POOL(pool, svn_wc_check_wc(path, &wc_format, pool));
+ apr_pool_destroy(pool);
+ return PyLong_FromLong(wc_format);
}
-static PyObject *resolved_conflict(PyObject *self, PyObject *args)
+static PyObject *cleanup_wc(PyObject *self, PyObject *args, PyObject *kwargs)
{
- AdmObject *admobj = (AdmObject *)self;
- apr_pool_t *temp_pool;
- bool resolve_props, resolve_tree, resolve_text;
- int depth;
-#if ONLY_SINCE_SVN(1, 5)
- svn_wc_conflict_choice_t conflict_choice;
-#else
- int conflict_choice;
-#endif
- PyObject *notify_func = Py_None;
const char *path;
+ char *diff3_cmd = NULL;
+ char *kwnames[] = { "path", "diff3_cmd", NULL };
+ apr_pool_t *temp_pool;
PyObject *py_path;
- if (!PyArg_ParseTuple(args, "Obbbii|O", &py_path, &resolve_text,
- &resolve_props, &resolve_tree, &depth,
- &conflict_choice, &notify_func))
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|z", kwnames,
+ &py_path, &diff3_cmd))
return NULL;
- ADM_CHECK_CLOSED(admobj);
-
temp_pool = Pool(NULL);
if (temp_pool == NULL) {
return NULL;
@@ -2117,275 +767,85 @@ static PyObject *resolved_conflict(PyObject *self, PyObject *args)
return NULL;
}
-#if ONLY_SINCE_SVN(1, 6)
RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_resolved_conflict4(path, admobj->adm, resolve_text?TRUE:FALSE,
- resolve_props?TRUE:FALSE, resolve_tree?TRUE:FALSE, depth,
- conflict_choice, py_wc_notify_func,
- (void *)notify_func, py_cancel_check,
- NULL, temp_pool));
-#elif ONLY_SINCE_SVN(1, 5)
- if (resolve_tree) {
- PyErr_SetString(PyExc_NotImplementedError,
- "resolve_tree not supported with svn < 1.6");
- apr_pool_destroy(temp_pool);
- return NULL;
- } else {
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_resolved_conflict3(path, admobj->adm, resolve_text?TRUE:FALSE,
- resolve_props?TRUE:FALSE, depth,
- conflict_choice, py_wc_notify_func,
- (void *)notify_func, py_cancel_check,
- NULL, temp_pool));
- }
-#else
- if (resolve_tree) {
- PyErr_SetString(PyExc_NotImplementedError,
- "resolve_tree not supported with svn < 1.6");
- apr_pool_destroy(temp_pool);
- return NULL;
- } else if (depth != svn_depth_infinity && depth != svn_depth_files) {
- PyErr_SetString(PyExc_NotImplementedError,
- "only infinity and files values for depth are supported");
- apr_pool_destroy(temp_pool);
- return NULL;
- } else if (conflict_choice != 0) {
- PyErr_SetString(PyExc_NotImplementedError,
- "conflict choice not supported with svn < 1.5");
- apr_pool_destroy(temp_pool);
- return NULL;
- } else {
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_resolved_conflict2(path, admobj->adm, resolve_text?TRUE:FALSE,
- resolve_props?TRUE:FALSE,
- (depth == svn_depth_infinity),
- py_wc_notify_func,
- (void *)notify_func, py_cancel_check,
- NULL,
- temp_pool));
- }
-#endif
+ svn_wc_cleanup2(path, diff3_cmd, py_cancel_check, NULL,
+ temp_pool));
apr_pool_destroy(temp_pool);
Py_RETURN_NONE;
}
-static PyObject *conflicted(PyObject *self, PyObject *args)
+static PyObject *match_ignore_list(PyObject *self, PyObject *args)
{
- const char *path;
+#if ONLY_SINCE_SVN(1, 5)
+ char *str;
+ PyObject *py_list;
+ apr_array_header_t *list;
apr_pool_t *temp_pool;
- PyObject *ret;
- AdmObject *admobj = (AdmObject *)self;
- svn_boolean_t text_conflicted, prop_conflicted, tree_conflicted;
- PyObject *py_path;
+ svn_boolean_t ret;
- if (!PyArg_ParseTuple(args, "O", &py_path))
+ if (!PyArg_ParseTuple(args, "sO", &str, &py_list))
return NULL;
- ADM_CHECK_CLOSED(admobj);
-
temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
+ if (!string_list_to_apr_array(temp_pool, py_list, &list)) {
apr_pool_destroy(temp_pool);
return NULL;
}
-#if ONLY_SINCE_SVN(1, 6)
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p2(&text_conflicted,
- &prop_conflicted, &tree_conflicted, path, admobj->adm, temp_pool));
-
- ret = Py_BuildValue("(bbb)", text_conflicted, prop_conflicted, tree_conflicted);
-#else
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p(&text_conflicted,
- &prop_conflicted, path, admobj->adm, temp_pool));
-
- ret = Py_BuildValue("(bbO)", text_conflicted, prop_conflicted, Py_None);
-#endif
+ ret = svn_wc_match_ignore_list(str, list, temp_pool);
apr_pool_destroy(temp_pool);
- return ret;
+ return PyBool_FromLong(ret);
+#else
+ PyErr_SetNone(PyExc_NotImplementedError);
+ return NULL;
+#endif
}
-/**
- * Determine the status of a file in the specified working copy.
- *
- * :return: A status object.
- */
-static PyObject *ra_status(PyObject *self, PyObject *args)
-{
- const char *path;
- svn_wc_status2_t *st;
- apr_pool_t *temp_pool;
- PyObject *ret;
- AdmObject *admobj = (AdmObject *)self;
- PyObject *py_path;
-
- if (!PyArg_ParseTuple(args, "O", &py_path))
- return NULL;
-
- ADM_CHECK_CLOSED(admobj);
-
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
-
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
-
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_status2(&st, path, admobj->adm, temp_pool));
-
- ret = py_status(st);
-
- apr_pool_destroy(temp_pool);
-
- return (PyObject*)ret;
-}
-
-static PyMethodDef adm_methods[] = {
- { "prop_set", adm_prop_set, METH_VARARGS, "S.prop_set(name, value, path, skip_checks=False)" },
- { "access_path", (PyCFunction)adm_access_path, METH_NOARGS,
- "S.access_path() -> path\n"
- "Returns the base path for this working copy handle." },
- { "prop_get", adm_prop_get, METH_VARARGS, "S.prop_get(name, path) -> value" },
- { "entries_read", adm_entries_read, METH_VARARGS, "S.entries_read(include_hidden=False) -> dict" },
- { "walk_entries", adm_walk_entries, METH_VARARGS,
- "S.walk_entries(path, callback, show_hidden=False)\n"
- "callback should be a function that takes a path and a wc entry" },
- { "locked", (PyCFunction)adm_locked, METH_NOARGS,
- "S.locked() -> bool" },
- { "get_prop_diffs", adm_get_prop_diffs, METH_VARARGS,
- "S.get_prop_diffs(path) -> (propchanges, originalprops)" },
- { "add", (PyCFunction)adm_add, METH_VARARGS|METH_KEYWORDS, "S.add(path, copyfrom_url=None, copyfrom_rev=-1, notify_func=None)" },
- { "copy", adm_copy, METH_VARARGS, "S.copy(src_path, dest_path, notify_func=None)" },
- { "delete", (PyCFunction)adm_delete, METH_VARARGS|METH_KEYWORDS, "S.delete(path, notify_func=None, keep_local=False)" },
- { "crawl_revisions", (PyCFunction)adm_crawl_revisions, METH_VARARGS|METH_KEYWORDS,
- "S.crawl_revisions(path, reporter, restore_files=True, recurse=True, use_commit_times=True, notify_func=None) -> None" },
- { "get_update_editor", adm_get_update_editor, METH_VARARGS, NULL },
- { "close", (PyCFunction)adm_close, METH_NOARGS,
- "S.close()" },
- { "entry", (PyCFunction)adm_entry, METH_VARARGS,
- "s.entry(path, show_hidden=False) -> entry" },
- { "process_committed", (PyCFunction)adm_process_committed, METH_VARARGS|METH_KEYWORDS, "S.process_committed(path, recurse, new_revnum, rev_date, rev_author, wcprop_changes=None, remove_lock=False, digest=None)" },
- { "process_committed_queue", (PyCFunction)adm_process_committed_queue, METH_VARARGS, "S.process_committed_queue(queue, new_revnum, rev_date, rev_author)" },
- { "remove_lock", (PyCFunction)adm_remove_lock, METH_VARARGS, "S.remove_lock(path)" },
- { "has_binary_prop", (PyCFunction)adm_has_binary_prop, METH_VARARGS, "S.has_binary_prop(path) -> bool" },
- { "text_modified", (PyCFunction)adm_text_modified, METH_VARARGS, "S.text_modified(filename, force_comparison=False) -> bool" },
- { "props_modified", (PyCFunction)adm_props_modified, METH_VARARGS, "S.props_modified(filename) -> bool" },
- { "get_ancestry", (PyCFunction)get_ancestry, METH_VARARGS,
- "S.get_ancestry(path) -> (url, rev)" },
- { "maybe_set_repos_root", (PyCFunction)maybe_set_repos_root, METH_VARARGS, "S.maybe_set_repos_root(path, repos)" },
- { "add_repos_file", (PyCFunction)add_repos_file, METH_KEYWORDS,
- "S.add_repos_file(dst_path, new_base_contents, new_contents, new_base_props, new_props, copyfrom_url=None, copyfrom_rev=-1, notify_func=None)" },
- { "mark_missing_deleted", (PyCFunction)mark_missing_deleted, METH_VARARGS,
- "S.mark_missing_deleted(path)" },
- { "remove_from_revision_control", (PyCFunction)remove_from_revision_control, METH_VARARGS,
- "S.remove_from_revision_control(name, destroy_wf=False, instant_error=False)" },
- { "relocate", (PyCFunction)relocate, METH_VARARGS,
- "S.relocate(path, from, to, recurse=TRUE, validator=None)" },
- { "crop_tree", (PyCFunction)crop_tree, METH_VARARGS,
- "S.crop_tree(target, depth, notify_func=None, cancel=None)" },
- { "translated_stream", (PyCFunction)translated_stream, METH_VARARGS,
- "S.translated_stream(path, versioned_file, flags) -> stream" },
- { "is_wc_root", (PyCFunction)is_wc_root, METH_VARARGS,
- "S.is_wc_root(path) -> wc_root" },
- { "transmit_text_deltas", (PyCFunction)transmit_text_deltas, METH_VARARGS,
- "S.transmit_text_deltas(fulltext, editor) -> (tempfile, digest)" },
- { "transmit_prop_deltas", (PyCFunction)transmit_prop_deltas, METH_VARARGS,
- "S.transmit_prop_deltas(path, entry, editor)" },
- { "probe_retrieve", (PyCFunction)probe_retrieve, METH_VARARGS,
- "S.probe_retrieve(path) -> WorkingCopy" },
- { "retrieve", (PyCFunction)retrieve, METH_VARARGS,
- "S.retrieve(path) -> WorkingCopy" },
- { "probe_try", (PyCFunction)probe_try, METH_VARARGS,
- "S.probe_try(path, write_lock=False, levels_to_lock=-1)" },
- { "conflicted", (PyCFunction)conflicted, METH_VARARGS,
- "S.conflicted(path) -> (text_conflicted, prop_conflicted, tree_conflicted)" },
- { "resolved_conflict", (PyCFunction)resolved_conflict, METH_VARARGS,
- "S.resolved_conflict(path, resolve_text, resolve_props, resolve_tree, depth, conflict_choice, notify_func=None, cancel=None)" },
- { "status", (PyCFunction)ra_status, METH_VARARGS, "status(wc_path) -> Status" },
- { NULL, }
-};
-
-static PyTypeObject Adm_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "wc.WorkingCopy", /* const char *tp_name; For printing, in format "<module>.<name>" */
- sizeof(AdmObject),
- 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
-
- /* Methods to implement standard operations */
-
- adm_dealloc, /* destructor tp_dealloc; */
- NULL, /* printfunc tp_print; */
- NULL, /* getattrfunc tp_getattr; */
- NULL, /* setattrfunc tp_setattr; */
- NULL, /* cmpfunc tp_compare; */
- adm_repr, /* reprfunc tp_repr; */
-
- /* Method suites for standard classes */
-
- NULL, /* PyNumberMethods *tp_as_number; */
- NULL, /* PySequenceMethods *tp_as_sequence; */
- NULL, /* PyMappingMethods *tp_as_mapping; */
-
- /* More standard operations (here for binary compatibility) */
-
- NULL, /* hashfunc tp_hash; */
- NULL, /* ternaryfunc tp_call; */
- adm_repr, /* reprfunc tp_repr; */
- NULL, /* getattrofunc tp_getattro; */
- NULL, /* setattrofunc tp_setattro; */
-
- /* Functions to access object as input/output buffer */
- NULL, /* PyBufferProcs *tp_as_buffer; */
-
- /* Flags to define presence of optional/expanded features */
- 0, /* long tp_flags; */
-
- "Local working copy", /* const char *tp_doc; Documentation string */
-
- /* Assigned meaning in release 2.0 */
- /* call function for all accessible objects */
- NULL, /* traverseproc tp_traverse; */
-
- /* delete references to contained objects */
- NULL, /* inquiry tp_clear; */
-
- /* Assigned meaning in release 2.1 */
- /* rich comparisons */
- NULL, /* richcmpfunc tp_richcompare; */
-
- /* weak reference enabler */
- 0, /* Py_ssize_t tp_weaklistoffset; */
-
- /* Added in release 2.2 */
- /* Iterators */
- NULL, /* getiterfunc tp_iter; */
- NULL, /* iternextfunc tp_iternext; */
-
- /* Attribute descriptor and subclassing stuff */
- adm_methods, /* struct PyMethodDef *tp_methods; */
- NULL, /* struct PyMemberDef *tp_members; */
- NULL, /* struct PyGetSetDef *tp_getset; */
- NULL, /* struct _typeobject *tp_base; */
- NULL, /* PyObject *tp_dict; */
- NULL, /* descrgetfunc tp_descr_get; */
- NULL, /* descrsetfunc tp_descr_set; */
- 0, /* Py_ssize_t tp_dictoffset; */
- NULL, /* initproc tp_init; */
- NULL, /* allocfunc tp_alloc; */
- adm_init, /* newfunc tp_new; */
+static PyMethodDef wc_methods[] = {
+ { "check_wc", check_wc, METH_VARARGS, "check_wc(path) -> version\n"
+ "Check whether path contains a Subversion working copy\n"
+ "return the workdir version"},
+ { "cleanup", (PyCFunction)cleanup_wc,
+ METH_VARARGS|METH_KEYWORDS, "cleanup(path, diff3_cmd=None)\n" },
+ { "ensure_adm", (PyCFunction)ensure_adm, METH_KEYWORDS|METH_VARARGS,
+ "ensure_adm(path, uuid, url, repos=None, rev=None)" },
+ { "get_adm_dir", (PyCFunction)get_adm_dir, METH_NOARGS,
+ "get_adm_dir() -> name" },
+ { "set_adm_dir", (PyCFunction)set_adm_dir, METH_VARARGS,
+ "set_adm_dir(name)" },
+ { "get_pristine_copy_path", get_pristine_copy_path, METH_VARARGS,
+ "get_pristine_copy_path(path) -> path" },
+ { "get_pristine_contents", get_pristine_contents, METH_VARARGS,
+ "get_pristine_contents(path) -> stream" },
+ { "is_adm_dir", is_adm_dir, METH_VARARGS,
+ "is_adm_dir(name) -> bool" },
+ { "is_normal_prop", is_normal_prop, METH_VARARGS,
+ "is_normal_prop(name) -> bool" },
+ { "is_entry_prop", is_entry_prop, METH_VARARGS,
+ "is_entry_prop(name) -> bool" },
+ { "is_wc_prop", is_wc_prop, METH_VARARGS,
+ "is_wc_prop(name) -> bool" },
+ { "revision_status", (PyCFunction)revision_status,
+ METH_KEYWORDS|METH_VARARGS,
+ "revision_status(wc_path, trail_url=None, committed=False)"
+ "-> (min_rev, max_rev, switched, modified)" },
+ { "version", (PyCFunction)version, METH_NOARGS,
+ "version() -> (major, minor, patch, tag)\n\n"
+ "Version of libsvn_wc currently used."
+ },
+ { "api_version", (PyCFunction)api_version, METH_NOARGS,
+ "api_version() -> (major, minor, patch, tag)\n\n"
+ "Version of libsvn_wc Subvertpy was compiled against." },
+ { "match_ignore_list", (PyCFunction)match_ignore_list, METH_VARARGS,
+ "match_ignore_list(str, patterns) -> bool" },
+ { "get_actual_target", (PyCFunction)get_actual_target, METH_VARARGS,
+ "get_actual_target(path) -> (anchor, target)" },
+ { NULL, }
};
static void committed_queue_dealloc(PyObject *self)
@@ -2428,48 +888,39 @@ static PyObject *committed_queue_init(PyTypeObject *self, PyObject *args, PyObje
static PyObject *committed_queue_queue(CommittedQueueObject *self, PyObject *args, PyObject *kwargs)
{
- char *path;
- AdmObject *admobj;
- PyObject *py_wcprop_changes = Py_None;
+ const char *path;
+ PyObject *admobj;
+ PyObject *py_wcprop_changes = Py_None, *py_path;
+ svn_wc_adm_access_t *adm = NULL;
bool remove_lock = false, remove_changelist = false;
char *md5_digest = NULL, *sha1_digest = NULL;
bool recurse = false;
- apr_pool_t *temp_pool;
apr_array_header_t *wcprop_changes;
int md5_digest_len, sha1_digest_len;
+#if ONLY_SINCE_SVN(1, 7)
+ svn_wc_context_t *context = NULL;
+#endif
char *kwnames[] = { "path", "adm", "recurse", "wcprop_changes", "remove_lock", "remove_changelist", "md5_digest", "sha1_digest", NULL };
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!|bObbz#z#", kwnames,
- &path, &Adm_Type, &admobj,
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bObbz#z#", kwnames,
+ &py_path, &admobj,
&recurse, &py_wcprop_changes, &remove_lock,
&remove_changelist, &md5_digest, &md5_digest_len,
&sha1_digest, &sha1_digest_len))
return NULL;
- temp_pool = Pool(NULL);
- if (temp_pool == NULL)
- return NULL;
-
if (!py_dict_to_wcprop_changes(py_wcprop_changes, self->pool, &wcprop_changes)) {
- apr_pool_destroy(temp_pool);
return NULL;
}
- path = apr_pstrdup(self->pool, path);
+ path = py_object_to_svn_abspath(py_path, self->pool);
if (path == NULL) {
- PyErr_NoMemory();
return NULL;
}
if (md5_digest != NULL) {
if (md5_digest_len != APR_MD5_DIGESTSIZE) {
PyErr_SetString(PyExc_ValueError, "Invalid size for md5 digest");
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- md5_digest = apr_pstrdup(temp_pool, md5_digest);
- if (md5_digest == NULL) {
- PyErr_NoMemory();
return NULL;
}
}
@@ -2477,42 +928,65 @@ static PyObject *committed_queue_queue(CommittedQueueObject *self, PyObject *arg
if (sha1_digest != NULL) {
if (sha1_digest_len != APR_SHA1_DIGESTSIZE) {
PyErr_SetString(PyExc_ValueError, "Invalid size for sha1 digest");
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- sha1_digest = apr_pstrdup(temp_pool, sha1_digest);
- if (sha1_digest == NULL) {
- PyErr_NoMemory();
return NULL;
}
}
+ if (PyObject_IsInstance(admobj, (PyObject *)&Adm_Type)) {
+ adm = PyObject_GetAdmAccess(admobj);
+#if ONLY_SINCE_SVN(1, 7)
+ } else if (PyObject_IsInstance(admobj, (PyObject *)&Context_Type)) {
+ context = ((ContextObject*)admobj)->context;
+#endif
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Second arguments needs to be Adm or Context");
+ return NULL;
+ }
+
+#if ONLY_SINCE_SVN(1, 7)
+ if (adm != NULL) {
+#endif
#if ONLY_SINCE_SVN(1, 6)
{
- svn_checksum_t svn_checksum, *svn_checksum_p = &svn_checksum;
+ svn_checksum_t *svn_checksum_p;
- if (sha1_digest != NULL) {
- svn_checksum.digest = (unsigned char *)sha1_digest;
- svn_checksum.kind = svn_checksum_sha1;
- } else if (md5_digest != NULL) {
- svn_checksum.digest = (unsigned char *)md5_digest;
- svn_checksum.kind = svn_checksum_md5;
+ if (md5_digest != NULL) {
+ svn_checksum_p = apr_palloc(self->pool, sizeof(svn_checksum_t));
+ svn_checksum_p->digest = apr_pmemdup(
+ self->pool, (unsigned char *)md5_digest, APR_MD5_DIGESTSIZE);
+ svn_checksum_p->kind = svn_checksum_md5;
} else {
svn_checksum_p = NULL;
}
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_queue_committed2(self->queue, path, admobj->adm, recurse?TRUE:FALSE,
+ RUN_SVN(
+ svn_wc_queue_committed2(self->queue, path, adm, recurse?TRUE:FALSE,
wcprop_changes, remove_lock?TRUE:FALSE, remove_changelist?TRUE:FALSE,
- svn_checksum_p, temp_pool));
+ svn_checksum_p, self->pool));
}
#else
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_queue_committed(&self->queue, path, admobj->adm, recurse?TRUE:FALSE,
+ RUN_SVN(
+ svn_wc_queue_committed(&self->queue, path, adm, recurse?TRUE:FALSE,
wcprop_changes, remove_lock?TRUE:FALSE, remove_changelist?TRUE:FALSE,
- (unsigned char *)md5_digest, temp_pool));
+ (unsigned char *)md5_digest, self->pool));
#endif
+#if ONLY_SINCE_SVN(1, 7)
+ } else {
+ svn_checksum_t *svn_checksum_p;
- apr_pool_destroy(temp_pool);
+ if (sha1_digest != NULL) {
+ svn_checksum_p = apr_palloc(self->pool, sizeof(svn_checksum_t));
+ svn_checksum_p->digest = apr_pmemdup(
+ self->pool, (unsigned char *)sha1_digest, APR_SHA1_DIGESTSIZE);
+ svn_checksum_p->kind = svn_checksum_sha1;
+ } else {
+ svn_checksum_p = NULL;
+ }
+ RUN_SVN(
+ svn_wc_queue_committed3(self->queue, context, path, recurse?TRUE:FALSE,
+ wcprop_changes, remove_lock?TRUE:FALSE, remove_changelist?TRUE:FALSE,
+ svn_checksum_p, self->pool));
+ }
+#endif
Py_RETURN_NONE;
}
@@ -2523,7 +997,7 @@ static PyMethodDef committed_queue_methods[] = {
{ NULL }
};
-static PyTypeObject CommittedQueue_Type = {
+PyTypeObject CommittedQueue_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"wc.CommittedQueue", /* const char *tp_name; For printing, in format "<module>.<name>" */
sizeof(CommittedQueueObject),
@@ -2593,393 +1067,1062 @@ static PyTypeObject CommittedQueue_Type = {
committed_queue_init, /* newfunc tp_new; */
};
-/**
- * Determine the revision status of a specified working copy.
- *
- * :return: Tuple with minimum and maximum revnums found, whether the
- * working copy was switched and whether it was modified.
- */
-static PyObject *revision_status(PyObject *self, PyObject *args, PyObject *kwargs)
+svn_lock_t *py_object_to_svn_lock(PyObject *py_lock, apr_pool_t *pool)
{
- char *kwnames[] = { "wc_path", "trail_url", "committed", NULL };
- const char *wc_path;
- char *trail_url=NULL;
- bool committed=false;
- PyObject *ret, *py_wc_path;
- svn_wc_revision_status_t *revstatus;
- apr_pool_t *temp_pool;
+ LockObject* lockobj = (LockObject *)py_lock;
+ if (!PyObject_IsInstance(py_lock, (PyObject *)&Lock_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Expected Lock object");
+ return NULL;
+ }
+ return &lockobj->lock;
+}
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|zb", kwnames, &py_wc_path,
- &trail_url, &committed))
- return NULL;
+#if ONLY_SINCE_SVN(1, 7)
+static PyTypeObject Context_Type;
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
- return NULL;
- }
+static PyObject *py_wc_context_locked(PyObject *self, PyObject *args)
+{
+ PyObject* py_path;
+ const char *path;
+ apr_pool_t *pool;
+ svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
+ svn_boolean_t locked_here, locked;
- wc_path = py_object_to_svn_dirent(py_wc_path, temp_pool);
- if (wc_path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_revision_status(
- &revstatus, wc_path, trail_url,
- committed, py_cancel_check, NULL, temp_pool));
- ret = Py_BuildValue("(llbb)", revstatus->min_rev, revstatus->max_rev,
- revstatus->switched, revstatus->modified);
- apr_pool_destroy(temp_pool);
- return ret;
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
+
+ pool = Pool(NULL);
+
+ path = py_object_to_svn_abspath(py_path, pool);
+ if (path == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(pool, svn_wc_locked2(&locked_here, &locked, wc_context, path, pool));
+
+ apr_pool_destroy(pool);
+
+ return Py_BuildValue("(bb)", locked_here?true:false, locked?true:false);
}
-static PyObject *is_normal_prop(PyObject *self, PyObject *args)
+static PyObject *py_wc_context_check_wc(PyObject *self, PyObject *args)
{
- char *name;
+ PyObject* py_path;
+ const char *path;
+ apr_pool_t *pool;
+ svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
+ int wc_format;
- if (!PyArg_ParseTuple(args, "s", &name))
- return NULL;
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
- return PyBool_FromLong(svn_wc_is_normal_prop(name));
+ pool = Pool(NULL);
+
+ path = py_object_to_svn_abspath(py_path, pool);
+ if (path == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(pool, svn_wc_check_wc2(&wc_format, wc_context, path, pool));
+
+ apr_pool_destroy(pool);
+
+#if PY_MAJOR_VERSION >= 3
+ return PyLong_FromLong(wc_format);
+#else
+ return PyInt_FromLong(wc_format);
+#endif
}
-static PyObject *is_adm_dir(PyObject *self, PyObject *args)
+static PyObject *py_wc_context_text_modified_p2(PyObject *self, PyObject *args)
{
- char *name;
- apr_pool_t *pool;
- svn_boolean_t ret;
+ PyObject* py_path;
+ const char *path;
+ apr_pool_t *pool;
+ svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
+ svn_boolean_t modified;
- if (!PyArg_ParseTuple(args, "s", &name))
- return NULL;
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
- pool = Pool(NULL);
- if (pool == NULL)
- return NULL;
+ pool = Pool(NULL);
- ret = svn_wc_is_adm_dir(name, pool);
+ path = py_object_to_svn_abspath(py_path, pool);
+ if (path == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
- apr_pool_destroy(pool);
+ RUN_SVN_WITH_POOL(pool, svn_wc_text_modified_p2(&modified, wc_context,
+ path, FALSE, pool));
- return PyBool_FromLong(ret);
+ apr_pool_destroy(pool);
+
+ return PyBool_FromLong(modified);
}
-static PyObject *is_wc_prop(PyObject *self, PyObject *args)
+static PyObject *py_wc_context_props_modified_p2(PyObject *self, PyObject *args)
{
- char *name;
+ PyObject* py_path;
+ const char *path;
+ apr_pool_t *pool;
+ svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
+ svn_boolean_t modified;
- if (!PyArg_ParseTuple(args, "s", &name))
- return NULL;
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
- return PyBool_FromLong(svn_wc_is_wc_prop(name));
+ pool = Pool(NULL);
+
+ path = py_object_to_svn_abspath(py_path, pool);
+ if (path == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(pool, svn_wc_props_modified_p2(&modified, wc_context,
+ path, pool));
+
+ apr_pool_destroy(pool);
+
+ return PyBool_FromLong(modified);
}
-static PyObject *is_entry_prop(PyObject *self, PyObject *args)
+static PyObject *py_wc_context_conflicted(PyObject *self, PyObject *args)
{
- char *name;
+ PyObject* py_path;
+ const char *path;
+ apr_pool_t *pool;
+ svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
+ svn_boolean_t text_conflicted, props_conflicted, tree_conflicted;
- if (!PyArg_ParseTuple(args, "s", &name))
- return NULL;
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
- return PyBool_FromLong(svn_wc_is_entry_prop(name));
-}
+ pool = Pool(NULL);
-static PyObject *get_adm_dir(PyObject *self)
+ path = py_object_to_svn_abspath(py_path, pool);
+ if (path == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(pool, svn_wc_conflicted_p3(
+ &text_conflicted, &props_conflicted, &tree_conflicted, wc_context,
+ path, pool));
+
+ apr_pool_destroy(pool);
+
+ return Py_BuildValue("(bbb)", text_conflicted, props_conflicted, tree_conflicted);
+}
+
+static PyObject *py_wc_context_crawl_revisions(PyObject *self, PyObject *args, PyObject *kwargs)
{
- apr_pool_t *pool;
- PyObject *ret;
- const char *dir;
- pool = Pool(NULL);
- if (pool == NULL)
- return NULL;
- dir = svn_wc_get_adm_dir(pool);
- ret = py_object_from_svn_abspath(dir);
- apr_pool_destroy(pool);
- return ret;
+ PyObject* py_path, *py_reporter;
+ const char *path;
+ apr_pool_t *pool;
+ svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
+ char *kwnames[] = { "path", "reporter", "restore_files", "depth",
+ "honor_depth_exclude", "depth_compatibility_trick", "use_commit_times",
+ "cancel", "notify", NULL };
+ bool restore_files = false;
+ int depth = svn_depth_infinity;
+ bool honor_depth_exclude = true;
+ bool depth_compatibility_trick = false;
+ bool use_commit_times = false;
+ PyObject *notify = Py_None;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bibbbOO", kwnames,
+ &py_path, &py_reporter, &restore_files,
+ &depth, &honor_depth_exclude,
+ &depth_compatibility_trick,
+ &use_commit_times, &notify)) {
+ return NULL;
+ }
+
+ pool = Pool(NULL);
+
+ path = py_object_to_svn_abspath(py_path, pool);
+ if (path == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(pool, svn_wc_crawl_revisions5(
+ wc_context, path, &py_ra_reporter3, py_reporter, restore_files,
+ depth, honor_depth_exclude, depth_compatibility_trick,
+ use_commit_times, py_cancel_check, NULL, py_wc_notify_func, notify, pool));
+
+ apr_pool_destroy(pool);
+
+ Py_RETURN_NONE;
+}
+
+static void context_done_handler(void *self)
+{
+ PyObject *selfobj = (PyObject *)self;
+
+ Py_DECREF(selfobj);
+}
+
+static PyObject *py_wc_context_get_update_editor(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ char *kwnames[] = {
+ "anchor_abspath", "target_basename", "use_commit_times", "depth",
+ "depth_is_sticky", "allow_unver_obstructions", "adds_as_modification",
+ "server_performs_filtering", "clean_checkout", "diff3_cmd",
+ "preserved_exts", "dirents_func", "conflict_func", "external_func",
+ "notify_func", NULL };
+ const svn_delta_editor_t *editor;
+ void *edit_baton;
+ const char *anchor_abspath;
+ char *target_basename;
+ char *diff3_cmd = NULL;
+ svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
+ bool use_commit_times = false;
+ int depth = svn_depth_infinity;
+ bool depth_is_sticky = false;
+ bool allow_unver_obstructions = true;
+ bool adds_as_modification = false;
+ bool server_performs_filtering = false;
+ bool clean_checkout = false;
+ apr_array_header_t *preserved_exts = NULL;
+ PyObject *py_preserved_exts = Py_None;
+ PyObject *dirents_func = Py_None;
+ PyObject *conflict_func = Py_None;
+ PyObject *external_func = Py_None;
+ PyObject *notify_func = Py_None;
+ PyObject *py_anchor_abspath;
+ apr_pool_t *result_pool, *scratch_pool;
+ svn_error_t *err;
+ svn_revnum_t target_revision;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os|bibbbbbzOOOOO", kwnames,
+ &py_anchor_abspath, &target_basename,
+ &use_commit_times, &depth,
+ &depth_is_sticky,
+ &allow_unver_obstructions,
+ &adds_as_modification,
+ &server_performs_filtering,
+ &clean_checkout, &py_preserved_exts,
+ &dirents_func, &conflict_func,
+ &external_func, &notify_func)) {
+ return NULL;
+ }
+
+ if (conflict_func != Py_None) {
+ // TODO
+ PyErr_SetString(PyExc_NotImplementedError,
+ "conflict_func is not currently supported");
+ return NULL;
+ }
+
+ if (external_func != Py_None) {
+ // TODO
+ PyErr_SetString(PyExc_NotImplementedError,
+ "external_func is not currently supported");
+ return NULL;
+ }
+
+ if (dirents_func != Py_None) {
+ // TODO
+ PyErr_SetString(PyExc_NotImplementedError,
+ "dirents_func is not currently supported");
+ return NULL;
+ }
+
+ scratch_pool = Pool(NULL);
+
+ anchor_abspath = py_object_to_svn_abspath(py_anchor_abspath, scratch_pool);
+
+ if (py_preserved_exts != Py_None) {
+ if (!string_list_to_apr_array(scratch_pool, py_preserved_exts, &preserved_exts)) {
+ apr_pool_destroy(scratch_pool);
+ return NULL;
+ }
+ }
+
+ result_pool = Pool(NULL);
+
+ Py_BEGIN_ALLOW_THREADS
+ err = svn_wc_get_update_editor4(
+ &editor, &edit_baton, &target_revision, wc_context,
+ anchor_abspath, target_basename, use_commit_times, depth,
+ depth_is_sticky, allow_unver_obstructions, adds_as_modification,
+ server_performs_filtering, clean_checkout, diff3_cmd,
+ preserved_exts, NULL, dirents_func, NULL, conflict_func, NULL,
+ external_func, py_cancel_check, NULL, py_wc_notify_func,
+ notify_func, result_pool, scratch_pool);
+ Py_END_ALLOW_THREADS
+
+ apr_pool_destroy(scratch_pool);
+
+ if (err != NULL) {
+ handle_svn_error(err);
+ svn_error_clear(err);
+ apr_pool_destroy(result_pool);
+ return NULL;
+ }
+
+ /* TODO: Also return target_revision ? */
+ Py_INCREF(self);
+ return new_editor_object(NULL, editor, edit_baton, result_pool, &Editor_Type,
+ context_done_handler, self, NULL);
+}
+
+static PyObject *py_wc_context_ensure_adm(PyObject *self, PyObject *args,
+ PyObject *kwargs)
+{
+ ContextObject *context_obj = (ContextObject *)self;
+ char *kwnames[] = {
+ "local_abspath", "url", "repos_root_url", "repos_uuid",
+ "revnum", "depth", NULL };
+ char *local_abspath;
+ char *url;
+ char *repos_root_url;
+ char *repos_uuid;
+ int revnum;
+ int depth = svn_depth_infinity;
+ apr_pool_t *pool;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ssssi|i", kwnames,
+ &local_abspath, &url, &repos_root_url,
+ &repos_uuid, &revnum, &depth)) {
+ return NULL;
+ }
+
+ pool = Pool(NULL);
+
+ RUN_SVN_WITH_POOL(pool, svn_wc_ensure_adm4(context_obj->context,
+ local_abspath, url,
+ repos_root_url, repos_uuid,
+ revnum, depth, pool));
+
+ apr_pool_destroy(pool);
+
+ Py_RETURN_NONE;
}
-static PyObject *set_adm_dir(PyObject *self, PyObject *args)
+typedef struct {
+ PyObject_VAR_HEAD
+ apr_pool_t *pool;
+ svn_wc_status3_t status;
+} Status3Object;
+
+static void status_dealloc(PyObject *self)
{
- apr_pool_t *temp_pool;
- char *name;
- PyObject *py_name;
+ apr_pool_t *pool = ((Status3Object *)self)->pool;
+ if (pool != NULL)
+ apr_pool_destroy(pool);
+ PyObject_Del(self);
+}
- if (!PyArg_ParseTuple(args, "O", &py_name))
- return NULL;
+static PyMemberDef status_members[] = {
+ { "kind", T_INT, offsetof(Status3Object, status.kind), READONLY,
+ "The kind of node as recorded in the working copy." },
+ { "depth", T_INT, offsetof(Status3Object, status.depth), READONLY,
+ "The depth of the node as recorded in the working copy." },
+ { "filesize", T_LONG, offsetof(Status3Object, status.filesize), READONLY,
+ "The actual size of the working file on disk, or SVN_INVALID_FILESIZE"
+ "if unknown (or if the item isn't a file at all)" },
+ { "versioned", T_BOOL, offsetof(Status3Object, status.versioned), READONLY,
+ "If the path is under version control, versioned is TRUE, "
+ "otherwise FALSE." },
+ { "repos_uuid", T_STRING, offsetof(Status3Object, status.repos_uuid), READONLY,
+ "UUID of repository" },
+ { "repos_root_url", T_STRING, offsetof(Status3Object, status.repos_root_url), READONLY,
+ "Repository root URL" },
+ { "repos_relpath", T_STRING, offsetof(Status3Object, status.repos_relpath), READONLY,
+ "Relative path in repository" },
+ /* TODO */
+ { NULL }
+};
- temp_pool = Pool(NULL);
- if (temp_pool == NULL)
- return NULL;
- name = py_object_to_svn_string(py_name, temp_pool);
- if (name == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_set_adm_dir(name, temp_pool));
- apr_pool_destroy(temp_pool);
- Py_RETURN_NONE;
-}
+static PyTypeObject Status3_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "wc.Status", /* const char *tp_name; For printing, in format "<module>.<name>" */
+ sizeof(Status3Object),
+ 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
-static PyObject *get_pristine_copy_path(PyObject *self, PyObject *args)
-{
- apr_pool_t *pool;
- const char *pristine_path;
- const char *path;
- PyObject *py_path;
- PyObject *ret;
+ /* Methods to implement standard operations */
- if (!PyArg_ParseTuple(args, "O", &py_path))
- return NULL;
+ status_dealloc, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ NULL, /* reprfunc tp_repr; */
- pool = Pool(NULL);
- if (pool == NULL)
- return NULL;
+ /* Method suites for standard classes */
- path = py_object_to_svn_dirent(py_path, pool);
- if (path == NULL) {
- apr_pool_destroy(pool);
- return NULL;
- }
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
- PyErr_WarnEx(PyExc_DeprecationWarning, "get_pristine_copy_path is deprecated. Use get_pristine_contents instead.", 2);
- RUN_SVN_WITH_POOL(pool,
- svn_wc_get_pristine_copy_path(path,
- &pristine_path, pool));
- ret = py_object_from_svn_abspath(pristine_path);
- apr_pool_destroy(pool);
- return ret;
-}
+ /* More standard operations (here for binary compatibility) */
-static PyObject *get_pristine_contents(PyObject *self, PyObject *args)
-{
- const char *path;
- apr_pool_t *temp_pool;
- PyObject *py_path;
-#if ONLY_SINCE_SVN(1, 6)
- apr_pool_t *stream_pool;
- StreamObject *ret;
- svn_stream_t *stream;
-#else
- PyObject *ret;
- const char *pristine_path;
-#endif
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
- if (!PyArg_ParseTuple(args, "O", &py_path))
- return NULL;
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
-#if ONLY_SINCE_SVN(1, 6)
- stream_pool = Pool(NULL);
- if (stream_pool == NULL)
- return NULL;
+ /* Flags to define presence of optional/expanded features */
+ 0, /* long tp_flags; */
- temp_pool = Pool(stream_pool);
- if (temp_pool == NULL) {
- apr_pool_destroy(stream_pool);
- return NULL;
- }
+ NULL, /* const char *tp_doc; Documentation string */
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
+ /* Assigned meaning in release 2.0 */
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
- RUN_SVN_WITH_POOL(stream_pool, svn_wc_get_pristine_contents(&stream, path, stream_pool, temp_pool));
- apr_pool_destroy(temp_pool);
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
- if (stream == NULL) {
- apr_pool_destroy(stream_pool);
- Py_RETURN_NONE;
- }
+ /* Assigned meaning in release 2.1 */
+ /* rich comparisons */
+ NULL, /* richcmpfunc tp_richcompare; */
- ret = PyObject_New(StreamObject, &Stream_Type);
- if (ret == NULL)
- return NULL;
+ /* weak reference enabler */
+ 0, /* Py_ssize_t tp_weaklistoffset; */
- ret->pool = stream_pool;
- ret->closed = FALSE;
- ret->stream = stream;
+ /* Added in release 2.2 */
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
- return (PyObject *)ret;
+ /* Attribute descriptor and subclassing stuff */
+ NULL, /* struct PyMethodDef *tp_methods; */
+ status_members, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getsetters; */
+};
+
+static PyObject *py_wc_status(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ ContextObject *context_obj = (ContextObject *)self;
+ char *kwnames[] = {"path", NULL};
+ PyObject *py_path;
+ Status3Object *ret;
+ const char *path;
+ apr_pool_t *scratch_pool, *result_pool;
+ svn_wc_status3_t* status;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &py_path)) {
+ return NULL;
+ }
+
+ result_pool = Pool(NULL);
+ if (result_pool == NULL) {
+ return NULL;
+ }
+ scratch_pool = Pool(result_pool);
+ if (scratch_pool == NULL) {
+ apr_pool_destroy(result_pool);
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, scratch_pool);
+ if (path == NULL) {
+ apr_pool_destroy(result_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(result_pool,
+ svn_wc_status3(&status, context_obj->context, path,
+ result_pool, scratch_pool));
+
+ apr_pool_destroy(scratch_pool);
+
+ ret = PyObject_New(Status3Object, &Status3_Type);
+ if (ret == NULL) {
+ apr_pool_destroy(result_pool);
+ return NULL;
+ }
+ ret->pool = result_pool;
+ ret->status = *status;
+ return (PyObject *)ret;
+}
+
+static svn_error_t *py_status_receiver(void *baton, const char *local_abspath,
+ const svn_wc_status3_t *status,
+ apr_pool_t *scratch_pool)
+{
+ Status3Object *py_status;
+ PyObject *ret;
+ PyGILState_STATE state;
+
+ if (baton == Py_None)
+ return NULL;
+
+ state = PyGILState_Ensure();
+
+ py_status = PyObject_New(Status3Object, &Status3_Type);
+ if (py_status == NULL) {
+ PyGILState_Release(state);
+ return py_svn_error();
+ }
+ py_status->pool = Pool(NULL);
+ py_status->status = *svn_wc_dup_status3(status, py_status->pool);
+
+ ret = PyObject_CallFunction((PyObject *)baton, "sO", local_abspath, py_status);
+ Py_DECREF(py_status);
+
+ if (ret == NULL) {
+ PyGILState_Release(state);
+ return py_svn_error();
+ }
+
+ Py_DECREF(ret);
+ PyGILState_Release(state);
+
+ return NULL;
+}
+
+static PyObject *py_wc_walk_status(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ ContextObject *context_obj = (ContextObject *)self;
+ char *kwnames[] = {"path", "receiver", "depth", "get_all", "no_ignore",
+ "ignore_text_mode", "ignore_patterns", NULL};
+ PyObject *py_path;
+ const char *path;
+ int depth = svn_depth_infinity;
+ bool get_all = true;
+ bool no_ignore = false;
+ bool ignore_text_mode = false;
+ PyObject *py_ignore_patterns = Py_None;
+ PyObject *status_func;
+ apr_array_header_t *ignore_patterns;
+ apr_pool_t *pool;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|ibbbOO", kwnames,
+ &py_path, &status_func, &depth, &get_all, &no_ignore,
+ &ignore_text_mode, &py_ignore_patterns)) {
+ return NULL;
+ }
+
+ pool = Pool(NULL);
+
+ path = py_object_to_svn_abspath(py_path, pool);
+ if (path == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ if (py_ignore_patterns == Py_None) {
+ ignore_patterns = NULL;
+ } else {
+ if (!string_list_to_apr_array(pool, py_ignore_patterns, &ignore_patterns)) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+ }
+
+ RUN_SVN_WITH_POOL(pool,
+ svn_wc_walk_status(context_obj->context, path, depth,
+ get_all, no_ignore, ignore_text_mode,
+ ignore_patterns, py_status_receiver,
+ status_func, py_cancel_check, NULL,
+ pool));
+
+ apr_pool_destroy(pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_wc_add_lock(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ ContextObject *context_obj = (ContextObject *)self;
+ PyObject *py_path, *py_lock;
+ svn_lock_t *lock;
+ char *kwnames[] = { "path", "lock", NULL };
+ const char *path;
+ apr_pool_t *scratch_pool;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO!", kwnames, &py_path, &Lock_Type,
+ &py_lock)) {
+ return NULL;
+ }
+
+ scratch_pool = Pool(NULL);
+ if (scratch_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, scratch_pool);
+ if (path == NULL) {
+ apr_pool_destroy(scratch_pool);
+ return NULL;
+ }
+
+ lock = py_object_to_svn_lock(py_lock, scratch_pool);
+ if (lock == NULL) {
+ apr_pool_destroy(scratch_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(scratch_pool,
+ svn_wc_add_lock2(context_obj->context, path, lock, scratch_pool));
+
+ apr_pool_destroy(scratch_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_wc_remove_lock(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ ContextObject *context_obj = (ContextObject *)self;
+ char *kwnames[] = { "path", NULL };
+ PyObject *py_path;
+ const char *path;
+ apr_pool_t *scratch_pool;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &py_path)) {
+ return NULL;
+ }
+
+ scratch_pool = Pool(NULL);
+
+ path = py_object_to_svn_abspath(py_path, scratch_pool);
+ if (path == NULL) {
+ apr_pool_destroy(scratch_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(scratch_pool,
+ svn_wc_remove_lock2(context_obj->context, path,
+ scratch_pool));
+
+ apr_pool_destroy(scratch_pool);
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_wc_add_from_disk(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ ContextObject *context_obj = (ContextObject *)self;
+ char *kwnames[] = {"path", "props", "skip_checks", "notify", NULL };
+ PyObject *py_path;
+ const char *path;
+ bool skip_checks = false;
+ PyObject *py_props = Py_None;
+ PyObject *notify_func = Py_None;
+ apr_pool_t *pool;
+ apr_hash_t *props;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|ObO", kwnames,
+ &py_path, &py_props, &skip_checks, &notify_func)) {
+ return NULL;
+ }
+
+ pool = Pool(NULL);
+ if (pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, pool);
+ if (path == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ if (py_props == Py_None) {
+ props = NULL;
+ } else {
+ props = prop_dict_to_hash(pool, py_props);
+ if (props == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+ }
+
+#if ONLY_SINCE_SVN(1, 9)
+ RUN_SVN_WITH_POOL(
+ pool, svn_wc_add_from_disk3(
+ context_obj->context, path, props, skip_checks,
+ notify_func == Py_None?NULL:py_wc_notify_func,
+ notify_func, pool));
#else
- temp_pool = Pool(NULL);
- if (temp_pool == NULL)
- return NULL;
- RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_pristine_copy_path(path, &pristine_path, temp_pool));
- ret = PyFile_FromString((char *)pristine_path, "rb");
- apr_pool_destroy(temp_pool);
- return ret;
+ if (props != NULL) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "props argument only supported on svn >= 1.9");
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ if (skip_checks) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "skip_checks argument only supported on svn >= 1.9");
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+ RUN_SVN_WITH_POOL(
+ pool, svn_wc_add_from_disk(
+ context_obj->context, path,
+ notify_func == Py_None?NULL:py_wc_notify_func,
+ notify_func, pool));
#endif
+
+ apr_pool_destroy(pool);
+
+ Py_RETURN_NONE;
}
-static PyObject *ensure_adm(PyObject *self, PyObject *args, PyObject *kwargs)
+static PyObject *py_wc_get_prop_diffs(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ ContextObject *context_obj = (ContextObject *)self;
+ PyObject *py_path, *py_orig_props, *py_propchanges;
+ apr_pool_t *pool;
+ char *kwnames[] = {"path", NULL};
+ apr_hash_t *original_props;
+ apr_array_header_t *propchanges;
+ const char *path;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &py_path)) {
+ return NULL;
+ }
+
+ pool = Pool(NULL);
+
+ path = py_object_to_svn_abspath(py_path, pool);
+ if (path == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(pool, svn_wc_get_prop_diffs2(&propchanges,
+ &original_props,
+ context_obj->context,
+ path, pool, pool));
+
+ py_orig_props = prop_hash_to_dict(original_props);
+ if (py_orig_props == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ py_propchanges = propchanges_to_list(propchanges);
+ if (py_propchanges == NULL) {
+ apr_pool_destroy(pool);
+ Py_DECREF(py_propchanges);
+ return NULL;
+ }
+
+ apr_pool_destroy(pool);
+
+ return Py_BuildValue("NN", py_orig_props, py_propchanges);
+}
+
+static PyObject *py_wc_context_process_committed_queue(PyObject *self, PyObject *args)
+{
+ apr_pool_t *temp_pool;
+ ContextObject *contextobj = (ContextObject *)self;
+ svn_revnum_t revnum;
+ char *date, *author;
+ PyObject *py_queue;
+
+ if (!PyArg_ParseTuple(args, "O!lss", &CommittedQueue_Type, &py_queue,
+ &revnum, &date, &author))
+ return NULL;
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL)
+ return NULL;
+
+ svn_wc_committed_queue_t *committed_queue = PyObject_GetCommittedQueue(py_queue);
+
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_process_committed_queue2(committed_queue,
+ contextobj->context,
+ revnum, date, author,
+ py_cancel_check, NULL,
+ temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+
+
+static PyMethodDef context_methods[] = {
+ { "locked", py_wc_context_locked, METH_VARARGS,
+ "locked(path) -> (locked_here, locked)\n"
+ "Check whether a patch is locked."},
+ { "check_wc", py_wc_context_check_wc, METH_VARARGS,
+ "check_wc(path) -> wc_format\n"
+ "Check format version of a working copy." },
+ { "text_modified", py_wc_context_text_modified_p2, METH_VARARGS,
+ "text_modified(path) -> bool\n"
+ "Check whether text of a file is modified against base." },
+ { "props_modified", py_wc_context_props_modified_p2, METH_VARARGS,
+ "props_modified(path) -> bool\n"
+ "Check whether props of a file are modified against base." },
+ { "conflicted", py_wc_context_conflicted, METH_VARARGS,
+ "conflicted(path) -> (text_conflicted, prop_conflicted, "
+ "tree_conflicted)\n"
+ "Check whether a path is conflicted." },
+ { "crawl_revisions", (PyCFunction)py_wc_context_crawl_revisions,
+ METH_VARARGS|METH_KEYWORDS,
+ "crawl_revisions(path, reporter, restore_files, depth, "
+ "honor_depth_exclude, depth_compatibility_trick, "
+ "use_commit_time, notify)\n"
+ "Do a depth-first crawl of the working copy." },
+ { "get_update_editor",
+ (PyCFunction)py_wc_context_get_update_editor,
+ METH_VARARGS|METH_KEYWORDS,
+ "get_update_editor(anchor_abspath, target_basename, use_commit_time, "
+ "depth, depth_is_sticky, allow_unver_obstructions, "
+ "adds_as_modification, server_performs_filtering, clean_checkout, "
+ "diff3_cmd, dirent_func=None, conflict_func=None, "
+ "external_func=None) -> target_revnum" },
+ { "ensure_adm",
+ (PyCFunction)py_wc_context_ensure_adm,
+ METH_VARARGS|METH_KEYWORDS,
+ "ensure_adm(local_abspath, url, repos_root_url, repos_uuid, revnum, depth)" },
+ { "process_committed_queue",
+ (PyCFunction)py_wc_context_process_committed_queue,
+ METH_VARARGS|METH_KEYWORDS,
+ "" },
+ { "status",
+ (PyCFunction)py_wc_status,
+ METH_VARARGS|METH_KEYWORDS,
+ "status(path) -> status" },
+ { "walk_status",
+ (PyCFunction)py_wc_walk_status,
+ METH_VARARGS|METH_KEYWORDS,
+ "walk_status(path, receiver, depth=DEPTH_INFINITY, get_all=True, "
+ "no_ignore=False, ignore_text_mode=False, ignore_patterns=None)\n" },
+ { "add_lock",
+ (PyCFunction)py_wc_add_lock,
+ METH_VARARGS|METH_KEYWORDS,
+ "add_lock(path, lock)" },
+ { "remove_lock",
+ (PyCFunction)py_wc_remove_lock,
+ METH_VARARGS|METH_KEYWORDS,
+ "remove_lock(path)" },
+ { "add_from_disk",
+ (PyCFunction)py_wc_add_from_disk,
+ METH_VARARGS|METH_KEYWORDS,
+ "add_from_disk(local_abspath, props=None, skip_checks=False, notify=None)" },
+ { "get_prop_diffs",
+ (PyCFunction)py_wc_get_prop_diffs,
+ METH_VARARGS|METH_KEYWORDS,
+ "get_prop_diffs(path) -> (changes orig_props)" },
+ { NULL }
+};
+
+static void context_dealloc(PyObject *self)
{
- const char *path;
- char *uuid, *url;
- PyObject *py_path;
- char *repos=NULL;
- svn_revnum_t rev=-1;
- apr_pool_t *pool;
- char *kwnames[] = { "path", "uuid", "url", "repos", "rev", "depth", NULL };
- svn_depth_t depth = svn_depth_infinity;
+ ContextObject *context_obj = (ContextObject *)self;
+ svn_wc_context_destroy(context_obj->context);
+ apr_pool_destroy(context_obj->pool);
+ PyObject_Del(self);
+}
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oss|sli", kwnames,
- &py_path, &uuid, &url, &repos, &rev, &depth))
- return NULL;
+static PyObject *context_init(PyTypeObject *self, PyObject *args, PyObject *kwargs)
+{
+ ContextObject *ret;
+ char *kwnames[] = { NULL };
+ svn_config_t *config = NULL;
- pool = Pool(NULL);
- if (pool == NULL) {
- return NULL;
- }
+ // TODO(jelmer): Support passing in config
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwnames))
+ return NULL;
- path = py_object_to_svn_dirent(py_path, pool);
- if (path == NULL) {
- apr_pool_destroy(pool);
- return NULL;
- }
+ ret = PyObject_New(ContextObject, &Context_Type);
+ if (ret == NULL)
+ return NULL;
-#if ONLY_SINCE_SVN(1, 5)
- RUN_SVN_WITH_POOL(pool,
- svn_wc_ensure_adm3(path,
- uuid, url, repos, rev, depth, pool));
-#else
- if (depth != svn_depth_infinity) {
- PyErr_SetString(PyExc_NotImplementedError,
- "depth != infinity not supported with svn < 1.5");
- apr_pool_destroy(pool);
- return NULL;
- }
- RUN_SVN_WITH_POOL(pool,
- svn_wc_ensure_adm2(path,
- uuid, url, repos, rev, pool));
-#endif
- apr_pool_destroy(pool);
- Py_RETURN_NONE;
+ ret->pool = Pool(NULL);
+ if (ret->pool == NULL)
+ return NULL;
+ RUN_SVN_WITH_POOL(ret->pool, svn_wc_context_create(&ret->context, config,
+ ret->pool, ret->pool));
+
+ return (PyObject *)ret;
}
-static PyObject *check_wc(PyObject *self, PyObject *args)
-{
- const char *path;
- apr_pool_t *pool;
- int wc_format;
- PyObject *py_path;
+static PyTypeObject Context_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "wc.Context", /* const char *tp_name; For printing, in format "<module>.<name>" */
+ sizeof(ContextObject),
+ 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
- if (!PyArg_ParseTuple(args, "O", &py_path))
- return NULL;
+ /* Methods to implement standard operations */
- pool = Pool(NULL);
- if (pool == NULL) {
- return NULL;
- }
+ context_dealloc, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ NULL, /* reprfunc tp_repr; */
- path = py_object_to_svn_dirent(py_path, pool);
- if (path == NULL) {
- apr_pool_destroy(pool);
- return NULL;
- }
+ /* Method suites for standard classes */
- RUN_SVN_WITH_POOL(pool, svn_wc_check_wc(path, &wc_format, pool));
- apr_pool_destroy(pool);
- return PyLong_FromLong(wc_format);
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /* Flags to define presence of optional/expanded features */
+ 0, /* long tp_flags; */
+
+ "Context", /* const char *tp_doc; Documentation string */
+
+ /* Assigned meaning in release 2.0 */
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /* Assigned meaning in release 2.1 */
+ /* rich comparisons */
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /* weak reference enabler */
+ 0, /* Py_ssize_t tp_weaklistoffset; */
+
+ /* Added in release 2.2 */
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /* Attribute descriptor and subclassing stuff */
+ context_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* Py_ssize_t tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ context_init, /* newfunc tp_new; */
+};
+
+#endif
+
+static void lock_dealloc(PyObject *self)
+{
+ LockObject *lockself = (LockObject *)self;
+
+ apr_pool_destroy(lockself->pool);
+
+ PyObject_Del(self);
}
-static PyObject *cleanup_wc(PyObject *self, PyObject *args, PyObject *kwargs)
+static PyObject *lock_init(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
- const char *path;
- char *diff3_cmd = NULL;
- char *kwnames[] = { "path", "diff3_cmd", NULL };
- apr_pool_t *temp_pool;
- PyObject *py_path;
+ char *kwnames[] = { "token", NULL };
+ LockObject *ret;
+ char *token = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|z", kwnames,
- &py_path, &diff3_cmd))
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|z", kwnames, &token))
return NULL;
- temp_pool = Pool(NULL);
- if (temp_pool == NULL) {
+ ret = PyObject_New(LockObject, &Lock_Type);
+ if (ret == NULL)
return NULL;
- }
- path = py_object_to_svn_dirent(py_path, temp_pool);
- if (path == NULL) {
- apr_pool_destroy(temp_pool);
+ ret->pool = Pool(NULL);
+ if (ret->pool == NULL)
return NULL;
- }
+ ret->lock = *svn_lock_create(ret->pool);
+ if (token != NULL) {
+ ret->lock.token = apr_pstrdup(ret->pool, token);
+ }
- RUN_SVN_WITH_POOL(temp_pool,
- svn_wc_cleanup2(path, diff3_cmd, py_cancel_check, NULL,
- temp_pool));
- apr_pool_destroy(temp_pool);
+ return (PyObject *)ret;
+}
- Py_RETURN_NONE;
+static PyObject *lock_get_path(PyObject *self, void *closure) {
+ LockObject *lock_obj = (LockObject *)self;
+
+ if (lock_obj->lock.path == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ return PyUnicode_FromString(lock_obj->lock.path);
}
-static PyObject *match_ignore_list(PyObject *self, PyObject *args)
-{
-#if ONLY_SINCE_SVN(1, 5)
- char *str;
- PyObject *py_list;
- apr_array_header_t *list;
- apr_pool_t *temp_pool;
- svn_boolean_t ret;
+static int lock_set_path(PyObject *self, PyObject *value, void *closure) {
+ LockObject *lock_obj = (LockObject *)self;
+ char *path;
- if (!PyArg_ParseTuple(args, "sO", &str, &py_list))
- return NULL;
+ path = PyBytes_AsString(value);
+ if (path == NULL) {
+ return -1;
+ }
- temp_pool = Pool(NULL);
+ lock_obj->lock.path = py_object_to_svn_string(value, lock_obj->pool);
+ return 0;
+}
- if (!string_list_to_apr_array(temp_pool, py_list, &list)) {
- apr_pool_destroy(temp_pool);
- return NULL;
- }
+static PyObject *lock_get_token(PyObject *self, void *closure) {
+ LockObject *lock_obj = (LockObject *)self;
- ret = svn_wc_match_ignore_list(str, list, temp_pool);
+ if (lock_obj->lock.token == NULL) {
+ Py_RETURN_NONE;
+ }
- apr_pool_destroy(temp_pool);
+ return PyBytes_FromString(lock_obj->lock.token);
+}
- return PyBool_FromLong(ret);
-#else
- PyErr_SetNone(PyExc_NotImplementedError);
- return NULL;
-#endif
+static int lock_set_token(PyObject *self, PyObject *value, void *closure) {
+ LockObject *lock_obj = (LockObject *)self;
+ char *token;
+
+ token = PyBytes_AsString(value);
+ if (token == NULL) {
+ PyErr_SetNone(PyExc_TypeError);
+ return -1;
+ }
+
+ lock_obj->lock.token = apr_pstrdup(lock_obj->pool, PyBytes_AsString(value));
+ return 0;
}
-static PyMethodDef wc_methods[] = {
- { "check_wc", check_wc, METH_VARARGS, "check_wc(path) -> version\n"
- "Check whether path contains a Subversion working copy\n"
- "return the workdir version"},
- { "cleanup", (PyCFunction)cleanup_wc, METH_VARARGS|METH_KEYWORDS, "cleanup(path, diff3_cmd=None)\n" },
- { "ensure_adm", (PyCFunction)ensure_adm, METH_KEYWORDS|METH_VARARGS,
- "ensure_adm(path, uuid, url, repos=None, rev=None)" },
- { "get_adm_dir", (PyCFunction)get_adm_dir, METH_NOARGS,
- "get_adm_dir() -> name" },
- { "set_adm_dir", (PyCFunction)set_adm_dir, METH_VARARGS,
- "set_adm_dir(name)" },
- { "get_pristine_copy_path", get_pristine_copy_path, METH_VARARGS,
- "get_pristine_copy_path(path) -> path" },
- { "get_pristine_contents", get_pristine_contents, METH_VARARGS,
- "get_pristine_contents(path) -> stream" },
- { "is_adm_dir", is_adm_dir, METH_VARARGS,
- "is_adm_dir(name) -> bool" },
- { "is_normal_prop", is_normal_prop, METH_VARARGS,
- "is_normal_prop(name) -> bool" },
- { "is_entry_prop", is_entry_prop, METH_VARARGS,
- "is_entry_prop(name) -> bool" },
- { "is_wc_prop", is_wc_prop, METH_VARARGS,
- "is_wc_prop(name) -> bool" },
- { "revision_status", (PyCFunction)revision_status, METH_KEYWORDS|METH_VARARGS, "revision_status(wc_path, trail_url=None, committed=False) -> (min_rev, max_rev, switched, modified)" },
- { "version", (PyCFunction)version, METH_NOARGS,
- "version() -> (major, minor, patch, tag)\n\n"
- "Version of libsvn_wc currently used."
- },
- { "api_version", (PyCFunction)api_version, METH_NOARGS,
- "api_version() -> (major, minor, patch, tag)\n\n"
- "Version of libsvn_wc Subvertpy was compiled against."
- },
- { "match_ignore_list", (PyCFunction)match_ignore_list, METH_VARARGS,
- "match_ignore_list(str, patterns) -> bool" },
- { "get_actual_target", (PyCFunction)get_actual_target, METH_VARARGS,
- "get_actual_target(path) -> (anchor, target)" },
- { NULL, }
+static PyGetSetDef lock_getsetters[] = {
+ { "path", lock_get_path, lock_set_path,
+ "the path this lock applies to"},
+ { "token", lock_get_token, lock_set_token,
+ "unique URI representing lock"},
+ { NULL },
+};
+
+PyTypeObject Lock_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "wc.Lock", /* const char *tp_name; For printing, in format "<module>.<name>" */
+ sizeof(LockObject),
+ 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ .tp_dealloc = lock_dealloc, /* destructor tp_dealloc; */
+
+ .tp_doc = "Lock", /* const char *tp_doc; Documentation string */
+
+ .tp_methods = NULL, /* struct PyMethodDef *tp_methods; */
+
+ .tp_new = lock_init, /* tp_new tp_new */
+
+ .tp_getset = lock_getsetters,
};
static PyObject *
@@ -2990,12 +2133,17 @@ moduleinit(void)
if (PyType_Ready(&Entry_Type) < 0)
return NULL;
- if (PyType_Ready(&Status_Type) < 0)
+ if (PyType_Ready(&Status2_Type) < 0)
return NULL;
if (PyType_Ready(&Adm_Type) < 0)
return NULL;
+#if ONLY_SINCE_SVN(1, 7)
+ if (PyType_Ready(&Context_Type) < 0)
+ return NULL;
+#endif
+
if (PyType_Ready(&Editor_Type) < 0)
return NULL;
@@ -3014,6 +2162,14 @@ moduleinit(void)
if (PyType_Ready(&CommittedQueue_Type) < 0)
return NULL;
+#if ONLY_SINCE_SVN(1, 7)
+ if (PyType_Ready(&Status3_Type) < 0)
+ return NULL;
+#endif
+
+ if (PyType_Ready(&Lock_Type) < 0)
+ return NULL;
+
apr_initialize();
#if PY_MAJOR_VERSION >= 3
@@ -3089,15 +2245,18 @@ moduleinit(void)
PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MERGED", svn_wc_conflict_choose_merged);
#endif
-#if ONLY_BEFORE_SVN(1, 7)
- /* Subversion 1.7 has a couple of significant behaviour changes that break subvertpy.
- * We haven't updated the code to deal with these changes in behaviour yet.
- * */
- PyModule_AddObject(mod, "WorkingCopy", (PyObject *)&Adm_Type);
+ PyModule_AddObject(mod, "Adm", (PyObject *)&Adm_Type);
Py_INCREF(&Adm_Type);
+ PyModule_AddObject(mod, "Lock", (PyObject *)&Lock_Type);
+ Py_INCREF(&Lock_Type);
+
PyModule_AddObject(mod, "CommittedQueue", (PyObject *)&CommittedQueue_Type);
Py_INCREF(&CommittedQueue_Type);
+
+#if ONLY_SINCE_SVN(1, 7)
+ PyModule_AddObject(mod, "Context", (PyObject *)&Context_Type);
+ Py_INCREF(&Context_Type);
#endif
return mod;
diff --git a/subvertpy/wc.h b/subvertpy/wc.h
index 854611dd..ccd50d48 100644
--- a/subvertpy/wc.h
+++ b/subvertpy/wc.h
@@ -24,7 +24,28 @@
#pragma GCC visibility push(hidden)
#endif
+bool py_dict_to_wcprop_changes(PyObject *dict, apr_pool_t *pool, apr_array_header_t **ret);
void py_wc_notify_func(void *baton, const svn_wc_notify_t *notify, apr_pool_t *pool);
+PyObject *py_wc_status2(svn_wc_status2_t *status);
+#if ONLY_SINCE_SVN(1, 5)
+extern const svn_ra_reporter3_t py_ra_reporter3;
+#endif
+extern const svn_ra_reporter2_t py_ra_reporter2;
+
+#if ONLY_SINCE_SVN(1, 6)
+svn_error_t *wc_validator3(void *baton, const char *uuid, const char *url, const char *root_url, apr_pool_t *pool);
+#endif
+svn_error_t *wc_validator2(void *baton, const char *uuid, const char *url, svn_boolean_t root, apr_pool_t *pool);
+svn_wc_committed_queue_t *PyObject_GetCommittedQueue(PyObject *obj);
+extern PyTypeObject CommittedQueue_Type;
+svn_lock_t *py_object_to_svn_lock(PyObject *py_lock, apr_pool_t *pool);
+
+/* Provided by wc_adm.h */
+extern PyTypeObject Adm_Type;
+extern PyTypeObject Entry_Type;
+extern PyTypeObject Status2_Type;
+svn_wc_adm_access_t *PyObject_GetAdmAccess(PyObject *obj);
+extern PyTypeObject Lock_Type;
#ifdef __GNUC__
#pragma GCC visibility pop
diff --git a/subvertpy/wc_adm.c b/subvertpy/wc_adm.c
new file mode 100644
index 00000000..07df1343
--- /dev/null
+++ b/subvertpy/wc_adm.c
@@ -0,0 +1,2237 @@
+/*
+ * Copyright © 2008 Jelmer Vernooij <jelmer@jelmer.uk>
+ * -*- coding: utf-8 -*-
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include <Python.h>
+#include <apr_general.h>
+#include <svn_wc.h>
+#include <svn_path.h>
+#include <svn_props.h>
+#include <structmember.h>
+#include <stdbool.h>
+#include <apr_md5.h>
+#include <apr_sha1.h>
+
+#include "util.h"
+#include "editor.h"
+#include "wc.h"
+
+/* Suppress warnings for this specific file, as it
+ * provides backwards compatibility with svn < 1.7
+ */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+static svn_wc_entry_callbacks2_t py_wc_entry_callbacks2;
+static PyObject *py_entry(const svn_wc_entry_t *entry);
+
+typedef struct {
+ PyObject_VAR_HEAD
+ svn_wc_adm_access_t *adm;
+ apr_pool_t *pool;
+} AdmObject;
+
+typedef struct {
+ PyObject_VAR_HEAD
+ apr_pool_t *pool;
+ svn_wc_entry_t entry;
+} EntryObject;
+
+svn_wc_adm_access_t *Adm_GetAdmAccess(PyObject *obj) {
+ AdmObject *adm_obj = (AdmObject *)obj;
+ return adm_obj->adm;
+}
+
+#define ADM_CHECK_CLOSED(adm_obj) \
+ if (adm_obj->adm == NULL) { \
+ PyErr_SetString(PyExc_RuntimeError, "WorkingCopy instance already closed"); \
+ return NULL; \
+ }
+
+svn_wc_adm_access_t *PyObject_GetAdmAccess(PyObject *obj)
+{
+ return ((AdmObject *)obj)->adm;
+}
+
+static PyObject *adm_init(PyTypeObject *self, PyObject *args, PyObject *kwargs)
+{
+ PyObject *associated, *py_path;
+ const char *path;
+ bool write_lock=false;
+ int depth=0;
+ svn_wc_adm_access_t *parent_wc;
+ svn_error_t *err;
+ AdmObject *ret;
+ char *kwnames[] = { "associated", "path", "write_lock", "depth", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bi", kwnames,
+ &associated, &py_path, &write_lock, &depth))
+ return NULL;
+
+ ret = PyObject_New(AdmObject, &Adm_Type);
+ if (ret == NULL)
+ return NULL;
+
+ ret->pool = Pool(NULL);
+ if (ret->pool == NULL) {
+ return NULL;
+ }
+ if (associated == Py_None) {
+ parent_wc = NULL;
+ } else {
+ parent_wc = ((AdmObject *)associated)->adm;
+ }
+
+ path = py_object_to_svn_abspath(py_path, ret->pool);
+ if (path == NULL) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ err = svn_wc_adm_open3(&ret->adm, parent_wc,
+ path,
+ write_lock, depth, py_cancel_check, NULL,
+ ret->pool);
+ Py_END_ALLOW_THREADS
+
+ if (err != NULL) {
+ handle_svn_error(err);
+ svn_error_clear(err);
+ Py_DECREF(ret);
+ return NULL;
+ }
+
+ return (PyObject *)ret;
+}
+
+static PyObject *adm_access_path(PyObject *self)
+{
+ AdmObject *admobj = (AdmObject *)self;
+ ADM_CHECK_CLOSED(admobj);
+ return py_object_from_svn_abspath(svn_wc_adm_access_path(admobj->adm));
+}
+
+static PyObject *adm_locked(PyObject *self)
+{
+ AdmObject *admobj = (AdmObject *)self;
+ ADM_CHECK_CLOSED(admobj);
+ return PyBool_FromLong(svn_wc_adm_locked(admobj->adm));
+}
+
+static PyObject *adm_prop_get(PyObject *self, PyObject *args)
+{
+ char *name;
+ const char *path;
+ AdmObject *admobj = (AdmObject *)self;
+ const svn_string_t *value;
+ apr_pool_t *temp_pool;
+ PyObject *ret, *py_path;
+
+ if (!PyArg_ParseTuple(args, "sO", &name, &py_path))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_get(&value, name, path, admobj->adm, temp_pool));
+ if (value == NULL || value->data == NULL) {
+ ret = Py_None;
+ Py_INCREF(ret);
+ } else {
+ ret = PyBytes_FromStringAndSize(value->data, value->len);
+ }
+ apr_pool_destroy(temp_pool);
+ return ret;
+}
+
+static PyObject *adm_prop_set(PyObject *self, PyObject *args)
+{
+ char *name, *value;
+ const char *path;
+ AdmObject *admobj = (AdmObject *)self;
+ bool skip_checks=false;
+ apr_pool_t *temp_pool;
+ int vallen;
+ svn_string_t *cvalue;
+ PyObject *py_path;
+ PyObject *notify_func = Py_None;
+
+ if (!PyArg_ParseTuple(args, "sz#O|bO", &name, &value, &vallen, &py_path, &skip_checks,
+ &notify_func))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ if (value == NULL) {
+ cvalue = NULL;
+ } else {
+ cvalue = svn_string_ncreate(value, vallen, temp_pool);
+ }
+#if ONLY_SINCE_SVN(1, 6)
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_set3(name, cvalue, path, admobj->adm,
+ skip_checks, py_wc_notify_func, (void *)notify_func,
+ temp_pool));
+#else
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_set2(name, cvalue, path, admobj->adm,
+ skip_checks, temp_pool));
+#endif
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *adm_entries_read(PyObject *self, PyObject *args)
+{
+ apr_hash_t *entries;
+ AdmObject *admobj = (AdmObject *)self;
+ apr_pool_t *temp_pool;
+ bool show_hidden=false;
+ apr_hash_index_t *idx;
+ const char *key;
+ apr_ssize_t klen;
+ svn_wc_entry_t *entry;
+ PyObject *py_entries, *obj;
+
+ if (!PyArg_ParseTuple(args, "|b", &show_hidden))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL)
+ return NULL;
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_entries_read(&entries, admobj->adm,
+ show_hidden, temp_pool));
+ py_entries = PyDict_New();
+ if (py_entries == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ idx = apr_hash_first(temp_pool, entries);
+ while (idx != NULL) {
+ apr_hash_this(idx, (const void **)&key, &klen, (void **)&entry);
+ if (entry == NULL) {
+ obj = Py_None;
+ Py_INCREF(obj);
+ } else {
+ obj = py_entry(entry);
+ }
+ PyDict_SetItemString(py_entries, key, obj);
+ Py_DECREF(obj);
+ idx = apr_hash_next(idx);
+ }
+ apr_pool_destroy(temp_pool);
+ return py_entries;
+}
+
+static PyObject *adm_walk_entries(PyObject *self, PyObject *args)
+{
+ const char *path;
+ PyObject *callbacks;
+ bool show_hidden=false;
+ apr_pool_t *temp_pool;
+ AdmObject *admobj = (AdmObject *)self;
+ svn_depth_t depth = svn_depth_infinity;
+ PyObject *py_path;
+
+ if (!PyArg_ParseTuple(args, "OO|bi", &py_path, &callbacks, &show_hidden, &depth))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+#if ONLY_SINCE_SVN(1, 5)
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_walk_entries3(
+ path, admobj->adm,
+ &py_wc_entry_callbacks2, (void *)callbacks,
+ depth, show_hidden, py_cancel_check, NULL,
+ temp_pool));
+#else
+ if (depth != svn_depth_infinity) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "depth != infinity not supported for svn < 1.5");
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_walk_entries2(
+ path, admobj->adm,
+ &py_wc_entry_callbacks, (void *)callbacks,
+ show_hidden, py_cancel_check, NULL,
+ temp_pool));
+#endif
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *adm_entry(PyObject *self, PyObject *args)
+{
+ const char *path;
+ PyObject *py_path;
+ bool show_hidden=false;
+ apr_pool_t *temp_pool;
+ AdmObject *admobj = (AdmObject *)self;
+ const svn_wc_entry_t *entry;
+ PyObject *ret;
+
+ if (!PyArg_ParseTuple(args, "O|b", &py_path, &show_hidden))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_entry(&entry, path, admobj->adm, show_hidden, temp_pool));
+
+ if (entry == NULL) {
+ PyErr_Format(PyExc_KeyError, "No such entry '%s'", path);
+ ret = NULL;
+ } else {
+ ret = py_entry(entry);
+ }
+
+ apr_pool_destroy(temp_pool);
+ return ret;
+}
+
+static PyObject *adm_get_prop_diffs(PyObject *self, PyObject *args)
+{
+ const char *path;
+ apr_pool_t *temp_pool;
+ apr_array_header_t *propchanges;
+ apr_hash_t *original_props;
+ PyObject *py_path;
+ AdmObject *admobj = (AdmObject *)self;
+ PyObject *py_propchanges, *py_orig_props;
+
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_prop_diffs(&propchanges, &original_props,
+ path, admobj->adm, temp_pool));
+ py_propchanges = propchanges_to_list(propchanges);
+ if (py_propchanges == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ py_orig_props = prop_hash_to_dict(original_props);
+ apr_pool_destroy(temp_pool);
+ if (py_orig_props == NULL) {
+ Py_DECREF(py_propchanges);
+ return NULL;
+ }
+ return Py_BuildValue("(NN)", py_propchanges, py_orig_props);
+}
+
+static PyObject *adm_add(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ const char *path;
+ const char *copyfrom_url = NULL;
+ svn_revnum_t copyfrom_rev=-1;
+ char *kwnames[] = { "path", "copyfrom_url", "copyfrom_rev", "notify_func", "depth", NULL };
+ PyObject *notify_func=Py_None, *py_path;
+ AdmObject *admobj = (AdmObject *)self;
+ apr_pool_t *temp_pool;
+ svn_depth_t depth = svn_depth_infinity;
+ PyObject *py_copyfrom_url = Py_None;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OlOi", kwnames, &py_path,
+ &py_copyfrom_url, &copyfrom_rev, &notify_func, &depth))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ if (py_copyfrom_url != Py_None) {
+ copyfrom_url = py_object_to_svn_uri(py_copyfrom_url, temp_pool);
+ if (copyfrom_url == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ } else {
+ copyfrom_url = NULL;
+ }
+
+#if ONLY_SINCE_SVN(1, 6)
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_add3(
+ path, admobj->adm,
+ depth, copyfrom_url,
+ copyfrom_rev, py_cancel_check, NULL,
+ py_wc_notify_func,
+ (void *)notify_func,
+ temp_pool));
+#else
+ if (depth != svn_depth_infinity) {
+ PyErr_SetString(PyExc_NotImplementedError, "depth != infinity not supported on svn < 1.6");
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_add2(
+ path, admobj->adm, copyfrom_url,
+ copyfrom_rev, py_cancel_check,
+ NULL,
+ py_wc_notify_func,
+ (void *)notify_func,
+ temp_pool));
+#endif
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *adm_copy(PyObject *self, PyObject *args)
+{
+ AdmObject *admobj = (AdmObject *)self;
+ char *src, *dst;
+ PyObject *notify_func=Py_None;
+ apr_pool_t *temp_pool;
+
+ if (!PyArg_ParseTuple(args, "ss|O", &src, &dst, &notify_func))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL)
+ return NULL;
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_copy2(src, admobj->adm, dst,
+ py_cancel_check, NULL,
+ py_wc_notify_func, (void *)notify_func,
+ temp_pool));
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *adm_delete(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ AdmObject *admobj = (AdmObject *)self;
+ apr_pool_t *temp_pool;
+ char *kwnames[] = { "path", "notify_func", "keep_local",
+ NULL };
+ const char *path;
+ PyObject *py_path;
+ PyObject *notify_func=Py_None;
+ bool keep_local = false;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Ob:delete", kwnames,
+ &py_path, &notify_func, &keep_local))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+#if ONLY_SINCE_SVN(1, 5)
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_delete3(path, admobj->adm,
+ py_cancel_check, NULL,
+ py_wc_notify_func, (void *)notify_func,
+ keep_local,
+ temp_pool));
+#else
+ if (keep_local) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "keep_local not supported on Subversion < 1.5");
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_delete2(path, admobj->adm,
+ py_cancel_check, NULL,
+ py_wc_notify_func, (void *)notify_func,
+ temp_pool));
+#endif
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *adm_crawl_revisions(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ const char *path;
+ PyObject *reporter;
+ bool restore_files=true, recurse=true, use_commit_times=true;
+ PyObject *notify_func=Py_None;
+ apr_pool_t *temp_pool;
+ AdmObject *admobj = (AdmObject *)self;
+ svn_wc_traversal_info_t *traversal_info;
+ bool depth_compatibility_trick = false;
+ bool honor_depth_exclude = false;
+ char *kwnames[] = { "path", "reporter", "restore_files", "recurse",
+ "use_commit_times", "notify_func", "depth_compatibility_trick",
+ "honor_depth_exclude,", NULL };
+ PyObject *py_path;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bbbObb", kwnames, &py_path,
+ &reporter, &restore_files, &recurse, &use_commit_times,
+ &notify_func, &depth_compatibility_trick, &honor_depth_exclude))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ traversal_info = svn_wc_init_traversal_info(temp_pool);
+#if ONLY_SINCE_SVN(1, 6)
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions4(path, admobj->adm,
+ &py_ra_reporter3, (void *)reporter,
+ restore_files, recurse?svn_depth_infinity:svn_depth_files,
+ honor_depth_exclude?TRUE:FALSE,
+ depth_compatibility_trick?TRUE:FALSE, use_commit_times,
+ py_wc_notify_func, (void *)notify_func,
+ traversal_info, temp_pool));
+#elif ONLY_SINCE_SVN(1, 5)
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions3(path, admobj->adm,
+ &py_ra_reporter3, (void *)reporter,
+ restore_files, recurse?svn_depth_infinity:svn_depth_files,
+ depth_compatibility_trick, use_commit_times,
+ py_wc_notify_func, (void *)notify_func,
+ traversal_info, temp_pool));
+#else
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions2(path, admobj->adm,
+ &py_ra_reporter2, (void *)reporter,
+ restore_files, recurse, use_commit_times,
+ py_wc_notify_func, (void *)notify_func,
+ traversal_info, temp_pool));
+#endif
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static void wc_done_handler(void *self)
+{
+ AdmObject *admobj = (AdmObject *)self;
+
+ Py_DECREF(admobj);
+}
+
+static PyObject *adm_get_switch_editor(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ char *target;
+ bool use_commit_times=true;
+ PyObject * notify_func=Py_None;
+ char *diff3_cmd=NULL;
+ const svn_delta_editor_t *editor;
+ AdmObject *admobj = (AdmObject *)self;
+ void *edit_baton;
+ apr_pool_t *pool;
+ svn_revnum_t *latest_revnum;
+ svn_error_t *err;
+ bool allow_unver_obstructions = false;
+ bool depth_is_sticky = false;
+ int depth = svn_depth_infinity;
+ const char *switch_url;
+ PyObject *py_target, *py_switch_url;
+ char *kwnames[] = {
+ "target", "switch_url", "use_commit_times", "depth", "notify_func",
+ "diff3_cmd", "depth_is_sticky", "allow_unver_obstructions", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|biOzbb", kwnames,
+ &py_target, &py_switch_url, &use_commit_times,
+ &depth, &notify_func, &diff3_cmd,
+ &depth_is_sticky,
+ &allow_unver_obstructions))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ pool = Pool(NULL);
+ if (pool == NULL)
+ return NULL;
+
+ target = py_object_to_svn_string(py_target, pool);
+ if (target == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ switch_url = py_object_to_svn_uri(py_switch_url, pool);
+ if (switch_url == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ latest_revnum = (svn_revnum_t *)apr_palloc(pool, sizeof(svn_revnum_t));
+ Py_BEGIN_ALLOW_THREADS
+#if ONLY_SINCE_SVN(1, 5)
+ /* FIXME: Support fetch_func */
+ /* FIXME: Support conflict func */
+ err = svn_wc_get_switch_editor3(latest_revnum, admobj->adm, target, switch_url,
+ use_commit_times, depth,
+ depth_is_sticky?TRUE:FALSE, allow_unver_obstructions?TRUE:FALSE,
+ py_wc_notify_func, (void *)notify_func,
+ py_cancel_check, NULL,
+ NULL, NULL, diff3_cmd, NULL, &editor,
+ &edit_baton, NULL, pool);
+#else
+ if (allow_unver_obstructions) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "allow_unver_obstructions is not supported in svn < 1.5");
+ apr_pool_destroy(pool);
+ PyEval_RestoreThread(_save);
+ return NULL;
+ }
+ if (depth_is_sticky) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "depth_is_sticky is not supported in svn < 1.5");
+ apr_pool_destroy(pool);
+ PyEval_RestoreThread(_save);
+ return NULL;
+ }
+ err = svn_wc_get_switch_editor2(latest_revnum, admobj->adm, target, switch_url,
+ use_commit_times, recurse, py_wc_notify_func, (void *)notify_func,
+ py_cancel_check, NULL, diff3_cmd, &editor, &edit_baton,
+ NULL, pool);
+#endif
+ Py_END_ALLOW_THREADS
+ if (err != NULL) {
+ handle_svn_error(err);
+ svn_error_clear(err);
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+ Py_INCREF(admobj);
+ return new_editor_object(NULL, editor, edit_baton, pool, &Editor_Type,
+ wc_done_handler, admobj, NULL);
+}
+
+static PyObject *adm_get_update_editor(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ char *target;
+ bool use_commit_times=true;
+ PyObject * notify_func=Py_None;
+ char *diff3_cmd=NULL;
+ const svn_delta_editor_t *editor;
+ AdmObject *admobj = (AdmObject *)self;
+ void *edit_baton;
+ apr_pool_t *pool;
+ svn_revnum_t *latest_revnum;
+ svn_error_t *err;
+ bool allow_unver_obstructions = false;
+ bool depth_is_sticky = false;
+ int depth = svn_depth_infinity;
+ PyObject *py_target;
+ char *kwnames[] = {
+ "target", "use_commit_times", "depth", "notify_func",
+ "diff3_cmd", "depth_is_sticky", "allow_unver_obstructions", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|biOzbb", kwnames,
+ &py_target, &use_commit_times,
+ &depth, &notify_func, &diff3_cmd,
+ &depth_is_sticky,
+ &allow_unver_obstructions))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ pool = Pool(NULL);
+ if (pool == NULL)
+ return NULL;
+
+ target = py_object_to_svn_string(py_target, pool);
+ if (target == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+ latest_revnum = (svn_revnum_t *)apr_palloc(pool, sizeof(svn_revnum_t));
+ Py_BEGIN_ALLOW_THREADS
+#if ONLY_SINCE_SVN(1, 5)
+ /* FIXME: Support fetch_func */
+ /* FIXME: Support conflict func */
+ err = svn_wc_get_update_editor3(latest_revnum, admobj->adm, target,
+ use_commit_times, depth,
+ depth_is_sticky?TRUE:FALSE, allow_unver_obstructions?TRUE:FALSE,
+ py_wc_notify_func, (void *)notify_func,
+ py_cancel_check, NULL,
+ NULL, NULL, NULL, NULL,
+ diff3_cmd, NULL, &editor, &edit_baton,
+ NULL, pool);
+#else
+ if (allow_unver_obstructions) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "allow_unver_obstructions is not supported in svn < 1.5");
+ apr_pool_destroy(pool);
+ PyEval_RestoreThread(_save);
+ return NULL;
+ }
+ if (depth_is_sticky) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "depth_is_sticky is not supported in svn < 1.5");
+ apr_pool_destroy(pool);
+ PyEval_RestoreThread(_save);
+ return NULL;
+ }
+ err = svn_wc_get_update_editor2(latest_revnum, admobj->adm, target,
+ use_commit_times, recurse, py_wc_notify_func, (void *)notify_func,
+ py_cancel_check, NULL, diff3_cmd, &editor, &edit_baton,
+ NULL, pool);
+#endif
+ Py_END_ALLOW_THREADS
+ if (err != NULL) {
+ handle_svn_error(err);
+ svn_error_clear(err);
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+ Py_INCREF(admobj);
+ return new_editor_object(NULL, editor, edit_baton, pool, &Editor_Type,
+ wc_done_handler, admobj, NULL);
+}
+
+static PyObject *adm_has_binary_prop(PyObject *self, PyObject *args)
+{
+ const char *path;
+ svn_boolean_t binary;
+ AdmObject *admobj = (AdmObject *)self;
+ apr_pool_t *temp_pool;
+ PyObject *py_path;
+
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_has_binary_prop(&binary, path, admobj->adm, temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ return PyBool_FromLong(binary);
+}
+
+static PyObject *adm_process_committed(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ const char *path;
+ char *rev_date = NULL, *rev_author = NULL;
+ bool recurse, remove_lock = false;
+ unsigned char *digest = NULL;
+ svn_revnum_t new_revnum;
+ PyObject *py_wcprop_changes = Py_None, *py_path;
+ apr_array_header_t *wcprop_changes = NULL;
+ AdmObject *admobj = (AdmObject *)self;
+ apr_pool_t *temp_pool;
+ int digest_len;
+ bool remove_changelist = false;
+ char *kwnames[] = { "path", "recurse", "new_revnum", "rev_date", "rev_author",
+ "wcprop_changes", "remove_lock", "digest", "remove_changelist", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oblzz|Obz#b", kwnames,
+ &py_path, &recurse, &new_revnum, &rev_date,
+ &rev_author, &py_wcprop_changes,
+ &remove_lock, &digest, &digest_len, &remove_changelist))
+ return NULL;
+
+ PyErr_WarnEx(PyExc_DeprecationWarning, "process_committed is deprecated. Use process_committed_queue instead.", 2);
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ if (!py_dict_to_wcprop_changes(py_wcprop_changes, temp_pool, &wcprop_changes)) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+#if ONLY_SINCE_SVN(1, 6)
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed4(
+ path, admobj->adm, recurse, new_revnum,
+ rev_date, rev_author, wcprop_changes,
+ remove_lock, remove_changelist?TRUE:FALSE, digest, temp_pool));
+#else
+ if (remove_changelist) {
+ PyErr_SetString(PyExc_NotImplementedError, "remove_changelist only supported in svn < 1.6");
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(path, admobj->adm, recurse, new_revnum,
+ rev_date, rev_author, wcprop_changes,
+ remove_lock, digest, temp_pool));
+#endif
+
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *adm_close(PyObject *self)
+{
+ AdmObject *admobj = (AdmObject *)self;
+ if (admobj->adm != NULL) {
+#if ONLY_SINCE_SVN(1, 6)
+ apr_pool_t *temp_pool = Pool(NULL);
+ Py_BEGIN_ALLOW_THREADS
+ svn_wc_adm_close2(admobj->adm, temp_pool);
+ apr_pool_destroy(temp_pool);
+#else
+ Py_BEGIN_ALLOW_THREADS
+ svn_wc_adm_close(admobj->adm);
+#endif
+ Py_END_ALLOW_THREADS
+ admobj->adm = NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static void adm_dealloc(PyObject *self)
+{
+ apr_pool_destroy(((AdmObject *)self)->pool);
+ PyObject_Del(self);
+}
+
+static PyObject *adm_repr(PyObject *self)
+{
+ AdmObject *admobj = (AdmObject *)self;
+
+ if (admobj->adm == NULL) {
+ return PyRepr_FromFormat("<wc.WorkingCopy (closed) at 0x%p>", admobj);
+ } else {
+ return PyRepr_FromFormat("<wc.WorkingCopy at '%s'>",
+ svn_wc_adm_access_path(admobj->adm));
+ }
+}
+
+static PyObject *adm_remove_lock(PyObject *self, PyObject *args)
+{
+ const char *path;
+ PyObject *py_path;
+ AdmObject *admobj = (AdmObject *)self;
+ apr_pool_t *temp_pool;
+
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_remove_lock(path, admobj->adm, temp_pool))
+
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *get_ancestry(PyObject *self, PyObject *args)
+{
+ const char *path;
+ char *url;
+ svn_revnum_t rev;
+ apr_pool_t *temp_pool;
+ PyObject *py_path;
+ AdmObject *admobj = (AdmObject *)self;
+
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_ancestry(&url, &rev, path, admobj->adm, temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ return Py_BuildValue("(si)", url, rev);
+}
+
+static PyObject *maybe_set_repos_root(PyObject *self, PyObject *args)
+{
+ char *path, *repos;
+ apr_pool_t *temp_pool;
+ AdmObject *admobj = (AdmObject *)self;
+
+ if (!PyArg_ParseTuple(args, "ss", &path, &repos))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL)
+ return NULL;
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_maybe_set_repos_root(admobj->adm, path, repos, temp_pool));
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *add_repos_file(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ char *kwnames[] = { "dst_path", "new_base_contents", "new_contents",
+ "new_base_props", "new_props", "copyfrom_url", "copyfrom_rev",
+ "notify", NULL };
+ AdmObject *admobj = (AdmObject *)self;
+ PyObject *py_dst_path;
+ char *copyfrom_url = NULL;
+ svn_revnum_t copyfrom_rev = -1;
+ PyObject *py_new_base_contents, *py_new_contents, *py_new_base_props,
+ *py_new_props, *notify = Py_None;
+#if ONLY_SINCE_SVN(1, 6)
+ apr_pool_t *temp_pool;
+ const char *dst_path;
+ svn_stream_t *new_contents, *new_base_contents;
+ apr_hash_t *new_props, *new_base_props;
+#endif
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOOOO|zlO", kwnames,
+ &py_dst_path, &py_new_base_contents, &py_new_contents, &py_new_base_props,
+ &py_new_props, &copyfrom_url, &copyfrom_rev, &notify))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+#if ONLY_SINCE_SVN(1, 6)
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL)
+ return NULL;
+
+ new_base_props = prop_dict_to_hash(temp_pool, py_new_base_props);
+
+ new_props = prop_dict_to_hash(temp_pool, py_new_props);
+
+ new_base_contents = new_py_stream(temp_pool, py_new_base_contents);
+
+ new_contents = new_py_stream(temp_pool, py_new_contents);
+
+ dst_path = py_object_to_svn_abspath(py_dst_path, temp_pool);
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_add_repos_file3(dst_path, admobj->adm,
+ new_base_contents,
+ new_contents,
+ new_base_props,
+ new_props,
+ copyfrom_url, copyfrom_rev,
+ py_cancel_check, NULL,
+ py_wc_notify_func, notify, temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+
+#else
+ PyErr_SetString(PyExc_NotImplementedError,
+ "add_repos_file3 not supported on svn < 1.6");
+ return NULL;
+#endif
+}
+
+static PyObject *mark_missing_deleted(PyObject *self, PyObject *args)
+{
+ const char *path;
+ AdmObject *admobj = (AdmObject *)self;
+ apr_pool_t *temp_pool;
+ PyObject *py_path;
+
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_mark_missing_deleted(path, admobj->adm, temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *remove_from_revision_control(PyObject *self, PyObject *args)
+{
+ char *name;
+ bool destroy_wf = false, instant_error = false;
+ AdmObject *admobj = (AdmObject *)self;
+ apr_pool_t *temp_pool;
+
+ if (!PyArg_ParseTuple(args, "s|bb", &name, &destroy_wf, &instant_error))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL)
+ return NULL;
+
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_remove_from_revision_control(admobj->adm, name,
+ destroy_wf?TRUE:FALSE, instant_error?TRUE:FALSE, py_cancel_check, NULL, temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *relocate(PyObject *self, PyObject *args)
+{
+ const char *path;
+ char *from, *to;
+ AdmObject *admobj = (AdmObject *)self;
+ apr_pool_t *temp_pool;
+ bool recurse = true;
+ PyObject *py_validator = Py_None, *py_path;
+
+ if (!PyArg_ParseTuple(args, "Oss|bO:relocate", &py_path, &from, &to, &recurse,
+ &py_validator))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+#if ONLY_SINCE_SVN(1, 6)
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate3(path, admobj->adm, from, to, recurse?TRUE:FALSE, wc_validator3, py_validator, temp_pool));
+#else
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate2(path, admobj->adm, from, to, recurse?TRUE:FALSE, wc_validator2, py_validator, temp_pool));
+#endif
+
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *crop_tree(PyObject *self, PyObject *args)
+{
+ char *target;
+ svn_depth_t depth;
+ PyObject *notify;
+#if ONLY_SINCE_SVN(1, 6)
+ apr_pool_t *temp_pool;
+#endif
+ AdmObject *admobj = (AdmObject *)self;
+
+ if (!PyArg_ParseTuple(args, "si|O", &target, &depth, &notify))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+#if ONLY_SINCE_SVN(1, 6)
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL)
+ return NULL;
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_crop_tree(admobj->adm,
+ target, depth, py_wc_notify_func, notify,
+ py_cancel_check, NULL, temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+#else
+ PyErr_SetString(PyExc_NotImplementedError,
+ "crop_tree only available on subversion < 1.6");
+ return NULL;
+#endif
+}
+
+static PyObject *translated_stream(PyObject *self, PyObject *args)
+{
+ const char *path, *versioned_file;
+ StreamObject *ret;
+ svn_stream_t *stream;
+ AdmObject *admobj = (AdmObject *)self;
+ apr_pool_t *stream_pool;
+ PyObject *py_path, *py_versioned_file;
+ int flags;
+
+ if (!PyArg_ParseTuple(args, "OOi", &py_path, &py_versioned_file, &flags))
+ return NULL;
+
+#if ONLY_SINCE_SVN(1, 5)
+ ADM_CHECK_CLOSED(admobj);
+
+ stream_pool = Pool(NULL);
+ if (stream_pool == NULL)
+ return NULL;
+
+ path = py_object_to_svn_abspath(py_path, stream_pool);
+ if (path == NULL) {
+ apr_pool_destroy(stream_pool);
+ return NULL;
+ }
+
+ versioned_file = py_object_to_svn_abspath(py_versioned_file, stream_pool);
+ if (versioned_file == NULL) {
+ apr_pool_destroy(stream_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(stream_pool,
+ svn_wc_translated_stream(&stream, path, versioned_file, admobj->adm,
+ flags, stream_pool));
+
+ ret = PyObject_New(StreamObject, &Stream_Type);
+ if (ret == NULL)
+ return NULL;
+
+ ret->pool = stream_pool;
+ ret->closed = FALSE;
+ ret->stream = stream;
+
+ return (PyObject *)ret;
+#else
+ PyErr_SetString(PyExc_NotImplementedError,
+ "translated_stream() is only available on Subversion >= 1.5");
+ return NULL;
+#endif
+}
+
+static PyObject *adm_text_modified(PyObject *self, PyObject *args)
+{
+ const char *path;
+ bool force_comparison = false;
+ apr_pool_t *temp_pool;
+ svn_boolean_t ret;
+ AdmObject *admobj = (AdmObject *)self;
+ PyObject *py_path;
+
+ if (!PyArg_ParseTuple(args, "O|b", &py_path, &force_comparison))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_text_modified_p(&ret, path, force_comparison?TRUE:FALSE, admobj->adm,
+ temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ return PyBool_FromLong(ret);
+}
+
+static PyObject *adm_props_modified(PyObject *self, PyObject *args)
+{
+ const char *path;
+ apr_pool_t *temp_pool;
+ svn_boolean_t ret;
+ AdmObject *admobj = (AdmObject *)self;
+ PyObject *py_path;
+
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_props_modified_p(&ret, path, admobj->adm, temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ return PyBool_FromLong(ret);
+}
+
+static PyObject *adm_process_committed_queue(PyObject *self, PyObject *args)
+{
+ apr_pool_t *temp_pool;
+ AdmObject *admobj = (AdmObject *)self;
+ svn_revnum_t revnum;
+ char *date, *author;
+ PyObject *py_queue;
+
+ if (!PyArg_ParseTuple(args, "O!lss", &CommittedQueue_Type, &py_queue,
+ &revnum, &date, &author))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL)
+ return NULL;
+
+ svn_wc_committed_queue_t *committed_queue = PyObject_GetCommittedQueue(py_queue);
+
+#if ONLY_SINCE_SVN(1, 5)
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed_queue(committed_queue, admobj->adm, revnum, date, author, temp_pool));
+#else
+ {
+ int i;
+ for (i = 0; i < py_queue->queue->queue->nelts; i++) {
+ committed_queue_item_t *cqi = APR_ARRAY_IDX(committed_queue->queue, i,
+ committed_queue_item_t *);
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(cqi->path, admobj->adm,
+ cqi->recurse, revnum, date, author, cqi->wcprop_changes,
+ cqi->remove_lock, cqi->digest, temp_pool));
+ }
+ }
+#endif
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *is_wc_root(PyObject *self, PyObject *args)
+{
+ const char *path;
+ svn_boolean_t wc_root;
+ apr_pool_t *temp_pool;
+ AdmObject *admobj = (AdmObject *)self;
+ PyObject *py_path;
+
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_is_wc_root(&wc_root, path, admobj->adm, temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ return PyBool_FromLong(wc_root);
+}
+
+static PyObject *transmit_text_deltas(PyObject *self, PyObject *args)
+{
+ const char *path;
+ const char *tempfile;
+ bool fulltext;
+ PyObject *editor_obj, *py_digest, *py_path;
+ unsigned char digest[APR_MD5_DIGESTSIZE];
+ apr_pool_t *temp_pool;
+ AdmObject *admobj = (AdmObject *)self;
+ PyObject *ret;
+
+ if (!PyArg_ParseTuple(args, "ObO", &py_path, &fulltext, &editor_obj))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ Py_INCREF(editor_obj);
+
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_transmit_text_deltas2(&tempfile, digest,
+ path, admobj->adm, fulltext?TRUE:FALSE,
+ &py_editor, editor_obj, temp_pool));
+
+ py_digest = PyBytes_FromStringAndSize((char *)digest, APR_MD5_DIGESTSIZE);
+ if (py_digest == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ ret = Py_BuildValue("sN", tempfile, py_digest);
+ if (ret == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ apr_pool_destroy(temp_pool);
+
+ return ret;
+}
+
+static PyObject *transmit_prop_deltas(PyObject *self, PyObject *args)
+{
+ const char *path;
+ PyObject *editor_obj;
+ apr_pool_t *temp_pool;
+ AdmObject *admobj = (AdmObject *)self;
+ PyObject *py_path;
+ EntryObject *py_entry;
+
+ if (!PyArg_ParseTuple(args, "OO!O", &py_path, &Entry_Type, &py_entry, &editor_obj))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ Py_INCREF(editor_obj);
+
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_transmit_prop_deltas(path,
+ admobj->adm, &(py_entry->entry), &py_editor, editor_obj, NULL, temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *retrieve(PyObject *self, PyObject *args)
+{
+ const char *path;
+ svn_wc_adm_access_t *result;
+ PyObject *py_path;
+ AdmObject *admobj = (AdmObject *)self, *ret;
+ apr_pool_t *pool;
+
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ pool = Pool(NULL);
+ if (pool == NULL)
+ return NULL;
+
+ path = py_object_to_svn_abspath(py_path, pool);
+ if (path == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(pool, svn_wc_adm_retrieve(&result, admobj->adm,
+ path, pool));
+
+ ret = PyObject_New(AdmObject, &Adm_Type);
+ if (ret == NULL)
+ return NULL;
+
+ ret->pool = pool;
+ ret->adm = result;
+
+ return (PyObject *)ret;
+}
+
+static PyObject *probe_retrieve(PyObject *self, PyObject *args)
+{
+ const char *path;
+ svn_wc_adm_access_t *result;
+ AdmObject *admobj = (AdmObject *)self, *ret;
+ apr_pool_t *pool;
+ PyObject *py_path;
+
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ pool = Pool(NULL);
+ if (pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, pool);
+ if (path == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_retrieve(&result, admobj->adm,
+ path, pool));
+
+ ret = PyObject_New(AdmObject, &Adm_Type);
+ if (ret == NULL)
+ return NULL;
+
+ ret->pool = pool;
+ ret->adm = result;
+
+ return (PyObject *)ret;
+}
+
+static PyObject *probe_try(PyObject *self, PyObject *args)
+{
+ const char *path;
+ svn_wc_adm_access_t *result = NULL;
+ AdmObject *admobj = (AdmObject *)self, *ret;
+ apr_pool_t *pool;
+ int levels_to_lock = -1;
+ bool writelock = false;
+ PyObject *py_path;
+
+ if (!PyArg_ParseTuple(args, "O|bi", &py_path, &writelock, &levels_to_lock))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ pool = Pool(NULL);
+ if (pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, pool);
+ if (path == NULL) {
+ apr_pool_destroy(pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_try3(&result, admobj->adm,
+ path, writelock, levels_to_lock,
+ py_cancel_check, NULL, pool));
+
+ if (result == NULL) {
+ apr_pool_destroy(pool);
+ Py_RETURN_NONE;
+ }
+
+ ret = PyObject_New(AdmObject, &Adm_Type);
+ if (ret == NULL)
+ return NULL;
+
+ ret->pool = pool;
+ ret->adm = result;
+
+ return (PyObject *)ret;
+}
+
+static PyObject *resolved_conflict(PyObject *self, PyObject *args)
+{
+ AdmObject *admobj = (AdmObject *)self;
+ apr_pool_t *temp_pool;
+ bool resolve_props, resolve_tree, resolve_text;
+ int depth;
+#if ONLY_SINCE_SVN(1, 5)
+ svn_wc_conflict_choice_t conflict_choice;
+#else
+ int conflict_choice;
+#endif
+ PyObject *notify_func = Py_None;
+ const char *path;
+ PyObject *py_path;
+
+ if (!PyArg_ParseTuple(args, "Obbbii|O", &py_path, &resolve_text,
+ &resolve_props, &resolve_tree, &depth,
+ &conflict_choice, &notify_func))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+#if ONLY_SINCE_SVN(1, 6)
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_resolved_conflict4(path, admobj->adm, resolve_text?TRUE:FALSE,
+ resolve_props?TRUE:FALSE, resolve_tree?TRUE:FALSE, depth,
+ conflict_choice, py_wc_notify_func,
+ (void *)notify_func, py_cancel_check,
+ NULL, temp_pool));
+#elif ONLY_SINCE_SVN(1, 5)
+ if (resolve_tree) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "resolve_tree not supported with svn < 1.6");
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ } else {
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_resolved_conflict3(path, admobj->adm, resolve_text?TRUE:FALSE,
+ resolve_props?TRUE:FALSE, depth,
+ conflict_choice, py_wc_notify_func,
+ (void *)notify_func, py_cancel_check,
+ NULL, temp_pool));
+ }
+#else
+ if (resolve_tree) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "resolve_tree not supported with svn < 1.6");
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ } else if (depth != svn_depth_infinity && depth != svn_depth_files) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "only infinity and files values for depth are supported");
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ } else if (conflict_choice != 0) {
+ PyErr_SetString(PyExc_NotImplementedError,
+ "conflict choice not supported with svn < 1.5");
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ } else {
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_resolved_conflict2(path, admobj->adm, resolve_text?TRUE:FALSE,
+ resolve_props?TRUE:FALSE,
+ (depth == svn_depth_infinity),
+ py_wc_notify_func,
+ (void *)notify_func, py_cancel_check,
+ NULL,
+ temp_pool));
+ }
+#endif
+
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *conflicted(PyObject *self, PyObject *args)
+{
+ const char *path;
+ apr_pool_t *temp_pool;
+ PyObject *ret;
+ AdmObject *admobj = (AdmObject *)self;
+ svn_boolean_t text_conflicted, prop_conflicted;
+ PyObject *py_path;
+#if ONLY_BEFORE_SVN(1, 6)
+ const svn_wc_entry_t *entry;
+#else
+ svn_boolean_t tree_conflicted;
+#endif
+
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+#if ONLY_SINCE_SVN(1, 6)
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p2(&text_conflicted,
+ &prop_conflicted, &tree_conflicted, path, admobj->adm, temp_pool));
+
+ ret = Py_BuildValue("(bbb)", text_conflicted, prop_conflicted, tree_conflicted);
+#else
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_entry(&entry, path, admobj->adm, TRUE, temp_pool));
+
+ RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p(&text_conflicted,
+ &prop_conflicted, path, entry, temp_pool));
+
+ ret = Py_BuildValue("(bbO)", text_conflicted, prop_conflicted, Py_None);
+#endif
+
+ apr_pool_destroy(temp_pool);
+
+ return ret;
+}
+
+/**
+ * Determine the status of a file in the specified working copy.
+ *
+ * :return: A status object.
+ */
+static PyObject *wc_status(PyObject *self, PyObject *args)
+{
+ const char *path;
+ svn_wc_status2_t *st;
+ apr_pool_t *temp_pool;
+ PyObject *ret;
+ AdmObject *admobj = (AdmObject *)self;
+ PyObject *py_path;
+
+ if (!PyArg_ParseTuple(args, "O", &py_path))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_status2(&st, path, admobj->adm, temp_pool));
+
+ ret = py_wc_status2(st);
+
+ apr_pool_destroy(temp_pool);
+
+ return (PyObject*)ret;
+}
+
+static PyObject *wc_add_lock(PyObject *self, PyObject *args)
+{
+ const char *path;
+ apr_pool_t *temp_pool;
+ AdmObject *admobj = (AdmObject *)self;
+ svn_lock_t *lock;
+ PyObject *py_path, *py_lock;
+
+ if (!PyArg_ParseTuple(args, "OO!", &py_path, &Lock_Type, &py_lock))
+ return NULL;
+
+ ADM_CHECK_CLOSED(admobj);
+
+ temp_pool = Pool(NULL);
+ if (temp_pool == NULL) {
+ return NULL;
+ }
+
+ path = py_object_to_svn_abspath(py_path, temp_pool);
+ if (path == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ lock = py_object_to_svn_lock(py_lock, temp_pool);
+ if (lock == NULL) {
+ apr_pool_destroy(temp_pool);
+ return NULL;
+ }
+
+ RUN_SVN_WITH_POOL(temp_pool,
+ svn_wc_add_lock(path, lock, admobj->adm, temp_pool));
+
+ apr_pool_destroy(temp_pool);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *wc_enter(PyObject *self)
+{
+ Py_INCREF(self);
+ return self;
+}
+
+static PyObject *wc_exit(PyObject *self, PyObject *args)
+{
+ PyObject *exc_type, *exc_value, *exc_tb, *ret;
+
+ if (!PyArg_ParseTuple(args, "OOO", &exc_type, &exc_value, &exc_tb))
+ return NULL;
+
+ ret = adm_close(self);
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef adm_methods[] = {
+ { "prop_set", adm_prop_set, METH_VARARGS, "S.prop_set(name, value, path, skip_checks=False)" },
+ { "access_path", (PyCFunction)adm_access_path, METH_NOARGS,
+ "S.access_path() -> path\n"
+ "Returns the base path for this working copy handle." },
+ { "prop_get", adm_prop_get, METH_VARARGS, "S.prop_get(name, path) -> value" },
+ { "entries_read", adm_entries_read, METH_VARARGS, "S.entries_read(include_hidden=False) -> dict" },
+ { "walk_entries", adm_walk_entries, METH_VARARGS,
+ "S.walk_entries(path, callback, show_hidden=False)\n"
+ "callback should be a function that takes a path and a wc entry" },
+ { "locked", (PyCFunction)adm_locked, METH_NOARGS,
+ "S.locked() -> bool" },
+ { "get_prop_diffs", adm_get_prop_diffs, METH_VARARGS,
+ "S.get_prop_diffs(path) -> (propchanges, originalprops)" },
+ { "add", (PyCFunction)adm_add, METH_VARARGS|METH_KEYWORDS, "S.add(path, copyfrom_url=None, copyfrom_rev=-1, notify_func=None)" },
+ { "copy", adm_copy, METH_VARARGS, "S.copy(src_path, dest_path, notify_func=None)" },
+ { "delete", (PyCFunction)adm_delete, METH_VARARGS|METH_KEYWORDS, "S.delete(path, notify_func=None, keep_local=False)" },
+ { "crawl_revisions", (PyCFunction)adm_crawl_revisions, METH_VARARGS|METH_KEYWORDS,
+ "S.crawl_revisions(path, reporter, restore_files=True, recurse=True, use_commit_times=True, notify_func=None) -> None" },
+ { "get_update_editor", (PyCFunction)adm_get_update_editor,
+ METH_VARARGS|METH_KEYWORDS, NULL },
+ { "get_switch_editor", (PyCFunction)adm_get_switch_editor,
+ METH_VARARGS|METH_KEYWORDS, NULL },
+ { "close", (PyCFunction)adm_close, METH_NOARGS,
+ "S.close()" },
+ { "entry", (PyCFunction)adm_entry, METH_VARARGS,
+ "s.entry(path, show_hidden=False) -> entry" },
+ { "process_committed", (PyCFunction)adm_process_committed, METH_VARARGS|METH_KEYWORDS, "S.process_committed(path, recurse, new_revnum, rev_date, rev_author, wcprop_changes=None, remove_lock=False, digest=None)" },
+ { "process_committed_queue", (PyCFunction)adm_process_committed_queue, METH_VARARGS, "S.process_committed_queue(queue, new_revnum, rev_date, rev_author)" },
+ { "remove_lock", (PyCFunction)adm_remove_lock, METH_VARARGS, "S.remove_lock(path)" },
+ { "has_binary_prop", (PyCFunction)adm_has_binary_prop, METH_VARARGS, "S.has_binary_prop(path) -> bool" },
+ { "text_modified", (PyCFunction)adm_text_modified, METH_VARARGS, "S.text_modified(filename, force_comparison=False) -> bool" },
+ { "props_modified", (PyCFunction)adm_props_modified, METH_VARARGS, "S.props_modified(filename) -> bool" },
+ { "get_ancestry", (PyCFunction)get_ancestry, METH_VARARGS,
+ "S.get_ancestry(path) -> (url, rev)" },
+ { "maybe_set_repos_root", (PyCFunction)maybe_set_repos_root, METH_VARARGS, "S.maybe_set_repos_root(path, repos)" },
+ { "add_repos_file", (PyCFunction)add_repos_file, METH_KEYWORDS|METH_VARARGS,
+ "S.add_repos_file(dst_path, new_base_contents, new_contents, new_base_props, new_props, copyfrom_url=None, copyfrom_rev=-1, notify_func=None)" },
+ { "mark_missing_deleted", (PyCFunction)mark_missing_deleted, METH_VARARGS,
+ "S.mark_missing_deleted(path)" },
+ { "remove_from_revision_control", (PyCFunction)remove_from_revision_control, METH_VARARGS,
+ "S.remove_from_revision_control(name, destroy_wf=False, instant_error=False)" },
+ { "relocate", (PyCFunction)relocate, METH_VARARGS,
+ "S.relocate(path, from, to, recurse=TRUE, validator=None)" },
+ { "crop_tree", (PyCFunction)crop_tree, METH_VARARGS,
+ "S.crop_tree(target, depth, notify_func=None, cancel=None)" },
+ { "translated_stream", (PyCFunction)translated_stream, METH_VARARGS,
+ "S.translated_stream(path, versioned_file, flags) -> stream" },
+ { "is_wc_root", (PyCFunction)is_wc_root, METH_VARARGS,
+ "S.is_wc_root(path) -> wc_root" },
+ { "transmit_text_deltas", (PyCFunction)transmit_text_deltas, METH_VARARGS,
+ "S.transmit_text_deltas(fulltext, editor) -> (tempfile, digest)" },
+ { "transmit_prop_deltas", (PyCFunction)transmit_prop_deltas, METH_VARARGS,
+ "S.transmit_prop_deltas(path, entry, editor)" },
+ { "probe_retrieve", (PyCFunction)probe_retrieve, METH_VARARGS,
+ "S.probe_retrieve(path) -> WorkingCopy" },
+ { "retrieve", (PyCFunction)retrieve, METH_VARARGS,
+ "S.retrieve(path) -> WorkingCopy" },
+ { "probe_try", (PyCFunction)probe_try, METH_VARARGS,
+ "S.probe_try(path, write_lock=False, levels_to_lock=-1)" },
+ { "conflicted", (PyCFunction)conflicted, METH_VARARGS,
+ "S.conflicted(path) -> (text_conflicted, prop_conflicted, tree_conflicted)" },
+ { "resolved_conflict", (PyCFunction)resolved_conflict, METH_VARARGS,
+ "S.resolved_conflict(path, resolve_text, resolve_props, resolve_tree, depth, conflict_choice, notify_func=None, cancel=None)" },
+ { "status", (PyCFunction)wc_status, METH_VARARGS, "status(wc_path) -> Status" },
+ { "add_lock", (PyCFunction)wc_add_lock, METH_VARARGS, "add_lock(path, lock)" },
+ { "__enter__", (PyCFunction)wc_enter, METH_NOARGS, "__enter__() -> self" },
+ { "__exit__", (PyCFunction)wc_exit, METH_VARARGS, "__exit__(exc_type, exc_value, exc_tb)" },
+ { NULL, }
+};
+
+PyTypeObject Adm_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "wc.WorkingCopy", /* const char *tp_name; For printing, in format "<module>.<name>" */
+ sizeof(AdmObject),
+ 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ adm_dealloc, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ adm_repr, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ adm_repr, /* reprfunc tp_repr; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /* Flags to define presence of optional/expanded features */
+ 0, /* long tp_flags; */
+
+ "Local working copy", /* const char *tp_doc; Documentation string */
+
+ /* Assigned meaning in release 2.0 */
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /* Assigned meaning in release 2.1 */
+ /* rich comparisons */
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /* weak reference enabler */
+ 0, /* Py_ssize_t tp_weaklistoffset; */
+
+ /* Added in release 2.2 */
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /* Attribute descriptor and subclassing stuff */
+ adm_methods, /* struct PyMethodDef *tp_methods; */
+ NULL, /* struct PyMemberDef *tp_members; */
+ NULL, /* struct PyGetSetDef *tp_getset; */
+ NULL, /* struct _typeobject *tp_base; */
+ NULL, /* PyObject *tp_dict; */
+ NULL, /* descrgetfunc tp_descr_get; */
+ NULL, /* descrsetfunc tp_descr_set; */
+ 0, /* Py_ssize_t tp_dictoffset; */
+ NULL, /* initproc tp_init; */
+ NULL, /* allocfunc tp_alloc; */
+ adm_init, /* newfunc tp_new; */
+};
+
+static void entry_dealloc(PyObject *self)
+{
+ apr_pool_destroy(((EntryObject *)self)->pool);
+ PyObject_Del(self);
+}
+
+static PyMemberDef entry_members[] = {
+ { "name", T_STRING, offsetof(EntryObject, entry.name), READONLY,
+ "Name of the file"},
+ { "copyfrom_url", T_STRING, offsetof(EntryObject, entry.copyfrom_url), READONLY,
+ "Copyfrom location" },
+ { "copyfrom_rev", T_LONG, offsetof(EntryObject, entry.copyfrom_rev), READONLY,
+ "Copyfrom revision" },
+ { "uuid", T_STRING, offsetof(EntryObject, entry.uuid), READONLY,
+ "UUID of repository" },
+ { "url", T_STRING, offsetof(EntryObject, entry.url), READONLY,
+ "URL in repository" },
+ { "repos", T_STRING, offsetof(EntryObject, entry.repos), READONLY,
+ "Canonical repository URL" },
+ { "schedule", T_INT, offsetof(EntryObject, entry.schedule), READONLY,
+ "Scheduling (add, replace, delete, etc)" },
+ { "kind", T_INT, offsetof(EntryObject, entry.kind), READONLY,
+ "Kind of file (file, dir, etc)" },
+ { "revision", T_LONG, offsetof(EntryObject, entry.revision), READONLY,
+ "Base revision", },
+ { "cmt_rev", T_LONG, offsetof(EntryObject, entry.cmt_rev), READONLY,
+ "Last revision this was changed" },
+ { "checksum", T_STRING, offsetof(EntryObject, entry.checksum), READONLY,
+ "Hex MD5 checksum for the untranslated text base file" },
+ { "cmt_date", T_LONG, offsetof(EntryObject, entry.cmt_date), READONLY,
+ "Last date this was changed" },
+ { "cmt_author", T_STRING, offsetof(EntryObject, entry.cmt_author), READONLY,
+ "Last commit author of this item" },
+ { NULL, }
+};
+
+PyTypeObject Entry_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "wc.Entry", /* const char *tp_name; For printing, in format "<module>.<name>" */
+ sizeof(EntryObject),
+ 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ entry_dealloc, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /* Flags to define presence of optional/expanded features */
+ 0, /* long tp_flags; */
+
+ NULL, /* const char *tp_doc; Documentation string */
+
+ /* Assigned meaning in release 2.0 */
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /* Assigned meaning in release 2.1 */
+ /* rich comparisons */
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /* weak reference enabler */
+ 0, /* Py_ssize_t tp_weaklistoffset; */
+
+ /* Added in release 2.2 */
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /* Attribute descriptor and subclassing stuff */
+ NULL, /* struct PyMethodDef *tp_methods; */
+ entry_members, /* struct PyMemberDef *tp_members; */
+
+};
+
+static PyObject *py_entry(const svn_wc_entry_t *entry)
+{
+ EntryObject *ret;
+
+ if (entry == NULL) {
+ Py_RETURN_NONE;
+ }
+
+ ret = PyObject_New(EntryObject, &Entry_Type);
+ if (ret == NULL)
+ return NULL;
+
+ ret->pool = Pool(NULL);
+ if (ret->pool == NULL)
+ return NULL;
+ ret->entry = *svn_wc_entry_dup(entry, ret->pool);
+ return (PyObject *)ret;
+}
+
+typedef struct {
+ PyObject_VAR_HEAD
+ apr_pool_t *pool;
+ svn_wc_status2_t status;
+ PyObject *entry;
+} Status2Object;
+
+static void status_dealloc(PyObject *self)
+{
+ apr_pool_destroy(((Status2Object *)self)->pool);
+ Py_XDECREF(((Status2Object *)self)->entry);
+ PyObject_Del(self);
+}
+
+static PyMemberDef status_members[] = {
+ { "entry", T_OBJECT, offsetof(Status2Object, entry), READONLY,
+ "Can be NULL if not under version control." },
+ { "locked", T_BOOL, offsetof(Status2Object, status.locked), READONLY,
+ "a directory can be 'locked' if a working copy update was interrupted." },
+ { "copied", T_BOOL, offsetof(Status2Object, status.copied), READONLY,
+ "a file or directory can be 'copied' if it's scheduled for addition-with-history (or part of a subtree that is scheduled as such.)." },
+ { "switched", T_BOOL, offsetof(Status2Object, status.switched), READONLY,
+ "a file or directory can be 'switched' if the switch command has been used." },
+ { "url", T_STRING, offsetof(Status2Object, status.url), READONLY,
+ "URL (actual or expected) in repository" },
+ { "revision", T_LONG, offsetof(Status2Object, status.ood_last_cmt_rev), READONLY,
+ "Set to the youngest committed revision, or SVN_INVALID_REVNUM if not out of date.", },
+ { "kind", T_INT, offsetof(Status2Object, status.ood_kind), READONLY,
+ "Set to the node kind of the youngest commit, or svn_node_none if not out of date.", },
+ { "status", T_INT, offsetof(Status2Object, status.text_status), READONLY,
+ "The status of the entry.", },
+ { NULL, }
+};
+
+PyTypeObject Status2_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "wc.Status", /* const char *tp_name; For printing, in format "<module>.<name>" */
+ sizeof(Status2Object),
+ 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
+
+ /* Methods to implement standard operations */
+
+ status_dealloc, /* destructor tp_dealloc; */
+ NULL, /* printfunc tp_print; */
+ NULL, /* getattrfunc tp_getattr; */
+ NULL, /* setattrfunc tp_setattr; */
+ NULL, /* cmpfunc tp_compare; */
+ NULL, /* reprfunc tp_repr; */
+
+ /* Method suites for standard classes */
+
+ NULL, /* PyNumberMethods *tp_as_number; */
+ NULL, /* PySequenceMethods *tp_as_sequence; */
+ NULL, /* PyMappingMethods *tp_as_mapping; */
+
+ /* More standard operations (here for binary compatibility) */
+
+ NULL, /* hashfunc tp_hash; */
+ NULL, /* ternaryfunc tp_call; */
+ NULL, /* reprfunc tp_str; */
+ NULL, /* getattrofunc tp_getattro; */
+ NULL, /* setattrofunc tp_setattro; */
+
+ /* Functions to access object as input/output buffer */
+ NULL, /* PyBufferProcs *tp_as_buffer; */
+
+ /* Flags to define presence of optional/expanded features */
+ 0, /* long tp_flags; */
+
+ "Working copy status object", /* const char *tp_doc; Documentation string */
+
+ /* Assigned meaning in release 2.0 */
+ /* call function for all accessible objects */
+ NULL, /* traverseproc tp_traverse; */
+
+ /* delete references to contained objects */
+ NULL, /* inquiry tp_clear; */
+
+ /* Assigned meaning in release 2.1 */
+ /* rich comparisons */
+ NULL, /* richcmpfunc tp_richcompare; */
+
+ /* weak reference enabler */
+ 0, /* Py_ssize_t tp_weaklistoffset; */
+
+ /* Added in release 2.2 */
+ /* Iterators */
+ NULL, /* getiterfunc tp_iter; */
+ NULL, /* iternextfunc tp_iternext; */
+
+ /* Attribute descriptor and subclassing stuff */
+ NULL, /* struct PyMethodDef *tp_methods; */
+ status_members, /* struct PyMemberDef *tp_members; */
+
+};
+
+PyObject *py_wc_status2(svn_wc_status2_t *status)
+{
+ Status2Object *ret;
+ svn_wc_status2_t *dup_status;
+
+ ret = PyObject_New(Status2Object, &Status2_Type);
+ if (ret == NULL)
+ return NULL;
+
+ ret->pool = Pool(NULL);
+ if (ret->pool == NULL) {
+ PyObject_Del(ret);
+ return NULL;
+ }
+
+ dup_status = svn_wc_dup_status2(status, ret->pool);
+ if (dup_status == NULL)
+ {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ ret->status = *dup_status;
+
+ ret->entry = py_entry(ret->status.entry);
+ return (PyObject *)ret;
+}
+
+static svn_error_t *py_wc_found_entry(const char *path, const svn_wc_entry_t *entry, void *walk_baton, apr_pool_t *pool)
+{
+ PyObject *fn, *ret;
+ PyObject *callbacks = (PyObject *)walk_baton;
+ PyGILState_STATE state = PyGILState_Ensure();
+ if (PyTuple_Check(callbacks)) {
+ fn = PyTuple_GET_ITEM(callbacks, 0);
+ } else {
+ fn = (PyObject *)walk_baton;
+ }
+ ret = PyObject_CallFunction(fn, "sO", path, py_entry(entry));
+ CB_CHECK_PYRETVAL(ret);
+ Py_DECREF(ret);
+ PyGILState_Release(state);
+ return NULL;
+}
+
+#if ONLY_SINCE_SVN(1, 5)
+
+svn_error_t *py_wc_handle_error(const char *path, svn_error_t *err, void *walk_baton, apr_pool_t *pool)
+{
+ PyObject *fn, *ret;
+ PyObject *py_err;
+ PyGILState_STATE state;
+ PyObject *callbacks = (PyObject *)walk_baton;
+ if (PyTuple_Check(callbacks)) {
+ fn = PyTuple_GET_ITEM(callbacks, 1);
+ } else {
+ return err;
+ }
+ state = PyGILState_Ensure();
+ py_err = PyErr_NewSubversionException(err);
+ ret = PyObject_CallFunction(fn, "sO", path, py_err);
+ CB_CHECK_PYRETVAL(ret);
+ Py_DECREF(ret);
+ PyGILState_Release(state);
+ Py_DECREF(py_err);
+ return NULL;
+}
+
+static svn_wc_entry_callbacks2_t py_wc_entry_callbacks2 = {
+ py_wc_found_entry,
+ py_wc_handle_error,
+};
+#else
+static svn_wc_entry_callbacks_t py_wc_entry_callbacks = {
+ py_wc_found_entry
+};
+#endif
+
+#pragma GCC diagnostic pop
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 00000000..311abc92
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,9 @@
+[tox]
+downloadcache = {toxworkdir}/cache/
+envlist = py27, py35
+
+[testenv]
+
+commands = make check
+recreate = True
+whitelist_externals = make