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