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