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