1 |
|
|
/** |
2 |
|
|
* db.c : wrapper class around alpm_db_t |
3 |
|
|
* |
4 |
|
|
* Copyright (c) 2011 Rémy Oudompheng <remy@archlinux.org> |
5 |
|
|
* |
6 |
|
|
* This file is part of pyalpm. |
7 |
|
|
* |
8 |
|
|
* pyalpm is free software: you can redistribute it and/or modify |
9 |
|
|
* it under the terms of the GNU General Public License as published by |
10 |
|
|
* the Free Software Foundation, either version 3 of the License, or |
11 |
|
|
* (at your option) any later version. |
12 |
|
|
* |
13 |
|
|
* pyalpm is distributed in the hope that it will be useful, |
14 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 |
|
|
* GNU General Public License for more details. |
17 |
|
|
* |
18 |
|
|
* You should have received a copy of the GNU General Public License |
19 |
|
|
* along with pyalpm. If not, see <http://www.gnu.org/licenses/>. |
20 |
|
|
* |
21 |
|
|
*/ |
22 |
|
|
|
23 |
|
|
#include <pyconfig.h> |
24 |
|
|
#include <alpm.h> |
25 |
|
|
#include <Python.h> |
26 |
|
|
#include "db.h" |
27 |
|
|
#include "package.h" |
28 |
|
|
#include "util.h" |
29 |
|
|
|
30 |
|
|
typedef struct _AlpmDB { |
31 |
|
|
PyObject_HEAD |
32 |
|
|
alpm_db_t *c_data; |
33 |
|
|
} AlpmDB; |
34 |
|
|
|
35 |
|
|
#define ALPM_DB(self) (((AlpmDB*)self)->c_data) |
36 |
|
|
|
37 |
|
|
static PyTypeObject AlpmDBType; |
38 |
|
|
|
39 |
|
81 |
static void pyalpm_db_dealloc(AlpmDB *self) { |
40 |
|
81 |
Py_TYPE(self)->tp_free((PyObject*)self); |
41 |
|
81 |
} |
42 |
|
|
|
43 |
|
6 |
static PyObject* _pyobject_from_pmgrp(void *group) { |
44 |
|
6 |
const alpm_group_t* grp = (alpm_group_t*)group; |
45 |
✓✓ |
6 |
if (!grp) |
46 |
|
3 |
Py_RETURN_NONE; |
47 |
|
|
else { |
48 |
|
3 |
PyObject *fst = PyUnicode_FromString(grp->name); |
49 |
|
3 |
PyObject *snd = alpmlist_to_pylist(grp->packages, |
50 |
|
|
pyalpm_package_from_pmpkg); |
51 |
|
3 |
PyObject *tuple = PyTuple_Pack(2, fst, snd); |
52 |
✗✓ |
3 |
Py_DECREF(fst); |
53 |
✗✓ |
3 |
Py_DECREF(snd); |
54 |
|
3 |
return tuple; |
55 |
|
|
} |
56 |
|
|
} |
57 |
|
|
|
58 |
|
|
/** Converts a Python list of databases to an alpm_list_t linked list. |
59 |
|
|
* return 0 on success, -1 on failure |
60 |
|
|
*/ |
61 |
|
9 |
int pylist_db_to_alpmlist(PyObject *list, alpm_list_t **result) { |
62 |
|
9 |
alpm_list_t *ret = NULL; |
63 |
|
9 |
PyObject *iterator = PyObject_GetIter(list); |
64 |
|
9 |
PyObject *item; |
65 |
|
|
|
66 |
✗✓ |
9 |
if(iterator == NULL) { |
67 |
|
|
PyErr_SetString(PyExc_TypeError, "object is not iterable"); |
68 |
|
|
return -1; |
69 |
|
|
} |
70 |
|
|
|
71 |
✓✓ |
15 |
while((item = PyIter_Next(iterator))) |
72 |
|
|
{ |
73 |
✓✓✗✓
|
9 |
if (PyObject_TypeCheck(item, &AlpmDBType)) { |
74 |
|
6 |
ret = alpm_list_add(ret, ((AlpmDB*)item)->c_data); |
75 |
|
|
} else { |
76 |
|
3 |
PyErr_SetString(PyExc_TypeError, "list must contain only Database objects"); |
77 |
|
3 |
FREELIST(ret); |
78 |
✗✓ |
3 |
Py_DECREF(item); |
79 |
✓✗ |
3 |
Py_DECREF(iterator); |
80 |
|
3 |
return -1; |
81 |
|
|
} |
82 |
✗✓ |
21 |
Py_DECREF(item); |
83 |
|
|
} |
84 |
✓✗ |
6 |
Py_DECREF(iterator); |
85 |
|
|
|
86 |
|
6 |
*result = ret; |
87 |
|
6 |
return 0; |
88 |
|
|
} |
89 |
|
|
|
90 |
|
|
#define CHECK_IF_INITIALIZED() if (! self->c_data) { \ |
91 |
|
|
PyErr_SetString(alpm_error, "data is not initialized"); \ |
92 |
|
|
return NULL; \ |
93 |
|
|
} |
94 |
|
|
|
95 |
|
3 |
static PyObject* pyalpm_db_repr(PyObject *rawself) { |
96 |
|
3 |
AlpmDB *self = (AlpmDB *)rawself; |
97 |
|
3 |
return PyUnicode_FromFormat("<alpm.DB(\"%s\") at %p>", |
98 |
|
3 |
alpm_db_get_name(self->c_data), |
99 |
|
|
self); |
100 |
|
|
} |
101 |
|
|
|
102 |
|
3 |
static PyObject* pyalpm_db_str(PyObject *rawself) { |
103 |
|
3 |
AlpmDB *self = (AlpmDB *)rawself; |
104 |
|
3 |
return PyUnicode_FromFormat("alpm.DB(\"%s\")", |
105 |
|
3 |
alpm_db_get_name(self->c_data), |
106 |
|
|
self); |
107 |
|
|
} |
108 |
|
|
|
109 |
|
|
/** Database properties */ |
110 |
|
|
|
111 |
|
18 |
static PyObject* pyalpm_db_get_name(AlpmDB* self, void* closure) { |
112 |
|
18 |
const char* name; |
113 |
✗✓ |
18 |
CHECK_IF_INITIALIZED(); |
114 |
|
18 |
name = alpm_db_get_name(self->c_data); |
115 |
✗✓ |
18 |
if (!name) |
116 |
|
|
Py_RETURN_NONE; |
117 |
|
18 |
return PyUnicode_FromString(name); |
118 |
|
|
} |
119 |
|
|
|
120 |
|
9 |
static PyObject* pyalpm_db_get_servers(PyObject *self, void* closure) { |
121 |
|
9 |
alpm_db_t *db = ALPM_DB(self); |
122 |
|
9 |
return alpmlist_to_pylist(alpm_db_get_servers(db), pyobject_from_string); |
123 |
|
|
} |
124 |
|
|
|
125 |
|
30 |
static int pyalpm_db_set_servers(PyObject* self, PyObject* value, void* closure) { |
126 |
|
30 |
alpm_db_t *db = ALPM_DB(self); |
127 |
|
30 |
alpm_list_t *target; |
128 |
✓✓ |
30 |
if (pylist_string_to_alpmlist(value, &target) == -1) |
129 |
|
|
return -1; |
130 |
✗✓ |
27 |
if (alpm_db_set_servers(db, target) == -1) |
131 |
|
|
RET_ERR("unable to set servers", 0, -1); |
132 |
|
|
return 0; |
133 |
|
|
} |
134 |
|
|
|
135 |
|
3 |
static PyObject* pyalpm_db_get_pkgcache(AlpmDB* self, void* closure) { |
136 |
|
3 |
alpm_list_t *pkglist = alpm_db_get_pkgcache(self->c_data); |
137 |
|
3 |
return alpmlist_to_pylist(pkglist, pyalpm_package_from_pmpkg); |
138 |
|
|
} |
139 |
|
|
|
140 |
|
6 |
static PyObject* pyalpm_db_get_grpcache(AlpmDB* self, void* closure) { |
141 |
|
6 |
alpm_list_t *grplist = alpm_db_get_groupcache(self->c_data); |
142 |
|
6 |
return alpmlist_to_pylist(grplist, _pyobject_from_pmgrp); |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
/** Package get/set operations */ |
146 |
|
|
|
147 |
|
24 |
static PyObject* pyalpm_db_get_pkg(PyObject *rawself, PyObject* args) { |
148 |
|
24 |
char *pkgname; |
149 |
|
24 |
alpm_pkg_t *p; |
150 |
|
24 |
AlpmDB *self = (AlpmDB*)rawself; |
151 |
|
|
|
152 |
✓✓ |
24 |
if(!PyArg_ParseTuple(args, "s", &pkgname)) |
153 |
|
|
{ |
154 |
|
3 |
PyErr_SetString(PyExc_TypeError, "get_pkg() takes a string argument"); |
155 |
|
3 |
return NULL; |
156 |
|
|
} |
157 |
|
|
|
158 |
✗✓ |
21 |
CHECK_IF_INITIALIZED(); |
159 |
|
|
|
160 |
|
21 |
p = alpm_db_get_pkg(self->c_data, pkgname); |
161 |
|
|
|
162 |
✓✓ |
21 |
if (p == NULL) { |
163 |
|
3 |
Py_RETURN_NONE; |
164 |
|
|
} else { |
165 |
|
18 |
PyObject *result; |
166 |
|
18 |
result = pyalpm_package_from_pmpkg(p); |
167 |
✓✗ |
18 |
if (result == NULL) { |
168 |
|
|
return NULL; |
169 |
|
|
} else { |
170 |
|
18 |
return result; |
171 |
|
|
} |
172 |
|
|
} |
173 |
|
|
} |
174 |
|
|
|
175 |
|
6 |
static PyObject* pyalpm_db_get_group(PyObject* rawself, PyObject* args) { |
176 |
|
6 |
AlpmDB* self = (AlpmDB*)rawself; |
177 |
|
6 |
char *grpname; |
178 |
|
6 |
alpm_group_t *grp; |
179 |
✓✓ |
6 |
if (!PyArg_ParseTuple(args, "s", &grpname)) { |
180 |
|
3 |
PyErr_SetString(PyExc_TypeError, "expected string argument"); |
181 |
|
3 |
return NULL; |
182 |
|
|
} |
183 |
|
|
|
184 |
|
3 |
grp = alpm_db_get_group(self->c_data, grpname); |
185 |
|
3 |
return _pyobject_from_pmgrp(grp); |
186 |
|
|
} |
187 |
|
|
|
188 |
|
12 |
static PyObject *pyalpm_db_update(PyObject *rawself, PyObject *args, PyObject *kwargs) { |
189 |
|
12 |
AlpmDB* self = (AlpmDB*)rawself; |
190 |
|
12 |
char* keyword[] = {"force", NULL}; |
191 |
|
12 |
int ret; |
192 |
|
12 |
PyObject *force; |
193 |
✓✗ |
12 |
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!", keyword, &PyBool_Type, &force)) |
194 |
|
|
return NULL; |
195 |
|
|
|
196 |
|
12 |
ret = alpm_db_update((force == Py_True), self->c_data); |
197 |
|
|
|
198 |
✓✓✓✗
|
12 |
switch(ret) { |
199 |
|
3 |
case -1: |
200 |
|
3 |
RET_ERR("unable to update database", 0, NULL); |
201 |
|
|
case 0: |
202 |
|
3 |
Py_RETURN_TRUE; |
203 |
|
|
case 1: |
204 |
|
6 |
Py_RETURN_FALSE; |
205 |
|
|
default: |
206 |
|
|
RET_ERR("invalid return code from alpm_db_update()", 0, NULL); |
207 |
|
|
} |
208 |
|
|
} |
209 |
|
|
|
210 |
|
6 |
static PyObject* pyalpm_db_search(PyObject *rawself, PyObject *args) { |
211 |
|
6 |
AlpmDB* self = (AlpmDB *)rawself; |
212 |
|
6 |
alpm_list_t* rawargs; |
213 |
|
6 |
alpm_list_t* result; |
214 |
|
6 |
int ok = pylist_string_to_alpmlist(args, &rawargs); |
215 |
✓✗ |
6 |
if (ok == -1) return NULL; |
216 |
|
|
|
217 |
|
6 |
result = alpm_db_search(self->c_data, rawargs); |
218 |
|
6 |
return alpmlist_to_pylist(result, pyalpm_package_from_pmpkg); |
219 |
|
|
} |
220 |
|
|
|
221 |
|
|
static struct PyMethodDef db_methods[] = { |
222 |
|
|
{ "get_pkg", pyalpm_db_get_pkg, METH_VARARGS, |
223 |
|
|
"get a package by name\n" |
224 |
|
|
"args: a package name (string)\n" |
225 |
|
|
"returns: a Package object or None if not found" }, |
226 |
|
|
{ "search", pyalpm_db_search, METH_VARARGS, |
227 |
|
|
"search for packages matching a list of regexps\n" |
228 |
|
|
"args: a variable number of regexps (strings)\n" |
229 |
|
|
"returns: packages matching all these regexps" }, |
230 |
|
|
{ "read_grp", pyalpm_db_get_group, METH_VARARGS, |
231 |
|
|
"get contents of a group\n" |
232 |
|
|
"args: a group name (string)\n" |
233 |
|
|
"returns: a tuple (group name, list of packages)" }, |
234 |
|
|
{ "update", (PyCFunction)pyalpm_db_update, METH_VARARGS | METH_KEYWORDS, |
235 |
|
|
"update a database from its url attribute\n" |
236 |
|
|
"args: force (update even if DB is up to date, boolean)\n" |
237 |
|
|
"returns: True if an update has been done" }, |
238 |
|
|
{ NULL }, |
239 |
|
|
}; |
240 |
|
|
|
241 |
|
|
struct PyGetSetDef db_getset[] = { |
242 |
|
|
/* description properties */ |
243 |
|
|
{ "name", (getter)pyalpm_db_get_name, 0, |
244 |
|
|
"database name (e.g. \"core\", \"extra\")", NULL } , |
245 |
|
|
{ "servers", (getter)pyalpm_db_get_servers, (setter)pyalpm_db_set_servers, |
246 |
|
|
"a list of URLs (for sync DBs)", NULL } , |
247 |
|
|
{ "pkgcache", (getter)pyalpm_db_get_pkgcache, 0, "(read only) list of packages", NULL } , |
248 |
|
|
{ "grpcache", (getter)pyalpm_db_get_grpcache, 0, "(read only) list of package groups", NULL } , |
249 |
|
|
{ NULL } |
250 |
|
|
}; |
251 |
|
|
|
252 |
|
|
static PyTypeObject AlpmDBType = { |
253 |
|
|
PyVarObject_HEAD_INIT(NULL, 0) |
254 |
|
|
"alpm.DB", /*tp_name*/ |
255 |
|
|
sizeof(AlpmDB), /*tp_basicsize*/ |
256 |
|
|
0, /*tp_itemsize*/ |
257 |
|
|
.tp_dealloc = (destructor)pyalpm_db_dealloc, |
258 |
|
|
.tp_repr = pyalpm_db_repr, |
259 |
|
|
.tp_str = pyalpm_db_str, |
260 |
|
|
.tp_flags = Py_TPFLAGS_DEFAULT, |
261 |
|
|
.tp_doc = "libalpm DB object", |
262 |
|
|
.tp_methods = db_methods, |
263 |
|
|
.tp_getset = db_getset, |
264 |
|
|
}; |
265 |
|
|
|
266 |
|
|
/** Initializes Pb class in module */ |
267 |
|
3 |
void init_pyalpm_db(PyObject *module) { |
268 |
|
3 |
PyObject *type; |
269 |
|
|
|
270 |
✓✗ |
3 |
if (PyType_Ready(&AlpmDBType) < 0) |
271 |
|
|
return; |
272 |
|
3 |
type = (PyObject*)&AlpmDBType; |
273 |
|
3 |
Py_INCREF(type); |
274 |
|
3 |
PyModule_AddObject(module, "DB", type); |
275 |
|
|
|
276 |
|
|
/* signature check levels */ |
277 |
|
3 |
PyModule_AddIntConstant(module, "SIG_DATABASE", ALPM_SIG_DATABASE); |
278 |
|
3 |
PyModule_AddIntConstant(module, "SIG_DATABASE_OPTIONAL", ALPM_SIG_DATABASE_OPTIONAL); |
279 |
|
3 |
PyModule_AddIntConstant(module, "SIG_DATABASE_MARGINAL_OK", ALPM_SIG_DATABASE_MARGINAL_OK); |
280 |
|
3 |
PyModule_AddIntConstant(module, "SIG_DATABASE_UNKNOWN_OK", ALPM_SIG_DATABASE_UNKNOWN_OK); |
281 |
|
|
} |
282 |
|
|
|
283 |
|
|
|
284 |
|
81 |
PyObject *pyalpm_db_from_pmdb(void* data) { |
285 |
|
81 |
alpm_db_t *db = (alpm_db_t*)data; |
286 |
|
81 |
AlpmDB *self; |
287 |
|
81 |
self = (AlpmDB*)AlpmDBType.tp_alloc(&AlpmDBType, 0); |
288 |
✗✓ |
81 |
if (self == NULL) { |
289 |
|
|
PyErr_SetString(PyExc_RuntimeError, "unable to create DB object"); |
290 |
|
|
return NULL; |
291 |
|
|
} |
292 |
|
|
|
293 |
|
81 |
self->c_data = db; |
294 |
|
81 |
return (PyObject *)self; |
295 |
|
|
} |
296 |
|
|
|
297 |
|
|
/** non-class methods */ |
298 |
|
9 |
PyObject* pyalpm_find_grp_pkgs(PyObject* self, PyObject *args) { |
299 |
|
9 |
PyObject *dbs; |
300 |
|
9 |
char *grpname; |
301 |
|
9 |
alpm_list_t *db_list = NULL; |
302 |
|
9 |
alpm_list_t *pkg_list; |
303 |
|
9 |
PyObject *result; |
304 |
|
|
|
305 |
✓✓ |
9 |
if (!PyArg_ParseTuple(args, "Os", &dbs, &grpname)) { |
306 |
|
3 |
PyErr_SetString(PyExc_TypeError, "expected arguments (list of dbs, group name)"); |
307 |
|
3 |
return NULL; |
308 |
|
|
} |
309 |
|
|
|
310 |
|
|
{ |
311 |
|
6 |
int ret = pylist_db_to_alpmlist(dbs, &db_list); |
312 |
✓✓ |
6 |
if (ret == -1) |
313 |
|
|
return NULL; |
314 |
|
|
} |
315 |
|
3 |
pkg_list = alpm_find_group_pkgs(db_list, grpname); |
316 |
|
3 |
result = alpmlist_to_pylist(pkg_list, pyalpm_package_from_pmpkg); |
317 |
|
3 |
alpm_list_free(db_list); |
318 |
|
3 |
alpm_list_free(pkg_list); |
319 |
|
3 |
return result; |
320 |
|
|
} |
321 |
|
|
|
322 |
|
|
/** Finds an available upgrade for a package in a list of databases */ |
323 |
|
6 |
PyObject* pyalpm_sync_get_new_version(PyObject *self, PyObject* args) { |
324 |
|
6 |
PyObject *pkg; |
325 |
|
6 |
PyObject *dbs; |
326 |
|
6 |
alpm_list_t *db_list; |
327 |
|
6 |
alpm_pkg_t *result = NULL; |
328 |
✓✓ |
6 |
if(!PyArg_ParseTuple(args, "OO", &pkg, &dbs) |
329 |
✓✗ |
3 |
|| !PyAlpmPkg_Check(pkg) |
330 |
✗✓ |
3 |
|| pylist_db_to_alpmlist(dbs, &db_list) == -1) |
331 |
|
|
{ |
332 |
|
3 |
PyErr_SetString(PyExc_TypeError, "sync_newversion() takes a Package and a list of DBs"); |
333 |
|
3 |
return NULL; |
334 |
|
|
} |
335 |
|
|
|
336 |
|
|
{ |
337 |
|
3 |
alpm_pkg_t *rawpkg = pmpkg_from_pyalpm_pkg(pkg); |
338 |
✓✗ |
3 |
if (rawpkg) { |
339 |
|
3 |
result = alpm_sync_get_new_version(rawpkg, db_list); |
340 |
|
|
} |
341 |
|
3 |
alpm_list_free(db_list); |
342 |
|
|
} |
343 |
✓✗ |
3 |
if (!result) |
344 |
|
3 |
Py_RETURN_NONE; |
345 |
|
|
else |
346 |
|
|
return pyalpm_package_from_pmpkg(result); |
347 |
|
|
} |
348 |
|
|
|
349 |
|
|
/* vim: set ts=2 sw=2 et: */ |