f2992136885765eaa7398226d297c3200d00ca85
[jelmer/subvertpy.git] / repos.c
1 /*
2  * Copyright © 2008 Jelmer Vernooij <jelmer@samba.org>
3  * -*- coding: utf-8 -*-
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #include <stdbool.h>
20 #include <Python.h>
21 #include <apr_general.h>
22 #include <svn_fs.h>
23 #include <svn_repos.h>
24
25 #include "util.h"
26
27 extern PyTypeObject Repository_Type;
28 extern PyTypeObject FileSystem_Type;
29
30 typedef struct { 
31         PyObject_HEAD
32     apr_pool_t *pool;
33     svn_repos_t *repos;
34 } RepositoryObject;
35
36 static PyObject *repos_create(PyObject *self, PyObject *args)
37 {
38         char *path;
39         PyObject *config=Py_None, *fs_config=Py_None;
40     svn_repos_t *repos;
41     apr_pool_t *pool;
42     apr_hash_t *hash_config, *hash_fs_config;
43         RepositoryObject *ret;
44
45         if (!PyArg_ParseTuple(args, "s|OO", &path, &config, &fs_config))
46                 return NULL;
47
48     pool = Pool(NULL);
49         if (pool == NULL)
50                 return NULL;
51     hash_config = config_hash_from_object(config, pool);
52         if (hash_config == NULL)
53                 return NULL;
54     hash_fs_config = apr_hash_make(pool); /* FIXME */
55         if (hash_fs_config == NULL) {
56                 PyErr_SetString(PyExc_RuntimeError, "Unable to create fs config hash");
57                 return NULL;
58         }
59     RUN_SVN_WITH_POOL(pool, svn_repos_create(&repos, path, NULL, NULL, 
60                 hash_config, hash_fs_config, pool));
61
62         ret = PyObject_New(RepositoryObject, &Repository_Type);
63         if (ret == NULL)
64                 return NULL;
65
66         ret->pool = pool;
67         ret->repos = repos;
68
69     return (PyObject *)ret;
70 }
71
72 static void repos_dealloc(PyObject *self)
73 {
74         RepositoryObject *repos = (RepositoryObject *)self;
75
76         apr_pool_destroy(repos->pool);
77         PyObject_Del(repos);
78 }
79
80 static PyObject *repos_init(PyTypeObject *type, PyObject *args, PyObject *kwargs)
81 {
82         char *path;
83         char *kwnames[] = { "path", NULL };
84         svn_error_t *err;
85         RepositoryObject *ret;
86
87         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwnames, &path))
88                 return NULL;
89
90         ret = PyObject_New(RepositoryObject, &Repository_Type);
91         if (ret == NULL)
92                 return NULL;
93
94         ret->pool = Pool(NULL);
95         if (ret->pool == NULL)
96                 return NULL;
97         Py_BEGIN_ALLOW_THREADS
98         err = svn_repos_open(&ret->repos, path, ret->pool);
99         Py_END_ALLOW_THREADS
100     if (!check_error(err)) {
101                 Py_DECREF(ret);
102                 return NULL;
103         }
104
105         return (PyObject *)ret;
106 }
107
108 typedef struct {
109         PyObject_HEAD
110         RepositoryObject *repos;
111         apr_pool_t *pool;
112         svn_fs_t *fs;
113 } FileSystemObject;
114
115 static PyObject *repos_fs(PyObject *self)
116 {
117         RepositoryObject *reposobj = (RepositoryObject *)self;
118         FileSystemObject *ret;
119         svn_fs_t *fs;
120
121         fs = svn_repos_fs(reposobj->repos);
122
123         if (fs == NULL) {
124                 PyErr_SetString(PyExc_RuntimeError, "Unable to obtain fs handle");
125                 return NULL;
126         }
127
128         ret = PyObject_New(FileSystemObject, &FileSystem_Type);
129         if (ret == NULL)
130                 return NULL;
131
132         ret->fs = fs;
133         ret->repos = reposobj;
134         ret->pool = reposobj->pool;
135         Py_INCREF(reposobj);
136
137         return (PyObject *)ret;
138 }
139
140 static PyObject *fs_get_uuid(PyObject *self)
141 {
142         FileSystemObject *fsobj = (FileSystemObject *)self;
143         const char *uuid;
144         PyObject *ret;
145         apr_pool_t *temp_pool;
146
147         temp_pool = Pool(NULL);
148         if (temp_pool == NULL)
149                 return NULL;
150         RUN_SVN_WITH_POOL(temp_pool, svn_fs_get_uuid(fsobj->fs, &uuid, temp_pool));
151         ret = PyString_FromString(uuid);
152         apr_pool_destroy(temp_pool);
153
154         return ret;
155 }
156
157 static PyMethodDef fs_methods[] = {
158         { "get_uuid", (PyCFunction)fs_get_uuid, METH_NOARGS, NULL },
159         { NULL, }
160 };
161
162 static void fs_dealloc(PyObject *self)
163 {
164         FileSystemObject *fsobj = (FileSystemObject *)self;
165
166         Py_DECREF(fsobj->repos);
167         apr_pool_destroy(fsobj->pool);
168 }
169
170 PyTypeObject FileSystem_Type = {
171         PyObject_HEAD_INIT(NULL) 0,
172         "repos.FileSystem", /*  const char *tp_name;  For printing, in format "<module>.<name>" */
173         sizeof(FileSystemObject), 
174         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
175         
176         /* Methods to implement standard operations */
177         
178         fs_dealloc, /*  destructor tp_dealloc;  */
179         NULL, /*        printfunc tp_print;     */
180         NULL, /*        getattrfunc tp_getattr; */
181         NULL, /*        setattrfunc tp_setattr; */
182         NULL, /*        cmpfunc tp_compare;     */
183         NULL, /*        reprfunc tp_repr;       */
184         
185         /* Method suites for standard classes */
186         
187         NULL, /*        PyNumberMethods *tp_as_number;  */
188         NULL, /*        PySequenceMethods *tp_as_sequence;      */
189         NULL, /*        PyMappingMethods *tp_as_mapping;        */
190         
191         /* More standard operations (here for binary compatibility) */
192         
193         NULL, /*        hashfunc tp_hash;       */
194         NULL, /*        ternaryfunc tp_call;    */
195         NULL, /*        reprfunc tp_str;        */
196         NULL, /*        getattrofunc tp_getattro;       */
197         NULL, /*        setattrofunc tp_setattro;       */
198         
199         /* Functions to access object as input/output buffer */
200         NULL, /*        PyBufferProcs *tp_as_buffer;    */
201         
202         /* Flags to define presence of optional/expanded features */
203         0, /*   long tp_flags;  */
204         
205         NULL, /*        const char *tp_doc;  Documentation string */
206         
207         /* Assigned meaning in release 2.0 */
208         /* call function for all accessible objects */
209         NULL, /*        traverseproc tp_traverse;       */
210         
211         /* delete references to contained objects */
212         NULL, /*        inquiry tp_clear;       */
213         
214         /* Assigned meaning in release 2.1 */
215         /* rich comparisons */
216         NULL, /*        richcmpfunc tp_richcompare;     */
217         
218         /* weak reference enabler */
219         0, /*   Py_ssize_t tp_weaklistoffset;   */
220         
221         /* Added in release 2.2 */
222         /* Iterators */
223         NULL, /*        getiterfunc tp_iter;    */
224         NULL, /*        iternextfunc tp_iternext;       */
225         
226         /* Attribute descriptor and subclassing stuff */
227         fs_methods, /*  struct PyMethodDef *tp_methods; */
228
229 };
230
231 static PyObject *repos_load_fs(PyObject *self, PyObject *args, PyObject *kwargs)
232 {
233         const char *parent_dir = "";
234         PyObject *dumpstream, *feedback_stream, *cancel_func = Py_None;
235         bool use_pre_commit_hook = false, use_post_commit_hook = false;
236         char *kwnames[] = { "dumpstream", "feedback_stream", "uuid_action",
237                                 "parent_dir", "use_pre_commit_hook", 
238                                                 "use_post_commit_hook", "cancel_func", NULL };
239         int uuid_action;
240         apr_pool_t *temp_pool;
241         RepositoryObject *reposobj = (RepositoryObject *)self;
242
243     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOi|sbbO", kwnames,
244                                                                 &dumpstream, &feedback_stream, &uuid_action,
245                                                                 &parent_dir, &use_pre_commit_hook, 
246                                                                 &use_post_commit_hook,
247                                                                 &cancel_func))
248                 return NULL;
249
250         temp_pool = Pool(NULL);
251         if (temp_pool == NULL)
252                 return NULL;
253         RUN_SVN_WITH_POOL(temp_pool, svn_repos_load_fs2(reposobj->repos, 
254                                 new_py_stream(temp_pool, dumpstream), 
255                                 new_py_stream(temp_pool, feedback_stream),
256                                 uuid_action, parent_dir, use_pre_commit_hook, 
257                                 use_post_commit_hook, py_cancel_func, (void *)cancel_func,
258                                 reposobj->pool));
259         apr_pool_destroy(temp_pool);
260         Py_RETURN_NONE;
261 }
262
263 static PyMethodDef repos_module_methods[] = {
264         { "create", repos_create, METH_VARARGS, NULL },
265         { NULL, }
266 };
267
268 static PyMethodDef repos_methods[] = {
269         { "load_fs", (PyCFunction)repos_load_fs, METH_VARARGS|METH_KEYWORDS, NULL },
270         { "fs", (PyCFunction)repos_fs, METH_NOARGS, NULL },
271         { NULL, }
272 };
273
274 PyTypeObject Repository_Type = {
275         PyObject_HEAD_INIT(NULL) 0,
276         "repos.Repository", /*  const char *tp_name;  For printing, in format "<module>.<name>" */
277         sizeof(RepositoryObject), 
278         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
279         
280         /* Methods to implement standard operations */
281         
282         repos_dealloc, /*       destructor tp_dealloc;  */
283         NULL, /*        printfunc tp_print;     */
284         NULL, /*        getattrfunc tp_getattr; */
285         NULL, /*        setattrfunc tp_setattr; */
286         NULL, /*        cmpfunc tp_compare;     */
287         NULL, /*        reprfunc tp_repr;       */
288         
289         /* Method suites for standard classes */
290         
291         NULL, /*        PyNumberMethods *tp_as_number;  */
292         NULL, /*        PySequenceMethods *tp_as_sequence;      */
293         NULL, /*        PyMappingMethods *tp_as_mapping;        */
294         
295         /* More standard operations (here for binary compatibility) */
296         
297         NULL, /*        hashfunc tp_hash;       */
298         NULL, /*        ternaryfunc tp_call;    */
299         NULL, /*        reprfunc tp_str;        */
300         NULL, /*        getattrofunc tp_getattro;       */
301         NULL, /*        setattrofunc tp_setattro;       */
302         
303         /* Functions to access object as input/output buffer */
304         NULL, /*        PyBufferProcs *tp_as_buffer;    */
305         
306         /* Flags to define presence of optional/expanded features */
307         0, /*   long tp_flags;  */
308         
309         NULL, /*        const char *tp_doc;  Documentation string */
310         
311         /* Assigned meaning in release 2.0 */
312         /* call function for all accessible objects */
313         NULL, /*        traverseproc tp_traverse;       */
314         
315         /* delete references to contained objects */
316         NULL, /*        inquiry tp_clear;       */
317         
318         /* Assigned meaning in release 2.1 */
319         /* rich comparisons */
320         NULL, /*        richcmpfunc tp_richcompare;     */
321         
322         /* weak reference enabler */
323         0, /*   Py_ssize_t tp_weaklistoffset;   */
324         
325         /* Added in release 2.2 */
326         /* Iterators */
327         NULL, /*        getiterfunc tp_iter;    */
328         NULL, /*        iternextfunc tp_iternext;       */
329         
330         /* Attribute descriptor and subclassing stuff */
331         repos_methods, /*       struct PyMethodDef *tp_methods; */
332         NULL, /*        struct PyMemberDef *tp_members; */
333         NULL, /*        struct PyGetSetDef *tp_getset;  */
334         NULL, /*        struct _typeobject *tp_base;    */
335         NULL, /*        PyObject *tp_dict;      */
336         NULL, /*        descrgetfunc tp_descr_get;      */
337         NULL, /*        descrsetfunc tp_descr_set;      */
338         0, /*   Py_ssize_t tp_dictoffset;       */
339         NULL, /*        initproc tp_init;       */
340         NULL, /*        allocfunc tp_alloc;     */
341         repos_init, /*  newfunc tp_new; */
342
343 };
344
345 void initrepos(void)
346 {
347         static apr_pool_t *pool;
348         PyObject *mod;
349
350         if (PyType_Ready(&Repository_Type) < 0)
351                 return;
352
353         if (PyType_Ready(&FileSystem_Type) < 0)
354                 return;
355
356         apr_initialize();
357         pool = Pool(NULL);
358         if (pool == NULL)
359                 return;
360
361         svn_fs_initialize(pool);
362
363         mod = Py_InitModule3("repos", repos_module_methods, "Local repository management");
364         if (mod == NULL)
365                 return;
366
367         PyModule_AddObject(mod, "LOAD_UUID_DEFAULT", PyLong_FromLong(0));
368         PyModule_AddObject(mod, "LOAD_UUID_IGNORE", PyLong_FromLong(1));
369         PyModule_AddObject(mod, "LOAD_UUID_FORCE", PyLong_FromLong(2));
370
371         PyModule_AddObject(mod, "Repository", (PyObject *)&Repository_Type);
372         Py_INCREF(&Repository_Type);
373 }