GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/db.c Lines: 151 160 94.4 %
Date: 2020-02-19 21:21:49 Branches: 44 66 66.7 %

Line Branch Exec Source
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: */