ec681a11b6072b1d873b72ccec0bcb1effb2b236
[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 PyAPI_DATA(PyTypeObject) Repository_Type;
28 PyAPI_DATA(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 }
78
79 static PyObject *repos_init(PyTypeObject *type, PyObject *args, PyObject *kwargs)
80 {
81         char *path;
82         char *kwnames[] = { "path", NULL };
83         RepositoryObject *ret;
84
85         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwnames, &path))
86                 return NULL;
87
88         ret = PyObject_New(RepositoryObject, &Repository_Type);
89         if (ret == NULL)
90                 return NULL;
91
92         ret->pool = Pool(NULL);
93         if (ret->pool == NULL)
94                 return NULL;
95         Py_BEGIN_ALLOW_THREADS
96     if (!check_error(svn_repos_open(&ret->repos, path, ret->pool))) {
97                 apr_pool_destroy(ret->pool);
98                 PyEval_RestoreThread(_save);
99                 PyObject_Del(ret);
100                 return NULL;
101         }
102         Py_END_ALLOW_THREADS
103
104         return (PyObject *)ret;
105 }
106
107 typedef struct {
108         PyObject_HEAD
109         RepositoryObject *repos;
110         apr_pool_t *pool;
111         svn_fs_t *fs;
112 } FileSystemObject;
113
114 static PyObject *repos_fs(PyObject *self)
115 {
116         RepositoryObject *reposobj = (RepositoryObject *)self;
117         FileSystemObject *ret;
118         svn_fs_t *fs;
119
120         fs = svn_repos_fs(reposobj->repos);
121
122         if (fs == NULL) {
123                 PyErr_SetString(PyExc_RuntimeError, "Unable to obtain fs handle");
124                 return NULL;
125         }
126
127         ret = PyObject_New(FileSystemObject, &FileSystem_Type);
128         if (ret == NULL)
129                 return NULL;
130
131         ret->fs = fs;
132         ret->repos = reposobj;
133         ret->pool = reposobj->pool;
134         Py_INCREF(reposobj);
135
136         return (PyObject *)ret;
137 }
138
139 static PyObject *fs_get_uuid(PyObject *self)
140 {
141         FileSystemObject *fsobj = (FileSystemObject *)self;
142         const char *uuid;
143         PyObject *ret;
144         apr_pool_t *temp_pool;
145
146         temp_pool = Pool(NULL);
147         if (temp_pool == NULL)
148                 return NULL;
149         RUN_SVN_WITH_POOL(temp_pool, svn_fs_get_uuid(fsobj->fs, &uuid, temp_pool));
150         ret = PyString_FromString(uuid);
151         apr_pool_destroy(temp_pool);
152
153         return ret;
154 }
155
156 static PyMethodDef fs_methods[] = {
157         { "get_uuid", (PyCFunction)fs_get_uuid, METH_NOARGS, NULL },
158         { NULL, }
159 };
160
161 static void fs_dealloc(PyObject *self)
162 {
163         FileSystemObject *fsobj = (FileSystemObject *)self;
164
165         Py_DECREF(fsobj->repos);
166         apr_pool_destroy(fsobj->pool);
167 }
168
169 PyTypeObject FileSystem_Type = {
170         PyObject_HEAD_INIT(NULL) 0,
171         "repos.FileSystem", /*  const char *tp_name;  For printing, in format "<module>.<name>" */
172         sizeof(FileSystemObject), 
173         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
174         
175         /* Methods to implement standard operations */
176         
177         fs_dealloc, /*  destructor tp_dealloc;  */
178         NULL, /*        printfunc tp_print;     */
179         NULL, /*        getattrfunc tp_getattr; */
180         NULL, /*        setattrfunc tp_setattr; */
181         NULL, /*        cmpfunc tp_compare;     */
182         NULL, /*        reprfunc tp_repr;       */
183         
184         /* Method suites for standard classes */
185         
186         NULL, /*        PyNumberMethods *tp_as_number;  */
187         NULL, /*        PySequenceMethods *tp_as_sequence;      */
188         NULL, /*        PyMappingMethods *tp_as_mapping;        */
189         
190         /* More standard operations (here for binary compatibility) */
191         
192         NULL, /*        hashfunc tp_hash;       */
193         NULL, /*        ternaryfunc tp_call;    */
194         NULL, /*        reprfunc tp_str;        */
195         NULL, /*        getattrofunc tp_getattro;       */
196         NULL, /*        setattrofunc tp_setattro;       */
197         
198         /* Functions to access object as input/output buffer */
199         NULL, /*        PyBufferProcs *tp_as_buffer;    */
200         
201         /* Flags to define presence of optional/expanded features */
202         0, /*   long tp_flags;  */
203         
204         NULL, /*        const char *tp_doc;  Documentation string */
205         
206         /* Assigned meaning in release 2.0 */
207         /* call function for all accessible objects */
208         NULL, /*        traverseproc tp_traverse;       */
209         
210         /* delete references to contained objects */
211         NULL, /*        inquiry tp_clear;       */
212         
213         /* Assigned meaning in release 2.1 */
214         /* rich comparisons */
215         NULL, /*        richcmpfunc tp_richcompare;     */
216         
217         /* weak reference enabler */
218         0, /*   Py_ssize_t tp_weaklistoffset;   */
219         
220         /* Added in release 2.2 */
221         /* Iterators */
222         NULL, /*        getiterfunc tp_iter;    */
223         NULL, /*        iternextfunc tp_iternext;       */
224         
225         /* Attribute descriptor and subclassing stuff */
226         fs_methods, /*  struct PyMethodDef *tp_methods; */
227
228 };
229
230 static PyObject *repos_load_fs(PyObject *self, PyObject *args, PyObject *kwargs)
231 {
232         const char *parent_dir = "";
233         PyObject *dumpstream, *feedback_stream, *cancel_func = Py_None;
234         bool use_pre_commit_hook = false, use_post_commit_hook = false;
235         char *kwnames[] = { "dumpstream", "feedback_stream", "uuid_action",
236                                 "parent_dir", "use_pre_commit_hook", 
237                                                 "use_post_commit_hook", "cancel_func", NULL };
238         int uuid_action;
239         apr_pool_t *temp_pool;
240         RepositoryObject *reposobj = (RepositoryObject *)self;
241
242     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOi|sbbO", kwnames,
243                                                                 &dumpstream, &feedback_stream, &uuid_action,
244                                                                 &parent_dir, &use_pre_commit_hook, 
245                                                                 &use_post_commit_hook,
246                                                                 &cancel_func))
247                 return NULL;
248
249         temp_pool = Pool(NULL);
250         if (temp_pool == NULL)
251                 return NULL;
252         RUN_SVN_WITH_POOL(temp_pool, svn_repos_load_fs2(reposobj->repos, 
253                                 new_py_stream(temp_pool, dumpstream), 
254                                 new_py_stream(temp_pool, feedback_stream),
255                                 uuid_action, parent_dir, use_pre_commit_hook, 
256                                 use_post_commit_hook, py_cancel_func, (void *)cancel_func,
257                                 reposobj->pool));
258         apr_pool_destroy(temp_pool);
259         Py_RETURN_NONE;
260 }
261
262 static PyMethodDef repos_module_methods[] = {
263         { "create", repos_create, METH_VARARGS, NULL },
264         { NULL, }
265 };
266
267 static PyMethodDef repos_methods[] = {
268         { "load_fs", (PyCFunction)repos_load_fs, METH_VARARGS|METH_KEYWORDS, NULL },
269         { "fs", (PyCFunction)repos_fs, METH_NOARGS, NULL },
270         { NULL, }
271 };
272
273 PyTypeObject Repository_Type = {
274         PyObject_HEAD_INIT(NULL) 0,
275         "repos.Repository", /*  const char *tp_name;  For printing, in format "<module>.<name>" */
276         sizeof(RepositoryObject), 
277         0,/*    Py_ssize_t tp_basicsize, tp_itemsize;  For allocation */
278         
279         /* Methods to implement standard operations */
280         
281         repos_dealloc, /*       destructor tp_dealloc;  */
282         NULL, /*        printfunc tp_print;     */
283         NULL, /*        getattrfunc tp_getattr; */
284         NULL, /*        setattrfunc tp_setattr; */
285         NULL, /*        cmpfunc tp_compare;     */
286         NULL, /*        reprfunc tp_repr;       */
287         
288         /* Method suites for standard classes */
289         
290         NULL, /*        PyNumberMethods *tp_as_number;  */
291         NULL, /*        PySequenceMethods *tp_as_sequence;      */
292         NULL, /*        PyMappingMethods *tp_as_mapping;        */
293         
294         /* More standard operations (here for binary compatibility) */
295         
296         NULL, /*        hashfunc tp_hash;       */
297         NULL, /*        ternaryfunc tp_call;    */
298         NULL, /*        reprfunc tp_str;        */
299         NULL, /*        getattrofunc tp_getattro;       */
300         NULL, /*        setattrofunc tp_setattro;       */
301         
302         /* Functions to access object as input/output buffer */
303         NULL, /*        PyBufferProcs *tp_as_buffer;    */
304         
305         /* Flags to define presence of optional/expanded features */
306         0, /*   long tp_flags;  */
307         
308         NULL, /*        const char *tp_doc;  Documentation string */
309         
310         /* Assigned meaning in release 2.0 */
311         /* call function for all accessible objects */
312         NULL, /*        traverseproc tp_traverse;       */
313         
314         /* delete references to contained objects */
315         NULL, /*        inquiry tp_clear;       */
316         
317         /* Assigned meaning in release 2.1 */
318         /* rich comparisons */
319         NULL, /*        richcmpfunc tp_richcompare;     */
320         
321         /* weak reference enabler */
322         0, /*   Py_ssize_t tp_weaklistoffset;   */
323         
324         /* Added in release 2.2 */
325         /* Iterators */
326         NULL, /*        getiterfunc tp_iter;    */
327         NULL, /*        iternextfunc tp_iternext;       */
328         
329         /* Attribute descriptor and subclassing stuff */
330         repos_methods, /*       struct PyMethodDef *tp_methods; */
331         NULL, /*        struct PyMemberDef *tp_members; */
332         NULL, /*        struct PyGetSetDef *tp_getset;  */
333         NULL, /*        struct _typeobject *tp_base;    */
334         NULL, /*        PyObject *tp_dict;      */
335         NULL, /*        descrgetfunc tp_descr_get;      */
336         NULL, /*        descrsetfunc tp_descr_set;      */
337         0, /*   Py_ssize_t tp_dictoffset;       */
338         NULL, /*        initproc tp_init;       */
339         NULL, /*        allocfunc tp_alloc;     */
340         repos_init, /*  newfunc tp_new; */
341
342 };
343
344 void initrepos(void)
345 {
346         static apr_pool_t *pool;
347         PyObject *mod;
348
349         if (PyType_Ready(&Repository_Type) < 0)
350                 return;
351
352         if (PyType_Ready(&FileSystem_Type) < 0)
353                 return;
354
355         apr_initialize();
356         pool = Pool(NULL);
357         if (pool == NULL)
358                 return;
359
360         svn_fs_initialize(pool);
361
362         mod = Py_InitModule3("repos", repos_module_methods, "Local repository management");
363         if (mod == NULL)
364                 return;
365
366         PyModule_AddObject(mod, "LOAD_UUID_DEFAULT", PyLong_FromLong(0));
367         PyModule_AddObject(mod, "LOAD_UUID_IGNORE", PyLong_FromLong(1));
368         PyModule_AddObject(mod, "LOAD_UUID_FORCE", PyLong_FromLong(2));
369
370         PyModule_AddObject(mod, "Repository", (PyObject *)&Repository_Type);
371         Py_INCREF(&Repository_Type);
372 }