]> git.ipfire.org Git - people/ms/pakfire.git/blob - src/_pakfire/pakfire.c
archive: Change type from PakfireArchive to struct pakfire_archive
[people/ms/pakfire.git] / src / _pakfire / pakfire.c
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
21 #include <Python.h>
22 #include <errno.h>
23
24 #include <pakfire/archive.h>
25 #include <pakfire/build.h>
26 #include <pakfire/constants.h>
27 #include <pakfire/dist.h>
28 #include <pakfire/execute.h>
29 #include <pakfire/logging.h>
30 #include <pakfire/packagelist.h>
31 #include <pakfire/pakfire.h>
32 #include <pakfire/key.h>
33 #include <pakfire/repo.h>
34 #include <pakfire/repolist.h>
35 #include <pakfire/request.h>
36 #include <pakfire/util.h>
37
38 #include "archive.h"
39 #include "errors.h"
40 #include "key.h"
41 #include "pakfire.h"
42 #include "repo.h"
43 #include "util.h"
44
45 static PyObject* Pakfire_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
46 PakfireObject* self = (PakfireObject *)type->tp_alloc(type, 0);
47 if (self) {
48 self->pakfire = NULL;
49 self->logger = NULL;
50 }
51
52 return (PyObject *)self;
53 }
54
55 static void Pakfire_logging_callback(void* data, int priority, const char* file, int line,
56 const char* fn, const char* format, va_list args) {
57 PyObject* callback = (PyObject*)data;
58
59 // Do nothing if callback isn't set
60 if (!callback)
61 return;
62
63 // Translate priority to Python logging priorities
64 switch (priority) {
65 case LOG_DEBUG:
66 priority = 10;
67 break;
68
69 case LOG_INFO:
70 priority = 20;
71 break;
72
73 case LOG_ERR:
74 priority = 40;
75 break;
76
77 // Drop messages of an unknown priority
78 default:
79 return;
80 }
81
82 PyObject* tuple = NULL;
83 PyObject* result = NULL;
84 char* buffer = NULL;
85
86 // Make line
87 int r = vasprintf(&buffer, format, args);
88 if (r < 0)
89 goto ERROR;
90
91 // Build a tuple with the priority and the log message
92 tuple = Py_BuildValue("(is)", priority, buffer);
93 if (!tuple)
94 goto ERROR;
95
96 // Call the callback
97 result = PyObject_CallObject(callback, tuple);
98
99 ERROR:
100 if (buffer)
101 free(buffer);
102 Py_XDECREF(tuple);
103 Py_XDECREF(result);
104 }
105
106 static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) {
107 char* kwlist[] = { "path", "arch", "logger", "offline", "conf", "build",
108 "enable_ccache", "enable_snapshot", NULL };
109 const char* path = NULL;
110 const char* arch = NULL;
111 const char* conf = NULL;
112 int offline = 0;
113 int build = 0;
114 int enable_ccache = 1;
115 int enable_snapshot = 1;
116
117 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzOpzppp", kwlist,
118 &path, &arch, &self->logger, &offline, &conf, &build,
119 &enable_ccache, &enable_snapshot))
120 return -1;
121
122 // Check if logger is callable
123 if (self->logger && !PyCallable_Check(self->logger)) {
124 PyErr_SetString(PyExc_TypeError, "logger must be callable\n");
125 return -1;
126 }
127
128 int flags = 0;
129
130 // Enable offline mode
131 if (offline)
132 flags |= PAKFIRE_FLAGS_OFFLINE;
133
134 // Enable build mode
135 if (build) {
136 flags |= PAKFIRE_FLAGS_BUILD;
137
138 if (!enable_ccache)
139 flags |= PAKFIRE_FLAGS_DISABLE_CCACHE;
140
141 if (!enable_snapshot)
142 flags |= PAKFIRE_FLAGS_DISABLE_SNAPSHOT;
143 }
144
145 // Create a new Pakfire instance
146 int r = pakfire_create(&self->pakfire, path, arch, conf, flags,
147 (self->logger) ? Pakfire_logging_callback : NULL, self->logger);
148 if (r) {
149 switch (errno) {
150 // Invalid architecture or path
151 case EINVAL:
152 PyErr_SetString(PyExc_ValueError, "Invalid architecture or path");
153 break;
154
155 // Anything else
156 default:
157 PyErr_SetFromErrno(PyExc_OSError);
158 }
159
160 return -1;
161 }
162
163 Py_XINCREF(self->logger);
164
165 return 0;
166 }
167
168 static void Pakfire_dealloc(PakfireObject* self) {
169 if (self->pakfire)
170 pakfire_unref(self->pakfire);
171
172 if (self->logger)
173 Py_DECREF(self->logger);
174
175 Py_TYPE(self)->tp_free((PyObject *)self);
176 }
177
178 static PyObject* Pakfire_repr(PakfireObject* self) {
179 const char* path = pakfire_get_path(self->pakfire);
180 const char* arch = pakfire_get_arch(self->pakfire);
181
182 return PyUnicode_FromFormat("<_pakfire.Pakfire %s (%s)>", path, arch);
183 }
184
185 static PyObject* Pakfire_get_path(PakfireObject* self) {
186 const char* path = pakfire_get_path(self->pakfire);
187
188 return PyUnicode_FromString(path);
189 }
190
191 static PyObject* Pakfire_get_arch(PakfireObject* self) {
192 const char* arch = pakfire_get_arch(self->pakfire);
193
194 return PyUnicode_FromString(arch);
195 }
196
197 static PyObject* Pakfire_get_repo(PakfireObject* self, PyObject* args) {
198 const char* name = NULL;
199
200 if (!PyArg_ParseTuple(args, "s", &name))
201 return NULL;
202
203 struct pakfire_repo* repo = pakfire_get_repo(self->pakfire, name);
204 if (!repo)
205 Py_RETURN_NONE;
206
207 PyObject* obj = new_repo(&RepoType, repo);
208 pakfire_repo_unref(repo);
209
210 return obj;
211 }
212
213 static int convert_packages(PyObject* object, void* address) {
214 char*** packages = (char***)address;
215
216 // Called for cleanup
217 if (!object)
218 goto ERROR;
219
220 if (!PySequence_Check(object)) {
221 PyErr_SetString(PyExc_ValueError, "Packages must be a sequence");
222 goto ERROR;
223 }
224
225 const unsigned int length = PySequence_Length(object);
226 if (!length)
227 return Py_CLEANUP_SUPPORTED;
228
229 // Allocate array
230 *packages = calloc(length + 1, sizeof(*packages));
231 if (!*packages) {
232 PyErr_SetFromErrno(PyExc_OSError);
233 goto ERROR;
234 }
235
236 for (unsigned int i = 0; i < length; i++) {
237 PyObject* item = PySequence_GetItem(object, i);
238
239 // Check if input is a string
240 if (!PyUnicode_Check(item)) {
241 Py_DECREF(item);
242
243 PyErr_SetString(PyExc_AttributeError, "Expected a string");
244 goto ERROR;
245 }
246
247 // Fetch string
248 const char* package = PyUnicode_AsUTF8(item);
249 if (!package) {
250 Py_DECREF(item);
251 goto ERROR;
252 }
253
254 // Add package to array
255 (*packages)[i] = strdup(package);
256 if (!(*packages)[i]) {
257 Py_DECREF(item);
258 goto ERROR;
259 }
260
261 Py_DECREF(item);
262 }
263
264 // Success
265 return Py_CLEANUP_SUPPORTED;
266
267 ERROR:
268 if (*packages) {
269 for (char** package = *packages; *package; package++)
270 free(*package);
271 free(*packages);
272 }
273
274 return 0;
275 }
276
277 static PyObject* Pakfire_install(PakfireObject* self, PyObject* args, PyObject* kwargs) {
278 char* kwlist[] = {
279 "packages",
280 "without_recommended",
281 "allow_uninstall",
282 "allow_downgrade",
283 NULL
284 };
285 char** packages = NULL;
286 int without_recommended = 0;
287 int allow_uninstall = 0;
288 int allow_downgrade = 0;
289 int solver_flags = 0;
290
291 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$ppp", kwlist,
292 convert_packages, &packages, &without_recommended, &allow_uninstall,
293 &allow_downgrade))
294 return NULL;
295
296 // Do not install recommended packages
297 if (without_recommended)
298 solver_flags |= PAKFIRE_REQUEST_WITHOUT_RECOMMENDED;
299
300 // Can the solver uninstall packages?
301 if (allow_uninstall)
302 solver_flags |= PAKFIRE_REQUEST_ALLOW_UNINSTALL;
303
304 // Can the solver downgrade packages?
305 if (allow_downgrade)
306 solver_flags |= PAKFIRE_REQUEST_ALLOW_DOWNGRADE;
307
308 // Run pakfire_install
309 int r = pakfire_install(self->pakfire, solver_flags, (const char**)packages, NULL, 0, NULL);
310 if (r)
311 PyErr_SetFromErrno(PyExc_OSError);
312
313 if (packages) {
314 for (char** package = packages; *package; package++)
315 free(*package);
316 free(packages);
317 }
318
319 if (r)
320 return NULL;
321
322 Py_RETURN_NONE;
323 }
324
325 static PyObject* Pakfire_erase(PakfireObject* self, PyObject* args, PyObject* kwargs) {
326 char* kwlist[] = {
327 "packages",
328 "keep_dependencies",
329 NULL
330 };
331 char** packages = NULL;
332 int keep_dependencies = 0;
333 int flags = 0;
334
335 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$p", kwlist,
336 convert_packages, &packages, &keep_dependencies))
337 return NULL;
338
339 if (keep_dependencies)
340 flags |= PAKFIRE_REQUEST_KEEP_DEPS;
341
342 // Run pakfire_erase
343 int r = pakfire_erase(self->pakfire, 0, (const char**)packages, NULL, flags, NULL);
344 if (r)
345 PyErr_SetFromErrno(PyExc_OSError);
346
347 if (packages) {
348 for (char** package = packages; *package; package++)
349 free(*package);
350 free(packages);
351 }
352
353 if (r)
354 return NULL;
355
356 Py_RETURN_NONE;
357 }
358
359 static PyObject* Pakfire_update(PakfireObject* self, PyObject* args, PyObject* kwargs) {
360 char* kwlist[] = {
361 "packages",
362 "excludes",
363 "allow_uninstall",
364 "allow_downgrade",
365 NULL
366 };
367 char** packages = NULL;
368 char** excludes = NULL;
369 int allow_uninstall = 0;
370 int allow_downgrade = 0;
371 int solver_flags = 0;
372
373 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$O&pp", kwlist,
374 convert_packages, &packages, convert_packages, &excludes,
375 &allow_uninstall, &allow_downgrade))
376 return NULL;
377
378 // Can the solver uninstall packages?
379 if (allow_uninstall)
380 solver_flags |= PAKFIRE_REQUEST_ALLOW_UNINSTALL;
381
382 // Can the solver downgrade packages?
383 if (allow_downgrade)
384 solver_flags |= PAKFIRE_REQUEST_ALLOW_DOWNGRADE;
385
386 // Run pakfire_update
387 int r = pakfire_update(self->pakfire, solver_flags, (const char**)packages,
388 (const char**)excludes, 0, NULL);
389 if (r)
390 PyErr_SetFromErrno(PyExc_OSError);
391
392 if (packages) {
393 for (char** package = packages; *package; package++)
394 free(*package);
395 free(packages);
396 }
397
398 if (excludes) {
399 for (char** exclude = excludes; *exclude; exclude++)
400 free(*exclude);
401 free(excludes);
402 }
403
404 if (r)
405 return NULL;
406
407 Py_RETURN_NONE;
408 }
409
410 static PyObject* Pakfire_keys_to_list(struct pakfire_key** keys) {
411 PyObject* list = PyList_New(0);
412
413 // Empty input?
414 if (!keys)
415 return list;
416
417 // Push all keys onto the list
418 for (struct pakfire_key** key = keys; *key; key++) {
419 PyObject* object = new_key(&KeyType, *key);
420 if (!object)
421 goto ERROR;
422
423 PyList_Append(list, object);
424 Py_DECREF(object);
425 }
426
427 return list;
428
429 ERROR:
430 Py_DECREF(list);
431 return NULL;
432 }
433
434 static PyObject* Pakfire_get_keys(PakfireObject* self) {
435 struct pakfire_key** keys = NULL;
436
437 int r = pakfire_list_keys(self->pakfire, &keys);
438 if (r) {
439 PyErr_SetFromErrno(PyExc_OSError);
440 return NULL;
441 }
442
443 // Convert keys to list
444 PyObject* list = Pakfire_keys_to_list(keys);
445
446 // Free keys
447 for (struct pakfire_key** key = keys; *key; key++)
448 pakfire_key_unref(*key);
449 free(keys);
450
451 return list;
452 }
453
454 static PyObject* Pakfire_get_key(PakfireObject* self, PyObject* args) {
455 const char* pattern = NULL;
456
457 if (!PyArg_ParseTuple(args, "s", &pattern))
458 return NULL;
459
460 struct pakfire_key* key = pakfire_key_get(self->pakfire, pattern);
461 if (!key)
462 Py_RETURN_NONE;
463
464 return new_key(&KeyType, key);
465 }
466
467 static PyObject* Pakfire_generate_key(PakfireObject* self, PyObject* args, PyObject* kwds) {
468 char* kwlist[] = { "userid", "algorithm", NULL };
469 struct pakfire_key* key = NULL;
470 const char* userid = NULL;
471 const char* algo = NULL;
472
473 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|$z", kwlist, &userid, &algo))
474 return NULL;
475
476 // Generate a new key
477 int r = pakfire_key_generate(&key, self->pakfire, algo, userid);
478 if (r) {
479 PyErr_SetFromErrno(PyExc_OSError);
480 return NULL;
481 }
482
483 return new_key(&KeyType, key);
484 }
485
486 static PyObject* Pakfire_import_key(PakfireObject* self, PyObject* args) {
487 PyObject* object = NULL;
488
489 if (!PyArg_ParseTuple(args, "O", &object))
490 return NULL;
491
492 // Get a file descriptor from object
493 int fd = PyObject_AsFileDescriptor(object);
494 if (fd < 0)
495 return NULL;
496
497 // Convert to FILE*
498 FILE* f = fdopen(fd, "r");
499 if (!f) {
500 PyErr_SetFromErrno(PyExc_OSError);
501 return NULL;
502 }
503
504 struct pakfire_key** keys = NULL;
505
506 // Import keys from f
507 int r = pakfire_key_import(self->pakfire, f, &keys);
508 if (r) {
509 PyErr_SetFromErrno(PyExc_OSError);
510 return NULL;
511 }
512
513 // Convert keys to list
514 PyObject* list = Pakfire_keys_to_list(keys);
515
516 // Free keys
517 for (struct pakfire_key** key = keys; *key; key++)
518 pakfire_key_unref(*key);
519 free(keys);
520
521 return list;
522 }
523
524 static PyObject* Pakfire_fetch_key(PakfireObject* self, PyObject* args, PyObject* kwds) {
525 char* kwlist[] = { "userid", "fingerprint", NULL };
526 struct pakfire_key* key = NULL;
527 const char* userid = NULL;
528 const char* fingerprint = NULL;
529
530 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$zz", kwlist, &userid, &fingerprint))
531 return NULL;
532
533 // Fetch the key
534 int r = pakfire_key_fetch(&key, self->pakfire, userid, fingerprint);
535 if (r) {
536 PyErr_SetFromErrno(PyExc_OSError);
537 return NULL;
538 }
539
540 // Return the result
541 if (key)
542 return new_key(&KeyType, key);
543
544 Py_RETURN_NONE;
545 }
546
547 static PyObject* Pakfire_whatprovides(PakfireObject* self, PyObject* args) {
548 const char* provides = NULL;
549 struct pakfire_packagelist* list = NULL;
550
551 if (!PyArg_ParseTuple(args, "s", &provides))
552 return NULL;
553
554 int r = pakfire_whatprovides(self->pakfire, provides, 0, &list);
555 if (r) {
556 PyErr_SetFromErrno(PyExc_OSError);
557 return NULL;
558 }
559
560 PyObject* obj = PyList_FromPackageList(list);
561 pakfire_packagelist_unref(list);
562
563 return obj;
564 }
565
566 static PyObject* Pakfire_whatrequires(PakfireObject* self, PyObject* args) {
567 const char* requires = NULL;
568 struct pakfire_packagelist* list = NULL;
569
570 if (!PyArg_ParseTuple(args, "s", &requires))
571 return NULL;
572
573 int r = pakfire_whatrequires(self->pakfire, requires, 0, &list);
574 if (r) {
575 PyErr_SetFromErrno(PyExc_OSError);
576 return NULL;
577 }
578
579 PyObject* obj = PyList_FromPackageList(list);
580 pakfire_packagelist_unref(list);
581
582 return obj;
583 }
584
585 static PyObject* Pakfire_search(PakfireObject* self, PyObject* args, PyObject* kwds) {
586 char* kwlist[] = { "pattern", "name_only", NULL };
587 struct pakfire_packagelist* list = NULL;
588 const char* pattern = NULL;
589 int name_only = 0;
590 int flags = 0;
591
592 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|$p", kwlist, &pattern, &name_only))
593 return NULL;
594
595 // Search for package names only
596 if (name_only)
597 flags |= PAKFIRE_SEARCH_NAME_ONLY;
598
599 int r = pakfire_search(self->pakfire, pattern, flags, &list);
600 if (r) {
601 PyErr_SetFromErrno(PyExc_OSError);
602 return NULL;
603 }
604
605 PyObject* obj = PyList_FromPackageList(list);
606 pakfire_packagelist_unref(list);
607
608 return obj;
609 }
610
611 static PyObject* Pakfire_version_compare(PakfireObject* self, PyObject* args) {
612 const char* evr1 = NULL;
613 const char* evr2 = NULL;
614
615 if (!PyArg_ParseTuple(args, "ss", &evr1, &evr2))
616 return NULL;
617
618 int cmp = pakfire_version_compare(self->pakfire, evr1, evr2);
619
620 return PyLong_FromLong(cmp);
621 }
622
623 static PyObject* Pakfire_execute_logging_callback = NULL;
624
625 static int __Pakfire_execute_logging_callback(Pakfire pakfire, void* data,
626 int priority, const char* line, size_t length) {
627 int r = 0;
628
629 // Do nothing if callback isn't set
630 if (!Pakfire_execute_logging_callback)
631 return 0;
632
633 // Translate priority to Python logging priorities
634 switch (priority) {
635 case LOG_INFO:
636 priority = 20;
637 break;
638
639 case LOG_ERR:
640 priority = 40;
641 break;
642 }
643
644 // Remove the trailing newline
645 if (line && line[length - 1] == '\n')
646 length--;
647
648 // Create tuple with arguments for the callback function
649 PyObject* args = Py_BuildValue("(is#)", priority, line, length);
650 if (!args)
651 return 1;
652
653 PyObject* result = PyObject_CallObject(Pakfire_execute_logging_callback, args);
654 if (result && PyLong_Check(result)) {
655 r = PyLong_AsLong(result);
656 }
657
658 Py_XDECREF(args);
659 Py_XDECREF(result);
660
661 return r;
662 }
663
664 static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject* kwds) {
665 char* kwlist[] = {"command", "environ", "enable_network", "interactive",
666 "logging_callback", NULL};
667
668 PyObject* command = NULL;
669 PyObject* environ = NULL;
670 int enable_network = 0;
671 int interactive = 0;
672 PyObject* logging_callback = NULL;
673
674 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OppO", kwlist, &command, &environ,
675 &enable_network, &interactive, &logging_callback))
676 return NULL;
677
678 // Check if command is a list
679 if (!PyList_Check(command)) {
680 PyErr_SetString(PyExc_TypeError, "command must be a list");
681 return NULL;
682 }
683
684 ssize_t command_length = PyList_Size(command);
685
686 // Check if command is not empty
687 if (command_length == 0) {
688 PyErr_SetString(PyExc_ValueError, "command is empty");
689 return NULL;
690 }
691
692 // All arguments in command must be strings
693 for (unsigned int i = 0; i < command_length; i++) {
694 PyObject* item = PyList_GET_ITEM(command, i);
695
696 if (!PyUnicode_Check(item)) {
697 PyErr_Format(PyExc_TypeError, "Item %u in command is not a string", i);
698 return NULL;
699 }
700 }
701
702 // Check if logging_callback is
703 if (logging_callback && !PyCallable_Check(logging_callback)) {
704 PyErr_SetString(PyExc_TypeError, "logging_callback must be callable\n");
705 return NULL;
706 }
707
708 ssize_t environ_length = 0;
709 PyObject* key;
710 PyObject* value;
711 Py_ssize_t p = 0;
712
713 if (environ) {
714 // Check if environ is a dictionary
715 if (!PyDict_Check(environ)) {
716 PyErr_SetString(PyExc_TypeError, "environ must be a dictionary");
717 return NULL;
718 }
719
720 // All keys and values must be strings
721 while (PyDict_Next(environ, &p, &key, &value)) {
722 if (!PyUnicode_Check(key) || !PyUnicode_Check(value)) {
723 PyErr_SetString(PyExc_TypeError, "Environment contains a non-string object");
724 return NULL;
725 }
726 }
727
728 environ_length = PyDict_Size(environ);
729 }
730
731 // All inputs look fine
732
733 const char* argv[command_length + 1];
734 char* envp[environ_length + 1];
735 int flags = 0;
736
737 // Parse arguments
738 for (unsigned int i = 0; i < command_length; i++) {
739 PyObject* item = PyList_GET_ITEM(command, i);
740 argv[i] = PyUnicode_AsUTF8(item);
741 }
742
743 // Parse environ
744 if (environ) {
745 unsigned int i = 0;
746 p = 0;
747
748 while (PyDict_Next(environ, &p, &key, &value)) {
749 int r = asprintf(&envp[i++], "%s=%s",
750 PyUnicode_AsUTF8(key), PyUnicode_AsUTF8(value));
751
752 // Handle errors
753 if (r < 0) {
754 // Cleanup
755 for (unsigned int i = 0; envp[i]; i++)
756 free(envp[i]);
757
758 return PyErr_NoMemory();
759 }
760 }
761 }
762
763 // Terminate argv and envp
764 argv[command_length] = NULL;
765 envp[environ_length] = NULL;
766
767 // Enable network?
768 if (enable_network)
769 flags |= PAKFIRE_EXECUTE_ENABLE_NETWORK;
770
771 // Interactive?
772 if (interactive)
773 flags |= PAKFIRE_EXECUTE_INTERACTIVE;
774
775 // Set logging callback
776 Pakfire_execute_logging_callback = logging_callback;
777
778 // Execute command
779 int r = pakfire_execute(self->pakfire, argv, envp, flags,
780 (logging_callback) ? __Pakfire_execute_logging_callback : NULL, NULL);
781
782 // Cleanup
783 for (unsigned int i = 0; envp[i]; i++)
784 free(envp[i]);
785
786 // Raise an OS error if r < 0
787 if (r < 0) {
788 errno = -r;
789
790 PyErr_SetFromErrno(PyExc_OSError);
791 return NULL;
792
793 // Raise exception when the command failed
794 } else if (r > 0) {
795 PyObject* code = PyLong_FromLong(r);
796
797 PyErr_SetObject(PyExc_CommandExecutionError, code);
798 Py_DECREF(code);
799
800 return NULL;
801 }
802
803 // Return nothing
804 Py_RETURN_NONE;
805 }
806
807 static PyObject* Pakfire_dist(PakfireObject* self, PyObject* args) {
808 const char* path = NULL;
809 const char* target = NULL;
810
811 if (!PyArg_ParseTuple(args, "s|z", &path, &target))
812 return NULL;
813
814 int r = pakfire_dist(self->pakfire, path, target);
815 if (r) {
816 PyErr_SetFromErrno(PyExc_OSError);
817 return NULL;
818 }
819
820 Py_RETURN_NONE;
821 }
822
823 static PyObject* Pakfire_bind(PakfireObject* self, PyObject* args) {
824 const char* src = NULL;
825 const char* dst = NULL;
826
827 if (!PyArg_ParseTuple(args, "s|z", &src, &dst))
828 return NULL;
829
830 int r = pakfire_bind(self->pakfire, src, dst, 0);
831 if (r) {
832 PyErr_SetFromErrno(PyExc_OSError);
833 return NULL;
834 }
835
836 Py_RETURN_NONE;
837 }
838
839 static PyObject* Pakfire_copy_in(PakfireObject* self, PyObject* args) {
840 const char* src = NULL;
841 const char* dst = NULL;
842
843 if (!PyArg_ParseTuple(args, "ss", &src, &dst))
844 return NULL;
845
846 int r = pakfire_copy_in(self->pakfire, src, dst);
847 if (r) {
848 PyErr_SetFromErrno(PyExc_OSError);
849 return NULL;
850 }
851
852 Py_RETURN_NONE;
853 }
854
855 static PyObject* Pakfire_copy_out(PakfireObject* self, PyObject* args) {
856 const char* src = NULL;
857 const char* dst = NULL;
858
859 if (!PyArg_ParseTuple(args, "ss", &src, &dst))
860 return NULL;
861
862 int r = pakfire_copy_out(self->pakfire, src, dst);
863 if (r) {
864 PyErr_SetFromErrno(PyExc_OSError);
865 return NULL;
866 }
867
868 Py_RETURN_NONE;
869 }
870
871 static PyObject* Pakfire_get_repos(PakfireObject* self) {
872 struct pakfire_repolist* repos = pakfire_get_repos(self->pakfire);
873 if (!repos) {
874 PyErr_SetFromErrno(PyExc_OSError);
875 return NULL;
876 }
877
878 const size_t l = pakfire_repolist_size(repos);
879
880 PyObject* list = PyList_New(l);
881 if (!list)
882 goto ERROR;
883
884 for (unsigned int i = 0; i < l; i++) {
885 struct pakfire_repo* repo = pakfire_repolist_get(repos, i);
886 if (!repo)
887 continue;
888
889 PyObject* obj = new_repo(&RepoType, repo);
890 PyList_SET_ITEM(list, i, obj);
891
892 pakfire_repo_unref(repo);
893 }
894
895 ERROR:
896 pakfire_repolist_unref(repos);
897
898 return list;
899 }
900
901 static PyObject* execute_return_value(int r) {
902 // Raise an OS error if r < 0
903 if (r < 0) {
904 errno = -r;
905
906 PyErr_SetFromErrno(PyExc_OSError);
907 return NULL;
908
909 // Raise exception when the command failed
910 } else if (r > 0) {
911 PyObject* code = PyLong_FromLong(r);
912
913 PyErr_SetObject(PyExc_CommandExecutionError, code);
914 Py_DECREF(code);
915
916 return NULL;
917 }
918
919 Py_RETURN_NONE;
920 }
921
922 static PyObject* Pakfire_build(PakfireObject* self, PyObject* args, PyObject* kwargs) {
923 char* kwlist[] = { "path", "build_id", "logging_callback", "interactive", NULL };
924
925 const char* path = NULL;
926 const char* build_id = NULL;
927 PyObject* logging_callback = NULL;
928 int interactive = 0;
929
930 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zOp", kwlist, &path,
931 &build_id, &logging_callback, &interactive))
932 return NULL;
933
934 int flags = 0;
935
936 // Enable interactive mode
937 if (interactive)
938 flags |= PAKFIRE_BUILD_INTERACTIVE;
939
940 // Check if logging_callback is
941 if (logging_callback && !PyCallable_Check(logging_callback)) {
942 PyErr_SetString(PyExc_TypeError, "logging_callback must be callable\n");
943 return NULL;
944 }
945
946 // Set logging callback
947 Pakfire_execute_logging_callback = logging_callback;
948
949 // Run build
950 int r = pakfire_build(self->pakfire, path, NULL, build_id, flags,
951 (logging_callback) ? __Pakfire_execute_logging_callback : NULL, NULL);
952
953 return execute_return_value(r);
954 }
955
956 static PyObject* Pakfire_shell(PakfireObject* self) {
957 int r = pakfire_shell(self->pakfire);
958
959 return execute_return_value(r);
960 }
961
962 static PyObject* Pakfire_clean(PakfireObject* self) {
963 int r = pakfire_clean(self->pakfire, 0);
964 if (r) {
965 PyErr_SetFromErrno(PyExc_OSError);
966 return NULL;
967 }
968
969 Py_RETURN_NONE;
970 }
971
972 static PyObject* Pakfire_refresh(PakfireObject* self, PyObject* args) {
973 int force = 0;
974
975 if (!PyArg_ParseTuple(args, "|p", &force))
976 return NULL;
977
978 int r = pakfire_refresh(self->pakfire, force);
979 if (r) {
980 PyErr_SetFromErrno(PyExc_OSError);
981 return NULL;
982 }
983
984 Py_RETURN_NONE;
985 }
986
987 static PyObject* Pakfire_check(PakfireObject* self) {
988 int r = pakfire_check(self->pakfire);
989 if (r) {
990 PyErr_SetFromErrno(PyExc_OSError);
991 return NULL;
992 }
993
994 Py_RETURN_NONE;
995 }
996
997 static PyObject* Pakfire_sync(PakfireObject* self, PyObject* args, PyObject* kwargs) {
998 char* kwlist[] = {"keep_orphaned", NULL};
999 int keep_orphaned = 0;
1000 int flags = 0;
1001
1002 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|$p", kwlist, &keep_orphaned))
1003 return NULL;
1004
1005 if (keep_orphaned)
1006 flags |= PAKFIRE_REQUEST_KEEP_ORPHANED;
1007
1008 int r = pakfire_sync(self->pakfire, 0, flags, NULL);
1009 if (r) {
1010 PyErr_SetFromErrno(PyExc_OSError);
1011 return NULL;
1012 }
1013
1014 Py_RETURN_NONE;
1015 }
1016
1017 static PyObject* Pakfire_open(PakfireObject* self, PyObject* args) {
1018 struct pakfire_archive* archive = NULL;
1019 const char* path = NULL;
1020
1021 if (!PyArg_ParseTuple(args, "s", &path))
1022 return NULL;
1023
1024 int r = pakfire_archive_open(&archive, self->pakfire, path);
1025 if (r) {
1026 PyErr_SetFromErrno(PyExc_OSError);
1027 return NULL;
1028 }
1029
1030 // Create Python object
1031 PyObject* object = new_archive(&ArchiveType, archive);
1032 pakfire_archive_unref(archive);
1033
1034 return object;
1035 }
1036
1037 static struct PyMethodDef Pakfire_methods[] = {
1038 {
1039 "bind",
1040 (PyCFunction)Pakfire_bind,
1041 METH_VARARGS,
1042 NULL,
1043 },
1044 {
1045 "build",
1046 (PyCFunction)Pakfire_build,
1047 METH_VARARGS|METH_KEYWORDS,
1048 NULL
1049 },
1050 {
1051 "check",
1052 (PyCFunction)Pakfire_check,
1053 METH_NOARGS,
1054 NULL,
1055 },
1056 {
1057 "clean",
1058 (PyCFunction)Pakfire_clean,
1059 METH_NOARGS,
1060 NULL,
1061 },
1062 {
1063 "copy_in",
1064 (PyCFunction)Pakfire_copy_in,
1065 METH_VARARGS,
1066 NULL,
1067 },
1068 {
1069 "copy_out",
1070 (PyCFunction)Pakfire_copy_out,
1071 METH_VARARGS,
1072 NULL,
1073 },
1074 {
1075 "dist",
1076 (PyCFunction)Pakfire_dist,
1077 METH_VARARGS,
1078 NULL
1079 },
1080 {
1081 "erase",
1082 (PyCFunction)Pakfire_erase,
1083 METH_VARARGS|METH_KEYWORDS,
1084 NULL
1085 },
1086 {
1087 "execute",
1088 (PyCFunction)Pakfire_execute,
1089 METH_VARARGS|METH_KEYWORDS,
1090 NULL
1091 },
1092 {
1093 "fetch_key",
1094 (PyCFunction)Pakfire_fetch_key,
1095 METH_VARARGS|METH_KEYWORDS,
1096 NULL
1097 },
1098 {
1099 "generate_key",
1100 (PyCFunction)Pakfire_generate_key,
1101 METH_VARARGS|METH_KEYWORDS,
1102 NULL
1103 },
1104 {
1105 "get_key",
1106 (PyCFunction)Pakfire_get_key,
1107 METH_VARARGS,
1108 NULL
1109 },
1110 {
1111 "get_repo",
1112 (PyCFunction)Pakfire_get_repo,
1113 METH_VARARGS,
1114 NULL
1115 },
1116 {
1117 "import_key",
1118 (PyCFunction)Pakfire_import_key,
1119 METH_VARARGS,
1120 NULL
1121 },
1122 {
1123 "install",
1124 (PyCFunction)Pakfire_install,
1125 METH_VARARGS|METH_KEYWORDS,
1126 NULL,
1127 },
1128 {
1129 "open",
1130 (PyCFunction)Pakfire_open,
1131 METH_VARARGS,
1132 NULL
1133 },
1134 {
1135 "refresh",
1136 (PyCFunction)Pakfire_refresh,
1137 METH_VARARGS,
1138 NULL,
1139 },
1140 {
1141 "search",
1142 (PyCFunction)Pakfire_search,
1143 METH_VARARGS|METH_KEYWORDS,
1144 NULL
1145 },
1146 {
1147 "shell",
1148 (PyCFunction)Pakfire_shell,
1149 METH_NOARGS,
1150 NULL,
1151 },
1152 {
1153 "sync",
1154 (PyCFunction)Pakfire_sync,
1155 METH_VARARGS|METH_KEYWORDS,
1156 NULL,
1157 },
1158 {
1159 "update",
1160 (PyCFunction)Pakfire_update,
1161 METH_VARARGS|METH_KEYWORDS,
1162 NULL
1163 },
1164 {
1165 "version_compare",
1166 (PyCFunction)Pakfire_version_compare,
1167 METH_VARARGS,
1168 NULL
1169 },
1170 {
1171 "whatprovides",
1172 (PyCFunction)Pakfire_whatprovides,
1173 METH_VARARGS,
1174 NULL
1175 },
1176 {
1177 "whatrequires",
1178 (PyCFunction)Pakfire_whatrequires,
1179 METH_VARARGS,
1180 NULL
1181 },
1182 { NULL },
1183 };
1184
1185 static struct PyGetSetDef Pakfire_getsetters[] = {
1186 {
1187 "arch",
1188 (getter)Pakfire_get_arch,
1189 NULL,
1190 NULL,
1191 NULL
1192 },
1193 {
1194 "keys",
1195 (getter)Pakfire_get_keys,
1196 NULL,
1197 NULL,
1198 NULL
1199 },
1200 {
1201 "path",
1202 (getter)Pakfire_get_path,
1203 NULL,
1204 NULL,
1205 NULL
1206 },
1207 {
1208 "repos",
1209 (getter)Pakfire_get_repos,
1210 NULL,
1211 NULL,
1212 NULL
1213 },
1214 { NULL },
1215 };
1216
1217 PyTypeObject PakfireType = {
1218 PyVarObject_HEAD_INIT(NULL, 0)
1219 tp_name: "_pakfire.Pakfire",
1220 tp_basicsize: sizeof(PakfireObject),
1221 tp_flags: Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
1222 tp_new: Pakfire_new,
1223 tp_dealloc: (destructor)Pakfire_dealloc,
1224 tp_init: (initproc)Pakfire_init,
1225 tp_doc: "Pakfire object",
1226 tp_methods: Pakfire_methods,
1227 tp_getset: Pakfire_getsetters,
1228 tp_repr: (reprfunc)Pakfire_repr,
1229 };