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