1 /* Copyright © 2008 Jelmer Vernooij <jelmer@samba.org>
2 * -*- coding: utf-8 -*-
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <apr_general.h>
21 #include <svn_types.h>
22 #include <svn_delta.h>
29 const svn_delta_editor_t *editor;
32 void (*done_cb) (void *baton);
36 PyObject *new_editor_object(const svn_delta_editor_t *editor, void *baton, apr_pool_t *pool, PyTypeObject *type, void (*done_cb) (void *), void *done_baton)
38 EditorObject *obj = PyObject_New(EditorObject, type);
44 obj->done_cb = done_cb;
45 obj->done_baton = done_baton;
46 return (PyObject *)obj;
49 static void py_editor_dealloc(PyObject *self)
51 EditorObject *editor = (EditorObject *)self;
52 apr_pool_destroy(editor->pool);
57 #if defined(SIZEOF_SIZE_T) && SIZEOF_SIZE_T != SIZEOF_LONG
58 #error "Unable to determine PyArg_Parse format for size_t"
61 /* svn_filesize_t is always 64 bits */
63 #define SVN_FILESIZE_T_PYFMT "k"
64 #elif SIZEOF_LONG_LONG == 8
65 #define SVN_FILESIZE_T_PYFMT "K"
67 #error "Unable to determine PyArg_Parse format for size_t"
70 static PyObject *txdelta_call(PyObject *self, PyObject *args, PyObject *kwargs)
72 char *kwnames[] = { "window", NULL };
73 svn_txdelta_window_t window;
74 TxDeltaWindowHandlerObject *obj = (TxDeltaWindowHandlerObject *)self;
75 PyObject *py_window, *py_ops, *py_new_data;
77 svn_string_t new_data;
79 svn_txdelta_op_t *ops;
81 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwnames, &py_window))
84 if (py_window == Py_None) {
85 RUN_SVN(obj->txdelta_handler(NULL, obj->txdelta_baton));
89 if (!PyArg_ParseTuple(py_window, SVN_FILESIZE_T_PYFMT "kkiOO", &window.sview_offset, &window.sview_len,
90 &window.tview_len, &window.src_ops, &py_ops, &py_new_data))
93 if (py_new_data == Py_None) {
94 window.new_data = NULL;
96 new_data.data = PyString_AsString(py_new_data);
97 new_data.len = PyString_Size(py_new_data);
98 window.new_data = &new_data;
101 if (!PyList_Check(py_ops)) {
102 PyErr_SetString(PyExc_TypeError, "ops not a list");
106 window.num_ops = PyList_Size(py_ops);
108 window.ops = ops = malloc(sizeof(svn_txdelta_op_t) * window.num_ops);
110 for (i = 0; i < window.num_ops; i++) {
111 PyObject *windowitem = PyList_GetItem(py_ops, i);
112 if (!PyArg_ParseTuple(windowitem, "ikk", &ops[i].action_code,
113 &ops[i].offset, &ops[i].length)) {
119 Py_BEGIN_ALLOW_THREADS
120 error = obj->txdelta_handler(&window, obj->txdelta_baton);
122 if (!check_error(error)) {
132 PyTypeObject TxDeltaWindowHandler_Type = {
133 PyObject_HEAD_INIT(NULL) 0,
134 "ra.TxDeltaWindowHandler", /* const char *tp_name; For printing, in format "<module>.<name>" */
135 sizeof(TxDeltaWindowHandlerObject),
136 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
138 /* Methods to implement standard operations */
140 (destructor)PyObject_Del, /* destructor tp_dealloc; */
141 NULL, /* printfunc tp_print; */
142 NULL, /* getattrfunc tp_getattr; */
143 NULL, /* setattrfunc tp_setattr; */
144 NULL, /* cmpfunc tp_compare; */
145 NULL, /* reprfunc tp_repr; */
147 /* Method suites for standard classes */
149 NULL, /* PyNumberMethods *tp_as_number; */
150 NULL, /* PySequenceMethods *tp_as_sequence; */
151 NULL, /* PyMappingMethods *tp_as_mapping; */
153 /* More standard operations (here for binary compatibility) */
155 NULL, /* hashfunc tp_hash; */
156 txdelta_call, /* ternaryfunc tp_call; */
160 static PyObject *py_file_editor_apply_textdelta(PyObject *self, PyObject *args)
162 EditorObject *editor = (EditorObject *)self;
163 char *c_base_checksum = NULL;
164 svn_txdelta_window_handler_t txdelta_handler;
166 TxDeltaWindowHandlerObject *py_txdelta;
168 if (!FileEditor_Check(self)) {
173 if (!PyArg_ParseTuple(args, "|z", &c_base_checksum))
175 RUN_SVN(editor->editor->apply_textdelta(editor->baton,
176 c_base_checksum, editor->pool,
177 &txdelta_handler, &txdelta_baton));
178 py_txdelta = PyObject_New(TxDeltaWindowHandlerObject, &TxDeltaWindowHandler_Type);
179 py_txdelta->txdelta_handler = txdelta_handler;
180 py_txdelta->txdelta_baton = txdelta_baton;
181 return (PyObject *)py_txdelta;
184 static PyObject *py_file_editor_change_prop(PyObject *self, PyObject *args)
186 EditorObject *editor = (EditorObject *)self;
188 svn_string_t c_value;
191 if (!FileEditor_Check(self)) {
196 if (!PyArg_ParseTuple(args, "sz#", &name, &c_value.data, &vallen))
199 c_value.len = vallen;
201 RUN_SVN(editor->editor->change_file_prop(editor->baton, name,
202 &c_value, editor->pool));
206 static PyObject *py_file_editor_close(PyObject *self, PyObject *args)
208 EditorObject *editor = (EditorObject *)self;
209 char *c_checksum = NULL;
211 if (!FileEditor_Check(self)) {
216 if (!PyArg_ParseTuple(args, "|z", &c_checksum))
218 RUN_SVN(editor->editor->close_file(editor->baton, c_checksum,
223 static PyMethodDef py_file_editor_methods[] = {
224 { "change_prop", py_file_editor_change_prop, METH_VARARGS, NULL },
225 { "close", py_file_editor_close, METH_VARARGS, NULL },
226 { "apply_textdelta", py_file_editor_apply_textdelta, METH_VARARGS, NULL },
230 PyTypeObject FileEditor_Type = {
231 PyObject_HEAD_INIT(NULL) 0,
232 "ra.FileEditor", /* const char *tp_name; For printing, in format "<module>.<name>" */
233 sizeof(EditorObject),
234 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
236 /* Methods to implement standard operations */
238 (destructor)PyObject_Del, /* destructor tp_dealloc; */
239 NULL, /* printfunc tp_print; */
240 NULL, /* getattrfunc tp_getattr; */
241 NULL, /* setattrfunc tp_setattr; */
242 NULL, /* cmpfunc tp_compare; */
243 NULL, /* reprfunc tp_repr; */
245 /* Method suites for standard classes */
247 NULL, /* PyNumberMethods *tp_as_number; */
248 NULL, /* PySequenceMethods *tp_as_sequence; */
249 NULL, /* PyMappingMethods *tp_as_mapping; */
251 /* More standard operations (here for binary compatibility) */
253 NULL, /* hashfunc tp_hash; */
254 NULL, /* ternaryfunc tp_call; */
255 NULL, /* reprfunc tp_str; */
256 NULL, /* getattrofunc tp_getattro; */
257 NULL, /* setattrofunc tp_setattro; */
259 /* Functions to access object as input/output buffer */
260 NULL, /* PyBufferProcs *tp_as_buffer; */
262 /* Flags to define presence of optional/expanded features */
263 0, /* long tp_flags; */
265 NULL, /* const char *tp_doc; Documentation string */
267 /* Assigned meaning in release 2.0 */
268 /* call function for all accessible objects */
269 NULL, /* traverseproc tp_traverse; */
271 /* delete references to contained objects */
272 NULL, /* inquiry tp_clear; */
274 /* Assigned meaning in release 2.1 */
275 /* rich comparisons */
276 NULL, /* richcmpfunc tp_richcompare; */
278 /* weak reference enabler */
279 0, /* Py_ssize_t tp_weaklistoffset; */
281 /* Added in release 2.2 */
283 NULL, /* getiterfunc tp_iter; */
284 NULL, /* iternextfunc tp_iternext; */
286 /* Attribute descriptor and subclassing stuff */
287 py_file_editor_methods, /* struct PyMethodDef *tp_methods; */
290 static PyObject *py_dir_editor_delete_entry(PyObject *self, PyObject *args)
292 EditorObject *editor = (EditorObject *)self;
294 svn_revnum_t revision = -1;
296 if (!DirectoryEditor_Check(self)) {
301 if (!PyArg_ParseTuple(args, "s|l", &path, &revision))
304 RUN_SVN(editor->editor->delete_entry(path, revision, editor->baton,
310 static PyObject *py_dir_editor_add_directory(PyObject *self, PyObject *args)
313 char *copyfrom_path=NULL;
316 EditorObject *editor = (EditorObject *)self;
318 if (!DirectoryEditor_Check(self)) {
323 if (!PyArg_ParseTuple(args, "s|zl", &path, ©from_path, ©from_rev))
326 RUN_SVN(editor->editor->add_directory(path, editor->baton,
327 copyfrom_path, copyfrom_rev, editor->pool, &child_baton));
329 return new_editor_object(editor->editor, child_baton, editor->pool,
330 &DirectoryEditor_Type, NULL, NULL);
333 static PyObject *py_dir_editor_open_directory(PyObject *self, PyObject *args)
336 EditorObject *editor = (EditorObject *)self;
337 int base_revision=-1;
340 if (!DirectoryEditor_Check(self)) {
345 if (!PyArg_ParseTuple(args, "s|l", &path, &base_revision))
348 RUN_SVN(editor->editor->open_directory(path, editor->baton,
349 base_revision, editor->pool, &child_baton));
351 return new_editor_object(editor->editor, child_baton, editor->pool,
352 &DirectoryEditor_Type, NULL, NULL);
355 static PyObject *py_dir_editor_change_prop(PyObject *self, PyObject *args)
358 svn_string_t c_value;
359 EditorObject *editor = (EditorObject *)self;
362 if (!DirectoryEditor_Check(self)) {
367 if (!PyArg_ParseTuple(args, "sz#", &name, &c_value.data, &vallen))
370 c_value.len = vallen;
372 RUN_SVN(editor->editor->change_dir_prop(editor->baton, name,
373 &c_value, editor->pool));
378 static PyObject *py_dir_editor_close(PyObject *self)
380 EditorObject *editor = (EditorObject *)self;
382 if (!DirectoryEditor_Check(self)) {
387 RUN_SVN(editor->editor->close_directory(editor->baton, editor->pool));
392 static PyObject *py_dir_editor_absent_directory(PyObject *self, PyObject *args)
395 EditorObject *editor = (EditorObject *)self;
397 if (!Editor_Check(self)) {
403 if (!PyArg_ParseTuple(args, "s", &path))
406 RUN_SVN(editor->editor->absent_directory(path, editor->baton, editor->pool));
411 static PyObject *py_dir_editor_add_file(PyObject *self, PyObject *args)
413 char *path, *copy_path=NULL;
414 svn_revnum_t copy_rev=-1;
415 void *file_baton = NULL;
416 EditorObject *editor = (EditorObject *)self;
418 if (!DirectoryEditor_Check(self)) {
423 if (!PyArg_ParseTuple(args, "s|zl", &path, ©_path, ©_rev))
426 RUN_SVN(editor->editor->add_file(path, editor->baton, copy_path,
427 copy_rev, editor->pool, &file_baton));
429 return new_editor_object(editor->editor, file_baton, editor->pool,
430 &FileEditor_Type, NULL, NULL);
433 static PyObject *py_dir_editor_open_file(PyObject *self, PyObject *args)
436 int base_revision=-1;
438 EditorObject *editor = (EditorObject *)self;
440 if (!DirectoryEditor_Check(self)) {
445 if (!PyArg_ParseTuple(args, "s|l", &path, &base_revision))
448 RUN_SVN(editor->editor->open_file(path, editor->baton,
449 base_revision, editor->pool, &file_baton));
451 return new_editor_object(editor->editor, file_baton, editor->pool,
452 &FileEditor_Type, NULL, NULL);
455 static PyObject *py_dir_editor_absent_file(PyObject *self, PyObject *args)
458 EditorObject *editor = (EditorObject *)self;
460 if (!DirectoryEditor_Check(self)) {
465 if (!PyArg_ParseTuple(args, "s", &path))
468 RUN_SVN(editor->editor->absent_file(path, editor->baton, editor->pool));
473 static PyMethodDef py_dir_editor_methods[] = {
474 { "absent_file", py_dir_editor_absent_file, METH_VARARGS, NULL },
475 { "absent_directory", py_dir_editor_absent_directory, METH_VARARGS, NULL },
476 { "delete_entry", py_dir_editor_delete_entry, METH_VARARGS, NULL },
477 { "add_file", py_dir_editor_add_file, METH_VARARGS, NULL },
478 { "open_file", py_dir_editor_open_file, METH_VARARGS, NULL },
479 { "add_directory", py_dir_editor_add_directory, METH_VARARGS, NULL },
480 { "open_directory", py_dir_editor_open_directory, METH_VARARGS, NULL },
481 { "close", (PyCFunction)py_dir_editor_close, METH_NOARGS, NULL },
482 { "change_prop", py_dir_editor_change_prop, METH_VARARGS, NULL },
487 PyTypeObject DirectoryEditor_Type = {
488 PyObject_HEAD_INIT(NULL) 0,
489 "ra.DirEditor", /* const char *tp_name; For printing, in format "<module>.<name>" */
490 sizeof(EditorObject),
491 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
493 /* Methods to implement standard operations */
495 (destructor)PyObject_Del, /* destructor tp_dealloc; */
496 NULL, /* printfunc tp_print; */
497 NULL, /* getattrfunc tp_getattr; */
498 NULL, /* setattrfunc tp_setattr; */
499 NULL, /* cmpfunc tp_compare; */
500 NULL, /* reprfunc tp_repr; */
502 /* Method suites for standard classes */
504 NULL, /* PyNumberMethods *tp_as_number; */
505 NULL, /* PySequenceMethods *tp_as_sequence; */
506 NULL, /* PyMappingMethods *tp_as_mapping; */
508 /* More standard operations (here for binary compatibility) */
510 NULL, /* hashfunc tp_hash; */
511 NULL, /* ternaryfunc tp_call; */
512 NULL, /* reprfunc tp_str; */
513 NULL, /* getattrofunc tp_getattro; */
514 NULL, /* setattrofunc tp_setattro; */
516 /* Functions to access object as input/output buffer */
517 NULL, /* PyBufferProcs *tp_as_buffer; */
519 /* Flags to define presence of optional/expanded features */
520 0, /* long tp_flags; */
522 NULL, /* const char *tp_doc; Documentation string */
524 /* Assigned meaning in release 2.0 */
525 /* call function for all accessible objects */
526 NULL, /* traverseproc tp_traverse; */
528 /* delete references to contained objects */
529 NULL, /* inquiry tp_clear; */
531 /* Assigned meaning in release 2.1 */
532 /* rich comparisons */
533 NULL, /* richcmpfunc tp_richcompare; */
535 /* weak reference enabler */
536 0, /* Py_ssize_t tp_weaklistoffset; */
538 /* Added in release 2.2 */
540 NULL, /* getiterfunc tp_iter; */
541 NULL, /* iternextfunc tp_iternext; */
543 /* Attribute descriptor and subclassing stuff */
544 py_dir_editor_methods, /* struct PyMethodDef *tp_methods; */
548 static PyObject *py_editor_set_target_revision(PyObject *self, PyObject *args)
551 EditorObject *editor = (EditorObject *)self;
553 if (!Editor_Check(self)) {
558 if (!PyArg_ParseTuple(args, "i", &target_revision))
561 RUN_SVN(editor->editor->set_target_revision(editor->baton,
562 target_revision, editor->pool));
567 static PyObject *py_editor_open_root(PyObject *self, PyObject *args)
569 svn_revnum_t base_revision=-1;
571 EditorObject *editor = (EditorObject *)self;
573 if (!Editor_Check(self)) {
578 if (!PyArg_ParseTuple(args, "|l:open_root", &base_revision))
581 RUN_SVN(editor->editor->open_root(editor->baton, base_revision,
582 editor->pool, &root_baton));
584 return new_editor_object(editor->editor, root_baton, editor->pool,
585 &DirectoryEditor_Type, NULL, NULL);
588 static PyObject *py_editor_close(PyObject *self)
590 EditorObject *editor = (EditorObject *)self;
592 if (!Editor_Check(self)) {
597 RUN_SVN(editor->editor->close_edit(editor->baton, editor->pool));
599 if (editor->done_cb != NULL)
600 editor->done_cb(editor->done_baton);
605 static PyObject *py_editor_abort(PyObject *self)
607 EditorObject *editor = (EditorObject *)self;
609 if (!Editor_Check(self)) {
614 RUN_SVN(editor->editor->abort_edit(editor->baton, editor->pool));
616 if (editor->done_cb != NULL)
617 editor->done_cb(editor->done_baton);
622 static PyMethodDef py_editor_methods[] = {
623 { "abort", (PyCFunction)py_editor_abort, METH_NOARGS, NULL },
624 { "close", (PyCFunction)py_editor_close, METH_NOARGS, NULL },
625 { "open_root", py_editor_open_root, METH_VARARGS, NULL },
626 { "set_target_revision", py_editor_set_target_revision, METH_VARARGS, NULL },
630 PyTypeObject Editor_Type = {
631 PyObject_HEAD_INIT(NULL) 0,
632 "ra.Editor", /* const char *tp_name; For printing, in format "<module>.<name>" */
633 sizeof(EditorObject),
634 0,/* Py_ssize_t tp_basicsize, tp_itemsize; For allocation */
636 /* Methods to implement standard operations */
638 py_editor_dealloc, /* destructor tp_dealloc; */
639 NULL, /* printfunc tp_print; */
640 NULL, /* getattrfunc tp_getattr; */
641 NULL, /* setattrfunc tp_setattr; */
642 NULL, /* cmpfunc tp_compare; */
643 NULL, /* reprfunc tp_repr; */
645 /* Method suites for standard classes */
647 NULL, /* PyNumberMethods *tp_as_number; */
648 NULL, /* PySequenceMethods *tp_as_sequence; */
649 NULL, /* PyMappingMethods *tp_as_mapping; */
651 /* More standard operations (here for binary compatibility) */
653 NULL, /* hashfunc tp_hash; */
654 NULL, /* ternaryfunc tp_call; */
655 NULL, /* reprfunc tp_str; */
656 NULL, /* getattrofunc tp_getattro; */
657 NULL, /* setattrofunc tp_setattro; */
659 /* Functions to access object as input/output buffer */
660 NULL, /* PyBufferProcs *tp_as_buffer; */
662 /* Flags to define presence of optional/expanded features */
663 0, /* long tp_flags; */
665 NULL, /* const char *tp_doc; Documentation string */
667 /* Assigned meaning in release 2.0 */
668 /* call function for all accessible objects */
669 NULL, /* traverseproc tp_traverse; */
671 /* delete references to contained objects */
672 NULL, /* inquiry tp_clear; */
674 /* Assigned meaning in release 2.1 */
675 /* rich comparisons */
676 NULL, /* richcmpfunc tp_richcompare; */
678 /* weak reference enabler */
679 0, /* Py_ssize_t tp_weaklistoffset; */
681 /* Added in release 2.2 */
683 NULL, /* getiterfunc tp_iter; */
684 NULL, /* iternextfunc tp_iternext; */
686 /* Attribute descriptor and subclassing stuff */
687 py_editor_methods, /* struct PyMethodDef *tp_methods; */