Fix two long lines.
[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,
938                                 depth_is_sticky, allow_unver_obstructions, 
939                                 py_wc_notify_func, (void *)notify_func, 
940                                 py_cancel_func, (void *)cancel_func, 
941                                 NULL, NULL, NULL, NULL,
942                                 diff3_cmd, NULL, &editor, &edit_baton, 
943                                 NULL, pool);
944 #else
945         if (allow_unver_obstructions) {
946                 PyErr_SetString(PyExc_NotImplementedError, 
947                                                 "allow_unver_obstructions is not supported in svn < 1.5");
948                 apr_pool_destroy(pool);
949                 PyEval_RestoreThread(_save);
950                 return NULL;
951         }
952         if (depth_is_sticky) {
953                 PyErr_SetString(PyExc_NotImplementedError, 
954                                                 "depth_is_sticky is not supported in svn < 1.5");
955                 apr_pool_destroy(pool);
956                 PyEval_RestoreThread(_save);
957                 return NULL;
958         }
959         err = svn_wc_get_update_editor2(latest_revnum, admobj->adm, target, 
960                                 use_commit_times, recurse, py_wc_notify_func, (void *)notify_func, 
961                                 py_cancel_func, (void *)cancel_func, diff3_cmd, &editor, &edit_baton, 
962                                 NULL, pool);
963 #endif
964         if (!check_error(err)) {
965                 apr_pool_destroy(pool);
966                 PyEval_RestoreThread(_save);
967                 return NULL;
968         }
969         Py_END_ALLOW_THREADS
970         return new_editor_object(editor, edit_baton, pool, &Editor_Type, NULL, NULL, NULL);
971 }
972
973 static bool py_dict_to_wcprop_changes(PyObject *dict, apr_pool_t *pool, apr_array_header_t **ret)
974 {
975         PyObject *key, *val;
976         Py_ssize_t idx;
977
978         if (dict == Py_None) {
979                 *ret = NULL;
980                 return true;
981         }
982
983         if (!PyDict_Check(dict)) {
984                 PyErr_SetString(PyExc_TypeError, "Expected dictionary with property changes");
985                 return false;
986         }
987
988         *ret = apr_array_make(pool, PyDict_Size(dict), sizeof(char *));
989
990         while (PyDict_Next(dict, &idx, &key, &val)) {
991                    svn_prop_t *prop = apr_palloc(pool, sizeof(svn_prop_t));
992                    prop->name = PyString_AsString(key);
993                    if (val == Py_None) {
994                            prop->value = NULL;
995                    } else {
996                            prop->value = svn_string_ncreate(PyString_AsString(val), PyString_Size(val), pool);
997                    }
998                    APR_ARRAY_PUSH(*ret, svn_prop_t *) = prop;
999         }
1000
1001         return true;
1002 }
1003
1004 static PyObject *adm_has_binary_prop(PyObject *self, PyObject *args)
1005 {
1006         char *path;
1007         svn_boolean_t binary;
1008         AdmObject *admobj = (AdmObject *)self;
1009         apr_pool_t *temp_pool;
1010
1011         if (!PyArg_ParseTuple(args, "s", &path))
1012                 return NULL;
1013
1014         ADM_CHECK_CLOSED(admobj);
1015
1016         temp_pool = Pool(NULL);
1017         if (temp_pool == NULL)
1018                 return NULL;
1019
1020         RUN_SVN_WITH_POOL(temp_pool, svn_wc_has_binary_prop(&binary, path, admobj->adm, temp_pool));
1021
1022         apr_pool_destroy(temp_pool);
1023
1024         return PyBool_FromLong(binary);
1025 }
1026
1027 static PyObject *adm_process_committed(PyObject *self, PyObject *args, PyObject *kwargs)
1028 {
1029         char *path, *rev_date = NULL, *rev_author = NULL;
1030         bool recurse, remove_lock = false;
1031         unsigned char *digest = NULL;
1032         svn_revnum_t new_revnum;
1033         PyObject *py_wcprop_changes = Py_None;
1034         apr_array_header_t *wcprop_changes = NULL;
1035         AdmObject *admobj = (AdmObject *)self;
1036         apr_pool_t *temp_pool;
1037         svn_boolean_t remove_changelist = FALSE;
1038         char *kwnames[] = { "path", "recurse", "new_revnum", "rev_date", "rev_author", 
1039                                                 "wcprop_changes", "remove_lock", "digest", "remove_changelist", NULL };
1040
1041         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sblzz|Obzb", kwnames, 
1042                                                                          &path, &recurse, &new_revnum, &rev_date,
1043                                                                          &rev_author, &py_wcprop_changes, 
1044                                                                          &remove_lock, &digest, &remove_changelist))
1045                 return NULL;
1046
1047 #if PY_VERSION_HEX < 0x02050000
1048         PyErr_Warn(PyExc_DeprecationWarning, "process_committed is deprecated. Use process_committed_queue instead.");
1049 #else
1050         PyErr_WarnEx(PyExc_DeprecationWarning, "process_committed is deprecated. Use process_committed_queue instead.", 2);
1051 #endif
1052
1053
1054         ADM_CHECK_CLOSED(admobj);
1055
1056         temp_pool = Pool(NULL);
1057         if (temp_pool == NULL)
1058                 return NULL;
1059
1060         if (!py_dict_to_wcprop_changes(py_wcprop_changes, temp_pool, &wcprop_changes)) {
1061                 apr_pool_destroy(temp_pool);
1062                 return NULL;
1063         }
1064
1065 #if ONLY_SINCE_SVN(1, 6)
1066         RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed4(
1067                 svn_path_canonicalize(path, temp_pool), admobj->adm, recurse, new_revnum, 
1068                         rev_date, rev_author, wcprop_changes, 
1069                         remove_lock, remove_changelist, digest, temp_pool));
1070 #else
1071         if (remove_changelist) {
1072                 PyErr_SetString(PyExc_NotImplementedError, "remove_changelist only supported in svn < 1.6");
1073                 apr_pool_destroy(temp_pool);
1074                 return NULL;
1075         }
1076         RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(svn_path_canonicalize(path, temp_pool), admobj->adm, recurse, new_revnum, 
1077                                                                                                                    rev_date, rev_author, wcprop_changes, 
1078                                                                                                                    remove_lock, digest, temp_pool));
1079 #endif
1080
1081         apr_pool_destroy(temp_pool);
1082
1083         Py_RETURN_NONE;
1084 }
1085
1086 static PyObject *adm_close(PyObject *self)
1087 {
1088         AdmObject *admobj = (AdmObject *)self;
1089         if (admobj->adm != NULL) {
1090 #if ONLY_SINCE_SVN(1, 6)
1091                 apr_pool_t *temp_pool = Pool(NULL);
1092                 Py_BEGIN_ALLOW_THREADS
1093                 svn_wc_adm_close2(admobj->adm, temp_pool);
1094                 apr_pool_destroy(temp_pool);
1095 #else
1096                 Py_BEGIN_ALLOW_THREADS
1097                 svn_wc_adm_close(admobj->adm);
1098 #endif
1099                 Py_END_ALLOW_THREADS
1100                 admobj->adm = NULL;
1101         }
1102
1103         Py_RETURN_NONE;
1104 }
1105
1106 static void adm_dealloc(PyObject *self)
1107 {
1108         apr_pool_destroy(((AdmObject *)self)->pool);
1109         PyObject_Del(self);
1110 }
1111
1112 static PyObject *adm_repr(PyObject *self)
1113 {
1114         AdmObject *admobj = (AdmObject *)self;
1115
1116         if (admobj->adm == NULL) {
1117                 return PyString_FromFormat("<wc.WorkingCopy (closed) at 0x%p>", admobj);
1118         } else {
1119                 return PyString_FromFormat("<wc.WorkingCopy at '%s'>", 
1120                                                                    svn_wc_adm_access_path(admobj->adm));
1121         }
1122 }
1123
1124 static PyObject *adm_remove_lock(PyObject *self, PyObject *args)
1125 {
1126         char *path;
1127         AdmObject *admobj = (AdmObject *)self;
1128         apr_pool_t *temp_pool;
1129
1130         if (!PyArg_ParseTuple(args, "s", &path))
1131                 return NULL;
1132
1133         ADM_CHECK_CLOSED(admobj);
1134
1135         temp_pool = Pool(NULL);
1136         if (temp_pool == NULL)
1137                 return NULL;
1138
1139         RUN_SVN_WITH_POOL(temp_pool, svn_wc_remove_lock(path, admobj->adm, temp_pool))
1140
1141         apr_pool_destroy(temp_pool);
1142
1143         Py_RETURN_NONE;
1144 }
1145
1146 static PyObject *get_ancestry(PyObject *self, PyObject *args)
1147 {
1148         char *path;
1149         char *url;
1150         svn_revnum_t rev;
1151         apr_pool_t *temp_pool;
1152         AdmObject *admobj = (AdmObject *)self;
1153
1154         if (!PyArg_ParseTuple(args, "s", &path))
1155                 return NULL;
1156
1157         ADM_CHECK_CLOSED(admobj);
1158
1159         temp_pool = Pool(NULL);
1160         if (temp_pool == NULL)
1161                 return NULL;
1162
1163         RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_ancestry(&url, &rev, path, admobj->adm, temp_pool));
1164
1165         apr_pool_destroy(temp_pool);
1166
1167         return Py_BuildValue("(si)", url, rev);
1168 }
1169
1170 static PyObject *maybe_set_repos_root(PyObject *self, PyObject *args)
1171 {
1172         char *path, *repos;
1173         apr_pool_t *temp_pool;
1174         AdmObject *admobj = (AdmObject *)self;
1175
1176         if (!PyArg_ParseTuple(args, "ss", &path, &repos))
1177                 return NULL;
1178
1179         ADM_CHECK_CLOSED(admobj);
1180
1181         temp_pool = Pool(NULL);
1182         if (temp_pool == NULL)
1183                 return NULL;
1184
1185         RUN_SVN_WITH_POOL(temp_pool, svn_wc_maybe_set_repos_root(admobj->adm, path, repos, temp_pool));
1186
1187         Py_RETURN_NONE;
1188 }
1189
1190 static PyObject *add_repos_file(PyObject *self, PyObject *args, PyObject *kwargs)
1191 {
1192         char *kwnames[] = { "dst_path", "new_base_contents", "new_contents",
1193                 "new_base_props", "new_props", "copyfrom_url", "copyfrom_rev",
1194                 "cancel_func", "notify", NULL };
1195         AdmObject *admobj = (AdmObject *)self;
1196         apr_pool_t *temp_pool;
1197         char *dst_path, *copyfrom_url = NULL;
1198         svn_revnum_t copyfrom_rev = -1;
1199         PyObject *py_new_base_contents, *py_new_contents, *py_new_base_props,
1200                          *py_new_props, *cancel_func = Py_None, *notify = Py_None;
1201         svn_stream_t *new_contents, *new_base_contents;
1202         apr_hash_t *new_props, *new_base_props;
1203
1204         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sOOOO|ziOO", kwnames,
1205                         &dst_path, &py_new_base_contents, &py_new_contents, &py_new_base_props, 
1206                         &py_new_props, &copyfrom_url, &copyfrom_rev, &cancel_func, &notify))
1207                 return NULL;
1208
1209         ADM_CHECK_CLOSED(admobj);
1210
1211         temp_pool = Pool(NULL);
1212         if (temp_pool == NULL)
1213                 return NULL;
1214
1215         new_base_props = prop_dict_to_hash(temp_pool, py_new_base_props);
1216
1217         new_props = prop_dict_to_hash(temp_pool, py_new_props);
1218
1219         new_base_contents = new_py_stream(temp_pool, py_new_base_contents);
1220
1221         new_contents = new_py_stream(temp_pool, py_new_contents);
1222
1223 #if ONLY_BEFORE_SVN(1, 6)
1224         if (cancel_func != Py_None) {
1225                 PyErr_SetString(PyExc_NotImplementedError,
1226                                                 "cancel not support for svn < 1.6");
1227                 return NULL;
1228         }
1229 #endif
1230
1231 #if ONLY_SINCE_SVN(1, 6)
1232         RUN_SVN_WITH_POOL(temp_pool, svn_wc_add_repos_file3(dst_path, admobj->adm,
1233                                                    new_base_contents,
1234                                                    new_contents,
1235                                                    new_base_props,
1236                                                    new_props,
1237                                                    copyfrom_url, copyfrom_rev,
1238                                                    py_cancel_func, cancel_func,
1239                                                    py_wc_notify_func, notify, temp_pool));
1240 #else
1241         PyErr_SetString(PyExc_NotImplementedError,
1242                                         "add_repos_file3 not supported on svn < 1.6");
1243         apr_pool_destroy(temp_pool);
1244 #endif
1245
1246         apr_pool_destroy(temp_pool);
1247
1248         Py_RETURN_NONE;
1249 }
1250
1251 static PyObject *mark_missing_deleted(PyObject *self, PyObject *args)
1252 {
1253         char *path;
1254         AdmObject *admobj = (AdmObject *)self;
1255         apr_pool_t *temp_pool;
1256
1257         if (!PyArg_ParseTuple(args, "s", &path))
1258                 return NULL;
1259
1260         ADM_CHECK_CLOSED(admobj);
1261
1262         temp_pool = Pool(NULL);
1263         if (temp_pool == NULL)
1264                 return NULL;
1265
1266         RUN_SVN_WITH_POOL(temp_pool, svn_wc_mark_missing_deleted(path, admobj->adm, temp_pool));
1267
1268         apr_pool_destroy(temp_pool);
1269
1270         Py_RETURN_NONE;
1271 }
1272
1273 static PyObject *remove_from_revision_control(PyObject *self, PyObject *args)
1274 {
1275         char *name;
1276         svn_boolean_t destroy_wf = FALSE, instant_error = FALSE;
1277         AdmObject *admobj = (AdmObject *)self;
1278         PyObject *cancel_func = Py_None;
1279         apr_pool_t *temp_pool;
1280
1281         if (!PyArg_ParseTuple(args, "s|bbO", &name, &destroy_wf, &instant_error, &cancel_func))
1282                 return NULL;
1283
1284         ADM_CHECK_CLOSED(admobj);
1285
1286         temp_pool = Pool(NULL);
1287         if (temp_pool == NULL)
1288                 return NULL;
1289
1290         RUN_SVN_WITH_POOL(temp_pool,
1291                 svn_wc_remove_from_revision_control(admobj->adm, name,
1292                         destroy_wf, instant_error, py_cancel_func, cancel_func, temp_pool));
1293
1294         apr_pool_destroy(temp_pool);
1295
1296         Py_RETURN_NONE;
1297 }
1298
1299 #if ONLY_SINCE_SVN(1, 6)
1300 static svn_error_t *wc_validator3(void *baton, const char *uuid, const char *url, const char *root_url, apr_pool_t *pool)
1301 {
1302         PyObject *py_validator = baton, *ret;
1303
1304         if (py_validator == Py_None) {
1305                 return NULL;
1306         }
1307
1308         ret = PyObject_CallFunction(py_validator, "sss", uuid, url, root_url);
1309         if (ret == NULL) {
1310                 return py_svn_error();
1311         }
1312
1313         Py_DECREF(ret);
1314
1315         return NULL;
1316 }
1317
1318 #else
1319
1320 static svn_error_t *wc_validator2(void *baton, const char *uuid, const char *url, svn_boolean_t root, apr_pool_t *pool)
1321 {
1322         PyObject *py_validator = baton, *ret;
1323
1324         if (py_validator == Py_None) {
1325                 return NULL;
1326         }
1327
1328         ret = PyObject_CallFunction(py_validator, "ssO", uuid, url, Py_None);
1329         if (ret == NULL) {
1330                 return py_svn_error();
1331         }
1332
1333         Py_DECREF(ret);
1334
1335         return NULL;
1336 }
1337
1338 #endif
1339
1340 static PyObject *relocate(PyObject *self, PyObject *args)
1341 {
1342         char *path, *from, *to;
1343         AdmObject *admobj = (AdmObject *)self;
1344         apr_pool_t *temp_pool;
1345         svn_boolean_t recurse = TRUE;
1346         PyObject *py_validator = Py_None;
1347
1348         if (!PyArg_ParseTuple(args, "sss|bO", &path, &from, &to, &recurse, &py_validator))
1349                 return NULL;
1350
1351         ADM_CHECK_CLOSED(admobj);
1352
1353         temp_pool = Pool(NULL);
1354         if (temp_pool == NULL)
1355                 return NULL;
1356
1357 #if ONLY_SINCE_SVN(1, 6)
1358         RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate3(path, admobj->adm, from, to, recurse, wc_validator3, py_validator, temp_pool));
1359 #else
1360         RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate2(path, admobj->adm, from, to, recurse, wc_validator2, py_validator, temp_pool));
1361 #endif
1362
1363         apr_pool_destroy(temp_pool);
1364
1365         Py_RETURN_NONE;
1366 }
1367
1368 static PyObject *crop_tree(PyObject *self, PyObject *args)
1369 {
1370         char *target;
1371         svn_depth_t depth;
1372         PyObject *notify, *cancel;
1373         apr_pool_t *temp_pool;
1374         AdmObject *admobj = (AdmObject *)self;
1375
1376         if (!PyArg_ParseTuple(args, "si|OO", &target, &depth, &notify, &cancel))
1377                 return NULL;
1378
1379         ADM_CHECK_CLOSED(admobj);
1380
1381 #if ONLY_SINCE_SVN(1, 6)
1382         temp_pool = Pool(NULL);
1383         if (temp_pool == NULL)
1384                 return NULL;
1385
1386         RUN_SVN_WITH_POOL(temp_pool, svn_wc_crop_tree(admobj->adm, 
1387                 target, depth, py_wc_notify_func, notify,
1388                 py_cancel_func, cancel, temp_pool));
1389
1390         apr_pool_destroy(temp_pool);
1391
1392         Py_RETURN_NONE;
1393 #else
1394         PyErr_SetString(PyExc_NotImplementedError, 
1395                                         "crop_tree only available on subversion < 1.6");
1396         return NULL;
1397 #endif
1398 }
1399
1400 static PyObject *translated_stream(PyObject *self, PyObject *args)
1401 {
1402         char *path, *versioned_file;
1403         StreamObject *ret;
1404         svn_stream_t *stream;
1405         AdmObject *admobj = (AdmObject *)self;
1406         apr_pool_t *stream_pool;
1407         int flags;
1408
1409         if (!PyArg_ParseTuple(args, "ssi", &path, &versioned_file, &flags))
1410                 return NULL;
1411
1412         ADM_CHECK_CLOSED(admobj);
1413
1414 #if ONLY_SINCE_SVN(1, 5)
1415         stream_pool = Pool(NULL);
1416         if (stream_pool == NULL)
1417                 return NULL;
1418
1419         RUN_SVN_WITH_POOL(stream_pool,
1420                 svn_wc_translated_stream(&stream, path, versioned_file, admobj->adm, 
1421                         flags, stream_pool));
1422
1423         ret = PyObject_New(StreamObject, &Stream_Type);
1424         if (ret == NULL)
1425                 return NULL;
1426
1427         ret->pool = stream_pool;
1428         ret->closed = FALSE;
1429         ret->stream = stream;
1430
1431         return (PyObject *)ret;
1432 #else
1433         PyErr_SetString(PyExc_NotImplementedError,
1434                 "translated_stream() is only available on Subversion >= 1.5");
1435         return NULL;
1436 #endif
1437 }
1438
1439 static PyObject *adm_text_modified(PyObject *self, PyObject *args)
1440 {
1441         char *path;
1442         svn_boolean_t force_comparison = FALSE;
1443         apr_pool_t *temp_pool;
1444         svn_boolean_t ret;
1445         AdmObject *admobj = (AdmObject *)self;
1446
1447         if (!PyArg_ParseTuple(args, "s|b", &path, &force_comparison))
1448                 return NULL;
1449
1450         ADM_CHECK_CLOSED(admobj);
1451
1452         temp_pool = Pool(NULL);
1453         if (temp_pool == NULL)
1454                 return NULL;
1455
1456         RUN_SVN_WITH_POOL(temp_pool,
1457                   svn_wc_text_modified_p(&ret, path, force_comparison, admobj->adm, 
1458                         temp_pool));
1459
1460         apr_pool_destroy(temp_pool);
1461
1462         return PyBool_FromLong(ret);
1463 }
1464
1465 static PyObject *adm_props_modified(PyObject *self, PyObject *args)
1466 {
1467         char *path;
1468         apr_pool_t *temp_pool;
1469         svn_boolean_t ret;
1470         AdmObject *admobj = (AdmObject *)self;
1471
1472         if (!PyArg_ParseTuple(args, "s", &path))
1473                 return NULL;
1474
1475         ADM_CHECK_CLOSED(admobj);
1476
1477         temp_pool = Pool(NULL);
1478         if (temp_pool == NULL)
1479                 return NULL;
1480
1481         RUN_SVN_WITH_POOL(temp_pool,
1482                   svn_wc_props_modified_p(&ret, path, admobj->adm, temp_pool));
1483
1484         apr_pool_destroy(temp_pool);
1485
1486         return PyBool_FromLong(ret);
1487 }
1488
1489 static PyObject *adm_process_committed_queue(PyObject *self, PyObject *args)
1490 {
1491         apr_pool_t *temp_pool;
1492         AdmObject *admobj = (AdmObject *)self;
1493         svn_revnum_t revnum;
1494         char *date, *author;
1495         CommittedQueueObject *py_queue;
1496
1497         if (!PyArg_ParseTuple(args, "O!Iss", &CommittedQueue_Type, &py_queue, &revnum, &date, &author))
1498                 return NULL;
1499
1500         ADM_CHECK_CLOSED(admobj);
1501
1502         temp_pool = Pool(NULL);
1503         if (temp_pool == NULL)
1504                 return NULL;
1505
1506 #if ONLY_SINCE_SVN(1, 5)
1507         RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed_queue(py_queue->queue, admobj->adm, revnum, date, author, temp_pool));
1508 #else
1509         {
1510                 int i;
1511                 for (i = 0; i < py_queue->queue->queue->nelts; i++) {
1512                         committed_queue_item_t *cqi = APR_ARRAY_IDX(py_queue->queue->queue, i,
1513                                                                                                                 committed_queue_item_t *);
1514
1515                         RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(cqi->path, admobj->adm,
1516                                    cqi->recurse, revnum, date, author, cqi->wcprop_changes,
1517                                    cqi->remove_lock, cqi->digest, temp_pool));
1518                 }
1519         }
1520 #endif
1521         apr_pool_destroy(temp_pool);
1522
1523         Py_RETURN_NONE;
1524 }
1525
1526 static PyObject *get_actual_target(PyObject *self, PyObject *args)
1527 {
1528         char *path;
1529         const char *anchor = NULL, *target = NULL;
1530         apr_pool_t *temp_pool;
1531         PyObject *ret;
1532
1533         if (!PyArg_ParseTuple(args, "s", &path))
1534                 return NULL;
1535
1536         temp_pool = Pool(NULL);
1537         if (temp_pool == NULL)
1538                 return NULL;
1539
1540         RUN_SVN_WITH_POOL(temp_pool,
1541                   svn_wc_get_actual_target(svn_path_canonicalize(path, temp_pool),
1542                                                                    &anchor, &target, temp_pool));
1543
1544         ret = Py_BuildValue("(ss)", anchor, target);
1545
1546         apr_pool_destroy(temp_pool);
1547
1548         return ret;
1549 }
1550
1551 static PyObject *is_wc_root(PyObject *self, PyObject *args)
1552 {
1553         char *path;
1554         svn_boolean_t wc_root;
1555         apr_pool_t *temp_pool;
1556         AdmObject *admobj = (AdmObject *)self;
1557
1558         if (!PyArg_ParseTuple(args, "s", &path))
1559                 return NULL;
1560
1561         ADM_CHECK_CLOSED(admobj);
1562
1563         temp_pool = Pool(NULL);
1564         if (temp_pool == NULL)
1565                 return NULL;
1566
1567         RUN_SVN_WITH_POOL(temp_pool,
1568                   svn_wc_is_wc_root(&wc_root, path, admobj->adm, temp_pool));
1569
1570         apr_pool_destroy(temp_pool);
1571
1572         return PyBool_FromLong(wc_root);
1573 }
1574
1575 static PyObject *transmit_text_deltas(PyObject *self, PyObject *args)
1576 {
1577         char *path;
1578         const char *tempfile;
1579         svn_boolean_t fulltext;
1580         PyObject *editor_obj, *py_digest;
1581         unsigned char digest[APR_MD5_DIGESTSIZE];
1582         apr_pool_t *temp_pool;
1583         AdmObject *admobj = (AdmObject *)self;
1584         PyObject *ret;
1585
1586         if (!PyArg_ParseTuple(args, "sbO", &path, &fulltext, &editor_obj))
1587                 return NULL;
1588
1589         ADM_CHECK_CLOSED(admobj);
1590
1591         temp_pool = Pool(NULL);
1592         if (temp_pool == NULL)
1593                 return NULL;
1594
1595         Py_INCREF(editor_obj);
1596
1597         RUN_SVN_WITH_POOL(temp_pool,
1598                 svn_wc_transmit_text_deltas2(&tempfile, digest, 
1599                         svn_path_canonicalize(path, temp_pool), admobj->adm, fulltext,
1600                         &py_editor, editor_obj, temp_pool));
1601
1602         py_digest = PyString_FromStringAndSize((char *)digest, APR_MD5_DIGESTSIZE);
1603         if (py_digest == NULL) {
1604                 apr_pool_destroy(temp_pool);
1605                 return NULL;
1606         }
1607
1608         ret = Py_BuildValue("sN", tempfile, py_digest);
1609         if (ret == NULL) {
1610                 apr_pool_destroy(temp_pool);
1611                 return NULL;
1612         }
1613
1614         apr_pool_destroy(temp_pool);
1615
1616         return ret;
1617 }
1618
1619 static PyObject *transmit_prop_deltas(PyObject *self, PyObject *args)
1620 {
1621         char *path;
1622         PyObject *editor_obj;
1623         apr_pool_t *temp_pool;
1624         AdmObject *admobj = (AdmObject *)self;
1625         EntryObject *py_entry;
1626
1627         if (!PyArg_ParseTuple(args, "sO!O", &path, &Entry_Type, &py_entry, &editor_obj))
1628                 return NULL;
1629
1630         ADM_CHECK_CLOSED(admobj);
1631
1632         temp_pool = Pool(NULL);
1633         if (temp_pool == NULL)
1634                 return NULL;
1635
1636         Py_INCREF(editor_obj);
1637
1638         RUN_SVN_WITH_POOL(temp_pool,
1639                 svn_wc_transmit_prop_deltas(svn_path_canonicalize(path, temp_pool),
1640                         admobj->adm, &(py_entry->entry), &py_editor, editor_obj, NULL, temp_pool));
1641
1642         apr_pool_destroy(temp_pool);
1643
1644         Py_RETURN_NONE;
1645 }
1646
1647 static PyObject *retrieve(PyObject *self, PyObject *args)
1648 {
1649         char *path;
1650         svn_wc_adm_access_t *result;
1651         AdmObject *admobj = (AdmObject *)self, *ret;
1652         apr_pool_t *pool;
1653
1654         if (!PyArg_ParseTuple(args, "s", &path))
1655                 return NULL;
1656
1657         ADM_CHECK_CLOSED(admobj);
1658
1659         pool = Pool(NULL);
1660         if (pool == NULL)
1661                 return NULL;
1662
1663         RUN_SVN_WITH_POOL(pool, svn_wc_adm_retrieve(&result, admobj->adm, 
1664                 svn_path_canonicalize(path, pool), pool));
1665
1666         ret = PyObject_New(AdmObject, &Adm_Type);
1667         if (ret == NULL)
1668                 return NULL;
1669
1670         ret->pool = pool;
1671         ret->adm = result;
1672
1673         return (PyObject *)ret;
1674 }
1675
1676 static PyObject *probe_retrieve(PyObject *self, PyObject *args)
1677 {
1678         char *path;
1679         svn_wc_adm_access_t *result;
1680         AdmObject *admobj = (AdmObject *)self, *ret;
1681         apr_pool_t *pool;
1682
1683         if (!PyArg_ParseTuple(args, "s", &path))
1684                 return NULL;
1685
1686         ADM_CHECK_CLOSED(admobj);
1687
1688         pool = Pool(NULL);
1689         if (pool == NULL)
1690                 return NULL;
1691
1692         RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_retrieve(&result, admobj->adm, 
1693                 svn_path_canonicalize(path, pool), pool));
1694
1695         ret = PyObject_New(AdmObject, &Adm_Type);
1696         if (ret == NULL)
1697                 return NULL;
1698
1699         ret->pool = pool;
1700         ret->adm = result;
1701
1702         return (PyObject *)ret;
1703 }
1704
1705 static PyObject *probe_try(PyObject *self, PyObject *args)
1706 {
1707         char *path;
1708         svn_wc_adm_access_t *result = NULL;
1709         AdmObject *admobj = (AdmObject *)self, *ret;
1710         apr_pool_t *pool;
1711         PyObject *cancelfunc = Py_None;
1712         int levels_to_lock = -1;
1713         svn_boolean_t writelock = FALSE;
1714
1715         if (!PyArg_ParseTuple(args, "s|biO", &path, &writelock, &levels_to_lock, &cancelfunc))
1716                 return NULL;
1717
1718         ADM_CHECK_CLOSED(admobj);
1719
1720         pool = Pool(NULL);
1721         if (pool == NULL)
1722                 return NULL;
1723
1724         RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_try3(&result, admobj->adm, 
1725                 svn_path_canonicalize(path, pool), writelock, levels_to_lock,
1726                 py_cancel_func, cancelfunc, pool));
1727
1728         if (result == NULL) {
1729                 apr_pool_destroy(pool);
1730                 Py_RETURN_NONE;
1731         }
1732
1733         ret = PyObject_New(AdmObject, &Adm_Type);
1734         if (ret == NULL)
1735                 return NULL;
1736
1737         ret->pool = pool;
1738         ret->adm = result;
1739
1740         return (PyObject *)ret;
1741 }
1742
1743 static PyObject *resolved_conflict(PyObject *self, PyObject *args)
1744 {
1745         AdmObject *admobj = (AdmObject *)self;
1746         apr_pool_t *temp_pool;
1747         svn_boolean_t resolve_props, resolve_tree, resolve_text;
1748         int depth;
1749         svn_wc_conflict_choice_t conflict_choice;
1750         PyObject *notify_func = Py_None, *cancel_func = Py_None;
1751         char *path;
1752
1753         if (!PyArg_ParseTuple(args, "sbbbii|OO", &path, &resolve_text,
1754                                                   &resolve_props, &resolve_tree, &depth,
1755                                                   &conflict_choice, &notify_func, &cancel_func))
1756                 return NULL;
1757
1758         ADM_CHECK_CLOSED(admobj);
1759
1760         temp_pool = Pool(NULL);
1761         if (temp_pool == NULL)
1762                 return NULL;
1763
1764 #if ONLY_SINCE_SVN(1, 6)
1765         RUN_SVN_WITH_POOL(temp_pool,
1766                   svn_wc_resolved_conflict4(path, admobj->adm, resolve_text, 
1767                                                                                 resolve_props, resolve_tree, depth,
1768                                                                                 conflict_choice, py_wc_notify_func,
1769                                                                            (void *)notify_func, py_cancel_func,
1770                                                                            cancel_func, temp_pool));
1771 #elif ONLY_SINCE_SVN(1, 5)
1772         if (resolve_tree) {
1773                 PyErr_SetString(PyExc_NotImplementedError,
1774                                                 "resolve_tree not supported with svn < 1.6");
1775         } else {
1776                 RUN_SVN_WITH_POOL(temp_pool,
1777                           svn_wc_resolved_conflict3(path, admobj->adm, resolve_text, 
1778                                                                                         resolve_props, depth,
1779                                                                                         conflict_choice, py_wc_notify_func,
1780                                                                                    (void *)notify_func, py_cancel_func,
1781                                                                                    cancel_func, temp_pool));
1782         }
1783 #else
1784         if (resolve_tree) {
1785                 PyErr_SetString(PyExc_NotImplementedError,
1786                                                 "resolve_tree not supported with svn < 1.6");
1787         } else if (depth != svn_depth_infinity && depth != svn_depth_empty) {
1788                 PyErr_SetString(PyExc_NotImplementedError,
1789                                                 "only infinity and empty values for depth are supported");
1790         } else {
1791                 RUN_SVN_WITH_POOL(temp_pool,
1792                           svn_wc_resolved_conflict3(path, admobj->adm, resolve_text, 
1793                                                                                         resolve_props, 
1794                                                                                         (depth == svn_depth_infinity),
1795                                                                                         conflict_choice, py_wc_notify_func,
1796                                                                                    (void *)notify_func, py_cancel_func,
1797                                                                                    cancel_func, temp_pool));
1798         }
1799 #endif
1800
1801         apr_pool_destroy(temp_pool);
1802
1803         Py_RETURN_NONE;
1804 }
1805
1806 static PyObject *conflicted(PyObject *self, PyObject *args)
1807 {
1808         char *path;
1809         apr_pool_t *temp_pool;
1810         PyObject *ret;
1811         AdmObject *admobj = (AdmObject *)self;
1812         svn_boolean_t text_conflicted, prop_conflicted, tree_conflicted;
1813
1814         if (!PyArg_ParseTuple(args, "s", &path))
1815                 return NULL;
1816
1817         ADM_CHECK_CLOSED(admobj);
1818
1819         temp_pool = Pool(NULL);
1820         if (temp_pool == NULL)
1821                 return NULL;
1822
1823 #if ONLY_SINCE_SVN(1, 6)
1824         RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p2(&text_conflicted,
1825                 &prop_conflicted, &tree_conflicted, path, admobj->adm, temp_pool));
1826
1827         ret = Py_BuildValue("(bbb)", text_conflicted, prop_conflicted, tree_conflicted);
1828 #else
1829         RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p(&text_conflicted,
1830                 &prop_conflicted, path, admobj->adm, temp_pool));
1831
1832         ret = Py_BuildValue("(bbO)", text_conflicted, prop_conflicted, Py_None);
1833 #endif
1834
1835         apr_pool_destroy(temp_pool);
1836
1837         return ret;
1838 }
1839
1840 static PyMethodDef adm_methods[] = { 
1841         { "prop_set", adm_prop_set, METH_VARARGS, "S.prop_set(name, value, path, skip_checks=False)" },
1842         { "access_path", (PyCFunction)adm_access_path, METH_NOARGS, 
1843                 "S.access_path() -> path\n"
1844                 "Returns the base path for this working copy handle." },
1845         { "prop_get", adm_prop_get, METH_VARARGS, "S.prop_get(name, path) -> value" },
1846         { "entries_read", adm_entries_read, METH_VARARGS, "S.entries_read(include_hidden=False) -> dict" },
1847         { "walk_entries", adm_walk_entries, METH_VARARGS, 
1848                 "S.walk_entries(path, callback, show_hidden=False, cancel_func=None)\n"
1849                 "callback should be a function that takes a path and a wc entry" },
1850         { "locked", (PyCFunction)adm_locked, METH_NOARGS, 
1851                 "S.locked() -> bool" },
1852         { "get_prop_diffs", adm_get_prop_diffs, METH_VARARGS, 
1853                 "S.get_prop_diffs(path) -> (propchanges, originalprops)" },
1854         { "add", (PyCFunction)adm_add, METH_VARARGS|METH_KEYWORDS, "S.add(path, copyfrom_url=None, copyfrom_rev=-1, cancel_func=None, notify_func=None)" },
1855         { "copy", adm_copy, METH_VARARGS, "S.copy(src_path, dest_path, cancel_func=None, notify_func=None)" },
1856         { "delete", (PyCFunction)adm_delete, METH_VARARGS|METH_KEYWORDS, "S.delete(path, cancel_func=None, notify_func=None, keep_local=False)" },
1857         { "crawl_revisions", (PyCFunction)adm_crawl_revisions, METH_VARARGS|METH_KEYWORDS, 
1858                 "S.crawl_revisions(path, reporter, restore_files=True, recurse=True, use_commit_times=True, notify_func=None) -> None" },
1859         { "get_update_editor", adm_get_update_editor, METH_VARARGS, NULL },
1860         { "close", (PyCFunction)adm_close, METH_NOARGS, 
1861                 "S.close()" },
1862         { "entry", (PyCFunction)adm_entry, METH_VARARGS, 
1863                 "s.entry(path, show_hidden=False) -> entry" },
1864         { "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)" },
1865         { "process_committed_queue", (PyCFunction)adm_process_committed_queue, METH_VARARGS, "S.process_committed_queue(queue, new_revnum, rev_date, rev_author)" },
1866         { "remove_lock", (PyCFunction)adm_remove_lock, METH_VARARGS, "S.remove_lock(path)" }, 
1867         { "has_binary_prop", (PyCFunction)adm_has_binary_prop, METH_VARARGS, "S.has_binary_prop(path) -> bool" },
1868         { "text_modified", (PyCFunction)adm_text_modified, METH_VARARGS, "S.text_modified(filename, force_comparison=False) -> bool" },
1869         { "props_modified", (PyCFunction)adm_props_modified, METH_VARARGS, "S.props_modified(filename) -> bool" },
1870         { "get_ancestry", (PyCFunction)get_ancestry, METH_VARARGS,
1871                 "S.get_ancestry(path) -> (url, rev)" },
1872         { "maybe_set_repos_root", (PyCFunction)maybe_set_repos_root, METH_VARARGS, "S.maybe_set_repos_root(path, repos)" },
1873         { "add_repos_file", (PyCFunction)add_repos_file, METH_KEYWORDS, 
1874                 "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)" },
1875         { "mark_missing_deleted", (PyCFunction)mark_missing_deleted, METH_VARARGS,
1876                 "S.mark_missing_deleted(path)" },
1877         { "remove_from_revision_control", (PyCFunction)remove_from_revision_control, METH_VARARGS,
1878                 "S.remove_from_revision_control(name, destroy_wf=False, instant_error=False, cancel_func=None)" },
1879         { "relocate", (PyCFunction)relocate, METH_VARARGS,
1880                 "S.relocate(path, from, to, recurse=TRUE, validator=None)" },
1881         { "crop_tree", (PyCFunction)crop_tree, METH_VARARGS,
1882                 "S.crop_tree(target, depth, notify_func=None, cancel=None)" },
1883         { "translated_stream", (PyCFunction)translated_stream, METH_VARARGS,
1884                 "S.translated_stream(path, versioned_file, flags) -> stream" },
1885         { "is_wc_root", (PyCFunction)is_wc_root, METH_VARARGS,
1886                 "S.is_wc_root(path) -> wc_root" },
1887         { "transmit_text_deltas", (PyCFunction)transmit_text_deltas, METH_VARARGS,
1888                 "S.transmit_text_deltas(fulltext, editor) -> (tempfile, digest)" },
1889         { "transmit_prop_deltas", (PyCFunction)transmit_prop_deltas, METH_VARARGS,
1890                 "S.transmit_prop_deltas(path, entry, editor)" },
1891         { "probe_retrieve", (PyCFunction)probe_retrieve, METH_VARARGS,
1892                 "S.probe_retrieve(path) -> WorkingCopy" },
1893         { "retrieve", (PyCFunction)retrieve, METH_VARARGS,
1894                 "S.retrieve(path) -> WorkingCopy" },
1895         { "probe_try", (PyCFunction)probe_try, METH_VARARGS,
1896                 "S.probe_try(path, write_lock=False, levels_to_lock=-1)" },
1897         { "conflicted", (PyCFunction)conflicted, METH_VARARGS,
1898                 "S.conflicted(path) -> (text_conflicted, prop_conflicted, tree_conflicted)" },
1899         { "resolved_conflict", (PyCFunction)resolved_conflict, METH_VARARGS,
1900                 "S.resolved_conflict(path, resolve_text, resolve_props, resolve_tree, depth, conflict_choice, notify_func=None, cancel=None)" },
1901         { NULL, }
1902 };
1903
1904 static PyTypeObject Adm_Type = {
1905         PyObject_HEAD_INIT(NULL) 0,
1906         "wc.WorkingCopy", /*    const char *tp_name;  For printing, in format "<module>.<name>" */
1907         sizeof(AdmObject), 
1908         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
1909         
1910         /* Methods to implement standard operations */
1911         
1912         adm_dealloc, /* destructor tp_dealloc;  */
1913         NULL, /*        printfunc tp_print;     */
1914         NULL, /*        getattrfunc tp_getattr; */
1915         NULL, /*        setattrfunc tp_setattr; */
1916         NULL, /*        cmpfunc tp_compare;     */
1917         adm_repr, /*    reprfunc tp_repr;       */
1918         
1919         /* Method suites for standard classes */
1920         
1921         NULL, /*        PyNumberMethods *tp_as_number;  */
1922         NULL, /*        PySequenceMethods *tp_as_sequence;      */
1923         NULL, /*        PyMappingMethods *tp_as_mapping;        */
1924         
1925         /* More standard operations (here for binary compatibility) */
1926         
1927         NULL, /*        hashfunc tp_hash;       */
1928         NULL, /*        ternaryfunc tp_call;    */
1929         adm_repr, /*    reprfunc tp_repr;       */
1930         NULL, /*        getattrofunc tp_getattro;       */
1931         NULL, /*        setattrofunc tp_setattro;       */
1932         
1933         /* Functions to access object as input/output buffer */
1934         NULL, /*        PyBufferProcs *tp_as_buffer;    */
1935         
1936         /* Flags to define presence of optional/expanded features */
1937         0, /*   long tp_flags;  */
1938         
1939         "Local working copy", /*        const char *tp_doc;  Documentation string */
1940         
1941         /* Assigned meaning in release 2.0 */
1942         /* call function for all accessible objects */
1943         NULL, /*        traverseproc tp_traverse;       */
1944         
1945         /* delete references to contained objects */
1946         NULL, /*        inquiry tp_clear;       */
1947         
1948         /* Assigned meaning in release 2.1 */
1949         /* rich comparisons */
1950         NULL, /*        richcmpfunc tp_richcompare;     */
1951         
1952         /* weak reference enabler */
1953         0, /*   Py_ssize_t tp_weaklistoffset;   */
1954         
1955         /* Added in release 2.2 */
1956         /* Iterators */
1957         NULL, /*        getiterfunc tp_iter;    */
1958         NULL, /*        iternextfunc tp_iternext;       */
1959         
1960         /* Attribute descriptor and subclassing stuff */
1961         adm_methods, /* struct PyMethodDef *tp_methods; */
1962         NULL, /*        struct PyMemberDef *tp_members; */
1963         NULL, /*        struct PyGetSetDef *tp_getset;  */
1964         NULL, /*        struct _typeobject *tp_base;    */
1965         NULL, /*        PyObject *tp_dict;      */
1966         NULL, /*        descrgetfunc tp_descr_get;      */
1967         NULL, /*        descrsetfunc tp_descr_set;      */
1968         0, /*   Py_ssize_t tp_dictoffset;       */
1969         NULL, /*        initproc tp_init;       */
1970         NULL, /*        allocfunc tp_alloc;     */
1971         adm_init, /*    newfunc tp_new; */
1972 };
1973
1974 static void committed_queue_dealloc(PyObject *self)
1975 {
1976         apr_pool_destroy(((CommittedQueueObject *)self)->pool);
1977         PyObject_Del(self);
1978 }
1979
1980 static PyObject *committed_queue_repr(PyObject *self)
1981 {
1982         CommittedQueueObject *cqobj = (CommittedQueueObject *)self;
1983
1984         return PyString_FromFormat("<wc.CommittedQueue at 0x%p>", cqobj->queue);
1985 }
1986
1987 static PyObject *committed_queue_init(PyTypeObject *self, PyObject *args, PyObject *kwargs)
1988 {
1989         CommittedQueueObject *ret;
1990         char *kwnames[] = { NULL };
1991
1992         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwnames))
1993                 return NULL;
1994
1995         ret = PyObject_New(CommittedQueueObject, &CommittedQueue_Type);
1996         if (ret == NULL)
1997                 return NULL;
1998
1999         ret->pool = Pool(NULL);
2000         if (ret->pool == NULL)
2001                 return NULL;
2002         ret->queue = svn_wc_committed_queue_create(ret->pool);
2003         if (ret->queue == NULL) {
2004                 PyObject_Del(ret);
2005                 PyErr_NoMemory();
2006                 return NULL;
2007         }
2008
2009         return (PyObject *)ret;
2010 }
2011
2012 static PyObject *committed_queue_queue(CommittedQueueObject *self, PyObject *args)
2013 {
2014         char *path;
2015         AdmObject *admobj;
2016         PyObject *py_wcprop_changes = Py_None;
2017         svn_boolean_t remove_lock = FALSE, remove_changelist = FALSE;
2018         char *digest = NULL;
2019         svn_boolean_t recurse = FALSE;
2020         apr_pool_t *temp_pool;
2021         apr_array_header_t *wcprop_changes;
2022
2023         if (!PyArg_ParseTuple(args, "sO!|bObbz", &path, &Adm_Type, &admobj, &recurse, &py_wcprop_changes, &remove_lock, &remove_changelist, &digest))
2024                 return NULL;
2025
2026         temp_pool = Pool(NULL);
2027         if (temp_pool == NULL)
2028                 return NULL;
2029
2030         if (!py_dict_to_wcprop_changes(py_wcprop_changes, self->pool, &wcprop_changes)) {
2031                 apr_pool_destroy(temp_pool);
2032                 return NULL;
2033         }
2034
2035         path = apr_pstrdup(self->pool, path);
2036         if (path == NULL) {
2037                 PyErr_NoMemory();
2038                 return NULL;
2039         }
2040
2041         if (digest != NULL) {
2042                 digest = apr_pstrdup(self->pool, digest);
2043                 if (digest == NULL) {
2044                         PyErr_NoMemory();
2045                         return NULL;
2046                 }
2047         }
2048
2049         RUN_SVN_WITH_POOL(temp_pool, 
2050                 svn_wc_queue_committed(&self->queue, path, admobj->adm, recurse,
2051                                                            wcprop_changes, remove_lock, remove_changelist,
2052                                                            (unsigned char *)digest, temp_pool));
2053
2054         apr_pool_destroy(temp_pool);
2055
2056         Py_RETURN_NONE;
2057 }
2058
2059 static PyMethodDef committed_queue_methods[] = {
2060         { "queue", (PyCFunction)committed_queue_queue, METH_VARARGS,
2061                 "S.queue(path, adm, recurse, wcprop_changes, remove_lock, remove_changelist, digest)" },
2062         { NULL }
2063 };
2064
2065 static PyTypeObject CommittedQueue_Type = {
2066         PyObject_HEAD_INIT(NULL) 0,
2067         "wc.CommittedQueue", /* const char *tp_name;  For printing, in format "<module>.<name>" */
2068         sizeof(CommittedQueueObject), 
2069         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
2070         
2071         /* Methods to implement standard operations */
2072         
2073         committed_queue_dealloc, /*     destructor tp_dealloc;  */
2074         NULL, /*        printfunc tp_print;     */
2075         NULL, /*        getattrfunc tp_getattr; */
2076         NULL, /*        setattrfunc tp_setattr; */
2077         NULL, /*        cmpfunc tp_compare;     */
2078         committed_queue_repr, /*        reprfunc tp_repr;       */
2079         
2080         /* Method suites for standard classes */
2081         
2082         NULL, /*        PyNumberMethods *tp_as_number;  */
2083         NULL, /*        PySequenceMethods *tp_as_sequence;      */
2084         NULL, /*        PyMappingMethods *tp_as_mapping;        */
2085         
2086         /* More standard operations (here for binary compatibility) */
2087         
2088         NULL, /*        hashfunc tp_hash;       */
2089         NULL, /*        ternaryfunc tp_call;    */
2090         NULL, /*        reprfunc tp_str;        */
2091         NULL, /*        getattrofunc tp_getattro;       */
2092         NULL, /*        setattrofunc tp_setattro;       */
2093         
2094         /* Functions to access object as input/output buffer */
2095         NULL, /*        PyBufferProcs *tp_as_buffer;    */
2096         
2097         /* Flags to define presence of optional/expanded features */
2098         0, /*   long tp_flags;  */
2099         
2100         "Committed queue", /*   const char *tp_doc;  Documentation string */
2101         
2102         /* Assigned meaning in release 2.0 */
2103         /* call function for all accessible objects */
2104         NULL, /*        traverseproc tp_traverse;       */
2105         
2106         /* delete references to contained objects */
2107         NULL, /*        inquiry tp_clear;       */
2108         
2109         /* Assigned meaning in release 2.1 */
2110         /* rich comparisons */
2111         NULL, /*        richcmpfunc tp_richcompare;     */
2112         
2113         /* weak reference enabler */
2114         0, /*   Py_ssize_t tp_weaklistoffset;   */
2115         
2116         /* Added in release 2.2 */
2117         /* Iterators */
2118         NULL, /*        getiterfunc tp_iter;    */
2119         NULL, /*        iternextfunc tp_iternext;       */
2120         
2121         /* Attribute descriptor and subclassing stuff */
2122         committed_queue_methods, /*     struct PyMethodDef *tp_methods; */
2123         NULL, /*        struct PyMemberDef *tp_members; */
2124         NULL, /*        struct PyGetSetDef *tp_getset;  */
2125         NULL, /*        struct _typeobject *tp_base;    */
2126         NULL, /*        PyObject *tp_dict;      */
2127         NULL, /*        descrgetfunc tp_descr_get;      */
2128         NULL, /*        descrsetfunc tp_descr_set;      */
2129         0, /*   Py_ssize_t tp_dictoffset;       */
2130         NULL, /*        initproc tp_init;       */
2131         NULL, /*        allocfunc tp_alloc;     */
2132         committed_queue_init, /*        newfunc tp_new; */
2133 };
2134
2135 /** 
2136  * Determine the revision status of a specified working copy.
2137  *
2138  * :return: Tuple with minimum and maximum revnums found, whether the 
2139  * working copy was switched and whether it was modified.
2140  */
2141 static PyObject *revision_status(PyObject *self, PyObject *args, PyObject *kwargs)
2142 {
2143         char *kwnames[] = { "wc_path", "trail_url", "committed", "cancel_func", NULL };
2144         char *wc_path, *trail_url=NULL;
2145         bool committed=false;
2146         PyObject *cancel_func=Py_None, *ret;
2147          svn_wc_revision_status_t *revstatus;
2148         apr_pool_t *temp_pool;
2149
2150         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zbO", kwnames, &wc_path,
2151                                                                          &trail_url, &committed, &cancel_func))
2152                 return NULL;
2153
2154         temp_pool = Pool(NULL);
2155         if (temp_pool == NULL)
2156                 return NULL;
2157         RUN_SVN_WITH_POOL(temp_pool, 
2158                         svn_wc_revision_status(
2159                                 &revstatus, 
2160                                 svn_path_canonicalize(wc_path, temp_pool),
2161                                 trail_url,
2162                                  committed, py_cancel_func, cancel_func, temp_pool));
2163         ret = Py_BuildValue("(llbb)", revstatus->min_rev, revstatus->max_rev, 
2164                         revstatus->switched, revstatus->modified);
2165         apr_pool_destroy(temp_pool);
2166         return ret;
2167 }
2168
2169 static PyObject *is_normal_prop(PyObject *self, PyObject *args)
2170 {
2171         char *name;
2172
2173         if (!PyArg_ParseTuple(args, "s", &name))
2174                 return NULL;
2175
2176         return PyBool_FromLong(svn_wc_is_normal_prop(name));
2177 }
2178
2179 static PyObject *is_adm_dir(PyObject *self, PyObject *args)
2180 {
2181         char *name;
2182         apr_pool_t *pool;
2183         svn_boolean_t ret;
2184
2185         if (!PyArg_ParseTuple(args, "s", &name))
2186                 return NULL;
2187
2188         pool = Pool(NULL);
2189         if (pool == NULL)
2190                 return NULL;
2191
2192         ret = svn_wc_is_adm_dir(name, pool);
2193
2194         apr_pool_destroy(pool);
2195
2196         return PyBool_FromLong(ret);
2197 }
2198
2199 static PyObject *is_wc_prop(PyObject *self, PyObject *args)
2200 {
2201         char *name;
2202
2203         if (!PyArg_ParseTuple(args, "s", &name))
2204                 return NULL;
2205
2206         return PyBool_FromLong(svn_wc_is_wc_prop(name));
2207 }
2208
2209 static PyObject *is_entry_prop(PyObject *self, PyObject *args)
2210 {
2211         char *name;
2212
2213         if (!PyArg_ParseTuple(args, "s", &name))
2214                 return NULL;
2215
2216         return PyBool_FromLong(svn_wc_is_entry_prop(name));
2217 }
2218
2219 static PyObject *get_adm_dir(PyObject *self)
2220 {
2221         apr_pool_t *pool;
2222         PyObject *ret;
2223         const char *dir;
2224         pool = Pool(NULL);
2225         if (pool == NULL)
2226                 return NULL;
2227         dir = svn_wc_get_adm_dir(pool);
2228         ret = PyString_FromString(dir);
2229         apr_pool_destroy(pool);
2230         return ret;
2231 }
2232
2233 static PyObject *set_adm_dir(PyObject *self, PyObject *args)
2234 {
2235         apr_pool_t *temp_pool;
2236         char *name;
2237
2238         if (!PyArg_ParseTuple(args, "s", &name))
2239                 return NULL;
2240
2241         temp_pool = Pool(NULL);
2242         if (temp_pool == NULL)
2243                 return NULL;
2244         RUN_SVN_WITH_POOL(temp_pool, svn_wc_set_adm_dir(name, temp_pool));
2245         apr_pool_destroy(temp_pool);
2246         Py_RETURN_NONE;
2247 }
2248
2249 static PyObject *get_pristine_copy_path(PyObject *self, PyObject *args)
2250 {
2251         apr_pool_t *pool;
2252         const char *pristine_path;
2253         char *path;
2254         PyObject *ret;
2255
2256         if (!PyArg_ParseTuple(args, "s", &path))
2257                 return NULL;
2258
2259         pool = Pool(NULL);
2260         if (pool == NULL)
2261                 return NULL;
2262 #if PY_VERSION_HEX < 0x02050000
2263         PyErr_Warn(PyExc_DeprecationWarning, "get_pristine_copy_path is deprecated. Use get_pristine_contents instead.");
2264 #else
2265         PyErr_WarnEx(PyExc_DeprecationWarning, "get_pristine_copy_path is deprecated. Use get_pristine_contents instead.", 2);
2266 #endif
2267         RUN_SVN_WITH_POOL(pool,
2268                   svn_wc_get_pristine_copy_path(svn_path_canonicalize(path, pool),
2269                                                                                 &pristine_path, pool));
2270         ret = PyString_FromString(pristine_path);
2271         apr_pool_destroy(pool);
2272         return ret;
2273 }
2274
2275 static PyObject *get_pristine_contents(PyObject *self, PyObject *args)
2276 {
2277         char *path;
2278         apr_pool_t *temp_pool;
2279 #if ONLY_SINCE_SVN(1, 6)
2280         apr_pool_t *stream_pool;
2281         StreamObject *ret;
2282         svn_stream_t *stream;
2283 #else
2284         PyObject *ret;
2285         const char *pristine_path;
2286 #endif
2287
2288         if (!PyArg_ParseTuple(args, "s", &path))
2289                 return NULL;
2290
2291 #if ONLY_SINCE_SVN(1, 6)
2292         stream_pool = Pool(NULL);
2293         if (stream_pool == NULL)
2294                 return NULL;
2295
2296         temp_pool = Pool(stream_pool);
2297         if (temp_pool == NULL) {
2298                 apr_pool_destroy(stream_pool);
2299                 return NULL;
2300         }
2301
2302         RUN_SVN_WITH_POOL(stream_pool, svn_wc_get_pristine_contents(&stream, svn_path_canonicalize(path, temp_pool), stream_pool, temp_pool));
2303         apr_pool_destroy(temp_pool);
2304
2305         if (stream == NULL) {
2306                 apr_pool_destroy(stream_pool);
2307                 Py_RETURN_NONE;
2308         }
2309
2310         ret = PyObject_New(StreamObject, &Stream_Type);
2311         if (ret == NULL)
2312                 return NULL;
2313
2314         ret->pool = stream_pool;
2315         ret->closed = FALSE;
2316         ret->stream = stream;
2317
2318         return (PyObject *)ret;
2319 #else
2320         temp_pool = Pool(NULL);
2321         if (temp_pool == NULL)
2322                 return NULL;
2323         RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_pristine_copy_path(svn_path_canonicalize(path, temp_pool), &pristine_path, temp_pool));
2324         ret = PyFile_FromString((char *)pristine_path, "rb");
2325         apr_pool_destroy(temp_pool);
2326         return ret;
2327 #endif
2328 }
2329
2330 static PyObject *ensure_adm(PyObject *self, PyObject *args, PyObject *kwargs)
2331 {
2332         char *path, *uuid, *url;
2333         char *repos=NULL; 
2334         svn_revnum_t rev=-1;
2335         apr_pool_t *pool;
2336         char *kwnames[] = { "path", "uuid", "url", "repos", "rev", "depth", NULL };
2337         svn_depth_t depth = svn_depth_infinity;
2338
2339         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sss|sli", kwnames, 
2340                                                                          &path, &uuid, &url, &repos, &rev, &depth))
2341                 return NULL;
2342
2343         pool = Pool(NULL);
2344         if (pool == NULL)
2345                 return NULL;
2346 #if ONLY_SINCE_SVN(1, 5)
2347         RUN_SVN_WITH_POOL(pool, 
2348                                           svn_wc_ensure_adm3(svn_path_canonicalize(path, pool),
2349                                                                                  uuid, url, repos, rev, depth, pool));
2350 #else
2351         if (depth != svn_depth_infinity) {
2352                 PyErr_SetString(PyExc_NotImplementedError, 
2353                                                 "depth != infinity not supported with svn < 1.5");
2354                 apr_pool_destroy(pool);
2355                 return NULL;
2356         }
2357         RUN_SVN_WITH_POOL(pool, 
2358                                           svn_wc_ensure_adm2(svn_path_canonicalize(path, pool),
2359                                                                                  uuid, url, repos, rev, pool));
2360 #endif
2361         apr_pool_destroy(pool);
2362         Py_RETURN_NONE;
2363 }
2364
2365 static PyObject *check_wc(PyObject *self, PyObject *args)
2366 {
2367         char *path;
2368         apr_pool_t *pool;
2369         int wc_format;
2370
2371         if (!PyArg_ParseTuple(args, "s", &path))
2372                 return NULL;
2373
2374         pool = Pool(NULL);
2375         if (pool == NULL)
2376                 return NULL;
2377         RUN_SVN_WITH_POOL(pool, svn_wc_check_wc(svn_path_canonicalize(path, pool), &wc_format, pool));
2378         apr_pool_destroy(pool);
2379         return PyLong_FromLong(wc_format);
2380 }
2381
2382 static PyObject *cleanup_wc(PyObject *self, PyObject *args, PyObject *kwargs)
2383 {
2384         PyObject *cancel_func = Py_None;
2385         char *path;
2386         char *diff3_cmd = NULL;
2387         char *kwnames[] = { "path", "diff3_cmd", "cancel_func", NULL };
2388         apr_pool_t *temp_pool;
2389
2390         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zO", kwnames, 
2391                                                                          &path, &diff3_cmd, &cancel_func)) 
2392                 return NULL;
2393
2394         temp_pool = Pool(NULL);
2395         if (temp_pool == NULL)
2396                 return NULL;
2397         RUN_SVN_WITH_POOL(temp_pool, 
2398                                 svn_wc_cleanup2(path, diff3_cmd, py_cancel_func, cancel_func,
2399                                                                 temp_pool));
2400         apr_pool_destroy(temp_pool);
2401
2402         Py_RETURN_NONE;
2403 }
2404
2405 static PyObject *match_ignore_list(PyObject *self, PyObject *args)
2406 {
2407 #if ONLY_SINCE_SVN(1, 5)
2408         char *str;
2409         PyObject *py_list;
2410         apr_array_header_t *list;
2411         apr_pool_t *temp_pool;
2412         svn_boolean_t ret;
2413
2414         if (!PyArg_ParseTuple(args, "sO", &str, &py_list))
2415                 return NULL;
2416
2417         temp_pool = Pool(NULL);
2418
2419         if (!string_list_to_apr_array(temp_pool, py_list, &list)) {
2420                 apr_pool_destroy(temp_pool);
2421                 return NULL;
2422         }
2423
2424         ret = svn_wc_match_ignore_list(str, list, temp_pool);
2425
2426         apr_pool_destroy(temp_pool);
2427
2428         return PyBool_FromLong(ret);
2429 #else
2430         PyErr_SetNone(PyExc_NotImplementedError);
2431         return NULL;
2432 #endif
2433 }
2434
2435 static PyMethodDef wc_methods[] = {
2436         { "check_wc", check_wc, METH_VARARGS, "check_wc(path) -> version\n"
2437                 "Check whether path contains a Subversion working copy\n"
2438                 "return the workdir version"},
2439         { "cleanup", (PyCFunction)cleanup_wc, METH_VARARGS|METH_KEYWORDS, "cleanup(path, diff3_cmd=None, cancel_func=None)\n" },
2440         { "ensure_adm", (PyCFunction)ensure_adm, METH_KEYWORDS|METH_VARARGS, 
2441                 "ensure_adm(path, uuid, url, repos=None, rev=None)" },
2442         { "get_adm_dir", (PyCFunction)get_adm_dir, METH_NOARGS, 
2443                 "get_adm_dir() -> name" },
2444         { "set_adm_dir", (PyCFunction)set_adm_dir, METH_VARARGS,
2445                 "set_adm_dir(name)" },
2446         { "get_pristine_copy_path", get_pristine_copy_path, METH_VARARGS, 
2447                 "get_pristine_copy_path(path) -> path" },
2448         { "get_pristine_contents", get_pristine_contents, METH_VARARGS,
2449                 "get_pristine_contents(path) -> stream" },
2450         { "is_adm_dir", is_adm_dir, METH_VARARGS, 
2451                 "is_adm_dir(name) -> bool" },
2452         { "is_normal_prop", is_normal_prop, METH_VARARGS, 
2453                 "is_normal_prop(name) -> bool" },
2454         { "is_entry_prop", is_entry_prop, METH_VARARGS, 
2455                 "is_entry_prop(name) -> bool" },
2456         { "is_wc_prop", is_wc_prop, METH_VARARGS, 
2457                 "is_wc_prop(name) -> bool" },
2458         { "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)" },
2459         { "version", (PyCFunction)version, METH_NOARGS,
2460                 "version() -> (major, minor, patch, tag)\n\n"
2461                 "Version of libsvn_wc currently used."
2462         },
2463         { "api_version", (PyCFunction)api_version, METH_NOARGS,
2464                 "api_version() -> (major, minor, patch, tag)\n\n"
2465                 "Version of libsvn_wc Subvertpy was compiled against."
2466         },
2467         { "match_ignore_list", (PyCFunction)match_ignore_list, METH_VARARGS,
2468                 "match_ignore_list(str, patterns) -> bool" },
2469         { "get_actual_target", (PyCFunction)get_actual_target, METH_VARARGS,
2470                 "get_actual_target(path) -> (anchor, target)" },
2471         { NULL, }
2472 };
2473
2474 void initwc(void)
2475 {
2476         PyObject *mod;
2477
2478         if (PyType_Ready(&Entry_Type) < 0)
2479                 return;
2480
2481         if (PyType_Ready(&Adm_Type) < 0)
2482                 return;
2483
2484         if (PyType_Ready(&Editor_Type) < 0)
2485                 return;
2486
2487         if (PyType_Ready(&FileEditor_Type) < 0)
2488                 return;
2489
2490         if (PyType_Ready(&DirectoryEditor_Type) < 0)
2491                 return;
2492
2493         if (PyType_Ready(&TxDeltaWindowHandler_Type) < 0)
2494                 return;
2495
2496         if (PyType_Ready(&Stream_Type) < 0)
2497                 return;
2498
2499         if (PyType_Ready(&CommittedQueue_Type) < 0)
2500                 return;
2501
2502         initeditor();
2503
2504         apr_initialize();
2505
2506         mod = Py_InitModule3("wc", wc_methods, "Working Copies");
2507         if (mod == NULL)
2508                 return;
2509
2510         PyModule_AddIntConstant(mod, "SCHEDULE_NORMAL", 0);
2511         PyModule_AddIntConstant(mod, "SCHEDULE_ADD", 1);
2512         PyModule_AddIntConstant(mod, "SCHEDULE_DELETE", 2);
2513         PyModule_AddIntConstant(mod, "SCHEDULE_REPLACE", 3);
2514
2515 #if ONLY_SINCE_SVN(1, 5)
2516         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_POSTPONE",
2517                                                         svn_wc_conflict_choose_postpone);
2518         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_BASE",
2519                                                         svn_wc_conflict_choose_base);
2520         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_FULL",
2521                                                         svn_wc_conflict_choose_theirs_full);
2522         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_FULL",
2523                                                         svn_wc_conflict_choose_mine_full);
2524         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_CONFLICT",
2525                                                         svn_wc_conflict_choose_theirs_conflict);
2526         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_CONFLICT",
2527                                                         svn_wc_conflict_choose_mine_conflict);
2528         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MERGED",
2529                                                         svn_wc_conflict_choose_merged);
2530 #endif
2531
2532         PyModule_AddIntConstant(mod, "STATUS_NONE", svn_wc_status_none);
2533         PyModule_AddIntConstant(mod, "STATUS_UNVERSIONED", svn_wc_status_unversioned);
2534         PyModule_AddIntConstant(mod, "STATUS_NORMAL", svn_wc_status_normal);
2535         PyModule_AddIntConstant(mod, "STATUS_ADDED", svn_wc_status_added);
2536         PyModule_AddIntConstant(mod, "STATUS_MISSING", svn_wc_status_missing);
2537         PyModule_AddIntConstant(mod, "STATUS_DELETED", svn_wc_status_deleted);
2538         PyModule_AddIntConstant(mod, "STATUS_REPLACED", svn_wc_status_replaced);
2539         PyModule_AddIntConstant(mod, "STATUS_MODIFIED", svn_wc_status_modified);
2540         PyModule_AddIntConstant(mod, "STATUS_MERGED", svn_wc_status_merged);
2541         PyModule_AddIntConstant(mod, "STATUS_CONFLICTED", svn_wc_status_conflicted);
2542         PyModule_AddIntConstant(mod, "STATUS_IGNORED", svn_wc_status_ignored);
2543         PyModule_AddIntConstant(mod, "STATUS_OBSTRUCTED", svn_wc_status_obstructed);
2544         PyModule_AddIntConstant(mod, "STATUS_EXTERNAL", svn_wc_status_external);
2545         PyModule_AddIntConstant(mod, "STATUS_INCOMPLETE", svn_wc_status_incomplete);
2546
2547         PyModule_AddIntConstant(mod, "TRANSLATE_FROM_NF", SVN_WC_TRANSLATE_FROM_NF);
2548         PyModule_AddIntConstant(mod, "TRANSLATE_TO_NF", SVN_WC_TRANSLATE_TO_NF);
2549         PyModule_AddIntConstant(mod, "TRANSLATE_FORCE_EOL_REPAIR", SVN_WC_TRANSLATE_FORCE_EOL_REPAIR);
2550         PyModule_AddIntConstant(mod, "TRANSLATE_NO_OUTPUT_CLEANUP", SVN_WC_TRANSLATE_NO_OUTPUT_CLEANUP);
2551         PyModule_AddIntConstant(mod, "TRANSLATE_FORCE_COPY", SVN_WC_TRANSLATE_FORCE_COPY);
2552         PyModule_AddIntConstant(mod, "TRANSLATE_USE_GLOBAL_TMP", SVN_WC_TRANSLATE_USE_GLOBAL_TMP);
2553
2554         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_POSTPONE", svn_wc_conflict_choose_postpone);
2555         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_BASE", svn_wc_conflict_choose_base);
2556         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_FULL", svn_wc_conflict_choose_theirs_full);
2557         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_FULL", svn_wc_conflict_choose_mine_full);
2558         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_THEIRS_CONFLICT", svn_wc_conflict_choose_theirs_conflict);
2559         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MINE_CONFLICT", svn_wc_conflict_choose_mine_conflict);
2560         PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MERGED", svn_wc_conflict_choose_merged);
2561
2562         PyModule_AddObject(mod, "WorkingCopy", (PyObject *)&Adm_Type);
2563         Py_INCREF(&Adm_Type);
2564
2565         PyModule_AddObject(mod, "CommittedQueue", (PyObject *)&CommittedQueue_Type);
2566         Py_INCREF(&CommittedQueue_Type);
2567 }