2 * Copyright © 2008 Jelmer Vernooij <jelmer@jelmer.uk>
3 * -*- coding: utf-8 -*-
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation; either version 2.1 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <apr_general.h>
23 #include <svn_props.h>
24 #include <structmember.h>
33 /* Suppress warnings for this specific file, as it
34 * provides backwards compatibility with svn < 1.7
36 #pragma GCC diagnostic push
37 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
39 static svn_wc_entry_callbacks2_t py_wc_entry_callbacks2;
40 static PyObject *py_entry(const svn_wc_entry_t *entry);
44 svn_wc_adm_access_t *adm;
54 svn_wc_adm_access_t *Adm_GetAdmAccess(PyObject *obj) {
55 AdmObject *adm_obj = (AdmObject *)obj;
59 #define ADM_CHECK_CLOSED(adm_obj) \
60 if (adm_obj->adm == NULL) { \
61 PyErr_SetString(PyExc_RuntimeError, "WorkingCopy instance already closed"); \
65 svn_wc_adm_access_t *PyObject_GetAdmAccess(PyObject *obj)
67 return ((AdmObject *)obj)->adm;
70 static PyObject *adm_init(PyTypeObject *self, PyObject *args, PyObject *kwargs)
72 PyObject *associated, *py_path;
74 bool write_lock=false;
76 svn_wc_adm_access_t *parent_wc;
79 char *kwnames[] = { "associated", "path", "write_lock", "depth", NULL };
81 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bi", kwnames,
82 &associated, &py_path, &write_lock, &depth))
85 ret = PyObject_New(AdmObject, &Adm_Type);
89 ret->pool = Pool(NULL);
90 if (ret->pool == NULL) {
93 if (associated == Py_None) {
96 parent_wc = ((AdmObject *)associated)->adm;
99 path = py_object_to_svn_abspath(py_path, ret->pool);
105 Py_BEGIN_ALLOW_THREADS
106 err = svn_wc_adm_open3(&ret->adm, parent_wc,
108 write_lock, depth, py_cancel_check, NULL,
113 handle_svn_error(err);
114 svn_error_clear(err);
119 return (PyObject *)ret;
122 static PyObject *adm_access_path(PyObject *self)
124 AdmObject *admobj = (AdmObject *)self;
125 ADM_CHECK_CLOSED(admobj);
126 return py_object_from_svn_abspath(svn_wc_adm_access_path(admobj->adm));
129 static PyObject *adm_locked(PyObject *self)
131 AdmObject *admobj = (AdmObject *)self;
132 ADM_CHECK_CLOSED(admobj);
133 return PyBool_FromLong(svn_wc_adm_locked(admobj->adm));
136 static PyObject *adm_prop_get(PyObject *self, PyObject *args)
140 AdmObject *admobj = (AdmObject *)self;
141 const svn_string_t *value;
142 apr_pool_t *temp_pool;
143 PyObject *ret, *py_path;
145 if (!PyArg_ParseTuple(args, "sO", &name, &py_path))
148 ADM_CHECK_CLOSED(admobj);
150 temp_pool = Pool(NULL);
151 if (temp_pool == NULL) {
155 path = py_object_to_svn_abspath(py_path, temp_pool);
157 apr_pool_destroy(temp_pool);
161 RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_get(&value, name, path, admobj->adm, temp_pool));
162 if (value == NULL || value->data == NULL) {
166 ret = PyBytes_FromStringAndSize(value->data, value->len);
168 apr_pool_destroy(temp_pool);
172 static PyObject *adm_prop_set(PyObject *self, PyObject *args)
176 AdmObject *admobj = (AdmObject *)self;
177 bool skip_checks=false;
178 apr_pool_t *temp_pool;
180 svn_string_t *cvalue;
182 PyObject *notify_func = Py_None;
184 if (!PyArg_ParseTuple(args, "sz#O|bO", &name, &value, &vallen, &py_path, &skip_checks,
188 ADM_CHECK_CLOSED(admobj);
190 temp_pool = Pool(NULL);
191 if (temp_pool == NULL) {
195 path = py_object_to_svn_abspath(py_path, temp_pool);
197 apr_pool_destroy(temp_pool);
204 cvalue = svn_string_ncreate(value, vallen, temp_pool);
206 #if ONLY_SINCE_SVN(1, 6)
207 RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_set3(name, cvalue, path, admobj->adm,
208 skip_checks, py_wc_notify_func, (void *)notify_func,
211 RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_set2(name, cvalue, path, admobj->adm,
212 skip_checks, temp_pool));
214 apr_pool_destroy(temp_pool);
219 static PyObject *adm_entries_read(PyObject *self, PyObject *args)
222 AdmObject *admobj = (AdmObject *)self;
223 apr_pool_t *temp_pool;
224 bool show_hidden=false;
225 apr_hash_index_t *idx;
228 svn_wc_entry_t *entry;
229 PyObject *py_entries, *obj;
231 if (!PyArg_ParseTuple(args, "|b", &show_hidden))
234 ADM_CHECK_CLOSED(admobj);
236 temp_pool = Pool(NULL);
237 if (temp_pool == NULL)
239 RUN_SVN_WITH_POOL(temp_pool, svn_wc_entries_read(&entries, admobj->adm,
240 show_hidden, temp_pool));
241 py_entries = PyDict_New();
242 if (py_entries == NULL) {
243 apr_pool_destroy(temp_pool);
246 idx = apr_hash_first(temp_pool, entries);
247 while (idx != NULL) {
248 apr_hash_this(idx, (const void **)&key, &klen, (void **)&entry);
253 obj = py_entry(entry);
255 PyDict_SetItemString(py_entries, key, obj);
257 idx = apr_hash_next(idx);
259 apr_pool_destroy(temp_pool);
263 static PyObject *adm_walk_entries(PyObject *self, PyObject *args)
267 bool show_hidden=false;
268 apr_pool_t *temp_pool;
269 AdmObject *admobj = (AdmObject *)self;
270 svn_depth_t depth = svn_depth_infinity;
273 if (!PyArg_ParseTuple(args, "OO|bi", &py_path, &callbacks, &show_hidden, &depth))
276 ADM_CHECK_CLOSED(admobj);
278 temp_pool = Pool(NULL);
279 if (temp_pool == NULL) {
283 path = py_object_to_svn_abspath(py_path, temp_pool);
285 apr_pool_destroy(temp_pool);
289 #if ONLY_SINCE_SVN(1, 5)
290 RUN_SVN_WITH_POOL(temp_pool, svn_wc_walk_entries3(
292 &py_wc_entry_callbacks2, (void *)callbacks,
293 depth, show_hidden, py_cancel_check, NULL,
296 if (depth != svn_depth_infinity) {
297 PyErr_SetString(PyExc_NotImplementedError,
298 "depth != infinity not supported for svn < 1.5");
299 apr_pool_destroy(temp_pool);
302 RUN_SVN_WITH_POOL(temp_pool, svn_wc_walk_entries2(
304 &py_wc_entry_callbacks, (void *)callbacks,
305 show_hidden, py_cancel_check, NULL,
308 apr_pool_destroy(temp_pool);
313 static PyObject *adm_entry(PyObject *self, PyObject *args)
317 bool show_hidden=false;
318 apr_pool_t *temp_pool;
319 AdmObject *admobj = (AdmObject *)self;
320 const svn_wc_entry_t *entry;
323 if (!PyArg_ParseTuple(args, "O|b", &py_path, &show_hidden))
326 ADM_CHECK_CLOSED(admobj);
328 temp_pool = Pool(NULL);
329 if (temp_pool == NULL) {
333 path = py_object_to_svn_abspath(py_path, temp_pool);
335 apr_pool_destroy(temp_pool);
339 RUN_SVN_WITH_POOL(temp_pool, svn_wc_entry(&entry, path, admobj->adm, show_hidden, temp_pool));
342 PyErr_Format(PyExc_KeyError, "No such entry '%s'", path);
345 ret = py_entry(entry);
348 apr_pool_destroy(temp_pool);
352 static PyObject *adm_get_prop_diffs(PyObject *self, PyObject *args)
355 apr_pool_t *temp_pool;
356 apr_array_header_t *propchanges;
357 apr_hash_t *original_props;
359 AdmObject *admobj = (AdmObject *)self;
360 PyObject *py_propchanges, *py_orig_props;
362 if (!PyArg_ParseTuple(args, "O", &py_path))
365 ADM_CHECK_CLOSED(admobj);
367 temp_pool = Pool(NULL);
368 if (temp_pool == NULL) {
372 path = py_object_to_svn_abspath(py_path, temp_pool);
374 apr_pool_destroy(temp_pool);
377 RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_prop_diffs(&propchanges, &original_props,
378 path, admobj->adm, temp_pool));
379 py_propchanges = propchanges_to_list(propchanges);
380 if (py_propchanges == NULL) {
381 apr_pool_destroy(temp_pool);
384 py_orig_props = prop_hash_to_dict(original_props);
385 apr_pool_destroy(temp_pool);
386 if (py_orig_props == NULL) {
387 Py_DECREF(py_propchanges);
390 return Py_BuildValue("(NN)", py_propchanges, py_orig_props);
393 static PyObject *adm_add(PyObject *self, PyObject *args, PyObject *kwargs)
396 const char *copyfrom_url = NULL;
397 svn_revnum_t copyfrom_rev=-1;
398 char *kwnames[] = { "path", "copyfrom_url", "copyfrom_rev", "notify_func", "depth", NULL };
399 PyObject *notify_func=Py_None, *py_path;
400 AdmObject *admobj = (AdmObject *)self;
401 apr_pool_t *temp_pool;
402 svn_depth_t depth = svn_depth_infinity;
403 PyObject *py_copyfrom_url = Py_None;
405 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OlOi", kwnames, &py_path,
406 &py_copyfrom_url, ©from_rev, ¬ify_func, &depth))
409 ADM_CHECK_CLOSED(admobj);
411 temp_pool = Pool(NULL);
412 if (temp_pool == NULL) {
416 path = py_object_to_svn_abspath(py_path, temp_pool);
418 apr_pool_destroy(temp_pool);
422 if (py_copyfrom_url != Py_None) {
423 copyfrom_url = py_object_to_svn_uri(py_copyfrom_url, temp_pool);
424 if (copyfrom_url == NULL) {
425 apr_pool_destroy(temp_pool);
432 #if ONLY_SINCE_SVN(1, 6)
433 RUN_SVN_WITH_POOL(temp_pool, svn_wc_add3(
436 copyfrom_rev, py_cancel_check, NULL,
441 if (depth != svn_depth_infinity) {
442 PyErr_SetString(PyExc_NotImplementedError, "depth != infinity not supported on svn < 1.6");
443 apr_pool_destroy(temp_pool);
446 RUN_SVN_WITH_POOL(temp_pool, svn_wc_add2(
447 path, admobj->adm, copyfrom_url,
448 copyfrom_rev, py_cancel_check,
454 apr_pool_destroy(temp_pool);
459 static PyObject *adm_copy(PyObject *self, PyObject *args)
461 AdmObject *admobj = (AdmObject *)self;
463 PyObject *notify_func=Py_None;
464 apr_pool_t *temp_pool;
466 if (!PyArg_ParseTuple(args, "ss|O", &src, &dst, ¬ify_func))
469 ADM_CHECK_CLOSED(admobj);
471 temp_pool = Pool(NULL);
472 if (temp_pool == NULL)
474 RUN_SVN_WITH_POOL(temp_pool, svn_wc_copy2(src, admobj->adm, dst,
475 py_cancel_check, NULL,
476 py_wc_notify_func, (void *)notify_func,
478 apr_pool_destroy(temp_pool);
483 static PyObject *adm_delete(PyObject *self, PyObject *args, PyObject *kwargs)
485 AdmObject *admobj = (AdmObject *)self;
486 apr_pool_t *temp_pool;
487 char *kwnames[] = { "path", "notify_func", "keep_local",
491 PyObject *notify_func=Py_None;
492 bool keep_local = false;
494 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Ob:delete", kwnames,
495 &py_path, ¬ify_func, &keep_local))
498 ADM_CHECK_CLOSED(admobj);
500 temp_pool = Pool(NULL);
501 if (temp_pool == NULL) {
505 path = py_object_to_svn_abspath(py_path, temp_pool);
507 apr_pool_destroy(temp_pool);
511 #if ONLY_SINCE_SVN(1, 5)
512 RUN_SVN_WITH_POOL(temp_pool, svn_wc_delete3(path, admobj->adm,
513 py_cancel_check, NULL,
514 py_wc_notify_func, (void *)notify_func,
519 PyErr_SetString(PyExc_NotImplementedError,
520 "keep_local not supported on Subversion < 1.5");
524 RUN_SVN_WITH_POOL(temp_pool, svn_wc_delete2(path, admobj->adm,
525 py_cancel_check, NULL,
526 py_wc_notify_func, (void *)notify_func,
529 apr_pool_destroy(temp_pool);
534 static PyObject *adm_crawl_revisions(PyObject *self, PyObject *args, PyObject *kwargs)
538 bool restore_files=true, recurse=true, use_commit_times=true;
539 PyObject *notify_func=Py_None;
540 apr_pool_t *temp_pool;
541 AdmObject *admobj = (AdmObject *)self;
542 svn_wc_traversal_info_t *traversal_info;
543 bool depth_compatibility_trick = false;
544 bool honor_depth_exclude = false;
545 char *kwnames[] = { "path", "reporter", "restore_files", "recurse",
546 "use_commit_times", "notify_func", "depth_compatibility_trick",
547 "honor_depth_exclude,", NULL };
550 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bbbObb", kwnames, &py_path,
551 &reporter, &restore_files, &recurse, &use_commit_times,
552 ¬ify_func, &depth_compatibility_trick, &honor_depth_exclude))
555 ADM_CHECK_CLOSED(admobj);
557 temp_pool = Pool(NULL);
558 if (temp_pool == NULL) {
562 path = py_object_to_svn_abspath(py_path, temp_pool);
564 apr_pool_destroy(temp_pool);
567 traversal_info = svn_wc_init_traversal_info(temp_pool);
568 #if ONLY_SINCE_SVN(1, 6)
569 RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions4(path, admobj->adm,
570 &py_ra_reporter3, (void *)reporter,
571 restore_files, recurse?svn_depth_infinity:svn_depth_files,
572 honor_depth_exclude?TRUE:FALSE,
573 depth_compatibility_trick?TRUE:FALSE, use_commit_times,
574 py_wc_notify_func, (void *)notify_func,
575 traversal_info, temp_pool));
576 #elif ONLY_SINCE_SVN(1, 5)
577 RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions3(path, admobj->adm,
578 &py_ra_reporter3, (void *)reporter,
579 restore_files, recurse?svn_depth_infinity:svn_depth_files,
580 depth_compatibility_trick, use_commit_times,
581 py_wc_notify_func, (void *)notify_func,
582 traversal_info, temp_pool));
584 RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions2(path, admobj->adm,
585 &py_ra_reporter2, (void *)reporter,
586 restore_files, recurse, use_commit_times,
587 py_wc_notify_func, (void *)notify_func,
588 traversal_info, temp_pool));
590 apr_pool_destroy(temp_pool);
595 static void wc_done_handler(void *self)
597 AdmObject *admobj = (AdmObject *)self;
602 static PyObject *adm_get_switch_editor(PyObject *self, PyObject *args, PyObject *kwargs)
605 bool use_commit_times=true;
606 PyObject * notify_func=Py_None;
607 char *diff3_cmd=NULL;
608 const svn_delta_editor_t *editor;
609 AdmObject *admobj = (AdmObject *)self;
612 svn_revnum_t *latest_revnum;
614 bool allow_unver_obstructions = false;
615 bool depth_is_sticky = false;
616 int depth = svn_depth_infinity;
617 const char *switch_url;
618 PyObject *py_target, *py_switch_url;
620 "target", "switch_url", "use_commit_times", "depth", "notify_func",
621 "diff3_cmd", "depth_is_sticky", "allow_unver_obstructions", NULL };
623 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|biOzbb", kwnames,
624 &py_target, &py_switch_url, &use_commit_times,
625 &depth, ¬ify_func, &diff3_cmd,
627 &allow_unver_obstructions))
630 ADM_CHECK_CLOSED(admobj);
636 target = py_object_to_svn_string(py_target, pool);
637 if (target == NULL) {
638 apr_pool_destroy(pool);
642 switch_url = py_object_to_svn_uri(py_switch_url, pool);
643 if (switch_url == NULL) {
644 apr_pool_destroy(pool);
648 latest_revnum = (svn_revnum_t *)apr_palloc(pool, sizeof(svn_revnum_t));
649 Py_BEGIN_ALLOW_THREADS
650 #if ONLY_SINCE_SVN(1, 5)
651 /* FIXME: Support fetch_func */
652 /* FIXME: Support conflict func */
653 err = svn_wc_get_switch_editor3(latest_revnum, admobj->adm, target, switch_url,
654 use_commit_times, depth,
655 depth_is_sticky?TRUE:FALSE, allow_unver_obstructions?TRUE:FALSE,
656 py_wc_notify_func, (void *)notify_func,
657 py_cancel_check, NULL,
658 NULL, NULL, diff3_cmd, NULL, &editor,
659 &edit_baton, NULL, pool);
661 if (allow_unver_obstructions) {
662 PyErr_SetString(PyExc_NotImplementedError,
663 "allow_unver_obstructions is not supported in svn < 1.5");
664 apr_pool_destroy(pool);
665 PyEval_RestoreThread(_save);
668 if (depth_is_sticky) {
669 PyErr_SetString(PyExc_NotImplementedError,
670 "depth_is_sticky is not supported in svn < 1.5");
671 apr_pool_destroy(pool);
672 PyEval_RestoreThread(_save);
675 err = svn_wc_get_switch_editor2(latest_revnum, admobj->adm, target, switch_url,
676 use_commit_times, recurse, py_wc_notify_func, (void *)notify_func,
677 py_cancel_check, NULL, diff3_cmd, &editor, &edit_baton,
682 handle_svn_error(err);
683 svn_error_clear(err);
684 apr_pool_destroy(pool);
688 return new_editor_object(NULL, editor, edit_baton, pool, &Editor_Type,
689 wc_done_handler, admobj, NULL);
692 static PyObject *adm_get_update_editor(PyObject *self, PyObject *args, PyObject *kwargs)
695 bool use_commit_times=true;
696 PyObject * notify_func=Py_None;
697 char *diff3_cmd=NULL;
698 const svn_delta_editor_t *editor;
699 AdmObject *admobj = (AdmObject *)self;
702 svn_revnum_t *latest_revnum;
704 bool allow_unver_obstructions = false;
705 bool depth_is_sticky = false;
706 int depth = svn_depth_infinity;
709 "target", "use_commit_times", "depth", "notify_func",
710 "diff3_cmd", "depth_is_sticky", "allow_unver_obstructions", NULL };
712 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|biOzbb", kwnames,
713 &py_target, &use_commit_times,
714 &depth, ¬ify_func, &diff3_cmd,
716 &allow_unver_obstructions))
719 ADM_CHECK_CLOSED(admobj);
725 target = py_object_to_svn_string(py_target, pool);
726 if (target == NULL) {
727 apr_pool_destroy(pool);
730 latest_revnum = (svn_revnum_t *)apr_palloc(pool, sizeof(svn_revnum_t));
731 Py_BEGIN_ALLOW_THREADS
732 #if ONLY_SINCE_SVN(1, 5)
733 /* FIXME: Support fetch_func */
734 /* FIXME: Support conflict func */
735 err = svn_wc_get_update_editor3(latest_revnum, admobj->adm, target,
736 use_commit_times, depth,
737 depth_is_sticky?TRUE:FALSE, allow_unver_obstructions?TRUE:FALSE,
738 py_wc_notify_func, (void *)notify_func,
739 py_cancel_check, NULL,
740 NULL, NULL, NULL, NULL,
741 diff3_cmd, NULL, &editor, &edit_baton,
744 if (allow_unver_obstructions) {
745 PyErr_SetString(PyExc_NotImplementedError,
746 "allow_unver_obstructions is not supported in svn < 1.5");
747 apr_pool_destroy(pool);
748 PyEval_RestoreThread(_save);
751 if (depth_is_sticky) {
752 PyErr_SetString(PyExc_NotImplementedError,
753 "depth_is_sticky is not supported in svn < 1.5");
754 apr_pool_destroy(pool);
755 PyEval_RestoreThread(_save);
758 err = svn_wc_get_update_editor2(latest_revnum, admobj->adm, target,
759 use_commit_times, recurse, py_wc_notify_func, (void *)notify_func,
760 py_cancel_check, NULL, diff3_cmd, &editor, &edit_baton,
765 handle_svn_error(err);
766 svn_error_clear(err);
767 apr_pool_destroy(pool);
771 return new_editor_object(NULL, editor, edit_baton, pool, &Editor_Type,
772 wc_done_handler, admobj, NULL);
775 static PyObject *adm_has_binary_prop(PyObject *self, PyObject *args)
778 svn_boolean_t binary;
779 AdmObject *admobj = (AdmObject *)self;
780 apr_pool_t *temp_pool;
783 if (!PyArg_ParseTuple(args, "O", &py_path))
786 ADM_CHECK_CLOSED(admobj);
788 temp_pool = Pool(NULL);
789 if (temp_pool == NULL) {
793 path = py_object_to_svn_abspath(py_path, temp_pool);
795 apr_pool_destroy(temp_pool);
799 RUN_SVN_WITH_POOL(temp_pool, svn_wc_has_binary_prop(&binary, path, admobj->adm, temp_pool));
801 apr_pool_destroy(temp_pool);
803 return PyBool_FromLong(binary);
806 static PyObject *adm_process_committed(PyObject *self, PyObject *args, PyObject *kwargs)
809 char *rev_date = NULL, *rev_author = NULL;
810 bool recurse, remove_lock = false;
811 unsigned char *digest = NULL;
812 svn_revnum_t new_revnum;
813 PyObject *py_wcprop_changes = Py_None, *py_path;
814 apr_array_header_t *wcprop_changes = NULL;
815 AdmObject *admobj = (AdmObject *)self;
816 apr_pool_t *temp_pool;
818 bool remove_changelist = false;
819 char *kwnames[] = { "path", "recurse", "new_revnum", "rev_date", "rev_author",
820 "wcprop_changes", "remove_lock", "digest", "remove_changelist", NULL };
822 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oblzz|Obz#b", kwnames,
823 &py_path, &recurse, &new_revnum, &rev_date,
824 &rev_author, &py_wcprop_changes,
825 &remove_lock, &digest, &digest_len, &remove_changelist))
828 PyErr_WarnEx(PyExc_DeprecationWarning, "process_committed is deprecated. Use process_committed_queue instead.", 2);
830 ADM_CHECK_CLOSED(admobj);
832 temp_pool = Pool(NULL);
833 if (temp_pool == NULL) {
837 path = py_object_to_svn_abspath(py_path, temp_pool);
839 apr_pool_destroy(temp_pool);
843 if (!py_dict_to_wcprop_changes(py_wcprop_changes, temp_pool, &wcprop_changes)) {
844 apr_pool_destroy(temp_pool);
848 #if ONLY_SINCE_SVN(1, 6)
849 RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed4(
850 path, admobj->adm, recurse, new_revnum,
851 rev_date, rev_author, wcprop_changes,
852 remove_lock, remove_changelist?TRUE:FALSE, digest, temp_pool));
854 if (remove_changelist) {
855 PyErr_SetString(PyExc_NotImplementedError, "remove_changelist only supported in svn < 1.6");
856 apr_pool_destroy(temp_pool);
859 RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(path, admobj->adm, recurse, new_revnum,
860 rev_date, rev_author, wcprop_changes,
861 remove_lock, digest, temp_pool));
864 apr_pool_destroy(temp_pool);
869 static PyObject *adm_close(PyObject *self)
871 AdmObject *admobj = (AdmObject *)self;
872 if (admobj->adm != NULL) {
873 #if ONLY_SINCE_SVN(1, 6)
874 apr_pool_t *temp_pool = Pool(NULL);
875 Py_BEGIN_ALLOW_THREADS
876 svn_wc_adm_close2(admobj->adm, temp_pool);
877 apr_pool_destroy(temp_pool);
879 Py_BEGIN_ALLOW_THREADS
880 svn_wc_adm_close(admobj->adm);
889 static void adm_dealloc(PyObject *self)
891 apr_pool_destroy(((AdmObject *)self)->pool);
895 static PyObject *adm_repr(PyObject *self)
897 AdmObject *admobj = (AdmObject *)self;
899 if (admobj->adm == NULL) {
900 return PyRepr_FromFormat("<wc.WorkingCopy (closed) at 0x%p>", admobj);
902 return PyRepr_FromFormat("<wc.WorkingCopy at '%s'>",
903 svn_wc_adm_access_path(admobj->adm));
907 static PyObject *adm_remove_lock(PyObject *self, PyObject *args)
911 AdmObject *admobj = (AdmObject *)self;
912 apr_pool_t *temp_pool;
914 if (!PyArg_ParseTuple(args, "O", &py_path))
917 ADM_CHECK_CLOSED(admobj);
919 temp_pool = Pool(NULL);
920 if (temp_pool == NULL) {
924 path = py_object_to_svn_abspath(py_path, temp_pool);
926 apr_pool_destroy(temp_pool);
930 RUN_SVN_WITH_POOL(temp_pool, svn_wc_remove_lock(path, admobj->adm, temp_pool))
932 apr_pool_destroy(temp_pool);
937 static PyObject *get_ancestry(PyObject *self, PyObject *args)
942 apr_pool_t *temp_pool;
944 AdmObject *admobj = (AdmObject *)self;
946 if (!PyArg_ParseTuple(args, "O", &py_path))
949 ADM_CHECK_CLOSED(admobj);
951 temp_pool = Pool(NULL);
952 if (temp_pool == NULL) {
956 path = py_object_to_svn_abspath(py_path, temp_pool);
958 apr_pool_destroy(temp_pool);
962 RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_ancestry(&url, &rev, path, admobj->adm, temp_pool));
964 apr_pool_destroy(temp_pool);
966 return Py_BuildValue("(si)", url, rev);
969 static PyObject *maybe_set_repos_root(PyObject *self, PyObject *args)
972 apr_pool_t *temp_pool;
973 AdmObject *admobj = (AdmObject *)self;
975 if (!PyArg_ParseTuple(args, "ss", &path, &repos))
978 ADM_CHECK_CLOSED(admobj);
980 temp_pool = Pool(NULL);
981 if (temp_pool == NULL)
984 RUN_SVN_WITH_POOL(temp_pool, svn_wc_maybe_set_repos_root(admobj->adm, path, repos, temp_pool));
989 static PyObject *add_repos_file(PyObject *self, PyObject *args, PyObject *kwargs)
991 char *kwnames[] = { "dst_path", "new_base_contents", "new_contents",
992 "new_base_props", "new_props", "copyfrom_url", "copyfrom_rev",
994 AdmObject *admobj = (AdmObject *)self;
995 PyObject *py_dst_path;
996 char *copyfrom_url = NULL;
997 svn_revnum_t copyfrom_rev = -1;
998 PyObject *py_new_base_contents, *py_new_contents, *py_new_base_props,
999 *py_new_props, *notify = Py_None;
1000 #if ONLY_SINCE_SVN(1, 6)
1001 apr_pool_t *temp_pool;
1002 const char *dst_path;
1003 svn_stream_t *new_contents, *new_base_contents;
1004 apr_hash_t *new_props, *new_base_props;
1007 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOOOO|zlO", kwnames,
1008 &py_dst_path, &py_new_base_contents, &py_new_contents, &py_new_base_props,
1009 &py_new_props, ©from_url, ©from_rev, ¬ify))
1012 ADM_CHECK_CLOSED(admobj);
1014 #if ONLY_SINCE_SVN(1, 6)
1015 temp_pool = Pool(NULL);
1016 if (temp_pool == NULL)
1019 new_base_props = prop_dict_to_hash(temp_pool, py_new_base_props);
1021 new_props = prop_dict_to_hash(temp_pool, py_new_props);
1023 new_base_contents = new_py_stream(temp_pool, py_new_base_contents);
1025 new_contents = new_py_stream(temp_pool, py_new_contents);
1027 dst_path = py_object_to_svn_abspath(py_dst_path, temp_pool);
1029 RUN_SVN_WITH_POOL(temp_pool, svn_wc_add_repos_file3(dst_path, admobj->adm,
1034 copyfrom_url, copyfrom_rev,
1035 py_cancel_check, NULL,
1036 py_wc_notify_func, notify, temp_pool));
1038 apr_pool_destroy(temp_pool);
1043 PyErr_SetString(PyExc_NotImplementedError,
1044 "add_repos_file3 not supported on svn < 1.6");
1049 static PyObject *mark_missing_deleted(PyObject *self, PyObject *args)
1052 AdmObject *admobj = (AdmObject *)self;
1053 apr_pool_t *temp_pool;
1056 if (!PyArg_ParseTuple(args, "O", &py_path))
1059 ADM_CHECK_CLOSED(admobj);
1061 temp_pool = Pool(NULL);
1062 if (temp_pool == NULL) {
1066 path = py_object_to_svn_abspath(py_path, temp_pool);
1068 apr_pool_destroy(temp_pool);
1072 RUN_SVN_WITH_POOL(temp_pool, svn_wc_mark_missing_deleted(path, admobj->adm, temp_pool));
1074 apr_pool_destroy(temp_pool);
1079 static PyObject *remove_from_revision_control(PyObject *self, PyObject *args)
1082 bool destroy_wf = false, instant_error = false;
1083 AdmObject *admobj = (AdmObject *)self;
1084 apr_pool_t *temp_pool;
1086 if (!PyArg_ParseTuple(args, "s|bb", &name, &destroy_wf, &instant_error))
1089 ADM_CHECK_CLOSED(admobj);
1091 temp_pool = Pool(NULL);
1092 if (temp_pool == NULL)
1095 RUN_SVN_WITH_POOL(temp_pool,
1096 svn_wc_remove_from_revision_control(admobj->adm, name,
1097 destroy_wf?TRUE:FALSE, instant_error?TRUE:FALSE, py_cancel_check, NULL, temp_pool));
1099 apr_pool_destroy(temp_pool);
1104 static PyObject *relocate(PyObject *self, PyObject *args)
1108 AdmObject *admobj = (AdmObject *)self;
1109 apr_pool_t *temp_pool;
1110 bool recurse = true;
1111 PyObject *py_validator = Py_None, *py_path;
1113 if (!PyArg_ParseTuple(args, "Oss|bO:relocate", &py_path, &from, &to, &recurse,
1117 ADM_CHECK_CLOSED(admobj);
1119 temp_pool = Pool(NULL);
1120 if (temp_pool == NULL) {
1124 path = py_object_to_svn_abspath(py_path, temp_pool);
1126 apr_pool_destroy(temp_pool);
1130 #if ONLY_SINCE_SVN(1, 6)
1131 RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate3(path, admobj->adm, from, to, recurse?TRUE:FALSE, wc_validator3, py_validator, temp_pool));
1133 RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate2(path, admobj->adm, from, to, recurse?TRUE:FALSE, wc_validator2, py_validator, temp_pool));
1136 apr_pool_destroy(temp_pool);
1141 static PyObject *crop_tree(PyObject *self, PyObject *args)
1146 #if ONLY_SINCE_SVN(1, 6)
1147 apr_pool_t *temp_pool;
1149 AdmObject *admobj = (AdmObject *)self;
1151 if (!PyArg_ParseTuple(args, "si|O", &target, &depth, ¬ify))
1154 ADM_CHECK_CLOSED(admobj);
1156 #if ONLY_SINCE_SVN(1, 6)
1157 temp_pool = Pool(NULL);
1158 if (temp_pool == NULL)
1161 RUN_SVN_WITH_POOL(temp_pool, svn_wc_crop_tree(admobj->adm,
1162 target, depth, py_wc_notify_func, notify,
1163 py_cancel_check, NULL, temp_pool));
1165 apr_pool_destroy(temp_pool);
1169 PyErr_SetString(PyExc_NotImplementedError,
1170 "crop_tree only available on subversion < 1.6");
1175 static PyObject *translated_stream(PyObject *self, PyObject *args)
1177 char *path, *versioned_file;
1179 svn_stream_t *stream;
1180 AdmObject *admobj = (AdmObject *)self;
1181 apr_pool_t *stream_pool;
1184 if (!PyArg_ParseTuple(args, "ssi", &path, &versioned_file, &flags))
1187 ADM_CHECK_CLOSED(admobj);
1189 #if ONLY_SINCE_SVN(1, 5)
1190 stream_pool = Pool(NULL);
1191 if (stream_pool == NULL)
1194 RUN_SVN_WITH_POOL(stream_pool,
1195 svn_wc_translated_stream(&stream, path, versioned_file, admobj->adm,
1196 flags, stream_pool));
1198 ret = PyObject_New(StreamObject, &Stream_Type);
1202 ret->pool = stream_pool;
1203 ret->closed = FALSE;
1204 ret->stream = stream;
1206 return (PyObject *)ret;
1208 PyErr_SetString(PyExc_NotImplementedError,
1209 "translated_stream() is only available on Subversion >= 1.5");
1214 static PyObject *adm_text_modified(PyObject *self, PyObject *args)
1217 bool force_comparison = false;
1218 apr_pool_t *temp_pool;
1220 AdmObject *admobj = (AdmObject *)self;
1223 if (!PyArg_ParseTuple(args, "O|b", &py_path, &force_comparison))
1226 ADM_CHECK_CLOSED(admobj);
1228 temp_pool = Pool(NULL);
1229 if (temp_pool == NULL) {
1233 path = py_object_to_svn_abspath(py_path, temp_pool);
1235 apr_pool_destroy(temp_pool);
1239 RUN_SVN_WITH_POOL(temp_pool,
1240 svn_wc_text_modified_p(&ret, path, force_comparison?TRUE:FALSE, admobj->adm,
1243 apr_pool_destroy(temp_pool);
1245 return PyBool_FromLong(ret);
1248 static PyObject *adm_props_modified(PyObject *self, PyObject *args)
1251 apr_pool_t *temp_pool;
1253 AdmObject *admobj = (AdmObject *)self;
1256 if (!PyArg_ParseTuple(args, "O", &py_path))
1259 ADM_CHECK_CLOSED(admobj);
1261 temp_pool = Pool(NULL);
1262 if (temp_pool == NULL) {
1266 path = py_object_to_svn_abspath(py_path, temp_pool);
1268 apr_pool_destroy(temp_pool);
1272 RUN_SVN_WITH_POOL(temp_pool,
1273 svn_wc_props_modified_p(&ret, path, admobj->adm, temp_pool));
1275 apr_pool_destroy(temp_pool);
1277 return PyBool_FromLong(ret);
1280 static PyObject *adm_process_committed_queue(PyObject *self, PyObject *args)
1282 apr_pool_t *temp_pool;
1283 AdmObject *admobj = (AdmObject *)self;
1284 svn_revnum_t revnum;
1285 char *date, *author;
1288 if (!PyArg_ParseTuple(args, "O!lss", &CommittedQueue_Type, &py_queue,
1289 &revnum, &date, &author))
1292 ADM_CHECK_CLOSED(admobj);
1294 temp_pool = Pool(NULL);
1295 if (temp_pool == NULL)
1298 svn_wc_committed_queue_t *committed_queue = PyObject_GetCommittedQueue(py_queue);
1300 #if ONLY_SINCE_SVN(1, 5)
1301 RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed_queue(committed_queue, admobj->adm, revnum, date, author, temp_pool));
1305 for (i = 0; i < py_queue->queue->queue->nelts; i++) {
1306 committed_queue_item_t *cqi = APR_ARRAY_IDX(committed_queue->queue, i,
1307 committed_queue_item_t *);
1309 RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(cqi->path, admobj->adm,
1310 cqi->recurse, revnum, date, author, cqi->wcprop_changes,
1311 cqi->remove_lock, cqi->digest, temp_pool));
1315 apr_pool_destroy(temp_pool);
1321 static PyObject *is_wc_root(PyObject *self, PyObject *args)
1324 svn_boolean_t wc_root;
1325 apr_pool_t *temp_pool;
1326 AdmObject *admobj = (AdmObject *)self;
1329 if (!PyArg_ParseTuple(args, "O", &py_path))
1332 ADM_CHECK_CLOSED(admobj);
1334 temp_pool = Pool(NULL);
1335 if (temp_pool == NULL) {
1339 path = py_object_to_svn_abspath(py_path, temp_pool);
1341 apr_pool_destroy(temp_pool);
1345 RUN_SVN_WITH_POOL(temp_pool,
1346 svn_wc_is_wc_root(&wc_root, path, admobj->adm, temp_pool));
1348 apr_pool_destroy(temp_pool);
1350 return PyBool_FromLong(wc_root);
1353 static PyObject *transmit_text_deltas(PyObject *self, PyObject *args)
1356 const char *tempfile;
1358 PyObject *editor_obj, *py_digest, *py_path;
1359 unsigned char digest[APR_MD5_DIGESTSIZE];
1360 apr_pool_t *temp_pool;
1361 AdmObject *admobj = (AdmObject *)self;
1364 if (!PyArg_ParseTuple(args, "ObO", &py_path, &fulltext, &editor_obj))
1367 ADM_CHECK_CLOSED(admobj);
1369 temp_pool = Pool(NULL);
1370 if (temp_pool == NULL) {
1374 path = py_object_to_svn_abspath(py_path, temp_pool);
1376 apr_pool_destroy(temp_pool);
1380 Py_INCREF(editor_obj);
1382 RUN_SVN_WITH_POOL(temp_pool,
1383 svn_wc_transmit_text_deltas2(&tempfile, digest,
1384 path, admobj->adm, fulltext?TRUE:FALSE,
1385 &py_editor, editor_obj, temp_pool));
1387 py_digest = PyBytes_FromStringAndSize((char *)digest, APR_MD5_DIGESTSIZE);
1388 if (py_digest == NULL) {
1389 apr_pool_destroy(temp_pool);
1393 ret = Py_BuildValue("sN", tempfile, py_digest);
1395 apr_pool_destroy(temp_pool);
1399 apr_pool_destroy(temp_pool);
1404 static PyObject *transmit_prop_deltas(PyObject *self, PyObject *args)
1407 PyObject *editor_obj;
1408 apr_pool_t *temp_pool;
1409 AdmObject *admobj = (AdmObject *)self;
1411 EntryObject *py_entry;
1413 if (!PyArg_ParseTuple(args, "OO!O", &py_path, &Entry_Type, &py_entry, &editor_obj))
1416 ADM_CHECK_CLOSED(admobj);
1418 temp_pool = Pool(NULL);
1419 if (temp_pool == NULL) {
1423 path = py_object_to_svn_abspath(py_path, temp_pool);
1425 apr_pool_destroy(temp_pool);
1429 Py_INCREF(editor_obj);
1431 RUN_SVN_WITH_POOL(temp_pool,
1432 svn_wc_transmit_prop_deltas(path,
1433 admobj->adm, &(py_entry->entry), &py_editor, editor_obj, NULL, temp_pool));
1435 apr_pool_destroy(temp_pool);
1440 static PyObject *retrieve(PyObject *self, PyObject *args)
1443 svn_wc_adm_access_t *result;
1445 AdmObject *admobj = (AdmObject *)self, *ret;
1448 if (!PyArg_ParseTuple(args, "O", &py_path))
1451 ADM_CHECK_CLOSED(admobj);
1457 path = py_object_to_svn_abspath(py_path, pool);
1459 apr_pool_destroy(pool);
1463 RUN_SVN_WITH_POOL(pool, svn_wc_adm_retrieve(&result, admobj->adm,
1466 ret = PyObject_New(AdmObject, &Adm_Type);
1473 return (PyObject *)ret;
1476 static PyObject *probe_retrieve(PyObject *self, PyObject *args)
1479 svn_wc_adm_access_t *result;
1480 AdmObject *admobj = (AdmObject *)self, *ret;
1484 if (!PyArg_ParseTuple(args, "O", &py_path))
1487 ADM_CHECK_CLOSED(admobj);
1494 path = py_object_to_svn_abspath(py_path, pool);
1496 apr_pool_destroy(pool);
1500 RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_retrieve(&result, admobj->adm,
1503 ret = PyObject_New(AdmObject, &Adm_Type);
1510 return (PyObject *)ret;
1513 static PyObject *probe_try(PyObject *self, PyObject *args)
1516 svn_wc_adm_access_t *result = NULL;
1517 AdmObject *admobj = (AdmObject *)self, *ret;
1519 int levels_to_lock = -1;
1520 bool writelock = false;
1523 if (!PyArg_ParseTuple(args, "O|bi", &py_path, &writelock, &levels_to_lock))
1526 ADM_CHECK_CLOSED(admobj);
1533 path = py_object_to_svn_abspath(py_path, pool);
1535 apr_pool_destroy(pool);
1539 RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_try3(&result, admobj->adm,
1540 path, writelock, levels_to_lock,
1541 py_cancel_check, NULL, pool));
1543 if (result == NULL) {
1544 apr_pool_destroy(pool);
1548 ret = PyObject_New(AdmObject, &Adm_Type);
1555 return (PyObject *)ret;
1558 static PyObject *resolved_conflict(PyObject *self, PyObject *args)
1560 AdmObject *admobj = (AdmObject *)self;
1561 apr_pool_t *temp_pool;
1562 bool resolve_props, resolve_tree, resolve_text;
1564 #if ONLY_SINCE_SVN(1, 5)
1565 svn_wc_conflict_choice_t conflict_choice;
1567 int conflict_choice;
1569 PyObject *notify_func = Py_None;
1573 if (!PyArg_ParseTuple(args, "Obbbii|O", &py_path, &resolve_text,
1574 &resolve_props, &resolve_tree, &depth,
1575 &conflict_choice, ¬ify_func))
1578 ADM_CHECK_CLOSED(admobj);
1580 temp_pool = Pool(NULL);
1581 if (temp_pool == NULL) {
1585 path = py_object_to_svn_abspath(py_path, temp_pool);
1587 apr_pool_destroy(temp_pool);
1591 #if ONLY_SINCE_SVN(1, 6)
1592 RUN_SVN_WITH_POOL(temp_pool,
1593 svn_wc_resolved_conflict4(path, admobj->adm, resolve_text?TRUE:FALSE,
1594 resolve_props?TRUE:FALSE, resolve_tree?TRUE:FALSE, depth,
1595 conflict_choice, py_wc_notify_func,
1596 (void *)notify_func, py_cancel_check,
1598 #elif ONLY_SINCE_SVN(1, 5)
1600 PyErr_SetString(PyExc_NotImplementedError,
1601 "resolve_tree not supported with svn < 1.6");
1602 apr_pool_destroy(temp_pool);
1605 RUN_SVN_WITH_POOL(temp_pool,
1606 svn_wc_resolved_conflict3(path, admobj->adm, resolve_text?TRUE:FALSE,
1607 resolve_props?TRUE:FALSE, depth,
1608 conflict_choice, py_wc_notify_func,
1609 (void *)notify_func, py_cancel_check,
1614 PyErr_SetString(PyExc_NotImplementedError,
1615 "resolve_tree not supported with svn < 1.6");
1616 apr_pool_destroy(temp_pool);
1618 } else if (depth != svn_depth_infinity && depth != svn_depth_files) {
1619 PyErr_SetString(PyExc_NotImplementedError,
1620 "only infinity and files values for depth are supported");
1621 apr_pool_destroy(temp_pool);
1623 } else if (conflict_choice != 0) {
1624 PyErr_SetString(PyExc_NotImplementedError,
1625 "conflict choice not supported with svn < 1.5");
1626 apr_pool_destroy(temp_pool);
1629 RUN_SVN_WITH_POOL(temp_pool,
1630 svn_wc_resolved_conflict2(path, admobj->adm, resolve_text?TRUE:FALSE,
1631 resolve_props?TRUE:FALSE,
1632 (depth == svn_depth_infinity),
1634 (void *)notify_func, py_cancel_check,
1640 apr_pool_destroy(temp_pool);
1645 static PyObject *conflicted(PyObject *self, PyObject *args)
1648 apr_pool_t *temp_pool;
1650 AdmObject *admobj = (AdmObject *)self;
1651 svn_boolean_t text_conflicted, prop_conflicted;
1653 #if ONLY_BEFORE_SVN(1, 6)
1654 const svn_wc_entry_t *entry;
1656 svn_boolean_t tree_conflicted;
1659 if (!PyArg_ParseTuple(args, "O", &py_path))
1662 ADM_CHECK_CLOSED(admobj);
1664 temp_pool = Pool(NULL);
1665 if (temp_pool == NULL) {
1669 path = py_object_to_svn_abspath(py_path, temp_pool);
1671 apr_pool_destroy(temp_pool);
1675 #if ONLY_SINCE_SVN(1, 6)
1676 RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p2(&text_conflicted,
1677 &prop_conflicted, &tree_conflicted, path, admobj->adm, temp_pool));
1679 ret = Py_BuildValue("(bbb)", text_conflicted, prop_conflicted, tree_conflicted);
1681 RUN_SVN_WITH_POOL(temp_pool, svn_wc_entry(&entry, path, admobj->adm, TRUE, temp_pool));
1683 RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p(&text_conflicted,
1684 &prop_conflicted, path, entry, temp_pool));
1686 ret = Py_BuildValue("(bbO)", text_conflicted, prop_conflicted, Py_None);
1689 apr_pool_destroy(temp_pool);
1695 * Determine the status of a file in the specified working copy.
1697 * :return: A status object.
1699 static PyObject *wc_status(PyObject *self, PyObject *args)
1702 svn_wc_status2_t *st;
1703 apr_pool_t *temp_pool;
1705 AdmObject *admobj = (AdmObject *)self;
1708 if (!PyArg_ParseTuple(args, "O", &py_path))
1711 ADM_CHECK_CLOSED(admobj);
1713 temp_pool = Pool(NULL);
1714 if (temp_pool == NULL) {
1718 path = py_object_to_svn_abspath(py_path, temp_pool);
1720 apr_pool_destroy(temp_pool);
1724 RUN_SVN_WITH_POOL(temp_pool,
1725 svn_wc_status2(&st, path, admobj->adm, temp_pool));
1727 ret = py_wc_status2(st);
1729 apr_pool_destroy(temp_pool);
1731 return (PyObject*)ret;
1734 static PyMethodDef adm_methods[] = {
1735 { "prop_set", adm_prop_set, METH_VARARGS, "S.prop_set(name, value, path, skip_checks=False)" },
1736 { "access_path", (PyCFunction)adm_access_path, METH_NOARGS,
1737 "S.access_path() -> path\n"
1738 "Returns the base path for this working copy handle." },
1739 { "prop_get", adm_prop_get, METH_VARARGS, "S.prop_get(name, path) -> value" },
1740 { "entries_read", adm_entries_read, METH_VARARGS, "S.entries_read(include_hidden=False) -> dict" },
1741 { "walk_entries", adm_walk_entries, METH_VARARGS,
1742 "S.walk_entries(path, callback, show_hidden=False)\n"
1743 "callback should be a function that takes a path and a wc entry" },
1744 { "locked", (PyCFunction)adm_locked, METH_NOARGS,
1745 "S.locked() -> bool" },
1746 { "get_prop_diffs", adm_get_prop_diffs, METH_VARARGS,
1747 "S.get_prop_diffs(path) -> (propchanges, originalprops)" },
1748 { "add", (PyCFunction)adm_add, METH_VARARGS|METH_KEYWORDS, "S.add(path, copyfrom_url=None, copyfrom_rev=-1, notify_func=None)" },
1749 { "copy", adm_copy, METH_VARARGS, "S.copy(src_path, dest_path, notify_func=None)" },
1750 { "delete", (PyCFunction)adm_delete, METH_VARARGS|METH_KEYWORDS, "S.delete(path, notify_func=None, keep_local=False)" },
1751 { "crawl_revisions", (PyCFunction)adm_crawl_revisions, METH_VARARGS|METH_KEYWORDS,
1752 "S.crawl_revisions(path, reporter, restore_files=True, recurse=True, use_commit_times=True, notify_func=None) -> None" },
1753 { "get_update_editor", (PyCFunction)adm_get_update_editor,
1754 METH_VARARGS|METH_KEYWORDS, NULL },
1755 { "get_switch_editor", (PyCFunction)adm_get_switch_editor,
1756 METH_VARARGS|METH_KEYWORDS, NULL },
1757 { "close", (PyCFunction)adm_close, METH_NOARGS,
1759 { "entry", (PyCFunction)adm_entry, METH_VARARGS,
1760 "s.entry(path, show_hidden=False) -> entry" },
1761 { "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)" },
1762 { "process_committed_queue", (PyCFunction)adm_process_committed_queue, METH_VARARGS, "S.process_committed_queue(queue, new_revnum, rev_date, rev_author)" },
1763 { "remove_lock", (PyCFunction)adm_remove_lock, METH_VARARGS, "S.remove_lock(path)" },
1764 { "has_binary_prop", (PyCFunction)adm_has_binary_prop, METH_VARARGS, "S.has_binary_prop(path) -> bool" },
1765 { "text_modified", (PyCFunction)adm_text_modified, METH_VARARGS, "S.text_modified(filename, force_comparison=False) -> bool" },
1766 { "props_modified", (PyCFunction)adm_props_modified, METH_VARARGS, "S.props_modified(filename) -> bool" },
1767 { "get_ancestry", (PyCFunction)get_ancestry, METH_VARARGS,
1768 "S.get_ancestry(path) -> (url, rev)" },
1769 { "maybe_set_repos_root", (PyCFunction)maybe_set_repos_root, METH_VARARGS, "S.maybe_set_repos_root(path, repos)" },
1770 { "add_repos_file", (PyCFunction)add_repos_file, METH_KEYWORDS,
1771 "S.add_repos_file(dst_path, new_base_contents, new_contents, new_base_props, new_props, copyfrom_url=None, copyfrom_rev=-1, notify_func=None)" },
1772 { "mark_missing_deleted", (PyCFunction)mark_missing_deleted, METH_VARARGS,
1773 "S.mark_missing_deleted(path)" },
1774 { "remove_from_revision_control", (PyCFunction)remove_from_revision_control, METH_VARARGS,
1775 "S.remove_from_revision_control(name, destroy_wf=False, instant_error=False)" },
1776 { "relocate", (PyCFunction)relocate, METH_VARARGS,
1777 "S.relocate(path, from, to, recurse=TRUE, validator=None)" },
1778 { "crop_tree", (PyCFunction)crop_tree, METH_VARARGS,
1779 "S.crop_tree(target, depth, notify_func=None, cancel=None)" },
1780 { "translated_stream", (PyCFunction)translated_stream, METH_VARARGS,
1781 "S.translated_stream(path, versioned_file, flags) -> stream" },
1782 { "is_wc_root", (PyCFunction)is_wc_root, METH_VARARGS,
1783 "S.is_wc_root(path) -> wc_root" },
1784 { "transmit_text_deltas", (PyCFunction)transmit_text_deltas, METH_VARARGS,
1785 "S.transmit_text_deltas(fulltext, editor) -> (tempfile, digest)" },
1786 { "transmit_prop_deltas", (PyCFunction)transmit_prop_deltas, METH_VARARGS,
1787 "S.transmit_prop_deltas(path, entry, editor)" },
1788 { "probe_retrieve", (PyCFunction)probe_retrieve, METH_VARARGS,
1789 "S.probe_retrieve(path) -> WorkingCopy" },
1790 { "retrieve", (PyCFunction)retrieve, METH_VARARGS,
1791 "S.retrieve(path) -> WorkingCopy" },
1792 { "probe_try", (PyCFunction)probe_try, METH_VARARGS,
1793 "S.probe_try(path, write_lock=False, levels_to_lock=-1)" },
1794 { "conflicted", (PyCFunction)conflicted, METH_VARARGS,
1795 "S.conflicted(path) -> (text_conflicted, prop_conflicted, tree_conflicted)" },
1796 { "resolved_conflict", (PyCFunction)resolved_conflict, METH_VARARGS,
1797 "S.resolved_conflict(path, resolve_text, resolve_props, resolve_tree, depth, conflict_choice, notify_func=None, cancel=None)" },
1798 { "status", (PyCFunction)wc_status, METH_VARARGS, "status(wc_path) -> Status" },
1802 PyTypeObject Adm_Type = {
1803 PyVarObject_HEAD_INIT(NULL, 0)
1804 "wc.WorkingCopy", /* const char *tp_name; For printing, in format "<module>.<name>" */
1806 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
1808 /* Methods to implement standard operations */
1810 adm_dealloc, /* destructor tp_dealloc; */
1811 NULL, /* printfunc tp_print; */
1812 NULL, /* getattrfunc tp_getattr; */
1813 NULL, /* setattrfunc tp_setattr; */
1814 NULL, /* cmpfunc tp_compare; */
1815 adm_repr, /* reprfunc tp_repr; */
1817 /* Method suites for standard classes */
1819 NULL, /* PyNumberMethods *tp_as_number; */
1820 NULL, /* PySequenceMethods *tp_as_sequence; */
1821 NULL, /* PyMappingMethods *tp_as_mapping; */
1823 /* More standard operations (here for binary compatibility) */
1825 NULL, /* hashfunc tp_hash; */
1826 NULL, /* ternaryfunc tp_call; */
1827 adm_repr, /* reprfunc tp_repr; */
1828 NULL, /* getattrofunc tp_getattro; */
1829 NULL, /* setattrofunc tp_setattro; */
1831 /* Functions to access object as input/output buffer */
1832 NULL, /* PyBufferProcs *tp_as_buffer; */
1834 /* Flags to define presence of optional/expanded features */
1835 0, /* long tp_flags; */
1837 "Local working copy", /* const char *tp_doc; Documentation string */
1839 /* Assigned meaning in release 2.0 */
1840 /* call function for all accessible objects */
1841 NULL, /* traverseproc tp_traverse; */
1843 /* delete references to contained objects */
1844 NULL, /* inquiry tp_clear; */
1846 /* Assigned meaning in release 2.1 */
1847 /* rich comparisons */
1848 NULL, /* richcmpfunc tp_richcompare; */
1850 /* weak reference enabler */
1851 0, /* Py_ssize_t tp_weaklistoffset; */
1853 /* Added in release 2.2 */
1855 NULL, /* getiterfunc tp_iter; */
1856 NULL, /* iternextfunc tp_iternext; */
1858 /* Attribute descriptor and subclassing stuff */
1859 adm_methods, /* struct PyMethodDef *tp_methods; */
1860 NULL, /* struct PyMemberDef *tp_members; */
1861 NULL, /* struct PyGetSetDef *tp_getset; */
1862 NULL, /* struct _typeobject *tp_base; */
1863 NULL, /* PyObject *tp_dict; */
1864 NULL, /* descrgetfunc tp_descr_get; */
1865 NULL, /* descrsetfunc tp_descr_set; */
1866 0, /* Py_ssize_t tp_dictoffset; */
1867 NULL, /* initproc tp_init; */
1868 NULL, /* allocfunc tp_alloc; */
1869 adm_init, /* newfunc tp_new; */
1872 static void entry_dealloc(PyObject *self)
1874 apr_pool_destroy(((EntryObject *)self)->pool);
1878 static PyMemberDef entry_members[] = {
1879 { "name", T_STRING, offsetof(EntryObject, entry.name), READONLY,
1880 "Name of the file"},
1881 { "copyfrom_url", T_STRING, offsetof(EntryObject, entry.copyfrom_url), READONLY,
1882 "Copyfrom location" },
1883 { "copyfrom_rev", T_LONG, offsetof(EntryObject, entry.copyfrom_rev), READONLY,
1884 "Copyfrom revision" },
1885 { "uuid", T_STRING, offsetof(EntryObject, entry.uuid), READONLY,
1886 "UUID of repository" },
1887 { "url", T_STRING, offsetof(EntryObject, entry.url), READONLY,
1888 "URL in repository" },
1889 { "repos", T_STRING, offsetof(EntryObject, entry.repos), READONLY,
1890 "Canonical repository URL" },
1891 { "schedule", T_INT, offsetof(EntryObject, entry.schedule), READONLY,
1892 "Scheduling (add, replace, delete, etc)" },
1893 { "kind", T_INT, offsetof(EntryObject, entry.kind), READONLY,
1894 "Kind of file (file, dir, etc)" },
1895 { "revision", T_LONG, offsetof(EntryObject, entry.revision), READONLY,
1897 { "cmt_rev", T_LONG, offsetof(EntryObject, entry.cmt_rev), READONLY,
1898 "Last revision this was changed" },
1899 { "checksum", T_STRING, offsetof(EntryObject, entry.checksum), READONLY,
1900 "Hex MD5 checksum for the untranslated text base file" },
1901 { "cmt_date", T_LONG, offsetof(EntryObject, entry.cmt_date), READONLY,
1902 "Last date this was changed" },
1903 { "cmt_author", T_STRING, offsetof(EntryObject, entry.cmt_author), READONLY,
1904 "Last commit author of this item" },
1908 PyTypeObject Entry_Type = {
1909 PyVarObject_HEAD_INIT(NULL, 0)
1910 "wc.Entry", /* const char *tp_name; For printing, in format "<module>.<name>" */
1911 sizeof(EntryObject),
1912 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
1914 /* Methods to implement standard operations */
1916 entry_dealloc, /* destructor tp_dealloc; */
1917 NULL, /* printfunc tp_print; */
1918 NULL, /* getattrfunc tp_getattr; */
1919 NULL, /* setattrfunc tp_setattr; */
1920 NULL, /* cmpfunc tp_compare; */
1921 NULL, /* reprfunc tp_repr; */
1923 /* Method suites for standard classes */
1925 NULL, /* PyNumberMethods *tp_as_number; */
1926 NULL, /* PySequenceMethods *tp_as_sequence; */
1927 NULL, /* PyMappingMethods *tp_as_mapping; */
1929 /* More standard operations (here for binary compatibility) */
1931 NULL, /* hashfunc tp_hash; */
1932 NULL, /* ternaryfunc tp_call; */
1933 NULL, /* reprfunc tp_str; */
1934 NULL, /* getattrofunc tp_getattro; */
1935 NULL, /* setattrofunc tp_setattro; */
1937 /* Functions to access object as input/output buffer */
1938 NULL, /* PyBufferProcs *tp_as_buffer; */
1940 /* Flags to define presence of optional/expanded features */
1941 0, /* long tp_flags; */
1943 NULL, /* const char *tp_doc; Documentation string */
1945 /* Assigned meaning in release 2.0 */
1946 /* call function for all accessible objects */
1947 NULL, /* traverseproc tp_traverse; */
1949 /* delete references to contained objects */
1950 NULL, /* inquiry tp_clear; */
1952 /* Assigned meaning in release 2.1 */
1953 /* rich comparisons */
1954 NULL, /* richcmpfunc tp_richcompare; */
1956 /* weak reference enabler */
1957 0, /* Py_ssize_t tp_weaklistoffset; */
1959 /* Added in release 2.2 */
1961 NULL, /* getiterfunc tp_iter; */
1962 NULL, /* iternextfunc tp_iternext; */
1964 /* Attribute descriptor and subclassing stuff */
1965 NULL, /* struct PyMethodDef *tp_methods; */
1966 entry_members, /* struct PyMemberDef *tp_members; */
1970 static PyObject *py_entry(const svn_wc_entry_t *entry)
1974 if (entry == NULL) {
1978 ret = PyObject_New(EntryObject, &Entry_Type);
1982 ret->pool = Pool(NULL);
1983 if (ret->pool == NULL)
1985 ret->entry = *svn_wc_entry_dup(entry, ret->pool);
1986 return (PyObject *)ret;
1992 svn_wc_status2_t status;
1996 static void status_dealloc(PyObject *self)
1998 apr_pool_destroy(((Status2Object *)self)->pool);
1999 Py_XDECREF(((Status2Object *)self)->entry);
2003 static PyMemberDef status_members[] = {
2004 { "entry", T_OBJECT, offsetof(Status2Object, entry), READONLY,
2005 "Can be NULL if not under version control." },
2006 { "locked", T_BOOL, offsetof(Status2Object, status.locked), READONLY,
2007 "a directory can be 'locked' if a working copy update was interrupted." },
2008 { "copied", T_BOOL, offsetof(Status2Object, status.copied), READONLY,
2009 "a file or directory can be 'copied' if it's scheduled for addition-with-history (or part of a subtree that is scheduled as such.)." },
2010 { "switched", T_BOOL, offsetof(Status2Object, status.switched), READONLY,
2011 "a file or directory can be 'switched' if the switch command has been used." },
2012 { "url", T_STRING, offsetof(Status2Object, status.url), READONLY,
2013 "URL (actual or expected) in repository" },
2014 { "revision", T_LONG, offsetof(Status2Object, status.ood_last_cmt_rev), READONLY,
2015 "Set to the youngest committed revision, or SVN_INVALID_REVNUM if not out of date.", },
2016 { "kind", T_INT, offsetof(Status2Object, status.ood_kind), READONLY,
2017 "Set to the node kind of the youngest commit, or svn_node_none if not out of date.", },
2018 { "status", T_INT, offsetof(Status2Object, status.text_status), READONLY,
2019 "The status of the entry.", },
2023 PyTypeObject Status2_Type = {
2024 PyVarObject_HEAD_INIT(NULL, 0)
2025 "wc.Status", /* const char *tp_name; For printing, in format "<module>.<name>" */
2026 sizeof(Status2Object),
2027 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
2029 /* Methods to implement standard operations */
2031 status_dealloc, /* destructor tp_dealloc; */
2032 NULL, /* printfunc tp_print; */
2033 NULL, /* getattrfunc tp_getattr; */
2034 NULL, /* setattrfunc tp_setattr; */
2035 NULL, /* cmpfunc tp_compare; */
2036 NULL, /* reprfunc tp_repr; */
2038 /* Method suites for standard classes */
2040 NULL, /* PyNumberMethods *tp_as_number; */
2041 NULL, /* PySequenceMethods *tp_as_sequence; */
2042 NULL, /* PyMappingMethods *tp_as_mapping; */
2044 /* More standard operations (here for binary compatibility) */
2046 NULL, /* hashfunc tp_hash; */
2047 NULL, /* ternaryfunc tp_call; */
2048 NULL, /* reprfunc tp_str; */
2049 NULL, /* getattrofunc tp_getattro; */
2050 NULL, /* setattrofunc tp_setattro; */
2052 /* Functions to access object as input/output buffer */
2053 NULL, /* PyBufferProcs *tp_as_buffer; */
2055 /* Flags to define presence of optional/expanded features */
2056 0, /* long tp_flags; */
2058 "Working copy status object", /* const char *tp_doc; Documentation string */
2060 /* Assigned meaning in release 2.0 */
2061 /* call function for all accessible objects */
2062 NULL, /* traverseproc tp_traverse; */
2064 /* delete references to contained objects */
2065 NULL, /* inquiry tp_clear; */
2067 /* Assigned meaning in release 2.1 */
2068 /* rich comparisons */
2069 NULL, /* richcmpfunc tp_richcompare; */
2071 /* weak reference enabler */
2072 0, /* Py_ssize_t tp_weaklistoffset; */
2074 /* Added in release 2.2 */
2076 NULL, /* getiterfunc tp_iter; */
2077 NULL, /* iternextfunc tp_iternext; */
2079 /* Attribute descriptor and subclassing stuff */
2080 NULL, /* struct PyMethodDef *tp_methods; */
2081 status_members, /* struct PyMemberDef *tp_members; */
2085 PyObject *py_wc_status2(svn_wc_status2_t *status)
2088 svn_wc_status2_t *dup_status;
2090 ret = PyObject_New(Status2Object, &Status2_Type);
2094 ret->pool = Pool(NULL);
2095 if (ret->pool == NULL) {
2100 dup_status = svn_wc_dup_status2(status, ret->pool);
2101 if (dup_status == NULL)
2106 ret->status = *dup_status;
2108 ret->entry = py_entry(ret->status.entry);
2109 return (PyObject *)ret;
2112 static svn_error_t *py_wc_found_entry(const char *path, const svn_wc_entry_t *entry, void *walk_baton, apr_pool_t *pool)
2115 PyObject *callbacks = (PyObject *)walk_baton;
2116 PyGILState_STATE state = PyGILState_Ensure();
2117 if (PyTuple_Check(callbacks)) {
2118 fn = PyTuple_GET_ITEM(callbacks, 0);
2120 fn = (PyObject *)walk_baton;
2122 ret = PyObject_CallFunction(fn, "sO", path, py_entry(entry));
2123 CB_CHECK_PYRETVAL(ret);
2125 PyGILState_Release(state);
2129 #if ONLY_SINCE_SVN(1, 5)
2131 svn_error_t *py_wc_handle_error(const char *path, svn_error_t *err, void *walk_baton, apr_pool_t *pool)
2135 PyGILState_STATE state;
2136 PyObject *callbacks = (PyObject *)walk_baton;
2137 if (PyTuple_Check(callbacks)) {
2138 fn = PyTuple_GET_ITEM(callbacks, 1);
2142 state = PyGILState_Ensure();
2143 py_err = PyErr_NewSubversionException(err);
2144 ret = PyObject_CallFunction(fn, "sO", path, py_err);
2145 CB_CHECK_PYRETVAL(ret);
2147 PyGILState_Release(state);
2152 static svn_wc_entry_callbacks2_t py_wc_entry_callbacks2 = {
2157 static svn_wc_entry_callbacks_t py_wc_entry_callbacks = {
2162 #pragma GCC diagnostic pop