]> git.ipfire.org Git - people/ms/pakfire.git/blob - src/_pakfire/pakfire.c
_pakfire: Correctly handle it no configuration was given
[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
25 #include <pakfire/archive.h>
26 #include <pakfire/build.h>
27 #include <pakfire/constants.h>
28 #include <pakfire/dist.h>
29 #include <pakfire/jail.h>
30 #include <pakfire/logging.h>
31 #include <pakfire/mount.h>
32 #include <pakfire/packagelist.h>
33 #include <pakfire/pakfire.h>
34 #include <pakfire/key.h>
35 #include <pakfire/repo.h>
36 #include <pakfire/repolist.h>
37 #include <pakfire/request.h>
38 #include <pakfire/transaction.h>
39 #include <pakfire/util.h>
40
41 #include "archive.h"
42 #include "errors.h"
43 #include "key.h"
44 #include "pakfire.h"
45 #include "repo.h"
46 #include "util.h"
47
48 static PyObject* Pakfire_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
49 PakfireObject* self = (PakfireObject *)type->tp_alloc(type, 0);
50 if (self) {
51 self->pakfire = NULL;
52
53 // Callbacks
54 self->callbacks.log = NULL;
55 self->callbacks.confirm = NULL;
56 }
57
58 return (PyObject *)self;
59 }
60
61 static void Pakfire_log_callback(void* data, int priority, const char* file, int line,
62 const char* fn, const char* format, va_list args) {
63 PyObject* callback = (PyObject*)data;
64 PyObject* exception = NULL;
65 PyObject* type = NULL;
66 PyObject* value = NULL;
67 PyObject* traceback = NULL;
68
69 // Do nothing if callback isn't set
70 if (!callback)
71 return;
72
73 PyGILState_STATE state = PyGILState_Ensure();
74
75 // Translate priority to Python logging priorities
76 switch (priority) {
77 case LOG_DEBUG:
78 priority = 10;
79 break;
80
81 case LOG_INFO:
82 priority = 20;
83 break;
84
85 case LOG_ERR:
86 priority = 40;
87 break;
88
89 // Drop messages of an unknown priority
90 default:
91 return;
92 }
93
94 PyObject* tuple = NULL;
95 PyObject* result = NULL;
96 char* buffer = NULL;
97
98 // Make line
99 int r = vasprintf(&buffer, format, args);
100 if (r < 0)
101 goto ERROR;
102
103 // Build a tuple with the priority and the log message
104 tuple = Py_BuildValue("(is)", priority, buffer);
105 if (!tuple)
106 goto ERROR;
107
108 // Call the callback
109 result = PyObject_CallObject(callback, tuple);
110
111 ERROR:
112 /*
113 We cannot really catch any Python errors here, since we cannot send
114 any error codes up the chain.
115
116 So, in order to debug the problem, We will check if an exception has
117 occurred and if so, print it to the console.
118 */
119 exception = PyErr_Occurred();
120 if (exception) {
121 PyErr_Print();
122
123 // Fetch the exception and destroy it
124 PyErr_Fetch(&type, &value, &traceback);
125
126 Py_XDECREF(type);
127 Py_XDECREF(value);
128 Py_XDECREF(traceback);
129 }
130
131 if (buffer)
132 free(buffer);
133 Py_XDECREF(tuple);
134 Py_XDECREF(result);
135
136 // Release the GIL
137 PyGILState_Release(state);
138 }
139
140 static int Pakfire_confirm_callback(struct pakfire* pakfire, void* data,
141 const char* message, const char* question) {
142 PyObject* callback = (PyObject*)data;
143 PyObject* result = NULL;
144 int r = 0;
145
146 // Do nothing if callback isn't set
147 if (!callback)
148 return 0;
149
150 // Acquire GIL
151 PyGILState_STATE state = PyGILState_Ensure();
152
153 PyObject* args = Py_BuildValue("(ss)", message, question);
154 if (!args) {
155 r = -1;
156 goto ERROR;
157 }
158
159 result = PyObject_CallObject(callback, args);
160
161 // If the callback raised an exception, we will ignore it and indicate
162 // that an error happened, but we cannot re-raise the exception
163 if (!result) {
164 r = -1;
165 goto ERROR;
166 }
167
168 // Set the return code
169 if (result == Py_True)
170 r = 0;
171 else
172 r = 1;
173
174 ERROR:
175 Py_DECREF(args);
176 Py_DECREF(result);
177
178 // Release the GIL
179 PyGILState_Release(state);
180
181 return r;
182 }
183
184 static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) {
185 char* kwlist[] = {
186 "path",
187 "arch",
188 "logger",
189 "offline",
190 "conf",
191 "confirm_callback",
192 NULL,
193 };
194 const char* path = NULL;
195 const char* arch = NULL;
196 PyObject* conf = Py_None;
197 int offline = 0;
198 int r = 1;
199
200 FILE* fconf = NULL;
201
202 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzOpOO", kwlist,
203 &path, &arch, &self->callbacks.log, &offline, &conf, &self->callbacks.confirm))
204 goto ERROR;
205
206 // Check if log callback is callable
207 if (self->callbacks.log && !PyCallable_Check(self->callbacks.log)) {
208 PyErr_SetString(PyExc_TypeError, "logger must be callable\n");
209 goto ERROR;
210 }
211
212 // Check if confirm callback is callable
213 if (self->callbacks.confirm && !PyCallable_Check(self->callbacks.confirm)) {
214 PyErr_SetString(PyExc_TypeError, "Confirm callback is not callable");
215 goto ERROR;
216 }
217
218 // Map the configuration
219 if (conf != Py_None) {
220 fconf = PyObject_AsFileHandle(conf, "r");
221 if (!fconf)
222 goto ERROR;
223 }
224
225 int flags = 0;
226
227 // Enable offline mode
228 if (offline)
229 flags |= PAKFIRE_FLAGS_OFFLINE;
230
231 // Configure callbacks
232 if (self->callbacks.log)
233 Py_INCREF(self->callbacks.log);
234
235 Py_BEGIN_ALLOW_THREADS
236
237 // Create a new Pakfire instance
238 r = pakfire_create(&self->pakfire, path, arch, fconf, flags,
239 LOG_DEBUG, Pakfire_log_callback, self->callbacks.log);
240
241 Py_END_ALLOW_THREADS
242
243 if (r < 0) {
244 errno = -r;
245
246 switch (errno) {
247 // Invalid architecture or path
248 case EINVAL:
249 PyErr_SetString(PyExc_ValueError, "Invalid architecture or path");
250 break;
251
252 // Anything else
253 default:
254 PyErr_SetFromErrno(PyExc_OSError);
255 }
256
257 r = -1;
258 goto ERROR;
259 }
260
261 // Configure confirm callback
262 if (self->callbacks.confirm) {
263 pakfire_set_confirm_callback(self->pakfire,
264 Pakfire_confirm_callback, self->callbacks.confirm);
265
266 Py_INCREF(self->callbacks.confirm);
267 }
268
269 ERROR:
270 if (fconf)
271 fclose(fconf);
272
273 return -r;
274 }
275
276 static void Pakfire_dealloc(PakfireObject* self) {
277 if (self->pakfire) {
278 // Reset log callback
279 if (self->callbacks.log) {
280 pakfire_set_log_callback(self->pakfire, NULL, NULL);
281 Py_DECREF(self->callbacks.log);
282 }
283
284 // Reset confirm callback
285 if (self->callbacks.confirm) {
286 pakfire_set_confirm_callback(self->pakfire, NULL, NULL);
287 Py_DECREF(self->callbacks.confirm);
288 }
289
290 Py_BEGIN_ALLOW_THREADS
291
292 pakfire_unref(self->pakfire);
293
294 Py_END_ALLOW_THREADS
295 }
296
297 Py_TYPE(self)->tp_free((PyObject *)self);
298 }
299
300 static PyObject* Pakfire_repr(PakfireObject* self) {
301 const char* path = pakfire_get_path(self->pakfire);
302 const char* arch = pakfire_get_arch(self->pakfire);
303
304 return PyUnicode_FromFormat("<_pakfire.Pakfire %s (%s)>", path, arch);
305 }
306
307 static PyObject* Pakfire_get_path(PakfireObject* self) {
308 const char* path = pakfire_get_path(self->pakfire);
309
310 return PyUnicode_FromString(path);
311 }
312
313 static PyObject* Pakfire_get_arch(PakfireObject* self) {
314 const char* arch = pakfire_get_arch(self->pakfire);
315
316 return PyUnicode_FromString(arch);
317 }
318
319 static PyObject* Pakfire_get_repo(PakfireObject* self, PyObject* args) {
320 const char* name = NULL;
321
322 if (!PyArg_ParseTuple(args, "s", &name))
323 return NULL;
324
325 struct pakfire_repo* repo = pakfire_get_repo(self->pakfire, name);
326 if (!repo)
327 Py_RETURN_NONE;
328
329 PyObject* obj = new_repo(&RepoType, repo);
330 pakfire_repo_unref(repo);
331
332 return obj;
333 }
334
335 static void Pakfire_status_callback(struct pakfire* pakfire, void* data,
336 int progress, const char* status) {
337 PyObject* callback = (PyObject*)data;
338
339 // Do not attempt to call nothing
340 if (!callback)
341 return;
342
343 // Acquire GIL
344 PyGILState_STATE state = PyGILState_Ensure();
345
346 // Compile arguments
347 PyObject* args = Py_BuildValue("(is)", progress, status);
348 if (args) {
349 // Call the callback
350 PyObject* result = PyObject_CallObject(callback, args);
351
352 Py_XDECREF(result);
353 Py_DECREF(args);
354 }
355
356 // Release the GIL
357 PyGILState_Release(state);
358 }
359
360 static int convert_packages(PyObject* object, void* address) {
361 char*** packages = (char***)address;
362
363 // Called for cleanup
364 if (!object)
365 goto ERROR;
366
367 // Nothing to do when object is None
368 if (object == Py_None)
369 return Py_CLEANUP_SUPPORTED;
370
371 if (!PySequence_Check(object)) {
372 PyErr_SetString(PyExc_ValueError, "Packages must be a sequence");
373 goto ERROR;
374 }
375
376 const unsigned int length = PySequence_Length(object);
377 if (!length)
378 return Py_CLEANUP_SUPPORTED;
379
380 // Allocate array
381 *packages = calloc(length + 1, sizeof(*packages));
382 if (!*packages) {
383 PyErr_SetFromErrno(PyExc_OSError);
384 goto ERROR;
385 }
386
387 for (unsigned int i = 0; i < length; i++) {
388 PyObject* item = PySequence_GetItem(object, i);
389
390 // Check if input is a string
391 if (!PyUnicode_Check(item)) {
392 Py_DECREF(item);
393
394 PyErr_SetString(PyExc_AttributeError, "Expected a string");
395 goto ERROR;
396 }
397
398 // Fetch string
399 const char* package = PyUnicode_AsUTF8(item);
400 if (!package) {
401 Py_DECREF(item);
402 goto ERROR;
403 }
404
405 // Add package to array
406 (*packages)[i] = strdup(package);
407 if (!(*packages)[i]) {
408 Py_DECREF(item);
409 goto ERROR;
410 }
411
412 Py_DECREF(item);
413 }
414
415 // Success
416 return Py_CLEANUP_SUPPORTED;
417
418 ERROR:
419 if (*packages) {
420 for (char** package = *packages; *package; package++)
421 free(*package);
422 free(*packages);
423 }
424
425 return 0;
426 }
427
428 static PyObject* Pakfire_install(PakfireObject* self, PyObject* args, PyObject* kwargs) {
429 char* kwlist[] = {
430 "packages",
431 "dryrun",
432 "without_recommended",
433 "allow_uninstall",
434 "allow_downgrade",
435 "status_callback",
436 NULL
437 };
438 char** packages = NULL;
439 int dryrun = 0;
440 int without_recommended = 0;
441 int allow_uninstall = 0;
442 int allow_downgrade = 0;
443 int solver_flags = 0;
444 int transaction_flags = 0;
445 PyObject* status_callback = NULL;
446 int r;
447
448 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$ppppO", kwlist,
449 convert_packages, &packages, &dryrun, &without_recommended, &allow_uninstall,
450 &allow_downgrade, &status_callback))
451 return NULL;
452
453 // Check if callback is callable
454 if (status_callback && !PyCallable_Check(status_callback)) {
455 PyErr_SetString(PyExc_TypeError, "status_callback must be callable");
456 return NULL;
457 }
458
459 // Enable dry-run mode
460 if (dryrun)
461 transaction_flags |= PAKFIRE_TRANSACTION_DRY_RUN;
462
463 // Do not install recommended packages
464 if (without_recommended)
465 solver_flags |= PAKFIRE_REQUEST_WITHOUT_RECOMMENDED;
466
467 // Can the solver uninstall packages?
468 if (allow_uninstall)
469 solver_flags |= PAKFIRE_REQUEST_ALLOW_UNINSTALL;
470
471 // Can the solver downgrade packages?
472 if (allow_downgrade)
473 solver_flags |= PAKFIRE_REQUEST_ALLOW_DOWNGRADE;
474
475 Py_BEGIN_ALLOW_THREADS
476
477 // Run pakfire_install
478 r = pakfire_install(self->pakfire, transaction_flags, solver_flags,
479 (const char**)packages, NULL, 0, NULL, Pakfire_status_callback, status_callback);
480
481 Py_END_ALLOW_THREADS
482
483 if (r)
484 PyErr_SetFromErrno(PyExc_OSError);
485
486 if (packages) {
487 for (char** package = packages; *package; package++)
488 free(*package);
489 free(packages);
490 }
491
492 if (r)
493 return NULL;
494
495 Py_RETURN_NONE;
496 }
497
498 static PyObject* Pakfire_erase(PakfireObject* self, PyObject* args, PyObject* kwargs) {
499 char* kwlist[] = {
500 "packages",
501 "dryrun",
502 "keep_dependencies",
503 "status_callback",
504 NULL
505 };
506 char** packages = NULL;
507 int dryrun = 0;
508 int keep_dependencies = 0;
509 int transaction_flags = 0;
510 int flags = 0;
511 PyObject* status_callback = NULL;
512 int r;
513
514 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$ppO", kwlist,
515 convert_packages, &packages, &dryrun, &keep_dependencies, &status_callback))
516 return NULL;
517
518 // Check if callback is callable
519 if (status_callback && !PyCallable_Check(status_callback)) {
520 PyErr_SetString(PyExc_TypeError, "status_callback must be callable");
521 return NULL;
522 }
523
524 if (dryrun)
525 transaction_flags |= PAKFIRE_TRANSACTION_DRY_RUN;
526
527 if (keep_dependencies)
528 flags |= PAKFIRE_REQUEST_KEEP_DEPS;
529
530 Py_BEGIN_ALLOW_THREADS
531
532 // Run pakfire_erase
533 r = pakfire_erase(self->pakfire, transaction_flags, 0, (const char**)packages,
534 NULL, flags, NULL, Pakfire_status_callback, status_callback);
535
536 Py_END_ALLOW_THREADS
537
538 if (r)
539 PyErr_SetFromErrno(PyExc_OSError);
540
541 if (packages) {
542 for (char** package = packages; *package; package++)
543 free(*package);
544 free(packages);
545 }
546
547 if (r)
548 return NULL;
549
550 Py_RETURN_NONE;
551 }
552
553 static PyObject* Pakfire_update(PakfireObject* self, PyObject* args, PyObject* kwargs) {
554 char* kwlist[] = {
555 "packages",
556 "dryrun",
557 "excludes",
558 "allow_uninstall",
559 "allow_downgrade",
560 "status_callback",
561 NULL
562 };
563 char** packages = NULL;
564 char** excludes = NULL;
565 int dryrun = 0;
566 int allow_uninstall = 0;
567 int allow_downgrade = 0;
568 int solver_flags = 0;
569 int transaction_flags = 0;
570 PyObject* status_callback = NULL;
571 int r;
572
573 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$pO&ppO", kwlist,
574 convert_packages, &packages, &dryrun, convert_packages, &excludes,
575 &allow_uninstall, &allow_downgrade, &status_callback))
576 return NULL;
577
578 // Check if callback is callable
579 if (status_callback && !PyCallable_Check(status_callback)) {
580 PyErr_SetString(PyExc_TypeError, "status_callback must be callable");
581 return NULL;
582 }
583
584 if (dryrun)
585 transaction_flags = PAKFIRE_TRANSACTION_DRY_RUN;
586
587 // Can the solver uninstall packages?
588 if (allow_uninstall)
589 solver_flags |= PAKFIRE_REQUEST_ALLOW_UNINSTALL;
590
591 // Can the solver downgrade packages?
592 if (allow_downgrade)
593 solver_flags |= PAKFIRE_REQUEST_ALLOW_DOWNGRADE;
594
595 Py_BEGIN_ALLOW_THREADS
596
597 // Run pakfire_update
598 r = pakfire_update(self->pakfire, transaction_flags, solver_flags,
599 (const char**)packages, (const char**)excludes, 0, NULL,
600 Pakfire_status_callback, status_callback);
601
602 Py_END_ALLOW_THREADS
603
604 if (r)
605 PyErr_SetFromErrno(PyExc_OSError);
606
607 if (packages) {
608 for (char** package = packages; *package; package++)
609 free(*package);
610 free(packages);
611 }
612
613 if (excludes) {
614 for (char** exclude = excludes; *exclude; exclude++)
615 free(*exclude);
616 free(excludes);
617 }
618
619 if (r)
620 return NULL;
621
622 Py_RETURN_NONE;
623 }
624
625 static PyObject* Pakfire_generate_key(PakfireObject* self, PyObject* args, PyObject* kwds) {
626 char* kwlist[] = { "algorithm", "comment", NULL };
627 struct pakfire_key* key = NULL;
628 pakfire_key_algo_t algo = PAKFIRE_KEY_ALGO_NULL;
629 const char* comment = NULL;
630
631 if (!PyArg_ParseTupleAndKeywords(args, kwds, "is", kwlist, &algo, &comment))
632 return NULL;
633
634 // Generate a new key
635 int r = pakfire_key_generate(&key, self->pakfire, algo, comment);
636 if (r) {
637 PyErr_SetFromErrno(PyExc_OSError);
638 return NULL;
639 }
640
641 PyObject* object = new_key(&KeyType, key);
642 pakfire_key_unref(key);
643
644 return object;
645 }
646
647 static PyObject* Pakfire_import_key(PakfireObject* self, PyObject* args) {
648 struct pakfire_key* key = NULL;
649 PyObject* object = NULL;
650 char* data = NULL;
651 Py_ssize_t data_length = 0;
652 int r;
653
654 // Parse arguments
655 if (!PyArg_ParseTuple(args, "s#", &data, &data_length))
656 return NULL;
657
658 // Map the object
659 FILE* f = fmemopen(data, data_length, "r");
660 if (!f)
661 return NULL;
662
663 // Import the key
664 r = pakfire_key_import(&key, self->pakfire, f);
665 if (r) {
666 PyErr_SetFromErrno(PyExc_OSError);
667 goto ERROR;
668 }
669
670 // Convert the key into a Key object
671 object = new_key(&KeyType, key);
672 if (!object)
673 goto ERROR;
674
675 ERROR:
676 if (key)
677 pakfire_key_unref(key);
678 if (f)
679 fclose(f);
680
681 return object;
682 }
683
684 static PyObject* Pakfire_whatprovides(PakfireObject* self, PyObject* args) {
685 const char* provides = NULL;
686 struct pakfire_packagelist* list = NULL;
687 PyObject* ret = NULL;
688 int r;
689
690 if (!PyArg_ParseTuple(args, "s", &provides))
691 return NULL;
692
693 // Create a new list
694 r = pakfire_packagelist_create(&list, self->pakfire);
695 if (r) {
696 PyErr_SetFromErrno(PyExc_OSError);
697 goto ERROR;
698 }
699
700 r = pakfire_whatprovides(self->pakfire, provides, 0, list);
701 if (r) {
702 PyErr_SetFromErrno(PyExc_OSError);
703 goto ERROR;
704 }
705
706 // Create a Python list from the package list
707 ret = PyList_FromPackageList(list);
708
709 ERROR:
710 if (list)
711 pakfire_packagelist_unref(list);
712
713 return ret;
714 }
715
716 static PyObject* Pakfire_whatrequires(PakfireObject* self, PyObject* args) {
717 const char* requires = NULL;
718 struct pakfire_packagelist* list = NULL;
719 PyObject* ret = NULL;
720 int r;
721
722 if (!PyArg_ParseTuple(args, "s", &requires))
723 return NULL;
724
725 Py_BEGIN_ALLOW_THREADS
726
727 // Create a new list
728 r = pakfire_packagelist_create(&list, self->pakfire);
729 if (r) {
730 Py_BLOCK_THREADS
731 PyErr_SetFromErrno(PyExc_OSError);
732 goto ERROR;
733 }
734
735 r = pakfire_whatrequires(self->pakfire, requires, 0, list);
736 if (r) {
737 Py_BLOCK_THREADS
738 PyErr_SetFromErrno(PyExc_OSError);
739 goto ERROR;
740 }
741
742 Py_END_ALLOW_THREADS
743
744 // Create a Python list from the package list
745 ret = PyList_FromPackageList(list);
746
747 ERROR:
748 if (list)
749 pakfire_packagelist_unref(list);
750
751 return ret;
752 }
753
754 static PyObject* Pakfire_search(PakfireObject* self, PyObject* args, PyObject* kwds) {
755 char* kwlist[] = { "pattern", "name_only", NULL };
756 struct pakfire_packagelist* list = NULL;
757 const char* pattern = NULL;
758 int name_only = 0;
759 int flags = 0;
760 PyObject* ret = NULL;
761 int r;
762
763 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|$p", kwlist, &pattern, &name_only))
764 return NULL;
765
766 // Search for package names only
767 if (name_only)
768 flags |= PAKFIRE_SEARCH_NAME_ONLY;
769
770 r = pakfire_packagelist_create(&list, self->pakfire);
771 if (r) {
772 PyErr_SetFromErrno(PyExc_OSError);
773 goto ERROR;
774 }
775
776 r = pakfire_search(self->pakfire, pattern, flags, list);
777 if (r) {
778 PyErr_SetFromErrno(PyExc_OSError);
779 goto ERROR;
780 }
781
782 ret = PyList_FromPackageList(list);
783
784 ERROR:
785 if (list)
786 pakfire_packagelist_unref(list);
787
788 return ret;
789 }
790
791 static PyObject* Pakfire_version_compare(PakfireObject* self, PyObject* args) {
792 const char* evr1 = NULL;
793 const char* evr2 = NULL;
794
795 if (!PyArg_ParseTuple(args, "ss", &evr1, &evr2))
796 return NULL;
797
798 int cmp = pakfire_version_compare(self->pakfire, evr1, evr2);
799
800 return PyLong_FromLong(cmp);
801 }
802
803 static int Pakfire_execute_output_callback(struct pakfire* pakfire, void* data,
804 int priority, const char* line, size_t length) {
805 PyObject* callback = (PyObject*)data;
806 int r = 0;
807
808 // Do nothing if callback isn't set
809 if (!callback)
810 return 0;
811
812 // Translate priority to Python logging priorities
813 switch (priority) {
814 case LOG_INFO:
815 priority = 20;
816 break;
817
818 case LOG_ERR:
819 priority = 40;
820 break;
821 }
822
823 // Remove the trailing newline
824 if (line && line[length - 1] == '\n')
825 length--;
826
827 // Create tuple with arguments for the callback function
828 PyObject* args = Py_BuildValue("(is#)", priority, line, (Py_ssize_t)length);
829 if (!args)
830 return 1;
831
832 PyObject* result = PyObject_CallObject(callback, args);
833 if (result && PyLong_Check(result)) {
834 r = PyLong_AsLong(result);
835 }
836
837 Py_XDECREF(args);
838 Py_XDECREF(result);
839
840 return r;
841 }
842
843 static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject* kwds) {
844 char* kwlist[] = {
845 "command",
846 "environ",
847 "bind",
848 "callback",
849 "nice",
850 NULL
851 };
852
853 struct pakfire_jail* jail = NULL;
854 const char** argv = NULL;
855 int r;
856 PyObject* ret = NULL;
857
858 PyObject* command = NULL;
859 PyObject* environ = NULL;
860 PyObject* bind = NULL;
861 PyObject* callback = NULL;
862 int nice = 0;
863
864 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOOi", kwlist, &command, &environ,
865 &bind, &callback, &nice))
866 return NULL;
867
868 // Check if command is a list
869 if (!PyList_Check(command)) {
870 PyErr_SetString(PyExc_TypeError, "command must be a list");
871 goto ERROR;
872 }
873
874 const ssize_t command_length = PyList_Size(command);
875
876 // Check if command is not empty
877 if (command_length == 0) {
878 PyErr_SetString(PyExc_ValueError, "command is empty");
879 goto ERROR;
880 }
881
882 // Allocate argv
883 argv = calloc(command_length + 1, sizeof(*argv));
884 if (!argv)
885 goto ERROR;
886
887 // All arguments in command must be strings
888 for (unsigned int i = 0; i < command_length; i++) {
889 PyObject* item = PyList_GET_ITEM(command, i);
890
891 if (!PyUnicode_Check(item)) {
892 PyErr_Format(PyExc_TypeError, "Item %u in command is not a string", i);
893 return NULL;
894 }
895
896 // Copy to argv
897 argv[i] = PyUnicode_AsUTF8(item);
898 }
899
900 // Check if bind is a sequence
901 if (bind && !PySequence_Check(bind)) {
902 PyErr_SetString(PyExc_ValueError, "bind is not a sequence");
903 goto ERROR;
904 }
905
906 // Check callback
907 if (callback && !PyCallable_Check(callback)) {
908 PyErr_SetString(PyExc_TypeError, "callback must be callable\n");
909 goto ERROR;
910 }
911
912 // Create jail
913 r = pakfire_jail_create(&jail, self->pakfire);
914 if (r) {
915 PyErr_SetFromErrno(PyExc_OSError);
916 goto ERROR;
917 }
918
919 // Check callback
920 if (callback && !PyCallable_Check(callback)) {
921 PyErr_SetString(PyExc_TypeError, "callback must be callable\n");
922 goto ERROR;
923 }
924
925 // Set nice
926 if (nice) {
927 r = pakfire_jail_nice(jail, nice);
928 if (r) {
929 PyErr_SetFromErrno(PyExc_OSError);
930 goto ERROR;
931 }
932 }
933
934 PyObject* key = NULL;
935 PyObject* value = NULL;
936 Py_ssize_t p = 0;
937
938 // Parse the environment
939 if (environ) {
940 // Check if environ is a dictionary
941 if (!PyDict_Check(environ)) {
942 PyErr_SetString(PyExc_TypeError, "environ must be a dictionary");
943 goto ERROR;
944 }
945
946 // All keys and values must be strings
947 while (PyDict_Next(environ, &p, &key, &value)) {
948 if (!PyUnicode_Check(key) || !PyUnicode_Check(value)) {
949 PyErr_SetString(PyExc_TypeError, "Environment contains a non-string object");
950 goto ERROR;
951 }
952
953 // Set environment value
954 r = pakfire_jail_set_env(jail, PyUnicode_AsUTF8(key), PyUnicode_AsUTF8(value));
955 if (r) {
956 PyErr_SetFromErrno(PyExc_OSError);
957 goto ERROR;
958 }
959 }
960 }
961
962 const Py_ssize_t num_bind = PySequence_Length(bind);
963
964 // Bind
965 for (unsigned int i = 0; i < num_bind; i++) {
966 PyObject* b = PySequence_ITEM(bind, i);
967 if (!b)
968 goto ERROR;
969
970 // Check if this is a Unicode object
971 if (!PyUnicode_Check(b)) {
972 PyErr_SetString(PyExc_ValueError, "bind contains a non-Unicode object");
973 Py_DECREF(b);
974 goto ERROR;
975 }
976
977 const char* path = PyUnicode_AsUTF8(b);
978
979 // Perform bind
980 r = pakfire_jail_bind(jail, path, path, 0);
981 if (r) {
982 PyErr_SetFromErrno(PyExc_OSError);
983 Py_DECREF(b);
984 goto ERROR;
985 }
986
987 Py_DECREF(b);
988 }
989
990 Py_BEGIN_ALLOW_THREADS
991
992 // Execute command
993 r = pakfire_jail_exec(jail, argv,
994 NULL, Pakfire_execute_output_callback, callback, 0);
995
996 Py_END_ALLOW_THREADS
997
998 // If the return code was negative, we had some internal error
999 if (r < 0) {
1000 PyErr_SetFromErrno(PyExc_OSError);
1001 goto ERROR;
1002
1003 // Otherwise the executed command returned some error code
1004 } else if (r > 0) {
1005 PyObject* code = PyLong_FromLong(r);
1006
1007 // Raise CommandExecutionError
1008 PyErr_SetObject(PyExc_CommandExecutionError, code);
1009 Py_DECREF(code);
1010
1011 goto ERROR;
1012 }
1013
1014 // The process has exited successfully
1015
1016 // Return None
1017 ret = Py_None;
1018 Py_INCREF(ret);
1019
1020 ERROR:
1021 if (argv)
1022 free(argv);
1023 if (jail)
1024 pakfire_jail_unref(jail);
1025
1026 return ret;
1027 }
1028
1029 static PyObject* Pakfire_dist(PakfireObject* self, PyObject* args) {
1030 const char* path = NULL;
1031 const char* target = NULL;
1032 char* result = NULL;
1033 int r;
1034
1035 if (!PyArg_ParseTuple(args, "s|z", &path, &target))
1036 return NULL;
1037
1038 Py_BEGIN_ALLOW_THREADS
1039
1040 r = pakfire_dist(self->pakfire, path, target, &result);
1041 if (r) {
1042 Py_BLOCK_THREADS
1043 PyErr_SetFromErrno(PyExc_OSError);
1044 return NULL;
1045 }
1046
1047 Py_END_ALLOW_THREADS
1048
1049 PyObject* ret = PyUnicode_FromString(result);
1050 free(result);
1051
1052 return ret;
1053 }
1054
1055 static PyObject* Pakfire_copy_in(PakfireObject* self, PyObject* args) {
1056 const char* src = NULL;
1057 const char* dst = NULL;
1058
1059 if (!PyArg_ParseTuple(args, "ss", &src, &dst))
1060 return NULL;
1061
1062 Py_BEGIN_ALLOW_THREADS
1063
1064 int r = pakfire_copy_in(self->pakfire, src, dst);
1065 if (r) {
1066 Py_BLOCK_THREADS
1067 PyErr_SetFromErrno(PyExc_OSError);
1068 return NULL;
1069 }
1070
1071 Py_END_ALLOW_THREADS
1072
1073 Py_RETURN_NONE;
1074 }
1075
1076 static PyObject* Pakfire_copy_out(PakfireObject* self, PyObject* args) {
1077 const char* src = NULL;
1078 const char* dst = NULL;
1079
1080 if (!PyArg_ParseTuple(args, "ss", &src, &dst))
1081 return NULL;
1082
1083 Py_BEGIN_ALLOW_THREADS
1084
1085 int r = pakfire_copy_out(self->pakfire, src, dst);
1086 if (r) {
1087 Py_BLOCK_THREADS
1088 PyErr_SetFromErrno(PyExc_OSError);
1089 return NULL;
1090 }
1091
1092 Py_END_ALLOW_THREADS
1093
1094 Py_RETURN_NONE;
1095 }
1096
1097 static PyObject* Pakfire_get_repos(PakfireObject* self) {
1098 struct pakfire_repolist* repos = pakfire_get_repos(self->pakfire);
1099 if (!repos) {
1100 PyErr_SetFromErrno(PyExc_OSError);
1101 return NULL;
1102 }
1103
1104 const size_t l = pakfire_repolist_size(repos);
1105
1106 PyObject* list = PyList_New(l);
1107 if (!list)
1108 goto ERROR;
1109
1110 for (unsigned int i = 0; i < l; i++) {
1111 struct pakfire_repo* repo = pakfire_repolist_get(repos, i);
1112 if (!repo)
1113 continue;
1114
1115 PyObject* obj = new_repo(&RepoType, repo);
1116 PyList_SET_ITEM(list, i, obj);
1117
1118 pakfire_repo_unref(repo);
1119 }
1120
1121 ERROR:
1122 pakfire_repolist_unref(repos);
1123
1124 return list;
1125 }
1126
1127 static PyObject* execute_return_value(int r) {
1128 // Raise an OS error if r < 0
1129 if (r < 0) {
1130 errno = -r;
1131
1132 PyErr_SetFromErrno(PyExc_OSError);
1133 return NULL;
1134
1135 // Raise exception when the command failed
1136 } else if (r > 0) {
1137 PyObject* code = PyLong_FromLong(r);
1138
1139 PyErr_SetObject(PyExc_CommandExecutionError, code);
1140 Py_DECREF(code);
1141
1142 return NULL;
1143 }
1144
1145 Py_RETURN_NONE;
1146 }
1147
1148 static PyObject* Pakfire_build(PakfireObject* self, PyObject* args, PyObject* kwargs) {
1149 char* kwlist[] = {
1150 "path",
1151 "target",
1152 "build_id",
1153 "ccache_path",
1154 "interactive",
1155 "disable_snapshot",
1156 "disable_ccache",
1157 "disable_tests",
1158 NULL,
1159 };
1160 struct pakfire_build* build = NULL;
1161 const char* path = NULL;
1162 const char* target = NULL;
1163 const char* build_id = NULL;
1164 const char* ccache_path = NULL;
1165 int interactive = 0;
1166 int disable_snapshot = 0;
1167 int disable_ccache = 0;
1168 int disable_tests = 0;
1169 int r;
1170
1171 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zzzpppp", kwlist,
1172 &path, &target, &build_id, &ccache_path, &interactive,
1173 &disable_snapshot, &disable_ccache, &disable_tests))
1174 return NULL;
1175
1176 int flags = 0;
1177
1178 if (interactive)
1179 flags |= PAKFIRE_BUILD_INTERACTIVE;
1180
1181 // Disable snapshot if requested
1182 if (disable_snapshot)
1183 flags |= PAKFIRE_BUILD_DISABLE_SNAPSHOT;
1184
1185 // Disable ccache if requested
1186 if (disable_ccache)
1187 flags |= PAKFIRE_BUILD_DISABLE_CCACHE;
1188
1189 // Disable tests if requested
1190 if (disable_tests)
1191 flags |= PAKFIRE_BUILD_DISABLE_TESTS;
1192
1193 // Create a new build environment
1194 r = pakfire_build_create(&build, self->pakfire, build_id, flags);
1195 if (r) {
1196 PyErr_SetFromErrno(PyExc_OSError);
1197 goto ERROR;
1198 }
1199
1200 // Set target
1201 if (target) {
1202 r = pakfire_build_set_target(build, target);
1203 if (r) {
1204 PyErr_SetFromErrno(PyExc_OSError);
1205 goto ERROR;
1206 }
1207 }
1208
1209 // Set ccache path
1210 if (ccache_path) {
1211 r = pakfire_build_set_ccache_path(build, ccache_path);
1212 if (r) {
1213 PyErr_SetFromErrno(PyExc_OSError);
1214 goto ERROR;
1215 }
1216 }
1217
1218 Py_BEGIN_ALLOW_THREADS
1219
1220 // Run build
1221 r = pakfire_build_exec(build, path);
1222 if (r) {
1223 Py_BLOCK_THREADS;
1224
1225 if (r < 0) {
1226 PyErr_SetFromErrno(PyExc_OSError);
1227
1228 // Raise a command execution error
1229 } else {
1230 PyObject* code = PyLong_FromLong(r);
1231
1232 PyErr_SetObject(PyExc_CommandExecutionError, code);
1233 Py_DECREF(code);
1234 }
1235
1236 goto ERROR;
1237 }
1238
1239 Py_END_ALLOW_THREADS
1240
1241 ERROR:
1242 if (build)
1243 pakfire_build_unref(build);
1244
1245 if (r)
1246 return NULL;
1247
1248 Py_RETURN_NONE;
1249 }
1250
1251 static PyObject* Pakfire_shell(PakfireObject* self, PyObject* args, PyObject* kwargs) {
1252 char* kwlist[] = {
1253 "install",
1254 "disable_snapshot",
1255 NULL,
1256 };
1257 char** packages = NULL;
1258 int disable_snapshot = 0;
1259 int r;
1260
1261 // Parse everything
1262 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&p", kwlist,
1263 convert_packages, &packages, &disable_snapshot))
1264 return NULL;
1265
1266 int flags = 0;
1267
1268 if (disable_snapshot)
1269 flags |= PAKFIRE_BUILD_DISABLE_SNAPSHOT;
1270
1271 Py_BEGIN_ALLOW_THREADS
1272
1273 r = pakfire_shell(self->pakfire, (const char**)packages, flags);
1274
1275 Py_END_ALLOW_THREADS
1276
1277 return execute_return_value(r);
1278 }
1279
1280 static PyObject* Pakfire_clean(PakfireObject* self) {
1281 int r;
1282
1283 Py_BEGIN_ALLOW_THREADS
1284
1285 r = pakfire_clean(self->pakfire, 0);
1286 if (r) {
1287 Py_BLOCK_THREADS
1288 PyErr_SetFromErrno(PyExc_OSError);
1289 return NULL;
1290 }
1291
1292 Py_END_ALLOW_THREADS
1293
1294 Py_RETURN_NONE;
1295 }
1296
1297 static PyObject* Pakfire_refresh(PakfireObject* self, PyObject* args) {
1298 int force = 0;
1299 int r;
1300
1301 if (!PyArg_ParseTuple(args, "|p", &force))
1302 return NULL;
1303
1304 Py_BEGIN_ALLOW_THREADS
1305
1306 r = pakfire_refresh(self->pakfire, force);
1307 if (r) {
1308 Py_BLOCK_THREADS
1309 PyErr_SetFromErrno(PyExc_OSError);
1310 return NULL;
1311 }
1312
1313 Py_END_ALLOW_THREADS
1314
1315 Py_RETURN_NONE;
1316 }
1317
1318 static PyObject* Pakfire_check(PakfireObject* self) {
1319 struct pakfire_filelist* errors = NULL;
1320 int r;
1321
1322 // Allocate a filelist for errors
1323 r = pakfire_filelist_create(&errors, self->pakfire);
1324 if (r)
1325 goto ERROR;
1326
1327 Py_BEGIN_ALLOW_THREADS
1328
1329 // Perform check
1330 r = pakfire_check(self->pakfire, errors);
1331
1332 Py_END_ALLOW_THREADS
1333
1334 if (r)
1335 goto ERROR;
1336
1337 const size_t num_errors = pakfire_filelist_length(errors);
1338
1339 // Did we find any errors?
1340 if (num_errors) {
1341 PyObject* _errors = PyList_FromFileList(errors);
1342 if (!_errors)
1343 goto ERROR;
1344
1345 pakfire_filelist_unref(errors);
1346
1347 // Raise CheckFileVerificationError
1348 PyErr_SetObject(PyExc_CheckFileVerificationError, _errors);
1349 Py_DECREF(_errors);
1350 return NULL;
1351 }
1352
1353 pakfire_filelist_unref(errors);
1354 Py_RETURN_NONE;
1355
1356 ERROR:
1357 // Cleanup
1358 if (errors)
1359 pakfire_filelist_unref(errors);
1360
1361 // Raise exception from errno
1362 PyErr_SetFromErrno(PyExc_OSError);
1363 return NULL;
1364 }
1365
1366 static PyObject* Pakfire_sync(PakfireObject* self, PyObject* args, PyObject* kwargs) {
1367 char* kwlist[] = {
1368 "keep_orphaned",
1369 "status_callback",
1370 NULL,
1371 };
1372 int keep_orphaned = 0;
1373 int flags = 0;
1374 PyObject* status_callback = NULL;
1375 int r;
1376
1377 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|$pO", kwlist,
1378 &keep_orphaned, &status_callback))
1379 return NULL;
1380
1381 if (keep_orphaned)
1382 flags |= PAKFIRE_REQUEST_KEEP_ORPHANED;
1383
1384 Py_BEGIN_ALLOW_THREADS
1385
1386 r = pakfire_sync(self->pakfire, 0, flags, NULL,
1387 Pakfire_status_callback, status_callback);
1388 if (r) {
1389 Py_BLOCK_THREADS
1390 PyErr_SetFromErrno(PyExc_OSError);
1391 return NULL;
1392 }
1393
1394 Py_END_ALLOW_THREADS
1395
1396 Py_RETURN_NONE;
1397 }
1398
1399 static PyObject* Pakfire_open(PakfireObject* self, PyObject* args) {
1400 struct pakfire_archive* archive = NULL;
1401 const char* path = NULL;
1402
1403 if (!PyArg_ParseTuple(args, "s", &path))
1404 return NULL;
1405
1406 Py_BEGIN_ALLOW_THREADS
1407
1408 int r = pakfire_archive_open(&archive, self->pakfire, path);
1409 if (r) {
1410 Py_BLOCK_THREADS
1411 PyErr_SetFromErrno(PyExc_OSError);
1412 return NULL;
1413 }
1414
1415 Py_END_ALLOW_THREADS
1416
1417 // Create Python object
1418 PyObject* object = new_archive(&ArchiveType, archive);
1419 pakfire_archive_unref(archive);
1420
1421 return object;
1422 }
1423
1424 static PyObject* Pakfire_repo_compose(PakfireObject* self, PyObject* args, PyObject* kwargs) {
1425 char* kwlist[] = { "path", "files", "key", NULL };
1426 const char* path = NULL;
1427 PyObject* list = NULL;
1428 KeyObject* key = NULL;
1429
1430 PyObject* ret = NULL;
1431
1432 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|O!", kwlist, &path, &list, &KeyType, &key))
1433 return NULL;
1434
1435 // List must be a sequence
1436 if (!PySequence_Check(list)) {
1437 PyErr_SetString(PyExc_ValueError, "Expected a sequence.");
1438 return NULL;
1439 }
1440
1441 // How many new files do we have?
1442 ssize_t num_files = PySequence_Length(list);
1443 if (num_files < 0)
1444 return NULL;
1445
1446 // Allocate files array
1447 const char** files = calloc(num_files + 1, sizeof(*files));
1448 if (!files) {
1449 PyErr_SetFromErrno(PyExc_OSError);
1450 return NULL;
1451 }
1452
1453 for (int i = 0; i < num_files; i++) {
1454 PyObject* file = PySequence_GetItem(list, i);
1455 if (!file)
1456 goto ERROR;
1457
1458 // Check if file is a Unicode object
1459 if (!PyUnicode_Check(file)) {
1460 PyErr_SetString(PyExc_ValueError, "Expected a string.");
1461 goto ERROR;
1462 }
1463
1464 // Add pointer to string to files array
1465 files[i] = PyUnicode_AsUTF8(file);
1466 if (!files[i])
1467 goto ERROR;
1468
1469 Py_DECREF(file);
1470 }
1471
1472 Py_BEGIN_ALLOW_THREADS
1473
1474 int r = pakfire_repo_compose(self->pakfire, path, (key) ? key->key : NULL, files);
1475 if (r) {
1476 Py_BLOCK_THREADS
1477 PyErr_SetFromErrno(PyExc_OSError);
1478 return NULL;
1479 }
1480
1481 Py_END_ALLOW_THREADS
1482
1483 // Return None on success
1484 ret = Py_None;
1485 Py_INCREF(ret);
1486
1487 ERROR:
1488 if (files)
1489 free(files);
1490
1491 return ret;
1492 }
1493
1494 static PyObject* Pakfire_mkimage(PakfireObject* self, PyObject* args, PyObject* kwargs) {
1495 char* kwlist[] = {
1496 "type",
1497 "path",
1498 NULL,
1499 };
1500 struct pakfire_build* build = NULL;
1501 const char* type = NULL;
1502 PyObject* file = NULL;
1503 FILE* f = NULL;
1504 int r;
1505
1506 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO", kwlist, &type, &file))
1507 return NULL;
1508
1509 // Make a file handle out of file
1510 f = PyObject_AsFileHandle(file, "w");
1511 if (!f)
1512 return NULL;
1513
1514 // Create a new build environment
1515 r = pakfire_build_create(&build, self->pakfire, NULL, 0);
1516 if (r) {
1517 PyErr_SetFromErrno(PyExc_OSError);
1518 goto ERROR;
1519 }
1520
1521 Py_BEGIN_ALLOW_THREADS
1522
1523 // Run mkimage
1524 r = pakfire_build_mkimage(build, type, f);
1525 if (r) {
1526 Py_BLOCK_THREADS;
1527
1528 if (r < 0)
1529 PyErr_SetFromErrno(PyExc_OSError);
1530
1531 goto ERROR;
1532 }
1533
1534 Py_END_ALLOW_THREADS
1535
1536 ERROR:
1537 if (build)
1538 pakfire_build_unref(build);
1539 if (f)
1540 fclose(f);
1541 if (r)
1542 return NULL;
1543
1544 Py_RETURN_NONE;
1545 }
1546
1547 static struct PyMethodDef Pakfire_methods[] = {
1548 {
1549 "build",
1550 (PyCFunction)Pakfire_build,
1551 METH_VARARGS|METH_KEYWORDS,
1552 NULL
1553 },
1554 {
1555 "check",
1556 (PyCFunction)Pakfire_check,
1557 METH_NOARGS,
1558 NULL,
1559 },
1560 {
1561 "clean",
1562 (PyCFunction)Pakfire_clean,
1563 METH_NOARGS,
1564 NULL,
1565 },
1566 {
1567 "copy_in",
1568 (PyCFunction)Pakfire_copy_in,
1569 METH_VARARGS,
1570 NULL,
1571 },
1572 {
1573 "copy_out",
1574 (PyCFunction)Pakfire_copy_out,
1575 METH_VARARGS,
1576 NULL,
1577 },
1578 {
1579 "dist",
1580 (PyCFunction)Pakfire_dist,
1581 METH_VARARGS,
1582 NULL
1583 },
1584 {
1585 "erase",
1586 (PyCFunction)Pakfire_erase,
1587 METH_VARARGS|METH_KEYWORDS,
1588 NULL
1589 },
1590 {
1591 "execute",
1592 (PyCFunction)Pakfire_execute,
1593 METH_VARARGS|METH_KEYWORDS,
1594 NULL
1595 },
1596 {
1597 "generate_key",
1598 (PyCFunction)Pakfire_generate_key,
1599 METH_VARARGS|METH_KEYWORDS,
1600 NULL
1601 },
1602 {
1603 "get_repo",
1604 (PyCFunction)Pakfire_get_repo,
1605 METH_VARARGS,
1606 NULL
1607 },
1608 {
1609 "import_key",
1610 (PyCFunction)Pakfire_import_key,
1611 METH_VARARGS,
1612 NULL,
1613 },
1614 {
1615 "install",
1616 (PyCFunction)Pakfire_install,
1617 METH_VARARGS|METH_KEYWORDS,
1618 NULL,
1619 },
1620 {
1621 "mkimage",
1622 (PyCFunction)Pakfire_mkimage,
1623 METH_VARARGS|METH_KEYWORDS,
1624 NULL
1625 },
1626 {
1627 "open",
1628 (PyCFunction)Pakfire_open,
1629 METH_VARARGS,
1630 NULL
1631 },
1632 {
1633 "refresh",
1634 (PyCFunction)Pakfire_refresh,
1635 METH_VARARGS,
1636 NULL,
1637 },
1638 {
1639 "repo_compose",
1640 (PyCFunction)Pakfire_repo_compose,
1641 METH_VARARGS|METH_KEYWORDS,
1642 NULL
1643 },
1644 {
1645 "search",
1646 (PyCFunction)Pakfire_search,
1647 METH_VARARGS|METH_KEYWORDS,
1648 NULL
1649 },
1650 {
1651 "shell",
1652 (PyCFunction)Pakfire_shell,
1653 METH_VARARGS|METH_KEYWORDS,
1654 NULL,
1655 },
1656 {
1657 "sync",
1658 (PyCFunction)Pakfire_sync,
1659 METH_VARARGS|METH_KEYWORDS,
1660 NULL,
1661 },
1662 {
1663 "update",
1664 (PyCFunction)Pakfire_update,
1665 METH_VARARGS|METH_KEYWORDS,
1666 NULL
1667 },
1668 {
1669 "version_compare",
1670 (PyCFunction)Pakfire_version_compare,
1671 METH_VARARGS,
1672 NULL
1673 },
1674 {
1675 "whatprovides",
1676 (PyCFunction)Pakfire_whatprovides,
1677 METH_VARARGS,
1678 NULL
1679 },
1680 {
1681 "whatrequires",
1682 (PyCFunction)Pakfire_whatrequires,
1683 METH_VARARGS,
1684 NULL
1685 },
1686 { NULL },
1687 };
1688
1689 static struct PyGetSetDef Pakfire_getsetters[] = {
1690 {
1691 "arch",
1692 (getter)Pakfire_get_arch,
1693 NULL,
1694 NULL,
1695 NULL
1696 },
1697 {
1698 "path",
1699 (getter)Pakfire_get_path,
1700 NULL,
1701 NULL,
1702 NULL
1703 },
1704 {
1705 "repos",
1706 (getter)Pakfire_get_repos,
1707 NULL,
1708 NULL,
1709 NULL
1710 },
1711 { NULL },
1712 };
1713
1714 PyTypeObject PakfireType = {
1715 PyVarObject_HEAD_INIT(NULL, 0)
1716 tp_name: "_pakfire.Pakfire",
1717 tp_basicsize: sizeof(PakfireObject),
1718 tp_flags: Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,
1719 tp_new: Pakfire_new,
1720 tp_dealloc: (destructor)Pakfire_dealloc,
1721 tp_init: (initproc)Pakfire_init,
1722 tp_doc: "Pakfire object",
1723 tp_methods: Pakfire_methods,
1724 tp_getset: Pakfire_getsetters,
1725 tp_repr: (reprfunc)Pakfire_repr,
1726 };