]> git.ipfire.org Git - people/ms/pakfire.git/blob - src/_pakfire/pakfire.c
python: Pakfire.execute(): Fix parsing some arguments
[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 "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 goto ERROR;
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 // Set nice
530 if (nice) {
531 r = pakfire_jail_nice(jail, nice);
532 if (r) {
533 PyErr_SetFromErrno(PyExc_OSError);
534 goto ERROR;
535 }
536 }
537
538 PyObject* key = NULL;
539 PyObject* value = NULL;
540 Py_ssize_t p = 0;
541
542 // Parse the environment
543 if (environ) {
544 // Check if environ is a dictionary
545 if (!PyDict_Check(environ)) {
546 PyErr_SetString(PyExc_TypeError, "environ must be a dictionary");
547 goto ERROR;
548 }
549
550 // All keys and values must be strings
551 while (PyDict_Next(environ, &p, &key, &value)) {
552 if (!PyUnicode_Check(key) || !PyUnicode_Check(value)) {
553 PyErr_SetString(PyExc_TypeError, "Environment contains a non-string object");
554 goto ERROR;
555 }
556
557 // Set environment value
558 r = pakfire_jail_set_env(jail, PyUnicode_AsUTF8(key), PyUnicode_AsUTF8(value));
559 if (r) {
560 PyErr_SetFromErrno(PyExc_OSError);
561 goto ERROR;
562 }
563 }
564 }
565
566 // Bind
567 if (bind && PySequence_Check(bind)) {
568 const Py_ssize_t num_bind = PySequence_Length(bind);
569
570 for (unsigned int i = 0; i < num_bind; i++) {
571 PyObject* b = PySequence_ITEM(bind, i);
572 if (!b)
573 goto ERROR;
574
575 // Check if this is a Unicode object
576 if (!PyUnicode_Check(b)) {
577 PyErr_SetString(PyExc_ValueError, "bind contains a non-Unicode object");
578 Py_DECREF(b);
579 goto ERROR;
580 }
581
582 const char* path = PyUnicode_AsUTF8(b);
583
584 // Perform bind
585 r = pakfire_jail_bind(jail, path, path, 0);
586 if (r) {
587 PyErr_SetFromErrno(PyExc_OSError);
588 Py_DECREF(b);
589 goto ERROR;
590 }
591
592 Py_DECREF(b);
593 }
594 }
595
596 Py_BEGIN_ALLOW_THREADS
597
598 // Set callback
599 pakfire_jail_set_stdout_callback(jail, Pakfire_execute_output_callback, callback);
600
601 // Execute command
602 r = pakfire_jail_exec(jail, argv, 0);
603
604 Py_END_ALLOW_THREADS
605
606 // If the return code was negative, we had some internal error
607 if (r < 0) {
608 PyErr_SetFromErrno(PyExc_OSError);
609 goto ERROR;
610
611 // Otherwise the executed command returned some error code
612 } else if (r > 0) {
613 PyObject* code = PyLong_FromLong(r);
614
615 // Raise CommandExecutionError
616 PyErr_SetObject(PyExc_CommandExecutionError, code);
617 Py_DECREF(code);
618
619 goto ERROR;
620 }
621
622 // The process has exited successfully
623
624 // Return None
625 ret = Py_None;
626 Py_INCREF(ret);
627
628 ERROR:
629 if (argv)
630 free(argv);
631 if (jail)
632 pakfire_jail_unref(jail);
633
634 return ret;
635 }
636
637 static PyObject* Pakfire_dist(PakfireObject* self, PyObject* args) {
638 const char* path = NULL;
639 const char* target = NULL;
640 char* result = NULL;
641 int r;
642
643 if (!PyArg_ParseTuple(args, "s|z", &path, &target))
644 return NULL;
645
646 Py_BEGIN_ALLOW_THREADS
647
648 r = pakfire_dist(self->pakfire, path, target, &result);
649 if (r) {
650 Py_BLOCK_THREADS
651 PyErr_SetFromErrno(PyExc_OSError);
652 return NULL;
653 }
654
655 Py_END_ALLOW_THREADS
656
657 PyObject* ret = PyUnicode_FromString(result);
658 free(result);
659
660 return ret;
661 }
662
663 static PyObject* Pakfire_get_repos(PakfireObject* self) {
664 struct pakfire_repolist* repos = pakfire_get_repos(self->pakfire);
665 if (!repos) {
666 PyErr_SetFromErrno(PyExc_OSError);
667 return NULL;
668 }
669
670 const size_t l = pakfire_repolist_size(repos);
671
672 PyObject* list = PyList_New(l);
673 if (!list)
674 goto ERROR;
675
676 for (unsigned int i = 0; i < l; i++) {
677 struct pakfire_repo* repo = pakfire_repolist_get(repos, i);
678 if (!repo)
679 continue;
680
681 PyObject* obj = new_repo(&RepoType, repo);
682 PyList_SET_ITEM(list, i, obj);
683
684 pakfire_repo_unref(repo);
685 }
686
687 ERROR:
688 pakfire_repolist_unref(repos);
689
690 return list;
691 }
692
693 static PyObject* execute_return_value(int r) {
694 // Raise an OS error if r < 0
695 if (r < 0) {
696 errno = -r;
697
698 PyErr_SetFromErrno(PyExc_OSError);
699 return NULL;
700
701 // Raise exception when the command failed
702 } else if (r > 0) {
703 PyObject* code = PyLong_FromLong(r);
704
705 PyErr_SetObject(PyExc_CommandExecutionError, code);
706 Py_DECREF(code);
707
708 return NULL;
709 }
710
711 Py_RETURN_NONE;
712 }
713
714 static PyObject* Pakfire_build(PakfireObject* self, PyObject* args, PyObject* kwargs) {
715 char* kwlist[] = {
716 "path",
717 "target",
718 "build_id",
719 "ccache_path",
720 "interactive",
721 "disable_snapshot",
722 "disable_ccache",
723 "disable_tests",
724 NULL,
725 };
726 struct pakfire_build* build = NULL;
727 const char* path = NULL;
728 const char* target = NULL;
729 const char* build_id = NULL;
730 const char* ccache_path = NULL;
731 int interactive = 0;
732 int disable_snapshot = 0;
733 int disable_ccache = 0;
734 int disable_tests = 0;
735 int r;
736
737 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zzzpppp", kwlist,
738 &path, &target, &build_id, &ccache_path, &interactive,
739 &disable_snapshot, &disable_ccache, &disable_tests))
740 return NULL;
741
742 int flags = 0;
743
744 if (interactive)
745 flags |= PAKFIRE_BUILD_INTERACTIVE;
746
747 // Disable snapshot if requested
748 if (disable_snapshot)
749 flags |= PAKFIRE_BUILD_DISABLE_SNAPSHOT;
750
751 // Disable ccache if requested
752 if (disable_ccache)
753 flags |= PAKFIRE_BUILD_DISABLE_CCACHE;
754
755 // Disable tests if requested
756 if (disable_tests)
757 flags |= PAKFIRE_BUILD_DISABLE_TESTS;
758
759 // Create a new build environment
760 r = pakfire_build_create(&build, self->pakfire, build_id, flags);
761 if (r) {
762 PyErr_SetFromErrno(PyExc_OSError);
763 goto ERROR;
764 }
765
766 // Set target
767 if (target) {
768 r = pakfire_build_set_target(build, target);
769 if (r) {
770 PyErr_SetFromErrno(PyExc_OSError);
771 goto ERROR;
772 }
773 }
774
775 // Set ccache path
776 if (ccache_path) {
777 r = pakfire_build_set_ccache_path(build, ccache_path);
778 if (r) {
779 PyErr_SetFromErrno(PyExc_OSError);
780 goto ERROR;
781 }
782 }
783
784 Py_BEGIN_ALLOW_THREADS
785
786 // Run build
787 r = pakfire_build_exec(build, path);
788 if (r) {
789 Py_BLOCK_THREADS;
790
791 if (r < 0) {
792 PyErr_SetFromErrno(PyExc_OSError);
793
794 // Raise a command execution error
795 } else {
796 PyObject* code = PyLong_FromLong(r);
797
798 PyErr_SetObject(PyExc_CommandExecutionError, code);
799 Py_DECREF(code);
800 }
801
802 goto ERROR;
803 }
804
805 Py_END_ALLOW_THREADS
806
807 ERROR:
808 if (build)
809 pakfire_build_unref(build);
810
811 if (r)
812 return NULL;
813
814 Py_RETURN_NONE;
815 }
816
817 static PyObject* Pakfire_shell(PakfireObject* self, PyObject* args, PyObject* kwargs) {
818 char* kwlist[] = {
819 "install",
820 "disable_snapshot",
821 NULL,
822 };
823 char** packages = NULL;
824 int disable_snapshot = 0;
825 int r;
826
827 // Parse everything
828 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&p", kwlist,
829 convert_packages, &packages, &disable_snapshot))
830 return NULL;
831
832 int flags = 0;
833
834 if (disable_snapshot)
835 flags |= PAKFIRE_BUILD_DISABLE_SNAPSHOT;
836
837 Py_BEGIN_ALLOW_THREADS
838
839 r = pakfire_shell(self->pakfire, (const char**)packages, flags);
840
841 Py_END_ALLOW_THREADS
842
843 return execute_return_value(r);
844 }
845
846 static PyObject* Pakfire_clean(PakfireObject* self) {
847 int r;
848
849 Py_BEGIN_ALLOW_THREADS
850
851 r = pakfire_clean(self->pakfire, 0);
852 if (r) {
853 Py_BLOCK_THREADS
854 PyErr_SetFromErrno(PyExc_OSError);
855 return NULL;
856 }
857
858 Py_END_ALLOW_THREADS
859
860 Py_RETURN_NONE;
861 }
862
863 static PyObject* Pakfire_refresh(PakfireObject* self, PyObject* args) {
864 int force = 0;
865 int r;
866
867 if (!PyArg_ParseTuple(args, "|p", &force))
868 return NULL;
869
870 Py_BEGIN_ALLOW_THREADS
871
872 r = pakfire_refresh(self->pakfire, force);
873 if (r) {
874 Py_BLOCK_THREADS
875 PyErr_SetFromErrno(PyExc_OSError);
876 return NULL;
877 }
878
879 Py_END_ALLOW_THREADS
880
881 Py_RETURN_NONE;
882 }
883
884 static PyObject* Pakfire_open(PakfireObject* self, PyObject* args) {
885 struct pakfire_archive* archive = NULL;
886 const char* path = NULL;
887
888 if (!PyArg_ParseTuple(args, "s", &path))
889 return NULL;
890
891 Py_BEGIN_ALLOW_THREADS
892
893 int r = pakfire_archive_open(&archive, self->pakfire, path);
894 if (r) {
895 Py_BLOCK_THREADS
896 PyErr_SetFromErrno(PyExc_OSError);
897 return NULL;
898 }
899
900 Py_END_ALLOW_THREADS
901
902 // Create Python object
903 PyObject* object = new_archive(&ArchiveType, archive);
904 pakfire_archive_unref(archive);
905
906 return object;
907 }
908
909 static PyObject* Pakfire_repo_compose(PakfireObject* self, PyObject* args, PyObject* kwargs) {
910 char* kwlist[] = { "path", "files", "key", NULL };
911 const char* path = NULL;
912 PyObject* list = NULL;
913 KeyObject* key = NULL;
914
915 PyObject* ret = NULL;
916
917 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|O!", kwlist, &path, &list, &KeyType, &key))
918 return NULL;
919
920 // List must be a sequence
921 if (!PySequence_Check(list)) {
922 PyErr_SetString(PyExc_ValueError, "Expected a sequence.");
923 return NULL;
924 }
925
926 // How many new files do we have?
927 ssize_t num_files = PySequence_Length(list);
928 if (num_files < 0)
929 return NULL;
930
931 // Allocate files array
932 const char** files = calloc(num_files + 1, sizeof(*files));
933 if (!files) {
934 PyErr_SetFromErrno(PyExc_OSError);
935 return NULL;
936 }
937
938 for (int i = 0; i < num_files; i++) {
939 PyObject* file = PySequence_GetItem(list, i);
940 if (!file)
941 goto ERROR;
942
943 // Check if file is a Unicode object
944 if (!PyUnicode_Check(file)) {
945 PyErr_SetString(PyExc_ValueError, "Expected a string.");
946 goto ERROR;
947 }
948
949 // Add pointer to string to files array
950 files[i] = PyUnicode_AsUTF8(file);
951 if (!files[i])
952 goto ERROR;
953
954 Py_DECREF(file);
955 }
956
957 Py_BEGIN_ALLOW_THREADS
958
959 int r = pakfire_repo_compose(self->pakfire, path, (key) ? key->key : NULL, files);
960 if (r) {
961 Py_BLOCK_THREADS
962 PyErr_SetFromErrno(PyExc_OSError);
963 return NULL;
964 }
965
966 Py_END_ALLOW_THREADS
967
968 // Return None on success
969 ret = Py_None;
970 Py_INCREF(ret);
971
972 ERROR:
973 if (files)
974 free(files);
975
976 return ret;
977 }
978
979 static PyObject* Pakfire_mkimage(PakfireObject* self, PyObject* args, PyObject* kwargs) {
980 char* kwlist[] = {
981 "type",
982 "path",
983 NULL,
984 };
985 struct pakfire_build* build = NULL;
986 const char* type = NULL;
987 PyObject* file = NULL;
988 FILE* f = NULL;
989 int r;
990
991 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO", kwlist, &type, &file))
992 return NULL;
993
994 // Make a file handle out of file
995 f = PyObject_AsFileHandle(file, "w");
996 if (!f)
997 return NULL;
998
999 // Create a new build environment
1000 r = pakfire_build_create(&build, self->pakfire, NULL, 0);
1001 if (r) {
1002 PyErr_SetFromErrno(PyExc_OSError);
1003 goto ERROR;
1004 }
1005
1006 Py_BEGIN_ALLOW_THREADS
1007
1008 // Run mkimage
1009 r = pakfire_build_mkimage(build, type, f);
1010 if (r) {
1011 Py_BLOCK_THREADS;
1012
1013 if (r < 0)
1014 PyErr_SetFromErrno(PyExc_OSError);
1015
1016 goto ERROR;
1017 }
1018
1019 Py_END_ALLOW_THREADS
1020
1021 ERROR:
1022 if (build)
1023 pakfire_build_unref(build);
1024 if (f)
1025 fclose(f);
1026 if (r)
1027 return NULL;
1028
1029 Py_RETURN_NONE;
1030 }
1031
1032 static struct PyMethodDef Pakfire_methods[] = {
1033 {
1034 "build",
1035 (PyCFunction)Pakfire_build,
1036 METH_VARARGS|METH_KEYWORDS,
1037 NULL
1038 },
1039 {
1040 "clean",
1041 (PyCFunction)Pakfire_clean,
1042 METH_NOARGS,
1043 NULL,
1044 },
1045 {
1046 "dist",
1047 (PyCFunction)Pakfire_dist,
1048 METH_VARARGS,
1049 NULL
1050 },
1051 {
1052 "execute",
1053 (PyCFunction)Pakfire_execute,
1054 METH_VARARGS|METH_KEYWORDS,
1055 NULL
1056 },
1057 {
1058 "generate_key",
1059 (PyCFunction)Pakfire_generate_key,
1060 METH_VARARGS|METH_KEYWORDS,
1061 NULL
1062 },
1063 {
1064 "get_repo",
1065 (PyCFunction)Pakfire_get_repo,
1066 METH_VARARGS,
1067 NULL
1068 },
1069 {
1070 "import_key",
1071 (PyCFunction)Pakfire_import_key,
1072 METH_VARARGS,
1073 NULL,
1074 },
1075 {
1076 "mkimage",
1077 (PyCFunction)Pakfire_mkimage,
1078 METH_VARARGS|METH_KEYWORDS,
1079 NULL
1080 },
1081 {
1082 "open",
1083 (PyCFunction)Pakfire_open,
1084 METH_VARARGS,
1085 NULL
1086 },
1087 {
1088 "refresh",
1089 (PyCFunction)Pakfire_refresh,
1090 METH_VARARGS,
1091 NULL,
1092 },
1093 {
1094 "repo_compose",
1095 (PyCFunction)Pakfire_repo_compose,
1096 METH_VARARGS|METH_KEYWORDS,
1097 NULL
1098 },
1099 {
1100 "search",
1101 (PyCFunction)Pakfire_search,
1102 METH_VARARGS|METH_KEYWORDS,
1103 NULL
1104 },
1105 {
1106 "shell",
1107 (PyCFunction)Pakfire_shell,
1108 METH_VARARGS|METH_KEYWORDS,
1109 NULL,
1110 },
1111 {
1112 "version_compare",
1113 (PyCFunction)Pakfire_version_compare,
1114 METH_VARARGS,
1115 NULL
1116 },
1117 {
1118 "whatprovides",
1119 (PyCFunction)Pakfire_whatprovides,
1120 METH_VARARGS,
1121 NULL
1122 },
1123 {
1124 "whatrequires",
1125 (PyCFunction)Pakfire_whatrequires,
1126 METH_VARARGS,
1127 NULL
1128 },
1129 { NULL },
1130 };
1131
1132 static struct PyGetSetDef Pakfire_getsetters[] = {
1133 {
1134 "arch",
1135 (getter)Pakfire_get_arch,
1136 NULL,
1137 NULL,
1138 NULL
1139 },
1140 {
1141 "path",
1142 (getter)Pakfire_get_path,
1143 NULL,
1144 NULL,
1145 NULL
1146 },
1147 {
1148 "repos",
1149 (getter)Pakfire_get_repos,
1150 NULL,
1151 NULL,
1152 NULL
1153 },
1154 { NULL },
1155 };
1156
1157 PyTypeObject PakfireType = {
1158 PyVarObject_HEAD_INIT(NULL, 0)
1159 tp_name: "_pakfire.Pakfire",
1160 tp_basicsize: sizeof(PakfireObject),
1161 tp_flags: Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
1162 tp_new: Pakfire_new,
1163 tp_dealloc: (destructor)Pakfire_dealloc,
1164 tp_init: (initproc)Pakfire_init,
1165 tp_doc: "Pakfire object",
1166 tp_methods: Pakfire_methods,
1167 tp_getset: Pakfire_getsetters,
1168 tp_repr: (reprfunc)Pakfire_repr,
1169 };