]>
Commit | Line | Data |
---|---|---|
6e46b18e MT |
1 | /*############################################################################# |
2 | # # | |
3 | # Pakfire - The IPFire package management system # | |
4 | # Copyright (C) 2017 Pakfire development team # | |
5 | # # | |
6 | # This program is free software: you can redistribute it and/or modify # | |
7 | # it under the terms of the GNU General Public License as published by # | |
8 | # the Free Software Foundation, either version 3 of the License, or # | |
9 | # (at your option) any later version. # | |
10 | # # | |
11 | # This program is distributed in the hope that it will be useful, # | |
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of # | |
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # | |
14 | # GNU General Public License for more details. # | |
15 | # # | |
16 | # You should have received a copy of the GNU General Public License # | |
17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. # | |
18 | # # | |
19 | #############################################################################*/ | |
20 | ||
16495755 | 21 | #define PY_SSIZE_T_CLEAN |
6e46b18e | 22 | #include <Python.h> |
03b9652a | 23 | #include <errno.h> |
6e46b18e | 24 | |
36c98595 | 25 | #include <pakfire/archive.h> |
1a276007 | 26 | #include <pakfire/build.h> |
9d6b128a | 27 | #include <pakfire/constants.h> |
af41db7e | 28 | #include <pakfire/dist.h> |
9d6b128a | 29 | #include <pakfire/execute.h> |
bfa112c3 | 30 | #include <pakfire/logging.h> |
163851bc | 31 | #include <pakfire/mount.h> |
178a4506 | 32 | #include <pakfire/packagelist.h> |
6e46b18e | 33 | #include <pakfire/pakfire.h> |
ad62bb07 | 34 | #include <pakfire/key.h> |
843fcc66 | 35 | #include <pakfire/repo.h> |
78cc8800 | 36 | #include <pakfire/repolist.h> |
b7e72fe2 | 37 | #include <pakfire/request.h> |
b31be147 | 38 | #include <pakfire/util.h> |
6e46b18e | 39 | |
36c98595 | 40 | #include "archive.h" |
9d6b128a | 41 | #include "errors.h" |
ad62bb07 | 42 | #include "key.h" |
6e46b18e | 43 | #include "pakfire.h" |
843fcc66 | 44 | #include "repo.h" |
f989dacd | 45 | #include "util.h" |
6e46b18e MT |
46 | |
47 | static PyObject* Pakfire_new(PyTypeObject* type, PyObject* args, PyObject* kwds) { | |
48 | PakfireObject* self = (PakfireObject *)type->tp_alloc(type, 0); | |
49 | if (self) { | |
50 | self->pakfire = NULL; | |
45cbf6f4 MT |
51 | |
52 | // Callbacks | |
53 | self->callbacks.log = NULL; | |
d6409945 | 54 | self->callbacks.confirm = NULL; |
6e46b18e MT |
55 | } |
56 | ||
57 | return (PyObject *)self; | |
58 | } | |
59 | ||
45cbf6f4 | 60 | static void Pakfire_log_callback(void* data, int priority, const char* file, int line, |
0e45f213 | 61 | const char* fn, const char* format, va_list args) { |
09f1436a | 62 | PyObject* callback = (PyObject*)data; |
0e45f213 MT |
63 | |
64 | // Do nothing if callback isn't set | |
09f1436a | 65 | if (!callback) |
0e45f213 MT |
66 | return; |
67 | ||
68 | // Translate priority to Python logging priorities | |
69 | switch (priority) { | |
c1a3cf68 MT |
70 | case LOG_DEBUG: |
71 | priority = 10; | |
72 | break; | |
73 | ||
0e45f213 MT |
74 | case LOG_INFO: |
75 | priority = 20; | |
76 | break; | |
77 | ||
78 | case LOG_ERR: | |
79 | priority = 40; | |
80 | break; | |
af6dfef2 MT |
81 | |
82 | // Drop messages of an unknown priority | |
83 | default: | |
84 | return; | |
0e45f213 MT |
85 | } |
86 | ||
87 | PyObject* tuple = NULL; | |
88 | PyObject* result = NULL; | |
89 | char* buffer = NULL; | |
90 | ||
91 | // Make line | |
92 | int r = vasprintf(&buffer, format, args); | |
93 | if (r < 0) | |
94 | goto ERROR; | |
95 | ||
96 | // Build a tuple with the priority and the log message | |
97 | tuple = Py_BuildValue("(is)", priority, buffer); | |
98 | if (!tuple) | |
99 | goto ERROR; | |
100 | ||
101 | // Call the callback | |
09f1436a | 102 | result = PyObject_CallObject(callback, tuple); |
0e45f213 MT |
103 | |
104 | ERROR: | |
105 | if (buffer) | |
106 | free(buffer); | |
107 | Py_XDECREF(tuple); | |
108 | Py_XDECREF(result); | |
109 | } | |
110 | ||
d6409945 MT |
111 | static int Pakfire_confirm_callback(struct pakfire* pakfire, void* data, |
112 | const char* message, const char* question) { | |
113 | PyObject* callback = (PyObject*)data; | |
114 | int r = 0; | |
115 | ||
116 | // Do nothing if callback isn't set | |
117 | if (!callback) | |
118 | return 0; | |
119 | ||
120 | PyObject* args = Py_BuildValue("(ss)", message, question); | |
121 | if (!args) | |
122 | return -1; | |
123 | ||
124 | PyObject* result = PyObject_CallObject(callback, args); | |
125 | ||
126 | // Extract return code | |
127 | if (PyLong_Check(result)) | |
128 | r = PyLong_AsLong(result); | |
129 | ||
130 | Py_DECREF(args); | |
131 | Py_DECREF(result); | |
132 | ||
133 | return r; | |
134 | } | |
135 | ||
6e46b18e | 136 | static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) { |
09f1436a MT |
137 | char* kwlist[] = { |
138 | "path", | |
139 | "arch", | |
140 | "logger", | |
141 | "interactive", | |
142 | "offline", | |
143 | "conf", | |
144 | "build", | |
145 | "enable_ccache", | |
146 | "enable_snapshot", | |
d6409945 | 147 | "confirm_callback", |
09f1436a MT |
148 | NULL, |
149 | }; | |
6e46b18e | 150 | const char* path = NULL; |
72caad76 | 151 | const char* arch = NULL; |
54bf8fba | 152 | const char* conf = NULL; |
135aec29 | 153 | int interactive = 0; |
72caad76 | 154 | int offline = 0; |
26452aef MT |
155 | int build = 0; |
156 | int enable_ccache = 1; | |
157 | int enable_snapshot = 1; | |
6e46b18e | 158 | |
d6409945 | 159 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzOppzpppO", kwlist, |
135aec29 | 160 | &path, &arch, &self->callbacks.log, &interactive, &offline, &conf, &build, |
d6409945 | 161 | &enable_ccache, &enable_snapshot, &self->callbacks.confirm)) |
0e45f213 MT |
162 | return -1; |
163 | ||
45cbf6f4 MT |
164 | // Check if log callback is callable |
165 | if (self->callbacks.log && !PyCallable_Check(self->callbacks.log)) { | |
0e45f213 | 166 | PyErr_SetString(PyExc_TypeError, "logger must be callable\n"); |
6e46b18e | 167 | return -1; |
0e45f213 | 168 | } |
6e46b18e | 169 | |
d6409945 MT |
170 | // Check if confirm callback is callable |
171 | if (self->callbacks.confirm && !PyCallable_Check(self->callbacks.confirm)) { | |
172 | PyErr_SetString(PyExc_TypeError, "Confirm callback is not callable"); | |
173 | return -1; | |
174 | } | |
175 | ||
26452aef MT |
176 | int flags = 0; |
177 | ||
135aec29 MT |
178 | // Enable interactive mode |
179 | if (interactive) | |
180 | flags |= PAKFIRE_FLAGS_INTERACTIVE; | |
181 | ||
fb909902 MT |
182 | // Enable offline mode |
183 | if (offline) | |
184 | flags |= PAKFIRE_FLAGS_OFFLINE; | |
185 | ||
26452aef MT |
186 | // Enable build mode |
187 | if (build) { | |
188 | flags |= PAKFIRE_FLAGS_BUILD; | |
189 | ||
190 | if (!enable_ccache) | |
191 | flags |= PAKFIRE_FLAGS_DISABLE_CCACHE; | |
192 | ||
193 | if (!enable_snapshot) | |
194 | flags |= PAKFIRE_FLAGS_DISABLE_SNAPSHOT; | |
195 | } | |
196 | ||
836f71d2 | 197 | // Configure callbacks |
09f1436a | 198 | if (self->callbacks.log) |
45cbf6f4 | 199 | Py_INCREF(self->callbacks.log); |
45cbf6f4 | 200 | |
34c0706d | 201 | // Create a new Pakfire instance |
09f1436a | 202 | int r = pakfire_create(&self->pakfire, path, arch, conf, flags, |
bcb98c7b | 203 | LOG_DEBUG, Pakfire_log_callback, self->callbacks.log); |
6dbda957 | 204 | if (r) { |
f4e91beb MT |
205 | switch (errno) { |
206 | // Invalid architecture or path | |
207 | case EINVAL: | |
d971fe19 | 208 | PyErr_SetString(PyExc_ValueError, "Invalid architecture or path"); |
03b9652a MT |
209 | break; |
210 | ||
211 | // Anything else | |
212 | default: | |
f4e91beb | 213 | PyErr_SetFromErrno(PyExc_OSError); |
03b9652a | 214 | } |
6e46b18e | 215 | |
34c0706d | 216 | return -1; |
03b9652a MT |
217 | } |
218 | ||
d6409945 MT |
219 | // Configure confirm callback |
220 | if (self->callbacks.confirm) { | |
221 | pakfire_set_confirm_callback(self->pakfire, | |
222 | Pakfire_confirm_callback, self->callbacks.confirm); | |
223 | ||
224 | Py_INCREF(self->callbacks.confirm); | |
225 | } | |
226 | ||
03b9652a | 227 | return 0; |
6e46b18e MT |
228 | } |
229 | ||
230 | static void Pakfire_dealloc(PakfireObject* self) { | |
d122626c | 231 | if (self->pakfire) { |
09f1436a | 232 | // Reset log callback |
d6409945 MT |
233 | if (self->callbacks.log) { |
234 | pakfire_set_log_callback(self->pakfire, NULL, NULL); | |
235 | Py_DECREF(self->callbacks.log); | |
236 | } | |
237 | ||
238 | // Reset confirm callback | |
239 | if (self->callbacks.confirm) { | |
240 | pakfire_set_confirm_callback(self->pakfire, NULL, NULL); | |
241 | Py_DECREF(self->callbacks.confirm); | |
242 | } | |
6e46b18e | 243 | |
d122626c MT |
244 | pakfire_unref(self->pakfire); |
245 | } | |
a02be46b | 246 | |
6e46b18e MT |
247 | Py_TYPE(self)->tp_free((PyObject *)self); |
248 | } | |
249 | ||
250 | static PyObject* Pakfire_repr(PakfireObject* self) { | |
251 | const char* path = pakfire_get_path(self->pakfire); | |
252 | const char* arch = pakfire_get_arch(self->pakfire); | |
253 | ||
254 | return PyUnicode_FromFormat("<_pakfire.Pakfire %s (%s)>", path, arch); | |
255 | } | |
256 | ||
257 | static PyObject* Pakfire_get_path(PakfireObject* self) { | |
258 | const char* path = pakfire_get_path(self->pakfire); | |
259 | ||
260 | return PyUnicode_FromString(path); | |
261 | } | |
262 | ||
263 | static PyObject* Pakfire_get_arch(PakfireObject* self) { | |
264 | const char* arch = pakfire_get_arch(self->pakfire); | |
265 | ||
266 | return PyUnicode_FromString(arch); | |
267 | } | |
268 | ||
8ef6c388 MT |
269 | static PyObject* Pakfire_get_repo(PakfireObject* self, PyObject* args) { |
270 | const char* name = NULL; | |
271 | ||
272 | if (!PyArg_ParseTuple(args, "s", &name)) | |
273 | return NULL; | |
274 | ||
4651122b | 275 | struct pakfire_repo* repo = pakfire_get_repo(self->pakfire, name); |
8ef6c388 MT |
276 | if (!repo) |
277 | Py_RETURN_NONE; | |
278 | ||
279 | PyObject* obj = new_repo(&RepoType, repo); | |
280 | pakfire_repo_unref(repo); | |
281 | ||
282 | return obj; | |
283 | } | |
284 | ||
8a2ff479 MT |
285 | static void Pakfire_status_callback(struct pakfire* pakfire, void* data, |
286 | int progress, const char* status) { | |
287 | PyObject* callback = (PyObject*)data; | |
288 | ||
289 | // Do not attempt to call nothing | |
290 | if (!callback) | |
291 | return; | |
292 | ||
293 | // Compile arguments | |
294 | PyObject* args = Py_BuildValue("(is)", progress, status); | |
295 | if (!args) | |
296 | return; | |
297 | ||
298 | // Call the callback | |
299 | PyObject* result = PyObject_CallObject(callback, args); | |
300 | ||
301 | Py_XDECREF(result); | |
302 | Py_DECREF(args); | |
303 | } | |
304 | ||
b7e72fe2 MT |
305 | static int convert_packages(PyObject* object, void* address) { |
306 | char*** packages = (char***)address; | |
307 | ||
308 | // Called for cleanup | |
309 | if (!object) | |
310 | goto ERROR; | |
311 | ||
67a3604c MT |
312 | // Nothing to do when object is None |
313 | if (object == Py_None) | |
314 | return Py_CLEANUP_SUPPORTED; | |
315 | ||
b7e72fe2 MT |
316 | if (!PySequence_Check(object)) { |
317 | PyErr_SetString(PyExc_ValueError, "Packages must be a sequence"); | |
318 | goto ERROR; | |
319 | } | |
320 | ||
321 | const unsigned int length = PySequence_Length(object); | |
cb3f13aa MT |
322 | if (!length) |
323 | return Py_CLEANUP_SUPPORTED; | |
b7e72fe2 MT |
324 | |
325 | // Allocate array | |
326 | *packages = calloc(length + 1, sizeof(*packages)); | |
327 | if (!*packages) { | |
328 | PyErr_SetFromErrno(PyExc_OSError); | |
329 | goto ERROR; | |
330 | } | |
331 | ||
332 | for (unsigned int i = 0; i < length; i++) { | |
333 | PyObject* item = PySequence_GetItem(object, i); | |
334 | ||
335 | // Check if input is a string | |
336 | if (!PyUnicode_Check(item)) { | |
337 | Py_DECREF(item); | |
338 | ||
339 | PyErr_SetString(PyExc_AttributeError, "Expected a string"); | |
340 | goto ERROR; | |
341 | } | |
342 | ||
343 | // Fetch string | |
344 | const char* package = PyUnicode_AsUTF8(item); | |
345 | if (!package) { | |
346 | Py_DECREF(item); | |
347 | goto ERROR; | |
348 | } | |
349 | ||
350 | // Add package to array | |
9236f1b9 MT |
351 | (*packages)[i] = strdup(package); |
352 | if (!(*packages)[i]) { | |
b7e72fe2 MT |
353 | Py_DECREF(item); |
354 | goto ERROR; | |
355 | } | |
356 | ||
357 | Py_DECREF(item); | |
358 | } | |
359 | ||
360 | // Success | |
361 | return Py_CLEANUP_SUPPORTED; | |
362 | ||
363 | ERROR: | |
364 | if (*packages) { | |
365 | for (char** package = *packages; *package; package++) | |
366 | free(*package); | |
367 | free(*packages); | |
368 | } | |
369 | ||
370 | return 0; | |
371 | } | |
372 | ||
373 | static PyObject* Pakfire_install(PakfireObject* self, PyObject* args, PyObject* kwargs) { | |
374 | char* kwlist[] = { | |
375 | "packages", | |
46f60d93 | 376 | "dryrun", |
c572abee | 377 | "without_recommended", |
a005d132 MT |
378 | "allow_uninstall", |
379 | "allow_downgrade", | |
8a2ff479 | 380 | "status_callback", |
b7e72fe2 MT |
381 | NULL |
382 | }; | |
383 | char** packages = NULL; | |
46f60d93 | 384 | int dryrun = 0; |
c572abee | 385 | int without_recommended = 0; |
a005d132 MT |
386 | int allow_uninstall = 0; |
387 | int allow_downgrade = 0; | |
c572abee | 388 | int solver_flags = 0; |
46f60d93 | 389 | int transaction_flags = 0; |
8a2ff479 | 390 | PyObject* status_callback = NULL; |
b7e72fe2 | 391 | |
46f60d93 MT |
392 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$ppppO", kwlist, |
393 | convert_packages, &packages, &dryrun, &without_recommended, &allow_uninstall, | |
8a2ff479 MT |
394 | &allow_downgrade, &status_callback)) |
395 | return NULL; | |
396 | ||
397 | // Check if callback is callable | |
398 | if (status_callback && !PyCallable_Check(status_callback)) { | |
399 | PyErr_SetString(PyExc_TypeError, "status_callback must be callable"); | |
b7e72fe2 | 400 | return NULL; |
8a2ff479 | 401 | } |
b7e72fe2 | 402 | |
46f60d93 MT |
403 | // Enable dry-run mode |
404 | if (dryrun) | |
405 | transaction_flags |= PAKFIRE_TRANSACTION_DRY_RUN; | |
406 | ||
c572abee MT |
407 | // Do not install recommended packages |
408 | if (without_recommended) | |
409 | solver_flags |= PAKFIRE_REQUEST_WITHOUT_RECOMMENDED; | |
b7e72fe2 | 410 | |
a005d132 MT |
411 | // Can the solver uninstall packages? |
412 | if (allow_uninstall) | |
413 | solver_flags |= PAKFIRE_REQUEST_ALLOW_UNINSTALL; | |
414 | ||
415 | // Can the solver downgrade packages? | |
416 | if (allow_downgrade) | |
417 | solver_flags |= PAKFIRE_REQUEST_ALLOW_DOWNGRADE; | |
418 | ||
b7e72fe2 | 419 | // Run pakfire_install |
46f60d93 MT |
420 | int r = pakfire_install(self->pakfire, transaction_flags, solver_flags, |
421 | (const char**)packages, NULL, 0, NULL, Pakfire_status_callback, status_callback); | |
b7e72fe2 MT |
422 | if (r) |
423 | PyErr_SetFromErrno(PyExc_OSError); | |
424 | ||
425 | if (packages) { | |
426 | for (char** package = packages; *package; package++) | |
427 | free(*package); | |
428 | free(packages); | |
429 | } | |
430 | ||
431 | if (r) | |
432 | return NULL; | |
433 | ||
434 | Py_RETURN_NONE; | |
435 | } | |
436 | ||
437 | static PyObject* Pakfire_erase(PakfireObject* self, PyObject* args, PyObject* kwargs) { | |
438 | char* kwlist[] = { | |
439 | "packages", | |
46f60d93 | 440 | "dryrun", |
d798b956 | 441 | "keep_dependencies", |
8a2ff479 | 442 | "status_callback", |
b7e72fe2 MT |
443 | NULL |
444 | }; | |
445 | char** packages = NULL; | |
46f60d93 | 446 | int dryrun = 0; |
d798b956 | 447 | int keep_dependencies = 0; |
46f60d93 | 448 | int transaction_flags = 0; |
b7e72fe2 | 449 | int flags = 0; |
8a2ff479 | 450 | PyObject* status_callback = NULL; |
b7e72fe2 | 451 | |
46f60d93 MT |
452 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$ppO", kwlist, |
453 | convert_packages, &packages, &dryrun, &keep_dependencies, &status_callback)) | |
b7e72fe2 MT |
454 | return NULL; |
455 | ||
8a2ff479 MT |
456 | // Check if callback is callable |
457 | if (status_callback && !PyCallable_Check(status_callback)) { | |
458 | PyErr_SetString(PyExc_TypeError, "status_callback must be callable"); | |
459 | return NULL; | |
460 | } | |
461 | ||
46f60d93 MT |
462 | if (dryrun) |
463 | transaction_flags |= PAKFIRE_TRANSACTION_DRY_RUN; | |
464 | ||
d798b956 MT |
465 | if (keep_dependencies) |
466 | flags |= PAKFIRE_REQUEST_KEEP_DEPS; | |
467 | ||
b7e72fe2 | 468 | // Run pakfire_erase |
46f60d93 MT |
469 | int r = pakfire_erase(self->pakfire, transaction_flags, 0, (const char**)packages, |
470 | NULL, flags, NULL, Pakfire_status_callback, status_callback); | |
b7e72fe2 MT |
471 | if (r) |
472 | PyErr_SetFromErrno(PyExc_OSError); | |
473 | ||
474 | if (packages) { | |
475 | for (char** package = packages; *package; package++) | |
476 | free(*package); | |
477 | free(packages); | |
478 | } | |
479 | ||
480 | if (r) | |
481 | return NULL; | |
482 | ||
483 | Py_RETURN_NONE; | |
484 | } | |
485 | ||
486 | static PyObject* Pakfire_update(PakfireObject* self, PyObject* args, PyObject* kwargs) { | |
487 | char* kwlist[] = { | |
488 | "packages", | |
46f60d93 | 489 | "dryrun", |
c9b18fbd | 490 | "excludes", |
a005d132 MT |
491 | "allow_uninstall", |
492 | "allow_downgrade", | |
8a2ff479 | 493 | "status_callback", |
b7e72fe2 MT |
494 | NULL |
495 | }; | |
496 | char** packages = NULL; | |
c9b18fbd | 497 | char** excludes = NULL; |
46f60d93 | 498 | int dryrun = 0; |
a005d132 MT |
499 | int allow_uninstall = 0; |
500 | int allow_downgrade = 0; | |
501 | int solver_flags = 0; | |
46f60d93 | 502 | int transaction_flags = 0; |
8a2ff479 | 503 | PyObject* status_callback = NULL; |
b7e72fe2 | 504 | |
8a2ff479 | 505 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$O&ppO", kwlist, |
a005d132 | 506 | convert_packages, &packages, convert_packages, &excludes, |
8a2ff479 MT |
507 | &allow_uninstall, &allow_downgrade, &status_callback)) |
508 | return NULL; | |
509 | ||
510 | // Check if callback is callable | |
511 | if (status_callback && !PyCallable_Check(status_callback)) { | |
512 | PyErr_SetString(PyExc_TypeError, "status_callback must be callable"); | |
b7e72fe2 | 513 | return NULL; |
8a2ff479 | 514 | } |
b7e72fe2 | 515 | |
46f60d93 MT |
516 | if (dryrun) |
517 | transaction_flags = PAKFIRE_TRANSACTION_DRY_RUN; | |
518 | ||
a005d132 MT |
519 | // Can the solver uninstall packages? |
520 | if (allow_uninstall) | |
521 | solver_flags |= PAKFIRE_REQUEST_ALLOW_UNINSTALL; | |
522 | ||
523 | // Can the solver downgrade packages? | |
524 | if (allow_downgrade) | |
525 | solver_flags |= PAKFIRE_REQUEST_ALLOW_DOWNGRADE; | |
526 | ||
b7e72fe2 | 527 | // Run pakfire_update |
46f60d93 MT |
528 | int r = pakfire_update(self->pakfire, transaction_flags, solver_flags, |
529 | (const char**)packages, (const char**)excludes, 0, NULL, | |
530 | Pakfire_status_callback, status_callback); | |
b7e72fe2 MT |
531 | if (r) |
532 | PyErr_SetFromErrno(PyExc_OSError); | |
533 | ||
534 | if (packages) { | |
535 | for (char** package = packages; *package; package++) | |
536 | free(*package); | |
537 | free(packages); | |
538 | } | |
539 | ||
c9b18fbd MT |
540 | if (excludes) { |
541 | for (char** exclude = excludes; *exclude; exclude++) | |
542 | free(*exclude); | |
543 | free(excludes); | |
544 | } | |
545 | ||
b7e72fe2 MT |
546 | if (r) |
547 | return NULL; | |
548 | ||
549 | Py_RETURN_NONE; | |
550 | } | |
551 | ||
11fdddfa | 552 | static PyObject* Pakfire_keys_to_list(struct pakfire_key** keys) { |
ad62bb07 MT |
553 | PyObject* list = PyList_New(0); |
554 | ||
11fdddfa MT |
555 | // Empty input? |
556 | if (!keys) | |
557 | return list; | |
ad62bb07 | 558 | |
11fdddfa MT |
559 | // Push all keys onto the list |
560 | for (struct pakfire_key** key = keys; *key; key++) { | |
561 | PyObject* object = new_key(&KeyType, *key); | |
562 | if (!object) | |
563 | goto ERROR; | |
7b526dd2 | 564 | |
11fdddfa | 565 | PyList_Append(list, object); |
ad62bb07 | 566 | Py_DECREF(object); |
ad62bb07 MT |
567 | } |
568 | ||
569 | return list; | |
11fdddfa MT |
570 | |
571 | ERROR: | |
572 | Py_DECREF(list); | |
573 | return NULL; | |
ad62bb07 MT |
574 | } |
575 | ||
7b526dd2 | 576 | static PyObject* Pakfire_get_keys(PakfireObject* self) { |
56f34ab4 | 577 | struct pakfire_key** keys = NULL; |
7b526dd2 | 578 | |
56f34ab4 MT |
579 | int r = pakfire_list_keys(self->pakfire, &keys); |
580 | if (r) { | |
581 | PyErr_SetFromErrno(PyExc_OSError); | |
582 | return NULL; | |
583 | } | |
584 | ||
11fdddfa MT |
585 | // Convert keys to list |
586 | PyObject* list = Pakfire_keys_to_list(keys); | |
587 | ||
588 | // Free keys | |
bf332eec MT |
589 | if (keys) { |
590 | for (struct pakfire_key** key = keys; *key; key++) | |
591 | pakfire_key_unref(*key); | |
592 | free(keys); | |
593 | } | |
11fdddfa MT |
594 | |
595 | return list; | |
7b526dd2 MT |
596 | } |
597 | ||
ad62bb07 MT |
598 | static PyObject* Pakfire_get_key(PakfireObject* self, PyObject* args) { |
599 | const char* pattern = NULL; | |
600 | ||
601 | if (!PyArg_ParseTuple(args, "s", &pattern)) | |
602 | return NULL; | |
603 | ||
116a426f | 604 | // Try finding the key |
cf7aa31b | 605 | struct pakfire_key* key = pakfire_key_get(self->pakfire, pattern); |
ad62bb07 MT |
606 | if (!key) |
607 | Py_RETURN_NONE; | |
608 | ||
116a426f MT |
609 | PyObject* object = new_key(&KeyType, key); |
610 | pakfire_key_unref(key); | |
611 | ||
612 | return object; | |
ad62bb07 MT |
613 | } |
614 | ||
f54744b1 MT |
615 | static PyObject* Pakfire_generate_key(PakfireObject* self, PyObject* args, PyObject* kwds) { |
616 | char* kwlist[] = { "userid", "algorithm", NULL }; | |
617 | struct pakfire_key* key = NULL; | |
ad62bb07 | 618 | const char* userid = NULL; |
f54744b1 | 619 | const char* algo = NULL; |
ad62bb07 | 620 | |
f54744b1 | 621 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|$z", kwlist, &userid, &algo)) |
ad62bb07 MT |
622 | return NULL; |
623 | ||
f54744b1 MT |
624 | // Generate a new key |
625 | int r = pakfire_key_generate(&key, self->pakfire, algo, userid); | |
626 | if (r) { | |
627 | PyErr_SetFromErrno(PyExc_OSError); | |
628 | return NULL; | |
629 | } | |
ad62bb07 | 630 | |
116a426f MT |
631 | PyObject* object = new_key(&KeyType, key); |
632 | pakfire_key_unref(key); | |
633 | ||
634 | return object; | |
ad62bb07 MT |
635 | } |
636 | ||
7b526dd2 | 637 | static PyObject* Pakfire_import_key(PakfireObject* self, PyObject* args) { |
3a2bc504 | 638 | PyObject* object = NULL; |
7b526dd2 | 639 | |
3a2bc504 | 640 | if (!PyArg_ParseTuple(args, "O", &object)) |
7b526dd2 MT |
641 | return NULL; |
642 | ||
3a2bc504 MT |
643 | // Get a file descriptor from object |
644 | int fd = PyObject_AsFileDescriptor(object); | |
645 | if (fd < 0) | |
646 | return NULL; | |
647 | ||
648 | // Convert to FILE* | |
649 | FILE* f = fdopen(fd, "r"); | |
650 | if (!f) { | |
651 | PyErr_SetFromErrno(PyExc_OSError); | |
652 | return NULL; | |
653 | } | |
654 | ||
655 | struct pakfire_key** keys = NULL; | |
7b526dd2 | 656 | |
3a2bc504 MT |
657 | // Import keys from f |
658 | int r = pakfire_key_import(self->pakfire, f, &keys); | |
659 | if (r) { | |
660 | PyErr_SetFromErrno(PyExc_OSError); | |
661 | return NULL; | |
662 | } | |
663 | ||
11fdddfa MT |
664 | // Convert keys to list |
665 | PyObject* list = Pakfire_keys_to_list(keys); | |
666 | ||
667 | // Free keys | |
668 | for (struct pakfire_key** key = keys; *key; key++) | |
669 | pakfire_key_unref(*key); | |
670 | free(keys); | |
671 | ||
672 | return list; | |
7b526dd2 MT |
673 | } |
674 | ||
b238027b MT |
675 | static PyObject* Pakfire_fetch_key(PakfireObject* self, PyObject* args, PyObject* kwds) { |
676 | char* kwlist[] = { "userid", "fingerprint", NULL }; | |
677 | struct pakfire_key* key = NULL; | |
678 | const char* userid = NULL; | |
679 | const char* fingerprint = NULL; | |
680 | ||
681 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$zz", kwlist, &userid, &fingerprint)) | |
682 | return NULL; | |
683 | ||
684 | // Fetch the key | |
685 | int r = pakfire_key_fetch(&key, self->pakfire, userid, fingerprint); | |
686 | if (r) { | |
687 | PyErr_SetFromErrno(PyExc_OSError); | |
688 | return NULL; | |
689 | } | |
690 | ||
691 | // Return the result | |
116a426f MT |
692 | if (key) { |
693 | PyObject* object = new_key(&KeyType, key); | |
694 | pakfire_key_unref(key); | |
695 | ||
696 | return object; | |
697 | } | |
b238027b MT |
698 | |
699 | Py_RETURN_NONE; | |
700 | } | |
701 | ||
54334355 MT |
702 | static PyObject* Pakfire_whatprovides(PakfireObject* self, PyObject* args) { |
703 | const char* provides = NULL; | |
704 | struct pakfire_packagelist* list = NULL; | |
f989dacd | 705 | |
54334355 | 706 | if (!PyArg_ParseTuple(args, "s", &provides)) |
f989dacd MT |
707 | return NULL; |
708 | ||
54334355 MT |
709 | int r = pakfire_whatprovides(self->pakfire, provides, 0, &list); |
710 | if (r) { | |
711 | PyErr_SetFromErrno(PyExc_OSError); | |
712 | return NULL; | |
713 | } | |
f989dacd | 714 | |
178a4506 MT |
715 | PyObject* obj = PyList_FromPackageList(list); |
716 | pakfire_packagelist_unref(list); | |
717 | ||
718 | return obj; | |
f989dacd MT |
719 | } |
720 | ||
8201cef2 MT |
721 | static PyObject* Pakfire_whatrequires(PakfireObject* self, PyObject* args) { |
722 | const char* requires = NULL; | |
b055ddf1 | 723 | struct pakfire_packagelist* list = NULL; |
8201cef2 MT |
724 | |
725 | if (!PyArg_ParseTuple(args, "s", &requires)) | |
726 | return NULL; | |
727 | ||
b055ddf1 MT |
728 | int r = pakfire_whatrequires(self->pakfire, requires, 0, &list); |
729 | if (r) { | |
730 | PyErr_SetFromErrno(PyExc_OSError); | |
731 | return NULL; | |
732 | } | |
8201cef2 MT |
733 | |
734 | PyObject* obj = PyList_FromPackageList(list); | |
735 | pakfire_packagelist_unref(list); | |
736 | ||
737 | return obj; | |
738 | } | |
739 | ||
4952c631 MT |
740 | static PyObject* Pakfire_search(PakfireObject* self, PyObject* args, PyObject* kwds) { |
741 | char* kwlist[] = { "pattern", "name_only", NULL }; | |
689b4aca | 742 | struct pakfire_packagelist* list = NULL; |
4952c631 MT |
743 | const char* pattern = NULL; |
744 | int name_only = 0; | |
745 | int flags = 0; | |
f989dacd | 746 | |
4952c631 | 747 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|$p", kwlist, &pattern, &name_only)) |
f989dacd MT |
748 | return NULL; |
749 | ||
4952c631 MT |
750 | // Search for package names only |
751 | if (name_only) | |
752 | flags |= PAKFIRE_SEARCH_NAME_ONLY; | |
753 | ||
754 | int r = pakfire_search(self->pakfire, pattern, flags, &list); | |
689b4aca MT |
755 | if (r) { |
756 | PyErr_SetFromErrno(PyExc_OSError); | |
757 | return NULL; | |
758 | } | |
178a4506 MT |
759 | |
760 | PyObject* obj = PyList_FromPackageList(list); | |
761 | pakfire_packagelist_unref(list); | |
762 | ||
763 | return obj; | |
f989dacd MT |
764 | } |
765 | ||
766 | static PyObject* Pakfire_version_compare(PakfireObject* self, PyObject* args) { | |
767 | const char* evr1 = NULL; | |
768 | const char* evr2 = NULL; | |
769 | ||
770 | if (!PyArg_ParseTuple(args, "ss", &evr1, &evr2)) | |
771 | return NULL; | |
772 | ||
773 | int cmp = pakfire_version_compare(self->pakfire, evr1, evr2); | |
774 | ||
775 | return PyLong_FromLong(cmp); | |
776 | } | |
777 | ||
d5bb2996 MT |
778 | static PyObject* Pakfire_execute_logging_callback = NULL; |
779 | ||
ac4c607b | 780 | static int __Pakfire_execute_logging_callback(struct pakfire* pakfire, void* data, |
cccbd595 | 781 | int priority, const char* line, size_t length) { |
d5bb2996 MT |
782 | int r = 0; |
783 | ||
784 | // Do nothing if callback isn't set | |
785 | if (!Pakfire_execute_logging_callback) | |
786 | return 0; | |
787 | ||
69a9063c MT |
788 | // Translate priority to Python logging priorities |
789 | switch (priority) { | |
790 | case LOG_INFO: | |
791 | priority = 20; | |
792 | break; | |
793 | ||
794 | case LOG_ERR: | |
795 | priority = 40; | |
796 | break; | |
797 | } | |
798 | ||
8e632745 | 799 | // Remove the trailing newline |
9e2e186b | 800 | if (line && line[length - 1] == '\n') |
8e632745 MT |
801 | length--; |
802 | ||
d5bb2996 | 803 | // Create tuple with arguments for the callback function |
16495755 | 804 | PyObject* args = Py_BuildValue("(is#)", priority, line, (Py_ssize_t)length); |
d5bb2996 MT |
805 | if (!args) |
806 | return 1; | |
807 | ||
57c1dbb4 | 808 | PyObject* result = PyObject_CallObject(Pakfire_execute_logging_callback, args); |
d5bb2996 MT |
809 | if (result && PyLong_Check(result)) { |
810 | r = PyLong_AsLong(result); | |
811 | } | |
812 | ||
813 | Py_XDECREF(args); | |
b1a539ef | 814 | Py_XDECREF(result); |
d5bb2996 MT |
815 | |
816 | return r; | |
817 | } | |
818 | ||
9d6b128a | 819 | static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject* kwds) { |
d5bb2996 MT |
820 | char* kwlist[] = {"command", "environ", "enable_network", "interactive", |
821 | "logging_callback", NULL}; | |
9d6b128a MT |
822 | |
823 | PyObject* command = NULL; | |
824 | PyObject* environ = NULL; | |
d0759555 | 825 | int enable_network = 0; |
2aa9c5f5 | 826 | int interactive = 0; |
d5bb2996 | 827 | PyObject* logging_callback = NULL; |
9d6b128a | 828 | |
d5bb2996 MT |
829 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OppO", kwlist, &command, &environ, |
830 | &enable_network, &interactive, &logging_callback)) | |
9d6b128a MT |
831 | return NULL; |
832 | ||
833 | // Check if command is a list | |
834 | if (!PyList_Check(command)) { | |
835 | PyErr_SetString(PyExc_TypeError, "command must be a list"); | |
836 | return NULL; | |
837 | } | |
838 | ||
839 | ssize_t command_length = PyList_Size(command); | |
840 | ||
841 | // Check if command is not empty | |
842 | if (command_length == 0) { | |
843 | PyErr_SetString(PyExc_ValueError, "command is empty"); | |
844 | return NULL; | |
845 | } | |
846 | ||
847 | // All arguments in command must be strings | |
848 | for (unsigned int i = 0; i < command_length; i++) { | |
849 | PyObject* item = PyList_GET_ITEM(command, i); | |
850 | ||
851 | if (!PyUnicode_Check(item)) { | |
852 | PyErr_Format(PyExc_TypeError, "Item %u in command is not a string", i); | |
853 | return NULL; | |
854 | } | |
855 | } | |
856 | ||
d5bb2996 MT |
857 | // Check if logging_callback is |
858 | if (logging_callback && !PyCallable_Check(logging_callback)) { | |
859 | PyErr_SetString(PyExc_TypeError, "logging_callback must be callable\n"); | |
860 | return NULL; | |
861 | } | |
862 | ||
9d6b128a MT |
863 | ssize_t environ_length = 0; |
864 | PyObject* key; | |
865 | PyObject* value; | |
866 | Py_ssize_t p = 0; | |
867 | ||
868 | if (environ) { | |
869 | // Check if environ is a dictionary | |
870 | if (!PyDict_Check(environ)) { | |
871 | PyErr_SetString(PyExc_TypeError, "environ must be a dictionary"); | |
872 | return NULL; | |
873 | } | |
874 | ||
875 | // All keys and values must be strings | |
876 | while (PyDict_Next(environ, &p, &key, &value)) { | |
877 | if (!PyUnicode_Check(key) || !PyUnicode_Check(value)) { | |
878 | PyErr_SetString(PyExc_TypeError, "Environment contains a non-string object"); | |
879 | return NULL; | |
880 | } | |
881 | } | |
882 | ||
883 | environ_length = PyDict_Size(environ); | |
884 | } | |
885 | ||
886 | // All inputs look fine | |
887 | ||
888 | const char* argv[command_length + 1]; | |
889 | char* envp[environ_length + 1]; | |
d0759555 | 890 | int flags = 0; |
9d6b128a MT |
891 | |
892 | // Parse arguments | |
893 | for (unsigned int i = 0; i < command_length; i++) { | |
894 | PyObject* item = PyList_GET_ITEM(command, i); | |
895 | argv[i] = PyUnicode_AsUTF8(item); | |
896 | } | |
897 | ||
898 | // Parse environ | |
899 | if (environ) { | |
900 | unsigned int i = 0; | |
901 | p = 0; | |
902 | ||
903 | while (PyDict_Next(environ, &p, &key, &value)) { | |
29299220 MT |
904 | int r = asprintf(&envp[i++], "%s=%s", |
905 | PyUnicode_AsUTF8(key), PyUnicode_AsUTF8(value)); | |
9d6b128a MT |
906 | |
907 | // Handle errors | |
908 | if (r < 0) { | |
9d6b128a | 909 | // Cleanup |
23b93958 | 910 | for (i = 0; envp[i]; i++) |
9d6b128a MT |
911 | free(envp[i]); |
912 | ||
913 | return PyErr_NoMemory(); | |
914 | } | |
915 | } | |
916 | } | |
917 | ||
918 | // Terminate argv and envp | |
919 | argv[command_length] = NULL; | |
920 | envp[environ_length] = NULL; | |
921 | ||
d0759555 MT |
922 | // Enable network? |
923 | if (enable_network) | |
924 | flags |= PAKFIRE_EXECUTE_ENABLE_NETWORK; | |
925 | ||
2aa9c5f5 MT |
926 | // Interactive? |
927 | if (interactive) | |
928 | flags |= PAKFIRE_EXECUTE_INTERACTIVE; | |
31f64b2c | 929 | |
d5bb2996 MT |
930 | // Set logging callback |
931 | Pakfire_execute_logging_callback = logging_callback; | |
932 | ||
9d6b128a | 933 | // Execute command |
d5bb2996 | 934 | int r = pakfire_execute(self->pakfire, argv, envp, flags, |
7feb5580 | 935 | (logging_callback) ? __Pakfire_execute_logging_callback : NULL, NULL); |
9d6b128a MT |
936 | |
937 | // Cleanup | |
938 | for (unsigned int i = 0; envp[i]; i++) | |
939 | free(envp[i]); | |
940 | ||
6d16c080 MT |
941 | // Raise an OS error if r < 0 |
942 | if (r < 0) { | |
943 | errno = -r; | |
944 | ||
945 | PyErr_SetFromErrno(PyExc_OSError); | |
946 | return NULL; | |
947 | ||
9d6b128a | 948 | // Raise exception when the command failed |
6d16c080 | 949 | } else if (r > 0) { |
9d6b128a MT |
950 | PyObject* code = PyLong_FromLong(r); |
951 | ||
952 | PyErr_SetObject(PyExc_CommandExecutionError, code); | |
953 | Py_DECREF(code); | |
954 | ||
955 | return NULL; | |
956 | } | |
957 | ||
958 | // Return nothing | |
959 | Py_RETURN_NONE; | |
960 | } | |
961 | ||
af41db7e MT |
962 | static PyObject* Pakfire_dist(PakfireObject* self, PyObject* args) { |
963 | const char* path = NULL; | |
964 | const char* target = NULL; | |
45448dbd | 965 | char* result = NULL; |
af41db7e MT |
966 | |
967 | if (!PyArg_ParseTuple(args, "s|z", &path, &target)) | |
968 | return NULL; | |
969 | ||
45448dbd | 970 | int r = pakfire_dist(self->pakfire, path, target, &result); |
af41db7e MT |
971 | if (r) { |
972 | PyErr_SetFromErrno(PyExc_OSError); | |
973 | return NULL; | |
974 | } | |
975 | ||
45448dbd MT |
976 | PyObject* ret = PyUnicode_FromString(result); |
977 | free(result); | |
978 | ||
979 | return ret; | |
af41db7e MT |
980 | } |
981 | ||
69e754ab MT |
982 | static PyObject* Pakfire_bind(PakfireObject* self, PyObject* args) { |
983 | const char* src = NULL; | |
984 | const char* dst = NULL; | |
985 | ||
986 | if (!PyArg_ParseTuple(args, "s|z", &src, &dst)) | |
987 | return NULL; | |
988 | ||
989 | int r = pakfire_bind(self->pakfire, src, dst, 0); | |
990 | if (r) { | |
991 | PyErr_SetFromErrno(PyExc_OSError); | |
992 | return NULL; | |
993 | } | |
994 | ||
995 | Py_RETURN_NONE; | |
996 | } | |
997 | ||
78f7a47c MT |
998 | static PyObject* Pakfire_copy_in(PakfireObject* self, PyObject* args) { |
999 | const char* src = NULL; | |
1000 | const char* dst = NULL; | |
1001 | ||
1002 | if (!PyArg_ParseTuple(args, "ss", &src, &dst)) | |
1003 | return NULL; | |
1004 | ||
1005 | int r = pakfire_copy_in(self->pakfire, src, dst); | |
1006 | if (r) { | |
1007 | PyErr_SetFromErrno(PyExc_OSError); | |
1008 | return NULL; | |
1009 | } | |
1010 | ||
1011 | Py_RETURN_NONE; | |
1012 | } | |
1013 | ||
1014 | static PyObject* Pakfire_copy_out(PakfireObject* self, PyObject* args) { | |
1015 | const char* src = NULL; | |
1016 | const char* dst = NULL; | |
1017 | ||
1018 | if (!PyArg_ParseTuple(args, "ss", &src, &dst)) | |
1019 | return NULL; | |
1020 | ||
1021 | int r = pakfire_copy_out(self->pakfire, src, dst); | |
1022 | if (r) { | |
1023 | PyErr_SetFromErrno(PyExc_OSError); | |
1024 | return NULL; | |
1025 | } | |
1026 | ||
1027 | Py_RETURN_NONE; | |
1028 | } | |
1029 | ||
78cc8800 MT |
1030 | static PyObject* Pakfire_get_repos(PakfireObject* self) { |
1031 | struct pakfire_repolist* repos = pakfire_get_repos(self->pakfire); | |
1032 | if (!repos) { | |
1033 | PyErr_SetFromErrno(PyExc_OSError); | |
1034 | return NULL; | |
1035 | } | |
1036 | ||
1037 | const size_t l = pakfire_repolist_size(repos); | |
1038 | ||
1039 | PyObject* list = PyList_New(l); | |
1040 | if (!list) | |
1041 | goto ERROR; | |
1042 | ||
1043 | for (unsigned int i = 0; i < l; i++) { | |
4651122b | 1044 | struct pakfire_repo* repo = pakfire_repolist_get(repos, i); |
78cc8800 MT |
1045 | if (!repo) |
1046 | continue; | |
1047 | ||
1048 | PyObject* obj = new_repo(&RepoType, repo); | |
1049 | PyList_SET_ITEM(list, i, obj); | |
1050 | ||
1051 | pakfire_repo_unref(repo); | |
1052 | } | |
1053 | ||
1054 | ERROR: | |
1055 | pakfire_repolist_unref(repos); | |
1056 | ||
1057 | return list; | |
1058 | } | |
1059 | ||
1a276007 MT |
1060 | static PyObject* execute_return_value(int r) { |
1061 | // Raise an OS error if r < 0 | |
1062 | if (r < 0) { | |
1063 | errno = -r; | |
1064 | ||
1065 | PyErr_SetFromErrno(PyExc_OSError); | |
1066 | return NULL; | |
1067 | ||
1068 | // Raise exception when the command failed | |
1069 | } else if (r > 0) { | |
1070 | PyObject* code = PyLong_FromLong(r); | |
1071 | ||
1072 | PyErr_SetObject(PyExc_CommandExecutionError, code); | |
1073 | Py_DECREF(code); | |
1074 | ||
1075 | return NULL; | |
1076 | } | |
1077 | ||
1078 | Py_RETURN_NONE; | |
1079 | } | |
1080 | ||
1081 | static PyObject* Pakfire_build(PakfireObject* self, PyObject* args, PyObject* kwargs) { | |
f4e10417 MT |
1082 | char* kwlist[] = { |
1083 | "path", | |
1084 | "build_id", | |
1085 | "logging_callback", | |
1086 | NULL, | |
1087 | }; | |
1a276007 MT |
1088 | |
1089 | const char* path = NULL; | |
eeba5748 | 1090 | const char* build_id = NULL; |
7d999600 | 1091 | PyObject* logging_callback = NULL; |
1a276007 | 1092 | |
f4e10417 MT |
1093 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zO", kwlist, &path, |
1094 | &build_id, &logging_callback)) | |
1a276007 MT |
1095 | return NULL; |
1096 | ||
7d999600 MT |
1097 | // Check if logging_callback is |
1098 | if (logging_callback && !PyCallable_Check(logging_callback)) { | |
1099 | PyErr_SetString(PyExc_TypeError, "logging_callback must be callable\n"); | |
1100 | return NULL; | |
1101 | } | |
1102 | ||
1103 | // Set logging callback | |
1104 | Pakfire_execute_logging_callback = logging_callback; | |
1105 | ||
1a276007 | 1106 | // Run build |
f4e10417 | 1107 | int r = pakfire_build(self->pakfire, path, NULL, build_id, 0, |
7d999600 | 1108 | (logging_callback) ? __Pakfire_execute_logging_callback : NULL, NULL); |
1a276007 MT |
1109 | |
1110 | return execute_return_value(r); | |
1111 | } | |
1112 | ||
7f068a08 MT |
1113 | static PyObject* Pakfire_shell(PakfireObject* self, PyObject* args, PyObject* kwargs) { |
1114 | char* kwlist[] = { | |
1115 | "install", | |
1116 | NULL, | |
1117 | }; | |
1118 | char** packages = NULL; | |
1119 | ||
1120 | // Parse everything | |
1121 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&", kwlist, convert_packages, &packages)) | |
1122 | return NULL; | |
1123 | ||
1124 | int r = pakfire_shell(self->pakfire, (const char**)packages); | |
1a276007 MT |
1125 | |
1126 | return execute_return_value(r); | |
1127 | } | |
1128 | ||
d1ed1ada | 1129 | static PyObject* Pakfire_clean(PakfireObject* self) { |
119ec3cf | 1130 | int r = pakfire_clean(self->pakfire, 0); |
d1ed1ada MT |
1131 | if (r) { |
1132 | PyErr_SetFromErrno(PyExc_OSError); | |
1133 | return NULL; | |
1134 | } | |
1135 | ||
1136 | Py_RETURN_NONE; | |
1137 | } | |
1138 | ||
03359f52 MT |
1139 | static PyObject* Pakfire_refresh(PakfireObject* self, PyObject* args) { |
1140 | int force = 0; | |
1141 | ||
1142 | if (!PyArg_ParseTuple(args, "|p", &force)) | |
1143 | return NULL; | |
1144 | ||
1145 | int r = pakfire_refresh(self->pakfire, force); | |
1146 | if (r) { | |
1147 | PyErr_SetFromErrno(PyExc_OSError); | |
1148 | return NULL; | |
1149 | } | |
1150 | ||
1151 | Py_RETURN_NONE; | |
1152 | } | |
1153 | ||
d37d8d56 MT |
1154 | static PyObject* Pakfire_check(PakfireObject* self) { |
1155 | int r = pakfire_check(self->pakfire); | |
1156 | if (r) { | |
1157 | PyErr_SetFromErrno(PyExc_OSError); | |
1158 | return NULL; | |
1159 | } | |
1160 | ||
1161 | Py_RETURN_NONE; | |
1162 | } | |
1163 | ||
550c7c1f | 1164 | static PyObject* Pakfire_sync(PakfireObject* self, PyObject* args, PyObject* kwargs) { |
8a2ff479 MT |
1165 | char* kwlist[] = { |
1166 | "keep_orphaned", | |
1167 | "status_callback", | |
1168 | NULL, | |
1169 | }; | |
550c7c1f MT |
1170 | int keep_orphaned = 0; |
1171 | int flags = 0; | |
8a2ff479 | 1172 | PyObject* status_callback = NULL; |
550c7c1f | 1173 | |
8a2ff479 MT |
1174 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|$pO", kwlist, |
1175 | &keep_orphaned, &status_callback)) | |
550c7c1f MT |
1176 | return NULL; |
1177 | ||
1178 | if (keep_orphaned) | |
1179 | flags |= PAKFIRE_REQUEST_KEEP_ORPHANED; | |
1180 | ||
8a2ff479 MT |
1181 | int r = pakfire_sync(self->pakfire, 0, flags, NULL, |
1182 | Pakfire_status_callback, status_callback); | |
5ca41ab1 MT |
1183 | if (r) { |
1184 | PyErr_SetFromErrno(PyExc_OSError); | |
1185 | return NULL; | |
1186 | } | |
1187 | ||
1188 | Py_RETURN_NONE; | |
1189 | } | |
1190 | ||
36c98595 | 1191 | static PyObject* Pakfire_open(PakfireObject* self, PyObject* args) { |
900faa2f | 1192 | struct pakfire_archive* archive = NULL; |
36c98595 MT |
1193 | const char* path = NULL; |
1194 | ||
1195 | if (!PyArg_ParseTuple(args, "s", &path)) | |
1196 | return NULL; | |
1197 | ||
1198 | int r = pakfire_archive_open(&archive, self->pakfire, path); | |
1199 | if (r) { | |
1200 | PyErr_SetFromErrno(PyExc_OSError); | |
1201 | return NULL; | |
1202 | } | |
1203 | ||
1204 | // Create Python object | |
1205 | PyObject* object = new_archive(&ArchiveType, archive); | |
1206 | pakfire_archive_unref(archive); | |
1207 | ||
1208 | return object; | |
1209 | } | |
1210 | ||
c54d9960 | 1211 | static PyObject* Pakfire_repo_compose(PakfireObject* self, PyObject* args, PyObject* kwargs) { |
0c3dce19 | 1212 | char* kwlist[] = { "path", "files", NULL }; |
c54d9960 | 1213 | const char* path = NULL; |
0c3dce19 | 1214 | PyObject* list = NULL; |
c54d9960 | 1215 | |
0c3dce19 MT |
1216 | PyObject* ret = NULL; |
1217 | ||
1218 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO", kwlist, &path, &list)) | |
1219 | return NULL; | |
1220 | ||
1221 | // List must be a sequence | |
1222 | if (!PySequence_Check(list)) { | |
1223 | PyErr_SetString(PyExc_ValueError, "Expected a sequence."); | |
c54d9960 | 1224 | return NULL; |
0c3dce19 | 1225 | } |
c54d9960 MT |
1226 | |
1227 | const int flags = 0; | |
1228 | ||
0c3dce19 MT |
1229 | // How many new files do we have? |
1230 | ssize_t num_files = PySequence_Length(list); | |
1231 | if (num_files < 0) | |
1232 | return NULL; | |
1233 | ||
1234 | // Allocate files array | |
1235 | const char** files = calloc(num_files + 1, sizeof(*files)); | |
1236 | if (!files) { | |
1237 | PyErr_SetFromErrno(PyExc_OSError); | |
1238 | return NULL; | |
1239 | } | |
1240 | ||
1241 | for (int i = 0; i < num_files; i++) { | |
1242 | PyObject* file = PySequence_GetItem(list, i); | |
1243 | if (!file) | |
1244 | goto ERROR; | |
1245 | ||
1246 | // Check if file is a Unicode object | |
1247 | if (!PyUnicode_Check(file)) { | |
1248 | PyErr_SetString(PyExc_ValueError, "Expected a string."); | |
1249 | goto ERROR; | |
1250 | } | |
1251 | ||
1252 | // Add pointer to string to files array | |
1253 | files[i] = PyUnicode_AsUTF8(file); | |
1254 | if (!files[i]) | |
1255 | goto ERROR; | |
1256 | ||
1257 | Py_DECREF(file); | |
1258 | } | |
1259 | ||
1260 | int r = pakfire_repo_compose(self->pakfire, path, flags, files); | |
c54d9960 MT |
1261 | if (r) { |
1262 | PyErr_SetFromErrno(PyExc_OSError); | |
1263 | return NULL; | |
1264 | } | |
1265 | ||
0c3dce19 MT |
1266 | // Return None on success |
1267 | ret = Py_None; | |
1268 | Py_INCREF(ret); | |
1269 | ||
1270 | ERROR: | |
1271 | if (files) | |
1272 | free(files); | |
1273 | ||
1274 | return ret; | |
c54d9960 MT |
1275 | } |
1276 | ||
6e46b18e | 1277 | static struct PyMethodDef Pakfire_methods[] = { |
69e754ab MT |
1278 | { |
1279 | "bind", | |
1280 | (PyCFunction)Pakfire_bind, | |
1281 | METH_VARARGS, | |
1282 | NULL, | |
1283 | }, | |
1a276007 MT |
1284 | { |
1285 | "build", | |
1286 | (PyCFunction)Pakfire_build, | |
1287 | METH_VARARGS|METH_KEYWORDS, | |
1288 | NULL | |
1289 | }, | |
d37d8d56 MT |
1290 | { |
1291 | "check", | |
1292 | (PyCFunction)Pakfire_check, | |
1293 | METH_NOARGS, | |
1294 | NULL, | |
1295 | }, | |
d1ed1ada MT |
1296 | { |
1297 | "clean", | |
1298 | (PyCFunction)Pakfire_clean, | |
1299 | METH_NOARGS, | |
1300 | NULL, | |
1301 | }, | |
78f7a47c MT |
1302 | { |
1303 | "copy_in", | |
1304 | (PyCFunction)Pakfire_copy_in, | |
1305 | METH_VARARGS, | |
1306 | NULL, | |
1307 | }, | |
1308 | { | |
1309 | "copy_out", | |
1310 | (PyCFunction)Pakfire_copy_out, | |
1311 | METH_VARARGS, | |
1312 | NULL, | |
1313 | }, | |
af41db7e MT |
1314 | { |
1315 | "dist", | |
1316 | (PyCFunction)Pakfire_dist, | |
1317 | METH_VARARGS, | |
1318 | NULL | |
1319 | }, | |
b7e72fe2 MT |
1320 | { |
1321 | "erase", | |
1322 | (PyCFunction)Pakfire_erase, | |
1323 | METH_VARARGS|METH_KEYWORDS, | |
1324 | NULL | |
1325 | }, | |
9d6b128a MT |
1326 | { |
1327 | "execute", | |
1328 | (PyCFunction)Pakfire_execute, | |
1329 | METH_VARARGS|METH_KEYWORDS, | |
1330 | NULL | |
1331 | }, | |
b238027b MT |
1332 | { |
1333 | "fetch_key", | |
1334 | (PyCFunction)Pakfire_fetch_key, | |
1335 | METH_VARARGS|METH_KEYWORDS, | |
1336 | NULL | |
1337 | }, | |
ad62bb07 MT |
1338 | { |
1339 | "generate_key", | |
1340 | (PyCFunction)Pakfire_generate_key, | |
f54744b1 | 1341 | METH_VARARGS|METH_KEYWORDS, |
ad62bb07 MT |
1342 | NULL |
1343 | }, | |
1344 | { | |
1345 | "get_key", | |
1346 | (PyCFunction)Pakfire_get_key, | |
1347 | METH_VARARGS, | |
1348 | NULL | |
1349 | }, | |
8ef6c388 MT |
1350 | { |
1351 | "get_repo", | |
1352 | (PyCFunction)Pakfire_get_repo, | |
1353 | METH_VARARGS, | |
1354 | NULL | |
1355 | }, | |
7b526dd2 MT |
1356 | { |
1357 | "import_key", | |
1358 | (PyCFunction)Pakfire_import_key, | |
1359 | METH_VARARGS, | |
1360 | NULL | |
1361 | }, | |
b7e72fe2 MT |
1362 | { |
1363 | "install", | |
1364 | (PyCFunction)Pakfire_install, | |
1365 | METH_VARARGS|METH_KEYWORDS, | |
1366 | NULL, | |
1367 | }, | |
36c98595 MT |
1368 | { |
1369 | "open", | |
1370 | (PyCFunction)Pakfire_open, | |
1371 | METH_VARARGS, | |
1372 | NULL | |
1373 | }, | |
03359f52 MT |
1374 | { |
1375 | "refresh", | |
1376 | (PyCFunction)Pakfire_refresh, | |
1377 | METH_VARARGS, | |
1378 | NULL, | |
1379 | }, | |
c54d9960 MT |
1380 | { |
1381 | "repo_compose", | |
1382 | (PyCFunction)Pakfire_repo_compose, | |
1383 | METH_VARARGS|METH_KEYWORDS, | |
1384 | NULL | |
1385 | }, | |
f989dacd MT |
1386 | { |
1387 | "search", | |
1388 | (PyCFunction)Pakfire_search, | |
4952c631 | 1389 | METH_VARARGS|METH_KEYWORDS, |
f989dacd MT |
1390 | NULL |
1391 | }, | |
1a276007 MT |
1392 | { |
1393 | "shell", | |
1394 | (PyCFunction)Pakfire_shell, | |
7f068a08 | 1395 | METH_VARARGS|METH_KEYWORDS, |
1a276007 MT |
1396 | NULL, |
1397 | }, | |
5ca41ab1 MT |
1398 | { |
1399 | "sync", | |
1400 | (PyCFunction)Pakfire_sync, | |
550c7c1f | 1401 | METH_VARARGS|METH_KEYWORDS, |
5ca41ab1 MT |
1402 | NULL, |
1403 | }, | |
b7e72fe2 MT |
1404 | { |
1405 | "update", | |
1406 | (PyCFunction)Pakfire_update, | |
1407 | METH_VARARGS|METH_KEYWORDS, | |
1408 | NULL | |
1409 | }, | |
f989dacd MT |
1410 | { |
1411 | "version_compare", | |
1412 | (PyCFunction)Pakfire_version_compare, | |
1413 | METH_VARARGS, | |
1414 | NULL | |
1415 | }, | |
1416 | { | |
1417 | "whatprovides", | |
1418 | (PyCFunction)Pakfire_whatprovides, | |
54334355 | 1419 | METH_VARARGS, |
f989dacd MT |
1420 | NULL |
1421 | }, | |
8201cef2 MT |
1422 | { |
1423 | "whatrequires", | |
1424 | (PyCFunction)Pakfire_whatrequires, | |
1425 | METH_VARARGS, | |
1426 | NULL | |
1427 | }, | |
6e46b18e MT |
1428 | { NULL }, |
1429 | }; | |
1430 | ||
1431 | static struct PyGetSetDef Pakfire_getsetters[] = { | |
1432 | { | |
1433 | "arch", | |
1434 | (getter)Pakfire_get_arch, | |
1435 | NULL, | |
1436 | NULL, | |
1437 | NULL | |
1438 | }, | |
ad62bb07 MT |
1439 | { |
1440 | "keys", | |
1441 | (getter)Pakfire_get_keys, | |
1442 | NULL, | |
1443 | NULL, | |
1444 | NULL | |
1445 | }, | |
6e46b18e MT |
1446 | { |
1447 | "path", | |
1448 | (getter)Pakfire_get_path, | |
1449 | NULL, | |
1450 | NULL, | |
1451 | NULL | |
1452 | }, | |
78cc8800 MT |
1453 | { |
1454 | "repos", | |
1455 | (getter)Pakfire_get_repos, | |
1456 | NULL, | |
1457 | NULL, | |
1458 | NULL | |
1459 | }, | |
6e46b18e MT |
1460 | { NULL }, |
1461 | }; | |
1462 | ||
1463 | PyTypeObject PakfireType = { | |
1464 | PyVarObject_HEAD_INIT(NULL, 0) | |
1465 | tp_name: "_pakfire.Pakfire", | |
1466 | tp_basicsize: sizeof(PakfireObject), | |
1467 | tp_flags: Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, | |
1468 | tp_new: Pakfire_new, | |
1469 | tp_dealloc: (destructor)Pakfire_dealloc, | |
1470 | tp_init: (initproc)Pakfire_init, | |
1471 | tp_doc: "Pakfire object", | |
1472 | tp_methods: Pakfire_methods, | |
1473 | tp_getset: Pakfire_getsetters, | |
1474 | tp_repr: (reprfunc)Pakfire_repr, | |
1475 | }; |