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>
36 #if ONLY_SINCE_SVN(1, 5)
37 #define REPORTER_T svn_ra_reporter3_t
39 #define REPORTER_T svn_ra_reporter2_t
42 static PyTypeObject Entry_Type;
43 static PyTypeObject Status_Type;
44 static PyTypeObject Adm_Type;
46 static PyObject *py_entry(const svn_wc_entry_t *entry);
47 static PyObject *py_status(const svn_wc_status2_t *status);
49 #if ONLY_BEFORE_SVN(1, 5)
50 struct svn_wc_committed_queue_t
53 apr_array_header_t *queue;
54 svn_boolean_t have_recursive;
58 typedef struct svn_wc_committed_queue_t svn_wc_committed_queue_t;
64 svn_wc_adm_access_t *adm_access;
65 svn_boolean_t recurse;
66 svn_boolean_t remove_lock;
67 apr_array_header_t *wcprop_changes;
68 unsigned char *digest;
69 } committed_queue_item_t;
74 svn_wc_committed_queue_t *svn_wc_committed_queue_create(apr_pool_t *pool)
76 svn_wc_committed_queue_t *q;
78 q = apr_palloc(pool, sizeof(*q));
80 q->queue = apr_array_make(pool, 1, sizeof(committed_queue_item_t *));
81 q->have_recursive = FALSE;
89 svn_error_t *svn_wc_queue_committed(svn_wc_committed_queue_t **queue,
91 svn_wc_adm_access_t *adm_access,
92 svn_boolean_t recurse,
93 apr_array_header_t *wcprop_changes,
94 svn_boolean_t remove_lock,
95 svn_boolean_t remove_changelist,
96 const unsigned char *digest,
97 apr_pool_t *scratch_pool)
99 committed_queue_item_t *cqi;
101 (*queue)->have_recursive |= recurse;
103 /* Use the same pool as the one QUEUE was allocated in,
104 to prevent lifetime issues. Intermediate operations
105 should use SCRATCH_POOL. */
107 /* Add to the array with paths and options */
108 cqi = apr_palloc((*queue)->pool, sizeof(*cqi));
110 cqi->adm_access = adm_access;
111 cqi->recurse = recurse;
112 cqi->remove_lock = remove_lock;
113 cqi->wcprop_changes = wcprop_changes;
114 cqi->digest = digest;
116 APR_ARRAY_PUSH((*queue)->queue, committed_queue_item_t *) = cqi;
126 svn_wc_committed_queue_t *queue;
127 } CommittedQueueObject;
128 static PyTypeObject CommittedQueue_Type;
130 #if ONLY_SINCE_SVN(1, 5)
131 static svn_error_t *py_ra_report_set_path(void *baton, const char *path, svn_revnum_t revision, svn_depth_t depth, int start_empty, const char *lock_token, apr_pool_t *pool)
133 PyObject *self = (PyObject *)baton, *py_lock_token, *ret;
134 PyGILState_STATE state = PyGILState_Ensure();
135 if (lock_token == NULL) {
136 py_lock_token = Py_None;
137 Py_INCREF(py_lock_token);
139 py_lock_token = PyString_FromString(lock_token);
141 ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision, start_empty, py_lock_token, depth);
142 Py_DECREF(py_lock_token);
143 CB_CHECK_PYRETVAL(ret);
145 PyGILState_Release(state);
149 static svn_error_t *py_ra_report_link_path(void *report_baton, const char *path, const char *url, svn_revnum_t revision, svn_depth_t depth, int start_empty, const char *lock_token, apr_pool_t *pool)
151 PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token;
152 PyGILState_STATE state = PyGILState_Ensure();
153 if (lock_token == NULL) {
154 py_lock_token = Py_None;
155 Py_INCREF(py_lock_token);
157 py_lock_token = PyString_FromString(lock_token);
159 ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision, start_empty, py_lock_token, depth);
160 Py_DECREF(py_lock_token);
161 CB_CHECK_PYRETVAL(ret);
163 PyGILState_Release(state);
169 static svn_error_t *py_ra_report_set_path(void *baton, const char *path, svn_revnum_t revision, int start_empty, const char *lock_token, apr_pool_t *pool)
171 PyObject *self = (PyObject *)baton, *py_lock_token, *ret;
172 PyGILState_STATE state = PyGILState_Ensure();
173 if (lock_token == NULL) {
174 py_lock_token = Py_None;
175 Py_INCREF(py_lock_token);
177 py_lock_token = PyString_FromString(lock_token);
179 ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision, start_empty, py_lock_token, svn_depth_infinity);
180 CB_CHECK_PYRETVAL(ret);
182 PyGILState_Release(state);
186 static svn_error_t *py_ra_report_link_path(void *report_baton, const char *path, const char *url, svn_revnum_t revision, int start_empty, const char *lock_token, apr_pool_t *pool)
188 PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token;
189 PyGILState_STATE state = PyGILState_Ensure();
190 if (lock_token == NULL) {
191 py_lock_token = Py_None;
192 Py_INCREF(py_lock_token);
194 py_lock_token = PyString_FromString(lock_token);
196 ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision, start_empty, py_lock_token, svn_depth_infinity);
197 CB_CHECK_PYRETVAL(ret);
199 PyGILState_Release(state);
206 static svn_error_t *py_ra_report_delete_path(void *baton, const char *path, apr_pool_t *pool)
208 PyObject *self = (PyObject *)baton, *ret;
209 PyGILState_STATE state = PyGILState_Ensure();
210 ret = PyObject_CallMethod(self, "delete_path", "s", path);
211 CB_CHECK_PYRETVAL(ret);
213 PyGILState_Release(state);
217 static svn_error_t *py_ra_report_finish(void *baton, apr_pool_t *pool)
219 PyObject *self = (PyObject *)baton, *ret;
220 PyGILState_STATE state = PyGILState_Ensure();
221 ret = PyObject_CallMethod(self, "finish", "");
222 CB_CHECK_PYRETVAL(ret);
224 PyGILState_Release(state);
228 static svn_error_t *py_ra_report_abort(void *baton, apr_pool_t *pool)
230 PyObject *self = (PyObject *)baton, *ret;
231 PyGILState_STATE state = PyGILState_Ensure();
232 ret = PyObject_CallMethod(self, "abort", "");
233 CB_CHECK_PYRETVAL(ret);
235 PyGILState_Release(state);
239 static const REPORTER_T py_ra_reporter = {
240 py_ra_report_set_path,
241 py_ra_report_delete_path,
242 py_ra_report_link_path,
250 * Get runtime libsvn_wc version information.
252 * :return: tuple with major, minor, patch version number and tag.
254 static PyObject *version(PyObject *self)
256 const svn_version_t *ver = svn_wc_version();
257 return Py_BuildValue("(iiis)", ver->major, ver->minor,
258 ver->patch, ver->tag);
261 SVN_VERSION_DEFINE(svn_api_version);
264 * Get compile-time libsvn_wc version information.
266 * :return: tuple with major, minor, patch version number and tag.
268 static PyObject *api_version(PyObject *self)
270 const svn_version_t *ver = &svn_api_version;
271 return Py_BuildValue("(iiis)", ver->major, ver->minor,
272 ver->patch, ver->tag);
275 static svn_error_t *py_wc_found_entry(const char *path, const svn_wc_entry_t *entry, void *walk_baton, apr_pool_t *pool)
278 PyObject *callbacks = (PyObject *)walk_baton;
279 PyGILState_STATE state = PyGILState_Ensure();
280 if (PyTuple_Check(callbacks)) {
281 fn = PyTuple_GET_ITEM(callbacks, 0);
283 fn = (PyObject *)walk_baton;
285 ret = PyObject_CallFunction(fn, "sO", path, py_entry(entry));
286 CB_CHECK_PYRETVAL(ret);
288 PyGILState_Release(state);
292 #if ONLY_SINCE_SVN(1, 5)
294 svn_error_t *py_wc_handle_error(const char *path, svn_error_t *err, void *walk_baton, apr_pool_t *pool)
298 PyGILState_STATE state;
299 PyObject *callbacks = (PyObject *)walk_baton;
300 if (PyTuple_Check(callbacks)) {
301 fn = PyTuple_GET_ITEM(callbacks, 1);
305 state = PyGILState_Ensure();
306 py_err = PyErr_NewSubversionException(err);
307 ret = PyObject_CallFunction(fn, "sO", path, py_err);
308 CB_CHECK_PYRETVAL(ret);
310 PyGILState_Release(state);
315 static svn_wc_entry_callbacks2_t py_wc_entry_callbacks2 = {
320 static svn_wc_entry_callbacks_t py_wc_entry_callbacks = {
327 void py_wc_notify_func(void *baton, const svn_wc_notify_t *notify, apr_pool_t *pool)
329 PyObject *func = baton, *ret;
333 if (notify->err != NULL) {
334 PyObject *excval = PyErr_NewSubversionException(notify->err);
335 ret = PyObject_CallFunction(func, "O", excval);
338 /* If ret was NULL, the cancel func should abort the operation. */
345 svn_wc_entry_t entry;
348 static void entry_dealloc(PyObject *self)
350 apr_pool_destroy(((EntryObject *)self)->pool);
354 static PyMemberDef entry_members[] = {
355 { "name", T_STRING, offsetof(EntryObject, entry.name), READONLY,
357 { "copyfrom_url", T_STRING, offsetof(EntryObject, entry.copyfrom_url), READONLY,
358 "Copyfrom location" },
359 { "copyfrom_rev", T_LONG, offsetof(EntryObject, entry.copyfrom_rev), READONLY,
360 "Copyfrom revision" },
361 { "uuid", T_STRING, offsetof(EntryObject, entry.uuid), READONLY,
362 "UUID of repository" },
363 { "url", T_STRING, offsetof(EntryObject, entry.url), READONLY,
364 "URL in repository" },
365 { "repos", T_STRING, offsetof(EntryObject, entry.repos), READONLY,
366 "Canonical repository URL" },
367 { "schedule", T_INT, offsetof(EntryObject, entry.schedule), READONLY,
368 "Scheduling (add, replace, delete, etc)" },
369 { "kind", T_INT, offsetof(EntryObject, entry.kind), READONLY,
370 "Kind of file (file, dir, etc)" },
371 { "revision", T_LONG, offsetof(EntryObject, entry.revision), READONLY,
373 { "cmt_rev", T_LONG, offsetof(EntryObject, entry.cmt_rev), READONLY,
374 "Last revision this was changed" },
375 { "checksum", T_STRING, offsetof(EntryObject, entry.checksum), READONLY,
376 "Hex MD5 checksum for the untranslated text base file" },
377 { "cmt_date", T_LONG, offsetof(EntryObject, entry.cmt_date), READONLY,
378 "Last date this was changed" },
379 { "cmt_author", T_STRING, offsetof(EntryObject, entry.cmt_author), READONLY,
380 "Last commit author of this item" },
384 static PyTypeObject Entry_Type = {
385 PyObject_HEAD_INIT(NULL) 0,
386 "wc.Entry", /* const char *tp_name; For printing, in format "<module>.<name>" */
388 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
390 /* Methods to implement standard operations */
392 entry_dealloc, /* destructor tp_dealloc; */
393 NULL, /* printfunc tp_print; */
394 NULL, /* getattrfunc tp_getattr; */
395 NULL, /* setattrfunc tp_setattr; */
396 NULL, /* cmpfunc tp_compare; */
397 NULL, /* reprfunc tp_repr; */
399 /* Method suites for standard classes */
401 NULL, /* PyNumberMethods *tp_as_number; */
402 NULL, /* PySequenceMethods *tp_as_sequence; */
403 NULL, /* PyMappingMethods *tp_as_mapping; */
405 /* More standard operations (here for binary compatibility) */
407 NULL, /* hashfunc tp_hash; */
408 NULL, /* ternaryfunc tp_call; */
409 NULL, /* reprfunc tp_str; */
410 NULL, /* getattrofunc tp_getattro; */
411 NULL, /* setattrofunc tp_setattro; */
413 /* Functions to access object as input/output buffer */
414 NULL, /* PyBufferProcs *tp_as_buffer; */
416 /* Flags to define presence of optional/expanded features */
417 0, /* long tp_flags; */
419 NULL, /* const char *tp_doc; Documentation string */
421 /* Assigned meaning in release 2.0 */
422 /* call function for all accessible objects */
423 NULL, /* traverseproc tp_traverse; */
425 /* delete references to contained objects */
426 NULL, /* inquiry tp_clear; */
428 /* Assigned meaning in release 2.1 */
429 /* rich comparisons */
430 NULL, /* richcmpfunc tp_richcompare; */
432 /* weak reference enabler */
433 0, /* Py_ssize_t tp_weaklistoffset; */
435 /* Added in release 2.2 */
437 NULL, /* getiterfunc tp_iter; */
438 NULL, /* iternextfunc tp_iternext; */
440 /* Attribute descriptor and subclassing stuff */
441 NULL, /* struct PyMethodDef *tp_methods; */
442 entry_members, /* struct PyMemberDef *tp_members; */
446 static PyObject *py_entry(const svn_wc_entry_t *entry)
450 ret = PyObject_New(EntryObject, &Entry_Type);
454 ret->pool = Pool(NULL);
455 if (ret->pool == NULL)
457 ret->entry = *svn_wc_entry_dup(entry, ret->pool);
458 return (PyObject *)ret;
464 svn_wc_status2_t status;
468 static void status_dealloc(PyObject *self)
470 apr_pool_destroy(((StatusObject *)self)->pool);
471 Py_XDECREF(((StatusObject *)self)->entry);
475 static PyMemberDef status_members[] = {
476 { "entry", T_OBJECT, offsetof(StatusObject, entry), READONLY,
477 "Can be NULL if not under version control." },
478 { "locked", T_BOOL, offsetof(StatusObject, status.locked), READONLY,
479 "a directory can be 'locked' if a working copy update was interrupted." },
480 { "copied", T_BOOL, offsetof(StatusObject, status.copied), READONLY,
481 "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.)." },
482 { "switched", T_BOOL, offsetof(StatusObject, status.switched), READONLY,
483 "a file or directory can be 'switched' if the switch command has been used." },
484 { "url", T_STRING, offsetof(StatusObject, status.url), READONLY,
485 "URL (actual or expected) in repository" },
486 { "revision", T_LONG, offsetof(StatusObject, status.ood_last_cmt_rev), READONLY,
487 "Set to the youngest committed revision, or SVN_INVALID_REVNUM if not out of date.", },
488 { "kind", T_INT, offsetof(StatusObject, status.ood_kind), READONLY,
489 "Set to the node kind of the youngest commit, or svn_node_none if not out of date.", },
490 { "status", T_INT, offsetof(StatusObject, status.text_status), READONLY,
491 "The status of the entry.", },
495 static PyTypeObject Status_Type = {
496 PyObject_HEAD_INIT(NULL) 0,
497 "wc.Status", /* const char *tp_name; For printing, in format "<module>.<name>" */
498 sizeof(StatusObject),
499 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
501 /* Methods to implement standard operations */
503 status_dealloc, /* destructor tp_dealloc; */
504 NULL, /* printfunc tp_print; */
505 NULL, /* getattrfunc tp_getattr; */
506 NULL, /* setattrfunc tp_setattr; */
507 NULL, /* cmpfunc tp_compare; */
508 NULL, /* reprfunc tp_repr; */
510 /* Method suites for standard classes */
512 NULL, /* PyNumberMethods *tp_as_number; */
513 NULL, /* PySequenceMethods *tp_as_sequence; */
514 NULL, /* PyMappingMethods *tp_as_mapping; */
516 /* More standard operations (here for binary compatibility) */
518 NULL, /* hashfunc tp_hash; */
519 NULL, /* ternaryfunc tp_call; */
520 NULL, /* reprfunc tp_str; */
521 NULL, /* getattrofunc tp_getattro; */
522 NULL, /* setattrofunc tp_setattro; */
524 /* Functions to access object as input/output buffer */
525 NULL, /* PyBufferProcs *tp_as_buffer; */
527 /* Flags to define presence of optional/expanded features */
528 0, /* long tp_flags; */
530 "Working copy status object", /* const char *tp_doc; Documentation string */
532 /* Assigned meaning in release 2.0 */
533 /* call function for all accessible objects */
534 NULL, /* traverseproc tp_traverse; */
536 /* delete references to contained objects */
537 NULL, /* inquiry tp_clear; */
539 /* Assigned meaning in release 2.1 */
540 /* rich comparisons */
541 NULL, /* richcmpfunc tp_richcompare; */
543 /* weak reference enabler */
544 0, /* Py_ssize_t tp_weaklistoffset; */
546 /* Added in release 2.2 */
548 NULL, /* getiterfunc tp_iter; */
549 NULL, /* iternextfunc tp_iternext; */
551 /* Attribute descriptor and subclassing stuff */
552 NULL, /* struct PyMethodDef *tp_methods; */
553 status_members, /* struct PyMemberDef *tp_members; */
557 static PyObject *py_status(const svn_wc_status2_t *status)
560 svn_wc_status2_t *dup_status;
562 ret = PyObject_New(StatusObject, &Status_Type);
566 ret->pool = Pool(NULL);
567 if (ret->pool == NULL) {
572 dup_status = svn_wc_dup_status2(status, ret->pool);
573 if (dup_status == NULL)
578 ret->status = *dup_status;
580 ret->entry = py_entry(ret->status.entry);
581 return (PyObject *)ret;
586 svn_wc_adm_access_t *adm;
590 #define ADM_CHECK_CLOSED(adm_obj) \
591 if (adm_obj->adm == NULL) { \
592 PyErr_SetString(PyExc_RuntimeError, "WorkingCopy instance already closed"); \
596 static PyObject *adm_init(PyTypeObject *self, PyObject *args, PyObject *kwargs)
598 PyObject *associated;
600 bool write_lock=false;
602 svn_wc_adm_access_t *parent_wc;
605 char *kwnames[] = { "associated", "path", "write_lock", "depth", NULL };
607 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os|bi", kwnames,
608 &associated, &path, &write_lock, &depth))
611 ret = PyObject_New(AdmObject, &Adm_Type);
615 ret->pool = Pool(NULL);
616 if (ret->pool == NULL)
618 if (associated == Py_None) {
621 parent_wc = ((AdmObject *)associated)->adm;
623 Py_BEGIN_ALLOW_THREADS
624 err = svn_wc_adm_open3(&ret->adm, parent_wc,
625 svn_dirent_canonicalize(path, ret->pool),
626 write_lock, depth, py_cancel_check, NULL,
631 handle_svn_error(err);
632 svn_error_clear(err);
637 return (PyObject *)ret;
640 static PyObject *adm_access_path(PyObject *self)
642 AdmObject *admobj = (AdmObject *)self;
643 ADM_CHECK_CLOSED(admobj);
644 return PyString_FromString(svn_wc_adm_access_path(admobj->adm));
647 static PyObject *adm_locked(PyObject *self)
649 AdmObject *admobj = (AdmObject *)self;
650 ADM_CHECK_CLOSED(admobj);
651 return PyBool_FromLong(svn_wc_adm_locked(admobj->adm));
654 static PyObject *adm_prop_get(PyObject *self, PyObject *args)
657 AdmObject *admobj = (AdmObject *)self;
658 const svn_string_t *value;
659 apr_pool_t *temp_pool;
662 if (!PyArg_ParseTuple(args, "ss", &name, &path))
665 ADM_CHECK_CLOSED(admobj);
667 temp_pool = Pool(NULL);
668 if (temp_pool == NULL)
670 RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_get(&value, name, path, admobj->adm, temp_pool));
671 if (value == NULL || value->data == NULL) {
675 ret = PyString_FromStringAndSize(value->data, value->len);
677 apr_pool_destroy(temp_pool);
681 static PyObject *adm_prop_set(PyObject *self, PyObject *args)
683 char *name, *value, *path;
684 AdmObject *admobj = (AdmObject *)self;
685 bool skip_checks=false;
686 apr_pool_t *temp_pool;
688 svn_string_t *cvalue;
689 PyObject *notify_func = Py_None;
691 if (!PyArg_ParseTuple(args, "sz#s|bO", &name, &value, &vallen, &path, &skip_checks,
695 ADM_CHECK_CLOSED(admobj);
697 temp_pool = Pool(NULL);
698 if (temp_pool == NULL)
703 cvalue = svn_string_ncreate(value, vallen, temp_pool);
705 #if ONLY_SINCE_SVN(1, 6)
706 RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_set3(name, cvalue, path, admobj->adm,
707 skip_checks, py_wc_notify_func, (void *)notify_func,
710 RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_set2(name, cvalue, path, admobj->adm,
711 skip_checks, temp_pool));
713 apr_pool_destroy(temp_pool);
718 static PyObject *adm_entries_read(PyObject *self, PyObject *args)
721 AdmObject *admobj = (AdmObject *)self;
722 apr_pool_t *temp_pool;
723 bool show_hidden=false;
724 apr_hash_index_t *idx;
727 svn_wc_entry_t *entry;
728 PyObject *py_entries, *obj;
730 if (!PyArg_ParseTuple(args, "|b", &show_hidden))
733 ADM_CHECK_CLOSED(admobj);
735 temp_pool = Pool(NULL);
736 if (temp_pool == NULL)
738 RUN_SVN_WITH_POOL(temp_pool, svn_wc_entries_read(&entries, admobj->adm,
739 show_hidden, temp_pool));
740 py_entries = PyDict_New();
741 if (py_entries == NULL) {
742 apr_pool_destroy(temp_pool);
745 idx = apr_hash_first(temp_pool, entries);
746 while (idx != NULL) {
747 apr_hash_this(idx, (const void **)&key, &klen, (void **)&entry);
752 obj = py_entry(entry);
754 PyDict_SetItemString(py_entries, key, obj);
756 idx = apr_hash_next(idx);
758 apr_pool_destroy(temp_pool);
762 static PyObject *adm_walk_entries(PyObject *self, PyObject *args)
766 bool show_hidden=false;
767 apr_pool_t *temp_pool;
768 AdmObject *admobj = (AdmObject *)self;
769 svn_depth_t depth = svn_depth_infinity;
771 if (!PyArg_ParseTuple(args, "sO|bi", &path, &callbacks, &show_hidden, &depth))
774 ADM_CHECK_CLOSED(admobj);
776 temp_pool = Pool(NULL);
777 if (temp_pool == NULL)
779 #if ONLY_SINCE_SVN(1, 5)
780 RUN_SVN_WITH_POOL(temp_pool, svn_wc_walk_entries3(
781 svn_dirent_canonicalize(path, temp_pool), admobj->adm,
782 &py_wc_entry_callbacks2, (void *)callbacks,
783 depth, show_hidden, py_cancel_check, NULL,
786 if (depth != svn_depth_infinity) {
787 PyErr_SetString(PyExc_NotImplementedError,
788 "depth != infinity not supported for svn < 1.5");
789 apr_pool_destroy(temp_pool);
792 RUN_SVN_WITH_POOL(temp_pool, svn_wc_walk_entries2(
793 svn_dirent_canonicalize(path, temp_pool), admobj->adm,
794 &py_wc_entry_callbacks, (void *)callbacks,
795 show_hidden, py_cancel_check, NULL,
798 apr_pool_destroy(temp_pool);
803 static PyObject *adm_entry(PyObject *self, PyObject *args)
806 bool show_hidden=false;
807 apr_pool_t *temp_pool;
808 AdmObject *admobj = (AdmObject *)self;
809 const svn_wc_entry_t *entry;
812 if (!PyArg_ParseTuple(args, "s|b", &path, &show_hidden))
815 ADM_CHECK_CLOSED(admobj);
817 temp_pool = Pool(NULL);
818 if (temp_pool == NULL)
820 RUN_SVN_WITH_POOL(temp_pool, svn_wc_entry(&entry, svn_dirent_canonicalize(path, temp_pool), admobj->adm, show_hidden, temp_pool));
823 PyErr_Format(PyExc_KeyError, "No such entry '%s'", path);
826 ret = py_entry(entry);
829 apr_pool_destroy(temp_pool);
833 static PyObject *adm_get_prop_diffs(PyObject *self, PyObject *args)
836 apr_pool_t *temp_pool;
837 apr_array_header_t *propchanges;
838 apr_hash_t *original_props;
839 AdmObject *admobj = (AdmObject *)self;
842 PyObject *py_propchanges, *py_orig_props, *pyval;
844 if (!PyArg_ParseTuple(args, "s", &path))
847 ADM_CHECK_CLOSED(admobj);
849 temp_pool = Pool(NULL);
850 if (temp_pool == NULL)
852 RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_prop_diffs(&propchanges, &original_props,
853 svn_dirent_canonicalize(path, temp_pool), admobj->adm, temp_pool));
854 py_propchanges = PyList_New(propchanges->nelts);
855 if (py_propchanges == NULL) {
856 apr_pool_destroy(temp_pool);
859 for (i = 0; i < propchanges->nelts; i++) {
860 el = APR_ARRAY_IDX(propchanges, i, svn_prop_t);
861 if (el.value != NULL)
862 pyval = Py_BuildValue("(sz#)", el.name, el.value->data, el.value->len);
864 pyval = Py_BuildValue("(sO)", el.name, Py_None);
866 apr_pool_destroy(temp_pool);
867 Py_DECREF(py_propchanges);
870 if (PyList_SetItem(py_propchanges, i, pyval) != 0) {
871 Py_DECREF(py_propchanges);
872 apr_pool_destroy(temp_pool);
876 py_orig_props = prop_hash_to_dict(original_props);
877 apr_pool_destroy(temp_pool);
878 if (py_orig_props == NULL) {
879 Py_DECREF(py_propchanges);
882 return Py_BuildValue("(NN)", py_propchanges, py_orig_props);
885 static PyObject *adm_add(PyObject *self, PyObject *args, PyObject *kwargs)
887 char *path, *copyfrom_url=NULL;
888 svn_revnum_t copyfrom_rev=-1;
889 char *kwnames[] = { "path", "copyfrom_url", "copyfrom_rev", "notify_func", "depth", NULL };
890 PyObject *notify_func=Py_None;
891 AdmObject *admobj = (AdmObject *)self;
892 apr_pool_t *temp_pool;
893 svn_depth_t depth = svn_depth_infinity;
895 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zlOi", kwnames, &path,
896 ©from_url, ©from_rev, ¬ify_func, &depth))
899 ADM_CHECK_CLOSED(admobj);
901 temp_pool = Pool(NULL);
902 if (temp_pool == NULL)
905 #if ONLY_SINCE_SVN(1, 6)
906 RUN_SVN_WITH_POOL(temp_pool, svn_wc_add3(
907 svn_dirent_canonicalize(path, temp_pool), admobj->adm,
908 depth, svn_uri_canonicalize(copyfrom_url, temp_pool),
909 copyfrom_rev, py_cancel_check, NULL,
914 if (depth != svn_depth_infinity) {
915 PyErr_SetString(PyExc_NotImplementedError, "depth != infinity not supported on svn < 1.6");
916 apr_pool_destroy(temp_pool);
919 RUN_SVN_WITH_POOL(temp_pool, svn_wc_add2(
920 svn_dirent_canonicalize(path, temp_pool), admobj->adm, copyfrom_url,
921 copyfrom_rev, py_cancel_check,
926 apr_pool_destroy(temp_pool);
931 static PyObject *adm_copy(PyObject *self, PyObject *args)
933 AdmObject *admobj = (AdmObject *)self;
935 PyObject *notify_func=Py_None;
936 apr_pool_t *temp_pool;
938 if (!PyArg_ParseTuple(args, "ss|O", &src, &dst, ¬ify_func))
941 ADM_CHECK_CLOSED(admobj);
943 temp_pool = Pool(NULL);
944 if (temp_pool == NULL)
946 RUN_SVN_WITH_POOL(temp_pool, svn_wc_copy2(src, admobj->adm, dst,
947 py_cancel_check, NULL,
948 py_wc_notify_func, (void *)notify_func,
950 apr_pool_destroy(temp_pool);
955 static PyObject *adm_delete(PyObject *self, PyObject *args, PyObject *kwargs)
957 AdmObject *admobj = (AdmObject *)self;
958 apr_pool_t *temp_pool;
959 char *kwnames[] = { "path", "notify_func", "keep_local",
962 PyObject *notify_func=Py_None;
963 bool keep_local = false;
965 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|Ob:delete", kwnames,
966 &path, ¬ify_func, &keep_local))
969 ADM_CHECK_CLOSED(admobj);
971 temp_pool = Pool(NULL);
972 if (temp_pool == NULL)
975 #if ONLY_SINCE_SVN(1, 5)
976 RUN_SVN_WITH_POOL(temp_pool, svn_wc_delete3(path, admobj->adm,
977 py_cancel_check, NULL,
978 py_wc_notify_func, (void *)notify_func,
983 PyErr_SetString(PyExc_NotImplementedError,
984 "keep_local not supported on Subversion < 1.5");
988 RUN_SVN_WITH_POOL(temp_pool, svn_wc_delete2(path, admobj->adm,
989 py_cancel_check, NULL,
990 py_wc_notify_func, (void *)notify_func,
993 apr_pool_destroy(temp_pool);
998 static PyObject *adm_crawl_revisions(PyObject *self, PyObject *args, PyObject *kwargs)
1002 bool restore_files=true, recurse=true, use_commit_times=true;
1003 PyObject *notify_func=Py_None;
1004 apr_pool_t *temp_pool;
1005 AdmObject *admobj = (AdmObject *)self;
1006 svn_wc_traversal_info_t *traversal_info;
1007 svn_boolean_t depth_compatibility_trick = FALSE;
1008 svn_boolean_t honor_depth_exclude = FALSE;
1009 char *kwnames[] = { "path", "reporter", "restore_files", "recurse", "use_commit_times", "notify_func", "depth_compatibility_trick", "honor_depth_exclude,", NULL };
1011 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|bbbObb", kwnames, &path,
1012 &reporter, &restore_files, &recurse, &use_commit_times,
1013 ¬ify_func, &depth_compatibility_trick, &honor_depth_exclude))
1016 ADM_CHECK_CLOSED(admobj);
1018 temp_pool = Pool(NULL);
1019 if (temp_pool == NULL)
1021 traversal_info = svn_wc_init_traversal_info(temp_pool);
1022 #if ONLY_SINCE_SVN(1, 6)
1023 RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions4(svn_dirent_canonicalize(path, temp_pool), admobj->adm,
1024 &py_ra_reporter, (void *)reporter,
1025 restore_files, recurse?svn_depth_infinity:svn_depth_files,
1026 honor_depth_exclude,
1027 depth_compatibility_trick, use_commit_times,
1028 py_wc_notify_func, (void *)notify_func,
1029 traversal_info, temp_pool));
1030 #elif ONLY_SINCE_SVN(1, 5)
1031 RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions3(svn_dirent_canonicalize(path, temp_pool), admobj->adm,
1032 &py_ra_reporter, (void *)reporter,
1033 restore_files, recurse?svn_depth_infinity:svn_depth_files,
1034 depth_compatibility_trick, use_commit_times,
1035 py_wc_notify_func, (void *)notify_func,
1036 traversal_info, temp_pool));
1038 RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions2(svn_dirent_canonicalize(path, temp_pool), admobj->adm,
1039 &py_ra_reporter, (void *)reporter,
1040 restore_files, recurse, use_commit_times,
1041 py_wc_notify_func, (void *)notify_func,
1042 traversal_info, temp_pool));
1044 apr_pool_destroy(temp_pool);
1049 static void wc_done_handler(void *self)
1051 AdmObject *admobj = (AdmObject *)self;
1056 static PyObject *adm_get_update_editor(PyObject *self, PyObject *args)
1059 bool use_commit_times=true, recurse=true;
1060 PyObject * notify_func=Py_None;
1061 char *diff3_cmd=NULL;
1062 const svn_delta_editor_t *editor;
1063 AdmObject *admobj = (AdmObject *)self;
1066 svn_revnum_t *latest_revnum;
1068 svn_boolean_t allow_unver_obstructions = FALSE;
1069 svn_boolean_t depth_is_sticky = FALSE;
1071 if (!PyArg_ParseTuple(args, "s|bbOzbb", &target, &use_commit_times,
1072 &recurse, ¬ify_func, &diff3_cmd, &depth_is_sticky,
1073 &allow_unver_obstructions))
1076 ADM_CHECK_CLOSED(admobj);
1081 latest_revnum = (svn_revnum_t *)apr_palloc(pool, sizeof(svn_revnum_t));
1082 Py_BEGIN_ALLOW_THREADS
1083 #if ONLY_SINCE_SVN(1, 5)
1084 /* FIXME: Support all values of depth */
1085 /* FIXME: Support fetch_func */
1086 /* FIXME: Support conflict func */
1087 err = svn_wc_get_update_editor3(latest_revnum, admobj->adm, target,
1088 use_commit_times, recurse?svn_depth_infinity:svn_depth_files,
1089 depth_is_sticky, allow_unver_obstructions,
1090 py_wc_notify_func, (void *)notify_func,
1091 py_cancel_check, NULL,
1092 NULL, NULL, NULL, NULL,
1093 diff3_cmd, NULL, &editor, &edit_baton,
1096 if (allow_unver_obstructions) {
1097 PyErr_SetString(PyExc_NotImplementedError,
1098 "allow_unver_obstructions is not supported in svn < 1.5");
1099 apr_pool_destroy(pool);
1100 PyEval_RestoreThread(_save);
1103 if (depth_is_sticky) {
1104 PyErr_SetString(PyExc_NotImplementedError,
1105 "depth_is_sticky is not supported in svn < 1.5");
1106 apr_pool_destroy(pool);
1107 PyEval_RestoreThread(_save);
1110 err = svn_wc_get_update_editor2(latest_revnum, admobj->adm, target,
1111 use_commit_times, recurse, py_wc_notify_func, (void *)notify_func,
1112 py_cancel_check, NULL, diff3_cmd, &editor, &edit_baton,
1115 Py_END_ALLOW_THREADS
1117 handle_svn_error(err);
1118 svn_error_clear(err);
1119 apr_pool_destroy(pool);
1123 return new_editor_object(NULL, editor, edit_baton, pool, &Editor_Type,
1124 wc_done_handler, admobj, NULL);
1127 static bool py_dict_to_wcprop_changes(PyObject *dict, apr_pool_t *pool, apr_array_header_t **ret)
1129 PyObject *key, *val;
1132 if (dict == Py_None) {
1137 if (!PyDict_Check(dict)) {
1138 PyErr_SetString(PyExc_TypeError, "Expected dictionary with property changes");
1142 *ret = apr_array_make(pool, PyDict_Size(dict), sizeof(char *));
1144 while (PyDict_Next(dict, &idx, &key, &val)) {
1145 svn_prop_t *prop = apr_palloc(pool, sizeof(svn_prop_t));
1146 prop->name = py_object_to_svn_string(key, pool);
1147 if (prop->name == NULL) {
1150 if (val == Py_None) {
1153 if (!PyBytes_Check(val)) {
1154 PyErr_SetString(PyExc_TypeError, "property values should be bytes");
1157 prop->value = svn_string_ncreate(PyBytes_AsString(val), PyBytes_Size(val), pool);
1159 APR_ARRAY_PUSH(*ret, svn_prop_t *) = prop;
1165 static PyObject *adm_has_binary_prop(PyObject *self, PyObject *args)
1168 svn_boolean_t binary;
1169 AdmObject *admobj = (AdmObject *)self;
1170 apr_pool_t *temp_pool;
1172 if (!PyArg_ParseTuple(args, "s", &path))
1175 ADM_CHECK_CLOSED(admobj);
1177 temp_pool = Pool(NULL);
1178 if (temp_pool == NULL)
1181 RUN_SVN_WITH_POOL(temp_pool, svn_wc_has_binary_prop(&binary, path, admobj->adm, temp_pool));
1183 apr_pool_destroy(temp_pool);
1185 return PyBool_FromLong(binary);
1188 static PyObject *adm_process_committed(PyObject *self, PyObject *args, PyObject *kwargs)
1190 char *path, *rev_date = NULL, *rev_author = NULL;
1191 bool recurse, remove_lock = false;
1192 unsigned char *digest = NULL;
1193 svn_revnum_t new_revnum;
1194 PyObject *py_wcprop_changes = Py_None;
1195 apr_array_header_t *wcprop_changes = NULL;
1196 AdmObject *admobj = (AdmObject *)self;
1197 apr_pool_t *temp_pool;
1199 svn_boolean_t remove_changelist = FALSE;
1200 char *kwnames[] = { "path", "recurse", "new_revnum", "rev_date", "rev_author",
1201 "wcprop_changes", "remove_lock", "digest", "remove_changelist", NULL };
1203 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sblzz|Obz#b", kwnames,
1204 &path, &recurse, &new_revnum, &rev_date,
1205 &rev_author, &py_wcprop_changes,
1206 &remove_lock, &digest, &digest_len, &remove_changelist))
1209 PyErr_WarnEx(PyExc_DeprecationWarning, "process_committed is deprecated. Use process_committed_queue instead.", 2);
1212 ADM_CHECK_CLOSED(admobj);
1214 temp_pool = Pool(NULL);
1215 if (temp_pool == NULL)
1218 if (!py_dict_to_wcprop_changes(py_wcprop_changes, temp_pool, &wcprop_changes)) {
1219 apr_pool_destroy(temp_pool);
1223 #if ONLY_SINCE_SVN(1, 6)
1224 RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed4(
1225 svn_dirent_canonicalize(path, temp_pool), admobj->adm, recurse, new_revnum,
1226 rev_date, rev_author, wcprop_changes,
1227 remove_lock, remove_changelist, digest, temp_pool));
1229 if (remove_changelist) {
1230 PyErr_SetString(PyExc_NotImplementedError, "remove_changelist only supported in svn < 1.6");
1231 apr_pool_destroy(temp_pool);
1234 RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(svn_dirent_canonicalize(path, temp_pool), admobj->adm, recurse, new_revnum,
1235 rev_date, rev_author, wcprop_changes,
1236 remove_lock, digest, temp_pool));
1239 apr_pool_destroy(temp_pool);
1244 static PyObject *adm_close(PyObject *self)
1246 AdmObject *admobj = (AdmObject *)self;
1247 if (admobj->adm != NULL) {
1248 #if ONLY_SINCE_SVN(1, 6)
1249 apr_pool_t *temp_pool = Pool(NULL);
1250 Py_BEGIN_ALLOW_THREADS
1251 svn_wc_adm_close2(admobj->adm, temp_pool);
1252 apr_pool_destroy(temp_pool);
1254 Py_BEGIN_ALLOW_THREADS
1255 svn_wc_adm_close(admobj->adm);
1257 Py_END_ALLOW_THREADS
1264 static void adm_dealloc(PyObject *self)
1266 apr_pool_destroy(((AdmObject *)self)->pool);
1270 static PyObject *adm_repr(PyObject *self)
1272 AdmObject *admobj = (AdmObject *)self;
1274 if (admobj->adm == NULL) {
1275 return PyString_FromFormat("<wc.WorkingCopy (closed) at 0x%p>", admobj);
1277 return PyString_FromFormat("<wc.WorkingCopy at '%s'>",
1278 svn_wc_adm_access_path(admobj->adm));
1282 static PyObject *adm_remove_lock(PyObject *self, PyObject *args)
1285 AdmObject *admobj = (AdmObject *)self;
1286 apr_pool_t *temp_pool;
1288 if (!PyArg_ParseTuple(args, "s", &path))
1291 ADM_CHECK_CLOSED(admobj);
1293 temp_pool = Pool(NULL);
1294 if (temp_pool == NULL)
1297 RUN_SVN_WITH_POOL(temp_pool, svn_wc_remove_lock(path, admobj->adm, temp_pool))
1299 apr_pool_destroy(temp_pool);
1304 static PyObject *get_ancestry(PyObject *self, PyObject *args)
1309 apr_pool_t *temp_pool;
1310 AdmObject *admobj = (AdmObject *)self;
1312 if (!PyArg_ParseTuple(args, "s", &path))
1315 ADM_CHECK_CLOSED(admobj);
1317 temp_pool = Pool(NULL);
1318 if (temp_pool == NULL)
1321 RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_ancestry(&url, &rev, path, admobj->adm, temp_pool));
1323 apr_pool_destroy(temp_pool);
1325 return Py_BuildValue("(si)", url, rev);
1328 static PyObject *maybe_set_repos_root(PyObject *self, PyObject *args)
1331 apr_pool_t *temp_pool;
1332 AdmObject *admobj = (AdmObject *)self;
1334 if (!PyArg_ParseTuple(args, "ss", &path, &repos))
1337 ADM_CHECK_CLOSED(admobj);
1339 temp_pool = Pool(NULL);
1340 if (temp_pool == NULL)
1343 RUN_SVN_WITH_POOL(temp_pool, svn_wc_maybe_set_repos_root(admobj->adm, path, repos, temp_pool));
1348 static PyObject *add_repos_file(PyObject *self, PyObject *args, PyObject *kwargs)
1350 char *kwnames[] = { "dst_path", "new_base_contents", "new_contents",
1351 "new_base_props", "new_props", "copyfrom_url", "copyfrom_rev",
1353 AdmObject *admobj = (AdmObject *)self;
1354 apr_pool_t *temp_pool;
1355 char *dst_path, *copyfrom_url = NULL;
1356 svn_revnum_t copyfrom_rev = -1;
1357 PyObject *py_new_base_contents, *py_new_contents, *py_new_base_props,
1358 *py_new_props, *notify = Py_None;
1359 svn_stream_t *new_contents, *new_base_contents;
1360 apr_hash_t *new_props, *new_base_props;
1362 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sOOOO|zlO", kwnames,
1363 &dst_path, &py_new_base_contents, &py_new_contents, &py_new_base_props,
1364 &py_new_props, ©from_url, ©from_rev, ¬ify))
1367 ADM_CHECK_CLOSED(admobj);
1369 temp_pool = Pool(NULL);
1370 if (temp_pool == NULL)
1373 new_base_props = prop_dict_to_hash(temp_pool, py_new_base_props);
1375 new_props = prop_dict_to_hash(temp_pool, py_new_props);
1377 new_base_contents = new_py_stream(temp_pool, py_new_base_contents);
1379 new_contents = new_py_stream(temp_pool, py_new_contents);
1381 #if ONLY_SINCE_SVN(1, 6)
1382 RUN_SVN_WITH_POOL(temp_pool, svn_wc_add_repos_file3(dst_path, admobj->adm,
1387 copyfrom_url, copyfrom_rev,
1388 py_cancel_check, NULL,
1389 py_wc_notify_func, notify, temp_pool));
1391 PyErr_SetString(PyExc_NotImplementedError,
1392 "add_repos_file3 not supported on svn < 1.6");
1393 apr_pool_destroy(temp_pool);
1396 apr_pool_destroy(temp_pool);
1401 static PyObject *mark_missing_deleted(PyObject *self, PyObject *args)
1404 AdmObject *admobj = (AdmObject *)self;
1405 apr_pool_t *temp_pool;
1407 if (!PyArg_ParseTuple(args, "s", &path))
1410 ADM_CHECK_CLOSED(admobj);
1412 temp_pool = Pool(NULL);
1413 if (temp_pool == NULL)
1416 RUN_SVN_WITH_POOL(temp_pool, svn_wc_mark_missing_deleted(path, admobj->adm, temp_pool));
1418 apr_pool_destroy(temp_pool);
1423 static PyObject *remove_from_revision_control(PyObject *self, PyObject *args)
1426 svn_boolean_t destroy_wf = FALSE, instant_error = FALSE;
1427 AdmObject *admobj = (AdmObject *)self;
1428 apr_pool_t *temp_pool;
1430 if (!PyArg_ParseTuple(args, "s|bb", &name, &destroy_wf, &instant_error))
1433 ADM_CHECK_CLOSED(admobj);
1435 temp_pool = Pool(NULL);
1436 if (temp_pool == NULL)
1439 RUN_SVN_WITH_POOL(temp_pool,
1440 svn_wc_remove_from_revision_control(admobj->adm, name,
1441 destroy_wf, instant_error, py_cancel_check, NULL, temp_pool));
1443 apr_pool_destroy(temp_pool);
1448 #if ONLY_SINCE_SVN(1, 6)
1449 static svn_error_t *wc_validator3(void *baton, const char *uuid, const char *url, const char *root_url, apr_pool_t *pool)
1451 PyObject *py_validator = baton, *ret;
1453 if (py_validator == Py_None) {
1457 ret = PyObject_CallFunction(py_validator, "sss", uuid, url, root_url);
1459 return py_svn_error();
1469 static svn_error_t *wc_validator2(void *baton, const char *uuid, const char *url, svn_boolean_t root, apr_pool_t *pool)
1471 PyObject *py_validator = baton, *ret;
1473 if (py_validator == Py_None) {
1477 ret = PyObject_CallFunction(py_validator, "ssO", uuid, url, Py_None);
1479 return py_svn_error();
1489 static PyObject *relocate(PyObject *self, PyObject *args)
1491 char *path, *from, *to;
1492 AdmObject *admobj = (AdmObject *)self;
1493 apr_pool_t *temp_pool;
1494 svn_boolean_t recurse = TRUE;
1495 PyObject *py_validator = Py_None;
1497 if (!PyArg_ParseTuple(args, "sss|bO:relocate", &path, &from, &to, &recurse,
1501 ADM_CHECK_CLOSED(admobj);
1503 temp_pool = Pool(NULL);
1504 if (temp_pool == NULL)
1507 #if ONLY_SINCE_SVN(1, 6)
1508 RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate3(path, admobj->adm, from, to, recurse, wc_validator3, py_validator, temp_pool));
1510 RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate2(path, admobj->adm, from, to, recurse, wc_validator2, py_validator, temp_pool));
1513 apr_pool_destroy(temp_pool);
1518 static PyObject *crop_tree(PyObject *self, PyObject *args)
1523 apr_pool_t *temp_pool;
1524 AdmObject *admobj = (AdmObject *)self;
1526 if (!PyArg_ParseTuple(args, "si|O", &target, &depth, ¬ify))
1529 ADM_CHECK_CLOSED(admobj);
1531 #if ONLY_SINCE_SVN(1, 6)
1532 temp_pool = Pool(NULL);
1533 if (temp_pool == NULL)
1536 RUN_SVN_WITH_POOL(temp_pool, svn_wc_crop_tree(admobj->adm,
1537 target, depth, py_wc_notify_func, notify,
1538 py_cancel_check, NULL, temp_pool));
1540 apr_pool_destroy(temp_pool);
1544 PyErr_SetString(PyExc_NotImplementedError,
1545 "crop_tree only available on subversion < 1.6");
1550 static PyObject *translated_stream(PyObject *self, PyObject *args)
1552 char *path, *versioned_file;
1554 svn_stream_t *stream;
1555 AdmObject *admobj = (AdmObject *)self;
1556 apr_pool_t *stream_pool;
1559 if (!PyArg_ParseTuple(args, "ssi", &path, &versioned_file, &flags))
1562 ADM_CHECK_CLOSED(admobj);
1564 #if ONLY_SINCE_SVN(1, 5)
1565 stream_pool = Pool(NULL);
1566 if (stream_pool == NULL)
1569 RUN_SVN_WITH_POOL(stream_pool,
1570 svn_wc_translated_stream(&stream, path, versioned_file, admobj->adm,
1571 flags, stream_pool));
1573 ret = PyObject_New(StreamObject, &Stream_Type);
1577 ret->pool = stream_pool;
1578 ret->closed = FALSE;
1579 ret->stream = stream;
1581 return (PyObject *)ret;
1583 PyErr_SetString(PyExc_NotImplementedError,
1584 "translated_stream() is only available on Subversion >= 1.5");
1589 static PyObject *adm_text_modified(PyObject *self, PyObject *args)
1592 svn_boolean_t force_comparison = FALSE;
1593 apr_pool_t *temp_pool;
1595 AdmObject *admobj = (AdmObject *)self;
1597 if (!PyArg_ParseTuple(args, "s|b", &path, &force_comparison))
1600 ADM_CHECK_CLOSED(admobj);
1602 temp_pool = Pool(NULL);
1603 if (temp_pool == NULL)
1606 RUN_SVN_WITH_POOL(temp_pool,
1607 svn_wc_text_modified_p(&ret, path, force_comparison, admobj->adm,
1610 apr_pool_destroy(temp_pool);
1612 return PyBool_FromLong(ret);
1615 static PyObject *adm_props_modified(PyObject *self, PyObject *args)
1618 apr_pool_t *temp_pool;
1620 AdmObject *admobj = (AdmObject *)self;
1622 if (!PyArg_ParseTuple(args, "s", &path))
1625 ADM_CHECK_CLOSED(admobj);
1627 temp_pool = Pool(NULL);
1628 if (temp_pool == NULL)
1631 RUN_SVN_WITH_POOL(temp_pool,
1632 svn_wc_props_modified_p(&ret, path, admobj->adm, temp_pool));
1634 apr_pool_destroy(temp_pool);
1636 return PyBool_FromLong(ret);
1639 static PyObject *adm_process_committed_queue(PyObject *self, PyObject *args)
1641 apr_pool_t *temp_pool;
1642 AdmObject *admobj = (AdmObject *)self;
1643 svn_revnum_t revnum;
1644 char *date, *author;
1645 CommittedQueueObject *py_queue;
1647 if (!PyArg_ParseTuple(args, "O!lss", &CommittedQueue_Type, &py_queue,
1648 &revnum, &date, &author))
1651 ADM_CHECK_CLOSED(admobj);
1653 temp_pool = Pool(NULL);
1654 if (temp_pool == NULL)
1657 #if ONLY_SINCE_SVN(1, 5)
1658 RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed_queue(py_queue->queue, admobj->adm, revnum, date, author, temp_pool));
1662 for (i = 0; i < py_queue->queue->queue->nelts; i++) {
1663 committed_queue_item_t *cqi = APR_ARRAY_IDX(py_queue->queue->queue, i,
1664 committed_queue_item_t *);
1666 RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(cqi->path, admobj->adm,
1667 cqi->recurse, revnum, date, author, cqi->wcprop_changes,
1668 cqi->remove_lock, cqi->digest, temp_pool));
1672 apr_pool_destroy(temp_pool);
1677 static PyObject *get_actual_target(PyObject *self, PyObject *args)
1680 const char *anchor = NULL, *target = NULL;
1681 apr_pool_t *temp_pool;
1684 if (!PyArg_ParseTuple(args, "s", &path))
1687 temp_pool = Pool(NULL);
1688 if (temp_pool == NULL)
1691 RUN_SVN_WITH_POOL(temp_pool,
1692 svn_wc_get_actual_target(svn_dirent_canonicalize(path, temp_pool),
1693 &anchor, &target, temp_pool));
1695 ret = Py_BuildValue("(ss)", anchor, target);
1697 apr_pool_destroy(temp_pool);
1702 static PyObject *is_wc_root(PyObject *self, PyObject *args)
1705 svn_boolean_t wc_root;
1706 apr_pool_t *temp_pool;
1707 AdmObject *admobj = (AdmObject *)self;
1709 if (!PyArg_ParseTuple(args, "s", &path))
1712 ADM_CHECK_CLOSED(admobj);
1714 temp_pool = Pool(NULL);
1715 if (temp_pool == NULL)
1718 RUN_SVN_WITH_POOL(temp_pool,
1719 svn_wc_is_wc_root(&wc_root, path, admobj->adm, temp_pool));
1721 apr_pool_destroy(temp_pool);
1723 return PyBool_FromLong(wc_root);
1726 static PyObject *transmit_text_deltas(PyObject *self, PyObject *args)
1729 const char *tempfile;
1730 svn_boolean_t fulltext;
1731 PyObject *editor_obj, *py_digest;
1732 unsigned char digest[APR_MD5_DIGESTSIZE];
1733 apr_pool_t *temp_pool;
1734 AdmObject *admobj = (AdmObject *)self;
1737 if (!PyArg_ParseTuple(args, "sbO", &path, &fulltext, &editor_obj))
1740 ADM_CHECK_CLOSED(admobj);
1742 temp_pool = Pool(NULL);
1743 if (temp_pool == NULL)
1746 Py_INCREF(editor_obj);
1748 RUN_SVN_WITH_POOL(temp_pool,
1749 svn_wc_transmit_text_deltas2(&tempfile, digest,
1750 svn_dirent_canonicalize(path, temp_pool), admobj->adm, fulltext,
1751 &py_editor, editor_obj, temp_pool));
1753 py_digest = PyString_FromStringAndSize((char *)digest, APR_MD5_DIGESTSIZE);
1754 if (py_digest == NULL) {
1755 apr_pool_destroy(temp_pool);
1759 ret = Py_BuildValue("sN", tempfile, py_digest);
1761 apr_pool_destroy(temp_pool);
1765 apr_pool_destroy(temp_pool);
1770 static PyObject *transmit_prop_deltas(PyObject *self, PyObject *args)
1773 PyObject *editor_obj;
1774 apr_pool_t *temp_pool;
1775 AdmObject *admobj = (AdmObject *)self;
1776 EntryObject *py_entry;
1778 if (!PyArg_ParseTuple(args, "sO!O", &path, &Entry_Type, &py_entry, &editor_obj))
1781 ADM_CHECK_CLOSED(admobj);
1783 temp_pool = Pool(NULL);
1784 if (temp_pool == NULL)
1787 Py_INCREF(editor_obj);
1789 RUN_SVN_WITH_POOL(temp_pool,
1790 svn_wc_transmit_prop_deltas(svn_dirent_canonicalize(path, temp_pool),
1791 admobj->adm, &(py_entry->entry), &py_editor, editor_obj, NULL, temp_pool));
1793 apr_pool_destroy(temp_pool);
1798 static PyObject *retrieve(PyObject *self, PyObject *args)
1801 svn_wc_adm_access_t *result;
1802 AdmObject *admobj = (AdmObject *)self, *ret;
1805 if (!PyArg_ParseTuple(args, "s", &path))
1808 ADM_CHECK_CLOSED(admobj);
1814 RUN_SVN_WITH_POOL(pool, svn_wc_adm_retrieve(&result, admobj->adm,
1815 svn_dirent_canonicalize(path, pool), pool));
1817 ret = PyObject_New(AdmObject, &Adm_Type);
1824 return (PyObject *)ret;
1827 static PyObject *probe_retrieve(PyObject *self, PyObject *args)
1830 svn_wc_adm_access_t *result;
1831 AdmObject *admobj = (AdmObject *)self, *ret;
1834 if (!PyArg_ParseTuple(args, "s", &path))
1837 ADM_CHECK_CLOSED(admobj);
1843 RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_retrieve(&result, admobj->adm,
1844 svn_dirent_canonicalize(path, pool), pool));
1846 ret = PyObject_New(AdmObject, &Adm_Type);
1853 return (PyObject *)ret;
1856 static PyObject *probe_try(PyObject *self, PyObject *args)
1859 svn_wc_adm_access_t *result = NULL;
1860 AdmObject *admobj = (AdmObject *)self, *ret;
1862 int levels_to_lock = -1;
1863 svn_boolean_t writelock = FALSE;
1865 if (!PyArg_ParseTuple(args, "s|bi", &path, &writelock, &levels_to_lock))
1868 ADM_CHECK_CLOSED(admobj);
1874 RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_try3(&result, admobj->adm,
1875 svn_dirent_canonicalize(path, pool), writelock, levels_to_lock,
1876 py_cancel_check, NULL, pool));
1878 if (result == NULL) {
1879 apr_pool_destroy(pool);
1883 ret = PyObject_New(AdmObject, &Adm_Type);
1890 return (PyObject *)ret;
1893 static PyObject *resolved_conflict(PyObject *self, PyObject *args)
1895 AdmObject *admobj = (AdmObject *)self;
1896 apr_pool_t *temp_pool;
1897 svn_boolean_t resolve_props, resolve_tree, resolve_text;
1899 #if ONLY_SINCE_SVN(1, 5)
1900 svn_wc_conflict_choice_t conflict_choice;
1902 int conflict_choice;
1904 PyObject *notify_func = Py_None;
1907 if (!PyArg_ParseTuple(args, "sbbbii|O", &path, &resolve_text,
1908 &resolve_props, &resolve_tree, &depth,
1909 &conflict_choice, ¬ify_func))
1912 ADM_CHECK_CLOSED(admobj);
1914 temp_pool = Pool(NULL);
1915 if (temp_pool == NULL)
1918 #if ONLY_SINCE_SVN(1, 6)
1919 RUN_SVN_WITH_POOL(temp_pool,
1920 svn_wc_resolved_conflict4(path, admobj->adm, resolve_text,
1921 resolve_props, resolve_tree, depth,
1922 conflict_choice, py_wc_notify_func,
1923 (void *)notify_func, py_cancel_check,
1925 #elif ONLY_SINCE_SVN(1, 5)
1927 PyErr_SetString(PyExc_NotImplementedError,
1928 "resolve_tree not supported with svn < 1.6");
1929 apr_pool_destroy(temp_pool);
1932 RUN_SVN_WITH_POOL(temp_pool,
1933 svn_wc_resolved_conflict3(path, admobj->adm, resolve_text,
1934 resolve_props, depth,
1935 conflict_choice, py_wc_notify_func,
1936 (void *)notify_func, py_cancel_check,
1941 PyErr_SetString(PyExc_NotImplementedError,
1942 "resolve_tree not supported with svn < 1.6");
1943 apr_pool_destroy(temp_pool);
1945 } else if (depth != svn_depth_infinity && depth != svn_depth_files) {
1946 PyErr_SetString(PyExc_NotImplementedError,
1947 "only infinity and files values for depth are supported");
1948 apr_pool_destroy(temp_pool);
1950 } else if (conflict_choice != 0) {
1951 PyErr_SetString(PyExc_NotImplementedError,
1952 "conflict choice not supported with svn < 1.5");
1953 apr_pool_destroy(temp_pool);
1956 RUN_SVN_WITH_POOL(temp_pool,
1957 svn_wc_resolved_conflict2(path, admobj->adm, resolve_text,
1959 (depth == svn_depth_infinity),
1961 (void *)notify_func, py_cancel_check,
1967 apr_pool_destroy(temp_pool);
1972 static PyObject *conflicted(PyObject *self, PyObject *args)
1975 apr_pool_t *temp_pool;
1977 AdmObject *admobj = (AdmObject *)self;
1978 svn_boolean_t text_conflicted, prop_conflicted, tree_conflicted;
1980 if (!PyArg_ParseTuple(args, "s", &path))
1983 ADM_CHECK_CLOSED(admobj);
1985 temp_pool = Pool(NULL);
1986 if (temp_pool == NULL)
1989 #if ONLY_SINCE_SVN(1, 6)
1990 RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p2(&text_conflicted,
1991 &prop_conflicted, &tree_conflicted, path, admobj->adm, temp_pool));
1993 ret = Py_BuildValue("(bbb)", text_conflicted, prop_conflicted, tree_conflicted);
1995 RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p(&text_conflicted,
1996 &prop_conflicted, path, admobj->adm, temp_pool));
1998 ret = Py_BuildValue("(bbO)", text_conflicted, prop_conflicted, Py_None);
2001 apr_pool_destroy(temp_pool);
2007 * Determine the status of a file in the specified working copy.
2009 * :return: A status object.
2011 static PyObject *ra_status(PyObject *self, PyObject *args)
2014 svn_wc_status2_t *st;
2015 apr_pool_t *temp_pool;
2017 AdmObject *admobj = (AdmObject *)self;
2019 if (!PyArg_ParseTuple(args, "s", &path))
2022 ADM_CHECK_CLOSED(admobj);
2024 temp_pool = Pool(NULL);
2025 if (temp_pool == NULL)
2028 RUN_SVN_WITH_POOL(temp_pool,
2031 svn_dirent_canonicalize(svn_path_join(svn_wc_adm_access_path(admobj->adm), path, temp_pool), temp_pool),
2035 ret = py_status(st);
2037 apr_pool_destroy(temp_pool);
2039 return (PyObject*)ret;
2042 static PyMethodDef adm_methods[] = {
2043 { "prop_set", adm_prop_set, METH_VARARGS, "S.prop_set(name, value, path, skip_checks=False)" },
2044 { "access_path", (PyCFunction)adm_access_path, METH_NOARGS,
2045 "S.access_path() -> path\n"
2046 "Returns the base path for this working copy handle." },
2047 { "prop_get", adm_prop_get, METH_VARARGS, "S.prop_get(name, path) -> value" },
2048 { "entries_read", adm_entries_read, METH_VARARGS, "S.entries_read(include_hidden=False) -> dict" },
2049 { "walk_entries", adm_walk_entries, METH_VARARGS,
2050 "S.walk_entries(path, callback, show_hidden=False)\n"
2051 "callback should be a function that takes a path and a wc entry" },
2052 { "locked", (PyCFunction)adm_locked, METH_NOARGS,
2053 "S.locked() -> bool" },
2054 { "get_prop_diffs", adm_get_prop_diffs, METH_VARARGS,
2055 "S.get_prop_diffs(path) -> (propchanges, originalprops)" },
2056 { "add", (PyCFunction)adm_add, METH_VARARGS|METH_KEYWORDS, "S.add(path, copyfrom_url=None, copyfrom_rev=-1, notify_func=None)" },
2057 { "copy", adm_copy, METH_VARARGS, "S.copy(src_path, dest_path, notify_func=None)" },
2058 { "delete", (PyCFunction)adm_delete, METH_VARARGS|METH_KEYWORDS, "S.delete(path, notify_func=None, keep_local=False)" },
2059 { "crawl_revisions", (PyCFunction)adm_crawl_revisions, METH_VARARGS|METH_KEYWORDS,
2060 "S.crawl_revisions(path, reporter, restore_files=True, recurse=True, use_commit_times=True, notify_func=None) -> None" },
2061 { "get_update_editor", adm_get_update_editor, METH_VARARGS, NULL },
2062 { "close", (PyCFunction)adm_close, METH_NOARGS,
2064 { "entry", (PyCFunction)adm_entry, METH_VARARGS,
2065 "s.entry(path, show_hidden=False) -> entry" },
2066 { "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)" },
2067 { "process_committed_queue", (PyCFunction)adm_process_committed_queue, METH_VARARGS, "S.process_committed_queue(queue, new_revnum, rev_date, rev_author)" },
2068 { "remove_lock", (PyCFunction)adm_remove_lock, METH_VARARGS, "S.remove_lock(path)" },
2069 { "has_binary_prop", (PyCFunction)adm_has_binary_prop, METH_VARARGS, "S.has_binary_prop(path) -> bool" },
2070 { "text_modified", (PyCFunction)adm_text_modified, METH_VARARGS, "S.text_modified(filename, force_comparison=False) -> bool" },
2071 { "props_modified", (PyCFunction)adm_props_modified, METH_VARARGS, "S.props_modified(filename) -> bool" },
2072 { "get_ancestry", (PyCFunction)get_ancestry, METH_VARARGS,
2073 "S.get_ancestry(path) -> (url, rev)" },
2074 { "maybe_set_repos_root", (PyCFunction)maybe_set_repos_root, METH_VARARGS, "S.maybe_set_repos_root(path, repos)" },
2075 { "add_repos_file", (PyCFunction)add_repos_file, METH_KEYWORDS,
2076 "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)" },
2077 { "mark_missing_deleted", (PyCFunction)mark_missing_deleted, METH_VARARGS,
2078 "S.mark_missing_deleted(path)" },
2079 { "remove_from_revision_control", (PyCFunction)remove_from_revision_control, METH_VARARGS,
2080 "S.remove_from_revision_control(name, destroy_wf=False, instant_error=False)" },
2081 { "relocate", (PyCFunction)relocate, METH_VARARGS,
2082 "S.relocate(path, from, to, recurse=TRUE, validator=None)" },
2083 { "crop_tree", (PyCFunction)crop_tree, METH_VARARGS,
2084 "S.crop_tree(target, depth, notify_func=None, cancel=None)" },
2085 { "translated_stream", (PyCFunction)translated_stream, METH_VARARGS,
2086 "S.translated_stream(path, versioned_file, flags) -> stream" },
2087 { "is_wc_root", (PyCFunction)is_wc_root, METH_VARARGS,
2088 "S.is_wc_root(path) -> wc_root" },
2089 { "transmit_text_deltas", (PyCFunction)transmit_text_deltas, METH_VARARGS,
2090 "S.transmit_text_deltas(fulltext, editor) -> (tempfile, digest)" },
2091 { "transmit_prop_deltas", (PyCFunction)transmit_prop_deltas, METH_VARARGS,
2092 "S.transmit_prop_deltas(path, entry, editor)" },
2093 { "probe_retrieve", (PyCFunction)probe_retrieve, METH_VARARGS,
2094 "S.probe_retrieve(path) -> WorkingCopy" },
2095 { "retrieve", (PyCFunction)retrieve, METH_VARARGS,
2096 "S.retrieve(path) -> WorkingCopy" },
2097 { "probe_try", (PyCFunction)probe_try, METH_VARARGS,
2098 "S.probe_try(path, write_lock=False, levels_to_lock=-1)" },
2099 { "conflicted", (PyCFunction)conflicted, METH_VARARGS,
2100 "S.conflicted(path) -> (text_conflicted, prop_conflicted, tree_conflicted)" },
2101 { "resolved_conflict", (PyCFunction)resolved_conflict, METH_VARARGS,
2102 "S.resolved_conflict(path, resolve_text, resolve_props, resolve_tree, depth, conflict_choice, notify_func=None, cancel=None)" },
2103 { "status", (PyCFunction)ra_status, METH_VARARGS, "status(wc_path) -> Status" },
2107 static PyTypeObject Adm_Type = {
2108 PyObject_HEAD_INIT(NULL) 0,
2109 "wc.WorkingCopy", /* const char *tp_name; For printing, in format "<module>.<name>" */
2111 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
2113 /* Methods to implement standard operations */
2115 adm_dealloc, /* destructor tp_dealloc; */
2116 NULL, /* printfunc tp_print; */
2117 NULL, /* getattrfunc tp_getattr; */
2118 NULL, /* setattrfunc tp_setattr; */
2119 NULL, /* cmpfunc tp_compare; */
2120 adm_repr, /* reprfunc tp_repr; */
2122 /* Method suites for standard classes */
2124 NULL, /* PyNumberMethods *tp_as_number; */
2125 NULL, /* PySequenceMethods *tp_as_sequence; */
2126 NULL, /* PyMappingMethods *tp_as_mapping; */
2128 /* More standard operations (here for binary compatibility) */
2130 NULL, /* hashfunc tp_hash; */
2131 NULL, /* ternaryfunc tp_call; */
2132 adm_repr, /* reprfunc tp_repr; */
2133 NULL, /* getattrofunc tp_getattro; */
2134 NULL, /* setattrofunc tp_setattro; */
2136 /* Functions to access object as input/output buffer */
2137 NULL, /* PyBufferProcs *tp_as_buffer; */
2139 /* Flags to define presence of optional/expanded features */
2140 0, /* long tp_flags; */
2142 "Local working copy", /* const char *tp_doc; Documentation string */
2144 /* Assigned meaning in release 2.0 */
2145 /* call function for all accessible objects */
2146 NULL, /* traverseproc tp_traverse; */
2148 /* delete references to contained objects */
2149 NULL, /* inquiry tp_clear; */
2151 /* Assigned meaning in release 2.1 */
2152 /* rich comparisons */
2153 NULL, /* richcmpfunc tp_richcompare; */
2155 /* weak reference enabler */
2156 0, /* Py_ssize_t tp_weaklistoffset; */
2158 /* Added in release 2.2 */
2160 NULL, /* getiterfunc tp_iter; */
2161 NULL, /* iternextfunc tp_iternext; */
2163 /* Attribute descriptor and subclassing stuff */
2164 adm_methods, /* struct PyMethodDef *tp_methods; */
2165 NULL, /* struct PyMemberDef *tp_members; */
2166 NULL, /* struct PyGetSetDef *tp_getset; */
2167 NULL, /* struct _typeobject *tp_base; */
2168 NULL, /* PyObject *tp_dict; */
2169 NULL, /* descrgetfunc tp_descr_get; */
2170 NULL, /* descrsetfunc tp_descr_set; */
2171 0, /* Py_ssize_t tp_dictoffset; */
2172 NULL, /* initproc tp_init; */
2173 NULL, /* allocfunc tp_alloc; */
2174 adm_init, /* newfunc tp_new; */
2177 static void committed_queue_dealloc(PyObject *self)
2179 apr_pool_destroy(((CommittedQueueObject *)self)->pool);
2183 static PyObject *committed_queue_repr(PyObject *self)
2185 CommittedQueueObject *cqobj = (CommittedQueueObject *)self;
2187 return PyString_FromFormat("<wc.CommittedQueue at 0x%p>", cqobj->queue);
2190 static PyObject *committed_queue_init(PyTypeObject *self, PyObject *args, PyObject *kwargs)
2192 CommittedQueueObject *ret;
2193 char *kwnames[] = { NULL };
2195 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwnames))
2198 ret = PyObject_New(CommittedQueueObject, &CommittedQueue_Type);
2202 ret->pool = Pool(NULL);
2203 if (ret->pool == NULL)
2205 ret->queue = svn_wc_committed_queue_create(ret->pool);
2206 if (ret->queue == NULL) {
2212 return (PyObject *)ret;
2215 static PyObject *committed_queue_queue(CommittedQueueObject *self, PyObject *args)
2219 PyObject *py_wcprop_changes = Py_None;
2220 svn_boolean_t remove_lock = FALSE, remove_changelist = FALSE;
2221 char *digest = NULL;
2222 svn_boolean_t recurse = FALSE;
2223 apr_pool_t *temp_pool;
2224 apr_array_header_t *wcprop_changes;
2227 if (!PyArg_ParseTuple(args, "sO!|bObbz#", &path, &Adm_Type, &admobj,
2228 &recurse, &py_wcprop_changes, &remove_lock,
2229 &remove_changelist, &digest, &digest_len))
2232 temp_pool = Pool(NULL);
2233 if (temp_pool == NULL)
2236 if (!py_dict_to_wcprop_changes(py_wcprop_changes, self->pool, &wcprop_changes)) {
2237 apr_pool_destroy(temp_pool);
2241 path = apr_pstrdup(self->pool, path);
2247 if (digest != NULL) {
2248 if (digest_len != APR_MD5_DIGESTSIZE) {
2249 PyErr_SetString(PyExc_ValueError, "Invalid size for md5 digest");
2250 apr_pool_destroy(temp_pool);
2253 digest = apr_pstrdup(self->pool, digest);
2254 if (digest == NULL) {
2260 RUN_SVN_WITH_POOL(temp_pool,
2261 svn_wc_queue_committed(&self->queue, path, admobj->adm, recurse,
2262 wcprop_changes, remove_lock, remove_changelist,
2263 (unsigned char *)digest, temp_pool));
2265 apr_pool_destroy(temp_pool);
2270 static PyMethodDef committed_queue_methods[] = {
2271 { "queue", (PyCFunction)committed_queue_queue, METH_VARARGS,
2272 "S.queue(path, adm, recurse, wcprop_changes, remove_lock, remove_changelist, digest)" },
2276 static PyTypeObject CommittedQueue_Type = {
2277 PyObject_HEAD_INIT(NULL) 0,
2278 "wc.CommittedQueue", /* const char *tp_name; For printing, in format "<module>.<name>" */
2279 sizeof(CommittedQueueObject),
2280 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
2282 /* Methods to implement standard operations */
2284 committed_queue_dealloc, /* destructor tp_dealloc; */
2285 NULL, /* printfunc tp_print; */
2286 NULL, /* getattrfunc tp_getattr; */
2287 NULL, /* setattrfunc tp_setattr; */
2288 NULL, /* cmpfunc tp_compare; */
2289 committed_queue_repr, /* reprfunc tp_repr; */
2291 /* Method suites for standard classes */
2293 NULL, /* PyNumberMethods *tp_as_number; */
2294 NULL, /* PySequenceMethods *tp_as_sequence; */
2295 NULL, /* PyMappingMethods *tp_as_mapping; */
2297 /* More standard operations (here for binary compatibility) */
2299 NULL, /* hashfunc tp_hash; */
2300 NULL, /* ternaryfunc tp_call; */
2301 NULL, /* reprfunc tp_str; */
2302 NULL, /* getattrofunc tp_getattro; */
2303 NULL, /* setattrofunc tp_setattro; */
2305 /* Functions to access object as input/output buffer */
2306 NULL, /* PyBufferProcs *tp_as_buffer; */
2308 /* Flags to define presence of optional/expanded features */
2309 0, /* long tp_flags; */
2311 "Committed queue", /* const char *tp_doc; Documentation string */
2313 /* Assigned meaning in release 2.0 */
2314 /* call function for all accessible objects */
2315 NULL, /* traverseproc tp_traverse; */
2317 /* delete references to contained objects */
2318 NULL, /* inquiry tp_clear; */
2320 /* Assigned meaning in release 2.1 */
2321 /* rich comparisons */
2322 NULL, /* richcmpfunc tp_richcompare; */
2324 /* weak reference enabler */
2325 0, /* Py_ssize_t tp_weaklistoffset; */
2327 /* Added in release 2.2 */
2329 NULL, /* getiterfunc tp_iter; */
2330 NULL, /* iternextfunc tp_iternext; */
2332 /* Attribute descriptor and subclassing stuff */
2333 committed_queue_methods, /* struct PyMethodDef *tp_methods; */
2334 NULL, /* struct PyMemberDef *tp_members; */
2335 NULL, /* struct PyGetSetDef *tp_getset; */
2336 NULL, /* struct _typeobject *tp_base; */
2337 NULL, /* PyObject *tp_dict; */
2338 NULL, /* descrgetfunc tp_descr_get; */
2339 NULL, /* descrsetfunc tp_descr_set; */
2340 0, /* Py_ssize_t tp_dictoffset; */
2341 NULL, /* initproc tp_init; */
2342 NULL, /* allocfunc tp_alloc; */
2343 committed_queue_init, /* newfunc tp_new; */
2347 * Determine the revision status of a specified working copy.
2349 * :return: Tuple with minimum and maximum revnums found, whether the
2350 * working copy was switched and whether it was modified.
2352 static PyObject *revision_status(PyObject *self, PyObject *args, PyObject *kwargs)
2354 char *kwnames[] = { "wc_path", "trail_url", "committed", NULL };
2355 char *wc_path, *trail_url=NULL;
2356 bool committed=false;
2358 svn_wc_revision_status_t *revstatus;
2359 apr_pool_t *temp_pool;
2361 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zb", kwnames, &wc_path,
2362 &trail_url, &committed))
2365 temp_pool = Pool(NULL);
2366 if (temp_pool == NULL)
2368 RUN_SVN_WITH_POOL(temp_pool,
2369 svn_wc_revision_status(
2371 svn_dirent_canonicalize(wc_path, temp_pool),
2373 committed, py_cancel_check, NULL, temp_pool));
2374 ret = Py_BuildValue("(llbb)", revstatus->min_rev, revstatus->max_rev,
2375 revstatus->switched, revstatus->modified);
2376 apr_pool_destroy(temp_pool);
2380 static PyObject *is_normal_prop(PyObject *self, PyObject *args)
2384 if (!PyArg_ParseTuple(args, "s", &name))
2387 return PyBool_FromLong(svn_wc_is_normal_prop(name));
2390 static PyObject *is_adm_dir(PyObject *self, PyObject *args)
2396 if (!PyArg_ParseTuple(args, "s", &name))
2403 ret = svn_wc_is_adm_dir(name, pool);
2405 apr_pool_destroy(pool);
2407 return PyBool_FromLong(ret);
2410 static PyObject *is_wc_prop(PyObject *self, PyObject *args)
2414 if (!PyArg_ParseTuple(args, "s", &name))
2417 return PyBool_FromLong(svn_wc_is_wc_prop(name));
2420 static PyObject *is_entry_prop(PyObject *self, PyObject *args)
2424 if (!PyArg_ParseTuple(args, "s", &name))
2427 return PyBool_FromLong(svn_wc_is_entry_prop(name));
2430 static PyObject *get_adm_dir(PyObject *self)
2438 dir = svn_wc_get_adm_dir(pool);
2439 ret = PyString_FromString(dir);
2440 apr_pool_destroy(pool);
2444 static PyObject *set_adm_dir(PyObject *self, PyObject *args)
2446 apr_pool_t *temp_pool;
2449 if (!PyArg_ParseTuple(args, "s", &name))
2452 temp_pool = Pool(NULL);
2453 if (temp_pool == NULL)
2455 RUN_SVN_WITH_POOL(temp_pool, svn_wc_set_adm_dir(name, temp_pool));
2456 apr_pool_destroy(temp_pool);
2460 static PyObject *get_pristine_copy_path(PyObject *self, PyObject *args)
2463 const char *pristine_path;
2467 if (!PyArg_ParseTuple(args, "s", &path))
2473 PyErr_WarnEx(PyExc_DeprecationWarning, "get_pristine_copy_path is deprecated. Use get_pristine_contents instead.", 2);
2474 RUN_SVN_WITH_POOL(pool,
2475 svn_wc_get_pristine_copy_path(svn_dirent_canonicalize(path, pool),
2476 &pristine_path, pool));
2477 ret = PyString_FromString(pristine_path);
2478 apr_pool_destroy(pool);
2482 static PyObject *get_pristine_contents(PyObject *self, PyObject *args)
2485 apr_pool_t *temp_pool;
2486 #if ONLY_SINCE_SVN(1, 6)
2487 apr_pool_t *stream_pool;
2489 svn_stream_t *stream;
2492 const char *pristine_path;
2495 if (!PyArg_ParseTuple(args, "s", &path))
2498 #if ONLY_SINCE_SVN(1, 6)
2499 stream_pool = Pool(NULL);
2500 if (stream_pool == NULL)
2503 temp_pool = Pool(stream_pool);
2504 if (temp_pool == NULL) {
2505 apr_pool_destroy(stream_pool);
2509 RUN_SVN_WITH_POOL(stream_pool, svn_wc_get_pristine_contents(&stream, svn_dirent_canonicalize(path, temp_pool), stream_pool, temp_pool));
2510 apr_pool_destroy(temp_pool);
2512 if (stream == NULL) {
2513 apr_pool_destroy(stream_pool);
2517 ret = PyObject_New(StreamObject, &Stream_Type);
2521 ret->pool = stream_pool;
2522 ret->closed = FALSE;
2523 ret->stream = stream;
2525 return (PyObject *)ret;
2527 temp_pool = Pool(NULL);
2528 if (temp_pool == NULL)
2530 RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_pristine_copy_path(svn_dirent_canonicalize(path, temp_pool), &pristine_path, temp_pool));
2531 ret = PyFile_FromString((char *)pristine_path, "rb");
2532 apr_pool_destroy(temp_pool);
2537 static PyObject *ensure_adm(PyObject *self, PyObject *args, PyObject *kwargs)
2539 char *path, *uuid, *url;
2541 svn_revnum_t rev=-1;
2543 char *kwnames[] = { "path", "uuid", "url", "repos", "rev", "depth", NULL };
2544 svn_depth_t depth = svn_depth_infinity;
2546 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sss|sli", kwnames,
2547 &path, &uuid, &url, &repos, &rev, &depth))
2553 #if ONLY_SINCE_SVN(1, 5)
2554 RUN_SVN_WITH_POOL(pool,
2555 svn_wc_ensure_adm3(svn_dirent_canonicalize(path, pool),
2556 uuid, url, repos, rev, depth, pool));
2558 if (depth != svn_depth_infinity) {
2559 PyErr_SetString(PyExc_NotImplementedError,
2560 "depth != infinity not supported with svn < 1.5");
2561 apr_pool_destroy(pool);
2564 RUN_SVN_WITH_POOL(pool,
2565 svn_wc_ensure_adm2(svn_dirent_canonicalize(path, pool),
2566 uuid, url, repos, rev, pool));
2568 apr_pool_destroy(pool);
2572 static PyObject *check_wc(PyObject *self, PyObject *args)
2578 if (!PyArg_ParseTuple(args, "s", &path))
2584 RUN_SVN_WITH_POOL(pool, svn_wc_check_wc(svn_dirent_canonicalize(path, pool), &wc_format, pool));
2585 apr_pool_destroy(pool);
2586 return PyLong_FromLong(wc_format);
2589 static PyObject *cleanup_wc(PyObject *self, PyObject *args, PyObject *kwargs)
2592 char *diff3_cmd = NULL;
2593 char *kwnames[] = { "path", "diff3_cmd", NULL };
2594 apr_pool_t *temp_pool;
2596 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|z", kwnames,
2600 temp_pool = Pool(NULL);
2601 if (temp_pool == NULL)
2603 RUN_SVN_WITH_POOL(temp_pool,
2604 svn_wc_cleanup2(path, diff3_cmd, py_cancel_check, NULL,
2606 apr_pool_destroy(temp_pool);
2611 static PyObject *match_ignore_list(PyObject *self, PyObject *args)
2613 #if ONLY_SINCE_SVN(1, 5)
2616 apr_array_header_t *list;
2617 apr_pool_t *temp_pool;
2620 if (!PyArg_ParseTuple(args, "sO", &str, &py_list))
2623 temp_pool = Pool(NULL);
2625 if (!string_list_to_apr_array(temp_pool, py_list, &list)) {
2626 apr_pool_destroy(temp_pool);
2630 ret = svn_wc_match_ignore_list(str, list, temp_pool);
2632 apr_pool_destroy(temp_pool);
2634 return PyBool_FromLong(ret);
2636 PyErr_SetNone(PyExc_NotImplementedError);
2641 static PyMethodDef wc_methods[] = {
2642 { "check_wc", check_wc, METH_VARARGS, "check_wc(path) -> version\n"
2643 "Check whether path contains a Subversion working copy\n"
2644 "return the workdir version"},
2645 { "cleanup", (PyCFunction)cleanup_wc, METH_VARARGS|METH_KEYWORDS, "cleanup(path, diff3_cmd=None)\n" },
2646 { "ensure_adm", (PyCFunction)ensure_adm, METH_KEYWORDS|METH_VARARGS,
2647 "ensure_adm(path, uuid, url, repos=None, rev=None)" },
2648 { "get_adm_dir", (PyCFunction)get_adm_dir, METH_NOARGS,
2649 "get_adm_dir() -> name" },
2650 { "set_adm_dir", (PyCFunction)set_adm_dir, METH_VARARGS,
2651 "set_adm_dir(name)" },
2652 { "get_pristine_copy_path", get_pristine_copy_path, METH_VARARGS,
2653 "get_pristine_copy_path(path) -> path" },
2654 { "get_pristine_contents", get_pristine_contents, METH_VARARGS,
2655 "get_pristine_contents(path) -> stream" },
2656 { "is_adm_dir", is_adm_dir, METH_VARARGS,
2657 "is_adm_dir(name) -> bool" },
2658 { "is_normal_prop", is_normal_prop, METH_VARARGS,
2659 "is_normal_prop(name) -> bool" },
2660 { "is_entry_prop", is_entry_prop, METH_VARARGS,
2661 "is_entry_prop(name) -> bool" },
2662 { "is_wc_prop", is_wc_prop, METH_VARARGS,
2663 "is_wc_prop(name) -> bool" },
2664 { "revision_status", (PyCFunction)revision_status, METH_KEYWORDS|METH_VARARGS, "revision_status(wc_path, trail_url=None, committed=False) -> (min_rev, max_rev, switched, modified)" },
2665 { "version", (PyCFunction)version, METH_NOARGS,
2666 "version() -> (major, minor, patch, tag)\n\n"
2667 "Version of libsvn_wc currently used."
2669 { "api_version", (PyCFunction)api_version, METH_NOARGS,
2670 "api_version() -> (major, minor, patch, tag)\n\n"
2671 "Version of libsvn_wc Subvertpy was compiled against."
2673 { "match_ignore_list", (PyCFunction)match_ignore_list, METH_VARARGS,
2674 "match_ignore_list(str, patterns) -> bool" },
2675 { "get_actual_target", (PyCFunction)get_actual_target, METH_VARARGS,
2676 "get_actual_target(path) -> (anchor, target)" },
2685 if (PyType_Ready(&Entry_Type) < 0)
2688 if (PyType_Ready(&Status_Type) < 0)
2691 if (PyType_Ready(&Adm_Type) < 0)
2694 if (PyType_Ready(&Editor_Type) < 0)
2697 if (PyType_Ready(&FileEditor_Type) < 0)
2700 if (PyType_Ready(&DirectoryEditor_Type) < 0)
2703 if (PyType_Ready(&TxDeltaWindowHandler_Type) < 0)
2706 if (PyType_Ready(&Stream_Type) < 0)
2709 if (PyType_Ready(&CommittedQueue_Type) < 0)
2714 #if PY_MAJOR_VERSION >= 3
2715 static struct PyModuleDef moduledef = {
2716 PyModuleDef_HEAD_INIT,
2718 "Working Copies", /* m_doc */
2720 wc_methods, /* m_methods */
2721 NULL, /* m_reload */
2722 NULL, /* m_traverse */
2726 mod = PyModule_Create(&moduledef);
2728 mod = Py_InitModule3("wc", wc_methods, "Working Copies");
2733 PyModule_AddIntConstant(mod, "SCHEDULE_NORMAL", 0);
2734 PyModule_AddIntConstant(mod, "SCHEDULE_ADD", 1);
2735 PyModule_AddIntConstant(mod, "SCHEDULE_DELETE", 2);
2736 PyModule_AddIntConstant(mod, "SCHEDULE_REPLACE", 3);
2738 #if ONLY_SINCE_SVN(1, 5)
2739 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_POSTPONE",
2740 svn_wc_conflict_choose_postpone);
2741 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_BASE",
2742 svn_wc_conflict_choose_base);
2743 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_FULL",
2744 svn_wc_conflict_choose_theirs_full);
2745 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_FULL",
2746 svn_wc_conflict_choose_mine_full);
2747 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_CONFLICT",
2748 svn_wc_conflict_choose_theirs_conflict);
2749 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_CONFLICT",
2750 svn_wc_conflict_choose_mine_conflict);
2751 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MERGED",
2752 svn_wc_conflict_choose_merged);
2755 PyModule_AddIntConstant(mod, "STATUS_NONE", svn_wc_status_none);
2756 PyModule_AddIntConstant(mod, "STATUS_UNVERSIONED", svn_wc_status_unversioned);
2757 PyModule_AddIntConstant(mod, "STATUS_NORMAL", svn_wc_status_normal);
2758 PyModule_AddIntConstant(mod, "STATUS_ADDED", svn_wc_status_added);
2759 PyModule_AddIntConstant(mod, "STATUS_MISSING", svn_wc_status_missing);
2760 PyModule_AddIntConstant(mod, "STATUS_DELETED", svn_wc_status_deleted);
2761 PyModule_AddIntConstant(mod, "STATUS_REPLACED", svn_wc_status_replaced);
2762 PyModule_AddIntConstant(mod, "STATUS_MODIFIED", svn_wc_status_modified);
2763 PyModule_AddIntConstant(mod, "STATUS_MERGED", svn_wc_status_merged);
2764 PyModule_AddIntConstant(mod, "STATUS_CONFLICTED", svn_wc_status_conflicted);
2765 PyModule_AddIntConstant(mod, "STATUS_IGNORED", svn_wc_status_ignored);
2766 PyModule_AddIntConstant(mod, "STATUS_OBSTRUCTED", svn_wc_status_obstructed);
2767 PyModule_AddIntConstant(mod, "STATUS_EXTERNAL", svn_wc_status_external);
2768 PyModule_AddIntConstant(mod, "STATUS_INCOMPLETE", svn_wc_status_incomplete);
2770 PyModule_AddIntConstant(mod, "TRANSLATE_FROM_NF", SVN_WC_TRANSLATE_FROM_NF);
2771 PyModule_AddIntConstant(mod, "TRANSLATE_TO_NF", SVN_WC_TRANSLATE_TO_NF);
2772 PyModule_AddIntConstant(mod, "TRANSLATE_FORCE_EOL_REPAIR", SVN_WC_TRANSLATE_FORCE_EOL_REPAIR);
2773 PyModule_AddIntConstant(mod, "TRANSLATE_NO_OUTPUT_CLEANUP", SVN_WC_TRANSLATE_NO_OUTPUT_CLEANUP);
2774 PyModule_AddIntConstant(mod, "TRANSLATE_FORCE_COPY", SVN_WC_TRANSLATE_FORCE_COPY);
2775 PyModule_AddIntConstant(mod, "TRANSLATE_USE_GLOBAL_TMP", SVN_WC_TRANSLATE_USE_GLOBAL_TMP);
2777 #if ONLY_SINCE_SVN(1, 5)
2778 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_POSTPONE", svn_wc_conflict_choose_postpone);
2779 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_BASE", svn_wc_conflict_choose_base);
2780 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_FULL", svn_wc_conflict_choose_theirs_full);
2781 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_FULL", svn_wc_conflict_choose_mine_full);
2782 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_CONFLICT", svn_wc_conflict_choose_theirs_conflict);
2783 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_CONFLICT", svn_wc_conflict_choose_mine_conflict);
2784 PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MERGED", svn_wc_conflict_choose_merged);
2787 #if ONLY_BEFORE_SVN(1, 7)
2788 /* Subversion 1.7 has a couple of significant behaviour changes that break subvertpy.
2789 * We haven't updated the code to deal with these changes in behaviour yet.
2791 PyModule_AddObject(mod, "WorkingCopy", (PyObject *)&Adm_Type);
2792 Py_INCREF(&Adm_Type);
2794 PyModule_AddObject(mod, "CommittedQueue", (PyObject *)&CommittedQueue_Type);
2795 Py_INCREF(&CommittedQueue_Type);
2801 #if PY_MAJOR_VERSION >= 3
2805 return moduleinit();