Fix potential memory leaks in subvertpy.wc.
[jelmer/subvertpy.git] / subvertpy / wc.c
1 /*
2  * Copyright © 2008 Jelmer Vernooij <jelmer@samba.org>
3  * -*- coding: utf-8 -*-
4  *
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.
9  *
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.
14  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #include <Python.h>
20 #include <apr_general.h>
21 #include <svn_wc.h>
22 #include <svn_path.h>
23 #include <svn_props.h>
24 #include <structmember.h>
25 #include <stdbool.h>
26 #include <apr_md5.h>
27
28 #include "util.h"
29 #include "editor.h"
30
31 #if ONLY_SINCE_SVN(1, 5)
32 #define REPORTER_T svn_ra_reporter3_t
33 #else
34 #define REPORTER_T svn_ra_reporter2_t
35 #endif
36
37 staticforward PyTypeObject Entry_Type;
38 staticforward PyTypeObject Adm_Type;
39
40 static PyObject *py_entry(const svn_wc_entry_t *entry);
41
42 #if ONLY_BEFORE_SVN(1, 5)
43 struct svn_wc_committed_queue_t
44 {
45         apr_pool_t *pool;
46         apr_array_header_t *queue;
47         svn_boolean_t have_recursive;
48 };
49
50 #if SVN_VER_MINOR < 5
51 typedef struct svn_wc_committed_queue_t svn_wc_committed_queue_t;
52 #endif
53
54 typedef struct
55 {
56         const char *path;
57         svn_wc_adm_access_t *adm_access;
58         svn_boolean_t recurse;
59         svn_boolean_t remove_lock;
60         apr_array_header_t *wcprop_changes;
61         unsigned char *digest;
62 } committed_queue_item_t;
63
64 #if SVN_VER_MINOR < 5
65 static
66 #endif
67 svn_wc_committed_queue_t *svn_wc_committed_queue_create(apr_pool_t *pool)
68 {
69         svn_wc_committed_queue_t *q;
70
71         q = apr_palloc(pool, sizeof(*q));
72         q->pool = pool;
73         q->queue = apr_array_make(pool, 1, sizeof(committed_queue_item_t *));
74         q->have_recursive = FALSE;
75
76         return q;
77 }
78
79 #if SVN_VER_MINOR < 5
80 static
81 #endif
82 svn_error_t *svn_wc_queue_committed(svn_wc_committed_queue_t **queue,
83                         const char *path,
84                         svn_wc_adm_access_t *adm_access,
85                         svn_boolean_t recurse,
86                         apr_array_header_t *wcprop_changes,
87                         svn_boolean_t remove_lock,
88                         svn_boolean_t remove_changelist,
89                         const unsigned char *digest,
90                         apr_pool_t *scratch_pool)
91 {
92   committed_queue_item_t *cqi;
93
94   (*queue)->have_recursive |= recurse;
95
96   /* Use the same pool as the one QUEUE was allocated in,
97      to prevent lifetime issues.  Intermediate operations
98      should use SCRATCH_POOL. */
99
100   /* Add to the array with paths and options */
101   cqi = apr_palloc((*queue)->pool, sizeof(*cqi));
102   cqi->path = path;
103   cqi->adm_access = adm_access;
104   cqi->recurse = recurse;
105   cqi->remove_lock = remove_lock;
106   cqi->wcprop_changes = wcprop_changes;
107   cqi->digest = digest;
108
109   APR_ARRAY_PUSH((*queue)->queue, committed_queue_item_t *) = cqi;
110
111   return SVN_NO_ERROR;
112 }
113
114 #endif
115
116 typedef struct {
117         PyObject_HEAD
118         apr_pool_t *pool;
119         svn_wc_committed_queue_t *queue;
120 } CommittedQueueObject;
121 staticforward PyTypeObject CommittedQueue_Type;
122
123 #if ONLY_SINCE_SVN(1, 5)
124 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)
125 {
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);
131         } else {
132                 py_lock_token = PyString_FromString(lock_token);
133         }
134         ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision, start_empty, py_lock_token, depth);
135         Py_DECREF(py_lock_token);
136         CB_CHECK_PYRETVAL(ret);
137         Py_DECREF(ret);
138         PyGILState_Release(state);
139         return NULL;
140 }
141
142 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)
143 {
144         PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token;
145         PyGILState_STATE state = PyGILState_Ensure();
146         if (lock_token == NULL) {
147                 py_lock_token = Py_None;
148                 Py_INCREF(py_lock_token);
149         } else { 
150                 py_lock_token = PyString_FromString(lock_token);
151         }
152         ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision, start_empty, py_lock_token, depth);
153         Py_DECREF(py_lock_token);
154         CB_CHECK_PYRETVAL(ret);
155         Py_DECREF(ret);
156         PyGILState_Release(state);
157         return NULL;
158 }
159
160
161 #else
162 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)
163 {
164         PyObject *self = (PyObject *)baton, *py_lock_token, *ret;
165         PyGILState_STATE state = PyGILState_Ensure();
166         if (lock_token == NULL) {
167                 py_lock_token = Py_None;
168                 Py_INCREF(py_lock_token);
169         } else {
170                 py_lock_token = PyString_FromString(lock_token);
171         }
172         ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision, start_empty, py_lock_token, svn_depth_infinity);
173         CB_CHECK_PYRETVAL(ret);
174         Py_DECREF(ret);
175         PyGILState_Release(state);
176         return NULL;
177 }
178
179 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)
180 {
181         PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token;
182         PyGILState_STATE state = PyGILState_Ensure();
183         if (lock_token == NULL) {
184                 py_lock_token = Py_None;
185                 Py_INCREF(py_lock_token);
186         } else { 
187                 py_lock_token = PyString_FromString(lock_token);
188         }
189         ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision, start_empty, py_lock_token, svn_depth_infinity);
190         CB_CHECK_PYRETVAL(ret);
191         Py_DECREF(ret);
192         PyGILState_Release(state);
193         return NULL;
194 }
195
196
197 #endif
198
199 static svn_error_t *py_ra_report_delete_path(void *baton, const char *path, apr_pool_t *pool)
200 {
201         PyObject *self = (PyObject *)baton, *ret;
202         PyGILState_STATE state = PyGILState_Ensure();
203         ret = PyObject_CallMethod(self, "delete_path", "s", path);
204         CB_CHECK_PYRETVAL(ret);
205         Py_DECREF(ret);
206         PyGILState_Release(state);
207         return NULL;
208 }
209
210 static svn_error_t *py_ra_report_finish(void *baton, apr_pool_t *pool)
211 {
212         PyObject *self = (PyObject *)baton, *ret;
213         PyGILState_STATE state = PyGILState_Ensure();
214         ret = PyObject_CallMethod(self, "finish", "");
215         CB_CHECK_PYRETVAL(ret);
216         Py_DECREF(ret);
217         PyGILState_Release(state);
218         return NULL;
219 }
220
221 static svn_error_t *py_ra_report_abort(void *baton, apr_pool_t *pool)
222 {
223         PyObject *self = (PyObject *)baton, *ret;
224         PyGILState_STATE state = PyGILState_Ensure();
225         ret = PyObject_CallMethod(self, "abort", "");
226         CB_CHECK_PYRETVAL(ret);
227         Py_DECREF(ret);
228         PyGILState_Release(state);
229         return NULL;
230 }
231
232 static const REPORTER_T py_ra_reporter = {
233         py_ra_report_set_path,
234         py_ra_report_delete_path,
235         py_ra_report_link_path,
236         py_ra_report_finish,
237         py_ra_report_abort,
238 };
239
240
241
242 /**
243  * Get runtime libsvn_wc version information.
244  *
245  * :return: tuple with major, minor, patch version number and tag.
246  */
247 static PyObject *version(PyObject *self)
248 {
249         const svn_version_t *ver = svn_wc_version();
250         return Py_BuildValue("(iiis)", ver->major, ver->minor, 
251                                                  ver->patch, ver->tag);
252 }
253
254 SVN_VERSION_DEFINE(svn_api_version);
255
256 /**
257  * Get compile-time libsvn_wc version information.
258  *
259  * :return: tuple with major, minor, patch version number and tag.
260  */
261 static PyObject *api_version(PyObject *self)
262 {
263         const svn_version_t *ver = &svn_api_version;
264         return Py_BuildValue("(iiis)", ver->major, ver->minor, 
265                                                  ver->patch, ver->tag);
266 }
267
268 static svn_error_t *py_wc_found_entry(const char *path, const svn_wc_entry_t *entry, void *walk_baton, apr_pool_t *pool)
269 {
270         PyObject *fn, *ret;
271         PyObject *callbacks = (PyObject *)walk_baton;
272         PyGILState_STATE state = PyGILState_Ensure();
273         if (PyTuple_Check(callbacks)) {
274                 fn = PyTuple_GET_ITEM(callbacks, 0);
275         } else {
276                 fn = (PyObject *)walk_baton;
277         }
278         ret = PyObject_CallFunction(fn, "sO", path, py_entry(entry));
279         CB_CHECK_PYRETVAL(ret);
280         Py_DECREF(ret);
281         PyGILState_Release(state);
282         return NULL;
283 }
284
285 #if ONLY_SINCE_SVN(1, 5)
286
287 svn_error_t *py_wc_handle_error(const char *path, svn_error_t *err, void *walk_baton, apr_pool_t *pool)
288 {
289         PyObject *fn, *ret;
290         PyObject *py_err;
291         PyGILState_STATE state;
292         PyObject *callbacks = (PyObject *)walk_baton;
293         if (PyTuple_Check(callbacks)) {
294                 fn = PyTuple_GET_ITEM(callbacks, 1);
295         } else {
296                 return err;
297         }
298         state = PyGILState_Ensure();
299         py_err = PyErr_NewSubversionException(err);
300         ret = PyObject_CallFunction(fn, "sO", path, py_err);
301         CB_CHECK_PYRETVAL(ret);
302         Py_DECREF(ret);
303         PyGILState_Release(state);
304         Py_DECREF(py_err);
305         return NULL;
306 }
307
308 static svn_wc_entry_callbacks2_t py_wc_entry_callbacks2 = {
309         py_wc_found_entry,
310         py_wc_handle_error,
311 };
312 #else
313 static svn_wc_entry_callbacks_t py_wc_entry_callbacks = {
314         py_wc_found_entry
315 };
316
317 #endif
318
319
320 void py_wc_notify_func(void *baton, const svn_wc_notify_t *notify, apr_pool_t *pool)
321 {
322         PyObject *func = baton, *ret;
323         if (func == Py_None)
324                 return;
325
326         if (notify->err != NULL) {
327                 PyObject *excval = PyErr_NewSubversionException(notify->err);
328                 ret = PyObject_CallFunction(func, "O", excval);
329                 Py_DECREF(excval);
330                 Py_XDECREF(ret);
331                 /* FIXME: Use return value */
332         }
333 }
334
335 typedef struct {
336         PyObject_HEAD
337         apr_pool_t *pool;
338         svn_wc_entry_t entry;
339 } EntryObject;
340
341 static void entry_dealloc(PyObject *self)
342 {
343         apr_pool_destroy(((EntryObject *)self)->pool);
344         PyObject_Del(self);
345 }
346
347 static PyMemberDef entry_members[] = {
348         { "name", T_STRING, offsetof(EntryObject, entry.name), READONLY, 
349                 "Name of the file"},
350         { "copyfrom_url", T_STRING, offsetof(EntryObject, entry.copyfrom_url), READONLY, 
351                 "Copyfrom location" },
352         { "copyfrom_rev", T_LONG, offsetof(EntryObject, entry.copyfrom_rev), READONLY, 
353                 "Copyfrom revision" },
354         { "uuid", T_STRING, offsetof(EntryObject, entry.uuid), READONLY,
355                 "UUID of repository" },
356         { "url", T_STRING, offsetof(EntryObject, entry.url), READONLY, 
357                 "URL in repository" },
358         { "repos", T_STRING, offsetof(EntryObject, entry.repos), READONLY, 
359                 "Canonical repository URL" },
360         { "schedule", T_INT, offsetof(EntryObject, entry.schedule), READONLY, 
361                 "Scheduling (add, replace, delete, etc)" },
362         { "kind", T_INT, offsetof(EntryObject, entry.kind), READONLY, 
363                 "Kind of file (file, dir, etc)" },
364         { "revision", T_LONG, offsetof(EntryObject, entry.revision), READONLY, 
365                 "Base revision", },
366         { "cmt_rev", T_LONG, offsetof(EntryObject, entry.cmt_rev), READONLY, 
367                 "Last revision this was changed" },
368         { "checksum", T_STRING, offsetof(EntryObject, entry.checksum), READONLY, 
369                 "Hex MD5 checksum for the untranslated text base file" },
370         { "cmt_date", T_LONG, offsetof(EntryObject, entry.cmt_date), READONLY, 
371                 "Last date this was changed" },
372         { "cmt_author", T_STRING, offsetof(EntryObject, entry.cmt_author), READONLY, 
373                 "Last commit author of this item" },
374         { NULL, }
375 };
376
377 static PyTypeObject Entry_Type = {
378         PyObject_HEAD_INIT(NULL) 0,
379         "wc.Entry", /*  const char *tp_name;  For printing, in format "<module>.<name>" */
380         sizeof(EntryObject), 
381         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
382         
383         /* Methods to implement standard operations */
384         
385         entry_dealloc, /*       destructor tp_dealloc;  */
386         NULL, /*        printfunc tp_print;     */
387         NULL, /*        getattrfunc tp_getattr; */
388         NULL, /*        setattrfunc tp_setattr; */
389         NULL, /*        cmpfunc tp_compare;     */
390         NULL, /*        reprfunc tp_repr;       */
391         
392         /* Method suites for standard classes */
393         
394         NULL, /*        PyNumberMethods *tp_as_number;  */
395         NULL, /*        PySequenceMethods *tp_as_sequence;      */
396         NULL, /*        PyMappingMethods *tp_as_mapping;        */
397         
398         /* More standard operations (here for binary compatibility) */
399         
400         NULL, /*        hashfunc tp_hash;       */
401         NULL, /*        ternaryfunc tp_call;    */
402         NULL, /*        reprfunc tp_str;        */
403         NULL, /*        getattrofunc tp_getattro;       */
404         NULL, /*        setattrofunc tp_setattro;       */
405         
406         /* Functions to access object as input/output buffer */
407         NULL, /*        PyBufferProcs *tp_as_buffer;    */
408         
409         /* Flags to define presence of optional/expanded features */
410         0, /*   long tp_flags;  */
411         
412         NULL, /*        const char *tp_doc;  Documentation string */
413         
414         /* Assigned meaning in release 2.0 */
415         /* call function for all accessible objects */
416         NULL, /*        traverseproc tp_traverse;       */
417         
418         /* delete references to contained objects */
419         NULL, /*        inquiry tp_clear;       */
420         
421         /* Assigned meaning in release 2.1 */
422         /* rich comparisons */
423         NULL, /*        richcmpfunc tp_richcompare;     */
424         
425         /* weak reference enabler */
426         0, /*   Py_ssize_t tp_weaklistoffset;   */
427         
428         /* Added in release 2.2 */
429         /* Iterators */
430         NULL, /*        getiterfunc tp_iter;    */
431         NULL, /*        iternextfunc tp_iternext;       */
432         
433         /* Attribute descriptor and subclassing stuff */
434         NULL, /*        struct PyMethodDef *tp_methods; */
435         entry_members, /*       struct PyMemberDef *tp_members; */
436
437 };
438
439 static PyObject *py_entry(const svn_wc_entry_t *entry)
440 {
441         EntryObject *ret;
442
443         ret = PyObject_New(EntryObject, &Entry_Type);
444         if (ret == NULL)
445                 return NULL;
446
447         ret->pool = Pool(NULL);
448         if (ret->pool == NULL)
449                 return NULL;
450         ret->entry = *svn_wc_entry_dup(entry, ret->pool);
451         return (PyObject *)ret;
452 }
453
454 typedef struct {
455         PyObject_HEAD
456         svn_wc_adm_access_t *adm;
457         apr_pool_t *pool;
458 } AdmObject;
459
460 #define ADM_CHECK_CLOSED(adm_obj) \
461         if (adm_obj->adm == NULL) { \
462                 PyErr_SetString(PyExc_RuntimeError, "WorkingCopy instance already closed"); \
463                 return NULL; \
464         }
465
466 static PyObject *adm_init(PyTypeObject *self, PyObject *args, PyObject *kwargs)
467 {
468         PyObject *associated;
469         char *path;
470         bool write_lock=false;
471         int depth=0;
472         PyObject *cancel_func=Py_None;
473         svn_wc_adm_access_t *parent_wc;
474         svn_error_t *err;
475         AdmObject *ret;
476         char *kwnames[] = { "associated", "path", "write_lock", "depth", "cancel_func", NULL };
477
478         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os|biO", kwnames, &associated, &path, &write_lock, &depth, &cancel_func))
479                 return NULL;
480
481         ret = PyObject_New(AdmObject, &Adm_Type);
482         if (ret == NULL)
483                 return NULL;
484
485         ret->pool = Pool(NULL);
486         if (ret->pool == NULL)
487                 return NULL;
488         if (associated == Py_None) {
489                 parent_wc = NULL;
490         } else {
491                 parent_wc = ((AdmObject *)associated)->adm;
492         }
493         Py_BEGIN_ALLOW_THREADS
494         err = svn_wc_adm_open3(&ret->adm, parent_wc, 
495                                                    svn_path_canonicalize(path, ret->pool),
496                                                    write_lock, depth, py_cancel_func, cancel_func, 
497                                                    ret->pool);
498         Py_END_ALLOW_THREADS
499         
500         if (!check_error(err)) {
501                 return NULL;
502         }
503
504         return (PyObject *)ret;
505 }
506
507 static PyObject *adm_access_path(PyObject *self)
508 {
509         AdmObject *admobj = (AdmObject *)self;
510         ADM_CHECK_CLOSED(admobj);
511         return PyString_FromString(svn_wc_adm_access_path(admobj->adm));
512 }
513
514 static PyObject *adm_locked(PyObject *self)
515 {
516         AdmObject *admobj = (AdmObject *)self;
517         ADM_CHECK_CLOSED(admobj);
518         return PyBool_FromLong(svn_wc_adm_locked(admobj->adm));
519 }
520
521 static PyObject *adm_prop_get(PyObject *self, PyObject *args)
522 {
523         char *name, *path;
524         AdmObject *admobj = (AdmObject *)self;
525         const svn_string_t *value;
526         apr_pool_t *temp_pool;
527         PyObject *ret;
528
529         if (!PyArg_ParseTuple(args, "ss", &name, &path))
530                 return NULL;
531
532         ADM_CHECK_CLOSED(admobj);
533
534         temp_pool = Pool(NULL);
535         if (temp_pool == NULL)
536                 return NULL;
537         RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_get(&value, name, path, admobj->adm, temp_pool));
538         if (value == NULL || value->data == NULL) {
539                 ret = Py_None;
540                 Py_INCREF(ret);
541         } else {
542                 ret = PyString_FromStringAndSize(value->data, value->len);
543         }
544         apr_pool_destroy(temp_pool);
545         return ret;
546 }
547
548 static PyObject *adm_prop_set(PyObject *self, PyObject *args)
549 {
550         char *name, *value, *path; 
551         AdmObject *admobj = (AdmObject *)self;
552         bool skip_checks=false;
553         apr_pool_t *temp_pool;
554         int vallen;
555         svn_string_t *cvalue;
556         PyObject *notify_func = Py_None;
557
558         if (!PyArg_ParseTuple(args, "ss#s|bO", &name, &value, &vallen, &path, &skip_checks,
559                                                   &notify_func))
560                 return NULL;
561
562         ADM_CHECK_CLOSED(admobj);
563
564         temp_pool = Pool(NULL);
565         if (temp_pool == NULL)
566                 return NULL;
567         cvalue = svn_string_ncreate(value, vallen, temp_pool);
568 #if ONLY_SINCE_SVN(1, 6)
569         RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_set3(name, cvalue, path, admobj->adm, 
570                                 skip_checks, py_wc_notify_func, (void *)notify_func, 
571                                 temp_pool));
572 #else
573         RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_set2(name, cvalue, path, admobj->adm, 
574                                 skip_checks, temp_pool));
575 #endif
576         apr_pool_destroy(temp_pool);
577
578         Py_RETURN_NONE;
579 }
580
581 static PyObject *adm_entries_read(PyObject *self, PyObject *args)
582 {
583         apr_hash_t *entries;
584         AdmObject *admobj = (AdmObject *)self;
585         apr_pool_t *temp_pool;
586         bool show_hidden=false;
587         apr_hash_index_t *idx;
588         const char *key;
589         apr_ssize_t klen;
590         svn_wc_entry_t *entry;
591         PyObject *py_entries, *obj;
592
593         if (!PyArg_ParseTuple(args, "|b", &show_hidden))
594                 return NULL;
595
596         ADM_CHECK_CLOSED(admobj);
597
598         temp_pool = Pool(NULL);
599         if (temp_pool == NULL)
600                 return NULL;
601         RUN_SVN_WITH_POOL(temp_pool, svn_wc_entries_read(&entries, admobj->adm, 
602                                  show_hidden, temp_pool));
603         py_entries = PyDict_New();
604         if (py_entries == NULL) {
605                 apr_pool_destroy(temp_pool);
606                 return NULL;
607         }
608         idx = apr_hash_first(temp_pool, entries);
609         while (idx != NULL) {
610                 apr_hash_this(idx, (const void **)&key, &klen, (void **)&entry);
611                 if (entry == NULL) {
612                         obj = Py_None;
613                         Py_INCREF(obj);
614                 } else {
615                         obj = py_entry(entry);
616                 }
617                 PyDict_SetItemString(py_entries, key, obj);
618                 Py_DECREF(obj);
619                 idx = apr_hash_next(idx);
620         }
621         apr_pool_destroy(temp_pool);
622         return py_entries;
623 }
624
625 static PyObject *adm_walk_entries(PyObject *self, PyObject *args)
626 {
627         char *path;
628         PyObject *callbacks; 
629         bool show_hidden=false;
630         PyObject *cancel_func=Py_None;
631         apr_pool_t *temp_pool;
632         AdmObject *admobj = (AdmObject *)self;
633         svn_depth_t depth = svn_depth_infinity;
634
635         if (!PyArg_ParseTuple(args, "sO|bOi", &path, &callbacks, &show_hidden, &cancel_func,
636                                                   &depth))
637                 return NULL;
638
639         ADM_CHECK_CLOSED(admobj);
640
641         temp_pool = Pool(NULL);
642         if (temp_pool == NULL)
643                 return NULL;
644 #if ONLY_SINCE_SVN(1, 5)
645         RUN_SVN_WITH_POOL(temp_pool, svn_wc_walk_entries3(path, admobj->adm, 
646                                 &py_wc_entry_callbacks2, (void *)callbacks,
647                                 depth, show_hidden, py_cancel_func, (void *)cancel_func,
648                                 temp_pool));
649 #else
650         if (depth != svn_depth_infinity) {
651                 PyErr_SetString(PyExc_NotImplementedError, 
652                                                 "depth != infinity not supported for svn < 1.5");
653                 apr_pool_destroy(temp_pool);
654                 return NULL;
655         }
656         RUN_SVN_WITH_POOL(temp_pool, svn_wc_walk_entries2(path, admobj->adm, 
657                                 &py_wc_entry_callbacks, (void *)callbacks,
658                                 show_hidden, py_cancel_func, (void *)cancel_func,
659                                 temp_pool));
660 #endif
661         apr_pool_destroy(temp_pool);
662
663         Py_RETURN_NONE;
664 }
665
666 static PyObject *adm_entry(PyObject *self, PyObject *args)
667 {
668         char *path;
669         bool show_hidden=false;
670         apr_pool_t *temp_pool;
671         AdmObject *admobj = (AdmObject *)self;
672         const svn_wc_entry_t *entry;
673         PyObject *ret;
674
675         if (!PyArg_ParseTuple(args, "s|b", &path, &show_hidden))
676                 return NULL;
677
678         ADM_CHECK_CLOSED(admobj);
679
680         temp_pool = Pool(NULL);
681         if (temp_pool == NULL)
682                 return NULL;
683         RUN_SVN_WITH_POOL(temp_pool, svn_wc_entry(&entry, svn_path_canonicalize(path, temp_pool), admobj->adm, show_hidden, temp_pool));
684
685         if (entry == NULL) {
686                 PyErr_Format(PyExc_KeyError, "No such entry '%s'", path);
687                 ret = NULL;
688         } else  {
689                 ret = py_entry(entry);
690         }
691
692         apr_pool_destroy(temp_pool);
693         return ret;
694 }
695
696 static PyObject *adm_get_prop_diffs(PyObject *self, PyObject *args)
697 {
698         char *path;
699         apr_pool_t *temp_pool;
700         apr_array_header_t *propchanges;
701         apr_hash_t *original_props;
702         AdmObject *admobj = (AdmObject *)self;
703         svn_prop_t el;
704         int i;
705         PyObject *py_propchanges, *py_orig_props, *pyval;
706
707         if (!PyArg_ParseTuple(args, "s", &path))
708                 return NULL;
709
710         ADM_CHECK_CLOSED(admobj);
711
712         temp_pool = Pool(NULL);
713         if (temp_pool == NULL)
714                 return NULL;
715         RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_prop_diffs(&propchanges, &original_props, 
716                                 svn_path_canonicalize(path, temp_pool), admobj->adm, temp_pool));
717         py_propchanges = PyList_New(propchanges->nelts);
718         if (py_propchanges == NULL) {
719                 apr_pool_destroy(temp_pool);
720                 return NULL;
721         }
722         for (i = 0; i < propchanges->nelts; i++) {
723                 el = APR_ARRAY_IDX(propchanges, i, svn_prop_t);
724                 if (el.value != NULL)
725                         pyval = Py_BuildValue("(sz#)", el.name, el.value->data, el.value->len);
726                 else
727                         pyval = Py_BuildValue("(sO)", el.name, Py_None);
728                 if (pyval == NULL) {
729                         apr_pool_destroy(temp_pool);
730                         return NULL;
731                 }
732                 PyList_SetItem(py_propchanges, i, pyval);
733         }
734         py_orig_props = prop_hash_to_dict(original_props);
735         apr_pool_destroy(temp_pool);
736         if (py_orig_props == NULL)
737                 return NULL;
738         return Py_BuildValue("(NN)", py_propchanges, py_orig_props);
739 }
740
741 static PyObject *adm_add(PyObject *self, PyObject *args, PyObject *kwargs)
742 {
743         char *path, *copyfrom_url=NULL;
744         svn_revnum_t copyfrom_rev=-1; 
745         char *kwnames[] = { "path", "copyfrom_url", "copyfrom_rev", "cancel_func", 
746                                 "notify_func", "depth", NULL };
747         PyObject *cancel_func=Py_None, *notify_func=Py_None;
748         AdmObject *admobj = (AdmObject *)self;
749         apr_pool_t *temp_pool;
750         svn_depth_t depth = svn_depth_infinity;
751
752         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zlOOi", kwnames, &path, &copyfrom_url, &copyfrom_rev, &cancel_func, &notify_func, &depth))
753                 return NULL;
754
755         ADM_CHECK_CLOSED(admobj);
756
757         temp_pool = Pool(NULL);
758         if (temp_pool == NULL)
759                 return NULL;
760
761 #if ONLY_SINCE_SVN(1, 6)
762         RUN_SVN_WITH_POOL(temp_pool, svn_wc_add3(
763                                                    svn_path_canonicalize(path, temp_pool), admobj->adm, depth, copyfrom_url, 
764                                                         copyfrom_rev, py_cancel_func, 
765                                                         (void *)cancel_func,
766                                                         py_wc_notify_func, 
767                                                         (void *)notify_func, 
768                                                         temp_pool));
769 #else
770         if (depth != svn_depth_infinity) {
771                 PyErr_SetString(PyExc_NotImplementedError, "depth != infinity not supported on svn < 1.6");
772                 apr_pool_destroy(temp_pool);
773                 return NULL;
774         }
775         RUN_SVN_WITH_POOL(temp_pool, svn_wc_add2(
776                                                    svn_path_canonicalize(path, temp_pool), admobj->adm, copyfrom_url, 
777                                                         copyfrom_rev, py_cancel_func, 
778                                                         (void *)cancel_func,
779                                                         py_wc_notify_func, 
780                                                         (void *)notify_func, 
781                                                         temp_pool));
782 #endif
783         apr_pool_destroy(temp_pool);
784
785         Py_RETURN_NONE;
786 }
787
788 static PyObject *adm_copy(PyObject *self, PyObject *args)
789 {
790         AdmObject *admobj = (AdmObject *)self;
791         char *src, *dst; 
792         PyObject *cancel_func=Py_None, *notify_func=Py_None;
793         apr_pool_t *temp_pool;
794
795         if (!PyArg_ParseTuple(args, "ss|OO", &src, &dst, &cancel_func, &notify_func))
796                 return NULL;
797
798         ADM_CHECK_CLOSED(admobj);
799
800         temp_pool = Pool(NULL);
801         if (temp_pool == NULL)
802                 return NULL;
803         RUN_SVN_WITH_POOL(temp_pool, svn_wc_copy2(src, admobj->adm, dst,
804                                                         py_cancel_func, (void *)cancel_func,
805                                                         py_wc_notify_func, (void *)notify_func, 
806                                                         temp_pool));
807         apr_pool_destroy(temp_pool);
808
809         Py_RETURN_NONE;
810 }
811
812 static PyObject *adm_delete(PyObject *self, PyObject *args, PyObject *kwargs)
813 {
814         AdmObject *admobj = (AdmObject *)self;
815         apr_pool_t *temp_pool;
816         char *kwnames[] = { "path", "cancel_func", "notify_func", "keep_local",
817                                 NULL };
818         char *path;
819         PyObject *cancel_func=Py_None, *notify_func=Py_None;
820         bool keep_local = false;
821
822         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|OOb", kwnames, 
823                                                                          &path, &cancel_func, &notify_func, 
824                                                                          &keep_local))
825                 return NULL;
826
827         ADM_CHECK_CLOSED(admobj);
828
829         temp_pool = Pool(NULL);
830         if (temp_pool == NULL)
831                 return NULL;
832
833 #if ONLY_SINCE_SVN(1, 5)
834         RUN_SVN_WITH_POOL(temp_pool, svn_wc_delete3(path, admobj->adm, 
835                                                         py_cancel_func, (void *)cancel_func,
836                                                         py_wc_notify_func, (void *)notify_func, 
837                                                         keep_local,
838                                                         temp_pool));
839 #else
840         if (keep_local) {
841                 PyErr_SetString(PyExc_NotImplementedError, 
842                                                 "keep_local not supported on Subversion < 1.5");
843                 return NULL;
844         }
845
846         RUN_SVN_WITH_POOL(temp_pool, svn_wc_delete2(path, admobj->adm, 
847                                                         py_cancel_func, (void *)cancel_func,
848                                                         py_wc_notify_func, (void *)notify_func, 
849                                                         temp_pool));
850 #endif
851         apr_pool_destroy(temp_pool);
852
853         Py_RETURN_NONE;
854 }
855
856 static PyObject *adm_crawl_revisions(PyObject *self, PyObject *args, PyObject *kwargs)
857 {
858         char *path;
859         PyObject *reporter;
860         bool restore_files=true, recurse=true, use_commit_times=true;
861         PyObject *notify_func=Py_None;
862         apr_pool_t *temp_pool;
863         AdmObject *admobj = (AdmObject *)self;
864         svn_wc_traversal_info_t *traversal_info;
865         svn_boolean_t depth_compatibility_trick = FALSE;
866         svn_boolean_t honor_depth_exclude = FALSE;
867         char *kwnames[] = { "path", "reporter", "restore_files", "recurse", "use_commit_times", "notify_func", "depth_compatibility_trick", "honor_depth_exclude,", NULL };
868
869         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|bbbObb", kwnames, &path, &reporter, &restore_files, &recurse, &use_commit_times,
870                                                   &notify_func, &depth_compatibility_trick, &honor_depth_exclude))
871                 return NULL;
872
873         ADM_CHECK_CLOSED(admobj);
874
875         temp_pool = Pool(NULL);
876         if (temp_pool == NULL)
877                 return NULL;
878         traversal_info = svn_wc_init_traversal_info(temp_pool);
879 #if ONLY_SINCE_SVN(1, 6)
880         RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions4(path, admobj->adm, 
881                                 &py_ra_reporter, (void *)reporter, 
882                                 restore_files, recurse?svn_depth_infinity:svn_depth_files,
883                                 honor_depth_exclude,
884                                 depth_compatibility_trick, use_commit_times, 
885                                 py_wc_notify_func, (void *)notify_func,
886                                 traversal_info, temp_pool));
887 #elif ONLY_SINCE_SVN(1, 5)
888         RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions3(path, admobj->adm, 
889                                 &py_ra_reporter, (void *)reporter, 
890                                 restore_files, recurse?svn_depth_infinity:svn_depth_files, 
891                                 depth_compatibility_trick, use_commit_times, 
892                                 py_wc_notify_func, (void *)notify_func,
893                                 traversal_info, temp_pool));
894 #else
895         RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions2(path, admobj->adm, 
896                                 &py_ra_reporter, (void *)reporter, 
897                                 restore_files, recurse, use_commit_times, 
898                                 py_wc_notify_func, (void *)notify_func,
899                                 traversal_info, temp_pool));
900 #endif
901         apr_pool_destroy(temp_pool);
902
903         Py_RETURN_NONE;
904 }
905
906 static PyObject *adm_get_update_editor(PyObject *self, PyObject *args)
907 {
908         char *target;
909         bool use_commit_times=true, recurse=true;
910         PyObject * notify_func=Py_None, *cancel_func=Py_None;
911         char *diff3_cmd=NULL;
912         const svn_delta_editor_t *editor;
913         AdmObject *admobj = (AdmObject *)self;
914         void *edit_baton;
915         apr_pool_t *pool;
916         svn_revnum_t *latest_revnum;
917         svn_error_t *err;
918         svn_boolean_t allow_unver_obstructions = FALSE;
919         svn_boolean_t depth_is_sticky = FALSE;
920
921         if (!PyArg_ParseTuple(args, "s|bbOOzbb", &target, &use_commit_times, &recurse, &notify_func, &cancel_func, &diff3_cmd,
922                                                   &depth_is_sticky, &allow_unver_obstructions))
923                 return NULL;
924
925         ADM_CHECK_CLOSED(admobj);
926
927         pool = Pool(NULL);
928         if (pool == NULL)
929                 return NULL;
930         latest_revnum = (svn_revnum_t *)apr_palloc(pool, sizeof(svn_revnum_t));
931         Py_BEGIN_ALLOW_THREADS
932 #if ONLY_SINCE_SVN(1, 5)
933         /* FIXME: Support all values of depth */
934         /* FIXME: Support fetch_func */
935         /* FIXME: Support conflict func */
936         err = svn_wc_get_update_editor3(latest_revnum, admobj->adm, target, 
937                                 use_commit_times, recurse?svn_depth_infinity:svn_depth_files, depth_is_sticky, allow_unver_obstructions, 
938                                 py_wc_notify_func, (void *)notify_func, 
939                                 py_cancel_func, (void *)cancel_func, 
940                                 NULL, NULL, NULL, NULL,
941                                 diff3_cmd, NULL, &editor, &edit_baton, 
942                                 NULL, pool);
943 #else
944         if (allow_unver_obstructions) {
945                 PyErr_SetString(PyExc_NotImplementedError, 
946                                                 "allow_unver_obstructions is not supported in svn < 1.5");
947                 apr_pool_destroy(pool);
948                 PyEval_RestoreThread(_save);
949                 return NULL;
950         }
951         if (depth_is_sticky) {
952                 PyErr_SetString(PyExc_NotImplementedError, 
953                                                 "depth_is_sticky is not supported in svn < 1.5");
954                 apr_pool_destroy(pool);
955                 PyEval_RestoreThread(_save);
956                 return NULL;
957         }
958         err = svn_wc_get_update_editor2(latest_revnum, admobj->adm, target, 
959                                 use_commit_times, recurse, py_wc_notify_func, (void *)notify_func, 
960                                 py_cancel_func, (void *)cancel_func, diff3_cmd, &editor, &edit_baton, 
961                                 NULL, pool);
962 #endif
963         if (!check_error(err)) {
964                 apr_pool_destroy(pool);
965                 PyEval_RestoreThread(_save);
966                 return NULL;
967         }
968         Py_END_ALLOW_THREADS
969         return new_editor_object(editor, edit_baton, pool, &Editor_Type, NULL, NULL, NULL);
970 }
971
972 static bool py_dict_to_wcprop_changes(PyObject *dict, apr_pool_t *pool, apr_array_header_t **ret)
973 {
974         PyObject *key, *val;
975         Py_ssize_t idx;
976
977         if (dict == Py_None) {
978                 *ret = NULL;
979                 return true;
980         }
981
982         if (!PyDict_Check(dict)) {
983                 PyErr_SetString(PyExc_TypeError, "Expected dictionary with property changes");
984                 return false;
985         }
986
987         *ret = apr_array_make(pool, PyDict_Size(dict), sizeof(char *));
988
989         while (PyDict_Next(dict, &idx, &key, &val)) {
990                    svn_prop_t *prop = apr_palloc(pool, sizeof(svn_prop_t));
991                    prop->name = PyString_AsString(key);
992                    if (val == Py_None) {
993                            prop->value = NULL;
994                    } else {
995                            prop->value = svn_string_ncreate(PyString_AsString(val), PyString_Size(val), pool);
996                    }
997                    APR_ARRAY_PUSH(*ret, svn_prop_t *) = prop;
998         }
999
1000         return true;
1001 }
1002
1003 static PyObject *adm_has_binary_prop(PyObject *self, PyObject *args)
1004 {
1005         char *path;
1006         svn_boolean_t binary;
1007         AdmObject *admobj = (AdmObject *)self;
1008         apr_pool_t *temp_pool;
1009
1010         if (!PyArg_ParseTuple(args, "s", &path))
1011                 return NULL;
1012
1013         ADM_CHECK_CLOSED(admobj);
1014
1015         temp_pool = Pool(NULL);
1016         if (temp_pool == NULL)
1017                 return NULL;
1018
1019         RUN_SVN_WITH_POOL(temp_pool, svn_wc_has_binary_prop(&binary, path, admobj->adm, temp_pool));
1020
1021         apr_pool_destroy(temp_pool);
1022
1023         return PyBool_FromLong(binary);
1024 }
1025
1026 static PyObject *adm_process_committed(PyObject *self, PyObject *args, PyObject *kwargs)
1027 {
1028         char *path, *rev_date = NULL, *rev_author = NULL;
1029         bool recurse, remove_lock = false;
1030         unsigned char *digest = NULL;
1031         svn_revnum_t new_revnum;
1032         PyObject *py_wcprop_changes = Py_None;
1033         apr_array_header_t *wcprop_changes = NULL;
1034         AdmObject *admobj = (AdmObject *)self;
1035         apr_pool_t *temp_pool;
1036         svn_boolean_t remove_changelist = FALSE;
1037         char *kwnames[] = { "path", "recurse", "new_revnum", "rev_date", "rev_author", 
1038                                                 "wcprop_changes", "remove_lock", "digest", "remove_changelist", NULL };
1039
1040         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sblzz|Obzb", kwnames, 
1041                                                                          &path, &recurse, &new_revnum, &rev_date,
1042                                                                          &rev_author, &py_wcprop_changes, 
1043                                                                          &remove_lock, &digest, &remove_changelist))
1044                 return NULL;
1045
1046 #if PY_VERSION_HEX < 0x02050000
1047         PyErr_Warn(PyExc_DeprecationWarning, "process_committed is deprecated. Use process_committed_queue instead.");
1048 #else
1049         PyErr_WarnEx(PyExc_DeprecationWarning, "process_committed is deprecated. Use process_committed_queue instead.", 2);
1050 #endif
1051
1052
1053         ADM_CHECK_CLOSED(admobj);
1054
1055         temp_pool = Pool(NULL);
1056         if (temp_pool == NULL)
1057                 return NULL;
1058
1059         if (!py_dict_to_wcprop_changes(py_wcprop_changes, temp_pool, &wcprop_changes)) {
1060                 apr_pool_destroy(temp_pool);
1061                 return NULL;
1062         }
1063
1064 #if ONLY_SINCE_SVN(1, 6)
1065         RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed4(
1066                 svn_path_canonicalize(path, temp_pool), admobj->adm, recurse, new_revnum, 
1067                         rev_date, rev_author, wcprop_changes, 
1068                         remove_lock, remove_changelist, digest, temp_pool));
1069 #else
1070         if (remove_changelist) {
1071                 PyErr_SetString(PyExc_NotImplementedError, "remove_changelist only supported in svn < 1.6");
1072                 apr_pool_destroy(temp_pool);
1073                 return NULL;
1074         }
1075         RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(svn_path_canonicalize(path, temp_pool), admobj->adm, recurse, new_revnum, 
1076                                                                                                                    rev_date, rev_author, wcprop_changes, 
1077                                                                                                                    remove_lock, digest, temp_pool));
1078 #endif
1079
1080         apr_pool_destroy(temp_pool);
1081
1082         Py_RETURN_NONE;
1083 }
1084
1085 static PyObject *adm_close(PyObject *self)
1086 {
1087         AdmObject *admobj = (AdmObject *)self;
1088         if (admobj->adm != NULL) {
1089 #if ONLY_SINCE_SVN(1, 6)
1090                 apr_pool_t *temp_pool = Pool(NULL);
1091                 Py_BEGIN_ALLOW_THREADS
1092                 svn_wc_adm_close2(admobj->adm, temp_pool);
1093                 apr_pool_destroy(temp_pool);
1094 #else
1095                 Py_BEGIN_ALLOW_THREADS
1096                 svn_wc_adm_close(admobj->adm);
1097 #endif
1098                 Py_END_ALLOW_THREADS
1099                 admobj->adm = NULL;
1100         }
1101
1102         Py_RETURN_NONE;
1103 }
1104
1105 static void adm_dealloc(PyObject *self)
1106 {
1107         apr_pool_destroy(((AdmObject *)self)->pool);
1108         PyObject_Del(self);
1109 }
1110
1111 static PyObject *adm_repr(PyObject *self)
1112 {
1113         AdmObject *admobj = (AdmObject *)self;
1114
1115         if (admobj->adm == NULL) {
1116                 return PyString_FromFormat("<wc.WorkingCopy (closed) at 0x%p>", admobj);
1117         } else {
1118                 return PyString_FromFormat("<wc.WorkingCopy at '%s'>", 
1119                                                                    svn_wc_adm_access_path(admobj->adm));
1120         }
1121 }
1122
1123 static PyObject *adm_remove_lock(PyObject *self, PyObject *args)
1124 {
1125         char *path;
1126         AdmObject *admobj = (AdmObject *)self;
1127         apr_pool_t *temp_pool;
1128
1129         if (!PyArg_ParseTuple(args, "s", &path))
1130                 return NULL;
1131
1132         ADM_CHECK_CLOSED(admobj);
1133
1134         temp_pool = Pool(NULL);
1135         if (temp_pool == NULL)
1136                 return NULL;
1137
1138         RUN_SVN_WITH_POOL(temp_pool, svn_wc_remove_lock(path, admobj->adm, temp_pool))
1139
1140         apr_pool_destroy(temp_pool);
1141
1142         Py_RETURN_NONE;
1143 }
1144
1145 static PyObject *get_ancestry(PyObject *self, PyObject *args)
1146 {
1147         char *path;
1148         char *url;
1149         svn_revnum_t rev;
1150         apr_pool_t *temp_pool;
1151         AdmObject *admobj = (AdmObject *)self;
1152
1153         if (!PyArg_ParseTuple(args, "s", &path))
1154                 return NULL;
1155
1156         ADM_CHECK_CLOSED(admobj);
1157
1158         temp_pool = Pool(NULL);
1159         if (temp_pool == NULL)
1160                 return NULL;
1161
1162         RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_ancestry(&url, &rev, path, admobj->adm, temp_pool));
1163
1164         apr_pool_destroy(temp_pool);
1165
1166         return Py_BuildValue("(si)", url, rev);
1167 }
1168
1169 static PyObject *maybe_set_repos_root(PyObject *self, PyObject *args)
1170 {
1171         char *path, *repos;
1172         apr_pool_t *temp_pool;
1173         AdmObject *admobj = (AdmObject *)self;
1174
1175         if (!PyArg_ParseTuple(args, "ss", &path, &repos))
1176                 return NULL;
1177
1178         ADM_CHECK_CLOSED(admobj);
1179
1180         temp_pool = Pool(NULL);
1181         if (temp_pool == NULL)
1182                 return NULL;
1183
1184         RUN_SVN_WITH_POOL(temp_pool, svn_wc_maybe_set_repos_root(admobj->adm, path, repos, temp_pool));
1185
1186         Py_RETURN_NONE;
1187 }
1188
1189 static PyObject *add_repos_file(PyObject *self, PyObject *args, PyObject *kwargs)
1190 {
1191         char *kwnames[] = { "dst_path", "new_base_contents", "new_contents",
1192                 "new_base_props", "new_props", "copyfrom_url", "copyfrom_rev",
1193                 "cancel_func", "notify", NULL };
1194         AdmObject *admobj = (AdmObject *)self;
1195         apr_pool_t *temp_pool;
1196         char *dst_path, *copyfrom_url = NULL;
1197         svn_revnum_t copyfrom_rev = -1;
1198         PyObject *py_new_base_contents, *py_new_contents, *py_new_base_props,
1199                          *py_new_props, *cancel_func = Py_None, *notify = Py_None;
1200         svn_stream_t *new_contents, *new_base_contents;
1201         apr_hash_t *new_props, *new_base_props;
1202
1203         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sOOOO|ziOO", kwnames,
1204                         &dst_path, &py_new_base_contents, &py_new_contents, &py_new_base_props, 
1205                         &py_new_props, &copyfrom_url, &copyfrom_rev, &cancel_func, &notify))
1206                 return NULL;
1207
1208         ADM_CHECK_CLOSED(admobj);
1209
1210         temp_pool = Pool(NULL);
1211         if (temp_pool == NULL)
1212                 return NULL;
1213
1214         new_base_props = prop_dict_to_hash(temp_pool, py_new_base_props);
1215
1216         new_props = prop_dict_to_hash(temp_pool, py_new_props);
1217
1218         new_base_contents = new_py_stream(temp_pool, py_new_base_contents);
1219
1220         new_contents = new_py_stream(temp_pool, py_new_contents);
1221
1222 #if ONLY_BEFORE_SVN(1, 6)
1223         if (cancel_func != Py_None) {
1224                 PyErr_SetString(PyExc_NotImplementedError,
1225                                                 "cancel not support for svn < 1.6");
1226                 return NULL;
1227         }
1228 #endif
1229
1230 #if ONLY_SINCE_SVN(1, 6)
1231         RUN_SVN_WITH_POOL(temp_pool, svn_wc_add_repos_file3(dst_path, admobj->adm,
1232                                                    new_base_contents,
1233                                                    new_contents,
1234                                                    new_base_props,
1235                                                    new_props,
1236                                                    copyfrom_url, copyfrom_rev,
1237                                                    py_cancel_func, cancel_func,
1238                                                    py_wc_notify_func, notify, temp_pool));
1239 #else
1240         PyErr_SetString(PyExc_NotImplementedError,
1241                                         "add_repos_file3 not supported on svn < 1.6");
1242         apr_pool_destroy(temp_pool);
1243 #endif
1244
1245         apr_pool_destroy(temp_pool);
1246
1247         Py_RETURN_NONE;
1248 }
1249
1250 static PyObject *mark_missing_deleted(PyObject *self, PyObject *args)
1251 {
1252         char *path;
1253         AdmObject *admobj = (AdmObject *)self;
1254         apr_pool_t *temp_pool;
1255
1256         if (!PyArg_ParseTuple(args, "s", &path))
1257                 return NULL;
1258
1259         ADM_CHECK_CLOSED(admobj);
1260
1261         temp_pool = Pool(NULL);
1262         if (temp_pool == NULL)
1263                 return NULL;
1264
1265         RUN_SVN_WITH_POOL(temp_pool, svn_wc_mark_missing_deleted(path, admobj->adm, temp_pool));
1266
1267         apr_pool_destroy(temp_pool);
1268
1269         Py_RETURN_NONE;
1270 }
1271
1272 static PyObject *remove_from_revision_control(PyObject *self, PyObject *args)
1273 {
1274         char *name;
1275         svn_boolean_t destroy_wf = FALSE, instant_error = FALSE;
1276         AdmObject *admobj = (AdmObject *)self;
1277         PyObject *cancel_func = Py_None;
1278         apr_pool_t *temp_pool;
1279
1280         if (!PyArg_ParseTuple(args, "s|bbO", &name, &destroy_wf, &instant_error, &cancel_func))
1281                 return NULL;
1282
1283         ADM_CHECK_CLOSED(admobj);
1284
1285         temp_pool = Pool(NULL);
1286         if (temp_pool == NULL)
1287                 return NULL;
1288
1289         RUN_SVN_WITH_POOL(temp_pool,
1290                 svn_wc_remove_from_revision_control(admobj->adm, name,
1291                         destroy_wf, instant_error, py_cancel_func, cancel_func, temp_pool));
1292
1293         apr_pool_destroy(temp_pool);
1294
1295         Py_RETURN_NONE;
1296 }
1297
1298 #if ONLY_SINCE_SVN(1, 6)
1299 static svn_error_t *wc_validator3(void *baton, const char *uuid, const char *url, const char *root_url, apr_pool_t *pool)
1300 {
1301         PyObject *py_validator = baton, *ret;
1302
1303         if (py_validator == Py_None) {
1304                 return NULL;
1305         }
1306
1307         ret = PyObject_CallFunction(py_validator, "sss", uuid, url, root_url);
1308         if (ret == NULL) {
1309                 return py_svn_error();
1310         }
1311
1312         Py_DECREF(ret);
1313
1314         return NULL;
1315 }
1316
1317 #else
1318
1319 static svn_error_t *wc_validator2(void *baton, const char *uuid, const char *url, svn_boolean_t root, apr_pool_t *pool)
1320 {
1321         PyObject *py_validator = baton, *ret;
1322
1323         if (py_validator == Py_None) {
1324                 return NULL;
1325         }
1326
1327         ret = PyObject_CallFunction(py_validator, "ssO", uuid, url, Py_None);
1328         if (ret == NULL) {
1329                 return py_svn_error();
1330         }
1331
1332         Py_DECREF(ret);
1333
1334         return NULL;
1335 }
1336
1337 #endif
1338
1339 static PyObject *relocate(PyObject *self, PyObject *args)
1340 {
1341         char *path, *from, *to;
1342         AdmObject *admobj = (AdmObject *)self;
1343         apr_pool_t *temp_pool;
1344         svn_boolean_t recurse = TRUE;
1345         PyObject *py_validator = Py_None;
1346
1347         if (!PyArg_ParseTuple(args, "sss|bO", &path, &from, &to, &recurse, &py_validator))
1348                 return NULL;
1349
1350         ADM_CHECK_CLOSED(admobj);
1351
1352         temp_pool = Pool(NULL);
1353         if (temp_pool == NULL)
1354                 return NULL;
1355
1356 #if ONLY_SINCE_SVN(1, 6)
1357         RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate3(path, admobj->adm, from, to, recurse, wc_validator3, py_validator, temp_pool));
1358 #else
1359         RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate2(path, admobj->adm, from, to, recurse, wc_validator2, py_validator, temp_pool));
1360 #endif
1361
1362         apr_pool_destroy(temp_pool);
1363
1364         Py_RETURN_NONE;
1365 }
1366
1367 static PyObject *crop_tree(PyObject *self, PyObject *args)
1368 {
1369         char *target;
1370         svn_depth_t depth;
1371         PyObject *notify, *cancel;
1372         apr_pool_t *temp_pool;
1373         AdmObject *admobj = (AdmObject *)self;
1374
1375         if (!PyArg_ParseTuple(args, "si|OO", &target, &depth, &notify, &cancel))
1376                 return NULL;
1377
1378         ADM_CHECK_CLOSED(admobj);
1379
1380 #if ONLY_SINCE_SVN(1, 6)
1381         temp_pool = Pool(NULL);
1382         if (temp_pool == NULL)
1383                 return NULL;
1384
1385         RUN_SVN_WITH_POOL(temp_pool, svn_wc_crop_tree(admobj->adm, 
1386                 target, depth, py_wc_notify_func, notify,
1387                 py_cancel_func, cancel, temp_pool));
1388
1389         apr_pool_destroy(temp_pool);
1390
1391         Py_RETURN_NONE;
1392 #else
1393         PyErr_SetString(PyExc_NotImplementedError, 
1394                                         "crop_tree only available on subversion < 1.6");
1395         return NULL;
1396 #endif
1397 }
1398
1399 static PyObject *translated_stream(PyObject *self, PyObject *args)
1400 {
1401         char *path, *versioned_file;
1402         StreamObject *ret;
1403         svn_stream_t *stream;
1404         AdmObject *admobj = (AdmObject *)self;
1405         apr_pool_t *stream_pool;
1406         int flags;
1407
1408         if (!PyArg_ParseTuple(args, "ssi", &path, &versioned_file, &flags))
1409                 return NULL;
1410
1411         ADM_CHECK_CLOSED(admobj);
1412
1413 #if ONLY_SINCE_SVN(1, 5)
1414         stream_pool = Pool(NULL);
1415         if (stream_pool == NULL)
1416                 return NULL;
1417
1418         RUN_SVN_WITH_POOL(stream_pool,
1419                 svn_wc_translated_stream(&stream, path, versioned_file, admobj->adm, 
1420                         flags, stream_pool));
1421
1422         ret = PyObject_New(StreamObject, &Stream_Type);
1423         if (ret == NULL)
1424                 return NULL;
1425
1426         ret->pool = stream_pool;
1427         ret->closed = FALSE;
1428         ret->stream = stream;
1429
1430         return (PyObject *)ret;
1431 #else
1432         PyErr_SetString(PyExc_NotImplementedError,
1433                 "translated_stream() is only available on Subversion >= 1.5");
1434         return NULL;
1435 #endif
1436 }
1437
1438 static PyObject *adm_text_modified(PyObject *self, PyObject *args)
1439 {
1440         char *path;
1441         svn_boolean_t force_comparison = FALSE;
1442         apr_pool_t *temp_pool;
1443         svn_boolean_t ret;
1444         AdmObject *admobj = (AdmObject *)self;
1445
1446         if (!PyArg_ParseTuple(args, "s|b", &path, &force_comparison))
1447                 return NULL;
1448
1449         ADM_CHECK_CLOSED(admobj);
1450
1451         temp_pool = Pool(NULL);
1452         if (temp_pool == NULL)
1453                 return NULL;
1454
1455         RUN_SVN_WITH_POOL(temp_pool,
1456                   svn_wc_text_modified_p(&ret, path, force_comparison, admobj->adm, 
1457                         temp_pool));
1458
1459         apr_pool_destroy(temp_pool);
1460
1461         return PyBool_FromLong(ret);
1462 }
1463
1464 static PyObject *adm_props_modified(PyObject *self, PyObject *args)
1465 {
1466         char *path;
1467         apr_pool_t *temp_pool;
1468         svn_boolean_t ret;
1469         AdmObject *admobj = (AdmObject *)self;
1470
1471         if (!PyArg_ParseTuple(args, "s", &path))
1472                 return NULL;
1473
1474         ADM_CHECK_CLOSED(admobj);
1475
1476         temp_pool = Pool(NULL);
1477         if (temp_pool == NULL)
1478                 return NULL;
1479
1480         RUN_SVN_WITH_POOL(temp_pool,
1481                   svn_wc_props_modified_p(&ret, path, admobj->adm, temp_pool));
1482
1483         apr_pool_destroy(temp_pool);
1484
1485         return PyBool_FromLong(ret);
1486 }
1487
1488 static PyObject *adm_process_committed_queue(PyObject *self, PyObject *args)
1489 {
1490         apr_pool_t *temp_pool;
1491         AdmObject *admobj = (AdmObject *)self;
1492         svn_revnum_t revnum;
1493         char *date, *author;
1494         CommittedQueueObject *py_queue;
1495
1496         if (!PyArg_ParseTuple(args, "O!Iss", &CommittedQueue_Type, &py_queue, &revnum, &date, &author))
1497                 return NULL;
1498
1499         ADM_CHECK_CLOSED(admobj);
1500
1501         temp_pool = Pool(NULL);
1502         if (temp_pool == NULL)
1503                 return NULL;
1504
1505 #if ONLY_SINCE_SVN(1, 5)
1506         RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed_queue(py_queue->queue, admobj->adm, revnum, date, author, temp_pool));
1507 #else
1508         {
1509                 int i;
1510                 for (i = 0; i < py_queue->queue->queue->nelts; i++) {
1511                         committed_queue_item_t *cqi = APR_ARRAY_IDX(py_queue->queue->queue, i,
1512                                                                                                                 committed_queue_item_t *);
1513
1514                         RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(cqi->path, admobj->adm,
1515                                    cqi->recurse, revnum, date, author, cqi->wcprop_changes,
1516                                    cqi->remove_lock, cqi->digest, temp_pool));
1517                 }
1518         }
1519 #endif
1520         apr_pool_destroy(temp_pool);
1521
1522         Py_RETURN_NONE;
1523 }
1524
1525 static PyObject *get_actual_target(PyObject *self, PyObject *args)
1526 {
1527         char *path;
1528         const char *anchor = NULL, *target = NULL;
1529         apr_pool_t *temp_pool;
1530         PyObject *ret;
1531
1532         if (!PyArg_ParseTuple(args, "s", &path))
1533                 return NULL;
1534
1535         temp_pool = Pool(NULL);
1536         if (temp_pool == NULL)
1537                 return NULL;
1538
1539         RUN_SVN_WITH_POOL(temp_pool,
1540                   svn_wc_get_actual_target(svn_path_canonicalize(path, temp_pool),
1541                                                                    &anchor, &target, temp_pool));
1542
1543         ret = Py_BuildValue("(ss)", anchor, target);
1544
1545         apr_pool_destroy(temp_pool);
1546
1547         return ret;
1548 }
1549
1550 static PyObject *is_wc_root(PyObject *self, PyObject *args)
1551 {
1552         char *path;
1553         svn_boolean_t wc_root;
1554         apr_pool_t *temp_pool;
1555         AdmObject *admobj = (AdmObject *)self;
1556
1557         if (!PyArg_ParseTuple(args, "s", &path))
1558                 return NULL;
1559
1560         ADM_CHECK_CLOSED(admobj);
1561
1562         temp_pool = Pool(NULL);
1563         if (temp_pool == NULL)
1564                 return NULL;
1565
1566         RUN_SVN_WITH_POOL(temp_pool,
1567                   svn_wc_is_wc_root(&wc_root, path, admobj->adm, temp_pool));
1568
1569         apr_pool_destroy(temp_pool);
1570
1571         return PyBool_FromLong(wc_root);
1572 }
1573
1574 static PyObject *transmit_text_deltas(PyObject *self, PyObject *args)
1575 {
1576         char *path;
1577         const char *tempfile;
1578         svn_boolean_t fulltext;
1579         PyObject *editor_obj, *py_digest;
1580         unsigned char digest[APR_MD5_DIGESTSIZE];
1581         apr_pool_t *temp_pool;
1582         AdmObject *admobj = (AdmObject *)self;
1583         PyObject *ret;
1584
1585         if (!PyArg_ParseTuple(args, "sbO", &path, &fulltext, &editor_obj))
1586                 return NULL;
1587
1588         ADM_CHECK_CLOSED(admobj);
1589
1590         temp_pool = Pool(NULL);
1591         if (temp_pool == NULL)
1592                 return NULL;
1593
1594         Py_INCREF(editor_obj);
1595
1596         RUN_SVN_WITH_POOL(temp_pool,
1597                 svn_wc_transmit_text_deltas2(&tempfile, digest, 
1598                         svn_path_canonicalize(path, temp_pool), admobj->adm, fulltext,
1599                         &py_editor, editor_obj, temp_pool));
1600
1601         py_digest = PyString_FromStringAndSize((char *)digest, APR_MD5_DIGESTSIZE);
1602         if (py_digest == NULL) {
1603                 apr_pool_destroy(temp_pool);
1604                 return NULL;
1605         }
1606
1607         ret = Py_BuildValue("sN", tempfile, py_digest);
1608         if (ret == NULL) {
1609                 apr_pool_destroy(temp_pool);
1610                 return NULL;
1611         }
1612
1613         apr_pool_destroy(temp_pool);
1614
1615         return ret;
1616 }
1617
1618 static PyObject *transmit_prop_deltas(PyObject *self, PyObject *args)
1619 {
1620         char *path;
1621         PyObject *editor_obj;
1622         apr_pool_t *temp_pool;
1623         AdmObject *admobj = (AdmObject *)self;
1624         EntryObject *py_entry;
1625
1626         if (!PyArg_ParseTuple(args, "sO!O", &path, &Entry_Type, &py_entry, &editor_obj))
1627                 return NULL;
1628
1629         ADM_CHECK_CLOSED(admobj);
1630
1631         temp_pool = Pool(NULL);
1632         if (temp_pool == NULL)
1633                 return NULL;
1634
1635         Py_INCREF(editor_obj);
1636
1637         RUN_SVN_WITH_POOL(temp_pool,
1638                 svn_wc_transmit_prop_deltas(svn_path_canonicalize(path, temp_pool),
1639                         admobj->adm, &(py_entry->entry), &py_editor, editor_obj, NULL, temp_pool));
1640
1641         apr_pool_destroy(temp_pool);
1642
1643         Py_RETURN_NONE;
1644 }
1645
1646 static PyObject *retrieve(PyObject *self, PyObject *args)
1647 {
1648         char *path;
1649         svn_wc_adm_access_t *result;
1650         AdmObject *admobj = (AdmObject *)self, *ret;
1651         apr_pool_t *pool;
1652
1653         if (!PyArg_ParseTuple(args, "s", &path))
1654                 return NULL;
1655
1656         ADM_CHECK_CLOSED(admobj);
1657
1658         pool = Pool(NULL);
1659         if (pool == NULL)
1660                 return NULL;
1661
1662         RUN_SVN_WITH_POOL(pool, svn_wc_adm_retrieve(&result, admobj->adm, 
1663                 svn_path_canonicalize(path, pool), pool));
1664
1665         ret = PyObject_New(AdmObject, &Adm_Type);
1666         if (ret == NULL)
1667                 return NULL;
1668
1669         ret->pool = pool;
1670         ret->adm = result;
1671
1672         return (PyObject *)ret;
1673 }
1674
1675 static PyObject *probe_retrieve(PyObject *self, PyObject *args)
1676 {
1677         char *path;
1678         svn_wc_adm_access_t *result;
1679         AdmObject *admobj = (AdmObject *)self, *ret;
1680         apr_pool_t *pool;
1681
1682         if (!PyArg_ParseTuple(args, "s", &path))
1683                 return NULL;
1684
1685         ADM_CHECK_CLOSED(admobj);
1686
1687         pool = Pool(NULL);
1688         if (pool == NULL)
1689                 return NULL;
1690
1691         RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_retrieve(&result, admobj->adm, 
1692                 svn_path_canonicalize(path, pool), pool));
1693
1694         ret = PyObject_New(AdmObject, &Adm_Type);
1695         if (ret == NULL)
1696                 return NULL;
1697
1698         ret->pool = pool;
1699         ret->adm = result;
1700
1701         return (PyObject *)ret;
1702 }
1703
1704 static PyObject *probe_try(PyObject *self, PyObject *args)
1705 {
1706         char *path;
1707         svn_wc_adm_access_t *result = NULL;
1708         AdmObject *admobj = (AdmObject *)self, *ret;
1709         apr_pool_t *pool;
1710         PyObject *cancelfunc = Py_None;
1711         int levels_to_lock = -1;
1712         svn_boolean_t writelock = FALSE;
1713
1714         if (!PyArg_ParseTuple(args, "s|biO", &path, &writelock, &levels_to_lock, &cancelfunc))
1715                 return NULL;
1716
1717         ADM_CHECK_CLOSED(admobj);
1718
1719         pool = Pool(NULL);
1720         if (pool == NULL)
1721                 return NULL;
1722
1723         RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_try3(&result, admobj->adm, 
1724                 svn_path_canonicalize(path, pool), writelock, levels_to_lock,
1725                 py_cancel_func, cancelfunc, pool));
1726
1727         if (result == NULL) {
1728                 apr_pool_destroy(pool);
1729                 Py_RETURN_NONE;
1730         }
1731
1732         ret = PyObject_New(AdmObject, &Adm_Type);
1733         if (ret == NULL)
1734                 return NULL;
1735
1736         ret->pool = pool;
1737         ret->adm = result;
1738
1739         return (PyObject *)ret;
1740 }
1741
1742 static PyObject *resolved_conflict(PyObject *self, PyObject *args)
1743 {
1744         AdmObject *admobj = (AdmObject *)self;
1745         apr_pool_t *temp_pool;
1746         svn_boolean_t resolve_props, resolve_tree, resolve_text;
1747         int depth;
1748         svn_wc_conflict_choice_t conflict_choice;
1749         PyObject *notify_func = Py_None, *cancel_func = Py_None;
1750         char *path;
1751
1752         if (!PyArg_ParseTuple(args, "sbbbii|OO", &path, &resolve_text,
1753                                                   &resolve_props, &resolve_tree, &depth,
1754                                                   &conflict_choice, &notify_func, &cancel_func))
1755                 return NULL;
1756
1757         ADM_CHECK_CLOSED(admobj);
1758
1759         temp_pool = Pool(NULL);
1760         if (temp_pool == NULL)
1761                 return NULL;
1762
1763 #if ONLY_SINCE_SVN(1, 6)
1764         RUN_SVN_WITH_POOL(temp_pool,
1765                   svn_wc_resolved_conflict4(path, admobj->adm, resolve_text, 
1766                                                                                 resolve_props, resolve_tree, depth,
1767                                                                                 conflict_choice, py_wc_notify_func,
1768                                                                            (void *)notify_func, py_cancel_func,
1769                                                                            cancel_func, temp_pool));
1770 #elif ONLY_SINCE_SVN(1, 5)
1771         if (resolve_tree) {
1772                 PyErr_SetString(PyExc_NotImplementedError,
1773                                                 "resolve_tree not supported with svn < 1.6");
1774         } else {
1775                 RUN_SVN_WITH_POOL(temp_pool,
1776                           svn_wc_resolved_conflict3(path, admobj->adm, resolve_text, 
1777                                                                                         resolve_props, depth,
1778                                                                                         conflict_choice, py_wc_notify_func,
1779                                                                                    (void *)notify_func, py_cancel_func,
1780                                                                                    cancel_func, temp_pool));
1781         }
1782 #else
1783         if (resolve_tree) {
1784                 PyErr_SetString(PyExc_NotImplementedError,
1785                                                 "resolve_tree not supported with svn < 1.6");
1786         } else if (depth != svn_depth_infinity && depth != svn_depth_empty) {
1787                 PyErr_SetString(PyExc_NotImplementedError,
1788                                                 "only infinity and empty values for depth are supported");
1789         } else {
1790                 RUN_SVN_WITH_POOL(temp_pool,
1791                           svn_wc_resolved_conflict3(path, admobj->adm, resolve_text, 
1792                                                                                         resolve_props, 
1793                                                                                         (depth == svn_depth_infinity),
1794                                                                                         conflict_choice, py_wc_notify_func,
1795                                                                                    (void *)notify_func, py_cancel_func,
1796                                                                                    cancel_func, temp_pool));
1797         }
1798 #endif
1799
1800         apr_pool_destroy(temp_pool);
1801
1802         Py_RETURN_NONE;
1803 }
1804
1805 static PyObject *conflicted(PyObject *self, PyObject *args)
1806 {
1807         char *path;
1808         apr_pool_t *temp_pool;
1809         PyObject *ret;
1810         AdmObject *admobj = (AdmObject *)self;
1811         svn_boolean_t text_conflicted, prop_conflicted, tree_conflicted;
1812
1813         if (!PyArg_ParseTuple(args, "s", &path))
1814                 return NULL;
1815
1816         ADM_CHECK_CLOSED(admobj);
1817
1818         temp_pool = Pool(NULL);
1819         if (temp_pool == NULL)
1820                 return NULL;
1821
1822 #if ONLY_SINCE_SVN(1, 6)
1823         RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p2(&text_conflicted,
1824                 &prop_conflicted, &tree_conflicted, path, admobj->adm, temp_pool));
1825
1826         ret = Py_BuildValue("(bbb)", text_conflicted, prop_conflicted, tree_conflicted);
1827 #else
1828         RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p(&text_conflicted,
1829                 &prop_conflicted, path, admobj->adm, temp_pool));
1830
1831         ret = Py_BuildValue("(bbO)", text_conflicted, prop_conflicted, Py_None);
1832 #endif
1833
1834         apr_pool_destroy(temp_pool);
1835
1836         return ret;
1837 }
1838
1839 static PyMethodDef adm_methods[] = { 
1840         { "prop_set", adm_prop_set, METH_VARARGS, "S.prop_set(name, value, path, skip_checks=False)" },
1841         { "access_path", (PyCFunction)adm_access_path, METH_NOARGS, 
1842                 "S.access_path() -> path\n"
1843                 "Returns the base path for this working copy handle." },
1844         { "prop_get", adm_prop_get, METH_VARARGS, "S.prop_get(name, path) -> value" },
1845         { "entries_read", adm_entries_read, METH_VARARGS, "S.entries_read(include_hidden=False) -> dict" },
1846         { "walk_entries", adm_walk_entries, METH_VARARGS, 
1847                 "S.walk_entries(path, callback, show_hidden=False, cancel_func=None)\n"
1848                 "callback should be a function that takes a path and a wc entry" },
1849         { "locked", (PyCFunction)adm_locked, METH_NOARGS, 
1850                 "S.locked() -> bool" },
1851         { "get_prop_diffs", adm_get_prop_diffs, METH_VARARGS, 
1852                 "S.get_prop_diffs(path) -> (propchanges, originalprops)" },
1853         { "add", (PyCFunction)adm_add, METH_VARARGS|METH_KEYWORDS, "S.add(path, copyfrom_url=None, copyfrom_rev=-1, cancel_func=None, notify_func=None)" },
1854         { "copy", adm_copy, METH_VARARGS, "S.copy(src_path, dest_path, cancel_func=None, notify_func=None)" },
1855         { "delete", (PyCFunction)adm_delete, METH_VARARGS|METH_KEYWORDS, "S.delete(path, cancel_func=None, notify_func=None, keep_local=False)" },
1856         { "crawl_revisions", (PyCFunction)adm_crawl_revisions, METH_VARARGS|METH_KEYWORDS, 
1857                 "S.crawl_revisions(path, reporter, restore_files=True, recurse=True, use_commit_times=True, notify_func=None) -> None" },
1858         { "get_update_editor", adm_get_update_editor, METH_VARARGS, NULL },
1859         { "close", (PyCFunction)adm_close, METH_NOARGS, 
1860                 "S.close()" },
1861         { "entry", (PyCFunction)adm_entry, METH_VARARGS, 
1862                 "s.entry(path, show_hidden=False) -> entry" },
1863         { "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)" },
1864         { "process_committed_queue", (PyCFunction)adm_process_committed_queue, METH_VARARGS, "S.process_committed_queue(queue, new_revnum, rev_date, rev_author)" },
1865         { "remove_lock", (PyCFunction)adm_remove_lock, METH_VARARGS, "S.remove_lock(path)" }, 
1866         { "has_binary_prop", (PyCFunction)adm_has_binary_prop, METH_VARARGS, "S.has_binary_prop(path) -> bool" },
1867         { "text_modified", (PyCFunction)adm_text_modified, METH_VARARGS, "S.text_modified(filename, force_comparison=False) -> bool" },
1868         { "props_modified", (PyCFunction)adm_props_modified, METH_VARARGS, "S.props_modified(filename) -> bool" },
1869         { "get_ancestry", (PyCFunction)get_ancestry, METH_VARARGS,
1870                 "S.get_ancestry(path) -> (url, rev)" },
1871         { "maybe_set_repos_root", (PyCFunction)maybe_set_repos_root, METH_VARARGS, "S.maybe_set_repos_root(path, repos)" },
1872         { "add_repos_file", (PyCFunction)add_repos_file, METH_KEYWORDS, 
1873                 "S.add_repos_file(dst_path, new_base_contents, new_contents, new_base_props, new_props, copyfrom_url=None, copyfrom_rev=-1, cancel_func=None, notify_func=None)" },
1874         { "mark_missing_deleted", (PyCFunction)mark_missing_deleted, METH_VARARGS,
1875                 "S.mark_missing_deleted(path)" },
1876         { "remove_from_revision_control", (PyCFunction)remove_from_revision_control, METH_VARARGS,
1877                 "S.remove_from_revision_control(name, destroy_wf=False, instant_error=False, cancel_func=None)" },
1878         { "relocate", (PyCFunction)relocate, METH_VARARGS,
1879                 "S.relocate(path, from, to, recurse=TRUE, validator=None)" },
1880         { "crop_tree", (PyCFunction)crop_tree, METH_VARARGS,
1881                 "S.crop_tree(target, depth, notify_func=None, cancel=None)" },
1882         { "translated_stream", (PyCFunction)translated_stream, METH_VARARGS,
1883                 "S.translated_stream(path, versioned_file, flags) -> stream" },
1884         { "is_wc_root", (PyCFunction)is_wc_root, METH_VARARGS,
1885                 "S.is_wc_root(path) -> wc_root" },
1886         { "transmit_text_deltas", (PyCFunction)transmit_text_deltas, METH_VARARGS,
1887                 "S.transmit_text_deltas(fulltext, editor) -> (tempfile, digest)" },
1888         { "transmit_prop_deltas", (PyCFunction)transmit_prop_deltas, METH_VARARGS,
1889                 "S.transmit_prop_deltas(path, entry, editor)" },
1890         { "probe_retrieve", (PyCFunction)probe_retrieve, METH_VARARGS,
1891                 "S.probe_retrieve(path) -> WorkingCopy" },
1892         { "retrieve", (PyCFunction)retrieve, METH_VARARGS,
1893                 "S.retrieve(path) -> WorkingCopy" },
1894         { "probe_try", (PyCFunction)probe_try, METH_VARARGS,
1895                 "S.probe_try(path, write_lock=False, levels_to_lock=-1)" },
1896         { "conflicted", (PyCFunction)conflicted, METH_VARARGS,
1897                 "S.conflicted(path) -> (text_conflicted, prop_conflicted, tree_conflicted)" },
1898         { "resolved_conflict", (PyCFunction)resolved_conflict, METH_VARARGS,
1899                 "S.resolved_conflict(path, resolve_text, resolve_props, resolve_tree, depth, conflict_choice, notify_func=None, cancel=None)" },
1900         { NULL, }
1901 };
1902
1903 static PyTypeObject Adm_Type = {
1904         PyObject_HEAD_INIT(NULL) 0,
1905         "wc.WorkingCopy", /*    const char *tp_name;  For printing, in format "<module>.<name>" */
1906         sizeof(AdmObject), 
1907         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
1908         
1909         /* Methods to implement standard operations */
1910         
1911         adm_dealloc, /* destructor tp_dealloc;  */
1912         NULL, /*        printfunc tp_print;     */
1913         NULL, /*        getattrfunc tp_getattr; */
1914         NULL, /*        setattrfunc tp_setattr; */
1915         NULL, /*        cmpfunc tp_compare;     */
1916         adm_repr, /*    reprfunc tp_repr;       */
1917         
1918         /* Method suites for standard classes */
1919         
1920         NULL, /*        PyNumberMethods *tp_as_number;  */
1921         NULL, /*        PySequenceMethods *tp_as_sequence;      */
1922         NULL, /*        PyMappingMethods *tp_as_mapping;        */
1923         
1924         /* More standard operations (here for binary compatibility) */
1925         
1926         NULL, /*        hashfunc tp_hash;       */
1927         NULL, /*        ternaryfunc tp_call;    */
1928         adm_repr, /*    reprfunc tp_repr;       */
1929         NULL, /*        getattrofunc tp_getattro;       */
1930         NULL, /*        setattrofunc tp_setattro;       */
1931         
1932         /* Functions to access object as input/output buffer */
1933         NULL, /*        PyBufferProcs *tp_as_buffer;    */
1934         
1935         /* Flags to define presence of optional/expanded features */
1936         0, /*   long tp_flags;  */
1937         
1938         "Local working copy", /*        const char *tp_doc;  Documentation string */
1939         
1940         /* Assigned meaning in release 2.0 */
1941         /* call function for all accessible objects */
1942         NULL, /*        traverseproc tp_traverse;       */
1943         
1944         /* delete references to contained objects */
1945         NULL, /*        inquiry tp_clear;       */
1946         
1947         /* Assigned meaning in release 2.1 */
1948         /* rich comparisons */
1949         NULL, /*        richcmpfunc tp_richcompare;     */
1950         
1951         /* weak reference enabler */
1952         0, /*   Py_ssize_t tp_weaklistoffset;   */
1953         
1954         /* Added in release 2.2 */
1955         /* Iterators */
1956         NULL, /*        getiterfunc tp_iter;    */
1957         NULL, /*        iternextfunc tp_iternext;       */
1958         
1959         /* Attribute descriptor and subclassing stuff */
1960         adm_methods, /* struct PyMethodDef *tp_methods; */
1961         NULL, /*        struct PyMemberDef *tp_members; */
1962         NULL, /*        struct PyGetSetDef *tp_getset;  */
1963         NULL, /*        struct _typeobject *tp_base;    */
1964         NULL, /*        PyObject *tp_dict;      */
1965         NULL, /*        descrgetfunc tp_descr_get;      */
1966         NULL, /*        descrsetfunc tp_descr_set;      */
1967         0, /*   Py_ssize_t tp_dictoffset;       */
1968         NULL, /*        initproc tp_init;       */
1969         NULL, /*        allocfunc tp_alloc;     */
1970         adm_init, /*    newfunc tp_new; */
1971 };
1972
1973 static void committed_queue_dealloc(PyObject *self)
1974 {
1975         apr_pool_destroy(((CommittedQueueObject *)self)->pool);
1976         PyObject_Del(self);
1977 }
1978
1979 static PyObject *committed_queue_repr(PyObject *self)
1980 {
1981         CommittedQueueObject *cqobj = (CommittedQueueObject *)self;
1982
1983         return PyString_FromFormat("<wc.CommittedQueue at 0x%p>", cqobj->queue);
1984 }
1985
1986 static PyObject *committed_queue_init(PyTypeObject *self, PyObject *args, PyObject *kwargs)
1987 {
1988         CommittedQueueObject *ret;
1989         char *kwnames[] = { NULL };
1990
1991         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwnames))
1992                 return NULL;
1993
1994         ret = PyObject_New(CommittedQueueObject, &CommittedQueue_Type);
1995         if (ret == NULL)
1996                 return NULL;
1997
1998         ret->pool = Pool(NULL);
1999         if (ret->pool == NULL)
2000                 return NULL;
2001         ret->queue = svn_wc_committed_queue_create(ret->pool);
2002         if (ret->queue == NULL) {
2003                 PyObject_Del(ret);
2004                 PyErr_NoMemory();
2005                 return NULL;
2006         }
2007
2008         return (PyObject *)ret;
2009 }
2010
2011 static PyObject *committed_queue_queue(CommittedQueueObject *self, PyObject *args)
2012 {
2013         char *path;
2014         AdmObject *admobj;
2015         PyObject *py_wcprop_changes = Py_None;
2016         svn_boolean_t remove_lock = FALSE, remove_changelist = FALSE;
2017         char *digest = NULL;
2018         svn_boolean_t recurse = FALSE;
2019         apr_pool_t *temp_pool;
2020         apr_array_header_t *wcprop_changes;
2021
2022         if (!PyArg_ParseTuple(args, "sO!|bObbz", &path, &Adm_Type, &admobj, &recurse, &py_wcprop_changes, &remove_lock, &remove_changelist, &digest))
2023                 return NULL;
2024
2025         temp_pool = Pool(NULL);
2026         if (temp_pool == NULL)
2027                 return NULL;
2028
2029         if (!py_dict_to_wcprop_changes(py_wcprop_changes, self->pool, &wcprop_changes)) {
2030                 apr_pool_destroy(temp_pool);
2031                 return NULL;
2032         }
2033
2034         path = apr_pstrdup(self->pool, path);
2035         if (path == NULL) {
2036                 PyErr_NoMemory();
2037                 return NULL;
2038         }
2039
2040         if (digest != NULL) {
2041                 digest = apr_pstrdup(self->pool, digest);
2042                 if (digest == NULL) {
2043                         PyErr_NoMemory();
2044                         return NULL;
2045                 }
2046         }
2047
2048         RUN_SVN_WITH_POOL(temp_pool, 
2049                 svn_wc_queue_committed(&self->queue, path, admobj->adm, recurse,
2050                                                            wcprop_changes, remove_lock, remove_changelist,
2051                                                            (unsigned char *)digest, temp_pool));
2052
2053         apr_pool_destroy(temp_pool);
2054
2055         Py_RETURN_NONE;
2056 }
2057
2058 static PyMethodDef committed_queue_methods[] = {
2059         { "queue", (PyCFunction)committed_queue_queue, METH_VARARGS,
2060                 "S.queue(path, adm, recurse, wcprop_changes, remove_lock, remove_changelist, digest)" },
2061         { NULL }
2062 };
2063
2064 static PyTypeObject CommittedQueue_Type = {
2065         PyObject_HEAD_INIT(NULL) 0,
2066         "wc.CommittedQueue", /* const char *tp_name;  For printing, in format "<module>.<name>" */
2067         sizeof(CommittedQueueObject), 
2068         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
2069         
2070         /* Methods to implement standard operations */
2071         
2072         committed_queue_dealloc, /*     destructor tp_dealloc;  */
2073         NULL, /*        printfunc tp_print;     */
2074         NULL, /*        getattrfunc tp_getattr; */
2075         NULL, /*        setattrfunc tp_setattr; */
2076         NULL, /*        cmpfunc tp_compare;     */
2077         committed_queue_repr, /*        reprfunc tp_repr;       */
2078         
2079         /* Method suites for standard classes */
2080         
2081         NULL, /*        PyNumberMethods *tp_as_number;  */
2082         NULL, /*        PySequenceMethods *tp_as_sequence;      */
2083         NULL, /*        PyMappingMethods *tp_as_mapping;        */
2084         
2085         /* More standard operations (here for binary compatibility) */
2086         
2087         NULL, /*        hashfunc tp_hash;       */
2088         NULL, /*        ternaryfunc tp_call;    */
2089         NULL, /*        reprfunc tp_str;        */
2090         NULL, /*        getattrofunc tp_getattro;       */
2091         NULL, /*        setattrofunc tp_setattro;       */
2092         
2093         /* Functions to access object as input/output buffer */
2094         NULL, /*        PyBufferProcs *tp_as_buffer;    */
2095         
2096         /* Flags to define presence of optional/expanded features */
2097         0, /*   long tp_flags;  */
2098         
2099         "Committed queue", /*   const char *tp_doc;  Documentation string */
2100         
2101         /* Assigned meaning in release 2.0 */
2102         /* call function for all accessible objects */
2103         NULL, /*        traverseproc tp_traverse;       */
2104         
2105         /* delete references to contained objects */
2106         NULL, /*        inquiry tp_clear;       */
2107         
2108         /* Assigned meaning in release 2.1 */
2109         /* rich comparisons */
2110         NULL, /*        richcmpfunc tp_richcompare;     */
2111         
2112         /* weak reference enabler */
2113         0, /*   Py_ssize_t tp_weaklistoffset;   */
2114         
2115         /* Added in release 2.2 */
2116         /* Iterators */
2117         NULL, /*        getiterfunc tp_iter;    */
2118         NULL, /*        iternextfunc tp_iternext;       */
2119         
2120         /* Attribute descriptor and subclassing stuff */
2121         committed_queue_methods, /*     struct PyMethodDef *tp_methods; */
2122         NULL, /*        struct PyMemberDef *tp_members; */
2123         NULL, /*        struct PyGetSetDef *tp_getset;  */
2124         NULL, /*        struct _typeobject *tp_base;    */
2125         NULL, /*        PyObject *tp_dict;      */
2126         NULL, /*        descrgetfunc tp_descr_get;      */
2127         NULL, /*        descrsetfunc tp_descr_set;      */
2128         0, /*   Py_ssize_t tp_dictoffset;       */
2129         NULL, /*        initproc tp_init;       */
2130         NULL, /*        allocfunc tp_alloc;     */
2131         committed_queue_init, /*        newfunc tp_new; */
2132 };
2133
2134 /** 
2135  * Determine the revision status of a specified working copy.
2136  *
2137  * :return: Tuple with minimum and maximum revnums found, whether the 
2138  * working copy was switched and whether it was modified.
2139  */
2140 static PyObject *revision_status(PyObject *self, PyObject *args, PyObject *kwargs)
2141 {
2142         char *kwnames[] = { "wc_path", "trail_url", "committed", "cancel_func", NULL };
2143         char *wc_path, *trail_url=NULL;
2144         bool committed=false;
2145         PyObject *cancel_func=Py_None, *ret;
2146          svn_wc_revision_status_t *revstatus;
2147         apr_pool_t *temp_pool;
2148
2149         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zbO", kwnames, &wc_path,
2150                                                                          &trail_url, &committed, &cancel_func))
2151                 return NULL;
2152
2153         temp_pool = Pool(NULL);
2154         if (temp_pool == NULL)
2155                 return NULL;
2156         RUN_SVN_WITH_POOL(temp_pool, 
2157                         svn_wc_revision_status(
2158                                 &revstatus, 
2159                                 svn_path_canonicalize(wc_path, temp_pool),
2160                                 trail_url,
2161                                  committed, py_cancel_func, cancel_func, temp_pool));
2162         ret = Py_BuildValue("(llbb)", revstatus->min_rev, revstatus->max_rev, 
2163                         revstatus->switched, revstatus->modified);
2164         apr_pool_destroy(temp_pool);
2165         return ret;
2166 }
2167
2168 static PyObject *is_normal_prop(PyObject *self, PyObject *args)
2169 {
2170         char *name;
2171
2172         if (!PyArg_ParseTuple(args, "s", &name))
2173                 return NULL;
2174
2175         return PyBool_FromLong(svn_wc_is_normal_prop(name));
2176 }
2177
2178 static PyObject *is_adm_dir(PyObject *self, PyObject *args)
2179 {
2180         char *name;
2181         apr_pool_t *pool;
2182         svn_boolean_t ret;
2183
2184         if (!PyArg_ParseTuple(args, "s", &name))
2185                 return NULL;
2186
2187         pool = Pool(NULL);
2188         if (pool == NULL)
2189                 return NULL;
2190
2191         ret = svn_wc_is_adm_dir(name, pool);
2192
2193         apr_pool_destroy(pool);
2194
2195         return PyBool_FromLong(ret);
2196 }
2197
2198 static PyObject *is_wc_prop(PyObject *self, PyObject *args)
2199 {
2200         char *name;
2201
2202         if (!PyArg_ParseTuple(args, "s", &name))
2203                 return NULL;
2204
2205         return PyBool_FromLong(svn_wc_is_wc_prop(name));
2206 }
2207
2208 static PyObject *is_entry_prop(PyObject *self, PyObject *args)
2209 {
2210         char *name;
2211
2212         if (!PyArg_ParseTuple(args, "s", &name))
2213                 return NULL;
2214
2215         return PyBool_FromLong(svn_wc_is_entry_prop(name));
2216 }
2217
2218 static PyObject *get_adm_dir(PyObject *self)
2219 {
2220         apr_pool_t *pool;
2221         PyObject *ret;
2222         const char *dir;
2223         pool = Pool(NULL);
2224         if (pool == NULL)
2225                 return NULL;
2226         dir = svn_wc_get_adm_dir(pool);
2227         ret = PyString_FromString(dir);
2228         apr_pool_destroy(pool);
2229         return ret;
2230 }
2231
2232 static PyObject *set_adm_dir(PyObject *self, PyObject *args)
2233 {
2234         apr_pool_t *temp_pool;
2235         char *name;
2236
2237         if (!PyArg_ParseTuple(args, "s", &name))
2238                 return NULL;
2239
2240         temp_pool = Pool(NULL);
2241         if (temp_pool == NULL)
2242                 return NULL;
2243         RUN_SVN_WITH_POOL(temp_pool, svn_wc_set_adm_dir(name, temp_pool));
2244         apr_pool_destroy(temp_pool);
2245         Py_RETURN_NONE;
2246 }
2247
2248 static PyObject *get_pristine_copy_path(PyObject *self, PyObject *args)
2249 {
2250         apr_pool_t *pool;
2251         const char *pristine_path;
2252         char *path;
2253         PyObject *ret;
2254
2255         if (!PyArg_ParseTuple(args, "s", &path))
2256                 return NULL;
2257
2258         pool = Pool(NULL);
2259         if (pool == NULL)
2260                 return NULL;
2261 #if PY_VERSION_HEX < 0x02050000
2262         PyErr_Warn(PyExc_DeprecationWarning, "get_pristine_copy_path is deprecated. Use get_pristine_contents instead.");
2263 #else
2264         PyErr_WarnEx(PyExc_DeprecationWarning, "get_pristine_copy_path is deprecated. Use get_pristine_contents instead.", 2);
2265 #endif
2266         RUN_SVN_WITH_POOL(pool,
2267                   svn_wc_get_pristine_copy_path(svn_path_canonicalize(path, pool),
2268                                                                                 &pristine_path, pool));
2269         ret = PyString_FromString(pristine_path);
2270         apr_pool_destroy(pool);
2271         return ret;
2272 }
2273
2274 static PyObject *get_pristine_contents(PyObject *self, PyObject *args)
2275 {
2276         char *path;
2277         apr_pool_t *temp_pool;
2278 #if ONLY_SINCE_SVN(1, 6)
2279         apr_pool_t *stream_pool;
2280         StreamObject *ret;
2281         svn_stream_t *stream;
2282 #else
2283         PyObject *ret;
2284         const char *pristine_path;
2285 #endif
2286
2287         if (!PyArg_ParseTuple(args, "s", &path))
2288                 return NULL;
2289
2290 #if ONLY_SINCE_SVN(1, 6)
2291         stream_pool = Pool(NULL);
2292         if (stream_pool == NULL)
2293                 return NULL;
2294
2295         temp_pool = Pool(stream_pool);
2296         if (temp_pool == NULL) {
2297                 apr_pool_destroy(stream_pool);
2298                 return NULL;
2299         }
2300
2301         RUN_SVN_WITH_POOL(stream_pool, svn_wc_get_pristine_contents(&stream, svn_path_canonicalize(path, temp_pool), stream_pool, temp_pool));
2302         apr_pool_destroy(temp_pool);
2303
2304         if (stream == NULL) {
2305                 apr_pool_destroy(stream_pool);
2306                 Py_RETURN_NONE;
2307         }
2308
2309         ret = PyObject_New(StreamObject, &Stream_Type);
2310         if (ret == NULL)
2311                 return NULL;
2312
2313         ret->pool = stream_pool;
2314         ret->closed = FALSE;
2315         ret->stream = stream;
2316
2317         return (PyObject *)ret;
2318 #else
2319         temp_pool = Pool(NULL);
2320         if (temp_pool == NULL)
2321                 return NULL;
2322         RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_pristine_copy_path(svn_path_canonicalize(path, temp_pool), &pristine_path, temp_pool));
2323         ret = PyFile_FromString((char *)pristine_path, "rb");
2324         apr_pool_destroy(temp_pool);
2325         return ret;
2326 #endif
2327 }
2328
2329 static PyObject *ensure_adm(PyObject *self, PyObject *args, PyObject *kwargs)
2330 {
2331         char *path, *uuid, *url;
2332         char *repos=NULL; 
2333         svn_revnum_t rev=-1;
2334         apr_pool_t *pool;
2335         char *kwnames[] = { "path", "uuid", "url", "repos", "rev", "depth", NULL };
2336         svn_depth_t depth = svn_depth_infinity;
2337
2338         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sss|sli", kwnames, 
2339                                                                          &path, &uuid, &url, &repos, &rev, &depth))
2340                 return NULL;
2341
2342         pool = Pool(NULL);
2343         if (pool == NULL)
2344                 return NULL;
2345 #if ONLY_SINCE_SVN(1, 5)
2346         RUN_SVN_WITH_POOL(pool, 
2347                                           svn_wc_ensure_adm3(svn_path_canonicalize(path, pool),
2348                                                                                  uuid, url, repos, rev, depth, pool));
2349 #else
2350         if (depth != svn_depth_infinity) {
2351                 PyErr_SetString(PyExc_NotImplementedError, 
2352                                                 "depth != infinity not supported with svn < 1.5");
2353                 apr_pool_destroy(pool);
2354                 return NULL;
2355         }
2356         RUN_SVN_WITH_POOL(pool, 
2357                                           svn_wc_ensure_adm2(svn_path_canonicalize(path, pool),
2358                                                                                  uuid, url, repos, rev, pool));
2359 #endif
2360         apr_pool_destroy(pool);
2361         Py_RETURN_NONE;
2362 }
2363
2364 static PyObject *check_wc(PyObject *self, PyObject *args)
2365 {
2366         char *path;
2367         apr_pool_t *pool;
2368         int wc_format;
2369
2370         if (!PyArg_ParseTuple(args, "s", &path))
2371                 return NULL;
2372
2373         pool = Pool(NULL);
2374         if (pool == NULL)
2375                 return NULL;
2376         RUN_SVN_WITH_POOL(pool, svn_wc_check_wc(svn_path_canonicalize(path, pool), &wc_format, pool));
2377         apr_pool_destroy(pool);
2378         return PyLong_FromLong(wc_format);
2379 }
2380
2381 static PyObject *cleanup_wc(PyObject *self, PyObject *args, PyObject *kwargs)
2382 {
2383         PyObject *cancel_func = Py_None;
2384         char *path;
2385         char *diff3_cmd = NULL;
2386         char *kwnames[] = { "path", "diff3_cmd", "cancel_func", NULL };
2387         apr_pool_t *temp_pool;
2388
2389         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zO", kwnames, 
2390                                                                          &path, &diff3_cmd, &cancel_func)) 
2391                 return NULL;
2392
2393         temp_pool = Pool(NULL);
2394         if (temp_pool == NULL)
2395                 return NULL;
2396         RUN_SVN_WITH_POOL(temp_pool, 
2397                                 svn_wc_cleanup2(path, diff3_cmd, py_cancel_func, cancel_func,
2398                                                                 temp_pool));
2399         apr_pool_destroy(temp_pool);
2400
2401         Py_RETURN_NONE;
2402 }
2403
2404 static PyObject *match_ignore_list(PyObject *self, PyObject *args)
2405 {
2406 #if ONLY_SINCE_SVN(1, 5)
2407         char *str;
2408         PyObject *py_list;
2409         apr_array_header_t *list;
2410         apr_pool_t *temp_pool;
2411         svn_boolean_t ret;
2412
2413         if (!PyArg_ParseTuple(args, "sO", &str, &py_list))
2414                 return NULL;
2415
2416         temp_pool = Pool(NULL);
2417
2418         if (!string_list_to_apr_array(temp_pool, py_list, &list)) {
2419                 apr_pool_destroy(temp_pool);
2420                 return NULL;
2421         }
2422
2423         ret = svn_wc_match_ignore_list(str, list, temp_pool);
2424
2425         apr_pool_destroy(temp_pool);
2426
2427         return PyBool_FromLong(ret);
2428 #else
2429         PyErr_SetNone(PyExc_NotImplementedError);
2430         return NULL;
2431 #endif
2432 }
2433
2434 static PyMethodDef wc_methods[] = {
2435         { "check_wc", check_wc, METH_VARARGS, "check_wc(path) -> version\n"
2436                 "Check whether path contains a Subversion working copy\n"
2437                 "return the workdir version"},
2438         { "cleanup", (PyCFunction)cleanup_wc, METH_VARARGS|METH_KEYWORDS, "cleanup(path, diff3_cmd=None, cancel_func=None)\n" },
2439         { "ensure_adm", (PyCFunction)ensure_adm, METH_KEYWORDS|METH_VARARGS, 
2440                 "ensure_adm(path, uuid, url, repos=None, rev=None)" },
2441         { "get_adm_dir", (PyCFunction)get_adm_dir, METH_NOARGS, 
2442                 "get_adm_dir() -> name" },
2443         { "set_adm_dir", (PyCFunction)set_adm_dir, METH_VARARGS,
2444                 "set_adm_dir(name)" },
2445         { "get_pristine_copy_path", get_pristine_copy_path, METH_VARARGS, 
2446                 "get_pristine_copy_path(path) -> path" },
2447         { "get_pristine_contents", get_pristine_contents, METH_VARARGS,
2448                 "get_pristine_contents(path) -> stream" },
2449         { "is_adm_dir", is_adm_dir, METH_VARARGS, 
2450                 "is_adm_dir(name) -> bool" },
2451         { "is_normal_prop", is_normal_prop, METH_VARARGS, 
2452                 "is_normal_prop(name) -> bool" },
2453         { "is_entry_prop", is_entry_prop, METH_VARARGS, 
2454                 "is_entry_prop(name) -> bool" },
2455         { "is_wc_prop", is_wc_prop, METH_VARARGS, 
2456                 "is_wc_prop(name) -> bool" },
2457         { "revision_status", (PyCFunction)revision_status, METH_KEYWORDS|METH_VARARGS, "revision_status(wc_path, trail_url=None, committed=False, cancel_func=None) -> (min_rev, max_rev, switched, modified)" },
2458         { "version", (PyCFunction)version, METH_NOARGS,
2459                 "version() -> (major, minor, patch, tag)\n\n"
2460                 "Version of libsvn_wc currently used."
2461         },
2462         { "api_version", (PyCFunction)api_version, METH_NOARGS,
2463                 "api_version() -> (major, minor, patch, tag)\n\n"
2464                 "Version of libsvn_wc Subvertpy was compiled against."
2465         },
2466         { "match_ignore_list", (PyCFunction)match_ignore_list, METH_VARARGS,
2467                 "match_ignore_list(str, patterns) -> bool" },
2468         { "get_actual_target", (PyCFunction)get_actual_target, METH_VARARGS,
2469                 "get_actual_target(path) -> (anchor, target)" },
2470         { NULL, }
2471 };
2472
2473 void initwc(void)
2474 {
2475         PyObject *mod;
2476
2477         if (PyType_Ready(&Entry_Type) < 0)
2478                 return;
2479
2480         if (PyType_Ready(&Adm_Type) < 0)
2481                 return;
2482
2483         if (PyType_Ready(&Editor_Type) < 0)
2484                 return;
2485
2486         if (PyType_Ready(&FileEditor_Type) < 0)
2487                 return;
2488
2489         if (PyType_Ready(&DirectoryEditor_Type) < 0)
2490                 return;
2491
2492         if (PyType_Ready(&TxDeltaWindowHandler_Type) < 0)
2493                 return;
2494
2495         if (PyType_Ready(&Stream_Type) < 0)
2496                 return;
2497
2498         if (PyType_Ready(&CommittedQueue_Type) < 0)
2499                 return;
2500
2501         initeditor();
2502
2503         apr_initialize();
2504
2505         mod = Py_InitModule3("wc", wc_methods, "Working Copies");
2506         if (mod == NULL)
2507                 return;
2508
2509         PyModule_AddIntConstant(mod, "SCHEDULE_NORMAL", 0);
2510         PyModule_AddIntConstant(mod, "SCHEDULE_ADD", 1);
2511         PyModule_AddIntConstant(mod, "SCHEDULE_DELETE", 2);
2512         PyModule_AddIntConstant(mod, "SCHEDULE_REPLACE", 3);
2513
2514 #if ONLY_SINCE_SVN(1, 5)
2515         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_POSTPONE",
2516                                                         svn_wc_conflict_choose_postpone);
2517         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_BASE",
2518                                                         svn_wc_conflict_choose_base);
2519         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_FULL",
2520                                                         svn_wc_conflict_choose_theirs_full);
2521         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_FULL",
2522                                                         svn_wc_conflict_choose_mine_full);
2523         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_CONFLICT",
2524                                                         svn_wc_conflict_choose_theirs_conflict);
2525         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_CONFLICT",
2526                                                         svn_wc_conflict_choose_mine_conflict);
2527         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MERGED",
2528                                                         svn_wc_conflict_choose_merged);
2529 #endif
2530
2531         PyModule_AddIntConstant(mod, "STATUS_NONE", svn_wc_status_none);
2532         PyModule_AddIntConstant(mod, "STATUS_UNVERSIONED", svn_wc_status_unversioned);
2533         PyModule_AddIntConstant(mod, "STATUS_NORMAL", svn_wc_status_normal);
2534         PyModule_AddIntConstant(mod, "STATUS_ADDED", svn_wc_status_added);
2535         PyModule_AddIntConstant(mod, "STATUS_MISSING", svn_wc_status_missing);
2536         PyModule_AddIntConstant(mod, "STATUS_DELETED", svn_wc_status_deleted);
2537         PyModule_AddIntConstant(mod, "STATUS_REPLACED", svn_wc_status_replaced);
2538         PyModule_AddIntConstant(mod, "STATUS_MODIFIED", svn_wc_status_modified);
2539         PyModule_AddIntConstant(mod, "STATUS_MERGED", svn_wc_status_merged);
2540         PyModule_AddIntConstant(mod, "STATUS_CONFLICTED", svn_wc_status_conflicted);
2541         PyModule_AddIntConstant(mod, "STATUS_IGNORED", svn_wc_status_ignored);
2542         PyModule_AddIntConstant(mod, "STATUS_OBSTRUCTED", svn_wc_status_obstructed);
2543         PyModule_AddIntConstant(mod, "STATUS_EXTERNAL", svn_wc_status_external);
2544         PyModule_AddIntConstant(mod, "STATUS_INCOMPLETE", svn_wc_status_incomplete);
2545
2546         PyModule_AddIntConstant(mod, "TRANSLATE_FROM_NF", SVN_WC_TRANSLATE_FROM_NF);
2547         PyModule_AddIntConstant(mod, "TRANSLATE_TO_NF", SVN_WC_TRANSLATE_TO_NF);
2548         PyModule_AddIntConstant(mod, "TRANSLATE_FORCE_EOL_REPAIR", SVN_WC_TRANSLATE_FORCE_EOL_REPAIR);
2549         PyModule_AddIntConstant(mod, "TRANSLATE_NO_OUTPUT_CLEANUP", SVN_WC_TRANSLATE_NO_OUTPUT_CLEANUP);
2550         PyModule_AddIntConstant(mod, "TRANSLATE_FORCE_COPY", SVN_WC_TRANSLATE_FORCE_COPY);
2551         PyModule_AddIntConstant(mod, "TRANSLATE_USE_GLOBAL_TMP", SVN_WC_TRANSLATE_USE_GLOBAL_TMP);
2552
2553         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_POSTPONE", svn_wc_conflict_choose_postpone);
2554         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_BASE", svn_wc_conflict_choose_base);
2555         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_FULL", svn_wc_conflict_choose_theirs_full);
2556         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_FULL", svn_wc_conflict_choose_mine_full);
2557         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_CONFLICT", svn_wc_conflict_choose_theirs_conflict);
2558         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_CONFLICT", svn_wc_conflict_choose_mine_conflict);
2559         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MERGED", svn_wc_conflict_choose_merged);
2560
2561         PyModule_AddObject(mod, "WorkingCopy", (PyObject *)&Adm_Type);
2562         Py_INCREF(&Adm_Type);
2563
2564         PyModule_AddObject(mod, "CommittedQueue", (PyObject *)&CommittedQueue_Type);
2565         Py_INCREF(&CommittedQueue_Type);
2566 }