2 * Copyright © 2008 Jelmer Vernooij <jelmer@jelmer.uk>
3 * -*- coding: utf-8 -*-
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation; either version 2.1 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <apr_general.h>
23 #include <svn_props.h>
24 #include <structmember.h>
43 extern PyTypeObject Lock_Type;
45 #if ONLY_BEFORE_SVN(1, 5)
46 struct svn_wc_committed_queue_t
49 apr_array_header_t *queue;
50 svn_boolean_t have_recursive;
56 svn_wc_adm_access_t *adm_access;
57 svn_boolean_t recurse;
58 svn_boolean_t remove_lock;
59 apr_array_header_t *wcprop_changes;
60 unsigned char *digest;
61 } committed_queue_item_t;
63 svn_wc_committed_queue_t *svn_wc_committed_queue_create(apr_pool_t *pool)
65 svn_wc_committed_queue_t *q;
67 q = apr_palloc(pool, sizeof(*q));
69 q->queue = apr_array_make(pool, 1, sizeof(committed_queue_item_t *));
70 q->have_recursive = FALSE;
75 svn_error_t *svn_wc_queue_committed(svn_wc_committed_queue_t **queue,
77 svn_wc_adm_access_t *adm_access,
78 svn_boolean_t recurse,
79 apr_array_header_t *wcprop_changes,
80 svn_boolean_t remove_lock,
81 svn_boolean_t remove_changelist,
82 const unsigned char *digest,
83 apr_pool_t *scratch_pool)
85 committed_queue_item_t *cqi;
87 (*queue)->have_recursive |= recurse;
89 /* Use the same pool as the one QUEUE was allocated in,
90 to prevent lifetime issues. Intermediate operations
91 should use SCRATCH_POOL. */
93 /* Add to the array with paths and options */
94 cqi = apr_palloc((*queue)->pool, sizeof(*cqi));
96 cqi->adm_access = adm_access;
97 cqi->recurse = recurse;
98 cqi->remove_lock = remove_lock;
99 cqi->wcprop_changes = wcprop_changes;
100 cqi->digest = digest;
102 APR_ARRAY_PUSH((*queue)->queue, committed_queue_item_t *) = cqi;
112 svn_wc_committed_queue_t *queue;
113 } CommittedQueueObject;
115 svn_wc_committed_queue_t *PyObject_GetCommittedQueue(PyObject *obj)
117 return ((CommittedQueueObject *)obj)->queue;
120 #if ONLY_SINCE_SVN(1, 5)
121 static svn_error_t *py_ra_report3_set_path(void *baton, const char *path,
122 svn_revnum_t revision,
123 svn_depth_t depth, int start_empty,
124 const char *lock_token, apr_pool_t *pool)
126 PyObject *self = (PyObject *)baton, *py_lock_token, *ret;
127 PyGILState_STATE state = PyGILState_Ensure();
128 if (lock_token == NULL) {
129 py_lock_token = Py_None;
130 Py_INCREF(py_lock_token);
132 py_lock_token = PyBytes_FromString(lock_token);
134 ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision,
135 start_empty, py_lock_token, depth);
136 Py_DECREF(py_lock_token);
137 CB_CHECK_PYRETVAL(ret);
139 PyGILState_Release(state);
143 static svn_error_t *py_ra_report3_link_path(void *report_baton,
144 const char *path, const char *url,
145 svn_revnum_t revision,
146 svn_depth_t depth, int start_empty,
147 const char *lock_token, apr_pool_t *pool)
149 PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token;
150 PyGILState_STATE state = PyGILState_Ensure();
151 if (lock_token == NULL) {
152 py_lock_token = Py_None;
153 Py_INCREF(py_lock_token);
155 py_lock_token = PyBytes_FromString(lock_token);
157 ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision,
158 start_empty, py_lock_token, depth);
159 Py_DECREF(py_lock_token);
160 CB_CHECK_PYRETVAL(ret);
162 PyGILState_Release(state);
168 static svn_error_t *py_ra_report2_set_path(void *baton, const char *path,
169 svn_revnum_t revision,
170 int start_empty, const char *lock_token,
173 PyObject *self = (PyObject *)baton, *py_lock_token, *ret;
174 PyGILState_STATE state = PyGILState_Ensure();
175 if (lock_token == NULL) {
176 py_lock_token = Py_None;
177 Py_INCREF(py_lock_token);
179 py_lock_token = PyBytes_FromString(lock_token);
181 ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision,
182 start_empty, py_lock_token, svn_depth_infinity);
183 CB_CHECK_PYRETVAL(ret);
185 PyGILState_Release(state);
189 static svn_error_t *py_ra_report2_link_path(void *report_baton,
190 const char *path, const char *url,
191 svn_revnum_t revision,
193 const char *lock_token,
196 PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token;
197 PyGILState_STATE state = PyGILState_Ensure();
198 if (lock_token == NULL) {
199 py_lock_token = Py_None;
200 Py_INCREF(py_lock_token);
202 py_lock_token = PyBytes_FromString(lock_token);
204 ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision,
205 start_empty, py_lock_token, svn_depth_infinity);
206 CB_CHECK_PYRETVAL(ret);
208 PyGILState_Release(state);
212 static svn_error_t *py_ra_report_delete_path(void *baton, const char *path,
215 PyObject *self = (PyObject *)baton, *ret;
216 PyGILState_STATE state = PyGILState_Ensure();
217 ret = PyObject_CallMethod(self, "delete_path", "s", path);
218 CB_CHECK_PYRETVAL(ret);
220 PyGILState_Release(state);
224 static svn_error_t *py_ra_report_finish(void *baton, apr_pool_t *pool)
226 PyObject *self = (PyObject *)baton, *ret;
227 PyGILState_STATE state = PyGILState_Ensure();
228 ret = PyObject_CallMethod(self, "finish", "");
229 CB_CHECK_PYRETVAL(ret);
231 PyGILState_Release(state);
235 static svn_error_t *py_ra_report_abort(void *baton, apr_pool_t *pool)
237 PyObject *self = (PyObject *)baton, *ret;
238 PyGILState_STATE state = PyGILState_Ensure();
239 ret = PyObject_CallMethod(self, "abort", "");
240 CB_CHECK_PYRETVAL(ret);
242 PyGILState_Release(state);
246 #if ONLY_SINCE_SVN(1, 5)
247 const svn_ra_reporter3_t py_ra_reporter3 = {
248 py_ra_report3_set_path,
249 py_ra_report_delete_path,
250 py_ra_report3_link_path,
256 const svn_ra_reporter2_t py_ra_reporter2 = {
257 py_ra_report2_set_path,
258 py_ra_report_delete_path,
259 py_ra_report2_link_path,
266 * Get runtime libsvn_wc version information.
268 * :return: tuple with major, minor, patch version number and tag.
270 static PyObject *version(PyObject *self)
272 const svn_version_t *ver = svn_wc_version();
273 return Py_BuildValue("(iiis)", ver->major, ver->minor,
274 ver->patch, ver->tag);
277 SVN_VERSION_DEFINE(svn_api_version);
280 * Get compile-time libsvn_wc version information.
282 * :return: tuple with major, minor, patch version number and tag.
284 static PyObject *api_version(PyObject *self)
286 const svn_version_t *ver = &svn_api_version;
287 return Py_BuildValue("(iiis)", ver->major, ver->minor,
288 ver->patch, ver->tag);
292 void py_wc_notify_func(void *baton, const svn_wc_notify_t *notify, apr_pool_t *pool)
294 PyObject *func = baton, *ret;
298 if (notify->err != NULL) {
299 PyGILState_STATE state = PyGILState_Ensure();
300 PyObject *excval = PyErr_NewSubversionException(notify->err);
301 ret = PyObject_CallFunction(func, "O", excval);
304 /* If ret was NULL, the cancel func should abort the operation. */
305 PyGILState_Release(state);
308 bool py_dict_to_wcprop_changes(PyObject *dict, apr_pool_t *pool, apr_array_header_t **ret)
313 if (dict == Py_None) {
318 if (!PyDict_Check(dict)) {
319 PyErr_SetString(PyExc_TypeError, "Expected dictionary with property changes");
323 *ret = apr_array_make(pool, PyDict_Size(dict), sizeof(char *));
325 while (PyDict_Next(dict, &idx, &key, &val)) {
326 svn_prop_t *prop = apr_palloc(pool, sizeof(svn_prop_t));
327 prop->name = py_object_to_svn_string(key, pool);
328 if (prop->name == NULL) {
331 if (val == Py_None) {
334 if (!PyBytes_Check(val)) {
335 PyErr_SetString(PyExc_TypeError, "property values should be bytes");
338 prop->value = svn_string_ncreate(PyBytes_AsString(val), PyBytes_Size(val), pool);
340 APR_ARRAY_PUSH(*ret, svn_prop_t *) = prop;
346 #if ONLY_SINCE_SVN(1, 6)
347 svn_error_t *wc_validator3(void *baton, const char *uuid, const char *url, const char *root_url, apr_pool_t *pool)
349 PyObject *py_validator = baton, *ret;
350 PyGILState_STATE state;
352 if (py_validator == Py_None) {
355 state = PyGILState_Ensure();
356 ret = PyObject_CallFunction(py_validator, "sss", uuid, url, root_url);
358 PyGILState_Release(state);
359 return py_svn_error();
364 PyGILState_Release(state);
370 svn_error_t *wc_validator2(void *baton, const char *uuid, const char *url, svn_boolean_t root, apr_pool_t *pool)
372 PyObject *py_validator = baton, *ret;
373 PyGILState_STATE state;
375 if (py_validator == Py_None) {
379 state = PyGILState_Ensure();
380 ret = PyObject_CallFunction(py_validator, "ssO", uuid, url, Py_None);
382 PyGILState_Release(state);
383 return py_svn_error();
387 PyGILState_Release(state);
392 static PyObject *get_actual_target(PyObject *self, PyObject *args)
395 const char *anchor = NULL, *target = NULL;
396 apr_pool_t *temp_pool;
397 PyObject *ret, *py_path;
399 if (!PyArg_ParseTuple(args, "O", &py_path))
402 temp_pool = Pool(NULL);
403 if (temp_pool == NULL) {
407 path = py_object_to_svn_dirent(py_path, temp_pool);
409 apr_pool_destroy(temp_pool);
413 RUN_SVN_WITH_POOL(temp_pool,
414 svn_wc_get_actual_target(path,
415 &anchor, &target, temp_pool));
417 ret = Py_BuildValue("(ss)", anchor, target);
419 apr_pool_destroy(temp_pool);
425 * Determine the revision status of a specified working copy.
427 * :return: Tuple with minimum and maximum revnums found, whether the
428 * working copy was switched and whether it was modified.
430 static PyObject *revision_status(PyObject *self, PyObject *args, PyObject *kwargs)
432 char *kwnames[] = { "wc_path", "trail_url", "committed", NULL };
434 char *trail_url=NULL;
435 bool committed=false;
436 PyObject *ret, *py_wc_path;
437 svn_wc_revision_status_t *revstatus;
438 apr_pool_t *temp_pool;
440 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|zb", kwnames, &py_wc_path,
441 &trail_url, &committed))
444 temp_pool = Pool(NULL);
445 if (temp_pool == NULL) {
449 wc_path = py_object_to_svn_dirent(py_wc_path, temp_pool);
450 if (wc_path == NULL) {
451 apr_pool_destroy(temp_pool);
454 RUN_SVN_WITH_POOL(temp_pool,
455 svn_wc_revision_status(
456 &revstatus, wc_path, trail_url,
457 committed, py_cancel_check, NULL, temp_pool));
458 ret = Py_BuildValue("(llbb)", revstatus->min_rev, revstatus->max_rev,
459 revstatus->switched, revstatus->modified);
460 apr_pool_destroy(temp_pool);
464 static PyObject *is_normal_prop(PyObject *self, PyObject *args)
468 if (!PyArg_ParseTuple(args, "s", &name))
471 return PyBool_FromLong(svn_wc_is_normal_prop(name));
474 static PyObject *is_adm_dir(PyObject *self, PyObject *args)
480 if (!PyArg_ParseTuple(args, "s", &name))
487 ret = svn_wc_is_adm_dir(name, pool);
489 apr_pool_destroy(pool);
491 return PyBool_FromLong(ret);
494 static PyObject *is_wc_prop(PyObject *self, PyObject *args)
498 if (!PyArg_ParseTuple(args, "s", &name))
501 return PyBool_FromLong(svn_wc_is_wc_prop(name));
504 static PyObject *is_entry_prop(PyObject *self, PyObject *args)
508 if (!PyArg_ParseTuple(args, "s", &name))
511 return PyBool_FromLong(svn_wc_is_entry_prop(name));
514 static PyObject *get_adm_dir(PyObject *self)
522 dir = svn_wc_get_adm_dir(pool);
523 ret = py_object_from_svn_abspath(dir);
524 apr_pool_destroy(pool);
528 static PyObject *set_adm_dir(PyObject *self, PyObject *args)
530 apr_pool_t *temp_pool;
534 if (!PyArg_ParseTuple(args, "O", &py_name))
537 temp_pool = Pool(NULL);
538 if (temp_pool == NULL)
540 name = py_object_to_svn_string(py_name, temp_pool);
542 apr_pool_destroy(temp_pool);
545 RUN_SVN_WITH_POOL(temp_pool, svn_wc_set_adm_dir(name, temp_pool));
546 apr_pool_destroy(temp_pool);
550 static PyObject *get_pristine_copy_path(PyObject *self, PyObject *args)
553 const char *pristine_path;
558 if (!PyArg_ParseTuple(args, "O", &py_path))
565 path = py_object_to_svn_abspath(py_path, pool);
567 apr_pool_destroy(pool);
571 PyErr_WarnEx(PyExc_DeprecationWarning, "get_pristine_copy_path is deprecated. Use get_pristine_contents instead.", 2);
572 RUN_SVN_WITH_POOL(pool,
573 svn_wc_get_pristine_copy_path(path,
574 &pristine_path, pool));
575 ret = py_object_from_svn_abspath(pristine_path);
576 apr_pool_destroy(pool);
580 static PyObject *get_pristine_contents(PyObject *self, PyObject *args)
583 apr_pool_t *temp_pool;
585 #if ONLY_SINCE_SVN(1, 6)
587 apr_pool_t *stream_pool;
588 svn_stream_t *stream;
590 #if PY_MAJOR_VERSION >= 3
594 const char *pristine_path;
597 if (!PyArg_ParseTuple(args, "O", &py_path))
600 #if ONLY_SINCE_SVN(1, 6)
601 stream_pool = Pool(NULL);
602 if (stream_pool == NULL)
605 temp_pool = Pool(stream_pool);
606 if (temp_pool == NULL) {
607 apr_pool_destroy(stream_pool);
611 temp_pool = Pool(NULL);
612 if (temp_pool == NULL) {
617 path = py_object_to_svn_abspath(py_path, temp_pool);
619 apr_pool_destroy(temp_pool);
623 #if ONLY_SINCE_SVN(1, 6)
624 RUN_SVN_WITH_POOL(stream_pool, svn_wc_get_pristine_contents(&stream, path, stream_pool, temp_pool));
625 apr_pool_destroy(temp_pool);
627 if (stream == NULL) {
628 apr_pool_destroy(stream_pool);
632 ret = PyObject_New(StreamObject, &Stream_Type);
636 ret->pool = stream_pool;
638 ret->stream = stream;
640 return (PyObject *)ret;
642 temp_pool = Pool(NULL);
643 if (temp_pool == NULL)
645 RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_pristine_copy_path(path, &pristine_path, temp_pool));
646 #if PY_MAJOR_VERSION >= 3
647 fd = open(pristine_path, O_RDONLY);
649 PyErr_SetFromErrno(PyExc_IOError);
650 apr_pool_destroy(temp_pool);
653 ret = PyFile_FromFd(fd, pristine_path, "rb", -1, NULL, NULL, NULL, true);
655 ret = PyFile_FromString((char *)pristine_path, "rb");
657 apr_pool_destroy(temp_pool);
662 static PyObject *ensure_adm(PyObject *self, PyObject *args, PyObject *kwargs)
665 char *uuid, *url = NULL;
670 char *kwnames[] = { "path", "uuid", "url", "repos", "rev", "depth", NULL };
671 int depth = svn_depth_infinity;
673 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oss|sli", kwnames,
674 &py_path, &uuid, &url, &repos, &rev, &depth))
682 path = py_object_to_svn_dirent(py_path, pool);
684 apr_pool_destroy(pool);
688 #if ONLY_SINCE_SVN(1, 5)
689 RUN_SVN_WITH_POOL(pool,
690 svn_wc_ensure_adm3(path,
691 uuid, url, repos, rev, depth, pool));
693 if (depth != svn_depth_infinity) {
694 PyErr_SetString(PyExc_NotImplementedError,
695 "depth != infinity not supported with svn < 1.5");
696 apr_pool_destroy(pool);
699 RUN_SVN_WITH_POOL(pool,
700 svn_wc_ensure_adm2(path,
701 uuid, url, repos, rev, pool));
703 apr_pool_destroy(pool);
707 static PyObject *check_wc(PyObject *self, PyObject *args)
714 if (!PyArg_ParseTuple(args, "O", &py_path))
722 path = py_object_to_svn_dirent(py_path, pool);
724 apr_pool_destroy(pool);
728 RUN_SVN_WITH_POOL(pool, svn_wc_check_wc(path, &wc_format, pool));
729 apr_pool_destroy(pool);
730 return PyLong_FromLong(wc_format);
733 static PyObject *cleanup_wc(PyObject *self, PyObject *args, PyObject *kwargs)
736 char *diff3_cmd = NULL;
737 char *kwnames[] = { "path", "diff3_cmd", NULL };
738 apr_pool_t *temp_pool;
741 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|z", kwnames,
742 &py_path, &diff3_cmd))
745 temp_pool = Pool(NULL);
746 if (temp_pool == NULL) {
750 path = py_object_to_svn_dirent(py_path, temp_pool);
752 apr_pool_destroy(temp_pool);
756 RUN_SVN_WITH_POOL(temp_pool,
757 svn_wc_cleanup2(path, diff3_cmd, py_cancel_check, NULL,
760 apr_pool_destroy(temp_pool);
765 static PyObject *match_ignore_list(PyObject *self, PyObject *args)
767 #if ONLY_SINCE_SVN(1, 5)
770 apr_array_header_t *list;
771 apr_pool_t *temp_pool;
774 if (!PyArg_ParseTuple(args, "sO", &str, &py_list))
777 temp_pool = Pool(NULL);
779 if (!string_list_to_apr_array(temp_pool, py_list, &list)) {
780 apr_pool_destroy(temp_pool);
784 ret = svn_wc_match_ignore_list(str, list, temp_pool);
786 apr_pool_destroy(temp_pool);
788 return PyBool_FromLong(ret);
790 PyErr_SetNone(PyExc_NotImplementedError);
795 static PyMethodDef wc_methods[] = {
796 { "check_wc", check_wc, METH_VARARGS, "check_wc(path) -> version\n"
797 "Check whether path contains a Subversion working copy\n"
798 "return the workdir version"},
799 { "cleanup", (PyCFunction)cleanup_wc,
800 METH_VARARGS|METH_KEYWORDS, "cleanup(path, diff3_cmd=None)\n" },
801 { "ensure_adm", (PyCFunction)ensure_adm, METH_KEYWORDS|METH_VARARGS,
802 "ensure_adm(path, uuid, url, repos=None, rev=None)" },
803 { "get_adm_dir", (PyCFunction)get_adm_dir, METH_NOARGS,
804 "get_adm_dir() -> name" },
805 { "set_adm_dir", (PyCFunction)set_adm_dir, METH_VARARGS,
806 "set_adm_dir(name)" },
807 { "get_pristine_copy_path", get_pristine_copy_path, METH_VARARGS,
808 "get_pristine_copy_path(path) -> path" },
809 { "get_pristine_contents", get_pristine_contents, METH_VARARGS,
810 "get_pristine_contents(path) -> stream" },
811 { "is_adm_dir", is_adm_dir, METH_VARARGS,
812 "is_adm_dir(name) -> bool" },
813 { "is_normal_prop", is_normal_prop, METH_VARARGS,
814 "is_normal_prop(name) -> bool" },
815 { "is_entry_prop", is_entry_prop, METH_VARARGS,
816 "is_entry_prop(name) -> bool" },
817 { "is_wc_prop", is_wc_prop, METH_VARARGS,
818 "is_wc_prop(name) -> bool" },
819 { "revision_status", (PyCFunction)revision_status,
820 METH_KEYWORDS|METH_VARARGS,
821 "revision_status(wc_path, trail_url=None, committed=False)"
822 "-> (min_rev, max_rev, switched, modified)" },
823 { "version", (PyCFunction)version, METH_NOARGS,
824 "version() -> (major, minor, patch, tag)\n\n"
825 "Version of libsvn_wc currently used."
827 { "api_version", (PyCFunction)api_version, METH_NOARGS,
828 "api_version() -> (major, minor, patch, tag)\n\n"
829 "Version of libsvn_wc Subvertpy was compiled against." },
830 { "match_ignore_list", (PyCFunction)match_ignore_list, METH_VARARGS,
831 "match_ignore_list(str, patterns) -> bool" },
832 { "get_actual_target", (PyCFunction)get_actual_target, METH_VARARGS,
833 "get_actual_target(path) -> (anchor, target)" },
837 static void committed_queue_dealloc(PyObject *self)
839 apr_pool_destroy(((CommittedQueueObject *)self)->pool);
843 static PyObject *committed_queue_repr(PyObject *self)
845 CommittedQueueObject *cqobj = (CommittedQueueObject *)self;
847 return PyRepr_FromFormat("<wc.CommittedQueue at 0x%p>", cqobj->queue);
850 static PyObject *committed_queue_init(PyTypeObject *self, PyObject *args, PyObject *kwargs)
852 CommittedQueueObject *ret;
853 char *kwnames[] = { NULL };
855 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwnames))
858 ret = PyObject_New(CommittedQueueObject, &CommittedQueue_Type);
862 ret->pool = Pool(NULL);
863 if (ret->pool == NULL)
865 ret->queue = svn_wc_committed_queue_create(ret->pool);
866 if (ret->queue == NULL) {
872 return (PyObject *)ret;
875 static PyObject *committed_queue_queue(CommittedQueueObject *self, PyObject *args, PyObject *kwargs)
879 PyObject *py_wcprop_changes = Py_None, *py_path;
880 svn_wc_adm_access_t *adm;
881 bool remove_lock = false, remove_changelist = false;
882 char *md5_digest = NULL, *sha1_digest = NULL;
883 bool recurse = false;
884 apr_pool_t *temp_pool;
885 apr_array_header_t *wcprop_changes;
886 int md5_digest_len, sha1_digest_len;
887 char *kwnames[] = { "path", "adm", "recurse", "wcprop_changes", "remove_lock", "remove_changelist", "md5_digest", "sha1_digest", NULL };
889 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO!|bObbz#z#", kwnames,
890 &py_path, &Adm_Type, &admobj,
891 &recurse, &py_wcprop_changes, &remove_lock,
892 &remove_changelist, &md5_digest, &md5_digest_len,
893 &sha1_digest, &sha1_digest_len))
896 temp_pool = Pool(NULL);
897 if (temp_pool == NULL)
900 if (!py_dict_to_wcprop_changes(py_wcprop_changes, self->pool, &wcprop_changes)) {
901 apr_pool_destroy(temp_pool);
905 path = py_object_to_svn_dirent(py_path, self->pool);
907 apr_pool_destroy(temp_pool);
911 if (md5_digest != NULL) {
912 if (md5_digest_len != APR_MD5_DIGESTSIZE) {
913 PyErr_SetString(PyExc_ValueError, "Invalid size for md5 digest");
914 apr_pool_destroy(temp_pool);
917 md5_digest = apr_pstrdup(temp_pool, md5_digest);
918 if (md5_digest == NULL) {
924 if (sha1_digest != NULL) {
925 if (sha1_digest_len != APR_SHA1_DIGESTSIZE) {
926 PyErr_SetString(PyExc_ValueError, "Invalid size for sha1 digest");
927 apr_pool_destroy(temp_pool);
930 sha1_digest = apr_pstrdup(temp_pool, sha1_digest);
931 if (sha1_digest == NULL) {
937 adm = PyObject_GetAdmAccess(admobj);
939 #if ONLY_SINCE_SVN(1, 6)
941 svn_checksum_t svn_checksum, *svn_checksum_p = &svn_checksum;
943 if (sha1_digest != NULL) {
944 svn_checksum.digest = (unsigned char *)sha1_digest;
945 svn_checksum.kind = svn_checksum_sha1;
946 } else if (md5_digest != NULL) {
947 svn_checksum.digest = (unsigned char *)md5_digest;
948 svn_checksum.kind = svn_checksum_md5;
950 svn_checksum_p = NULL;
952 RUN_SVN_WITH_POOL(temp_pool,
953 svn_wc_queue_committed2(self->queue, path, adm, recurse?TRUE:FALSE,
954 wcprop_changes, remove_lock?TRUE:FALSE, remove_changelist?TRUE:FALSE,
955 svn_checksum_p, temp_pool));
958 RUN_SVN_WITH_POOL(temp_pool,
959 svn_wc_queue_committed(&self->queue, path, adm, recurse?TRUE:FALSE,
960 wcprop_changes, remove_lock?TRUE:FALSE, remove_changelist?TRUE:FALSE,
961 (unsigned char *)md5_digest, temp_pool));
964 apr_pool_destroy(temp_pool);
969 static PyMethodDef committed_queue_methods[] = {
970 { "queue", (PyCFunction)committed_queue_queue, METH_VARARGS|METH_KEYWORDS,
971 "S.queue(path, adm, recurse=False, wcprop_changes=[], remove_lock=False, remove_changelist=False, digest=None)" },
975 PyTypeObject CommittedQueue_Type = {
976 PyVarObject_HEAD_INIT(NULL, 0)
977 "wc.CommittedQueue", /* const char *tp_name; For printing, in format "<module>.<name>" */
978 sizeof(CommittedQueueObject),
979 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
981 /* Methods to implement standard operations */
983 committed_queue_dealloc, /* destructor tp_dealloc; */
984 NULL, /* printfunc tp_print; */
985 NULL, /* getattrfunc tp_getattr; */
986 NULL, /* setattrfunc tp_setattr; */
987 NULL, /* cmpfunc tp_compare; */
988 committed_queue_repr, /* reprfunc tp_repr; */
990 /* Method suites for standard classes */
992 NULL, /* PyNumberMethods *tp_as_number; */
993 NULL, /* PySequenceMethods *tp_as_sequence; */
994 NULL, /* PyMappingMethods *tp_as_mapping; */
996 /* More standard operations (here for binary compatibility) */
998 NULL, /* hashfunc tp_hash; */
999 NULL, /* ternaryfunc tp_call; */
1000 NULL, /* reprfunc tp_str; */
1001 NULL, /* getattrofunc tp_getattro; */
1002 NULL, /* setattrofunc tp_setattro; */
1004 /* Functions to access object as input/output buffer */
1005 NULL, /* PyBufferProcs *tp_as_buffer; */
1007 /* Flags to define presence of optional/expanded features */
1008 0, /* long tp_flags; */
1010 "Committed queue", /* const char *tp_doc; Documentation string */
1012 /* Assigned meaning in release 2.0 */
1013 /* call function for all accessible objects */
1014 NULL, /* traverseproc tp_traverse; */
1016 /* delete references to contained objects */
1017 NULL, /* inquiry tp_clear; */
1019 /* Assigned meaning in release 2.1 */
1020 /* rich comparisons */
1021 NULL, /* richcmpfunc tp_richcompare; */
1023 /* weak reference enabler */
1024 0, /* Py_ssize_t tp_weaklistoffset; */
1026 /* Added in release 2.2 */
1028 NULL, /* getiterfunc tp_iter; */
1029 NULL, /* iternextfunc tp_iternext; */
1031 /* Attribute descriptor and subclassing stuff */
1032 committed_queue_methods, /* struct PyMethodDef *tp_methods; */
1033 NULL, /* struct PyMemberDef *tp_members; */
1034 NULL, /* struct PyGetSetDef *tp_getset; */
1035 NULL, /* struct _typeobject *tp_base; */
1036 NULL, /* PyObject *tp_dict; */
1037 NULL, /* descrgetfunc tp_descr_get; */
1038 NULL, /* descrsetfunc tp_descr_set; */
1039 0, /* Py_ssize_t tp_dictoffset; */
1040 NULL, /* initproc tp_init; */
1041 NULL, /* allocfunc tp_alloc; */
1042 committed_queue_init, /* newfunc tp_new; */
1045 #if ONLY_SINCE_SVN(1, 7)
1046 static PyTypeObject Context_Type;
1051 svn_wc_context_t *context;
1054 static PyObject *py_wc_context_locked(PyObject *self, PyObject *args)
1059 svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
1060 svn_boolean_t locked_here, locked;
1062 if (!PyArg_ParseTuple(args, "O", &py_path))
1067 path = py_object_to_svn_abspath(py_path, pool);
1069 apr_pool_destroy(pool);
1073 RUN_SVN_WITH_POOL(pool, svn_wc_locked2(&locked_here, &locked, wc_context, path, pool));
1075 apr_pool_destroy(pool);
1077 return Py_BuildValue("(bb)", locked_here?true:false, locked?true:false);
1080 static PyObject *py_wc_context_check_wc(PyObject *self, PyObject *args)
1085 svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
1088 if (!PyArg_ParseTuple(args, "O", &py_path))
1093 path = py_object_to_svn_abspath(py_path, pool);
1095 apr_pool_destroy(pool);
1099 RUN_SVN_WITH_POOL(pool, svn_wc_check_wc2(&wc_format, wc_context, path, pool));
1101 apr_pool_destroy(pool);
1103 #if PY_MAJOR_VERSION >= 3
1104 return PyLong_FromLong(wc_format);
1106 return PyInt_FromLong(wc_format);
1110 static PyObject *py_wc_context_text_modified_p2(PyObject *self, PyObject *args)
1115 svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
1116 svn_boolean_t modified;
1118 if (!PyArg_ParseTuple(args, "O", &py_path))
1123 path = py_object_to_svn_abspath(py_path, pool);
1125 apr_pool_destroy(pool);
1129 RUN_SVN_WITH_POOL(pool, svn_wc_text_modified_p2(&modified, wc_context,
1130 path, FALSE, pool));
1132 apr_pool_destroy(pool);
1134 return PyBool_FromLong(modified);
1137 static PyObject *py_wc_context_props_modified_p2(PyObject *self, PyObject *args)
1142 svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
1143 svn_boolean_t modified;
1145 if (!PyArg_ParseTuple(args, "O", &py_path))
1150 path = py_object_to_svn_abspath(py_path, pool);
1152 apr_pool_destroy(pool);
1156 RUN_SVN_WITH_POOL(pool, svn_wc_props_modified_p2(&modified, wc_context,
1159 apr_pool_destroy(pool);
1161 return PyBool_FromLong(modified);
1164 static PyObject *py_wc_context_conflicted(PyObject *self, PyObject *args)
1169 svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
1170 svn_boolean_t text_conflicted, props_conflicted, tree_conflicted;
1172 if (!PyArg_ParseTuple(args, "O", &py_path))
1177 path = py_object_to_svn_abspath(py_path, pool);
1179 apr_pool_destroy(pool);
1183 RUN_SVN_WITH_POOL(pool, svn_wc_conflicted_p3(
1184 &text_conflicted, &props_conflicted, &tree_conflicted, wc_context,
1187 apr_pool_destroy(pool);
1189 return Py_BuildValue("(bbb)", text_conflicted, props_conflicted, tree_conflicted);
1192 static PyObject *py_wc_context_crawl_revisions(PyObject *self, PyObject *args, PyObject *kwargs)
1194 PyObject* py_path, *py_reporter;
1197 svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
1198 char *kwnames[] = { "path", "reporter", "restore_files", "depth",
1199 "honor_depth_exclude", "depth_compatibility_trick", "use_commit_times",
1200 "cancel", "notify", NULL };
1201 bool restore_files = false;
1202 int depth = svn_depth_infinity;
1203 bool honor_depth_exclude = true;
1204 bool depth_compatibility_trick = false;
1205 bool use_commit_times = false;
1206 PyObject *notify = Py_None;
1208 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bibbbOO", kwnames,
1209 &py_path, &py_reporter, &restore_files,
1210 &depth, &honor_depth_exclude,
1211 &depth_compatibility_trick,
1212 &use_commit_times, ¬ify)) {
1218 path = py_object_to_svn_abspath(py_path, pool);
1220 apr_pool_destroy(pool);
1224 RUN_SVN_WITH_POOL(pool, svn_wc_crawl_revisions5(
1225 wc_context, path, &py_ra_reporter3, py_reporter, restore_files,
1226 depth, honor_depth_exclude, depth_compatibility_trick,
1227 use_commit_times, py_cancel_check, NULL, py_wc_notify_func, notify, pool));
1229 apr_pool_destroy(pool);
1234 static void context_done_handler(void *self)
1236 PyObject *selfobj = (PyObject *)self;
1241 static PyObject *py_wc_context_get_update_editor(PyObject *self, PyObject *args, PyObject *kwargs)
1244 "anchor_abspath", "target_basename", "use_commit_times", "depth",
1245 "depth_is_sticky", "allow_unver_obstructions", "adds_as_modification",
1246 "server_performs_filtering", "clean_checkout", "diff3_cmd",
1247 "preserved_exts", "dirents_func", "conflict_func", "external_func",
1248 "notify_func", NULL };
1249 const svn_delta_editor_t *editor;
1251 const char *anchor_abspath;
1252 char *target_basename;
1253 char *diff3_cmd = NULL;
1254 svn_wc_context_t *wc_context = ((ContextObject *)self)->context;
1255 bool use_commit_times = false;
1256 int depth = svn_depth_infinity;
1257 bool depth_is_sticky = false;
1258 bool allow_unver_obstructions = true;
1259 bool adds_as_modification = false;
1260 bool server_performs_filtering = false;
1261 bool clean_checkout = false;
1262 apr_array_header_t *preserved_exts = NULL;
1263 PyObject *py_preserved_exts = Py_None;
1264 PyObject *dirents_func = Py_None;
1265 PyObject *conflict_func = Py_None;
1266 PyObject *external_func = Py_None;
1267 PyObject *notify_func = Py_None;
1268 PyObject *py_anchor_abspath;
1269 apr_pool_t *result_pool, *scratch_pool;
1271 svn_revnum_t target_revision;
1273 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os|bibbbbbzOOOOO", kwnames,
1274 &py_anchor_abspath, &target_basename,
1275 &use_commit_times, &depth,
1277 &allow_unver_obstructions,
1278 &adds_as_modification,
1279 &server_performs_filtering,
1280 &clean_checkout, &py_preserved_exts,
1281 &dirents_func, &conflict_func,
1282 &external_func, ¬ify_func)) {
1286 if (conflict_func != Py_None) {
1288 PyErr_SetString(PyExc_NotImplementedError,
1289 "conflict_func is not currently supported");
1293 if (external_func != Py_None) {
1295 PyErr_SetString(PyExc_NotImplementedError,
1296 "external_func is not currently supported");
1300 if (dirents_func != Py_None) {
1302 PyErr_SetString(PyExc_NotImplementedError,
1303 "dirents_func is not currently supported");
1307 scratch_pool = Pool(NULL);
1309 anchor_abspath = py_object_to_svn_abspath(py_anchor_abspath, scratch_pool);
1311 if (py_preserved_exts != Py_None) {
1312 if (!string_list_to_apr_array(scratch_pool, py_preserved_exts, &preserved_exts)) {
1313 apr_pool_destroy(scratch_pool);
1318 result_pool = Pool(NULL);
1320 Py_BEGIN_ALLOW_THREADS
1321 err = svn_wc_get_update_editor4(
1322 &editor, &edit_baton, &target_revision, wc_context,
1323 anchor_abspath, target_basename, use_commit_times, depth,
1324 depth_is_sticky, allow_unver_obstructions, adds_as_modification,
1325 server_performs_filtering, clean_checkout, diff3_cmd,
1326 preserved_exts, NULL, dirents_func, NULL, conflict_func, NULL,
1327 external_func, py_cancel_check, NULL, py_wc_notify_func,
1328 notify_func, result_pool, scratch_pool);
1329 Py_END_ALLOW_THREADS
1331 apr_pool_destroy(scratch_pool);
1334 handle_svn_error(err);
1335 svn_error_clear(err);
1336 apr_pool_destroy(result_pool);
1340 /* TODO: Also return target_revision ? */
1342 return new_editor_object(NULL, editor, edit_baton, result_pool, &Editor_Type,
1343 context_done_handler, self, NULL);
1346 static PyObject *py_wc_context_ensure_adm(PyObject *self, PyObject *args,
1349 ContextObject *context_obj = (ContextObject *)self;
1351 "local_abspath", "url", "repos_root_url", "repos_uuid",
1352 "revnum", "depth", NULL };
1353 char *local_abspath;
1355 char *repos_root_url;
1358 int depth = svn_depth_infinity;
1361 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ssssi|i", kwnames,
1362 &local_abspath, &url, &repos_root_url,
1363 &repos_uuid, &revnum, &depth)) {
1369 RUN_SVN_WITH_POOL(pool, svn_wc_ensure_adm4(context_obj->context,
1371 repos_root_url, repos_uuid,
1372 revnum, depth, pool));
1374 apr_pool_destroy(pool);
1382 svn_wc_status3_t status;
1385 static void status_dealloc(PyObject *self)
1387 apr_pool_t *pool = ((Status3Object *)self)->pool;
1389 apr_pool_destroy(pool);
1393 static PyMemberDef status_members[] = {
1394 { "kind", T_INT, offsetof(Status3Object, status.kind), READONLY,
1395 "The kind of node as recorded in the working copy." },
1396 { "depth", T_INT, offsetof(Status3Object, status.depth), READONLY,
1397 "The depth of the node as recorded in the working copy." },
1398 { "filesize", T_LONG, offsetof(Status3Object, status.filesize), READONLY,
1399 "The actual size of the working file on disk, or SVN_INVALID_FILESIZE"
1400 "if unknown (or if the item isn't a file at all)" },
1401 { "versioned", T_BOOL, offsetof(Status3Object, status.versioned), READONLY,
1402 "If the path is under version control, versioned is TRUE, "
1403 "otherwise FALSE." },
1404 { "repos_uuid", T_STRING, offsetof(Status3Object, status.repos_uuid), READONLY,
1405 "UUID of repository" },
1406 { "repos_root_url", T_STRING, offsetof(Status3Object, status.repos_root_url), READONLY,
1407 "Repository root URL" },
1408 { "repos_relpath", T_STRING, offsetof(Status3Object, status.repos_relpath), READONLY,
1409 "Relative path in repository" },
1414 static PyTypeObject Status3_Type = {
1415 PyVarObject_HEAD_INIT(NULL, 0)
1416 "wc.Status", /* const char *tp_name; For printing, in format "<module>.<name>" */
1417 sizeof(Status3Object),
1418 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
1420 /* Methods to implement standard operations */
1422 status_dealloc, /* destructor tp_dealloc; */
1423 NULL, /* printfunc tp_print; */
1424 NULL, /* getattrfunc tp_getattr; */
1425 NULL, /* setattrfunc tp_setattr; */
1426 NULL, /* cmpfunc tp_compare; */
1427 NULL, /* reprfunc tp_repr; */
1429 /* Method suites for standard classes */
1431 NULL, /* PyNumberMethods *tp_as_number; */
1432 NULL, /* PySequenceMethods *tp_as_sequence; */
1433 NULL, /* PyMappingMethods *tp_as_mapping; */
1435 /* More standard operations (here for binary compatibility) */
1437 NULL, /* hashfunc tp_hash; */
1438 NULL, /* ternaryfunc tp_call; */
1439 NULL, /* reprfunc tp_str; */
1440 NULL, /* getattrofunc tp_getattro; */
1441 NULL, /* setattrofunc tp_setattro; */
1443 /* Functions to access object as input/output buffer */
1444 NULL, /* PyBufferProcs *tp_as_buffer; */
1446 /* Flags to define presence of optional/expanded features */
1447 0, /* long tp_flags; */
1449 NULL, /* const char *tp_doc; Documentation string */
1451 /* Assigned meaning in release 2.0 */
1452 /* call function for all accessible objects */
1453 NULL, /* traverseproc tp_traverse; */
1455 /* delete references to contained objects */
1456 NULL, /* inquiry tp_clear; */
1458 /* Assigned meaning in release 2.1 */
1459 /* rich comparisons */
1460 NULL, /* richcmpfunc tp_richcompare; */
1462 /* weak reference enabler */
1463 0, /* Py_ssize_t tp_weaklistoffset; */
1465 /* Added in release 2.2 */
1467 NULL, /* getiterfunc tp_iter; */
1468 NULL, /* iternextfunc tp_iternext; */
1470 /* Attribute descriptor and subclassing stuff */
1471 NULL, /* struct PyMethodDef *tp_methods; */
1472 status_members, /* struct PyMemberDef *tp_members; */
1473 NULL, /* struct PyGetSetDef *tp_getsetters; */
1476 static PyObject *py_wc_status(PyObject *self, PyObject *args, PyObject *kwargs)
1478 ContextObject *context_obj = (ContextObject *)self;
1479 char *kwnames[] = {"path", NULL};
1483 apr_pool_t *scratch_pool, *result_pool;
1484 svn_wc_status3_t* status;
1486 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &py_path)) {
1490 result_pool = Pool(NULL);
1491 if (result_pool == NULL) {
1494 scratch_pool = Pool(result_pool);
1495 if (scratch_pool == NULL) {
1496 apr_pool_destroy(result_pool);
1500 path = py_object_to_svn_abspath(py_path, scratch_pool);
1502 apr_pool_destroy(result_pool);
1506 RUN_SVN_WITH_POOL(result_pool,
1507 svn_wc_status3(&status, context_obj->context, path,
1508 result_pool, scratch_pool));
1510 apr_pool_destroy(scratch_pool);
1512 ret = PyObject_New(Status3Object, &Status3_Type);
1514 apr_pool_destroy(result_pool);
1517 ret->pool = result_pool;
1518 ret->status = *status;
1519 return (PyObject *)ret;
1522 static svn_error_t *py_status_receiver(void *baton, const char *local_abspath,
1523 const svn_wc_status3_t *status,
1524 apr_pool_t *scratch_pool)
1526 Status3Object *py_status;
1528 PyGILState_STATE state;
1530 if (baton == Py_None)
1533 state = PyGILState_Ensure();
1535 py_status = PyObject_New(Status3Object, &Status3_Type);
1536 if (py_status == NULL) {
1537 PyGILState_Release(state);
1538 return py_svn_error();
1540 py_status->pool = Pool(NULL);
1541 py_status->status = *svn_wc_dup_status3(status, py_status->pool);
1543 ret = PyObject_CallFunction((PyObject *)baton, "sO", local_abspath, py_status);
1544 Py_DECREF(py_status);
1547 PyGILState_Release(state);
1548 return py_svn_error();
1552 PyGILState_Release(state);
1557 static PyObject *py_wc_walk_status(PyObject *self, PyObject *args, PyObject *kwargs)
1559 ContextObject *context_obj = (ContextObject *)self;
1560 char *kwnames[] = {"path", "receiver", "depth", "get_all", "no_ignore",
1561 "ignore_text_mode", "ignore_patterns", NULL};
1564 int depth = svn_depth_infinity;
1565 bool get_all = true;
1566 bool no_ignore = false;
1567 bool ignore_text_mode = false;
1568 PyObject *py_ignore_patterns = Py_None;
1569 PyObject *status_func;
1570 apr_array_header_t *ignore_patterns;
1573 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|ibbbOO", kwnames,
1574 &py_path, &status_func, &depth, &get_all, &no_ignore,
1575 &ignore_text_mode, &py_ignore_patterns)) {
1581 path = py_object_to_svn_abspath(py_path, pool);
1583 apr_pool_destroy(pool);
1587 if (py_ignore_patterns == Py_None) {
1588 ignore_patterns = NULL;
1590 if (!string_list_to_apr_array(pool, py_ignore_patterns, &ignore_patterns)) {
1591 apr_pool_destroy(pool);
1596 RUN_SVN_WITH_POOL(pool,
1597 svn_wc_walk_status(context_obj->context, path, depth,
1598 get_all, no_ignore, ignore_text_mode,
1599 ignore_patterns, py_status_receiver,
1600 status_func, py_cancel_check, NULL,
1603 apr_pool_destroy(pool);
1608 static svn_lock_t *py_object_to_svn_lock(PyObject *py_lock, apr_pool_t *pool)
1610 LockObject* lockobj = (LockObject *)py_lock;
1611 return lockobj->lock;
1614 static PyObject *py_wc_add_lock(PyObject *self, PyObject *args, PyObject *kwargs)
1616 ContextObject *context_obj = (ContextObject *)self;
1617 PyObject *py_path, *py_lock;
1619 char *kwnames[] = { "path", "lock", NULL };
1621 apr_pool_t *scratch_pool;
1623 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO!", kwnames, &py_path, &Lock_Type,
1628 scratch_pool = Pool(NULL);
1630 path = py_object_to_svn_abspath(py_path, scratch_pool);
1632 apr_pool_destroy(scratch_pool);
1636 lock = py_object_to_svn_lock(py_lock, scratch_pool);
1638 apr_pool_destroy(scratch_pool);
1642 RUN_SVN_WITH_POOL(scratch_pool,
1643 svn_wc_add_lock2(context_obj->context, path, lock, scratch_pool));
1645 apr_pool_destroy(scratch_pool);
1650 static PyObject *py_wc_remove_lock(PyObject *self, PyObject *args, PyObject *kwargs)
1652 ContextObject *context_obj = (ContextObject *)self;
1653 char *kwnames[] = { "path", NULL };
1656 apr_pool_t *scratch_pool;
1658 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &py_path)) {
1662 scratch_pool = Pool(NULL);
1664 path = py_object_to_svn_abspath(py_path, scratch_pool);
1666 apr_pool_destroy(scratch_pool);
1670 RUN_SVN_WITH_POOL(scratch_pool,
1671 svn_wc_remove_lock2(context_obj->context, path,
1674 apr_pool_destroy(scratch_pool);
1678 static PyObject *py_wc_add_from_disk(PyObject *self, PyObject *args, PyObject *kwargs)
1680 ContextObject *context_obj = (ContextObject *)self;
1681 char *kwnames[] = {"path", "props", "skip_checks", "notify", NULL };
1684 bool skip_checks = false;
1685 PyObject *py_props = Py_None;
1686 PyObject *notify_func = Py_None;
1690 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|ObO", kwnames,
1691 &py_path, &py_props, &skip_checks, ¬ify_func)) {
1700 path = py_object_to_svn_abspath(py_path, pool);
1702 apr_pool_destroy(pool);
1706 if (py_props == Py_None) {
1709 props = prop_dict_to_hash(pool, py_props);
1710 if (props == NULL) {
1711 apr_pool_destroy(pool);
1716 #if ONLY_SINCE_SVN(1, 9)
1718 pool, svn_wc_add_from_disk3(
1719 context_obj->context, path, props, skip_checks,
1720 notify_func == Py_None?NULL:py_wc_notify_func,
1721 notify_func, pool));
1723 if (props != NULL) {
1724 PyErr_SetString(PyExc_NotImplementedError,
1725 "props argument only supported on svn >= 1.9");
1726 apr_pool_destroy(pool);
1731 PyErr_SetString(PyExc_NotImplementedError,
1732 "skip_checks argument only supported on svn >= 1.9");
1733 apr_pool_destroy(pool);
1737 pool, svn_wc_add_from_disk(
1738 context_obj->context, path,
1739 notify_func == Py_None?NULL:py_wc_notify_func,
1740 notify_func, pool));
1743 apr_pool_destroy(pool);
1748 static PyObject *py_wc_get_prop_diffs(PyObject *self, PyObject *args, PyObject *kwargs)
1750 ContextObject *context_obj = (ContextObject *)self;
1751 PyObject *py_path, *py_orig_props, *py_propchanges;
1753 char *kwnames[] = {"path", NULL};
1754 apr_hash_t *original_props;
1755 apr_array_header_t *propchanges;
1758 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &py_path)) {
1764 path = py_object_to_svn_abspath(py_path, pool);
1766 apr_pool_destroy(pool);
1770 RUN_SVN_WITH_POOL(pool, svn_wc_get_prop_diffs2(&propchanges,
1772 context_obj->context,
1775 py_orig_props = prop_hash_to_dict(original_props);
1776 if (py_orig_props == NULL) {
1777 apr_pool_destroy(pool);
1781 py_propchanges = propchanges_to_list(propchanges);
1782 if (py_propchanges == NULL) {
1783 apr_pool_destroy(pool);
1784 Py_DECREF(py_propchanges);
1788 apr_pool_destroy(pool);
1790 return Py_BuildValue("NN", py_orig_props, py_propchanges);
1793 static PyMethodDef context_methods[] = {
1794 { "locked", py_wc_context_locked, METH_VARARGS,
1795 "locked(path) -> (locked_here, locked)\n"
1796 "Check whether a patch is locked."},
1797 { "check_wc", py_wc_context_check_wc, METH_VARARGS,
1798 "check_wc(path) -> wc_format\n"
1799 "Check format version of a working copy." },
1800 { "text_modified", py_wc_context_text_modified_p2, METH_VARARGS,
1801 "text_modified(path) -> bool\n"
1802 "Check whether text of a file is modified against base." },
1803 { "props_modified", py_wc_context_props_modified_p2, METH_VARARGS,
1804 "props_modified(path) -> bool\n"
1805 "Check whether props of a file are modified against base." },
1806 { "conflicted", py_wc_context_conflicted, METH_VARARGS,
1807 "conflicted(path) -> (text_conflicted, prop_conflicted, "
1808 "tree_conflicted)\n"
1809 "Check whether a path is conflicted." },
1810 { "crawl_revisions", (PyCFunction)py_wc_context_crawl_revisions,
1811 METH_VARARGS|METH_KEYWORDS,
1812 "crawl_revisions(path, reporter, restore_files, depth, "
1813 "honor_depth_exclude, depth_compatibility_trick, "
1814 "use_commit_time, notify)\n"
1815 "Do a depth-first crawl of the working copy." },
1816 { "get_update_editor",
1817 (PyCFunction)py_wc_context_get_update_editor,
1818 METH_VARARGS|METH_KEYWORDS,
1819 "get_update_editor(anchor_abspath, target_basename, use_commit_time, "
1820 "depth, depth_is_sticky, allow_unver_obstructions, "
1821 "adds_as_modification, server_performs_filtering, clean_checkout, "
1822 "diff3_cmd, dirent_func=None, conflict_func=None, "
1823 "external_func=None) -> target_revnum" },
1825 (PyCFunction)py_wc_context_ensure_adm,
1826 METH_VARARGS|METH_KEYWORDS,
1827 "ensure_adm(local_abspath, url, repos_root_url, repos_uuid, revnum, depth)" },
1829 (PyCFunction)py_wc_status,
1830 METH_VARARGS|METH_KEYWORDS,
1831 "status(path) -> status" },
1833 (PyCFunction)py_wc_walk_status,
1834 METH_VARARGS|METH_KEYWORDS,
1835 "walk_status(path, receiver, depth=DEPTH_INFINITY, get_all=True, "
1836 "no_ignore=False, ignore_text_mode=False, ignore_patterns=None)\n" },
1838 (PyCFunction)py_wc_add_lock,
1839 METH_VARARGS|METH_KEYWORDS,
1840 "add_lock(path, lock)" },
1842 (PyCFunction)py_wc_remove_lock,
1843 METH_VARARGS|METH_KEYWORDS,
1844 "remove_lock(path)" },
1846 (PyCFunction)py_wc_add_from_disk,
1847 METH_VARARGS|METH_KEYWORDS,
1848 "add_from_disk(local_abspath, props=None, skip_checks=False, notify=None)" },
1850 (PyCFunction)py_wc_get_prop_diffs,
1851 METH_VARARGS|METH_KEYWORDS,
1852 "get_prop_diffs(path) -> (changes orig_props)" },
1856 static void context_dealloc(PyObject *self)
1858 ContextObject *context_obj = (ContextObject *)self;
1859 svn_wc_context_destroy(context_obj->context);
1860 apr_pool_destroy(context_obj->pool);
1864 static PyObject *context_init(PyTypeObject *self, PyObject *args, PyObject *kwargs)
1867 char *kwnames[] = { NULL };
1868 svn_config_t *config = NULL;
1870 // TODO(jelmer): Support passing in config
1871 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwnames))
1874 ret = PyObject_New(ContextObject, &Context_Type);
1878 ret->pool = Pool(NULL);
1879 if (ret->pool == NULL)
1881 RUN_SVN_WITH_POOL(ret->pool, svn_wc_context_create(&ret->context, config,
1882 ret->pool, ret->pool));
1884 return (PyObject *)ret;
1887 static PyTypeObject Context_Type = {
1888 PyVarObject_HEAD_INIT(NULL, 0)
1889 "wc.Context", /* const char *tp_name; For printing, in format "<module>.<name>" */
1890 sizeof(ContextObject),
1891 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
1893 /* Methods to implement standard operations */
1895 context_dealloc, /* destructor tp_dealloc; */
1896 NULL, /* printfunc tp_print; */
1897 NULL, /* getattrfunc tp_getattr; */
1898 NULL, /* setattrfunc tp_setattr; */
1899 NULL, /* cmpfunc tp_compare; */
1900 NULL, /* reprfunc tp_repr; */
1902 /* Method suites for standard classes */
1904 NULL, /* PyNumberMethods *tp_as_number; */
1905 NULL, /* PySequenceMethods *tp_as_sequence; */
1906 NULL, /* PyMappingMethods *tp_as_mapping; */
1908 /* More standard operations (here for binary compatibility) */
1910 NULL, /* hashfunc tp_hash; */
1911 NULL, /* ternaryfunc tp_call; */
1912 NULL, /* reprfunc tp_str; */
1913 NULL, /* getattrofunc tp_getattro; */
1914 NULL, /* setattrofunc tp_setattro; */
1916 /* Functions to access object as input/output buffer */
1917 NULL, /* PyBufferProcs *tp_as_buffer; */
1919 /* Flags to define presence of optional/expanded features */
1920 0, /* long tp_flags; */
1922 "Context", /* const char *tp_doc; Documentation string */
1924 /* Assigned meaning in release 2.0 */
1925 /* call function for all accessible objects */
1926 NULL, /* traverseproc tp_traverse; */
1928 /* delete references to contained objects */
1929 NULL, /* inquiry tp_clear; */
1931 /* Assigned meaning in release 2.1 */
1932 /* rich comparisons */
1933 NULL, /* richcmpfunc tp_richcompare; */
1935 /* weak reference enabler */
1936 0, /* Py_ssize_t tp_weaklistoffset; */
1938 /* Added in release 2.2 */
1940 NULL, /* getiterfunc tp_iter; */
1941 NULL, /* iternextfunc tp_iternext; */
1943 /* Attribute descriptor and subclassing stuff */
1944 context_methods, /* struct PyMethodDef *tp_methods; */
1945 NULL, /* struct PyMemberDef *tp_members; */
1946 NULL, /* struct PyGetSetDef *tp_getset; */
1947 NULL, /* struct _typeobject *tp_base; */
1948 NULL, /* PyObject *tp_dict; */
1949 NULL, /* descrgetfunc tp_descr_get; */
1950 NULL, /* descrsetfunc tp_descr_set; */
1951 0, /* Py_ssize_t tp_dictoffset; */
1952 NULL, /* initproc tp_init; */
1953 NULL, /* allocfunc tp_alloc; */
1954 context_init, /* newfunc tp_new; */
1959 static void lock_dealloc(PyObject *self)
1961 LockObject *lockself = (LockObject *)self;
1963 apr_pool_destroy(lockself->pool);
1968 static PyObject *lock_init(PyTypeObject *type, PyObject *args, PyObject *kwargs)
1970 char *kwnames[] = { NULL };
1973 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwnames))
1976 ret = PyObject_New(LockObject, &Lock_Type);
1980 ret->pool = Pool(NULL);
1981 if (ret->pool == NULL)
1983 ret->lock = svn_lock_create(ret->pool);
1985 return (PyObject *)ret;
1988 PyTypeObject Lock_Type = {
1989 PyVarObject_HEAD_INIT(NULL, 0)
1990 "wc.Lock", /* const char *tp_name; For printing, in format "<module>.<name>" */
1992 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
1994 /* Methods to implement standard operations */
1996 .tp_dealloc = lock_dealloc, /* destructor tp_dealloc; */
1998 .tp_doc = "Lock", /* const char *tp_doc; Documentation string */
2000 .tp_methods = NULL, /* struct PyMethodDef *tp_methods; */
2002 .tp_new = lock_init, /* tp_new tp_new */
2010 if (PyType_Ready(&Entry_Type) < 0)
2013 if (PyType_Ready(&Status2_Type) < 0)
2016 if (PyType_Ready(&Adm_Type) < 0)
2019 #if ONLY_SINCE_SVN(1, 7)
2020 if (PyType_Ready(&Context_Type) < 0)
2024 if (PyType_Ready(&Editor_Type) < 0)
2027 if (PyType_Ready(&FileEditor_Type) < 0)
2030 if (PyType_Ready(&DirectoryEditor_Type) < 0)
2033 if (PyType_Ready(&TxDeltaWindowHandler_Type) < 0)
2036 if (PyType_Ready(&Stream_Type) < 0)
2039 if (PyType_Ready(&CommittedQueue_Type) < 0)
2042 #if ONLY_SINCE_SVN(1, 7)
2043 if (PyType_Ready(&Status3_Type) < 0)
2047 if (PyType_Ready(&Lock_Type) < 0)
2052 #if PY_MAJOR_VERSION >= 3
2053 static struct PyModuleDef moduledef = {
2054 PyModuleDef_HEAD_INIT,
2056 "Working Copies", /* m_doc */
2058 wc_methods, /* m_methods */
2059 NULL, /* m_reload */
2060 NULL, /* m_traverse */
2064 mod = PyModule_Create(&moduledef);
2066 mod = Py_InitModule3("wc", wc_methods, "Working Copies");
2071 PyModule_AddIntConstant(mod, "SCHEDULE_NORMAL", 0);
2072 PyModule_AddIntConstant(mod, "SCHEDULE_ADD", 1);
2073 PyModule_AddIntConstant(mod, "SCHEDULE_DELETE", 2);
2074 PyModule_AddIntConstant(mod, "SCHEDULE_REPLACE", 3);
2076 #if ONLY_SINCE_SVN(1, 5)
2077 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_POSTPONE",
2078 svn_wc_conflict_choose_postpone);
2079 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_BASE",
2080 svn_wc_conflict_choose_base);
2081 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_FULL",
2082 svn_wc_conflict_choose_theirs_full);
2083 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_FULL",
2084 svn_wc_conflict_choose_mine_full);
2085 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_CONFLICT",
2086 svn_wc_conflict_choose_theirs_conflict);
2087 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_CONFLICT",
2088 svn_wc_conflict_choose_mine_conflict);
2089 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MERGED",
2090 svn_wc_conflict_choose_merged);
2093 PyModule_AddIntConstant(mod, "STATUS_NONE", svn_wc_status_none);
2094 PyModule_AddIntConstant(mod, "STATUS_UNVERSIONED", svn_wc_status_unversioned);
2095 PyModule_AddIntConstant(mod, "STATUS_NORMAL", svn_wc_status_normal);
2096 PyModule_AddIntConstant(mod, "STATUS_ADDED", svn_wc_status_added);
2097 PyModule_AddIntConstant(mod, "STATUS_MISSING", svn_wc_status_missing);
2098 PyModule_AddIntConstant(mod, "STATUS_DELETED", svn_wc_status_deleted);
2099 PyModule_AddIntConstant(mod, "STATUS_REPLACED", svn_wc_status_replaced);
2100 PyModule_AddIntConstant(mod, "STATUS_MODIFIED", svn_wc_status_modified);
2101 PyModule_AddIntConstant(mod, "STATUS_MERGED", svn_wc_status_merged);
2102 PyModule_AddIntConstant(mod, "STATUS_CONFLICTED", svn_wc_status_conflicted);
2103 PyModule_AddIntConstant(mod, "STATUS_IGNORED", svn_wc_status_ignored);
2104 PyModule_AddIntConstant(mod, "STATUS_OBSTRUCTED", svn_wc_status_obstructed);
2105 PyModule_AddIntConstant(mod, "STATUS_EXTERNAL", svn_wc_status_external);
2106 PyModule_AddIntConstant(mod, "STATUS_INCOMPLETE", svn_wc_status_incomplete);
2108 PyModule_AddIntConstant(mod, "TRANSLATE_FROM_NF", SVN_WC_TRANSLATE_FROM_NF);
2109 PyModule_AddIntConstant(mod, "TRANSLATE_TO_NF", SVN_WC_TRANSLATE_TO_NF);
2110 PyModule_AddIntConstant(mod, "TRANSLATE_FORCE_EOL_REPAIR", SVN_WC_TRANSLATE_FORCE_EOL_REPAIR);
2111 PyModule_AddIntConstant(mod, "TRANSLATE_NO_OUTPUT_CLEANUP", SVN_WC_TRANSLATE_NO_OUTPUT_CLEANUP);
2112 PyModule_AddIntConstant(mod, "TRANSLATE_FORCE_COPY", SVN_WC_TRANSLATE_FORCE_COPY);
2113 PyModule_AddIntConstant(mod, "TRANSLATE_USE_GLOBAL_TMP", SVN_WC_TRANSLATE_USE_GLOBAL_TMP);
2115 #if ONLY_SINCE_SVN(1, 5)
2116 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_POSTPONE", svn_wc_conflict_choose_postpone);
2117 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_BASE", svn_wc_conflict_choose_base);
2118 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_FULL", svn_wc_conflict_choose_theirs_full);
2119 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_FULL", svn_wc_conflict_choose_mine_full);
2120 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_CONFLICT", svn_wc_conflict_choose_theirs_conflict);
2121 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_CONFLICT", svn_wc_conflict_choose_mine_conflict);
2122 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MERGED", svn_wc_conflict_choose_merged);
2125 PyModule_AddObject(mod, "Adm", (PyObject *)&Adm_Type);
2126 Py_INCREF(&Adm_Type);
2128 PyModule_AddObject(mod, "CommittedQueue", (PyObject *)&CommittedQueue_Type);
2129 Py_INCREF(&CommittedQueue_Type);
2131 #if ONLY_SINCE_SVN(1, 7)
2132 PyModule_AddObject(mod, "Context", (PyObject *)&Context_Type);
2133 Py_INCREF(&Context_Type);
2139 #if PY_MAJOR_VERSION >= 3
2143 return moduleinit();