2 * Copyright © 2008-2009 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
21 #include <apr_general.h>
22 #include <svn_types.h>
25 #include <svn_props.h>
26 #include <apr_file_io.h>
27 #include <apr_portable.h>
29 #include <structmember.h>
35 #if ONLY_SINCE_SVN(1, 5)
36 #define REPORTER_T svn_ra_reporter3_t
38 #define REPORTER_T svn_ra_reporter2_t
41 static PyObject *busy_exc;
43 static PyTypeObject Reporter_Type;
44 static PyTypeObject RemoteAccess_Type;
45 static PyTypeObject AuthProvider_Type;
46 static PyTypeObject CredentialsIter_Type;
47 static PyTypeObject Auth_Type;
49 static bool ra_check_svn_path(const char *path)
51 /* svn_ra_check_path will raise an assertion error if the path has a
52 * leading '/'. Raise a Python exception if there ar eleading '/'s so that
53 * the Python interpreter won't crash and die. */
55 PyErr_SetString(PyExc_ValueError, "invalid path has a leading '/'");
61 static svn_error_t *py_commit_callback(const svn_commit_info_t *commit_info, void *baton, apr_pool_t *pool)
63 PyObject *fn = (PyObject *)baton, *ret;
64 PyGILState_STATE state;
69 state = PyGILState_Ensure();
71 ret = PyObject_CallFunction(fn, "lzz",
72 commit_info->revision, commit_info->date,
74 CB_CHECK_PYRETVAL(ret);
76 PyGILState_Release(state);
80 static PyObject *pyify_lock(const svn_lock_t *lock)
82 return Py_BuildValue("(ssszbLL)",
83 lock->path, lock->token,
84 lock->owner, lock->comment,
87 lock->expiration_date);
90 static svn_error_t *py_lock_func (void *baton, const char *path, int do_lock,
91 const svn_lock_t *lock, svn_error_t *ra_err,
94 PyObject *py_ra_err, *ret, *py_lock;
95 PyGILState_STATE state = PyGILState_Ensure();
97 py_ra_err = PyErr_NewSubversionException(ra_err);
100 Py_INCREF(py_ra_err);
102 py_lock = pyify_lock(lock);
103 ret = PyObject_CallFunction((PyObject *)baton, "zbOO", path, do_lock,
106 Py_DECREF(py_ra_err);
107 CB_CHECK_PYRETVAL(ret);
109 PyGILState_Release(state);
113 /** Connection to a remote Subversion repository. */
116 svn_ra_session_t *ra;
119 PyObject *progress_func;
122 PyObject *client_string_func;
123 PyObject *open_tmp_file_func;
125 const char *corrected_url;
126 } RemoteAccessObject;
130 const REPORTER_T *reporter;
133 RemoteAccessObject *ra;
136 static PyObject *reporter_set_path(PyObject *self, PyObject *args)
139 svn_revnum_t revision;
141 char *lock_token = NULL;
142 svn_depth_t depth = svn_depth_infinity;
143 ReporterObject *reporter = (ReporterObject *)self;
145 if (!PyArg_ParseTuple(args, "slb|zi:set_path", &path, &revision, &start_empty,
146 &lock_token, &depth))
149 if (reporter->ra == NULL) {
150 PyErr_SetString(PyExc_RuntimeError,
151 "Reporter already finished.");
155 #if ONLY_SINCE_SVN(1, 5)
156 RUN_SVN(reporter->reporter->set_path(reporter->report_baton,
157 path, revision, depth, start_empty,
158 lock_token, reporter->pool));
160 if (depth != svn_depth_infinity) {
161 PyErr_SetString(PyExc_NotImplementedError,
162 "depth != infinity only supported for svn >= 1.5");
165 RUN_SVN(reporter->reporter->set_path(reporter->report_baton,
166 path, revision, start_empty,
167 lock_token, reporter->pool));
172 static PyObject *reporter_delete_path(PyObject *self, PyObject *args)
174 ReporterObject *reporter = (ReporterObject *)self;
176 if (!PyArg_ParseTuple(args, "s:delete_path", &path))
179 if (reporter->ra == NULL) {
180 PyErr_SetString(PyExc_RuntimeError,
181 "Reporter already finished.");
185 RUN_SVN(reporter->reporter->delete_path(reporter->report_baton,
186 path, reporter->pool));
191 static PyObject *reporter_link_path(PyObject *self, PyObject *args)
194 svn_revnum_t revision;
196 char *lock_token = NULL;
197 ReporterObject *reporter = (ReporterObject *)self;
198 svn_depth_t depth = svn_depth_infinity;
200 if (!PyArg_ParseTuple(args, "sslb|zi:link_path", &path, &url, &revision,
201 &start_empty, &lock_token, &depth))
204 if (reporter->ra == NULL) {
205 PyErr_SetString(PyExc_RuntimeError,
206 "Reporter already finished.");
210 #if ONLY_SINCE_SVN(1, 5)
211 RUN_SVN(reporter->reporter->link_path(reporter->report_baton, path, url,
212 revision, depth, start_empty, lock_token, reporter->pool));
214 if (depth != svn_depth_infinity) {
215 PyErr_SetString(PyExc_NotImplementedError,
216 "depth != infinity only supported for svn >= 1.5");
219 RUN_SVN(reporter->reporter->link_path(reporter->report_baton, path, url,
220 revision, start_empty, lock_token, reporter->pool));
226 static PyObject *reporter_finish(PyObject *self)
228 ReporterObject *reporter = (ReporterObject *)self;
230 if (reporter->ra == NULL) {
231 PyErr_SetString(PyExc_RuntimeError,
232 "Reporter already finished.");
236 reporter->ra->busy = false;
238 RUN_SVN(reporter->reporter->finish_report(
239 reporter->report_baton, reporter->pool));
241 apr_pool_destroy(reporter->pool);
242 Py_XDECREF(reporter->ra);
248 static PyObject *reporter_abort(PyObject *self)
250 ReporterObject *reporter = (ReporterObject *)self;
252 if (reporter->ra == NULL) {
253 PyErr_SetString(PyExc_RuntimeError,
254 "Reporter already finished.");
258 reporter->ra->busy = false;
260 RUN_SVN(reporter->reporter->abort_report(reporter->report_baton,
263 apr_pool_destroy(reporter->pool);
264 Py_XDECREF(reporter->ra);
270 static PyMethodDef reporter_methods[] = {
271 { "abort", (PyCFunction)reporter_abort, METH_NOARGS,
273 "Abort this report." },
274 { "finish", (PyCFunction)reporter_finish, METH_NOARGS,
276 "Finish this report." },
277 { "link_path", (PyCFunction)reporter_link_path, METH_VARARGS,
278 "S.link_path(path, url, revision, start_empty, lock_token=None)\n" },
279 { "set_path", (PyCFunction)reporter_set_path, METH_VARARGS,
280 "S.set_path(path, revision, start_empty, lock_token=None)\n" },
281 { "delete_path", (PyCFunction)reporter_delete_path, METH_VARARGS,
282 "S.delete_path(path)\n" },
286 static void reporter_dealloc(PyObject *self)
288 ReporterObject *reporter = (ReporterObject *)self;
289 if (reporter->ra != NULL) {
291 apr_pool_destroy(reporter->pool);
292 Py_DECREF(reporter->ra);
297 static PyTypeObject Reporter_Type = {
298 PyVarObject_HEAD_INIT(NULL, 0)
299 "_ra.Reporter", /* const char *tp_name; For printing, in format "<module>.<name>" */
300 sizeof(ReporterObject),
301 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
303 /* Methods to implement standard operations */
305 reporter_dealloc, /* destructor tp_dealloc; */
306 NULL, /* printfunc tp_print; */
307 NULL, /* getattrfunc tp_getattr; */
308 NULL, /* setattrfunc tp_setattr; */
309 NULL, /* cmpfunc tp_compare; */
310 NULL, /* reprfunc tp_repr; */
312 /* Method suites for standard classes */
314 NULL, /* PyNumberMethods *tp_as_number; */
315 NULL, /* PySequenceMethods *tp_as_sequence; */
316 NULL, /* PyMappingMethods *tp_as_mapping; */
318 /* More standard operations (here for binary compatibility) */
320 NULL, /* hashfunc tp_hash; */
321 NULL, /* ternaryfunc tp_call; */
322 NULL, /* reprfunc tp_str; */
323 NULL, /* getattrofunc tp_getattro; */
324 NULL, /* setattrofunc tp_setattro; */
326 /* Functions to access object as input/output buffer */
327 NULL, /* PyBufferProcs *tp_as_buffer; */
329 /* Flags to define presence of optional/expanded features */
330 0, /* long tp_flags; */
332 NULL, /* const char *tp_doc; Documentation string */
334 /* Assigned meaning in release 2.0 */
335 /* call function for all accessible objects */
336 NULL, /* traverseproc tp_traverse; */
338 /* delete references to contained objects */
339 NULL, /* inquiry tp_clear; */
341 /* Assigned meaning in release 2.1 */
342 /* rich comparisons */
343 NULL, /* richcmpfunc tp_richcompare; */
345 /* weak reference enabler */
346 0, /* Py_ssize_t tp_weaklistoffset; */
348 /* Added in release 2.2 */
350 NULL, /* getiterfunc tp_iter; */
351 NULL, /* iternextfunc tp_iternext; */
353 /* Attribute descriptor and subclassing stuff */
354 reporter_methods, /* struct PyMethodDef *tp_methods; */
359 * Get libsvn_ra version information.
361 * :return: tuple with major, minor, patch version number and tag.
363 static PyObject *version(PyObject *self)
365 const svn_version_t *ver = svn_ra_version();
366 return Py_BuildValue("(iiis)", ver->major, ver->minor,
367 ver->patch, ver->tag);
370 SVN_VERSION_DEFINE(svn_api_version);
373 * Get compile-time libsvn_ra version information.
375 * :return: tuple with major, minor, patch version number and tag.
377 static PyObject *api_version(PyObject *self)
379 const svn_version_t *ver = &svn_api_version;
380 return Py_BuildValue("(iiis)", ver->major, ver->minor,
381 ver->patch, ver->tag);
384 #if ONLY_SINCE_SVN(1, 5)
385 static svn_error_t *py_file_rev_handler(void *baton, const char *path, svn_revnum_t rev, apr_hash_t *rev_props, svn_boolean_t result_of_merge, svn_txdelta_window_handler_t *delta_handler, void **delta_baton, apr_array_header_t *prop_diffs, apr_pool_t *pool)
387 PyObject *fn = (PyObject *)baton, *ret, *py_rev_props;
388 PyGILState_STATE state = PyGILState_Ensure();
390 py_rev_props = prop_hash_to_dict(rev_props);
391 CB_CHECK_PYRETVAL(py_rev_props);
393 ret = PyObject_CallFunction(fn, "slOb", path, rev, py_rev_props, result_of_merge);
394 Py_DECREF(py_rev_props);
395 CB_CHECK_PYRETVAL(ret);
397 if (delta_baton != NULL && delta_handler != NULL) {
398 *delta_baton = (void *)ret;
399 *delta_handler = py_txdelta_window_handler;
403 PyGILState_Release(state);
407 static svn_error_t *py_ra_file_rev_handler(void *baton, const char *path, svn_revnum_t rev, apr_hash_t *rev_props, svn_txdelta_window_handler_t *delta_handler, void **delta_baton, apr_array_header_t *prop_diffs, apr_pool_t *pool)
409 PyObject *fn = (PyObject *)baton, *ret, *py_rev_props;
410 PyGILState_STATE state = PyGILState_Ensure();
412 py_rev_props = prop_hash_to_dict(rev_props);
413 CB_CHECK_PYRETVAL(py_rev_props);
415 ret = PyObject_CallFunction(fn, "slO", path, rev, py_rev_props);
416 Py_DECREF(py_rev_props);
417 CB_CHECK_PYRETVAL(ret);
419 if (delta_baton != NULL && delta_handler != NULL) {
420 *delta_baton = (void *)ret;
421 *delta_handler = py_txdelta_window_handler;
425 PyGILState_Release(state);
432 static void ra_done_handler(void *_ra)
434 RemoteAccessObject *ra = (RemoteAccessObject *)_ra;
441 #define RUN_RA_WITH_POOL(pool, ra, cmd) { \
443 PyThreadState *_save; \
444 _save = PyEval_SaveThread(); \
446 PyEval_RestoreThread(_save); \
448 handle_svn_error(err); \
449 svn_error_clear(err); \
450 apr_pool_destroy(pool); \
457 static bool ra_check_busy(RemoteAccessObject *raobj)
460 PyErr_SetString(busy_exc, "Remote access object already in use");
467 #if ONLY_SINCE_SVN(1, 5)
468 static svn_error_t *py_get_client_string(void *baton, const char **name, apr_pool_t *pool)
470 RemoteAccessObject *self = (RemoteAccessObject *)baton;
472 PyGILState_STATE state;
474 if (self->client_string_func == Py_None) {
479 state = PyGILState_Ensure();
481 ret = PyObject_CallFunction(self->client_string_func, "");
483 CB_CHECK_PYRETVAL(ret);
485 *name = py_object_to_svn_string(ret, pool);
488 PyGILState_Release(state);
493 /* Based on svn_swig_py_make_file() from Subversion */
494 static svn_error_t *py_open_tmp_file(apr_file_t **fp, void *callback,
497 RemoteAccessObject *self = (RemoteAccessObject *)callback;
500 PyGILState_STATE state;
502 if (self->open_tmp_file_func == Py_None) {
505 SVN_ERR (svn_io_temp_dir (&path, pool));
506 path = svn_dirent_join (path, "subvertpy", pool);
507 #if ONLY_SINCE_SVN(1, 6)
508 SVN_ERR (svn_io_open_unique_file3(fp, NULL, path, svn_io_file_del_on_pool_cleanup, pool, pool));
510 SVN_ERR (svn_io_open_unique_file (fp, NULL, path, ".tmp", TRUE, pool));
516 state = PyGILState_Ensure();
518 ret = PyObject_CallFunction(self->open_tmp_file_func, "");
520 CB_CHECK_PYRETVAL(ret);
522 if (PyString_Check(ret)) {
523 char* fname = PyString_AsString(ret);
524 status = apr_file_open(fp, fname, APR_CREATE | APR_READ | APR_WRITE, APR_OS_DEFAULT,
527 PyErr_SetAprStatus(status);
531 } else if (PyFile_Check(ret)) {
532 *fp = apr_file_from_object(ret, pool);
538 PyErr_SetString(PyExc_TypeError, "Unknown type for file variable");
540 PyGILState_Release(state);
541 return py_svn_error();
544 PyGILState_Release(state);
550 PyGILState_Release(state);
551 return py_svn_error();
554 static void py_progress_func(apr_off_t progress, apr_off_t total, void *baton, apr_pool_t *pool)
556 PyGILState_STATE state = PyGILState_Ensure();
557 RemoteAccessObject *ra = (RemoteAccessObject *)baton;
558 PyObject *fn = (PyObject *)ra->progress_func, *ret;
560 ret = PyObject_CallFunction(fn, "LL", progress, total);
563 PyGILState_Release(state);
566 static PyObject *ra_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
568 char *kwnames[] = { "url", "progress_cb", "auth", "config",
569 "client_string_func", "open_tmp_file_func", "uuid",
573 PyObject *progress_cb = Py_None;
574 AuthObject *auth = (AuthObject *)Py_None;
575 PyObject *config = Py_None;
576 PyObject *client_string_func = Py_None, *open_tmp_file_func = Py_None;
577 RemoteAccessObject *ret;
578 apr_hash_t *config_hash;
579 svn_ra_callbacks2_t *callbacks2;
580 svn_auth_baton_t *auth_baton;
583 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOOOOz", kwnames, &py_url,
584 &progress_cb, (PyObject **)&auth, &config,
585 &client_string_func, &open_tmp_file_func,
589 ret = PyObject_New(RemoteAccessObject, &RemoteAccess_Type);
593 ret->client_string_func = client_string_func;
594 ret->open_tmp_file_func = open_tmp_file_func;
595 Py_INCREF(client_string_func);
597 Py_INCREF(progress_cb);
598 ret->progress_func = progress_cb;
601 ret->corrected_url = NULL;
604 ret->pool = Pool(NULL);
605 if (ret->pool == NULL) {
610 ret->url = py_object_to_svn_uri(py_url, ret->pool);
611 if (ret->url == NULL) {
616 if ((PyObject *)auth == Py_None) {
618 svn_auth_open(&auth_baton, apr_array_make(ret->pool, 0, sizeof(svn_auth_provider_object_t *)), ret->pool);
619 } else if (PyObject_TypeCheck(auth, &Auth_Type)) {
622 auth_baton = ret->auth->auth_baton;
624 PyErr_SetString(PyExc_TypeError, "auth argument is not an Auth object");
629 err = svn_ra_create_callbacks(&callbacks2, ret->pool);
631 handle_svn_error(err);
632 svn_error_clear(err);
637 callbacks2->progress_baton = (void *)ret;
638 callbacks2->progress_func = py_progress_func;
639 callbacks2->auth_baton = auth_baton;
640 callbacks2->open_tmp_file = py_open_tmp_file;
641 callbacks2->cancel_func = py_cancel_check;
642 #if ONLY_SINCE_SVN(1, 5)
643 callbacks2->get_client_string = py_get_client_string;
645 config_hash = config_hash_from_object(config, ret->pool);
646 if (config_hash == NULL) {
650 Py_BEGIN_ALLOW_THREADS
651 #if ONLY_SINCE_SVN(1, 7)
652 err = svn_ra_open4(&ret->ra, &ret->corrected_url, ret->url, uuid,
653 callbacks2, ret, config_hash, ret->pool);
654 #elif ONLY_SINCE_SVN(1, 5)
655 err = svn_ra_open3(&ret->ra, ret->url, uuid,
656 callbacks2, ret, config_hash, ret->pool);
659 PyErr_SetString(PyExc_TypeError,
660 "uuid argument not supported with svn 1.4");
664 err = svn_ra_open2(&ret->ra, ret->url,
665 callbacks2, ret, config_hash, ret->pool);
669 handle_svn_error(err);
670 svn_error_clear(err);
675 return (PyObject *)ret;
679 * Obtain the globally unique identifier for this repository.
681 static PyObject *ra_get_uuid(PyObject *self)
684 RemoteAccessObject *ra = (RemoteAccessObject *)self;
686 apr_pool_t *temp_pool;
688 if (ra_check_busy(ra))
691 temp_pool = Pool(NULL);
692 if (temp_pool == NULL)
694 #if ONLY_SINCE_SVN(1, 5)
695 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_uuid2(ra->ra, &uuid, temp_pool));
697 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_uuid(ra->ra, &uuid, temp_pool));
699 ret = PyUnicode_FromString(uuid);
700 apr_pool_destroy(temp_pool);
704 /** Switch to a different url. */
705 static PyObject *ra_reparent(PyObject *self, PyObject *args)
708 apr_pool_t *temp_pool;
709 RemoteAccessObject *ra = (RemoteAccessObject *)self;
711 if (!PyArg_ParseTuple(args, "O:reparent", &py_url))
714 if (ra_check_busy(ra))
717 temp_pool = Pool(NULL);
718 if (temp_pool == NULL)
720 ra->url = py_object_to_svn_uri(py_url, ra->pool);
721 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_reparent(ra->ra, ra->url, temp_pool));
722 apr_pool_destroy(temp_pool);
727 * Obtain the number of the latest committed revision in the
728 * connected repository.
730 static PyObject *ra_get_latest_revnum(PyObject *self)
732 RemoteAccessObject *ra = (RemoteAccessObject *)self;
733 svn_revnum_t latest_revnum;
734 apr_pool_t *temp_pool;
735 if (ra_check_busy(ra))
738 temp_pool = Pool(NULL);
739 if (temp_pool == NULL)
741 RUN_RA_WITH_POOL(temp_pool, ra,
742 svn_ra_get_latest_revnum(ra->ra, &latest_revnum, temp_pool));
743 apr_pool_destroy(temp_pool);
744 return PyInt_FromLong(latest_revnum);
748 static bool ra_get_log_prepare(RemoteAccessObject *ra, PyObject *paths,
749 bool include_merged_revisions, PyObject *revprops, apr_pool_t **pool,
750 apr_array_header_t **apr_paths, apr_array_header_t **apr_revprops)
752 if (ra_check_busy(ra))
758 if (paths == Py_None) {
759 /* The subversion libraries don't behave as expected,
760 * so tweak our own parameters a bit. */
761 *apr_paths = apr_array_make(*pool, 1, sizeof(char *));
762 APR_ARRAY_PUSH(*apr_paths, char *) = apr_pstrdup(*pool, "");
763 } else if (!path_list_to_apr_array(*pool, paths, apr_paths)) {
767 #if ONLY_BEFORE_SVN(1, 5)
768 if (revprops == Py_None) {
769 PyErr_SetString(PyExc_NotImplementedError,
770 "fetching all revision properties not supported");
772 } else if (!PySequence_Check(revprops)) {
773 PyErr_SetString(PyExc_TypeError, "revprops should be a sequence");
777 for (i = 0; i < PySequence_Size(revprops); i++) {
778 PyObject *n = PySequence_GetItem(revprops, i);
781 ns = py_object_to_svn_string(n, *pool);
786 if (strcmp(SVN_PROP_REVISION_LOG, ns) &&
787 strcmp(SVN_PROP_REVISION_AUTHOR, ns) &&
788 strcmp(SVN_PROP_REVISION_DATE, ns)) {
789 PyErr_SetString(PyExc_NotImplementedError,
790 "fetching custom revision properties not supported");
796 if (include_merged_revisions) {
797 PyErr_SetString(PyExc_NotImplementedError,
798 "include_merged_revisions not supported in Subversion 1.4");
803 if (!string_list_to_apr_array(*pool, revprops, apr_revprops)) {
810 apr_pool_destroy(*pool);
817 static PyObject *ra_get_log(PyObject *self, PyObject *args, PyObject *kwargs)
819 char *kwnames[] = { "callback", "paths", "start", "end", "limit",
820 "discover_changed_paths", "strict_node_history", "include_merged_revisions", "revprops", NULL };
821 PyObject *callback, *paths;
822 svn_revnum_t start = 0, end = 0;
824 bool discover_changed_paths=false, strict_node_history=true,include_merged_revisions=false;
825 RemoteAccessObject *ra = (RemoteAccessObject *)self;
826 PyObject *revprops = Py_None;
827 apr_pool_t *temp_pool;
828 apr_array_header_t *apr_paths;
829 apr_array_header_t *apr_revprops;
831 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOll|ibbbO:get_log", kwnames,
832 &callback, &paths, &start, &end, &limit,
833 &discover_changed_paths, &strict_node_history,
834 &include_merged_revisions, &revprops))
837 if (!ra_get_log_prepare(ra, paths, include_merged_revisions,
838 revprops, &temp_pool, &apr_paths, &apr_revprops)) {
842 #if ONLY_SINCE_SVN(1, 5)
843 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_log2(ra->ra,
844 apr_paths, start, end, limit,
845 discover_changed_paths, strict_node_history,
846 include_merged_revisions,
848 py_svn_log_entry_receiver,
849 callback, temp_pool));
851 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_log(ra->ra,
852 apr_paths, start, end, limit,
853 discover_changed_paths, strict_node_history, py_svn_log_wrapper,
854 callback, temp_pool));
856 apr_pool_destroy(temp_pool);
861 * Obtain the URL of the root of this repository.
863 static PyObject *ra_get_repos_root(PyObject *self)
865 RemoteAccessObject *ra = (RemoteAccessObject *)self;
867 apr_pool_t *temp_pool;
869 if (ra->root == NULL) {
870 if (ra_check_busy(ra))
873 temp_pool = Pool(NULL);
874 if (temp_pool == NULL)
876 #if ONLY_SINCE_SVN(1, 5)
877 RUN_RA_WITH_POOL(temp_pool, ra,
878 svn_ra_get_repos_root2(ra->ra, &root, temp_pool));
880 RUN_RA_WITH_POOL(temp_pool, ra,
881 svn_ra_get_repos_root(ra->ra, &root, temp_pool));
883 ra->root = svn_uri_canonicalize(root, ra->pool);
884 apr_pool_destroy(temp_pool);
887 return PyString_FromString(ra->root);
891 * Obtain the URL of this repository.
893 static PyObject *ra_get_url(PyObject *self, void *closure)
896 apr_pool_t *temp_pool;
898 RemoteAccessObject *ra = (RemoteAccessObject *)self;
900 if (ra_check_busy(ra))
903 #if ONLY_SINCE_SVN(1, 5)
904 temp_pool = Pool(NULL);
906 RUN_RA_WITH_POOL(temp_pool, ra,
907 svn_ra_get_session_url(ra->ra, &url, temp_pool));
909 r = PyString_FromString(url);
911 apr_pool_destroy(temp_pool);
915 PyErr_SetString(PyExc_NotImplementedError,
916 "svn_ra_get_session_url only supported for svn >= 1.5");
921 static PyObject *ra_do_update(PyObject *self, PyObject *args)
923 svn_revnum_t revision_to_update_to;
926 PyObject *update_editor;
927 const REPORTER_T *reporter;
930 apr_pool_t *temp_pool;
932 RemoteAccessObject *ra = (RemoteAccessObject *)self;
933 svn_boolean_t send_copyfrom_args = FALSE;
935 if (!PyArg_ParseTuple(args, "lsbO|b:do_update", &revision_to_update_to, &update_target, &recurse, &update_editor,
936 &send_copyfrom_args))
939 if (ra_check_busy(ra))
942 temp_pool = Pool(NULL);
943 if (temp_pool == NULL)
946 Py_INCREF(update_editor);
947 #if ONLY_SINCE_SVN(1, 5)
948 Py_BEGIN_ALLOW_THREADS
949 err = svn_ra_do_update2(ra->ra, &reporter,
951 revision_to_update_to,
952 update_target, recurse?svn_depth_infinity:svn_depth_files,
954 &py_editor, update_editor,
957 if (send_copyfrom_args) {
958 PyErr_SetString(PyExc_NotImplementedError, "send_copyfrom_args only supported for svn >= 1.5");
959 apr_pool_destroy(temp_pool);
962 Py_BEGIN_ALLOW_THREADS
963 err = svn_ra_do_update(ra->ra, &reporter,
964 &report_baton, revision_to_update_to,
965 update_target, recurse,
966 &py_editor, update_editor,
972 handle_svn_error(err);
973 svn_error_clear(err);
974 apr_pool_destroy(temp_pool);
979 ret = PyObject_New(ReporterObject, &Reporter_Type);
982 ret->reporter = reporter;
983 ret->report_baton = report_baton;
984 ret->pool = temp_pool;
987 return (PyObject *)ret;
990 static PyObject *ra_do_switch(PyObject *self, PyObject *args)
992 RemoteAccessObject *ra = (RemoteAccessObject *)self;
993 svn_revnum_t revision_to_update_to;
997 PyObject *update_editor;
998 const REPORTER_T *reporter;
1000 apr_pool_t *temp_pool;
1001 ReporterObject *ret;
1004 if (!PyArg_ParseTuple(args, "lsbsO:do_switch", &revision_to_update_to, &update_target,
1005 &recurse, &switch_url, &update_editor))
1007 if (ra_check_busy(ra))
1010 temp_pool = Pool(NULL);
1011 if (temp_pool == NULL) {
1016 Py_INCREF(update_editor);
1017 Py_BEGIN_ALLOW_THREADS
1019 #if ONLY_SINCE_SVN(1, 5)
1020 err = svn_ra_do_switch2(
1021 ra->ra, &reporter, &report_baton,
1022 revision_to_update_to, update_target,
1023 recurse?svn_depth_infinity:svn_depth_files, switch_url, &py_editor,
1024 update_editor, temp_pool);
1026 err = svn_ra_do_switch(
1027 ra->ra, &reporter, &report_baton,
1028 revision_to_update_to, update_target,
1029 recurse, switch_url, &py_editor,
1030 update_editor, temp_pool);
1033 Py_END_ALLOW_THREADS
1036 handle_svn_error(err);
1037 svn_error_clear(err);
1038 apr_pool_destroy(temp_pool);
1042 ret = PyObject_New(ReporterObject, &Reporter_Type);
1044 apr_pool_destroy(temp_pool);
1048 ret->reporter = reporter;
1049 ret->report_baton = report_baton;
1050 ret->pool = temp_pool;
1053 return (PyObject *)ret;
1056 static PyObject *ra_do_diff(PyObject *self, PyObject *args)
1058 svn_revnum_t revision_to_update_to;
1059 char *diff_target, *versus_url;
1060 PyObject *diff_editor;
1061 const REPORTER_T *reporter;
1064 apr_pool_t *temp_pool;
1065 bool ignore_ancestry = false, text_deltas = false, recurse=true;
1066 ReporterObject *ret;
1067 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1069 if (!PyArg_ParseTuple(args, "lssO|bbb:do_diff", &revision_to_update_to, &diff_target, &versus_url, &diff_editor, &recurse, &ignore_ancestry, &text_deltas))
1072 if (ra_check_busy(ra))
1075 temp_pool = Pool(NULL);
1076 if (temp_pool == NULL)
1079 Py_INCREF(diff_editor);
1080 Py_BEGIN_ALLOW_THREADS
1081 #if ONLY_SINCE_SVN(1, 5)
1082 err = svn_ra_do_diff3(ra->ra, &reporter, &report_baton,
1083 revision_to_update_to,
1084 diff_target, recurse?svn_depth_infinity:svn_depth_files,
1088 &py_editor, diff_editor,
1091 err = svn_ra_do_diff2(ra->ra, &reporter, &report_baton,
1092 revision_to_update_to,
1093 diff_target, recurse,
1097 &py_editor, diff_editor,
1100 Py_END_ALLOW_THREADS
1102 handle_svn_error(err);
1103 svn_error_clear(err);
1104 apr_pool_destroy(temp_pool);
1109 ret = PyObject_New(ReporterObject, &Reporter_Type);
1112 ret->reporter = reporter;
1113 ret->report_baton = report_baton;
1114 ret->pool = temp_pool;
1117 return (PyObject *)ret;
1120 static PyObject *ra_replay(PyObject *self, PyObject *args)
1122 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1123 apr_pool_t *temp_pool;
1124 svn_revnum_t revision, low_water_mark;
1125 PyObject *update_editor;
1126 bool send_deltas = true;
1128 if (!PyArg_ParseTuple(args, "llO|b:replay", &revision, &low_water_mark, &update_editor, &send_deltas))
1131 if (ra_check_busy(ra))
1134 temp_pool = Pool(NULL);
1135 if (temp_pool == NULL)
1137 /* Only INCREF here, py_editor takes care of the DECREF */
1138 Py_INCREF(update_editor);
1139 RUN_RA_WITH_POOL(temp_pool, ra,
1140 svn_ra_replay(ra->ra, revision, low_water_mark,
1141 send_deltas, &py_editor, update_editor,
1143 apr_pool_destroy(temp_pool);
1148 #if ONLY_SINCE_SVN(1, 5)
1149 static svn_error_t *py_revstart_cb(svn_revnum_t revision, void *replay_baton,
1150 const svn_delta_editor_t **editor, void **edit_baton, apr_hash_t *rev_props, apr_pool_t *pool)
1152 PyObject *cbs = (PyObject *)replay_baton;
1153 PyObject *py_start_fn = PyTuple_GetItem(cbs, 0);
1154 PyObject *py_revprops = prop_hash_to_dict(rev_props);
1156 PyGILState_STATE state = PyGILState_Ensure();
1158 ret = PyObject_CallFunction(py_start_fn, "lO", revision, py_revprops);
1159 CB_CHECK_PYRETVAL(ret);
1161 *editor = &py_editor;
1164 PyGILState_Release(state);
1168 static svn_error_t *py_revfinish_cb(svn_revnum_t revision, void *replay_baton,
1169 const svn_delta_editor_t *editor, void *edit_baton,
1170 apr_hash_t *rev_props, apr_pool_t *pool)
1172 PyObject *cbs = (PyObject *)replay_baton;
1173 PyObject *py_finish_fn = PyTuple_GetItem(cbs, 1);
1174 PyObject *py_revprops = prop_hash_to_dict(rev_props);
1176 PyGILState_STATE state = PyGILState_Ensure();
1178 ret = PyObject_CallFunction(py_finish_fn, "lOO", revision, py_revprops, edit_baton);
1179 CB_CHECK_PYRETVAL(ret);
1181 Py_DECREF((PyObject *)edit_baton);
1184 PyGILState_Release(state);
1189 static PyObject *ra_replay_range(PyObject *self, PyObject *args)
1191 #if ONLY_SINCE_SVN(1, 5)
1192 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1193 apr_pool_t *temp_pool;
1194 svn_revnum_t start_revision, end_revision, low_water_mark;
1196 bool send_deltas = true;
1198 if (!PyArg_ParseTuple(args, "lllO|b:replay_range", &start_revision, &end_revision, &low_water_mark, &cbs, &send_deltas))
1201 if (!PyTuple_Check(cbs)) {
1202 PyErr_SetString(PyExc_TypeError, "Expected tuple with callbacks");
1206 if (ra_check_busy(ra))
1209 temp_pool = Pool(NULL);
1210 if (temp_pool == NULL)
1214 RUN_RA_WITH_POOL(temp_pool, ra,
1215 svn_ra_replay_range(ra->ra, start_revision, end_revision, low_water_mark,
1216 send_deltas, py_revstart_cb, py_revfinish_cb, cbs,
1218 apr_pool_destroy(temp_pool);
1222 PyErr_SetString(PyExc_NotImplementedError,
1223 "svn_ra_replay not available with Subversion 1.4");
1230 static PyObject *ra_rev_proplist(PyObject *self, PyObject *args)
1232 apr_pool_t *temp_pool;
1234 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1237 if (!PyArg_ParseTuple(args, "l:rev_proplist", &rev))
1240 if (ra_check_busy(ra))
1243 temp_pool = Pool(NULL);
1244 if (temp_pool == NULL)
1246 RUN_RA_WITH_POOL(temp_pool, ra,
1247 svn_ra_rev_proplist(ra->ra, rev, &props, temp_pool));
1248 py_props = prop_hash_to_dict(props);
1249 apr_pool_destroy(temp_pool);
1253 static PyObject *get_commit_editor(PyObject *self, PyObject *args, PyObject *kwargs)
1255 char *kwnames[] = { "revprops", "callback", "lock_tokens", "keep_locks",
1257 PyObject *revprops, *commit_callback = Py_None, *lock_tokens = Py_None;
1258 bool keep_locks = false;
1260 const svn_delta_editor_t *editor;
1262 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1263 apr_hash_t *hash_lock_tokens;
1264 #if ONLY_SINCE_SVN(1, 5)
1265 apr_hash_t *hash_revprops;
1268 PyObject *py_log_msg;
1272 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOb:get_commit_editor",
1273 kwnames, &revprops, &commit_callback, &lock_tokens, &keep_locks))
1279 if (lock_tokens == Py_None) {
1280 hash_lock_tokens = NULL;
1284 hash_lock_tokens = apr_hash_make(pool);
1285 while (PyDict_Next(lock_tokens, &idx, &k, &v)) {
1286 if (!PyBytes_Check(k)) {
1287 PyErr_SetString(PyExc_TypeError, "token not bytes");
1290 apr_hash_set(hash_lock_tokens, PyBytes_AsString(k),
1291 PyString_Size(k), PyBytes_AsString(v));
1295 if (!PyDict_Check(revprops)) {
1296 PyErr_SetString(PyExc_TypeError, "Expected dictionary with revision properties");
1300 if (ra_check_busy(ra))
1303 Py_INCREF(commit_callback);
1305 #if ONLY_SINCE_SVN(1, 5)
1306 hash_revprops = prop_dict_to_hash(pool, revprops);
1307 if (hash_revprops == NULL) {
1310 Py_BEGIN_ALLOW_THREADS
1311 err = svn_ra_get_commit_editor3(ra->ra, &editor,
1313 hash_revprops, py_commit_callback,
1314 commit_callback, hash_lock_tokens, keep_locks, pool);
1316 /* Check that revprops has only one member named SVN_PROP_REVISION_LOG */
1317 if (PyDict_Size(revprops) != 1) {
1318 PyErr_SetString(PyExc_ValueError, "Only svn:log can be set with Subversion 1.4");
1322 py_log_msg = PyDict_GetItemString(revprops, SVN_PROP_REVISION_LOG);
1323 if (py_log_msg == NULL) {
1324 PyErr_SetString(PyExc_ValueError, "Only svn:log can be set with Subversion 1.4.");
1328 log_msg = py_object_to_svn_string(py_log_msg, pool);
1329 if (log_msg == NULL) {
1333 Py_BEGIN_ALLOW_THREADS
1334 err = svn_ra_get_commit_editor2(ra->ra, &editor,
1336 log_msg, py_commit_callback,
1337 commit_callback, hash_lock_tokens, keep_locks, pool);
1339 Py_END_ALLOW_THREADS
1342 handle_svn_error(err);
1343 svn_error_clear(err);
1348 return new_editor_object(NULL, editor, edit_baton, pool,
1349 &Editor_Type, ra_done_handler, ra, commit_callback);
1352 Py_DECREF(commit_callback);
1355 apr_pool_destroy(pool);
1360 static PyObject *ra_change_rev_prop(PyObject *self, PyObject *args)
1364 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1367 apr_pool_t *temp_pool;
1368 svn_string_t *val_string;
1370 if (!PyArg_ParseTuple(args, "lss#:change_rev_prop", &rev, &name, &value,
1373 if (ra_check_busy(ra))
1376 temp_pool = Pool(NULL);
1377 if (temp_pool == NULL)
1379 val_string = svn_string_ncreate(value, vallen, temp_pool);
1380 RUN_RA_WITH_POOL(temp_pool, ra,
1381 svn_ra_change_rev_prop(ra->ra, rev, name, val_string,
1383 apr_pool_destroy(temp_pool);
1388 static PyObject *ra_get_dir(PyObject *self, PyObject *args, PyObject *kwargs)
1390 apr_pool_t *temp_pool;
1391 apr_hash_t *dirents;
1392 apr_hash_index_t *idx;
1394 svn_revnum_t fetch_rev;
1396 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1397 svn_dirent_t *dirent;
1401 svn_revnum_t revision = -1;
1402 unsigned int dirent_fields = 0;
1403 PyObject *py_dirents, *py_props;
1404 char *kwnames[] = { "path", "revision", "fields", NULL };
1406 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|lI:get_dir", kwnames,
1407 &py_path, &revision, &dirent_fields))
1410 if (ra_check_busy(ra))
1413 temp_pool = Pool(NULL);
1414 if (temp_pool == NULL)
1417 if (revision != SVN_INVALID_REVNUM)
1418 fetch_rev = revision;
1420 path = py_object_to_svn_relpath(py_path, temp_pool);
1424 /* Yuck. Subversion doesn't like leading slashes.. */
1425 while (*path == '/') path++;
1427 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_dir2(ra->ra, &dirents, &fetch_rev, &props,
1428 path, revision, dirent_fields, temp_pool));
1430 if (dirents == NULL) {
1431 py_dirents = Py_None;
1432 Py_INCREF(py_dirents);
1434 py_dirents = PyDict_New();
1435 if (py_dirents == NULL) {
1438 idx = apr_hash_first(temp_pool, dirents);
1439 while (idx != NULL) {
1440 PyObject *item, *pykey;
1441 apr_hash_this(idx, (const void **)&key, &klen, (void **)&dirent);
1442 item = py_dirent(dirent, dirent_fields);
1450 pykey = PyString_FromString((char *)key);
1452 if (PyDict_SetItem(py_dirents, pykey, item) != 0) {
1459 idx = apr_hash_next(idx);
1463 py_props = prop_hash_to_dict(props);
1464 if (py_props == NULL) {
1467 apr_pool_destroy(temp_pool);
1468 return Py_BuildValue("(NlN)", py_dirents, fetch_rev, py_props);
1471 Py_DECREF(py_dirents);
1473 apr_pool_destroy(temp_pool);
1477 static PyObject *ra_get_file(PyObject *self, PyObject *args)
1481 svn_revnum_t revision = -1;
1482 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1484 svn_revnum_t fetch_rev;
1485 PyObject *py_stream, *py_props;
1486 apr_pool_t *temp_pool;
1488 if (!PyArg_ParseTuple(args, "OO|l:get_file", &py_path, &py_stream, &revision))
1491 if (ra_check_busy(ra))
1494 temp_pool = Pool(NULL);
1495 if (temp_pool == NULL)
1498 if (revision != SVN_INVALID_REVNUM)
1499 fetch_rev = revision;
1501 path = py_object_to_svn_relpath(py_path, temp_pool);
1505 /* Yuck. Subversion doesn't like leading slashes.. */
1506 while (*path == '/') path++;
1508 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_file(ra->ra, path, revision,
1509 new_py_stream(temp_pool, py_stream),
1510 &fetch_rev, &props, temp_pool));
1512 py_props = prop_hash_to_dict(props);
1513 if (py_props == NULL) {
1514 apr_pool_destroy(temp_pool);
1518 apr_pool_destroy(temp_pool);
1520 return Py_BuildValue("(lN)", fetch_rev, py_props);
1523 static PyObject *ra_get_lock(PyObject *self, PyObject *args)
1526 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1528 apr_pool_t *temp_pool;
1530 if (!PyArg_ParseTuple(args, "s:get_lock", &path))
1533 if (ra_check_busy(ra))
1536 temp_pool = Pool(NULL);
1537 if (temp_pool == NULL)
1539 RUN_RA_WITH_POOL(temp_pool, ra,
1540 svn_ra_get_lock(ra->ra, &lock, path, temp_pool));
1541 apr_pool_destroy(temp_pool);
1542 return wrap_lock(lock);
1545 static PyObject *ra_check_path(PyObject *self, PyObject *args)
1548 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1549 svn_revnum_t revision;
1550 svn_node_kind_t kind;
1552 apr_pool_t *temp_pool;
1554 if (!PyArg_ParseTuple(args, "Ol:check_path", &py_path, &revision))
1556 if (ra_check_busy(ra))
1559 temp_pool = Pool(NULL);
1560 if (temp_pool == NULL)
1563 path = py_object_to_svn_relpath(py_path, temp_pool);
1567 if (ra_check_svn_path(path))
1570 RUN_RA_WITH_POOL(temp_pool, ra,
1571 svn_ra_check_path(ra->ra, path, revision, &kind,
1573 apr_pool_destroy(temp_pool);
1574 return PyInt_FromLong(kind);
1577 static PyObject *ra_stat(PyObject *self, PyObject *args)
1581 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1583 svn_revnum_t revision;
1584 svn_dirent_t *dirent;
1585 apr_pool_t *temp_pool;
1587 if (!PyArg_ParseTuple(args, "Ol:stat", &py_path, &revision))
1589 if (ra_check_busy(ra))
1592 temp_pool = Pool(NULL);
1593 if (temp_pool == NULL)
1596 path = py_object_to_svn_relpath(py_path, temp_pool);
1600 if (ra_check_svn_path(path))
1603 RUN_RA_WITH_POOL(temp_pool, ra,
1604 svn_ra_stat(ra->ra, path, revision, &dirent,
1606 ret = py_dirent(dirent, SVN_DIRENT_ALL);
1607 apr_pool_destroy(temp_pool);
1611 static PyObject *ra_has_capability(PyObject *self, PyObject *args)
1613 #if ONLY_SINCE_SVN(1, 5)
1615 apr_pool_t *temp_pool;
1616 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1619 if (!PyArg_ParseTuple(args, "s:has_capability", &capability))
1622 if (ra_check_busy(ra))
1625 temp_pool = Pool(NULL);
1626 if (temp_pool == NULL)
1628 RUN_RA_WITH_POOL(temp_pool, ra,
1629 svn_ra_has_capability(ra->ra, &has, capability, temp_pool));
1630 apr_pool_destroy(temp_pool);
1631 return PyBool_FromLong(has);
1633 PyErr_SetString(PyExc_NotImplementedError, "has_capability is only supported in Subversion >= 1.5");
1638 static PyObject *ra_unlock(PyObject *self, PyObject *args)
1640 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1641 PyObject *path_tokens, *lock_func, *k, *v;
1644 apr_pool_t *temp_pool;
1645 apr_hash_t *hash_path_tokens;
1647 if (!PyArg_ParseTuple(args, "ObO:unlock", &path_tokens, &break_lock, &lock_func))
1650 if (ra_check_busy(ra))
1653 temp_pool = Pool(NULL);
1654 if (temp_pool == NULL)
1656 hash_path_tokens = apr_hash_make(temp_pool);
1657 while (PyDict_Next(path_tokens, &idx, &k, &v)) {
1658 if (!PyBytes_Check(k)) {
1659 PyErr_SetString(PyExc_TypeError, "token not bytes");
1662 apr_hash_set(hash_path_tokens, PyBytes_AsString(k), PyBytes_Size(k), (char *)PyString_AsString(v));
1664 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_unlock(ra->ra, hash_path_tokens, break_lock,
1665 py_lock_func, lock_func, temp_pool));
1667 apr_pool_destroy(temp_pool);
1671 apr_pool_destroy(temp_pool);
1678 static PyObject *ra_lock(PyObject *self, PyObject *args)
1680 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1681 PyObject *path_revs;
1684 PyObject *lock_func, *k, *v;
1685 apr_pool_t *temp_pool;
1686 apr_hash_t *hash_path_revs;
1690 if (!PyArg_ParseTuple(args, "OsbO:lock", &path_revs, &comment, &steal_lock,
1694 if (ra_check_busy(ra))
1697 temp_pool = Pool(NULL);
1698 if (temp_pool == NULL)
1700 if (path_revs == Py_None) {
1701 hash_path_revs = NULL;
1703 hash_path_revs = apr_hash_make(temp_pool);
1706 while (PyDict_Next(path_revs, &idx, &k, &v)) {
1707 rev = (svn_revnum_t *)apr_palloc(temp_pool, sizeof(svn_revnum_t));
1708 *rev = PyInt_AsLong(v);
1709 if (*rev == -1 && PyErr_Occurred()) {
1712 if (!PyBytes_Check(k)) {
1713 PyErr_SetString(PyExc_TypeError, "token not bytes");
1716 apr_hash_set(hash_path_revs, PyBytes_AsString(k), PyBytes_Size(k), rev);
1718 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_lock(ra->ra, hash_path_revs, comment, steal_lock,
1719 py_lock_func, lock_func, temp_pool));
1720 apr_pool_destroy(temp_pool);
1724 apr_pool_destroy(temp_pool);
1731 static PyObject *ra_get_locks(PyObject *self, PyObject *args)
1735 apr_pool_t *temp_pool;
1736 apr_hash_t *hash_locks;
1737 apr_hash_index_t *idx;
1738 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1739 svn_depth_t depth = svn_depth_infinity;
1745 if (!PyArg_ParseTuple(args, "O|i:get_locks", &py_path, &depth))
1748 if (ra_check_busy(ra))
1751 temp_pool = Pool(NULL);
1752 if (temp_pool == NULL)
1755 path = py_object_to_svn_relpath(py_path, temp_pool);
1759 if (ra_check_svn_path(path))
1762 #if ONLY_SINCE_SVN(1, 7)
1763 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_locks2(ra->ra, &hash_locks, path, depth, temp_pool));
1765 if (depth != svn_depth_infinity) {
1766 PyErr_SetString(PyExc_NotImplementedError,
1767 "depth != infinity only supported for svn >= 1.7");
1771 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_locks(ra->ra, &hash_locks, path, temp_pool));
1776 apr_pool_destroy(temp_pool);
1779 for (idx = apr_hash_first(temp_pool, hash_locks); idx != NULL;
1780 idx = apr_hash_next(idx)) {
1782 apr_hash_this(idx, (const void **)&key, &klen, (void **)&lock);
1783 pyval = pyify_lock(lock);
1784 if (pyval == NULL) {
1786 apr_pool_destroy(temp_pool);
1789 if (PyDict_SetItemString(ret, key, pyval) != 0) {
1790 apr_pool_destroy(temp_pool);
1798 apr_pool_destroy(temp_pool);
1802 static PyObject *ra_get_locations(PyObject *self, PyObject *args)
1806 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1807 svn_revnum_t peg_revision;
1808 PyObject *location_revisions;
1809 apr_pool_t *temp_pool;
1810 apr_hash_t *hash_locations;
1811 apr_hash_index_t *idx;
1817 if (!PyArg_ParseTuple(args, "OlO:get_locations", &py_path, &peg_revision, &location_revisions))
1820 if (ra_check_busy(ra))
1823 temp_pool = Pool(NULL);
1824 if (temp_pool == NULL)
1827 path = py_object_to_svn_relpath(py_path, temp_pool);
1831 if (ra_check_svn_path(path))
1834 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_locations(ra->ra, &hash_locations,
1836 revnum_list_to_apr_array(temp_pool, location_revisions),
1843 for (idx = apr_hash_first(temp_pool, hash_locations); idx != NULL;
1844 idx = apr_hash_next(idx)) {
1845 apr_hash_this(idx, (const void **)&key, &klen, (void **)&val);
1846 if (PyDict_SetItem(ret, PyInt_FromLong(*key), PyString_FromString(val)) != 0) {
1850 apr_pool_destroy(temp_pool);
1856 apr_pool_destroy(temp_pool);
1863 #if ONLY_SINCE_SVN(1, 5)
1864 static PyObject *range_to_tuple(svn_merge_range_t *range)
1866 return Py_BuildValue("(llb)", range->start, range->end, range->inheritable);
1869 static PyObject *merge_rangelist_to_list(apr_array_header_t *rangelist)
1874 ret = PyList_New(rangelist->nelts);
1878 for (i = 0; i < rangelist->nelts; i++) {
1880 pyval = range_to_tuple(APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *));
1881 if (pyval == NULL) {
1885 if (PyList_SetItem(ret, i, pyval) != 0) {
1895 static PyObject *mergeinfo_to_dict(svn_mergeinfo_t mergeinfo, apr_pool_t *temp_pool)
1900 apr_hash_index_t *idx;
1901 apr_array_header_t *range;
1908 for (idx = apr_hash_first(temp_pool, mergeinfo); idx != NULL;
1909 idx = apr_hash_next(idx)) {
1911 apr_hash_this(idx, (const void **)&key, &klen, (void **)&range);
1912 pyval = merge_rangelist_to_list(range);
1913 if (pyval == NULL) {
1917 if (PyDict_SetItemString(ret, key, pyval) != 0) {
1929 static PyObject *ra_mergeinfo(PyObject *self, PyObject *args)
1931 #if ONLY_SINCE_SVN(1, 5)
1932 RemoteAccessObject *ra = (RemoteAccessObject *)self;
1933 apr_array_header_t *apr_paths;
1934 apr_pool_t *temp_pool;
1935 svn_mergeinfo_catalog_t catalog;
1937 apr_hash_index_t *idx;
1938 svn_mergeinfo_t val;
1941 svn_revnum_t revision = -1;
1943 svn_mergeinfo_inheritance_t inherit = svn_mergeinfo_explicit;
1944 svn_boolean_t include_descendants;
1946 if (!PyArg_ParseTuple(args, "O|lib:mergeinfo", &paths, &revision, &inherit, &include_descendants))
1949 temp_pool = Pool(NULL);
1950 if (temp_pool == NULL)
1953 if (!path_list_to_apr_array(temp_pool, paths, &apr_paths)) {
1954 apr_pool_destroy(temp_pool);
1958 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_mergeinfo(ra->ra,
1959 &catalog, apr_paths, revision, inherit,
1960 include_descendants,
1965 apr_pool_destroy(temp_pool);
1969 if (catalog != NULL) {
1970 for (idx = apr_hash_first(temp_pool, catalog); idx != NULL;
1971 idx = apr_hash_next(idx)) {
1973 apr_hash_this(idx, (const void **)&key, &klen, (void **)&val);
1974 pyval = mergeinfo_to_dict(val, temp_pool);
1975 if (pyval == NULL) {
1976 apr_pool_destroy(temp_pool);
1980 if (PyDict_SetItemString(ret, key, pyval) != 0) {
1981 apr_pool_destroy(temp_pool);
1991 apr_pool_destroy(temp_pool);
1995 PyErr_SetString(PyExc_NotImplementedError, "mergeinfo is only supported in Subversion >= 1.5");
2000 #if ONLY_SINCE_SVN(1, 5)
2001 static svn_error_t *py_location_segment_receiver(svn_location_segment_t *segment, void *baton, apr_pool_t *pool)
2003 PyObject *fn = baton, *ret;
2004 PyGILState_STATE state = PyGILState_Ensure();
2006 ret = PyObject_CallFunction(fn, "llz", segment->range_start, segment->range_end, segment->path);
2007 CB_CHECK_PYRETVAL(ret);
2009 PyGILState_Release(state);
2014 static PyObject *ra_get_location_segments(PyObject *self, PyObject *args)
2016 #if ONLY_SINCE_SVN(1, 5)
2017 RemoteAccessObject *ra = (RemoteAccessObject *)self;
2018 svn_revnum_t peg_revision, start_revision, end_revision;
2022 apr_pool_t *temp_pool;
2024 if (!PyArg_ParseTuple(args, "OlllO:get_location_segments", &py_path,
2025 &peg_revision, &start_revision, &end_revision, &py_rcvr))
2028 temp_pool = Pool(NULL);
2029 if (temp_pool == NULL)
2032 path = py_object_to_svn_relpath(py_path, temp_pool);
2036 if (ra_check_svn_path(path))
2039 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_location_segments(ra->ra,
2040 path, peg_revision, start_revision, end_revision,
2041 py_location_segment_receiver,
2042 py_rcvr, temp_pool));
2044 apr_pool_destroy(temp_pool);
2047 PyErr_SetString(PyExc_NotImplementedError, "mergeinfo is only supported in Subversion >= 1.5");
2053 static PyObject *ra_get_file_revs(PyObject *self, PyObject *args)
2056 svn_revnum_t start, end;
2057 PyObject *file_rev_handler;
2058 apr_pool_t *temp_pool;
2059 RemoteAccessObject *ra = (RemoteAccessObject *)self;
2060 svn_boolean_t include_merged_revisions = FALSE;
2062 if (!PyArg_ParseTuple(args, "sllO|b:get_file_revs", &path, &start,
2063 &end, &file_rev_handler, &include_merged_revisions))
2066 if (ra_check_svn_path(path))
2069 if (ra_check_busy(ra))
2072 temp_pool = Pool(NULL);
2073 if (temp_pool == NULL)
2076 #if ONLY_SINCE_SVN(1, 5)
2077 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_file_revs2(ra->ra, path, start, end,
2078 include_merged_revisions,
2079 py_file_rev_handler, (void *)file_rev_handler,
2082 if (include_merged_revisions) {
2083 PyErr_SetString(PyExc_NotImplementedError,
2084 "include_merged_revisions only supported with svn >= 1.5");
2085 apr_pool_destroy(temp_pool);
2088 RUN_RA_WITH_POOL(temp_pool, ra, svn_ra_get_file_revs(ra->ra, path, start, end,
2089 py_ra_file_rev_handler, (void *)file_rev_handler, temp_pool));
2092 apr_pool_destroy(temp_pool);
2097 static void ra_dealloc(PyObject *self)
2099 RemoteAccessObject *ra = (RemoteAccessObject *)self;
2100 Py_XDECREF(ra->client_string_func);
2101 Py_XDECREF(ra->progress_func);
2102 Py_XDECREF(ra->auth);
2103 apr_pool_destroy(ra->pool);
2107 static PyObject *ra_repr(PyObject *self)
2109 RemoteAccessObject *ra = (RemoteAccessObject *)self;
2110 return PyRepr_FromFormat("RemoteAccess(\"%s\")", ra->url);
2113 static int ra_set_progress_func(PyObject *self, PyObject *value, void *closure)
2115 RemoteAccessObject *ra = (RemoteAccessObject *)self;
2116 Py_XDECREF(ra->progress_func);
2117 ra->progress_func = value;
2118 Py_INCREF(ra->progress_func);
2122 static PyGetSetDef ra_getsetters[] = {
2123 { "progress_func", NULL, ra_set_progress_func, NULL },
2127 #include "_ra_iter_log.c"
2129 static PyMethodDef ra_methods[] = {
2130 { "get_file_revs", ra_get_file_revs, METH_VARARGS,
2131 "S.get_file_revs(path, start_rev, end_revs, handler)" },
2132 { "get_locations", ra_get_locations, METH_VARARGS,
2133 "S.get_locations(path, peg_revision, location_revisions)" },
2134 { "get_locks", ra_get_locks, METH_VARARGS,
2135 "S.get_locks(path, depth=DEPTH_INFINITY)" },
2136 { "lock", ra_lock, METH_VARARGS,
2137 "S.lock(path_revs, comment, steal_lock, lock_func)\n" },
2138 { "unlock", ra_unlock, METH_VARARGS,
2139 "S.unlock(path_tokens, break_lock, lock_func)\n" },
2140 { "mergeinfo", ra_mergeinfo, METH_VARARGS,
2141 "S.mergeinfo(paths, revision, inherit, include_descendants)\n" },
2142 { "get_location_segments", ra_get_location_segments, METH_VARARGS,
2143 "S.get_location_segments(path, peg_revision, start_revision, "
2144 "end_revision, rcvr)\n"
2145 "The receiver is called as rcvr(range_start, range_end, path)\n"
2147 { "has_capability", ra_has_capability, METH_VARARGS,
2148 "S.has_capability(name) -> bool\n"
2149 "Check whether the specified capability is supported by the client and server" },
2150 { "check_path", ra_check_path, METH_VARARGS,
2151 "S.check_path(path, revnum) -> node_kind\n"
2152 "Check the type of a path (one of NODE_DIR, NODE_FILE, NODE_UNKNOWN)" },
2153 { "stat", ra_stat, METH_VARARGS,
2154 "S.stat(path, revnum) -> dirent\n" },
2155 { "get_lock", ra_get_lock, METH_VARARGS,
2156 "S.get_lock(path) -> lock\n"
2158 { "get_dir", (PyCFunction)ra_get_dir, METH_VARARGS|METH_KEYWORDS,
2159 "S.get_dir(path, revision, dirent_fields=-1) -> (dirents, fetched_rev, properties)\n"
2160 "Get the contents of a directory. "},
2161 { "get_file", ra_get_file, METH_VARARGS,
2162 "S.get_file(path, stream, revnum=-1) -> (fetched_rev, properties)\n"
2163 "Fetch a file. The contents will be written to stream." },
2164 { "change_rev_prop", ra_change_rev_prop, METH_VARARGS,
2165 "S.change_rev_prop(revnum, name, value)\n"
2166 "Change a revision property" },
2167 { "get_commit_editor", (PyCFunction)get_commit_editor, METH_VARARGS|METH_KEYWORDS,
2168 "S.get_commit_editor(revprops, commit_callback, lock_tokens, keep_locks) -> editor\n"
2170 { "rev_proplist", ra_rev_proplist, METH_VARARGS,
2171 "S.rev_proplist(revnum) -> properties\n"
2172 "Return a dictionary with the properties set on the specified revision" },
2173 { "replay", ra_replay, METH_VARARGS,
2174 "S.replay(revision, low_water_mark, update_editor, send_deltas=True)\n"
2175 "Replay a revision, reporting changes to update_editor." },
2176 { "replay_range", ra_replay_range, METH_VARARGS,
2177 "S.replay_range(start_rev, end_rev, low_water_mark, cbs, send_deltas=True)\n"
2178 "Replay a range of revisions, reporting them to an update editor.\n"
2179 "cbs is a two-tuple with two callbacks:\n"
2180 "- start_rev_cb(revision, revprops) -> editor\n"
2181 "- finish_rev_cb(revision, revprops, editor)\n"
2183 { "do_switch", ra_do_switch, METH_VARARGS,
2184 "S.do_switch(revision_to_update_to, update_target, recurse, switch_url, update_editor)\n" },
2185 { "do_update", ra_do_update, METH_VARARGS,
2186 "S.do_update(revision_to_update_to, update_target, recurse, update_editor)\n" },
2187 { "do_diff", ra_do_diff, METH_VARARGS,
2188 "S.do_diff(revision_to_update_to, diff_target, versus_url, diff_editor, recurse, ignore_ancestry, text_deltas) -> Reporter object\n"
2190 { "get_repos_root", (PyCFunction)ra_get_repos_root, METH_NOARGS,
2191 "S.get_repos_root() -> url\n"
2192 "Return the URL to the root of the repository." },
2193 { "get_url", (PyCFunction)ra_get_url, METH_NOARGS,
2194 "S.get_url() -> url\n"
2195 "Return the URL of the repository." },
2196 { "get_log", (PyCFunction)ra_get_log, METH_VARARGS|METH_KEYWORDS,
2197 "S.get_log(callback, paths, start, end, limit=0, "
2198 "discover_changed_paths=False, strict_node_history=True, "
2199 "include_merged_revisions=False, revprops=None)\n"
2200 "The callback is passed three or four arguments:\n"
2201 "callback(changed_paths, revision, revprops[, has_children])\n"
2202 "The changed_paths argument may be None, or a dictionary mapping each\n"
2203 "path to a tuple:\n"
2204 "(action, from_path, from_rev)\n"
2206 { "iter_log", (PyCFunction)ra_iter_log, METH_VARARGS|METH_KEYWORDS,
2207 "S.iter_log(paths, start, end, limit=0, "
2208 "discover_changed_paths=False, strict_node_history=True, "
2209 "include_merged_revisions=False, revprops=None)\n"
2210 "Yields tuples of three or four elements:\n"
2211 "(changed_paths, revision, revprops[, has_children])\n"
2212 "The changed_paths element may be None, or a dictionary mapping each\n"
2213 "path to a tuple:\n"
2214 "(action, from_path, from_rev, node_kind)\n"
2215 "This method collects the log entries in another thread. Before calling\n"
2216 "any further methods, make sure the thread has completed by running the\n"
2217 "iterator to exhaustion (i.e. until StopIteration is raised, the \"for\"\n"
2218 "loop finishes, etc).\n"
2220 { "get_latest_revnum", (PyCFunction)ra_get_latest_revnum, METH_NOARGS,
2221 "S.get_latest_revnum() -> int\n"
2222 "Return the last revision committed in the repository." },
2223 { "reparent", ra_reparent, METH_VARARGS,
2225 "Reparent to a new URL" },
2226 { "get_uuid", (PyCFunction)ra_get_uuid, METH_NOARGS,
2227 "S.get_uuid() -> uuid\n"
2228 "Return the UUID of the repository." },
2232 static PyMemberDef ra_members[] = {
2233 { "busy", T_BYTE, offsetof(RemoteAccessObject, busy), READONLY,
2234 "Whether this connection is in use at the moment" },
2235 { "url", T_STRING, offsetof(RemoteAccessObject, url), READONLY,
2236 "URL this connection is to" },
2237 { "corrected_url", T_STRING, offsetof(RemoteAccessObject, corrected_url), READONLY,
2242 static PyTypeObject RemoteAccess_Type = {
2243 PyVarObject_HEAD_INIT(NULL, 0)
2244 "_ra.RemoteAccess", /* const char *tp_name; For printing, in format "<module>.<name>" */
2245 sizeof(RemoteAccessObject),
2246 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
2248 /* Methods to implement standard operations */
2250 ra_dealloc, /* destructor tp_dealloc; */
2251 NULL, /* printfunc tp_print; */
2252 NULL, /* getattrfunc tp_getattr; */
2253 NULL, /* setattrfunc tp_setattr; */
2254 NULL, /* cmpfunc tp_compare; */
2255 ra_repr, /* reprfunc tp_repr; */
2257 /* Method suites for standard classes */
2259 NULL, /* PyNumberMethods *tp_as_number; */
2260 NULL, /* PySequenceMethods *tp_as_sequence; */
2261 NULL, /* PyMappingMethods *tp_as_mapping; */
2263 /* More standard operations (here for binary compatibility) */
2265 NULL, /* hashfunc tp_hash; */
2266 NULL, /* ternaryfunc tp_call; */
2267 NULL, /* reprfunc tp_str; */
2268 NULL, /* getattrofunc tp_getattro; */
2269 NULL, /* setattrofunc tp_setattro; */
2271 /* Functions to access object as input/output buffer */
2272 NULL, /* PyBufferProcs *tp_as_buffer; */
2274 /* Flags to define presence of optional/expanded features */
2275 Py_TPFLAGS_BASETYPE, /* long tp_flags; */
2277 NULL, /* const char *tp_doc; Documentation string */
2279 /* Assigned meaning in release 2.0 */
2280 /* call function for all accessible objects */
2281 NULL, /* traverseproc tp_traverse; */
2283 /* delete references to contained objects */
2284 NULL, /* inquiry tp_clear; */
2286 /* Assigned meaning in release 2.1 */
2287 /* rich comparisons */
2288 NULL, /* richcmpfunc tp_richcompare; */
2290 /* weak reference enabler */
2291 0, /* Py_ssize_t tp_weaklistoffset; */
2293 /* Added in release 2.2 */
2295 NULL, /* getiterfunc tp_iter; */
2296 NULL, /* iternextfunc tp_iternext; */
2298 /* Attribute descriptor and subclassing stuff */
2299 ra_methods, /* struct PyMethodDef *tp_methods; */
2300 ra_members, /* struct PyMemberDef *tp_members; */
2301 ra_getsetters, /* struct PyGetSetDef *tp_getset; */
2302 NULL, /* struct _typeobject *tp_base; */
2303 NULL, /* PyObject *tp_dict; */
2304 NULL, /* descrgetfunc tp_descr_get; */
2305 NULL, /* descrsetfunc tp_descr_set; */
2306 0, /* Py_ssize_t tp_dictoffset; */
2307 NULL, /* initproc tp_init; */
2308 NULL, /* allocfunc tp_alloc; */
2309 ra_new, /* newfunc tp_new; */
2316 svn_auth_provider_object_t *provider;
2318 } AuthProviderObject;
2320 static void auth_provider_dealloc(PyObject *self)
2322 AuthProviderObject *auth_provider = (AuthProviderObject *)self;
2323 Py_XDECREF(auth_provider->callback);
2324 auth_provider->callback = NULL;
2325 apr_pool_destroy(auth_provider->pool);
2329 static PyTypeObject AuthProvider_Type = {
2330 PyVarObject_HEAD_INIT(NULL, 0)
2331 "_ra.AuthProvider", /* const char *tp_name; For printing, in format "<module>.<name>" */
2332 sizeof(AuthProviderObject),
2333 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
2335 /* Methods to implement standard operations */
2337 auth_provider_dealloc, /* destructor tp_dealloc; */
2341 static PyObject *auth_init(PyTypeObject *type, PyObject *args, PyObject *kwargs)
2343 char *kwnames[] = { "providers", NULL };
2344 apr_array_header_t *c_providers;
2345 svn_auth_provider_object_t **el;
2346 PyObject *providers;
2350 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &providers))
2353 ret = PyObject_New(AuthObject, &Auth_Type);
2357 ret->providers = NULL;
2359 ret->pool = Pool(NULL);
2360 if (ret->pool == NULL) {
2366 if (!PySequence_Check(providers)) {
2367 PyErr_SetString(PyExc_TypeError, "Auth providers should be a sequence");
2372 Py_INCREF(providers);
2373 ret->providers = providers;
2375 c_providers = apr_array_make(ret->pool, PySequence_Size(providers),
2376 sizeof(svn_auth_provider_object_t *));
2377 if (c_providers == NULL) {
2382 for (i = 0; i < PySequence_Size(providers); i++) {
2383 AuthProviderObject *provider;
2384 el = (svn_auth_provider_object_t **)apr_array_push(c_providers);
2385 provider = (AuthProviderObject *)PySequence_GetItem(providers, i);
2386 if (!PyObject_TypeCheck(provider, &AuthProvider_Type)) {
2387 PyErr_SetString(PyExc_TypeError, "Invalid auth provider");
2391 *el = provider->provider;
2393 svn_auth_open(&ret->auth_baton, c_providers, ret->pool);
2394 return (PyObject *)ret;
2397 static PyObject *auth_set_parameter(PyObject *self, PyObject *args)
2399 AuthObject *auth = (AuthObject *)self;
2403 if (!PyArg_ParseTuple(args, "sO:set_parameter", &name, &value))
2406 if (!strcmp(name, SVN_AUTH_PARAM_SSL_SERVER_FAILURES)) {
2407 long ret = PyInt_AsLong(value);
2408 if (ret == -1 && PyErr_Occurred())
2410 vvalue = apr_pcalloc(auth->pool, sizeof(apr_uint32_t));
2411 *((apr_uint32_t *)vvalue) = ret;
2412 } else if (!strcmp(name, SVN_AUTH_PARAM_DEFAULT_USERNAME) ||
2413 !strcmp(name, SVN_AUTH_PARAM_DEFAULT_PASSWORD)) {
2414 vvalue = py_object_to_svn_string(value, auth->pool);
2415 if (vvalue == NULL) {
2419 PyErr_Format(PyExc_TypeError, "Unsupported auth parameter %s", name);
2423 svn_auth_set_parameter(auth->auth_baton, name, (char *)vvalue);
2428 static PyObject *auth_get_parameter(PyObject *self, PyObject *args)
2432 AuthObject *auth = (AuthObject *)self;
2434 if (!PyArg_ParseTuple(args, "s:get_parameter", &name))
2437 value = svn_auth_get_parameter(auth->auth_baton, name);
2439 if (!strcmp(name, SVN_AUTH_PARAM_SSL_SERVER_FAILURES)) {
2440 return PyInt_FromLong(*((apr_uint32_t *)value));
2441 } else if (!strcmp(name, SVN_AUTH_PARAM_DEFAULT_USERNAME) ||
2442 !strcmp(name, SVN_AUTH_PARAM_DEFAULT_PASSWORD)) {
2443 return PyString_FromString((const char *)value);
2445 PyErr_Format(PyExc_TypeError, "Unsupported auth parameter %s", name);
2454 svn_auth_iterstate_t *state;
2456 } CredentialsIterObject;
2458 static PyObject *auth_first_credentials(PyObject *self, PyObject *args)
2462 AuthObject *auth = (AuthObject *)self;
2465 CredentialsIterObject *ret;
2466 svn_auth_iterstate_t *state;
2468 if (!PyArg_ParseTuple(args, "ss:credentials", &cred_kind, &realmstring))
2475 RUN_SVN_WITH_POOL(pool,
2476 svn_auth_first_credentials(&creds, &state, cred_kind, realmstring, auth->auth_baton, pool));
2478 ret = PyObject_New(CredentialsIterObject, &CredentialsIter_Type);
2483 ret->cred_kind = apr_pstrdup(pool, cred_kind);
2485 ret->credentials = creds;
2487 return (PyObject *)ret;
2490 static void credentials_iter_dealloc(PyObject *self)
2492 CredentialsIterObject *credsiter = (CredentialsIterObject *)self;
2493 apr_pool_destroy(credsiter->pool);
2497 static PyObject *credentials_iter_next(CredentialsIterObject *iterator)
2501 if (iterator->credentials == NULL) {
2502 PyErr_SetString(PyExc_StopIteration, "No more credentials available");
2506 if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_SIMPLE)) {
2507 svn_auth_cred_simple_t *simple = iterator->credentials;
2508 ret = Py_BuildValue("(zzb)", simple->username, simple->password, simple->may_save);
2509 } else if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_USERNAME)) {
2510 svn_auth_cred_username_t *uname = iterator->credentials;
2511 ret = Py_BuildValue("(zb)", uname->username, uname->may_save);
2512 } else if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_SSL_CLIENT_CERT)) {
2513 svn_auth_cred_ssl_client_cert_t *ccert = iterator->credentials;
2514 ret = Py_BuildValue("(zb)", ccert->cert_file, ccert->may_save);
2515 } else if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_SSL_CLIENT_CERT_PW)) {
2516 svn_auth_cred_ssl_client_cert_pw_t *ccert = iterator->credentials;
2517 ret = Py_BuildValue("(zb)", ccert->password, ccert->may_save);
2518 } else if (!strcmp(iterator->cred_kind, SVN_AUTH_CRED_SSL_SERVER_TRUST)) {
2519 svn_auth_cred_ssl_server_trust_t *ccert = iterator->credentials;
2520 ret = Py_BuildValue("(ib)", ccert->accepted_failures, ccert->may_save);
2522 PyErr_Format(PyExc_RuntimeError, "Unknown cred kind %s", iterator->cred_kind);
2526 RUN_SVN_WITH_POOL(iterator->pool,
2527 svn_auth_next_credentials(&iterator->credentials, iterator->state, iterator->pool));
2532 static PyTypeObject CredentialsIter_Type = {
2533 PyVarObject_HEAD_INIT(NULL, 0)
2534 "_ra.CredentialsIter", /* const char *tp_name; For printing, in format "<module>.<name>" */
2535 sizeof(CredentialsIterObject),
2536 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
2538 /* Methods to implement standard operations */
2540 (destructor)credentials_iter_dealloc, /* destructor tp_dealloc; */
2541 NULL, /* printfunc tp_print; */
2542 NULL, /* getattrfunc tp_getattr; */
2543 NULL, /* setattrfunc tp_setattr; */
2544 NULL, /* cmpfunc tp_compare; */
2545 NULL, /* reprfunc tp_repr; */
2547 /* Method suites for standard classes */
2549 NULL, /* PyNumberMethods *tp_as_number; */
2550 NULL, /* PySequenceMethods *tp_as_sequence; */
2551 NULL, /* PyMappingMethods *tp_as_mapping; */
2553 /* More standard operations (here for binary compatibility) */
2555 NULL, /* hashfunc tp_hash; */
2556 NULL, /* ternaryfunc tp_call; */
2557 NULL, /* reprfunc tp_str; */
2558 NULL, /* getattrofunc tp_getattro; */
2559 NULL, /* setattrofunc tp_setattro; */
2561 /* Functions to access object as input/output buffer */
2562 NULL, /* PyBufferProcs *tp_as_buffer; */
2564 /* Flags to define presence of optional/expanded features */
2565 Py_TPFLAGS_HAVE_ITER, /* long tp_flags; */
2567 NULL, /* const char *tp_doc; Documentation string */
2569 /* Assigned meaning in release 2.0 */
2570 /* call function for all accessible objects */
2571 NULL, /* traverseproc tp_traverse; */
2573 /* delete references to contained objects */
2574 NULL, /* inquiry tp_clear; */
2576 /* Assigned meaning in release 2.1 */
2577 /* rich comparisons */
2578 NULL, /* richcmpfunc tp_richcompare; */
2580 /* weak reference enabler */
2581 0, /* Py_ssize_t tp_weaklistoffset; */
2583 /* Added in release 2.2 */
2585 NULL, /* getiterfunc tp_iter; */
2586 (iternextfunc)credentials_iter_next, /* iternextfunc tp_iternext; */
2590 static PyMethodDef auth_methods[] = {
2591 { "set_parameter", auth_set_parameter, METH_VARARGS,
2592 "S.set_parameter(key, value)\n"
2593 "Set a parameter" },
2594 { "get_parameter", auth_get_parameter, METH_VARARGS,
2595 "S.get_parameter(key) -> value\n"
2596 "Get a parameter" },
2597 { "credentials", auth_first_credentials, METH_VARARGS,
2602 static void auth_dealloc(PyObject *self)
2604 AuthObject *auth = (AuthObject *)self;
2605 apr_pool_destroy(auth->pool);
2606 Py_XDECREF(auth->providers);
2610 static PyTypeObject Auth_Type = {
2611 PyVarObject_HEAD_INIT(NULL, 0)
2612 "_ra.Auth", /* const char *tp_name; For printing, in format "<module>.<name>" */
2614 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
2616 /* Methods to implement standard operations */
2618 auth_dealloc, /* destructor tp_dealloc; */
2619 NULL, /* printfunc tp_print; */
2620 NULL, /* getattrfunc tp_getattr; */
2621 NULL, /* setattrfunc tp_setattr; */
2622 NULL, /* cmpfunc tp_compare; */
2623 NULL, /* reprfunc tp_repr; */
2625 /* Method suites for standard classes */
2627 NULL, /* PyNumberMethods *tp_as_number; */
2628 NULL, /* PySequenceMethods *tp_as_sequence; */
2629 NULL, /* PyMappingMethods *tp_as_mapping; */
2631 /* More standard operations (here for binary compatibility) */
2633 NULL, /* hashfunc tp_hash; */
2634 NULL, /* ternaryfunc tp_call; */
2635 NULL, /* reprfunc tp_str; */
2636 NULL, /* getattrofunc tp_getattro; */
2637 NULL, /* setattrofunc tp_setattro; */
2639 /* Functions to access object as input/output buffer */
2640 NULL, /* PyBufferProcs *tp_as_buffer; */
2642 /* Flags to define presence of optional/expanded features */
2643 0, /* long tp_flags; */
2645 NULL, /* const char *tp_doc; Documentation string */
2647 /* Assigned meaning in release 2.0 */
2648 /* call function for all accessible objects */
2649 NULL, /* traverseproc tp_traverse; */
2651 /* delete references to contained objects */
2652 NULL, /* inquiry tp_clear; */
2654 /* Assigned meaning in release 2.1 */
2655 /* rich comparisons */
2656 NULL, /* richcmpfunc tp_richcompare; */
2658 /* weak reference enabler */
2659 0, /* Py_ssize_t tp_weaklistoffset; */
2661 /* Added in release 2.2 */
2663 NULL, /* getiterfunc tp_iter; */
2664 NULL, /* iternextfunc tp_iternext; */
2666 /* Attribute descriptor and subclassing stuff */
2667 auth_methods, /* struct PyMethodDef *tp_methods; */
2668 NULL, /* struct PyMemberDef *tp_members; */
2669 NULL, /* struct PyGetSetDef *tp_getset; */
2670 NULL, /* struct _typeobject *tp_base; */
2671 NULL, /* PyObject *tp_dict; */
2672 NULL, /* descrgetfunc tp_descr_get; */
2673 NULL, /* descrsetfunc tp_descr_set; */
2674 0, /* Py_ssize_t tp_dictoffset; */
2675 NULL, /* initproc tp_init; */
2676 NULL, /* allocfunc tp_alloc; */
2677 auth_init, /* newfunc tp_new; */
2681 static svn_error_t *py_username_prompt(svn_auth_cred_username_t **cred, void *baton, const char *realm, int may_save, apr_pool_t *pool)
2683 PyObject *fn = (PyObject *)baton, *ret;
2684 PyObject *py_username, *py_may_save;
2686 PyGILState_STATE state = PyGILState_Ensure();
2687 ret = PyObject_CallFunction(fn, "sb", realm, may_save);
2688 CB_CHECK_PYRETVAL(ret);
2690 if (ret == Py_None) {
2692 PyGILState_Release(state);
2696 if (!PyTuple_Check(ret)) {
2697 PyErr_SetString(PyExc_TypeError, "expected tuple with username credentials");
2701 if (PyTuple_Size(ret) != 2) {
2702 PyErr_SetString(PyExc_TypeError, "expected tuple with username credentials to be size 2");
2706 py_may_save = PyTuple_GetItem(ret, 1);
2707 CB_CHECK_PYRETVAL(py_may_save);
2708 if (!PyBool_Check(py_may_save)) {
2709 PyErr_SetString(PyExc_TypeError, "may_save should be boolean");
2712 py_username = PyTuple_GetItem(ret, 0);
2713 CB_CHECK_PYRETVAL(py_username);
2714 username = py_object_to_svn_string(py_username, pool);
2715 if (username == NULL) {
2719 *cred = apr_pcalloc(pool, sizeof(**cred));
2720 (*cred)->username = username;
2721 (*cred)->may_save = (py_may_save == Py_True);
2723 PyGILState_Release(state);
2728 PyGILState_Release(state);
2729 return py_svn_error();
2732 static PyObject *get_username_prompt_provider(PyObject *self, PyObject *args)
2734 AuthProviderObject *auth;
2735 PyObject *prompt_func;
2737 if (!PyArg_ParseTuple(args, "Oi:get_username_prompt_provider",
2738 &prompt_func, &retry_limit))
2740 auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
2743 auth->pool = Pool(NULL);
2744 if (auth->pool == NULL)
2746 Py_INCREF(prompt_func);
2747 auth->callback = prompt_func;
2748 svn_auth_get_username_prompt_provider(&auth->provider, py_username_prompt,
2749 (void *)prompt_func, retry_limit, auth->pool);
2750 return (PyObject *)auth;
2753 static svn_error_t *py_simple_prompt(svn_auth_cred_simple_t **cred, void *baton, const char *realm, const char *username, int may_save, apr_pool_t *pool)
2755 PyObject *fn = (PyObject *)baton, *ret;
2756 PyObject *py_may_save, *py_username, *py_password;
2757 char *ret_username, *password;
2758 PyGILState_STATE state = PyGILState_Ensure();
2759 ret = PyObject_CallFunction(fn, "ssb", realm, username, may_save);
2760 CB_CHECK_PYRETVAL(ret);
2761 if (!PyTuple_Check(ret)) {
2762 PyErr_SetString(PyExc_TypeError, "expected tuple with simple credentials");
2765 if (PyTuple_Size(ret) != 3) {
2766 PyErr_SetString(PyExc_TypeError, "expected tuple of size 3");
2770 py_may_save = PyTuple_GetItem(ret, 2);
2771 CB_CHECK_PYRETVAL(py_may_save);
2773 if (!PyBool_Check(py_may_save)) {
2774 PyErr_SetString(PyExc_TypeError, "may_save should be boolean");
2778 py_username = PyTuple_GetItem(ret, 0);
2779 CB_CHECK_PYRETVAL(py_username);
2780 ret_username = py_object_to_svn_string(py_username, pool);
2781 if (ret_username == NULL) {
2785 py_password = PyTuple_GetItem(ret, 1);
2786 CB_CHECK_PYRETVAL(py_password);
2787 password = py_object_to_svn_string(py_password, pool);
2788 if (password == NULL) {
2792 *cred = apr_pcalloc(pool, sizeof(**cred));
2793 (*cred)->username = ret_username;
2794 (*cred)->password = password;
2795 (*cred)->may_save = (py_may_save == Py_True);
2797 PyGILState_Release(state);
2802 PyGILState_Release(state);
2803 return py_svn_error();
2806 static PyObject *get_simple_prompt_provider(PyObject *self, PyObject *args)
2808 PyObject *prompt_func;
2810 AuthProviderObject *auth;
2812 if (!PyArg_ParseTuple(args, "Oi", &prompt_func, &retry_limit))
2815 auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
2816 auth->pool = Pool(NULL);
2817 if (auth->pool == NULL)
2819 Py_INCREF(prompt_func);
2820 auth->callback = prompt_func;
2821 svn_auth_get_simple_prompt_provider (&auth->provider, py_simple_prompt, (void *)prompt_func, retry_limit, auth->pool);
2822 return (PyObject *)auth;
2825 static svn_error_t *py_ssl_server_trust_prompt(svn_auth_cred_ssl_server_trust_t **cred, void *baton, const char *realm, apr_uint32_t failures, const svn_auth_ssl_server_cert_info_t *cert_info, svn_boolean_t may_save, apr_pool_t *pool)
2827 PyObject *fn = (PyObject *)baton;
2829 PyObject *py_cert, *py_may_save, *py_accepted_failures;
2830 PyGILState_STATE state = PyGILState_Ensure();
2831 long accepted_failures;
2833 if (cert_info == NULL) {
2837 py_cert = Py_BuildValue("(sssss)", cert_info->hostname, cert_info->fingerprint,
2838 cert_info->valid_from, cert_info->valid_until,
2839 cert_info->issuer_dname, cert_info->ascii_cert);
2842 CB_CHECK_PYRETVAL(py_cert);
2844 ret = PyObject_CallFunction(fn, "slOb", realm, failures, py_cert, may_save);
2846 CB_CHECK_PYRETVAL(ret);
2848 if (ret == Py_None) {
2850 PyGILState_Release(state);
2853 if (!PyTuple_Check(ret)) {
2855 PyErr_SetString(PyExc_TypeError, "expected tuple with server trust credentials");
2856 PyGILState_Release(state);
2857 return py_svn_error();
2859 if (PyTuple_Size(ret) != 2) {
2861 PyErr_SetString(PyExc_TypeError, "expected tuple of size 2");
2862 PyGILState_Release(state);
2863 return py_svn_error();
2866 py_accepted_failures = PyTuple_GetItem(ret, 0);
2867 if (!PyInt_Check(py_accepted_failures)) {
2869 PyErr_SetString(PyExc_TypeError, "accepted_failures should be integer");
2870 PyGILState_Release(state);
2871 return py_svn_error();
2874 py_may_save = PyTuple_GetItem(ret, 1);
2875 if (!PyBool_Check(py_may_save)) {
2877 PyErr_SetString(PyExc_TypeError, "may_save should be boolean");
2878 PyGILState_Release(state);
2879 return py_svn_error();
2882 accepted_failures = PyInt_AsLong(py_accepted_failures);
2883 if (accepted_failures == -1 && PyErr_Occurred()) {
2885 PyGILState_Release(state);
2886 return py_svn_error();
2888 *cred = apr_pcalloc(pool, sizeof(**cred));
2889 (*cred)->accepted_failures = accepted_failures;
2890 (*cred)->may_save = (py_may_save == Py_True);
2893 PyGILState_Release(state);
2897 static PyObject *get_ssl_server_trust_prompt_provider(PyObject *self, PyObject *args)
2899 AuthProviderObject *auth;
2900 PyObject *prompt_func;
2902 if (!PyArg_ParseTuple(args, "O", &prompt_func))
2905 auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
2908 auth->pool = Pool(NULL);
2909 if (auth->pool == NULL)
2911 Py_INCREF(prompt_func);
2912 auth->callback = prompt_func;
2913 svn_auth_get_ssl_server_trust_prompt_provider (&auth->provider, py_ssl_server_trust_prompt, (void *)prompt_func, auth->pool);
2914 return (PyObject *)auth;
2917 static svn_error_t *py_ssl_client_cert_pw_prompt(svn_auth_cred_ssl_client_cert_pw_t **cred, void *baton, const char *realm, svn_boolean_t may_save, apr_pool_t *pool)
2919 PyObject *fn = (PyObject *)baton, *ret, *py_may_save, *py_password;
2920 PyGILState_STATE state = PyGILState_Ensure();
2921 ret = PyObject_CallFunction(fn, "sb", realm, may_save);
2922 CB_CHECK_PYRETVAL(ret);
2923 if (!PyTuple_Check(ret)) {
2924 PyErr_SetString(PyExc_TypeError, "expected tuple with client cert pw credentials");
2928 if (PyTuple_Size(ret) != 2) {
2929 PyErr_SetString(PyExc_TypeError, "expected tuple of size 2");
2932 py_may_save = PyTuple_GetItem(ret, 1);
2933 if (!PyBool_Check(py_may_save)) {
2934 PyErr_SetString(PyExc_TypeError, "may_save should be boolean");
2937 py_password = PyTuple_GetItem(ret, 0);
2938 if (!PyString_Check(py_password)) {
2939 PyErr_SetString(PyExc_TypeError, "password should be string");
2942 *cred = apr_pcalloc(pool, sizeof(**cred));
2943 (*cred)->password = py_object_to_svn_string(py_password, pool);
2944 (*cred)->may_save = (py_may_save == Py_True);
2946 PyGILState_Release(state);
2951 PyGILState_Release(state);
2952 return py_svn_error();
2955 static svn_error_t *py_ssl_client_cert_prompt(svn_auth_cred_ssl_client_cert_t **cred, void *baton, const char *realm, svn_boolean_t may_save, apr_pool_t *pool)
2957 PyObject *fn = (PyObject *)baton, *ret, *py_may_save, *py_cert_file;
2958 PyGILState_STATE state = PyGILState_Ensure();
2960 ret = PyObject_CallFunction(fn, "sb", realm, may_save);
2961 CB_CHECK_PYRETVAL(ret);
2963 if (!PyTuple_Check(ret)) {
2964 PyErr_SetString(PyExc_TypeError, "expected tuple with client cert credentials");
2968 if (PyTuple_Size(ret) != 2) {
2969 PyErr_SetString(PyExc_TypeError, "expected tuple of size 2");
2972 py_may_save = PyTuple_GetItem(ret, 1);
2973 if (!PyBool_Check(py_may_save)) {
2974 PyErr_SetString(PyExc_TypeError, "may_save should be boolean");
2978 py_cert_file = PyTuple_GetItem(ret, 0);
2979 cert_file = py_object_to_svn_string(py_cert_file, pool);
2984 *cred = apr_pcalloc(pool, sizeof(**cred));
2985 (*cred)->cert_file = cert_file;
2986 (*cred)->may_save = (py_may_save == Py_True);
2988 PyGILState_Release(state);
2993 PyGILState_Release(state);
2994 return py_svn_error();
2997 static PyObject *get_ssl_client_cert_pw_prompt_provider(PyObject *self, PyObject *args)
2999 PyObject *prompt_func;
3001 AuthProviderObject *auth;
3003 if (!PyArg_ParseTuple(args, "Oi", &prompt_func, &retry_limit))
3006 auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
3009 auth->pool = Pool(NULL);
3010 if (auth->pool == NULL)
3012 Py_INCREF(prompt_func);
3013 auth->callback = prompt_func;
3014 svn_auth_get_ssl_client_cert_pw_prompt_provider (&auth->provider, py_ssl_client_cert_pw_prompt, (void *)prompt_func, retry_limit, auth->pool);
3015 return (PyObject *)auth;
3018 static PyObject *get_ssl_client_cert_prompt_provider(PyObject *self, PyObject *args)
3020 PyObject *prompt_func;
3022 AuthProviderObject *auth;
3024 if (!PyArg_ParseTuple(args, "Oi", &prompt_func, &retry_limit))
3027 auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
3030 auth->pool = Pool(NULL);
3031 if (auth->pool == NULL)
3033 Py_INCREF(prompt_func);
3034 auth->callback = prompt_func;
3035 svn_auth_get_ssl_client_cert_prompt_provider (&auth->provider, py_ssl_client_cert_prompt, (void *)prompt_func, retry_limit, auth->pool);
3036 return (PyObject *)auth;
3039 static PyObject *get_username_provider(PyObject *self)
3041 AuthProviderObject *auth;
3042 auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
3045 auth->pool = Pool(NULL);
3046 auth->callback = NULL;
3047 if (auth->pool == NULL) {
3051 svn_auth_get_username_provider(&auth->provider, auth->pool);
3052 return (PyObject *)auth;
3055 #if ONLY_SINCE_SVN(1, 6)
3056 static svn_error_t *py_cb_get_simple_provider_prompt(svn_boolean_t *may_save_plaintext,
3057 const char *realmstring,
3061 if (baton == Py_None) {
3062 /* just disallow saving plaintext passwords on 1.6 and later */
3063 *may_save_plaintext = FALSE;
3066 PyGILState_STATE state = PyGILState_Ensure();
3067 ret = PyObject_CallFunction(baton, "s", realmstring);
3068 CB_CHECK_PYRETVAL(ret);
3070 PyGILState_Release(state);
3071 return py_svn_error();
3073 *may_save_plaintext = PyObject_IsTrue(ret);
3075 PyGILState_Release(state);
3082 static PyObject *get_simple_provider(PyObject *self, PyObject *args)
3084 AuthProviderObject *auth;
3085 PyObject *callback = Py_None;
3088 if (!PyArg_ParseTuple(args, "|O:get_simple_provider", &callback))
3094 auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
3096 apr_pool_destroy(pool);
3100 #if ONLY_SINCE_SVN(1, 6)
3101 Py_INCREF(callback);
3102 auth->callback = callback;
3103 svn_auth_get_simple_provider2(&auth->provider,
3104 py_cb_get_simple_provider_prompt, auth->callback, auth->pool);
3106 auth->callback = NULL;
3107 auth->provider = NULL;
3108 if (callback != Py_None) {
3109 PyErr_SetString(PyExc_NotImplementedError,
3110 "callback not supported with svn < 1.6");
3114 svn_auth_get_simple_provider(&auth->provider, auth->pool);
3116 return (PyObject *)auth;
3119 static PyObject *get_ssl_server_trust_file_provider(PyObject *self)
3121 AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
3124 auth->callback = NULL;
3125 auth->pool = Pool(NULL);
3126 if (auth->pool == NULL)
3128 svn_auth_get_ssl_server_trust_file_provider(&auth->provider, auth->pool);
3129 return (PyObject *)auth;
3132 static PyObject *get_ssl_client_cert_file_provider(PyObject *self)
3134 AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
3137 auth->callback = NULL;
3138 auth->pool = Pool(NULL);
3139 if (auth->pool == NULL)
3141 svn_auth_get_ssl_client_cert_file_provider(&auth->provider, auth->pool);
3142 return (PyObject *)auth;
3145 static PyObject *get_ssl_client_cert_pw_file_provider(PyObject *self)
3147 AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
3150 auth->callback = NULL;
3151 auth->pool = Pool(NULL);
3152 if (auth->pool == NULL)
3155 #if ONLY_SINCE_SVN(1, 6)
3156 svn_auth_get_ssl_client_cert_pw_file_provider2(&auth->provider, NULL, NULL, auth->pool);
3158 svn_auth_get_ssl_client_cert_pw_file_provider(&auth->provider, auth->pool);
3160 return (PyObject *)auth;
3163 static PyObject *print_modules(PyObject *self)
3165 svn_stringbuf_t *stringbuf;
3166 svn_string_t *string;
3168 apr_pool_t *pool = Pool(NULL);
3171 stringbuf = svn_stringbuf_create("", pool);
3172 if (stringbuf == NULL) {
3173 apr_pool_destroy(pool);
3176 RUN_SVN_WITH_POOL(pool, svn_ra_print_modules(stringbuf, pool));
3177 string = svn_string_create_from_buf(stringbuf, pool);
3178 if (string == NULL) {
3179 apr_pool_destroy(pool);
3182 ret = PyBytes_FromStringAndSize(string->data, string->len);
3183 apr_pool_destroy(pool);
3187 #if defined(WIN32) || defined(__CYGWIN__)
3188 static PyObject *get_windows_simple_provider(PyObject* self)
3190 AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
3193 auth->callback = NULL;
3194 auth->pool = Pool(NULL);
3195 if (auth->pool == NULL)
3197 svn_auth_get_windows_simple_provider(&auth->provider, auth->pool);
3198 return (PyObject *)auth;
3201 #if ONLY_SINCE_SVN(1, 5)
3202 static PyObject *get_windows_ssl_server_trust_provider(PyObject *self)
3204 AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
3207 auth->callback = NULL;
3208 auth->pool = Pool(NULL);
3209 if (auth->pool == NULL)
3211 svn_auth_get_windows_ssl_server_trust_provider(&auth->provider, auth->pool);
3212 return (PyObject *)auth;
3217 #if defined(SVN_KEYCHAIN_PROVIDER_AVAILABLE)
3218 static PyObject *get_keychain_simple_provider(PyObject* self)
3220 AuthProviderObject *auth = PyObject_New(AuthProviderObject, &AuthProvider_Type);
3223 auth->callback = NULL;
3224 auth->pool = Pool(NULL);
3225 if (auth->pool == NULL)
3227 svn_auth_get_keychain_simple_provider(&auth->provider, auth->pool);
3228 return (PyObject *)auth;
3232 static PyObject *get_platform_specific_client_providers(PyObject *self)
3234 #if ONLY_SINCE_SVN(1, 6)
3235 /* svn_auth_get_platform_specific_client_providers() allocates all the
3236 * providers in a single pool, so we can't use it :/ */
3237 const char *provider_names[] = {
3238 "gnome_keyring", "keychain", "kwallet", "windows", NULL,
3240 const char *provider_types[] = {
3241 "simple", "ssl_client_cert_pw", "ssl_server_trust", NULL,
3246 pylist = PyList_New(0);
3247 if (pylist == NULL) {
3251 for (i = 0; provider_names[i] != NULL; i++) {
3252 for (j = 0; provider_types[j] != NULL; j++) {
3253 svn_auth_provider_object_t *c_provider = NULL;
3254 apr_pool_t *pool = Pool(NULL);
3255 AuthProviderObject *auth;
3260 RUN_SVN(svn_auth_get_platform_specific_provider(&c_provider,
3265 auth = PyObject_New(AuthProviderObject,
3266 &AuthProvider_Type);
3268 if (c_provider == NULL || auth == NULL) {
3269 apr_pool_destroy(pool);
3274 auth->callback = NULL;
3275 auth->provider = c_provider;
3277 PyList_Append(pylist, (PyObject *)auth);
3285 PyObject *pylist = PyList_New(0);
3286 PyObject *provider = NULL;
3288 if (pylist == NULL) {
3293 #if defined(WIN32) || defined(__CYGWIN__)
3294 provider = get_windows_simple_provider(self);
3295 if (provider == NULL)
3297 PyList_Append(pylist, provider);
3298 Py_DECREF(provider);
3300 #if ONLY_SINCE_SVN(1, 5)
3301 provider = get_windows_ssl_server_trust_provider(self);
3302 if (provider == NULL)
3304 PyList_Append(pylist, provider);
3305 Py_DECREF(provider);
3307 #endif /* WIN32 || __CYGWIN__ */
3309 #if defined(SVN_KEYCHAIN_PROVIDER_AVAILABLE)
3310 provider = get_keychain_simple_provider(self);
3311 if (provider == NULL)
3313 PyList_Append(pylist, provider);
3314 Py_DECREF(provider);
3321 static PyMethodDef ra_module_methods[] = {
3322 { "version", (PyCFunction)version, METH_NOARGS,
3323 "version() -> (major, minor, micro, tag)\n"
3324 "Version of libsvn_ra currently used." },
3325 { "api_version", (PyCFunction)api_version, METH_NOARGS,
3326 "api_version() -> (major, minor, patch, tag)\n\n"
3327 "Version of libsvn_ra Subvertpy was compiled against."
3329 { "get_ssl_client_cert_pw_file_provider", (PyCFunction)get_ssl_client_cert_pw_file_provider, METH_NOARGS, NULL },
3330 { "get_ssl_client_cert_file_provider", (PyCFunction)get_ssl_client_cert_file_provider, METH_NOARGS, NULL },
3331 { "get_ssl_server_trust_file_provider", (PyCFunction)get_ssl_server_trust_file_provider, METH_NOARGS, NULL },
3332 { "get_simple_provider", (PyCFunction)get_simple_provider, METH_VARARGS, NULL },
3333 #if defined(WIN32) || defined(__CYGWIN__)
3334 { "get_windows_simple_provider", (PyCFunction)get_windows_simple_provider, METH_NOARGS, NULL },
3335 #if ONLY_SINCE_SVN(1, 5)
3336 { "get_windows_ssl_server_trust_provider", (PyCFunction)get_windows_ssl_server_trust_provider, METH_NOARGS, NULL },
3339 #if defined(SVN_KEYCHAIN_PROVIDER_AVAILABLE)
3340 { "get_keychain_simple_provider", (PyCFunction)get_keychain_simple_provider, METH_NOARGS, NULL },
3342 { "get_username_prompt_provider", (PyCFunction)get_username_prompt_provider, METH_VARARGS, NULL },
3343 { "get_simple_prompt_provider", (PyCFunction)get_simple_prompt_provider, METH_VARARGS, NULL },
3344 { "get_ssl_server_trust_prompt_provider", (PyCFunction)get_ssl_server_trust_prompt_provider, METH_VARARGS, NULL },
3345 { "get_ssl_client_cert_prompt_provider", (PyCFunction)get_ssl_client_cert_prompt_provider, METH_VARARGS, NULL },
3346 { "get_ssl_client_cert_pw_prompt_provider", (PyCFunction)get_ssl_client_cert_pw_prompt_provider, METH_VARARGS, NULL },
3347 { "get_username_provider", (PyCFunction)get_username_provider, METH_NOARGS, NULL },
3348 { "get_platform_specific_client_providers",
3349 (PyCFunction)get_platform_specific_client_providers,
3351 "Get a list of all available platform client providers.",
3353 { "print_modules", (PyCFunction)print_modules, METH_NOARGS, NULL },
3360 static apr_pool_t *pool;
3363 if (PyType_Ready(&RemoteAccess_Type) < 0)
3366 if (PyType_Ready(&Editor_Type) < 0)
3369 if (PyType_Ready(&FileEditor_Type) < 0)
3372 if (PyType_Ready(&DirectoryEditor_Type) < 0)
3375 if (PyType_Ready(&Reporter_Type) < 0)
3378 if (PyType_Ready(&TxDeltaWindowHandler_Type) < 0)
3381 if (PyType_Ready(&Auth_Type) < 0)
3384 if (PyType_Ready(&CredentialsIter_Type) < 0)
3387 if (PyType_Ready(&AuthProvider_Type) < 0)
3390 if (PyType_Ready(&LogIterator_Type) < 0)
3397 svn_ra_initialize(pool);
3398 PyEval_InitThreads();
3401 #if PY_MAJOR_VERSION >= 3
3402 static struct PyModuleDef moduledef = {
3403 PyModuleDef_HEAD_INIT,
3405 "Remote Access", /* m_doc */
3407 ra_module_methods, /* m_methods */
3408 NULL, /* m_reload */
3409 NULL, /* m_traverse */
3413 mod = PyModule_Create(&moduledef);
3415 mod = Py_InitModule3("_ra", ra_module_methods, "Remote Access");
3420 PyModule_AddObject(mod, "RemoteAccess", (PyObject *)&RemoteAccess_Type);
3421 Py_INCREF(&RemoteAccess_Type);
3423 PyModule_AddObject(mod, "Auth", (PyObject *)&Auth_Type);
3424 Py_INCREF(&Auth_Type);
3426 PyModule_AddObject(mod, "Editor", (PyObject *)&Editor_Type);
3427 Py_INCREF(&Editor_Type);
3429 busy_exc = PyErr_NewException("_ra.BusyException", NULL, NULL);
3430 PyModule_AddObject(mod, "BusyException", busy_exc);
3432 #if ONLY_SINCE_SVN(1, 5)
3433 PyModule_AddIntConstant(mod, "DEPTH_UNKNOWN", svn_depth_unknown);
3434 PyModule_AddIntConstant(mod, "DEPTH_EXCLUDE", svn_depth_exclude);
3435 PyModule_AddIntConstant(mod, "DEPTH_EMPTY", svn_depth_empty);
3436 PyModule_AddIntConstant(mod, "DEPTH_FILES", svn_depth_files);
3437 PyModule_AddIntConstant(mod, "DEPTH_IMMEDIATES", svn_depth_immediates);
3438 PyModule_AddIntConstant(mod, "DEPTH_INFINITY", svn_depth_infinity);
3441 PyModule_AddIntConstant(mod, "DIRENT_KIND", SVN_DIRENT_KIND);
3442 PyModule_AddIntConstant(mod, "DIRENT_SIZE", SVN_DIRENT_SIZE);
3443 PyModule_AddIntConstant(mod, "DIRENT_HAS_PROPS", SVN_DIRENT_HAS_PROPS);
3444 PyModule_AddIntConstant(mod, "DIRENT_CREATED_REV", SVN_DIRENT_CREATED_REV);
3445 PyModule_AddIntConstant(mod, "DIRENT_TIME", SVN_DIRENT_TIME);
3446 PyModule_AddIntConstant(mod, "DIRENT_LAST_AUTHOR", SVN_DIRENT_LAST_AUTHOR);
3447 PyModule_AddIntConstant(mod, "DIRENT_ALL", SVN_DIRENT_ALL);
3449 #if ONLY_SINCE_SVN(1, 5)
3450 PyModule_AddIntConstant(mod, "MERGEINFO_EXPLICIT", svn_mergeinfo_explicit);
3451 PyModule_AddIntConstant(mod, "MERGEINFO_INHERITED", svn_mergeinfo_inherited);
3452 PyModule_AddIntConstant(mod, "MERGEINFO_NEAREST_ANCESTOR", svn_mergeinfo_nearest_ancestor);
3455 #ifdef SVN_VER_REVISION
3456 PyModule_AddIntConstant(mod, "SVN_REVISION", SVN_VER_REVISION);
3462 #if PY_MAJOR_VERSION >= 3
3466 return moduleinit();