diff options
Diffstat (limited to 'subvertpy/wc.c')
-rw-r--r-- | subvertpy/wc.c | 3767 |
1 files changed, 1463 insertions, 2304 deletions
diff --git a/subvertpy/wc.c b/subvertpy/wc.c index 7a635b25..4b6350c4 100644 --- a/subvertpy/wc.c +++ b/subvertpy/wc.c @@ -25,6 +25,7 @@ #include <stdbool.h> #include <apr_md5.h> #include <apr_sha1.h> +#include <fcntl.h> #include "util.h" #include "editor.h" @@ -34,59 +35,51 @@ #define T_BOOL T_BYTE #endif -#if ONLY_SINCE_SVN(1, 5) -#define REPORTER_T svn_ra_reporter3_t -#else -#define REPORTER_T svn_ra_reporter2_t -#endif - -static PyTypeObject Entry_Type; -static PyTypeObject Status_Type; -static PyTypeObject Adm_Type; +typedef struct { + PyObject_HEAD + svn_lock_t lock; + apr_pool_t *pool; +} LockObject; -static PyObject *py_entry(const svn_wc_entry_t *entry); -static PyObject *py_status(const svn_wc_status2_t *status); +#if ONLY_SINCE_SVN(1, 7) +typedef struct { + PyObject_VAR_HEAD + apr_pool_t *pool; + svn_wc_context_t *context; +} ContextObject; +static PyTypeObject Context_Type; +#endif #if ONLY_BEFORE_SVN(1, 5) struct svn_wc_committed_queue_t { - apr_pool_t *pool; - apr_array_header_t *queue; - svn_boolean_t have_recursive; + apr_pool_t *pool; + apr_array_header_t *queue; + svn_boolean_t have_recursive; }; -#if SVN_VER_MINOR < 5 -typedef struct svn_wc_committed_queue_t svn_wc_committed_queue_t; -#endif - typedef struct { - const char *path; - svn_wc_adm_access_t *adm_access; - svn_boolean_t recurse; - svn_boolean_t remove_lock; - apr_array_header_t *wcprop_changes; - unsigned char *digest; + const char *path; + svn_wc_adm_access_t *adm_access; + svn_boolean_t recurse; + svn_boolean_t remove_lock; + apr_array_header_t *wcprop_changes; + unsigned char *digest; } committed_queue_item_t; -#if SVN_VER_MINOR < 5 -static -#endif svn_wc_committed_queue_t *svn_wc_committed_queue_create(apr_pool_t *pool) { - svn_wc_committed_queue_t *q; + svn_wc_committed_queue_t *q; - q = apr_palloc(pool, sizeof(*q)); - q->pool = pool; - q->queue = apr_array_make(pool, 1, sizeof(committed_queue_item_t *)); - q->have_recursive = FALSE; + q = apr_palloc(pool, sizeof(*q)); + q->pool = pool; + q->queue = apr_array_make(pool, 1, sizeof(committed_queue_item_t *)); + q->have_recursive = FALSE; - return q; + return q; } -#if SVN_VER_MINOR < 5 -static -#endif svn_error_t *svn_wc_queue_committed(svn_wc_committed_queue_t **queue, const char *path, svn_wc_adm_access_t *adm_access, @@ -122,129 +115,159 @@ svn_error_t *svn_wc_queue_committed(svn_wc_committed_queue_t **queue, #endif typedef struct { - PyObject_VAR_HEAD - apr_pool_t *pool; - svn_wc_committed_queue_t *queue; + PyObject_VAR_HEAD + apr_pool_t *pool; + svn_wc_committed_queue_t *queue; } CommittedQueueObject; -static PyTypeObject CommittedQueue_Type; - -#if ONLY_SINCE_SVN(1, 5) -static svn_error_t *py_ra_report_set_path(void *baton, const char *path, svn_revnum_t revision, svn_depth_t depth, int start_empty, const char *lock_token, apr_pool_t *pool) -{ - PyObject *self = (PyObject *)baton, *py_lock_token, *ret; - PyGILState_STATE state = PyGILState_Ensure(); - if (lock_token == NULL) { - py_lock_token = Py_None; - Py_INCREF(py_lock_token); - } else { - py_lock_token = PyBytes_FromString(lock_token); - } - ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision, start_empty, py_lock_token, depth); - Py_DECREF(py_lock_token); - CB_CHECK_PYRETVAL(ret); - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; -} - -static svn_error_t *py_ra_report_link_path(void *report_baton, const char *path, const char *url, svn_revnum_t revision, svn_depth_t depth, int start_empty, const char *lock_token, apr_pool_t *pool) -{ - PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token; - PyGILState_STATE state = PyGILState_Ensure(); - if (lock_token == NULL) { - py_lock_token = Py_None; - Py_INCREF(py_lock_token); - } else { - py_lock_token = PyBytes_FromString(lock_token); - } - ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision, start_empty, py_lock_token, depth); - Py_DECREF(py_lock_token); - CB_CHECK_PYRETVAL(ret); - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; -} - -#else -static svn_error_t *py_ra_report_set_path(void *baton, const char *path, svn_revnum_t revision, int start_empty, const char *lock_token, apr_pool_t *pool) +svn_wc_committed_queue_t *PyObject_GetCommittedQueue(PyObject *obj) { - PyObject *self = (PyObject *)baton, *py_lock_token, *ret; - PyGILState_STATE state = PyGILState_Ensure(); - if (lock_token == NULL) { - py_lock_token = Py_None; - Py_INCREF(py_lock_token); - } else { - py_lock_token = PyBytes_FromString(lock_token); - } - ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision, start_empty, py_lock_token, svn_depth_infinity); - CB_CHECK_PYRETVAL(ret); - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; + return ((CommittedQueueObject *)obj)->queue; } -static svn_error_t *py_ra_report_link_path(void *report_baton, const char *path, const char *url, svn_revnum_t revision, int start_empty, const char *lock_token, apr_pool_t *pool) -{ - PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token; - PyGILState_STATE state = PyGILState_Ensure(); - if (lock_token == NULL) { - py_lock_token = Py_None; - Py_INCREF(py_lock_token); - } else { - py_lock_token = PyBytes_FromString(lock_token); - } - ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision, start_empty, py_lock_token, svn_depth_infinity); - CB_CHECK_PYRETVAL(ret); - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; +#if ONLY_SINCE_SVN(1, 5) +static svn_error_t *py_ra_report3_set_path(void *baton, const char *path, + svn_revnum_t revision, + svn_depth_t depth, int start_empty, + const char *lock_token, apr_pool_t *pool) +{ + PyObject *self = (PyObject *)baton, *py_lock_token, *ret; + PyGILState_STATE state = PyGILState_Ensure(); + if (lock_token == NULL) { + py_lock_token = Py_None; + Py_INCREF(py_lock_token); + } else { + py_lock_token = PyBytes_FromString(lock_token); + } + ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision, + start_empty, py_lock_token, depth); + Py_DECREF(py_lock_token); + CB_CHECK_PYRETVAL(ret); + Py_DECREF(ret); + PyGILState_Release(state); + return NULL; +} + +static svn_error_t *py_ra_report3_link_path(void *report_baton, + const char *path, const char *url, + svn_revnum_t revision, + svn_depth_t depth, int start_empty, + const char *lock_token, apr_pool_t *pool) +{ + PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token; + PyGILState_STATE state = PyGILState_Ensure(); + if (lock_token == NULL) { + py_lock_token = Py_None; + Py_INCREF(py_lock_token); + } else { + py_lock_token = PyBytes_FromString(lock_token); + } + ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision, + start_empty, py_lock_token, depth); + Py_DECREF(py_lock_token); + CB_CHECK_PYRETVAL(ret); + Py_DECREF(ret); + PyGILState_Release(state); + return NULL; } - #endif -static svn_error_t *py_ra_report_delete_path(void *baton, const char *path, apr_pool_t *pool) -{ - PyObject *self = (PyObject *)baton, *ret; - PyGILState_STATE state = PyGILState_Ensure(); - ret = PyObject_CallMethod(self, "delete_path", "s", path); - CB_CHECK_PYRETVAL(ret); - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; +static svn_error_t *py_ra_report2_set_path(void *baton, const char *path, + svn_revnum_t revision, + int start_empty, const char *lock_token, + apr_pool_t *pool) +{ + PyObject *self = (PyObject *)baton, *py_lock_token, *ret; + PyGILState_STATE state = PyGILState_Ensure(); + if (lock_token == NULL) { + py_lock_token = Py_None; + Py_INCREF(py_lock_token); + } else { + py_lock_token = PyBytes_FromString(lock_token); + } + ret = PyObject_CallMethod(self, "set_path", "slbOi", path, revision, + start_empty, py_lock_token, svn_depth_infinity); + CB_CHECK_PYRETVAL(ret); + Py_DECREF(ret); + PyGILState_Release(state); + return NULL; +} + +static svn_error_t *py_ra_report2_link_path(void *report_baton, + const char *path, const char *url, + svn_revnum_t revision, + int start_empty, + const char *lock_token, + apr_pool_t *pool) +{ + PyObject *self = (PyObject *)report_baton, *ret, *py_lock_token; + PyGILState_STATE state = PyGILState_Ensure(); + if (lock_token == NULL) { + py_lock_token = Py_None; + Py_INCREF(py_lock_token); + } else { + py_lock_token = PyBytes_FromString(lock_token); + } + ret = PyObject_CallMethod(self, "link_path", "sslbOi", path, url, revision, + start_empty, py_lock_token, svn_depth_infinity); + CB_CHECK_PYRETVAL(ret); + Py_DECREF(ret); + PyGILState_Release(state); + return NULL; +} + +static svn_error_t *py_ra_report_delete_path(void *baton, const char *path, + apr_pool_t *pool) +{ + PyObject *self = (PyObject *)baton, *ret; + PyGILState_STATE state = PyGILState_Ensure(); + ret = PyObject_CallMethod(self, "delete_path", "s", path); + CB_CHECK_PYRETVAL(ret); + Py_DECREF(ret); + PyGILState_Release(state); + return NULL; } static svn_error_t *py_ra_report_finish(void *baton, apr_pool_t *pool) { - PyObject *self = (PyObject *)baton, *ret; - PyGILState_STATE state = PyGILState_Ensure(); - ret = PyObject_CallMethod(self, "finish", ""); - CB_CHECK_PYRETVAL(ret); - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; + PyObject *self = (PyObject *)baton, *ret; + PyGILState_STATE state = PyGILState_Ensure(); + ret = PyObject_CallMethod(self, "finish", ""); + CB_CHECK_PYRETVAL(ret); + Py_DECREF(ret); + PyGILState_Release(state); + return NULL; } static svn_error_t *py_ra_report_abort(void *baton, apr_pool_t *pool) { - PyObject *self = (PyObject *)baton, *ret; - PyGILState_STATE state = PyGILState_Ensure(); - ret = PyObject_CallMethod(self, "abort", ""); - CB_CHECK_PYRETVAL(ret); - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; + PyObject *self = (PyObject *)baton, *ret; + PyGILState_STATE state = PyGILState_Ensure(); + ret = PyObject_CallMethod(self, "abort", ""); + CB_CHECK_PYRETVAL(ret); + Py_DECREF(ret); + PyGILState_Release(state); + return NULL; } -static const REPORTER_T py_ra_reporter = { - py_ra_report_set_path, - py_ra_report_delete_path, - py_ra_report_link_path, - py_ra_report_finish, - py_ra_report_abort, +#if ONLY_SINCE_SVN(1, 5) +const svn_ra_reporter3_t py_ra_reporter3 = { + py_ra_report3_set_path, + py_ra_report_delete_path, + py_ra_report3_link_path, + py_ra_report_finish, + py_ra_report_abort, }; +#endif +const svn_ra_reporter2_t py_ra_reporter2 = { + py_ra_report2_set_path, + py_ra_report_delete_path, + py_ra_report2_link_path, + py_ra_report_finish, + py_ra_report_abort, +}; /** @@ -273,57 +296,6 @@ static PyObject *api_version(PyObject *self) ver->patch, ver->tag); } -static svn_error_t *py_wc_found_entry(const char *path, const svn_wc_entry_t *entry, void *walk_baton, apr_pool_t *pool) -{ - PyObject *fn, *ret; - PyObject *callbacks = (PyObject *)walk_baton; - PyGILState_STATE state = PyGILState_Ensure(); - if (PyTuple_Check(callbacks)) { - fn = PyTuple_GET_ITEM(callbacks, 0); - } else { - fn = (PyObject *)walk_baton; - } - ret = PyObject_CallFunction(fn, "sO", path, py_entry(entry)); - CB_CHECK_PYRETVAL(ret); - Py_DECREF(ret); - PyGILState_Release(state); - return NULL; -} - -#if ONLY_SINCE_SVN(1, 5) - -svn_error_t *py_wc_handle_error(const char *path, svn_error_t *err, void *walk_baton, apr_pool_t *pool) -{ - PyObject *fn, *ret; - PyObject *py_err; - PyGILState_STATE state; - PyObject *callbacks = (PyObject *)walk_baton; - if (PyTuple_Check(callbacks)) { - fn = PyTuple_GET_ITEM(callbacks, 1); - } else { - return err; - } - state = PyGILState_Ensure(); - py_err = PyErr_NewSubversionException(err); - ret = PyObject_CallFunction(fn, "sO", path, py_err); - CB_CHECK_PYRETVAL(ret); - Py_DECREF(ret); - PyGILState_Release(state); - Py_DECREF(py_err); - return NULL; -} - -static svn_wc_entry_callbacks2_t py_wc_entry_callbacks2 = { - py_wc_found_entry, - py_wc_handle_error, -}; -#else -static svn_wc_entry_callbacks_t py_wc_entry_callbacks = { - py_wc_found_entry -}; - -#endif - void py_wc_notify_func(void *baton, const svn_wc_notify_t *notify, apr_pool_t *pool) { @@ -332,877 +304,16 @@ void py_wc_notify_func(void *baton, const svn_wc_notify_t *notify, apr_pool_t *p return; if (notify->err != NULL) { + PyGILState_STATE state = PyGILState_Ensure(); PyObject *excval = PyErr_NewSubversionException(notify->err); ret = PyObject_CallFunction(func, "O", excval); Py_DECREF(excval); Py_XDECREF(ret); /* If ret was NULL, the cancel func should abort the operation. */ + PyGILState_Release(state); } } - -typedef struct { - PyObject_VAR_HEAD - apr_pool_t *pool; - svn_wc_entry_t entry; -} EntryObject; - -static void entry_dealloc(PyObject *self) -{ - apr_pool_destroy(((EntryObject *)self)->pool); - PyObject_Del(self); -} - -static PyMemberDef entry_members[] = { - { "name", T_STRING, offsetof(EntryObject, entry.name), READONLY, - "Name of the file"}, - { "copyfrom_url", T_STRING, offsetof(EntryObject, entry.copyfrom_url), READONLY, - "Copyfrom location" }, - { "copyfrom_rev", T_LONG, offsetof(EntryObject, entry.copyfrom_rev), READONLY, - "Copyfrom revision" }, - { "uuid", T_STRING, offsetof(EntryObject, entry.uuid), READONLY, - "UUID of repository" }, - { "url", T_STRING, offsetof(EntryObject, entry.url), READONLY, - "URL in repository" }, - { "repos", T_STRING, offsetof(EntryObject, entry.repos), READONLY, - "Canonical repository URL" }, - { "schedule", T_INT, offsetof(EntryObject, entry.schedule), READONLY, - "Scheduling (add, replace, delete, etc)" }, - { "kind", T_INT, offsetof(EntryObject, entry.kind), READONLY, - "Kind of file (file, dir, etc)" }, - { "revision", T_LONG, offsetof(EntryObject, entry.revision), READONLY, - "Base revision", }, - { "cmt_rev", T_LONG, offsetof(EntryObject, entry.cmt_rev), READONLY, - "Last revision this was changed" }, - { "checksum", T_STRING, offsetof(EntryObject, entry.checksum), READONLY, - "Hex MD5 checksum for the untranslated text base file" }, - { "cmt_date", T_LONG, offsetof(EntryObject, entry.cmt_date), READONLY, - "Last date this was changed" }, - { "cmt_author", T_STRING, offsetof(EntryObject, entry.cmt_author), READONLY, - "Last commit author of this item" }, - { NULL, } -}; - -static PyTypeObject Entry_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "wc.Entry", /* const char *tp_name; For printing, in format "<module>.<name>" */ - sizeof(EntryObject), - 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */ - - /* Methods to implement standard operations */ - - entry_dealloc, /* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ - NULL, /* cmpfunc tp_compare; */ - NULL, /* reprfunc tp_repr; */ - - /* Method suites for standard classes */ - - NULL, /* PyNumberMethods *tp_as_number; */ - NULL, /* PySequenceMethods *tp_as_sequence; */ - NULL, /* PyMappingMethods *tp_as_mapping; */ - - /* More standard operations (here for binary compatibility) */ - - NULL, /* hashfunc tp_hash; */ - NULL, /* ternaryfunc tp_call; */ - NULL, /* reprfunc tp_str; */ - NULL, /* getattrofunc tp_getattro; */ - NULL, /* setattrofunc tp_setattro; */ - - /* Functions to access object as input/output buffer */ - NULL, /* PyBufferProcs *tp_as_buffer; */ - - /* Flags to define presence of optional/expanded features */ - 0, /* long tp_flags; */ - - NULL, /* const char *tp_doc; Documentation string */ - - /* Assigned meaning in release 2.0 */ - /* call function for all accessible objects */ - NULL, /* traverseproc tp_traverse; */ - - /* delete references to contained objects */ - NULL, /* inquiry tp_clear; */ - - /* Assigned meaning in release 2.1 */ - /* rich comparisons */ - NULL, /* richcmpfunc tp_richcompare; */ - - /* weak reference enabler */ - 0, /* Py_ssize_t tp_weaklistoffset; */ - - /* Added in release 2.2 */ - /* Iterators */ - NULL, /* getiterfunc tp_iter; */ - NULL, /* iternextfunc tp_iternext; */ - - /* Attribute descriptor and subclassing stuff */ - NULL, /* struct PyMethodDef *tp_methods; */ - entry_members, /* struct PyMemberDef *tp_members; */ - -}; - -static PyObject *py_entry(const svn_wc_entry_t *entry) -{ - EntryObject *ret; - - ret = PyObject_New(EntryObject, &Entry_Type); - if (ret == NULL) - return NULL; - - ret->pool = Pool(NULL); - if (ret->pool == NULL) - return NULL; - ret->entry = *svn_wc_entry_dup(entry, ret->pool); - return (PyObject *)ret; -} - -typedef struct { - PyObject_VAR_HEAD - apr_pool_t *pool; - svn_wc_status2_t status; - PyObject *entry; -} StatusObject; - -static void status_dealloc(PyObject *self) -{ - apr_pool_destroy(((StatusObject *)self)->pool); - Py_XDECREF(((StatusObject *)self)->entry); - PyObject_Del(self); -} - -static PyMemberDef status_members[] = { - { "entry", T_OBJECT, offsetof(StatusObject, entry), READONLY, - "Can be NULL if not under version control." }, - { "locked", T_BOOL, offsetof(StatusObject, status.locked), READONLY, - "a directory can be 'locked' if a working copy update was interrupted." }, - { "copied", T_BOOL, offsetof(StatusObject, status.copied), READONLY, - "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.)." }, - { "switched", T_BOOL, offsetof(StatusObject, status.switched), READONLY, - "a file or directory can be 'switched' if the switch command has been used." }, - { "url", T_STRING, offsetof(StatusObject, status.url), READONLY, - "URL (actual or expected) in repository" }, - { "revision", T_LONG, offsetof(StatusObject, status.ood_last_cmt_rev), READONLY, - "Set to the youngest committed revision, or SVN_INVALID_REVNUM if not out of date.", }, - { "kind", T_INT, offsetof(StatusObject, status.ood_kind), READONLY, - "Set to the node kind of the youngest commit, or svn_node_none if not out of date.", }, - { "status", T_INT, offsetof(StatusObject, status.text_status), READONLY, - "The status of the entry.", }, - { NULL, } -}; - -static PyTypeObject Status_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "wc.Status", /* const char *tp_name; For printing, in format "<module>.<name>" */ - sizeof(StatusObject), - 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */ - - /* Methods to implement standard operations */ - - status_dealloc, /* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ - NULL, /* cmpfunc tp_compare; */ - NULL, /* reprfunc tp_repr; */ - - /* Method suites for standard classes */ - - NULL, /* PyNumberMethods *tp_as_number; */ - NULL, /* PySequenceMethods *tp_as_sequence; */ - NULL, /* PyMappingMethods *tp_as_mapping; */ - - /* More standard operations (here for binary compatibility) */ - - NULL, /* hashfunc tp_hash; */ - NULL, /* ternaryfunc tp_call; */ - NULL, /* reprfunc tp_str; */ - NULL, /* getattrofunc tp_getattro; */ - NULL, /* setattrofunc tp_setattro; */ - - /* Functions to access object as input/output buffer */ - NULL, /* PyBufferProcs *tp_as_buffer; */ - - /* Flags to define presence of optional/expanded features */ - 0, /* long tp_flags; */ - - "Working copy status object", /* const char *tp_doc; Documentation string */ - - /* Assigned meaning in release 2.0 */ - /* call function for all accessible objects */ - NULL, /* traverseproc tp_traverse; */ - - /* delete references to contained objects */ - NULL, /* inquiry tp_clear; */ - - /* Assigned meaning in release 2.1 */ - /* rich comparisons */ - NULL, /* richcmpfunc tp_richcompare; */ - - /* weak reference enabler */ - 0, /* Py_ssize_t tp_weaklistoffset; */ - - /* Added in release 2.2 */ - /* Iterators */ - NULL, /* getiterfunc tp_iter; */ - NULL, /* iternextfunc tp_iternext; */ - - /* Attribute descriptor and subclassing stuff */ - NULL, /* struct PyMethodDef *tp_methods; */ - status_members, /* struct PyMemberDef *tp_members; */ - -}; - -static PyObject *py_status(const svn_wc_status2_t *status) -{ - StatusObject *ret; - svn_wc_status2_t *dup_status; - - ret = PyObject_New(StatusObject, &Status_Type); - if (ret == NULL) - return NULL; - - ret->pool = Pool(NULL); - if (ret->pool == NULL) { - PyObject_Del(ret); - return NULL; - } - - dup_status = svn_wc_dup_status2(status, ret->pool); - if (dup_status == NULL) - { - PyErr_NoMemory(); - return NULL; - } - ret->status = *dup_status; - - ret->entry = py_entry(ret->status.entry); - return (PyObject *)ret; -} - -typedef struct { - PyObject_VAR_HEAD - svn_wc_adm_access_t *adm; - apr_pool_t *pool; -} AdmObject; - -#define ADM_CHECK_CLOSED(adm_obj) \ - if (adm_obj->adm == NULL) { \ - PyErr_SetString(PyExc_RuntimeError, "WorkingCopy instance already closed"); \ - return NULL; \ - } - -static PyObject *adm_init(PyTypeObject *self, PyObject *args, PyObject *kwargs) -{ - PyObject *associated, *py_path; - const char *path; - bool write_lock=false; - int depth=0; - svn_wc_adm_access_t *parent_wc; - svn_error_t *err; - AdmObject *ret; - char *kwnames[] = { "associated", "path", "write_lock", "depth", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bi", kwnames, - &associated, &py_path, &write_lock, &depth)) - return NULL; - - ret = PyObject_New(AdmObject, &Adm_Type); - if (ret == NULL) - return NULL; - - ret->pool = Pool(NULL); - if (ret->pool == NULL) { - return NULL; - } - if (associated == Py_None) { - parent_wc = NULL; - } else { - parent_wc = ((AdmObject *)associated)->adm; - } - - path = py_object_to_svn_dirent(py_path, ret->pool); - if (path == NULL) { - Py_DECREF(ret); - return NULL; - } - - Py_BEGIN_ALLOW_THREADS - err = svn_wc_adm_open3(&ret->adm, parent_wc, - path, - write_lock, depth, py_cancel_check, NULL, - ret->pool); - Py_END_ALLOW_THREADS - - if (err != NULL) { - handle_svn_error(err); - svn_error_clear(err); - Py_DECREF(ret); - return NULL; - } - - return (PyObject *)ret; -} - -static PyObject *adm_access_path(PyObject *self) -{ - AdmObject *admobj = (AdmObject *)self; - ADM_CHECK_CLOSED(admobj); - return py_object_from_svn_abspath(svn_wc_adm_access_path(admobj->adm)); -} - -static PyObject *adm_locked(PyObject *self) -{ - AdmObject *admobj = (AdmObject *)self; - ADM_CHECK_CLOSED(admobj); - return PyBool_FromLong(svn_wc_adm_locked(admobj->adm)); -} - -static PyObject *adm_prop_get(PyObject *self, PyObject *args) -{ - char *name; - const char *path; - AdmObject *admobj = (AdmObject *)self; - const svn_string_t *value; - apr_pool_t *temp_pool; - PyObject *ret, *py_path; - - if (!PyArg_ParseTuple(args, "sO", &name, &py_path)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_get(&value, name, path, admobj->adm, temp_pool)); - if (value == NULL || value->data == NULL) { - ret = Py_None; - Py_INCREF(ret); - } else { - ret = PyBytes_FromStringAndSize(value->data, value->len); - } - apr_pool_destroy(temp_pool); - return ret; -} - -static PyObject *adm_prop_set(PyObject *self, PyObject *args) -{ - char *name, *value; - const char *path; - AdmObject *admobj = (AdmObject *)self; - bool skip_checks=false; - apr_pool_t *temp_pool; - int vallen; - svn_string_t *cvalue; - PyObject *py_path; - PyObject *notify_func = Py_None; - - if (!PyArg_ParseTuple(args, "sz#O|bO", &name, &value, &vallen, &py_path, &skip_checks, - ¬ify_func)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - if (value == NULL) { - cvalue = NULL; - } else { - cvalue = svn_string_ncreate(value, vallen, temp_pool); - } -#if ONLY_SINCE_SVN(1, 6) - RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_set3(name, cvalue, path, admobj->adm, - skip_checks, py_wc_notify_func, (void *)notify_func, - temp_pool)); -#else - RUN_SVN_WITH_POOL(temp_pool, svn_wc_prop_set2(name, cvalue, path, admobj->adm, - skip_checks, temp_pool)); -#endif - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -static PyObject *adm_entries_read(PyObject *self, PyObject *args) -{ - apr_hash_t *entries; - AdmObject *admobj = (AdmObject *)self; - apr_pool_t *temp_pool; - bool show_hidden=false; - apr_hash_index_t *idx; - const char *key; - apr_ssize_t klen; - svn_wc_entry_t *entry; - PyObject *py_entries, *obj; - - if (!PyArg_ParseTuple(args, "|b", &show_hidden)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - RUN_SVN_WITH_POOL(temp_pool, svn_wc_entries_read(&entries, admobj->adm, - show_hidden, temp_pool)); - py_entries = PyDict_New(); - if (py_entries == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - idx = apr_hash_first(temp_pool, entries); - while (idx != NULL) { - apr_hash_this(idx, (const void **)&key, &klen, (void **)&entry); - if (entry == NULL) { - obj = Py_None; - Py_INCREF(obj); - } else { - obj = py_entry(entry); - } - PyDict_SetItemString(py_entries, key, obj); - Py_DECREF(obj); - idx = apr_hash_next(idx); - } - apr_pool_destroy(temp_pool); - return py_entries; -} - -static PyObject *adm_walk_entries(PyObject *self, PyObject *args) -{ - const char *path; - PyObject *callbacks; - bool show_hidden=false; - apr_pool_t *temp_pool; - AdmObject *admobj = (AdmObject *)self; - svn_depth_t depth = svn_depth_infinity; - PyObject *py_path; - - if (!PyArg_ParseTuple(args, "OO|bi", &py_path, &callbacks, &show_hidden, &depth)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - -#if ONLY_SINCE_SVN(1, 5) - RUN_SVN_WITH_POOL(temp_pool, svn_wc_walk_entries3( - path, admobj->adm, - &py_wc_entry_callbacks2, (void *)callbacks, - depth, show_hidden, py_cancel_check, NULL, - temp_pool)); -#else - if (depth != svn_depth_infinity) { - PyErr_SetString(PyExc_NotImplementedError, - "depth != infinity not supported for svn < 1.5"); - apr_pool_destroy(temp_pool); - return NULL; - } - RUN_SVN_WITH_POOL(temp_pool, svn_wc_walk_entries2( - path, admobj->adm, - &py_wc_entry_callbacks, (void *)callbacks, - show_hidden, py_cancel_check, NULL, - temp_pool)); -#endif - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -static PyObject *adm_entry(PyObject *self, PyObject *args) -{ - const char *path; - PyObject *py_path; - bool show_hidden=false; - apr_pool_t *temp_pool; - AdmObject *admobj = (AdmObject *)self; - const svn_wc_entry_t *entry; - PyObject *ret; - - if (!PyArg_ParseTuple(args, "O|b", &py_path, &show_hidden)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - RUN_SVN_WITH_POOL(temp_pool, svn_wc_entry(&entry, path, admobj->adm, show_hidden, temp_pool)); - - if (entry == NULL) { - PyErr_Format(PyExc_KeyError, "No such entry '%s'", path); - ret = NULL; - } else { - ret = py_entry(entry); - } - - apr_pool_destroy(temp_pool); - return ret; -} - -static PyObject *adm_get_prop_diffs(PyObject *self, PyObject *args) -{ - const char *path; - apr_pool_t *temp_pool; - apr_array_header_t *propchanges; - apr_hash_t *original_props; - PyObject *py_path; - AdmObject *admobj = (AdmObject *)self; - svn_prop_t el; - int i; - PyObject *py_propchanges, *py_orig_props, *pyval; - - if (!PyArg_ParseTuple(args, "O", &py_path)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_prop_diffs(&propchanges, &original_props, - path, admobj->adm, temp_pool)); - py_propchanges = PyList_New(propchanges->nelts); - if (py_propchanges == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - for (i = 0; i < propchanges->nelts; i++) { - el = APR_ARRAY_IDX(propchanges, i, svn_prop_t); - if (el.value != NULL) - pyval = Py_BuildValue("(sz#)", el.name, el.value->data, el.value->len); - else - pyval = Py_BuildValue("(sO)", el.name, Py_None); - if (pyval == NULL) { - apr_pool_destroy(temp_pool); - Py_DECREF(py_propchanges); - return NULL; - } - if (PyList_SetItem(py_propchanges, i, pyval) != 0) { - Py_DECREF(py_propchanges); - apr_pool_destroy(temp_pool); - return NULL; - } - } - py_orig_props = prop_hash_to_dict(original_props); - apr_pool_destroy(temp_pool); - if (py_orig_props == NULL) { - Py_DECREF(py_propchanges); - return NULL; - } - return Py_BuildValue("(NN)", py_propchanges, py_orig_props); -} - -static PyObject *adm_add(PyObject *self, PyObject *args, PyObject *kwargs) -{ - const char *path; - char *copyfrom_url=NULL; - svn_revnum_t copyfrom_rev=-1; - char *kwnames[] = { "path", "copyfrom_url", "copyfrom_rev", "notify_func", "depth", NULL }; - PyObject *notify_func=Py_None, *py_path; - AdmObject *admobj = (AdmObject *)self; - apr_pool_t *temp_pool; - svn_depth_t depth = svn_depth_infinity; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|zlOi", kwnames, &py_path, - ©from_url, ©from_rev, ¬ify_func, &depth)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - -#if ONLY_SINCE_SVN(1, 6) - RUN_SVN_WITH_POOL(temp_pool, svn_wc_add3( - path, admobj->adm, - depth, svn_uri_canonicalize(copyfrom_url, temp_pool), - copyfrom_rev, py_cancel_check, NULL, - py_wc_notify_func, - (void *)notify_func, - temp_pool)); -#else - if (depth != svn_depth_infinity) { - PyErr_SetString(PyExc_NotImplementedError, "depth != infinity not supported on svn < 1.6"); - apr_pool_destroy(temp_pool); - return NULL; - } - RUN_SVN_WITH_POOL(temp_pool, svn_wc_add2( - path, admobj->adm, copyfrom_url, - copyfrom_rev, py_cancel_check, - py_wc_notify_func, - (void *)notify_func, - temp_pool)); -#endif - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -static PyObject *adm_copy(PyObject *self, PyObject *args) -{ - AdmObject *admobj = (AdmObject *)self; - char *src, *dst; - PyObject *notify_func=Py_None; - apr_pool_t *temp_pool; - - if (!PyArg_ParseTuple(args, "ss|O", &src, &dst, ¬ify_func)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - RUN_SVN_WITH_POOL(temp_pool, svn_wc_copy2(src, admobj->adm, dst, - py_cancel_check, NULL, - py_wc_notify_func, (void *)notify_func, - temp_pool)); - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -static PyObject *adm_delete(PyObject *self, PyObject *args, PyObject *kwargs) -{ - AdmObject *admobj = (AdmObject *)self; - apr_pool_t *temp_pool; - char *kwnames[] = { "path", "notify_func", "keep_local", - NULL }; - const char *path; - PyObject *py_path; - PyObject *notify_func=Py_None; - bool keep_local = false; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Ob:delete", kwnames, - &py_path, ¬ify_func, &keep_local)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - -#if ONLY_SINCE_SVN(1, 5) - RUN_SVN_WITH_POOL(temp_pool, svn_wc_delete3(path, admobj->adm, - py_cancel_check, NULL, - py_wc_notify_func, (void *)notify_func, - keep_local, - temp_pool)); -#else - if (keep_local) { - PyErr_SetString(PyExc_NotImplementedError, - "keep_local not supported on Subversion < 1.5"); - return NULL; - } - - RUN_SVN_WITH_POOL(temp_pool, svn_wc_delete2(path, admobj->adm, - py_cancel_check, NULL, - py_wc_notify_func, (void *)notify_func, - temp_pool)); -#endif - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -static PyObject *adm_crawl_revisions(PyObject *self, PyObject *args, PyObject *kwargs) -{ - const char *path; - PyObject *reporter; - bool restore_files=true, recurse=true, use_commit_times=true; - PyObject *notify_func=Py_None; - apr_pool_t *temp_pool; - AdmObject *admobj = (AdmObject *)self; - svn_wc_traversal_info_t *traversal_info; - bool depth_compatibility_trick = false; - bool honor_depth_exclude = false; - char *kwnames[] = { "path", "reporter", "restore_files", "recurse", "use_commit_times", "notify_func", "depth_compatibility_trick", "honor_depth_exclude,", NULL }; - PyObject *py_path; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bbbObb", kwnames, &py_path, - &reporter, &restore_files, &recurse, &use_commit_times, - ¬ify_func, &depth_compatibility_trick, &honor_depth_exclude)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - traversal_info = svn_wc_init_traversal_info(temp_pool); -#if ONLY_SINCE_SVN(1, 6) - RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions4(path, admobj->adm, - &py_ra_reporter, (void *)reporter, - restore_files, recurse?svn_depth_infinity:svn_depth_files, - honor_depth_exclude?TRUE:FALSE, - depth_compatibility_trick?TRUE:FALSE, use_commit_times, - py_wc_notify_func, (void *)notify_func, - traversal_info, temp_pool)); -#elif ONLY_SINCE_SVN(1, 5) - RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions3(path, admobj->adm, - &py_ra_reporter, (void *)reporter, - restore_files, recurse?svn_depth_infinity:svn_depth_files, - depth_compatibility_trick, use_commit_times, - py_wc_notify_func, (void *)notify_func, - traversal_info, temp_pool)); -#else - RUN_SVN_WITH_POOL(temp_pool, svn_wc_crawl_revisions2(path, admobj->adm, - &py_ra_reporter, (void *)reporter, - restore_files, recurse, use_commit_times, - py_wc_notify_func, (void *)notify_func, - traversal_info, temp_pool)); -#endif - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -static void wc_done_handler(void *self) -{ - AdmObject *admobj = (AdmObject *)self; - - Py_DECREF(admobj); -} - -static PyObject *adm_get_update_editor(PyObject *self, PyObject *args) -{ - char *target; - bool use_commit_times=true, recurse=true; - PyObject * notify_func=Py_None; - char *diff3_cmd=NULL; - const svn_delta_editor_t *editor; - AdmObject *admobj = (AdmObject *)self; - void *edit_baton; - apr_pool_t *pool; - svn_revnum_t *latest_revnum; - svn_error_t *err; - bool allow_unver_obstructions = false; - bool depth_is_sticky = false; - - if (!PyArg_ParseTuple(args, "s|bbOzbb", &target, &use_commit_times, - &recurse, ¬ify_func, &diff3_cmd, &depth_is_sticky, - &allow_unver_obstructions)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - pool = Pool(NULL); - if (pool == NULL) - return NULL; - latest_revnum = (svn_revnum_t *)apr_palloc(pool, sizeof(svn_revnum_t)); - Py_BEGIN_ALLOW_THREADS -#if ONLY_SINCE_SVN(1, 5) - /* FIXME: Support all values of depth */ - /* FIXME: Support fetch_func */ - /* FIXME: Support conflict func */ - err = svn_wc_get_update_editor3(latest_revnum, admobj->adm, target, - use_commit_times, recurse?svn_depth_infinity:svn_depth_files, - depth_is_sticky?TRUE:FALSE, allow_unver_obstructions?TRUE:FALSE, - py_wc_notify_func, (void *)notify_func, - py_cancel_check, NULL, - NULL, NULL, NULL, NULL, - diff3_cmd, NULL, &editor, &edit_baton, - NULL, pool); -#else - if (allow_unver_obstructions) { - PyErr_SetString(PyExc_NotImplementedError, - "allow_unver_obstructions is not supported in svn < 1.5"); - apr_pool_destroy(pool); - PyEval_RestoreThread(_save); - return NULL; - } - if (depth_is_sticky) { - PyErr_SetString(PyExc_NotImplementedError, - "depth_is_sticky is not supported in svn < 1.5"); - apr_pool_destroy(pool); - PyEval_RestoreThread(_save); - return NULL; - } - err = svn_wc_get_update_editor2(latest_revnum, admobj->adm, target, - use_commit_times, recurse, py_wc_notify_func, (void *)notify_func, - py_cancel_check, NULL, diff3_cmd, &editor, &edit_baton, - NULL, pool); -#endif - Py_END_ALLOW_THREADS - if (err != NULL) { - handle_svn_error(err); - svn_error_clear(err); - apr_pool_destroy(pool); - return NULL; - } - Py_INCREF(admobj); - return new_editor_object(NULL, editor, edit_baton, pool, &Editor_Type, - wc_done_handler, admobj, NULL); -} - -static bool py_dict_to_wcprop_changes(PyObject *dict, apr_pool_t *pool, apr_array_header_t **ret) +bool py_dict_to_wcprop_changes(PyObject *dict, apr_pool_t *pool, apr_array_header_t **ret) { PyObject *key, *val; Py_ssize_t idx; @@ -1240,384 +351,62 @@ static bool py_dict_to_wcprop_changes(PyObject *dict, apr_pool_t *pool, apr_arra return true; } -static PyObject *adm_has_binary_prop(PyObject *self, PyObject *args) -{ - const char *path; - svn_boolean_t binary; - AdmObject *admobj = (AdmObject *)self; - apr_pool_t *temp_pool; - PyObject *py_path; - - if (!PyArg_ParseTuple(args, "O", &py_path)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - RUN_SVN_WITH_POOL(temp_pool, svn_wc_has_binary_prop(&binary, path, admobj->adm, temp_pool)); - - apr_pool_destroy(temp_pool); - - return PyBool_FromLong(binary); -} - -static PyObject *adm_process_committed(PyObject *self, PyObject *args, PyObject *kwargs) -{ - const char *path; - char *rev_date = NULL, *rev_author = NULL; - bool recurse, remove_lock = false; - unsigned char *digest = NULL; - svn_revnum_t new_revnum; - PyObject *py_wcprop_changes = Py_None, *py_path; - apr_array_header_t *wcprop_changes = NULL; - AdmObject *admobj = (AdmObject *)self; - apr_pool_t *temp_pool; - int digest_len; - bool remove_changelist = false; - char *kwnames[] = { "path", "recurse", "new_revnum", "rev_date", "rev_author", - "wcprop_changes", "remove_lock", "digest", "remove_changelist", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oblzz|Obz#b", kwnames, - &py_path, &recurse, &new_revnum, &rev_date, - &rev_author, &py_wcprop_changes, - &remove_lock, &digest, &digest_len, &remove_changelist)) - return NULL; - - PyErr_WarnEx(PyExc_DeprecationWarning, "process_committed is deprecated. Use process_committed_queue instead.", 2); - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - if (!py_dict_to_wcprop_changes(py_wcprop_changes, temp_pool, &wcprop_changes)) { - apr_pool_destroy(temp_pool); - return NULL; - } - #if ONLY_SINCE_SVN(1, 6) - RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed4( - path, admobj->adm, recurse, new_revnum, - rev_date, rev_author, wcprop_changes, - remove_lock, remove_changelist?TRUE:FALSE, digest, temp_pool)); -#else - if (remove_changelist) { - PyErr_SetString(PyExc_NotImplementedError, "remove_changelist only supported in svn < 1.6"); - apr_pool_destroy(temp_pool); - return NULL; - } - RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(path, admobj->adm, recurse, new_revnum, - rev_date, rev_author, wcprop_changes, - remove_lock, digest, temp_pool)); -#endif - - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -static PyObject *adm_close(PyObject *self) -{ - AdmObject *admobj = (AdmObject *)self; - if (admobj->adm != NULL) { -#if ONLY_SINCE_SVN(1, 6) - apr_pool_t *temp_pool = Pool(NULL); - Py_BEGIN_ALLOW_THREADS - svn_wc_adm_close2(admobj->adm, temp_pool); - apr_pool_destroy(temp_pool); -#else - Py_BEGIN_ALLOW_THREADS - svn_wc_adm_close(admobj->adm); -#endif - Py_END_ALLOW_THREADS - admobj->adm = NULL; - } - - Py_RETURN_NONE; -} - -static void adm_dealloc(PyObject *self) -{ - apr_pool_destroy(((AdmObject *)self)->pool); - PyObject_Del(self); -} - -static PyObject *adm_repr(PyObject *self) -{ - AdmObject *admobj = (AdmObject *)self; - - if (admobj->adm == NULL) { - return PyRepr_FromFormat("<wc.WorkingCopy (closed) at 0x%p>", admobj); - } else { - return PyRepr_FromFormat("<wc.WorkingCopy at '%s'>", - svn_wc_adm_access_path(admobj->adm)); - } -} - -static PyObject *adm_remove_lock(PyObject *self, PyObject *args) -{ - const char *path; - PyObject *py_path; - AdmObject *admobj = (AdmObject *)self; - apr_pool_t *temp_pool; - - if (!PyArg_ParseTuple(args, "O", &py_path)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - RUN_SVN_WITH_POOL(temp_pool, svn_wc_remove_lock(path, admobj->adm, temp_pool)) - - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -static PyObject *get_ancestry(PyObject *self, PyObject *args) -{ - const char *path; - char *url; - svn_revnum_t rev; - apr_pool_t *temp_pool; - PyObject *py_path; - AdmObject *admobj = (AdmObject *)self; - - if (!PyArg_ParseTuple(args, "O", &py_path)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_ancestry(&url, &rev, path, admobj->adm, temp_pool)); - - apr_pool_destroy(temp_pool); - - return Py_BuildValue("(si)", url, rev); -} - -static PyObject *maybe_set_repos_root(PyObject *self, PyObject *args) -{ - char *path, *repos; - apr_pool_t *temp_pool; - AdmObject *admobj = (AdmObject *)self; - - if (!PyArg_ParseTuple(args, "ss", &path, &repos)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - RUN_SVN_WITH_POOL(temp_pool, svn_wc_maybe_set_repos_root(admobj->adm, path, repos, temp_pool)); - - Py_RETURN_NONE; -} - -static PyObject *add_repos_file(PyObject *self, PyObject *args, PyObject *kwargs) -{ - char *kwnames[] = { "dst_path", "new_base_contents", "new_contents", - "new_base_props", "new_props", "copyfrom_url", "copyfrom_rev", - "notify", NULL }; - AdmObject *admobj = (AdmObject *)self; - apr_pool_t *temp_pool; - char *dst_path, *copyfrom_url = NULL; - svn_revnum_t copyfrom_rev = -1; - PyObject *py_new_base_contents, *py_new_contents, *py_new_base_props, - *py_new_props, *notify = Py_None; - svn_stream_t *new_contents, *new_base_contents; - apr_hash_t *new_props, *new_base_props; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sOOOO|zlO", kwnames, - &dst_path, &py_new_base_contents, &py_new_contents, &py_new_base_props, - &py_new_props, ©from_url, ©from_rev, ¬ify)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - new_base_props = prop_dict_to_hash(temp_pool, py_new_base_props); - - new_props = prop_dict_to_hash(temp_pool, py_new_props); - - new_base_contents = new_py_stream(temp_pool, py_new_base_contents); - - new_contents = new_py_stream(temp_pool, py_new_contents); - -#if ONLY_SINCE_SVN(1, 6) - RUN_SVN_WITH_POOL(temp_pool, svn_wc_add_repos_file3(dst_path, admobj->adm, - new_base_contents, - new_contents, - new_base_props, - new_props, - copyfrom_url, copyfrom_rev, - py_cancel_check, NULL, - py_wc_notify_func, notify, temp_pool)); -#else - PyErr_SetString(PyExc_NotImplementedError, - "add_repos_file3 not supported on svn < 1.6"); - apr_pool_destroy(temp_pool); -#endif - - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -static PyObject *mark_missing_deleted(PyObject *self, PyObject *args) -{ - const char *path; - AdmObject *admobj = (AdmObject *)self; - apr_pool_t *temp_pool; - PyObject *py_path; - - if (!PyArg_ParseTuple(args, "O", &py_path)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - RUN_SVN_WITH_POOL(temp_pool, svn_wc_mark_missing_deleted(path, admobj->adm, temp_pool)); - - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -static PyObject *remove_from_revision_control(PyObject *self, PyObject *args) -{ - char *name; - bool destroy_wf = false, instant_error = false; - AdmObject *admobj = (AdmObject *)self; - apr_pool_t *temp_pool; - - if (!PyArg_ParseTuple(args, "s|bb", &name, &destroy_wf, &instant_error)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_remove_from_revision_control(admobj->adm, name, - destroy_wf?TRUE:FALSE, instant_error?TRUE:FALSE, py_cancel_check, NULL, temp_pool)); - - apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -} - -#if ONLY_SINCE_SVN(1, 6) -static svn_error_t *wc_validator3(void *baton, const char *uuid, const char *url, const char *root_url, apr_pool_t *pool) +svn_error_t *wc_validator3(void *baton, const char *uuid, const char *url, const char *root_url, apr_pool_t *pool) { PyObject *py_validator = baton, *ret; + PyGILState_STATE state; if (py_validator == Py_None) { return NULL; } - + state = PyGILState_Ensure(); ret = PyObject_CallFunction(py_validator, "sss", uuid, url, root_url); if (ret == NULL) { + PyGILState_Release(state); return py_svn_error(); } Py_DECREF(ret); + PyGILState_Release(state); return NULL; } -#else +#endif -static svn_error_t *wc_validator2(void *baton, const char *uuid, const char *url, svn_boolean_t root, apr_pool_t *pool) +svn_error_t *wc_validator2(void *baton, const char *uuid, const char *url, svn_boolean_t root, apr_pool_t *pool) { PyObject *py_validator = baton, *ret; + PyGILState_STATE state; if (py_validator == Py_None) { return NULL; } + state = PyGILState_Ensure(); ret = PyObject_CallFunction(py_validator, "ssO", uuid, url, Py_None); if (ret == NULL) { + PyGILState_Release(state); return py_svn_error(); } Py_DECREF(ret); + PyGILState_Release(state); return NULL; } -#endif - -static PyObject *relocate(PyObject *self, PyObject *args) +static PyObject *get_actual_target(PyObject *self, PyObject *args) { const char *path; - char *from, *to; - AdmObject *admobj = (AdmObject *)self; + const char *anchor = NULL, *target = NULL; apr_pool_t *temp_pool; - bool recurse = true; - PyObject *py_validator = Py_None, *py_path; + PyObject *ret, *py_path; - if (!PyArg_ParseTuple(args, "Oss|bO:relocate", &py_path, &from, &to, &recurse, - &py_validator)) + if (!PyArg_ParseTuple(args, "O", &py_path)) return NULL; - ADM_CHECK_CLOSED(admobj); - temp_pool = Pool(NULL); if (temp_pool == NULL) { return NULL; @@ -1629,392 +418,276 @@ static PyObject *relocate(PyObject *self, PyObject *args) return NULL; } -#if ONLY_SINCE_SVN(1, 6) - RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate3(path, admobj->adm, from, to, recurse?TRUE:FALSE, wc_validator3, py_validator, temp_pool)); -#else - RUN_SVN_WITH_POOL(temp_pool, svn_wc_relocate2(path, admobj->adm, from, to, recurse?TRUE:FALSE, wc_validator2, py_validator, temp_pool)); -#endif + RUN_SVN_WITH_POOL(temp_pool, + svn_wc_get_actual_target(path, + &anchor, &target, temp_pool)); + + ret = Py_BuildValue("(ss)", anchor, target); apr_pool_destroy(temp_pool); - Py_RETURN_NONE; + return ret; } -static PyObject *crop_tree(PyObject *self, PyObject *args) +/** + * Determine the revision status of a specified working copy. + * + * :return: Tuple with minimum and maximum revnums found, whether the + * working copy was switched and whether it was modified. + */ +static PyObject *revision_status(PyObject *self, PyObject *args, PyObject *kwargs) { - char *target; - svn_depth_t depth; - PyObject *notify; + char *kwnames[] = { "wc_path", "trail_url", "committed", NULL }; + const char *wc_path; + char *trail_url=NULL; + bool committed=false; + PyObject *ret, *py_wc_path; + svn_wc_revision_status_t *revstatus; apr_pool_t *temp_pool; - AdmObject *admobj = (AdmObject *)self; - if (!PyArg_ParseTuple(args, "si|O", &target, &depth, ¬ify)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|zb", kwnames, &py_wc_path, + &trail_url, &committed)) return NULL; - ADM_CHECK_CLOSED(admobj); - -#if ONLY_SINCE_SVN(1, 6) temp_pool = Pool(NULL); - if (temp_pool == NULL) + if (temp_pool == NULL) { return NULL; + } - RUN_SVN_WITH_POOL(temp_pool, svn_wc_crop_tree(admobj->adm, - target, depth, py_wc_notify_func, notify, - py_cancel_check, NULL, temp_pool)); - + wc_path = py_object_to_svn_dirent(py_wc_path, temp_pool); + if (wc_path == NULL) { + apr_pool_destroy(temp_pool); + return NULL; + } + RUN_SVN_WITH_POOL(temp_pool, + svn_wc_revision_status( + &revstatus, wc_path, trail_url, + committed, py_cancel_check, NULL, temp_pool)); + ret = Py_BuildValue("(llbb)", revstatus->min_rev, revstatus->max_rev, + revstatus->switched, revstatus->modified); apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; -#else - PyErr_SetString(PyExc_NotImplementedError, - "crop_tree only available on subversion < 1.6"); - return NULL; -#endif + return ret; } -static PyObject *translated_stream(PyObject *self, PyObject *args) +static PyObject *is_normal_prop(PyObject *self, PyObject *args) { - char *path, *versioned_file; - StreamObject *ret; - svn_stream_t *stream; - AdmObject *admobj = (AdmObject *)self; - apr_pool_t *stream_pool; - int flags; - - if (!PyArg_ParseTuple(args, "ssi", &path, &versioned_file, &flags)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - -#if ONLY_SINCE_SVN(1, 5) - stream_pool = Pool(NULL); - if (stream_pool == NULL) - return NULL; - - RUN_SVN_WITH_POOL(stream_pool, - svn_wc_translated_stream(&stream, path, versioned_file, admobj->adm, - flags, stream_pool)); + char *name; - ret = PyObject_New(StreamObject, &Stream_Type); - if (ret == NULL) + if (!PyArg_ParseTuple(args, "s", &name)) return NULL; - ret->pool = stream_pool; - ret->closed = FALSE; - ret->stream = stream; - - return (PyObject *)ret; -#else - PyErr_SetString(PyExc_NotImplementedError, - "translated_stream() is only available on Subversion >= 1.5"); - return NULL; -#endif + return PyBool_FromLong(svn_wc_is_normal_prop(name)); } -static PyObject *adm_text_modified(PyObject *self, PyObject *args) +static PyObject *is_adm_dir(PyObject *self, PyObject *args) { - const char *path; - bool force_comparison = false; - apr_pool_t *temp_pool; + const char *name; + PyObject *py_name; + apr_pool_t *pool; svn_boolean_t ret; - AdmObject *admobj = (AdmObject *)self; - PyObject *py_path; - if (!PyArg_ParseTuple(args, "O|b", &py_path, &force_comparison)) + if (!PyArg_ParseTuple(args, "O", &py_name)) return NULL; - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { + pool = Pool(NULL); + if (pool == NULL) return NULL; - } - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } + name = py_object_to_svn_string(py_name, pool); + if (name == NULL) { + return NULL; + } - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_text_modified_p(&ret, path, force_comparison?TRUE:FALSE, admobj->adm, - temp_pool)); + ret = svn_wc_is_adm_dir(name, pool); - apr_pool_destroy(temp_pool); + apr_pool_destroy(pool); return PyBool_FromLong(ret); } -static PyObject *adm_props_modified(PyObject *self, PyObject *args) +static PyObject *is_wc_prop(PyObject *self, PyObject *args) { - const char *path; - apr_pool_t *temp_pool; - svn_boolean_t ret; - AdmObject *admobj = (AdmObject *)self; - PyObject *py_path; + char *name; - if (!PyArg_ParseTuple(args, "O", &py_path)) + if (!PyArg_ParseTuple(args, "s", &name)) return NULL; - ADM_CHECK_CLOSED(admobj); + return PyBool_FromLong(svn_wc_is_wc_prop(name)); +} - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } +static PyObject *is_entry_prop(PyObject *self, PyObject *args) +{ + char *name; - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); + if (!PyArg_ParseTuple(args, "s", &name)) return NULL; - } - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_props_modified_p(&ret, path, admobj->adm, temp_pool)); - - apr_pool_destroy(temp_pool); + return PyBool_FromLong(svn_wc_is_entry_prop(name)); +} - return PyBool_FromLong(ret); +static PyObject *get_adm_dir(PyObject *self) +{ + apr_pool_t *pool; + PyObject *ret; + const char *dir; + pool = Pool(NULL); + if (pool == NULL) + return NULL; + dir = svn_wc_get_adm_dir(pool); + ret = py_object_from_svn_abspath(dir); + apr_pool_destroy(pool); + return ret; } -static PyObject *adm_process_committed_queue(PyObject *self, PyObject *args) +static PyObject *set_adm_dir(PyObject *self, PyObject *args) { apr_pool_t *temp_pool; - AdmObject *admobj = (AdmObject *)self; - svn_revnum_t revnum; - char *date, *author; - CommittedQueueObject *py_queue; + char *name; + PyObject *py_name; - if (!PyArg_ParseTuple(args, "O!lss", &CommittedQueue_Type, &py_queue, - &revnum, &date, &author)) + if (!PyArg_ParseTuple(args, "O", &py_name)) return NULL; - ADM_CHECK_CLOSED(admobj); - temp_pool = Pool(NULL); if (temp_pool == NULL) return NULL; - -#if ONLY_SINCE_SVN(1, 5) - RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed_queue(py_queue->queue, admobj->adm, revnum, date, author, temp_pool)); -#else - { - int i; - for (i = 0; i < py_queue->queue->queue->nelts; i++) { - committed_queue_item_t *cqi = APR_ARRAY_IDX(py_queue->queue->queue, i, - committed_queue_item_t *); - - RUN_SVN_WITH_POOL(temp_pool, svn_wc_process_committed3(cqi->path, admobj->adm, - cqi->recurse, revnum, date, author, cqi->wcprop_changes, - cqi->remove_lock, cqi->digest, temp_pool)); - } + name = py_object_to_svn_string(py_name, temp_pool); + if (name == NULL) { + apr_pool_destroy(temp_pool); + return NULL; } -#endif + RUN_SVN_WITH_POOL(temp_pool, svn_wc_set_adm_dir(name, temp_pool)); apr_pool_destroy(temp_pool); - Py_RETURN_NONE; } -static PyObject *get_actual_target(PyObject *self, PyObject *args) +static PyObject *get_pristine_copy_path(PyObject *self, PyObject *args) { + apr_pool_t *pool; + const char *pristine_path; const char *path; - const char *anchor = NULL, *target = NULL; - apr_pool_t *temp_pool; - PyObject *ret, *py_path; + PyObject *py_path; + PyObject *ret; if (!PyArg_ParseTuple(args, "O", &py_path)) return NULL; - temp_pool = Pool(NULL); - if (temp_pool == NULL) { + pool = Pool(NULL); + if (pool == NULL) return NULL; - } - path = py_object_to_svn_dirent(py_path, temp_pool); + path = py_object_to_svn_abspath(py_path, pool); if (path == NULL) { - apr_pool_destroy(temp_pool); + apr_pool_destroy(pool); return NULL; } - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_get_actual_target(path, - &anchor, &target, temp_pool)); - - ret = Py_BuildValue("(ss)", anchor, target); - - apr_pool_destroy(temp_pool); - + PyErr_WarnEx(PyExc_DeprecationWarning, "get_pristine_copy_path is deprecated. Use get_pristine_contents instead.", 2); + RUN_SVN_WITH_POOL(pool, + svn_wc_get_pristine_copy_path(path, + &pristine_path, pool)); + ret = py_object_from_svn_abspath(pristine_path); + apr_pool_destroy(pool); return ret; } -static PyObject *is_wc_root(PyObject *self, PyObject *args) +static PyObject *get_pristine_contents(PyObject *self, PyObject *args) { const char *path; - svn_boolean_t wc_root; apr_pool_t *temp_pool; - AdmObject *admobj = (AdmObject *)self; PyObject *py_path; +#if ONLY_SINCE_SVN(1, 6) + StreamObject *ret; + apr_pool_t *stream_pool; + svn_stream_t *stream; +#else +#if PY_MAJOR_VERSION >= 3 + int fd; +#endif + PyObject *ret; + const char *pristine_path; +#endif if (!PyArg_ParseTuple(args, "O", &py_path)) return NULL; - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { +#if ONLY_SINCE_SVN(1, 6) + stream_pool = Pool(NULL); + if (stream_pool == NULL) return NULL; - } - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); + temp_pool = Pool(stream_pool); + if (temp_pool == NULL) { + apr_pool_destroy(stream_pool); return NULL; } - - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_is_wc_root(&wc_root, path, admobj->adm, temp_pool)); - - apr_pool_destroy(temp_pool); - - return PyBool_FromLong(wc_root); -} - -static PyObject *transmit_text_deltas(PyObject *self, PyObject *args) -{ - const char *path; - const char *tempfile; - bool fulltext; - PyObject *editor_obj, *py_digest, *py_path; - unsigned char digest[APR_MD5_DIGESTSIZE]; - apr_pool_t *temp_pool; - AdmObject *admobj = (AdmObject *)self; - PyObject *ret; - - if (!PyArg_ParseTuple(args, "ObO", &py_path, &fulltext, &editor_obj)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - +#else temp_pool = Pool(NULL); if (temp_pool == NULL) { return NULL; } +#endif - path = py_object_to_svn_dirent(py_path, temp_pool); + path = py_object_to_svn_abspath(py_path, temp_pool); if (path == NULL) { apr_pool_destroy(temp_pool); return NULL; } - Py_INCREF(editor_obj); - - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_transmit_text_deltas2(&tempfile, digest, - path, admobj->adm, fulltext?TRUE:FALSE, - &py_editor, editor_obj, temp_pool)); - - py_digest = PyBytes_FromStringAndSize((char *)digest, APR_MD5_DIGESTSIZE); - if (py_digest == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - ret = Py_BuildValue("sN", tempfile, py_digest); - if (ret == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - +#if ONLY_SINCE_SVN(1, 6) + RUN_SVN_WITH_POOL(stream_pool, svn_wc_get_pristine_contents(&stream, path, stream_pool, temp_pool)); apr_pool_destroy(temp_pool); - return ret; -} - -static PyObject *transmit_prop_deltas(PyObject *self, PyObject *args) -{ - const char *path; - PyObject *editor_obj; - apr_pool_t *temp_pool; - AdmObject *admobj = (AdmObject *)self; - PyObject *py_path; - EntryObject *py_entry; + if (stream == NULL) { + apr_pool_destroy(stream_pool); + Py_RETURN_NONE; + } - if (!PyArg_ParseTuple(args, "OO!O", &py_path, &Entry_Type, &py_entry, &editor_obj)) + ret = PyObject_New(StreamObject, &Stream_Type); + if (ret == NULL) return NULL; - ADM_CHECK_CLOSED(admobj); + ret->pool = stream_pool; + ret->closed = FALSE; + ret->stream = stream; + return (PyObject *)ret; +#else temp_pool = Pool(NULL); - if (temp_pool == NULL) { + if (temp_pool == NULL) return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { + RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_pristine_copy_path(path, &pristine_path, temp_pool)); +#if PY_MAJOR_VERSION >= 3 + fd = open(pristine_path, O_RDONLY); + if (fd < 0) { + PyErr_SetFromErrno(PyExc_IOError); apr_pool_destroy(temp_pool); return NULL; } - - Py_INCREF(editor_obj); - - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_transmit_prop_deltas(path, - admobj->adm, &(py_entry->entry), &py_editor, editor_obj, NULL, temp_pool)); - + ret = PyFile_FromFd(fd, pristine_path, "rb", -1, NULL, NULL, NULL, true); +#else + ret = PyFile_FromString((char *)pristine_path, "rb"); +#endif apr_pool_destroy(temp_pool); - - Py_RETURN_NONE; + return ret; +#endif } -static PyObject *retrieve(PyObject *self, PyObject *args) +static PyObject *ensure_adm(PyObject *self, PyObject *args, PyObject *kwargs) { const char *path; - svn_wc_adm_access_t *result; + char *uuid, *url = NULL; PyObject *py_path; - AdmObject *admobj = (AdmObject *)self, *ret; + char *repos = NULL; + long rev = -1; apr_pool_t *pool; + char *kwnames[] = { "path", "uuid", "url", "repos", "rev", "depth", NULL }; + int depth = svn_depth_infinity; - if (!PyArg_ParseTuple(args, "O", &py_path)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - pool = Pool(NULL); - if (pool == NULL) - return NULL; - - path = py_object_to_svn_dirent(py_path, pool); - if (path == NULL) { - apr_pool_destroy(pool); - return NULL; - } - - RUN_SVN_WITH_POOL(pool, svn_wc_adm_retrieve(&result, admobj->adm, - path, pool)); - - ret = PyObject_New(AdmObject, &Adm_Type); - if (ret == NULL) - return NULL; - - ret->pool = pool; - ret->adm = result; - - return (PyObject *)ret; -} - -static PyObject *probe_retrieve(PyObject *self, PyObject *args) -{ - const char *path; - svn_wc_adm_access_t *result; - AdmObject *admobj = (AdmObject *)self, *ret; - apr_pool_t *pool; - PyObject *py_path; - - if (!PyArg_ParseTuple(args, "O", &py_path)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oss|sli", kwnames, + &py_path, &uuid, &url, &repos, &rev, &depth)) return NULL; - ADM_CHECK_CLOSED(admobj); - pool = Pool(NULL); if (pool == NULL) { return NULL; @@ -2026,34 +699,35 @@ static PyObject *probe_retrieve(PyObject *self, PyObject *args) return NULL; } - RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_retrieve(&result, admobj->adm, - path, pool)); - - ret = PyObject_New(AdmObject, &Adm_Type); - if (ret == NULL) +#if ONLY_SINCE_SVN(1, 5) + RUN_SVN_WITH_POOL(pool, + svn_wc_ensure_adm3(path, + uuid, url, repos, rev, depth, pool)); +#else + if (depth != svn_depth_infinity) { + PyErr_SetString(PyExc_NotImplementedError, + "depth != infinity not supported with svn < 1.5"); + apr_pool_destroy(pool); return NULL; - - ret->pool = pool; - ret->adm = result; - - return (PyObject *)ret; + } + RUN_SVN_WITH_POOL(pool, + svn_wc_ensure_adm2(path, + uuid, url, repos, rev, pool)); +#endif + apr_pool_destroy(pool); + Py_RETURN_NONE; } -static PyObject *probe_try(PyObject *self, PyObject *args) +static PyObject *check_wc(PyObject *self, PyObject *args) { const char *path; - svn_wc_adm_access_t *result = NULL; - AdmObject *admobj = (AdmObject *)self, *ret; apr_pool_t *pool; - int levels_to_lock = -1; - bool writelock = false; + int wc_format; PyObject *py_path; - if (!PyArg_ParseTuple(args, "O|bi", &py_path, &writelock, &levels_to_lock)) + if (!PyArg_ParseTuple(args, "O", &py_path)) return NULL; - ADM_CHECK_CLOSED(admobj); - pool = Pool(NULL); if (pool == NULL) { return NULL; @@ -2065,47 +739,23 @@ static PyObject *probe_try(PyObject *self, PyObject *args) return NULL; } - RUN_SVN_WITH_POOL(pool, svn_wc_adm_probe_try3(&result, admobj->adm, - path, writelock, levels_to_lock, - py_cancel_check, NULL, pool)); - - if (result == NULL) { - apr_pool_destroy(pool); - Py_RETURN_NONE; - } - - ret = PyObject_New(AdmObject, &Adm_Type); - if (ret == NULL) - return NULL; - - ret->pool = pool; - ret->adm = result; - - return (PyObject *)ret; + RUN_SVN_WITH_POOL(pool, svn_wc_check_wc(path, &wc_format, pool)); + apr_pool_destroy(pool); + return PyLong_FromLong(wc_format); } -static PyObject *resolved_conflict(PyObject *self, PyObject *args) +static PyObject *cleanup_wc(PyObject *self, PyObject *args, PyObject *kwargs) { - AdmObject *admobj = (AdmObject *)self; - apr_pool_t *temp_pool; - bool resolve_props, resolve_tree, resolve_text; - int depth; -#if ONLY_SINCE_SVN(1, 5) - svn_wc_conflict_choice_t conflict_choice; -#else - int conflict_choice; -#endif - PyObject *notify_func = Py_None; const char *path; + char *diff3_cmd = NULL; + char *kwnames[] = { "path", "diff3_cmd", NULL }; + apr_pool_t *temp_pool; PyObject *py_path; - if (!PyArg_ParseTuple(args, "Obbbii|O", &py_path, &resolve_text, - &resolve_props, &resolve_tree, &depth, - &conflict_choice, ¬ify_func)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|z", kwnames, + &py_path, &diff3_cmd)) return NULL; - ADM_CHECK_CLOSED(admobj); - temp_pool = Pool(NULL); if (temp_pool == NULL) { return NULL; @@ -2117,275 +767,85 @@ static PyObject *resolved_conflict(PyObject *self, PyObject *args) return NULL; } -#if ONLY_SINCE_SVN(1, 6) RUN_SVN_WITH_POOL(temp_pool, - svn_wc_resolved_conflict4(path, admobj->adm, resolve_text?TRUE:FALSE, - resolve_props?TRUE:FALSE, resolve_tree?TRUE:FALSE, depth, - conflict_choice, py_wc_notify_func, - (void *)notify_func, py_cancel_check, - NULL, temp_pool)); -#elif ONLY_SINCE_SVN(1, 5) - if (resolve_tree) { - PyErr_SetString(PyExc_NotImplementedError, - "resolve_tree not supported with svn < 1.6"); - apr_pool_destroy(temp_pool); - return NULL; - } else { - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_resolved_conflict3(path, admobj->adm, resolve_text?TRUE:FALSE, - resolve_props?TRUE:FALSE, depth, - conflict_choice, py_wc_notify_func, - (void *)notify_func, py_cancel_check, - NULL, temp_pool)); - } -#else - if (resolve_tree) { - PyErr_SetString(PyExc_NotImplementedError, - "resolve_tree not supported with svn < 1.6"); - apr_pool_destroy(temp_pool); - return NULL; - } else if (depth != svn_depth_infinity && depth != svn_depth_files) { - PyErr_SetString(PyExc_NotImplementedError, - "only infinity and files values for depth are supported"); - apr_pool_destroy(temp_pool); - return NULL; - } else if (conflict_choice != 0) { - PyErr_SetString(PyExc_NotImplementedError, - "conflict choice not supported with svn < 1.5"); - apr_pool_destroy(temp_pool); - return NULL; - } else { - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_resolved_conflict2(path, admobj->adm, resolve_text?TRUE:FALSE, - resolve_props?TRUE:FALSE, - (depth == svn_depth_infinity), - py_wc_notify_func, - (void *)notify_func, py_cancel_check, - NULL, - temp_pool)); - } -#endif + svn_wc_cleanup2(path, diff3_cmd, py_cancel_check, NULL, + temp_pool)); apr_pool_destroy(temp_pool); Py_RETURN_NONE; } -static PyObject *conflicted(PyObject *self, PyObject *args) +static PyObject *match_ignore_list(PyObject *self, PyObject *args) { - const char *path; +#if ONLY_SINCE_SVN(1, 5) + char *str; + PyObject *py_list; + apr_array_header_t *list; apr_pool_t *temp_pool; - PyObject *ret; - AdmObject *admobj = (AdmObject *)self; - svn_boolean_t text_conflicted, prop_conflicted, tree_conflicted; - PyObject *py_path; + svn_boolean_t ret; - if (!PyArg_ParseTuple(args, "O", &py_path)) + if (!PyArg_ParseTuple(args, "sO", &str, &py_list)) return NULL; - ADM_CHECK_CLOSED(admobj); - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { + if (!string_list_to_apr_array(temp_pool, py_list, &list)) { apr_pool_destroy(temp_pool); return NULL; } -#if ONLY_SINCE_SVN(1, 6) - RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p2(&text_conflicted, - &prop_conflicted, &tree_conflicted, path, admobj->adm, temp_pool)); - - ret = Py_BuildValue("(bbb)", text_conflicted, prop_conflicted, tree_conflicted); -#else - RUN_SVN_WITH_POOL(temp_pool, svn_wc_conflicted_p(&text_conflicted, - &prop_conflicted, path, admobj->adm, temp_pool)); - - ret = Py_BuildValue("(bbO)", text_conflicted, prop_conflicted, Py_None); -#endif + ret = svn_wc_match_ignore_list(str, list, temp_pool); apr_pool_destroy(temp_pool); - return ret; + return PyBool_FromLong(ret); +#else + PyErr_SetNone(PyExc_NotImplementedError); + return NULL; +#endif } -/** - * Determine the status of a file in the specified working copy. - * - * :return: A status object. - */ -static PyObject *ra_status(PyObject *self, PyObject *args) -{ - const char *path; - svn_wc_status2_t *st; - apr_pool_t *temp_pool; - PyObject *ret; - AdmObject *admobj = (AdmObject *)self; - PyObject *py_path; - - if (!PyArg_ParseTuple(args, "O", &py_path)) - return NULL; - - ADM_CHECK_CLOSED(admobj); - - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } - - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_status2(&st, path, admobj->adm, temp_pool)); - - ret = py_status(st); - - apr_pool_destroy(temp_pool); - - return (PyObject*)ret; -} - -static PyMethodDef adm_methods[] = { - { "prop_set", adm_prop_set, METH_VARARGS, "S.prop_set(name, value, path, skip_checks=False)" }, - { "access_path", (PyCFunction)adm_access_path, METH_NOARGS, - "S.access_path() -> path\n" - "Returns the base path for this working copy handle." }, - { "prop_get", adm_prop_get, METH_VARARGS, "S.prop_get(name, path) -> value" }, - { "entries_read", adm_entries_read, METH_VARARGS, "S.entries_read(include_hidden=False) -> dict" }, - { "walk_entries", adm_walk_entries, METH_VARARGS, - "S.walk_entries(path, callback, show_hidden=False)\n" - "callback should be a function that takes a path and a wc entry" }, - { "locked", (PyCFunction)adm_locked, METH_NOARGS, - "S.locked() -> bool" }, - { "get_prop_diffs", adm_get_prop_diffs, METH_VARARGS, - "S.get_prop_diffs(path) -> (propchanges, originalprops)" }, - { "add", (PyCFunction)adm_add, METH_VARARGS|METH_KEYWORDS, "S.add(path, copyfrom_url=None, copyfrom_rev=-1, notify_func=None)" }, - { "copy", adm_copy, METH_VARARGS, "S.copy(src_path, dest_path, notify_func=None)" }, - { "delete", (PyCFunction)adm_delete, METH_VARARGS|METH_KEYWORDS, "S.delete(path, notify_func=None, keep_local=False)" }, - { "crawl_revisions", (PyCFunction)adm_crawl_revisions, METH_VARARGS|METH_KEYWORDS, - "S.crawl_revisions(path, reporter, restore_files=True, recurse=True, use_commit_times=True, notify_func=None) -> None" }, - { "get_update_editor", adm_get_update_editor, METH_VARARGS, NULL }, - { "close", (PyCFunction)adm_close, METH_NOARGS, - "S.close()" }, - { "entry", (PyCFunction)adm_entry, METH_VARARGS, - "s.entry(path, show_hidden=False) -> entry" }, - { "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)" }, - { "process_committed_queue", (PyCFunction)adm_process_committed_queue, METH_VARARGS, "S.process_committed_queue(queue, new_revnum, rev_date, rev_author)" }, - { "remove_lock", (PyCFunction)adm_remove_lock, METH_VARARGS, "S.remove_lock(path)" }, - { "has_binary_prop", (PyCFunction)adm_has_binary_prop, METH_VARARGS, "S.has_binary_prop(path) -> bool" }, - { "text_modified", (PyCFunction)adm_text_modified, METH_VARARGS, "S.text_modified(filename, force_comparison=False) -> bool" }, - { "props_modified", (PyCFunction)adm_props_modified, METH_VARARGS, "S.props_modified(filename) -> bool" }, - { "get_ancestry", (PyCFunction)get_ancestry, METH_VARARGS, - "S.get_ancestry(path) -> (url, rev)" }, - { "maybe_set_repos_root", (PyCFunction)maybe_set_repos_root, METH_VARARGS, "S.maybe_set_repos_root(path, repos)" }, - { "add_repos_file", (PyCFunction)add_repos_file, METH_KEYWORDS, - "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)" }, - { "mark_missing_deleted", (PyCFunction)mark_missing_deleted, METH_VARARGS, - "S.mark_missing_deleted(path)" }, - { "remove_from_revision_control", (PyCFunction)remove_from_revision_control, METH_VARARGS, - "S.remove_from_revision_control(name, destroy_wf=False, instant_error=False)" }, - { "relocate", (PyCFunction)relocate, METH_VARARGS, - "S.relocate(path, from, to, recurse=TRUE, validator=None)" }, - { "crop_tree", (PyCFunction)crop_tree, METH_VARARGS, - "S.crop_tree(target, depth, notify_func=None, cancel=None)" }, - { "translated_stream", (PyCFunction)translated_stream, METH_VARARGS, - "S.translated_stream(path, versioned_file, flags) -> stream" }, - { "is_wc_root", (PyCFunction)is_wc_root, METH_VARARGS, - "S.is_wc_root(path) -> wc_root" }, - { "transmit_text_deltas", (PyCFunction)transmit_text_deltas, METH_VARARGS, - "S.transmit_text_deltas(fulltext, editor) -> (tempfile, digest)" }, - { "transmit_prop_deltas", (PyCFunction)transmit_prop_deltas, METH_VARARGS, - "S.transmit_prop_deltas(path, entry, editor)" }, - { "probe_retrieve", (PyCFunction)probe_retrieve, METH_VARARGS, - "S.probe_retrieve(path) -> WorkingCopy" }, - { "retrieve", (PyCFunction)retrieve, METH_VARARGS, - "S.retrieve(path) -> WorkingCopy" }, - { "probe_try", (PyCFunction)probe_try, METH_VARARGS, - "S.probe_try(path, write_lock=False, levels_to_lock=-1)" }, - { "conflicted", (PyCFunction)conflicted, METH_VARARGS, - "S.conflicted(path) -> (text_conflicted, prop_conflicted, tree_conflicted)" }, - { "resolved_conflict", (PyCFunction)resolved_conflict, METH_VARARGS, - "S.resolved_conflict(path, resolve_text, resolve_props, resolve_tree, depth, conflict_choice, notify_func=None, cancel=None)" }, - { "status", (PyCFunction)ra_status, METH_VARARGS, "status(wc_path) -> Status" }, - { NULL, } -}; - -static PyTypeObject Adm_Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "wc.WorkingCopy", /* const char *tp_name; For printing, in format "<module>.<name>" */ - sizeof(AdmObject), - 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */ - - /* Methods to implement standard operations */ - - adm_dealloc, /* destructor tp_dealloc; */ - NULL, /* printfunc tp_print; */ - NULL, /* getattrfunc tp_getattr; */ - NULL, /* setattrfunc tp_setattr; */ - NULL, /* cmpfunc tp_compare; */ - adm_repr, /* reprfunc tp_repr; */ - - /* Method suites for standard classes */ - - NULL, /* PyNumberMethods *tp_as_number; */ - NULL, /* PySequenceMethods *tp_as_sequence; */ - NULL, /* PyMappingMethods *tp_as_mapping; */ - - /* More standard operations (here for binary compatibility) */ - - NULL, /* hashfunc tp_hash; */ - NULL, /* ternaryfunc tp_call; */ - adm_repr, /* reprfunc tp_repr; */ - NULL, /* getattrofunc tp_getattro; */ - NULL, /* setattrofunc tp_setattro; */ - - /* Functions to access object as input/output buffer */ - NULL, /* PyBufferProcs *tp_as_buffer; */ - - /* Flags to define presence of optional/expanded features */ - 0, /* long tp_flags; */ - - "Local working copy", /* const char *tp_doc; Documentation string */ - - /* Assigned meaning in release 2.0 */ - /* call function for all accessible objects */ - NULL, /* traverseproc tp_traverse; */ - - /* delete references to contained objects */ - NULL, /* inquiry tp_clear; */ - - /* Assigned meaning in release 2.1 */ - /* rich comparisons */ - NULL, /* richcmpfunc tp_richcompare; */ - - /* weak reference enabler */ - 0, /* Py_ssize_t tp_weaklistoffset; */ - - /* Added in release 2.2 */ - /* Iterators */ - NULL, /* getiterfunc tp_iter; */ - NULL, /* iternextfunc tp_iternext; */ - - /* Attribute descriptor and subclassing stuff */ - adm_methods, /* struct PyMethodDef *tp_methods; */ - NULL, /* struct PyMemberDef *tp_members; */ - NULL, /* struct PyGetSetDef *tp_getset; */ - NULL, /* struct _typeobject *tp_base; */ - NULL, /* PyObject *tp_dict; */ - NULL, /* descrgetfunc tp_descr_get; */ - NULL, /* descrsetfunc tp_descr_set; */ - 0, /* Py_ssize_t tp_dictoffset; */ - NULL, /* initproc tp_init; */ - NULL, /* allocfunc tp_alloc; */ - adm_init, /* newfunc tp_new; */ +static PyMethodDef wc_methods[] = { + { "check_wc", check_wc, METH_VARARGS, "check_wc(path) -> version\n" + "Check whether path contains a Subversion working copy\n" + "return the workdir version"}, + { "cleanup", (PyCFunction)cleanup_wc, + METH_VARARGS|METH_KEYWORDS, "cleanup(path, diff3_cmd=None)\n" }, + { "ensure_adm", (PyCFunction)ensure_adm, METH_KEYWORDS|METH_VARARGS, + "ensure_adm(path, uuid, url, repos=None, rev=None)" }, + { "get_adm_dir", (PyCFunction)get_adm_dir, METH_NOARGS, + "get_adm_dir() -> name" }, + { "set_adm_dir", (PyCFunction)set_adm_dir, METH_VARARGS, + "set_adm_dir(name)" }, + { "get_pristine_copy_path", get_pristine_copy_path, METH_VARARGS, + "get_pristine_copy_path(path) -> path" }, + { "get_pristine_contents", get_pristine_contents, METH_VARARGS, + "get_pristine_contents(path) -> stream" }, + { "is_adm_dir", is_adm_dir, METH_VARARGS, + "is_adm_dir(name) -> bool" }, + { "is_normal_prop", is_normal_prop, METH_VARARGS, + "is_normal_prop(name) -> bool" }, + { "is_entry_prop", is_entry_prop, METH_VARARGS, + "is_entry_prop(name) -> bool" }, + { "is_wc_prop", is_wc_prop, METH_VARARGS, + "is_wc_prop(name) -> bool" }, + { "revision_status", (PyCFunction)revision_status, + METH_KEYWORDS|METH_VARARGS, + "revision_status(wc_path, trail_url=None, committed=False)" + "-> (min_rev, max_rev, switched, modified)" }, + { "version", (PyCFunction)version, METH_NOARGS, + "version() -> (major, minor, patch, tag)\n\n" + "Version of libsvn_wc currently used." + }, + { "api_version", (PyCFunction)api_version, METH_NOARGS, + "api_version() -> (major, minor, patch, tag)\n\n" + "Version of libsvn_wc Subvertpy was compiled against." }, + { "match_ignore_list", (PyCFunction)match_ignore_list, METH_VARARGS, + "match_ignore_list(str, patterns) -> bool" }, + { "get_actual_target", (PyCFunction)get_actual_target, METH_VARARGS, + "get_actual_target(path) -> (anchor, target)" }, + { NULL, } }; static void committed_queue_dealloc(PyObject *self) @@ -2428,48 +888,39 @@ static PyObject *committed_queue_init(PyTypeObject *self, PyObject *args, PyObje static PyObject *committed_queue_queue(CommittedQueueObject *self, PyObject *args, PyObject *kwargs) { - char *path; - AdmObject *admobj; - PyObject *py_wcprop_changes = Py_None; + const char *path; + PyObject *admobj; + PyObject *py_wcprop_changes = Py_None, *py_path; + svn_wc_adm_access_t *adm = NULL; bool remove_lock = false, remove_changelist = false; char *md5_digest = NULL, *sha1_digest = NULL; bool recurse = false; - apr_pool_t *temp_pool; apr_array_header_t *wcprop_changes; int md5_digest_len, sha1_digest_len; +#if ONLY_SINCE_SVN(1, 7) + svn_wc_context_t *context = NULL; +#endif char *kwnames[] = { "path", "adm", "recurse", "wcprop_changes", "remove_lock", "remove_changelist", "md5_digest", "sha1_digest", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!|bObbz#z#", kwnames, - &path, &Adm_Type, &admobj, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bObbz#z#", kwnames, + &py_path, &admobj, &recurse, &py_wcprop_changes, &remove_lock, &remove_changelist, &md5_digest, &md5_digest_len, &sha1_digest, &sha1_digest_len)) return NULL; - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - if (!py_dict_to_wcprop_changes(py_wcprop_changes, self->pool, &wcprop_changes)) { - apr_pool_destroy(temp_pool); return NULL; } - path = apr_pstrdup(self->pool, path); + path = py_object_to_svn_abspath(py_path, self->pool); if (path == NULL) { - PyErr_NoMemory(); return NULL; } if (md5_digest != NULL) { if (md5_digest_len != APR_MD5_DIGESTSIZE) { PyErr_SetString(PyExc_ValueError, "Invalid size for md5 digest"); - apr_pool_destroy(temp_pool); - return NULL; - } - md5_digest = apr_pstrdup(temp_pool, md5_digest); - if (md5_digest == NULL) { - PyErr_NoMemory(); return NULL; } } @@ -2477,42 +928,65 @@ static PyObject *committed_queue_queue(CommittedQueueObject *self, PyObject *arg if (sha1_digest != NULL) { if (sha1_digest_len != APR_SHA1_DIGESTSIZE) { PyErr_SetString(PyExc_ValueError, "Invalid size for sha1 digest"); - apr_pool_destroy(temp_pool); - return NULL; - } - sha1_digest = apr_pstrdup(temp_pool, sha1_digest); - if (sha1_digest == NULL) { - PyErr_NoMemory(); return NULL; } } + if (PyObject_IsInstance(admobj, (PyObject *)&Adm_Type)) { + adm = PyObject_GetAdmAccess(admobj); +#if ONLY_SINCE_SVN(1, 7) + } else if (PyObject_IsInstance(admobj, (PyObject *)&Context_Type)) { + context = ((ContextObject*)admobj)->context; +#endif + } else { + PyErr_SetString(PyExc_TypeError, "Second arguments needs to be Adm or Context"); + return NULL; + } + +#if ONLY_SINCE_SVN(1, 7) + if (adm != NULL) { +#endif #if ONLY_SINCE_SVN(1, 6) { - svn_checksum_t svn_checksum, *svn_checksum_p = &svn_checksum; + svn_checksum_t *svn_checksum_p; - if (sha1_digest != NULL) { - svn_checksum.digest = (unsigned char *)sha1_digest; - svn_checksum.kind = svn_checksum_sha1; - } else if (md5_digest != NULL) { - svn_checksum.digest = (unsigned char *)md5_digest; - svn_checksum.kind = svn_checksum_md5; + if (md5_digest != NULL) { + svn_checksum_p = apr_palloc(self->pool, sizeof(svn_checksum_t)); + svn_checksum_p->digest = apr_pmemdup( + self->pool, (unsigned char *)md5_digest, APR_MD5_DIGESTSIZE); + svn_checksum_p->kind = svn_checksum_md5; } else { svn_checksum_p = NULL; } - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_queue_committed2(self->queue, path, admobj->adm, recurse?TRUE:FALSE, + RUN_SVN( + svn_wc_queue_committed2(self->queue, path, adm, recurse?TRUE:FALSE, wcprop_changes, remove_lock?TRUE:FALSE, remove_changelist?TRUE:FALSE, - svn_checksum_p, temp_pool)); + svn_checksum_p, self->pool)); } #else - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_queue_committed(&self->queue, path, admobj->adm, recurse?TRUE:FALSE, + RUN_SVN( + svn_wc_queue_committed(&self->queue, path, adm, recurse?TRUE:FALSE, wcprop_changes, remove_lock?TRUE:FALSE, remove_changelist?TRUE:FALSE, - (unsigned char *)md5_digest, temp_pool)); + (unsigned char *)md5_digest, self->pool)); #endif +#if ONLY_SINCE_SVN(1, 7) + } else { + svn_checksum_t *svn_checksum_p; - apr_pool_destroy(temp_pool); + if (sha1_digest != NULL) { + svn_checksum_p = apr_palloc(self->pool, sizeof(svn_checksum_t)); + svn_checksum_p->digest = apr_pmemdup( + self->pool, (unsigned char *)sha1_digest, APR_SHA1_DIGESTSIZE); + svn_checksum_p->kind = svn_checksum_sha1; + } else { + svn_checksum_p = NULL; + } + RUN_SVN( + svn_wc_queue_committed3(self->queue, context, path, recurse?TRUE:FALSE, + wcprop_changes, remove_lock?TRUE:FALSE, remove_changelist?TRUE:FALSE, + svn_checksum_p, self->pool)); + } +#endif Py_RETURN_NONE; } @@ -2523,7 +997,7 @@ static PyMethodDef committed_queue_methods[] = { { NULL } }; -static PyTypeObject CommittedQueue_Type = { +PyTypeObject CommittedQueue_Type = { PyVarObject_HEAD_INIT(NULL, 0) "wc.CommittedQueue", /* const char *tp_name; For printing, in format "<module>.<name>" */ sizeof(CommittedQueueObject), @@ -2593,393 +1067,1062 @@ static PyTypeObject CommittedQueue_Type = { committed_queue_init, /* newfunc tp_new; */ }; -/** - * Determine the revision status of a specified working copy. - * - * :return: Tuple with minimum and maximum revnums found, whether the - * working copy was switched and whether it was modified. - */ -static PyObject *revision_status(PyObject *self, PyObject *args, PyObject *kwargs) +svn_lock_t *py_object_to_svn_lock(PyObject *py_lock, apr_pool_t *pool) { - char *kwnames[] = { "wc_path", "trail_url", "committed", NULL }; - const char *wc_path; - char *trail_url=NULL; - bool committed=false; - PyObject *ret, *py_wc_path; - svn_wc_revision_status_t *revstatus; - apr_pool_t *temp_pool; + LockObject* lockobj = (LockObject *)py_lock; + if (!PyObject_IsInstance(py_lock, (PyObject *)&Lock_Type)) { + PyErr_SetString(PyExc_TypeError, "Expected Lock object"); + return NULL; + } + return &lockobj->lock; +} - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|zb", kwnames, &py_wc_path, - &trail_url, &committed)) - return NULL; +#if ONLY_SINCE_SVN(1, 7) +static PyTypeObject Context_Type; - temp_pool = Pool(NULL); - if (temp_pool == NULL) { - return NULL; - } +static PyObject *py_wc_context_locked(PyObject *self, PyObject *args) +{ + PyObject* py_path; + const char *path; + apr_pool_t *pool; + svn_wc_context_t *wc_context = ((ContextObject *)self)->context; + svn_boolean_t locked_here, locked; - wc_path = py_object_to_svn_dirent(py_wc_path, temp_pool); - if (wc_path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_revision_status( - &revstatus, wc_path, trail_url, - committed, py_cancel_check, NULL, temp_pool)); - ret = Py_BuildValue("(llbb)", revstatus->min_rev, revstatus->max_rev, - revstatus->switched, revstatus->modified); - apr_pool_destroy(temp_pool); - return ret; + if (!PyArg_ParseTuple(args, "O", &py_path)) + return NULL; + + pool = Pool(NULL); + + path = py_object_to_svn_abspath(py_path, pool); + if (path == NULL) { + apr_pool_destroy(pool); + return NULL; + } + + RUN_SVN_WITH_POOL(pool, svn_wc_locked2(&locked_here, &locked, wc_context, path, pool)); + + apr_pool_destroy(pool); + + return Py_BuildValue("(bb)", locked_here?true:false, locked?true:false); } -static PyObject *is_normal_prop(PyObject *self, PyObject *args) +static PyObject *py_wc_context_check_wc(PyObject *self, PyObject *args) { - char *name; + PyObject* py_path; + const char *path; + apr_pool_t *pool; + svn_wc_context_t *wc_context = ((ContextObject *)self)->context; + int wc_format; - if (!PyArg_ParseTuple(args, "s", &name)) - return NULL; + if (!PyArg_ParseTuple(args, "O", &py_path)) + return NULL; - return PyBool_FromLong(svn_wc_is_normal_prop(name)); + pool = Pool(NULL); + + path = py_object_to_svn_abspath(py_path, pool); + if (path == NULL) { + apr_pool_destroy(pool); + return NULL; + } + + RUN_SVN_WITH_POOL(pool, svn_wc_check_wc2(&wc_format, wc_context, path, pool)); + + apr_pool_destroy(pool); + +#if PY_MAJOR_VERSION >= 3 + return PyLong_FromLong(wc_format); +#else + return PyInt_FromLong(wc_format); +#endif } -static PyObject *is_adm_dir(PyObject *self, PyObject *args) +static PyObject *py_wc_context_text_modified_p2(PyObject *self, PyObject *args) { - char *name; - apr_pool_t *pool; - svn_boolean_t ret; + PyObject* py_path; + const char *path; + apr_pool_t *pool; + svn_wc_context_t *wc_context = ((ContextObject *)self)->context; + svn_boolean_t modified; - if (!PyArg_ParseTuple(args, "s", &name)) - return NULL; + if (!PyArg_ParseTuple(args, "O", &py_path)) + return NULL; - pool = Pool(NULL); - if (pool == NULL) - return NULL; + pool = Pool(NULL); - ret = svn_wc_is_adm_dir(name, pool); + path = py_object_to_svn_abspath(py_path, pool); + if (path == NULL) { + apr_pool_destroy(pool); + return NULL; + } - apr_pool_destroy(pool); + RUN_SVN_WITH_POOL(pool, svn_wc_text_modified_p2(&modified, wc_context, + path, FALSE, pool)); - return PyBool_FromLong(ret); + apr_pool_destroy(pool); + + return PyBool_FromLong(modified); } -static PyObject *is_wc_prop(PyObject *self, PyObject *args) +static PyObject *py_wc_context_props_modified_p2(PyObject *self, PyObject *args) { - char *name; + PyObject* py_path; + const char *path; + apr_pool_t *pool; + svn_wc_context_t *wc_context = ((ContextObject *)self)->context; + svn_boolean_t modified; - if (!PyArg_ParseTuple(args, "s", &name)) - return NULL; + if (!PyArg_ParseTuple(args, "O", &py_path)) + return NULL; - return PyBool_FromLong(svn_wc_is_wc_prop(name)); + pool = Pool(NULL); + + path = py_object_to_svn_abspath(py_path, pool); + if (path == NULL) { + apr_pool_destroy(pool); + return NULL; + } + + RUN_SVN_WITH_POOL(pool, svn_wc_props_modified_p2(&modified, wc_context, + path, pool)); + + apr_pool_destroy(pool); + + return PyBool_FromLong(modified); } -static PyObject *is_entry_prop(PyObject *self, PyObject *args) +static PyObject *py_wc_context_conflicted(PyObject *self, PyObject *args) { - char *name; + PyObject* py_path; + const char *path; + apr_pool_t *pool; + svn_wc_context_t *wc_context = ((ContextObject *)self)->context; + svn_boolean_t text_conflicted, props_conflicted, tree_conflicted; - if (!PyArg_ParseTuple(args, "s", &name)) - return NULL; + if (!PyArg_ParseTuple(args, "O", &py_path)) + return NULL; - return PyBool_FromLong(svn_wc_is_entry_prop(name)); -} + pool = Pool(NULL); -static PyObject *get_adm_dir(PyObject *self) + path = py_object_to_svn_abspath(py_path, pool); + if (path == NULL) { + apr_pool_destroy(pool); + return NULL; + } + + RUN_SVN_WITH_POOL(pool, svn_wc_conflicted_p3( + &text_conflicted, &props_conflicted, &tree_conflicted, wc_context, + path, pool)); + + apr_pool_destroy(pool); + + return Py_BuildValue("(bbb)", text_conflicted, props_conflicted, tree_conflicted); +} + +static PyObject *py_wc_context_crawl_revisions(PyObject *self, PyObject *args, PyObject *kwargs) { - apr_pool_t *pool; - PyObject *ret; - const char *dir; - pool = Pool(NULL); - if (pool == NULL) - return NULL; - dir = svn_wc_get_adm_dir(pool); - ret = py_object_from_svn_abspath(dir); - apr_pool_destroy(pool); - return ret; + PyObject* py_path, *py_reporter; + const char *path; + apr_pool_t *pool; + svn_wc_context_t *wc_context = ((ContextObject *)self)->context; + char *kwnames[] = { "path", "reporter", "restore_files", "depth", + "honor_depth_exclude", "depth_compatibility_trick", "use_commit_times", + "cancel", "notify", NULL }; + bool restore_files = false; + int depth = svn_depth_infinity; + bool honor_depth_exclude = true; + bool depth_compatibility_trick = false; + bool use_commit_times = false; + PyObject *notify = Py_None; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|bibbbOO", kwnames, + &py_path, &py_reporter, &restore_files, + &depth, &honor_depth_exclude, + &depth_compatibility_trick, + &use_commit_times, ¬ify)) { + return NULL; + } + + pool = Pool(NULL); + + path = py_object_to_svn_abspath(py_path, pool); + if (path == NULL) { + apr_pool_destroy(pool); + return NULL; + } + + RUN_SVN_WITH_POOL(pool, svn_wc_crawl_revisions5( + wc_context, path, &py_ra_reporter3, py_reporter, restore_files, + depth, honor_depth_exclude, depth_compatibility_trick, + use_commit_times, py_cancel_check, NULL, py_wc_notify_func, notify, pool)); + + apr_pool_destroy(pool); + + Py_RETURN_NONE; +} + +static void context_done_handler(void *self) +{ + PyObject *selfobj = (PyObject *)self; + + Py_DECREF(selfobj); +} + +static PyObject *py_wc_context_get_update_editor(PyObject *self, PyObject *args, PyObject *kwargs) +{ + char *kwnames[] = { + "anchor_abspath", "target_basename", "use_commit_times", "depth", + "depth_is_sticky", "allow_unver_obstructions", "adds_as_modification", + "server_performs_filtering", "clean_checkout", "diff3_cmd", + "preserved_exts", "dirents_func", "conflict_func", "external_func", + "notify_func", NULL }; + const svn_delta_editor_t *editor; + void *edit_baton; + const char *anchor_abspath; + char *target_basename; + char *diff3_cmd = NULL; + svn_wc_context_t *wc_context = ((ContextObject *)self)->context; + bool use_commit_times = false; + int depth = svn_depth_infinity; + bool depth_is_sticky = false; + bool allow_unver_obstructions = true; + bool adds_as_modification = false; + bool server_performs_filtering = false; + bool clean_checkout = false; + apr_array_header_t *preserved_exts = NULL; + PyObject *py_preserved_exts = Py_None; + PyObject *dirents_func = Py_None; + PyObject *conflict_func = Py_None; + PyObject *external_func = Py_None; + PyObject *notify_func = Py_None; + PyObject *py_anchor_abspath; + apr_pool_t *result_pool, *scratch_pool; + svn_error_t *err; + svn_revnum_t target_revision; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os|bibbbbbzOOOOO", kwnames, + &py_anchor_abspath, &target_basename, + &use_commit_times, &depth, + &depth_is_sticky, + &allow_unver_obstructions, + &adds_as_modification, + &server_performs_filtering, + &clean_checkout, &py_preserved_exts, + &dirents_func, &conflict_func, + &external_func, ¬ify_func)) { + return NULL; + } + + if (conflict_func != Py_None) { + // TODO + PyErr_SetString(PyExc_NotImplementedError, + "conflict_func is not currently supported"); + return NULL; + } + + if (external_func != Py_None) { + // TODO + PyErr_SetString(PyExc_NotImplementedError, + "external_func is not currently supported"); + return NULL; + } + + if (dirents_func != Py_None) { + // TODO + PyErr_SetString(PyExc_NotImplementedError, + "dirents_func is not currently supported"); + return NULL; + } + + scratch_pool = Pool(NULL); + + anchor_abspath = py_object_to_svn_abspath(py_anchor_abspath, scratch_pool); + + if (py_preserved_exts != Py_None) { + if (!string_list_to_apr_array(scratch_pool, py_preserved_exts, &preserved_exts)) { + apr_pool_destroy(scratch_pool); + return NULL; + } + } + + result_pool = Pool(NULL); + + Py_BEGIN_ALLOW_THREADS + err = svn_wc_get_update_editor4( + &editor, &edit_baton, &target_revision, wc_context, + anchor_abspath, target_basename, use_commit_times, depth, + depth_is_sticky, allow_unver_obstructions, adds_as_modification, + server_performs_filtering, clean_checkout, diff3_cmd, + preserved_exts, NULL, dirents_func, NULL, conflict_func, NULL, + external_func, py_cancel_check, NULL, py_wc_notify_func, + notify_func, result_pool, scratch_pool); + Py_END_ALLOW_THREADS + + apr_pool_destroy(scratch_pool); + + if (err != NULL) { + handle_svn_error(err); + svn_error_clear(err); + apr_pool_destroy(result_pool); + return NULL; + } + + /* TODO: Also return target_revision ? */ + Py_INCREF(self); + return new_editor_object(NULL, editor, edit_baton, result_pool, &Editor_Type, + context_done_handler, self, NULL); +} + +static PyObject *py_wc_context_ensure_adm(PyObject *self, PyObject *args, + PyObject *kwargs) +{ + ContextObject *context_obj = (ContextObject *)self; + char *kwnames[] = { + "local_abspath", "url", "repos_root_url", "repos_uuid", + "revnum", "depth", NULL }; + char *local_abspath; + char *url; + char *repos_root_url; + char *repos_uuid; + int revnum; + int depth = svn_depth_infinity; + apr_pool_t *pool; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ssssi|i", kwnames, + &local_abspath, &url, &repos_root_url, + &repos_uuid, &revnum, &depth)) { + return NULL; + } + + pool = Pool(NULL); + + RUN_SVN_WITH_POOL(pool, svn_wc_ensure_adm4(context_obj->context, + local_abspath, url, + repos_root_url, repos_uuid, + revnum, depth, pool)); + + apr_pool_destroy(pool); + + Py_RETURN_NONE; } -static PyObject *set_adm_dir(PyObject *self, PyObject *args) +typedef struct { + PyObject_VAR_HEAD + apr_pool_t *pool; + svn_wc_status3_t status; +} Status3Object; + +static void status_dealloc(PyObject *self) { - apr_pool_t *temp_pool; - char *name; - PyObject *py_name; + apr_pool_t *pool = ((Status3Object *)self)->pool; + if (pool != NULL) + apr_pool_destroy(pool); + PyObject_Del(self); +} - if (!PyArg_ParseTuple(args, "O", &py_name)) - return NULL; +static PyMemberDef status_members[] = { + { "kind", T_INT, offsetof(Status3Object, status.kind), READONLY, + "The kind of node as recorded in the working copy." }, + { "depth", T_INT, offsetof(Status3Object, status.depth), READONLY, + "The depth of the node as recorded in the working copy." }, + { "filesize", T_LONG, offsetof(Status3Object, status.filesize), READONLY, + "The actual size of the working file on disk, or SVN_INVALID_FILESIZE" + "if unknown (or if the item isn't a file at all)" }, + { "versioned", T_BOOL, offsetof(Status3Object, status.versioned), READONLY, + "If the path is under version control, versioned is TRUE, " + "otherwise FALSE." }, + { "repos_uuid", T_STRING, offsetof(Status3Object, status.repos_uuid), READONLY, + "UUID of repository" }, + { "repos_root_url", T_STRING, offsetof(Status3Object, status.repos_root_url), READONLY, + "Repository root URL" }, + { "repos_relpath", T_STRING, offsetof(Status3Object, status.repos_relpath), READONLY, + "Relative path in repository" }, + /* TODO */ + { NULL } +}; - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - name = py_object_to_svn_string(py_name, temp_pool); - if (name == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } - RUN_SVN_WITH_POOL(temp_pool, svn_wc_set_adm_dir(name, temp_pool)); - apr_pool_destroy(temp_pool); - Py_RETURN_NONE; -} +static PyTypeObject Status3_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "wc.Status", /* const char *tp_name; For printing, in format "<module>.<name>" */ + sizeof(Status3Object), + 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */ -static PyObject *get_pristine_copy_path(PyObject *self, PyObject *args) -{ - apr_pool_t *pool; - const char *pristine_path; - const char *path; - PyObject *py_path; - PyObject *ret; + /* Methods to implement standard operations */ - if (!PyArg_ParseTuple(args, "O", &py_path)) - return NULL; + status_dealloc, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + NULL, /* reprfunc tp_repr; */ - pool = Pool(NULL); - if (pool == NULL) - return NULL; + /* Method suites for standard classes */ - path = py_object_to_svn_dirent(py_path, pool); - if (path == NULL) { - apr_pool_destroy(pool); - return NULL; - } + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ - PyErr_WarnEx(PyExc_DeprecationWarning, "get_pristine_copy_path is deprecated. Use get_pristine_contents instead.", 2); - RUN_SVN_WITH_POOL(pool, - svn_wc_get_pristine_copy_path(path, - &pristine_path, pool)); - ret = py_object_from_svn_abspath(pristine_path); - apr_pool_destroy(pool); - return ret; -} + /* More standard operations (here for binary compatibility) */ -static PyObject *get_pristine_contents(PyObject *self, PyObject *args) -{ - const char *path; - apr_pool_t *temp_pool; - PyObject *py_path; -#if ONLY_SINCE_SVN(1, 6) - apr_pool_t *stream_pool; - StreamObject *ret; - svn_stream_t *stream; -#else - PyObject *ret; - const char *pristine_path; -#endif + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ - if (!PyArg_ParseTuple(args, "O", &py_path)) - return NULL; + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ -#if ONLY_SINCE_SVN(1, 6) - stream_pool = Pool(NULL); - if (stream_pool == NULL) - return NULL; + /* Flags to define presence of optional/expanded features */ + 0, /* long tp_flags; */ - temp_pool = Pool(stream_pool); - if (temp_pool == NULL) { - apr_pool_destroy(stream_pool); - return NULL; - } + NULL, /* const char *tp_doc; Documentation string */ - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); - return NULL; - } + /* Assigned meaning in release 2.0 */ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ - RUN_SVN_WITH_POOL(stream_pool, svn_wc_get_pristine_contents(&stream, path, stream_pool, temp_pool)); - apr_pool_destroy(temp_pool); + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ - if (stream == NULL) { - apr_pool_destroy(stream_pool); - Py_RETURN_NONE; - } + /* Assigned meaning in release 2.1 */ + /* rich comparisons */ + NULL, /* richcmpfunc tp_richcompare; */ - ret = PyObject_New(StreamObject, &Stream_Type); - if (ret == NULL) - return NULL; + /* weak reference enabler */ + 0, /* Py_ssize_t tp_weaklistoffset; */ - ret->pool = stream_pool; - ret->closed = FALSE; - ret->stream = stream; + /* Added in release 2.2 */ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ - return (PyObject *)ret; + /* Attribute descriptor and subclassing stuff */ + NULL, /* struct PyMethodDef *tp_methods; */ + status_members, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getsetters; */ +}; + +static PyObject *py_wc_status(PyObject *self, PyObject *args, PyObject *kwargs) +{ + ContextObject *context_obj = (ContextObject *)self; + char *kwnames[] = {"path", NULL}; + PyObject *py_path; + Status3Object *ret; + const char *path; + apr_pool_t *scratch_pool, *result_pool; + svn_wc_status3_t* status; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &py_path)) { + return NULL; + } + + result_pool = Pool(NULL); + if (result_pool == NULL) { + return NULL; + } + scratch_pool = Pool(result_pool); + if (scratch_pool == NULL) { + apr_pool_destroy(result_pool); + return NULL; + } + + path = py_object_to_svn_abspath(py_path, scratch_pool); + if (path == NULL) { + apr_pool_destroy(result_pool); + return NULL; + } + + RUN_SVN_WITH_POOL(result_pool, + svn_wc_status3(&status, context_obj->context, path, + result_pool, scratch_pool)); + + apr_pool_destroy(scratch_pool); + + ret = PyObject_New(Status3Object, &Status3_Type); + if (ret == NULL) { + apr_pool_destroy(result_pool); + return NULL; + } + ret->pool = result_pool; + ret->status = *status; + return (PyObject *)ret; +} + +static svn_error_t *py_status_receiver(void *baton, const char *local_abspath, + const svn_wc_status3_t *status, + apr_pool_t *scratch_pool) +{ + Status3Object *py_status; + PyObject *ret; + PyGILState_STATE state; + + if (baton == Py_None) + return NULL; + + state = PyGILState_Ensure(); + + py_status = PyObject_New(Status3Object, &Status3_Type); + if (py_status == NULL) { + PyGILState_Release(state); + return py_svn_error(); + } + py_status->pool = Pool(NULL); + py_status->status = *svn_wc_dup_status3(status, py_status->pool); + + ret = PyObject_CallFunction((PyObject *)baton, "sO", local_abspath, py_status); + Py_DECREF(py_status); + + if (ret == NULL) { + PyGILState_Release(state); + return py_svn_error(); + } + + Py_DECREF(ret); + PyGILState_Release(state); + + return NULL; +} + +static PyObject *py_wc_walk_status(PyObject *self, PyObject *args, PyObject *kwargs) +{ + ContextObject *context_obj = (ContextObject *)self; + char *kwnames[] = {"path", "receiver", "depth", "get_all", "no_ignore", + "ignore_text_mode", "ignore_patterns", NULL}; + PyObject *py_path; + const char *path; + int depth = svn_depth_infinity; + bool get_all = true; + bool no_ignore = false; + bool ignore_text_mode = false; + PyObject *py_ignore_patterns = Py_None; + PyObject *status_func; + apr_array_header_t *ignore_patterns; + apr_pool_t *pool; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|ibbbOO", kwnames, + &py_path, &status_func, &depth, &get_all, &no_ignore, + &ignore_text_mode, &py_ignore_patterns)) { + return NULL; + } + + pool = Pool(NULL); + + path = py_object_to_svn_abspath(py_path, pool); + if (path == NULL) { + apr_pool_destroy(pool); + return NULL; + } + + if (py_ignore_patterns == Py_None) { + ignore_patterns = NULL; + } else { + if (!string_list_to_apr_array(pool, py_ignore_patterns, &ignore_patterns)) { + apr_pool_destroy(pool); + return NULL; + } + } + + RUN_SVN_WITH_POOL(pool, + svn_wc_walk_status(context_obj->context, path, depth, + get_all, no_ignore, ignore_text_mode, + ignore_patterns, py_status_receiver, + status_func, py_cancel_check, NULL, + pool)); + + apr_pool_destroy(pool); + + Py_RETURN_NONE; +} + +static PyObject *py_wc_add_lock(PyObject *self, PyObject *args, PyObject *kwargs) +{ + ContextObject *context_obj = (ContextObject *)self; + PyObject *py_path, *py_lock; + svn_lock_t *lock; + char *kwnames[] = { "path", "lock", NULL }; + const char *path; + apr_pool_t *scratch_pool; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO!", kwnames, &py_path, &Lock_Type, + &py_lock)) { + return NULL; + } + + scratch_pool = Pool(NULL); + if (scratch_pool == NULL) { + return NULL; + } + + path = py_object_to_svn_abspath(py_path, scratch_pool); + if (path == NULL) { + apr_pool_destroy(scratch_pool); + return NULL; + } + + lock = py_object_to_svn_lock(py_lock, scratch_pool); + if (lock == NULL) { + apr_pool_destroy(scratch_pool); + return NULL; + } + + RUN_SVN_WITH_POOL(scratch_pool, + svn_wc_add_lock2(context_obj->context, path, lock, scratch_pool)); + + apr_pool_destroy(scratch_pool); + + Py_RETURN_NONE; +} + +static PyObject *py_wc_remove_lock(PyObject *self, PyObject *args, PyObject *kwargs) +{ + ContextObject *context_obj = (ContextObject *)self; + char *kwnames[] = { "path", NULL }; + PyObject *py_path; + const char *path; + apr_pool_t *scratch_pool; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &py_path)) { + return NULL; + } + + scratch_pool = Pool(NULL); + + path = py_object_to_svn_abspath(py_path, scratch_pool); + if (path == NULL) { + apr_pool_destroy(scratch_pool); + return NULL; + } + + RUN_SVN_WITH_POOL(scratch_pool, + svn_wc_remove_lock2(context_obj->context, path, + scratch_pool)); + + apr_pool_destroy(scratch_pool); + Py_RETURN_NONE; +} + +static PyObject *py_wc_add_from_disk(PyObject *self, PyObject *args, PyObject *kwargs) +{ + ContextObject *context_obj = (ContextObject *)self; + char *kwnames[] = {"path", "props", "skip_checks", "notify", NULL }; + PyObject *py_path; + const char *path; + bool skip_checks = false; + PyObject *py_props = Py_None; + PyObject *notify_func = Py_None; + apr_pool_t *pool; + apr_hash_t *props; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|ObO", kwnames, + &py_path, &py_props, &skip_checks, ¬ify_func)) { + return NULL; + } + + pool = Pool(NULL); + if (pool == NULL) { + return NULL; + } + + path = py_object_to_svn_abspath(py_path, pool); + if (path == NULL) { + apr_pool_destroy(pool); + return NULL; + } + + if (py_props == Py_None) { + props = NULL; + } else { + props = prop_dict_to_hash(pool, py_props); + if (props == NULL) { + apr_pool_destroy(pool); + return NULL; + } + } + +#if ONLY_SINCE_SVN(1, 9) + RUN_SVN_WITH_POOL( + pool, svn_wc_add_from_disk3( + context_obj->context, path, props, skip_checks, + notify_func == Py_None?NULL:py_wc_notify_func, + notify_func, pool)); #else - temp_pool = Pool(NULL); - if (temp_pool == NULL) - return NULL; - RUN_SVN_WITH_POOL(temp_pool, svn_wc_get_pristine_copy_path(path, &pristine_path, temp_pool)); - ret = PyFile_FromString((char *)pristine_path, "rb"); - apr_pool_destroy(temp_pool); - return ret; + if (props != NULL) { + PyErr_SetString(PyExc_NotImplementedError, + "props argument only supported on svn >= 1.9"); + apr_pool_destroy(pool); + return NULL; + } + + if (skip_checks) { + PyErr_SetString(PyExc_NotImplementedError, + "skip_checks argument only supported on svn >= 1.9"); + apr_pool_destroy(pool); + return NULL; + } + RUN_SVN_WITH_POOL( + pool, svn_wc_add_from_disk( + context_obj->context, path, + notify_func == Py_None?NULL:py_wc_notify_func, + notify_func, pool)); #endif + + apr_pool_destroy(pool); + + Py_RETURN_NONE; } -static PyObject *ensure_adm(PyObject *self, PyObject *args, PyObject *kwargs) +static PyObject *py_wc_get_prop_diffs(PyObject *self, PyObject *args, PyObject *kwargs) +{ + ContextObject *context_obj = (ContextObject *)self; + PyObject *py_path, *py_orig_props, *py_propchanges; + apr_pool_t *pool; + char *kwnames[] = {"path", NULL}; + apr_hash_t *original_props; + apr_array_header_t *propchanges; + const char *path; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &py_path)) { + return NULL; + } + + pool = Pool(NULL); + + path = py_object_to_svn_abspath(py_path, pool); + if (path == NULL) { + apr_pool_destroy(pool); + return NULL; + } + + RUN_SVN_WITH_POOL(pool, svn_wc_get_prop_diffs2(&propchanges, + &original_props, + context_obj->context, + path, pool, pool)); + + py_orig_props = prop_hash_to_dict(original_props); + if (py_orig_props == NULL) { + apr_pool_destroy(pool); + return NULL; + } + + py_propchanges = propchanges_to_list(propchanges); + if (py_propchanges == NULL) { + apr_pool_destroy(pool); + Py_DECREF(py_propchanges); + return NULL; + } + + apr_pool_destroy(pool); + + return Py_BuildValue("NN", py_orig_props, py_propchanges); +} + +static PyObject *py_wc_context_process_committed_queue(PyObject *self, PyObject *args) +{ + apr_pool_t *temp_pool; + ContextObject *contextobj = (ContextObject *)self; + svn_revnum_t revnum; + char *date, *author; + PyObject *py_queue; + + if (!PyArg_ParseTuple(args, "O!lss", &CommittedQueue_Type, &py_queue, + &revnum, &date, &author)) + return NULL; + + temp_pool = Pool(NULL); + if (temp_pool == NULL) + return NULL; + + svn_wc_committed_queue_t *committed_queue = PyObject_GetCommittedQueue(py_queue); + + RUN_SVN_WITH_POOL(temp_pool, + svn_wc_process_committed_queue2(committed_queue, + contextobj->context, + revnum, date, author, + py_cancel_check, NULL, + temp_pool)); + + apr_pool_destroy(temp_pool); + + Py_RETURN_NONE; +} + + + +static PyMethodDef context_methods[] = { + { "locked", py_wc_context_locked, METH_VARARGS, + "locked(path) -> (locked_here, locked)\n" + "Check whether a patch is locked."}, + { "check_wc", py_wc_context_check_wc, METH_VARARGS, + "check_wc(path) -> wc_format\n" + "Check format version of a working copy." }, + { "text_modified", py_wc_context_text_modified_p2, METH_VARARGS, + "text_modified(path) -> bool\n" + "Check whether text of a file is modified against base." }, + { "props_modified", py_wc_context_props_modified_p2, METH_VARARGS, + "props_modified(path) -> bool\n" + "Check whether props of a file are modified against base." }, + { "conflicted", py_wc_context_conflicted, METH_VARARGS, + "conflicted(path) -> (text_conflicted, prop_conflicted, " + "tree_conflicted)\n" + "Check whether a path is conflicted." }, + { "crawl_revisions", (PyCFunction)py_wc_context_crawl_revisions, + METH_VARARGS|METH_KEYWORDS, + "crawl_revisions(path, reporter, restore_files, depth, " + "honor_depth_exclude, depth_compatibility_trick, " + "use_commit_time, notify)\n" + "Do a depth-first crawl of the working copy." }, + { "get_update_editor", + (PyCFunction)py_wc_context_get_update_editor, + METH_VARARGS|METH_KEYWORDS, + "get_update_editor(anchor_abspath, target_basename, use_commit_time, " + "depth, depth_is_sticky, allow_unver_obstructions, " + "adds_as_modification, server_performs_filtering, clean_checkout, " + "diff3_cmd, dirent_func=None, conflict_func=None, " + "external_func=None) -> target_revnum" }, + { "ensure_adm", + (PyCFunction)py_wc_context_ensure_adm, + METH_VARARGS|METH_KEYWORDS, + "ensure_adm(local_abspath, url, repos_root_url, repos_uuid, revnum, depth)" }, + { "process_committed_queue", + (PyCFunction)py_wc_context_process_committed_queue, + METH_VARARGS|METH_KEYWORDS, + "" }, + { "status", + (PyCFunction)py_wc_status, + METH_VARARGS|METH_KEYWORDS, + "status(path) -> status" }, + { "walk_status", + (PyCFunction)py_wc_walk_status, + METH_VARARGS|METH_KEYWORDS, + "walk_status(path, receiver, depth=DEPTH_INFINITY, get_all=True, " + "no_ignore=False, ignore_text_mode=False, ignore_patterns=None)\n" }, + { "add_lock", + (PyCFunction)py_wc_add_lock, + METH_VARARGS|METH_KEYWORDS, + "add_lock(path, lock)" }, + { "remove_lock", + (PyCFunction)py_wc_remove_lock, + METH_VARARGS|METH_KEYWORDS, + "remove_lock(path)" }, + { "add_from_disk", + (PyCFunction)py_wc_add_from_disk, + METH_VARARGS|METH_KEYWORDS, + "add_from_disk(local_abspath, props=None, skip_checks=False, notify=None)" }, + { "get_prop_diffs", + (PyCFunction)py_wc_get_prop_diffs, + METH_VARARGS|METH_KEYWORDS, + "get_prop_diffs(path) -> (changes orig_props)" }, + { NULL } +}; + +static void context_dealloc(PyObject *self) { - const char *path; - char *uuid, *url; - PyObject *py_path; - char *repos=NULL; - svn_revnum_t rev=-1; - apr_pool_t *pool; - char *kwnames[] = { "path", "uuid", "url", "repos", "rev", "depth", NULL }; - svn_depth_t depth = svn_depth_infinity; + ContextObject *context_obj = (ContextObject *)self; + svn_wc_context_destroy(context_obj->context); + apr_pool_destroy(context_obj->pool); + PyObject_Del(self); +} - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oss|sli", kwnames, - &py_path, &uuid, &url, &repos, &rev, &depth)) - return NULL; +static PyObject *context_init(PyTypeObject *self, PyObject *args, PyObject *kwargs) +{ + ContextObject *ret; + char *kwnames[] = { NULL }; + svn_config_t *config = NULL; - pool = Pool(NULL); - if (pool == NULL) { - return NULL; - } + // TODO(jelmer): Support passing in config + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", kwnames)) + return NULL; - path = py_object_to_svn_dirent(py_path, pool); - if (path == NULL) { - apr_pool_destroy(pool); - return NULL; - } + ret = PyObject_New(ContextObject, &Context_Type); + if (ret == NULL) + return NULL; -#if ONLY_SINCE_SVN(1, 5) - RUN_SVN_WITH_POOL(pool, - svn_wc_ensure_adm3(path, - uuid, url, repos, rev, depth, pool)); -#else - if (depth != svn_depth_infinity) { - PyErr_SetString(PyExc_NotImplementedError, - "depth != infinity not supported with svn < 1.5"); - apr_pool_destroy(pool); - return NULL; - } - RUN_SVN_WITH_POOL(pool, - svn_wc_ensure_adm2(path, - uuid, url, repos, rev, pool)); -#endif - apr_pool_destroy(pool); - Py_RETURN_NONE; + ret->pool = Pool(NULL); + if (ret->pool == NULL) + return NULL; + RUN_SVN_WITH_POOL(ret->pool, svn_wc_context_create(&ret->context, config, + ret->pool, ret->pool)); + + return (PyObject *)ret; } -static PyObject *check_wc(PyObject *self, PyObject *args) -{ - const char *path; - apr_pool_t *pool; - int wc_format; - PyObject *py_path; +static PyTypeObject Context_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "wc.Context", /* const char *tp_name; For printing, in format "<module>.<name>" */ + sizeof(ContextObject), + 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */ - if (!PyArg_ParseTuple(args, "O", &py_path)) - return NULL; + /* Methods to implement standard operations */ - pool = Pool(NULL); - if (pool == NULL) { - return NULL; - } + context_dealloc, /* destructor tp_dealloc; */ + NULL, /* printfunc tp_print; */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, /* cmpfunc tp_compare; */ + NULL, /* reprfunc tp_repr; */ - path = py_object_to_svn_dirent(py_path, pool); - if (path == NULL) { - apr_pool_destroy(pool); - return NULL; - } + /* Method suites for standard classes */ - RUN_SVN_WITH_POOL(pool, svn_wc_check_wc(path, &wc_format, pool)); - apr_pool_destroy(pool); - return PyLong_FromLong(wc_format); + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + NULL, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /* Flags to define presence of optional/expanded features */ + 0, /* long tp_flags; */ + + "Context", /* const char *tp_doc; Documentation string */ + + /* Assigned meaning in release 2.0 */ + /* call function for all accessible objects */ + NULL, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + NULL, /* inquiry tp_clear; */ + + /* Assigned meaning in release 2.1 */ + /* rich comparisons */ + NULL, /* richcmpfunc tp_richcompare; */ + + /* weak reference enabler */ + 0, /* Py_ssize_t tp_weaklistoffset; */ + + /* Added in release 2.2 */ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /* Attribute descriptor and subclassing stuff */ + context_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* Py_ssize_t tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + context_init, /* newfunc tp_new; */ +}; + +#endif + +static void lock_dealloc(PyObject *self) +{ + LockObject *lockself = (LockObject *)self; + + apr_pool_destroy(lockself->pool); + + PyObject_Del(self); } -static PyObject *cleanup_wc(PyObject *self, PyObject *args, PyObject *kwargs) +static PyObject *lock_init(PyTypeObject *type, PyObject *args, PyObject *kwargs) { - const char *path; - char *diff3_cmd = NULL; - char *kwnames[] = { "path", "diff3_cmd", NULL }; - apr_pool_t *temp_pool; - PyObject *py_path; + char *kwnames[] = { "token", NULL }; + LockObject *ret; + char *token = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|z", kwnames, - &py_path, &diff3_cmd)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|z", kwnames, &token)) return NULL; - temp_pool = Pool(NULL); - if (temp_pool == NULL) { + ret = PyObject_New(LockObject, &Lock_Type); + if (ret == NULL) return NULL; - } - path = py_object_to_svn_dirent(py_path, temp_pool); - if (path == NULL) { - apr_pool_destroy(temp_pool); + ret->pool = Pool(NULL); + if (ret->pool == NULL) return NULL; - } + ret->lock = *svn_lock_create(ret->pool); + if (token != NULL) { + ret->lock.token = apr_pstrdup(ret->pool, token); + } - RUN_SVN_WITH_POOL(temp_pool, - svn_wc_cleanup2(path, diff3_cmd, py_cancel_check, NULL, - temp_pool)); - apr_pool_destroy(temp_pool); + return (PyObject *)ret; +} - Py_RETURN_NONE; +static PyObject *lock_get_path(PyObject *self, void *closure) { + LockObject *lock_obj = (LockObject *)self; + + if (lock_obj->lock.path == NULL) { + Py_RETURN_NONE; + } + + return PyUnicode_FromString(lock_obj->lock.path); } -static PyObject *match_ignore_list(PyObject *self, PyObject *args) -{ -#if ONLY_SINCE_SVN(1, 5) - char *str; - PyObject *py_list; - apr_array_header_t *list; - apr_pool_t *temp_pool; - svn_boolean_t ret; +static int lock_set_path(PyObject *self, PyObject *value, void *closure) { + LockObject *lock_obj = (LockObject *)self; + char *path; - if (!PyArg_ParseTuple(args, "sO", &str, &py_list)) - return NULL; + path = PyBytes_AsString(value); + if (path == NULL) { + return -1; + } - temp_pool = Pool(NULL); + lock_obj->lock.path = py_object_to_svn_string(value, lock_obj->pool); + return 0; +} - if (!string_list_to_apr_array(temp_pool, py_list, &list)) { - apr_pool_destroy(temp_pool); - return NULL; - } +static PyObject *lock_get_token(PyObject *self, void *closure) { + LockObject *lock_obj = (LockObject *)self; - ret = svn_wc_match_ignore_list(str, list, temp_pool); + if (lock_obj->lock.token == NULL) { + Py_RETURN_NONE; + } - apr_pool_destroy(temp_pool); + return PyBytes_FromString(lock_obj->lock.token); +} - return PyBool_FromLong(ret); -#else - PyErr_SetNone(PyExc_NotImplementedError); - return NULL; -#endif +static int lock_set_token(PyObject *self, PyObject *value, void *closure) { + LockObject *lock_obj = (LockObject *)self; + char *token; + + token = PyBytes_AsString(value); + if (token == NULL) { + PyErr_SetNone(PyExc_TypeError); + return -1; + } + + lock_obj->lock.token = apr_pstrdup(lock_obj->pool, PyBytes_AsString(value)); + return 0; } -static PyMethodDef wc_methods[] = { - { "check_wc", check_wc, METH_VARARGS, "check_wc(path) -> version\n" - "Check whether path contains a Subversion working copy\n" - "return the workdir version"}, - { "cleanup", (PyCFunction)cleanup_wc, METH_VARARGS|METH_KEYWORDS, "cleanup(path, diff3_cmd=None)\n" }, - { "ensure_adm", (PyCFunction)ensure_adm, METH_KEYWORDS|METH_VARARGS, - "ensure_adm(path, uuid, url, repos=None, rev=None)" }, - { "get_adm_dir", (PyCFunction)get_adm_dir, METH_NOARGS, - "get_adm_dir() -> name" }, - { "set_adm_dir", (PyCFunction)set_adm_dir, METH_VARARGS, - "set_adm_dir(name)" }, - { "get_pristine_copy_path", get_pristine_copy_path, METH_VARARGS, - "get_pristine_copy_path(path) -> path" }, - { "get_pristine_contents", get_pristine_contents, METH_VARARGS, - "get_pristine_contents(path) -> stream" }, - { "is_adm_dir", is_adm_dir, METH_VARARGS, - "is_adm_dir(name) -> bool" }, - { "is_normal_prop", is_normal_prop, METH_VARARGS, - "is_normal_prop(name) -> bool" }, - { "is_entry_prop", is_entry_prop, METH_VARARGS, - "is_entry_prop(name) -> bool" }, - { "is_wc_prop", is_wc_prop, METH_VARARGS, - "is_wc_prop(name) -> bool" }, - { "revision_status", (PyCFunction)revision_status, METH_KEYWORDS|METH_VARARGS, "revision_status(wc_path, trail_url=None, committed=False) -> (min_rev, max_rev, switched, modified)" }, - { "version", (PyCFunction)version, METH_NOARGS, - "version() -> (major, minor, patch, tag)\n\n" - "Version of libsvn_wc currently used." - }, - { "api_version", (PyCFunction)api_version, METH_NOARGS, - "api_version() -> (major, minor, patch, tag)\n\n" - "Version of libsvn_wc Subvertpy was compiled against." - }, - { "match_ignore_list", (PyCFunction)match_ignore_list, METH_VARARGS, - "match_ignore_list(str, patterns) -> bool" }, - { "get_actual_target", (PyCFunction)get_actual_target, METH_VARARGS, - "get_actual_target(path) -> (anchor, target)" }, - { NULL, } +static PyGetSetDef lock_getsetters[] = { + { "path", lock_get_path, lock_set_path, + "the path this lock applies to"}, + { "token", lock_get_token, lock_set_token, + "unique URI representing lock"}, + { NULL }, +}; + +PyTypeObject Lock_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "wc.Lock", /* const char *tp_name; For printing, in format "<module>.<name>" */ + sizeof(LockObject), + 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */ + + /* Methods to implement standard operations */ + + .tp_dealloc = lock_dealloc, /* destructor tp_dealloc; */ + + .tp_doc = "Lock", /* const char *tp_doc; Documentation string */ + + .tp_methods = NULL, /* struct PyMethodDef *tp_methods; */ + + .tp_new = lock_init, /* tp_new tp_new */ + + .tp_getset = lock_getsetters, }; static PyObject * @@ -2990,12 +2133,17 @@ moduleinit(void) if (PyType_Ready(&Entry_Type) < 0) return NULL; - if (PyType_Ready(&Status_Type) < 0) + if (PyType_Ready(&Status2_Type) < 0) return NULL; if (PyType_Ready(&Adm_Type) < 0) return NULL; +#if ONLY_SINCE_SVN(1, 7) + if (PyType_Ready(&Context_Type) < 0) + return NULL; +#endif + if (PyType_Ready(&Editor_Type) < 0) return NULL; @@ -3014,6 +2162,14 @@ moduleinit(void) if (PyType_Ready(&CommittedQueue_Type) < 0) return NULL; +#if ONLY_SINCE_SVN(1, 7) + if (PyType_Ready(&Status3_Type) < 0) + return NULL; +#endif + + if (PyType_Ready(&Lock_Type) < 0) + return NULL; + apr_initialize(); #if PY_MAJOR_VERSION >= 3 @@ -3089,15 +2245,18 @@ moduleinit(void) PyModule_AddIntConstant(mod, "CONFLICT_CHOOSE_MERGED", svn_wc_conflict_choose_merged); #endif -#if ONLY_BEFORE_SVN(1, 7) - /* Subversion 1.7 has a couple of significant behaviour changes that break subvertpy. - * We haven't updated the code to deal with these changes in behaviour yet. - * */ - PyModule_AddObject(mod, "WorkingCopy", (PyObject *)&Adm_Type); + PyModule_AddObject(mod, "Adm", (PyObject *)&Adm_Type); Py_INCREF(&Adm_Type); + PyModule_AddObject(mod, "Lock", (PyObject *)&Lock_Type); + Py_INCREF(&Lock_Type); + PyModule_AddObject(mod, "CommittedQueue", (PyObject *)&CommittedQueue_Type); Py_INCREF(&CommittedQueue_Type); + +#if ONLY_SINCE_SVN(1, 7) + PyModule_AddObject(mod, "Context", (PyObject *)&Context_Type); + Py_INCREF(&Context_Type); #endif return mod; |