summaryrefslogtreecommitdiff
path: root/subvertpy/wc_adm.c
diff options
context:
space:
mode:
Diffstat (limited to 'subvertpy/wc_adm.c')
-rw-r--r--subvertpy/wc_adm.c2237
1 files changed, 2237 insertions, 0 deletions
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