1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2017 Pakfire development team #
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. #
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. #
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/>. #
19 #############################################################################*/
21 #define PY_SSIZE_T_CLEAN
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>
48 static PyObject
* Pakfire_new(PyTypeObject
* type
, PyObject
* args
, PyObject
* kwds
) {
49 PakfireObject
* self
= (PakfireObject
*)type
->tp_alloc(type
, 0);
54 self
->callbacks
.log
= NULL
;
55 self
->callbacks
.confirm
= NULL
;
58 return (PyObject
*)self
;
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
;
66 // Do nothing if callback isn't set
70 PyGILState_STATE state
= PyGILState_Ensure();
72 // Translate priority to Python logging priorities
86 // Drop messages of an unknown priority
91 PyObject
* tuple
= NULL
;
92 PyObject
* result
= NULL
;
96 int r
= vasprintf(&buffer
, format
, args
);
100 // Build a tuple with the priority and the log message
101 tuple
= Py_BuildValue("(is)", priority
, buffer
);
106 result
= PyObject_CallObject(callback
, tuple
);
110 We cannot really catch any Python errors here, since we cannot send
111 any error codes up the chain.
113 So, in order to debug the problem, We will check if an exception has
114 occurred and if so, print it to the console.
116 exception
= PyErr_Occurred();
126 PyGILState_Release(state
);
129 static int Pakfire_confirm_callback(struct pakfire
* pakfire
, void* data
,
130 const char* message
, const char* question
) {
131 PyObject
* callback
= (PyObject
*)data
;
132 PyObject
* result
= NULL
;
135 // Do nothing if callback isn't set
140 PyGILState_STATE state
= PyGILState_Ensure();
142 PyObject
* args
= Py_BuildValue("(ss)", message
, question
);
148 result
= PyObject_CallObject(callback
, args
);
150 // If the callback raised an exception, we will ignore it and indicate
151 // that an error happened, but we cannot re-raise the exception
157 // Set the return code
158 if (result
== Py_True
)
168 PyGILState_Release(state
);
173 static int Pakfire_init(PakfireObject
* self
, PyObject
* args
, PyObject
* kwds
) {
183 const char* path
= NULL
;
184 const char* arch
= NULL
;
185 const char* conf
= NULL
;
189 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "|zzOpzO", kwlist
,
190 &path
, &arch
, &self
->callbacks
.log
, &offline
, &conf
, &self
->callbacks
.confirm
))
193 // Check if log callback is callable
194 if (self
->callbacks
.log
&& !PyCallable_Check(self
->callbacks
.log
)) {
195 PyErr_SetString(PyExc_TypeError
, "logger must be callable\n");
199 // Check if confirm callback is callable
200 if (self
->callbacks
.confirm
&& !PyCallable_Check(self
->callbacks
.confirm
)) {
201 PyErr_SetString(PyExc_TypeError
, "Confirm callback is not callable");
207 // Enable offline mode
209 flags
|= PAKFIRE_FLAGS_OFFLINE
;
211 // Configure callbacks
212 if (self
->callbacks
.log
)
213 Py_INCREF(self
->callbacks
.log
);
215 Py_BEGIN_ALLOW_THREADS
217 // Create a new Pakfire instance
218 r
= pakfire_create(&self
->pakfire
, path
, arch
, conf
, flags
,
219 LOG_DEBUG
, Pakfire_log_callback
, self
->callbacks
.log
);
225 // Invalid architecture or path
227 PyErr_SetString(PyExc_ValueError
, "Invalid architecture or path");
232 PyErr_SetFromErrno(PyExc_OSError
);
238 // Configure confirm callback
239 if (self
->callbacks
.confirm
) {
240 pakfire_set_confirm_callback(self
->pakfire
,
241 Pakfire_confirm_callback
, self
->callbacks
.confirm
);
243 Py_INCREF(self
->callbacks
.confirm
);
249 static void Pakfire_dealloc(PakfireObject
* self
) {
251 // Reset log callback
252 if (self
->callbacks
.log
) {
253 pakfire_set_log_callback(self
->pakfire
, NULL
, NULL
);
254 Py_DECREF(self
->callbacks
.log
);
257 // Reset confirm callback
258 if (self
->callbacks
.confirm
) {
259 pakfire_set_confirm_callback(self
->pakfire
, NULL
, NULL
);
260 Py_DECREF(self
->callbacks
.confirm
);
263 Py_BEGIN_ALLOW_THREADS
265 pakfire_unref(self
->pakfire
);
270 Py_TYPE(self
)->tp_free((PyObject
*)self
);
273 static PyObject
* Pakfire_repr(PakfireObject
* self
) {
274 const char* path
= pakfire_get_path(self
->pakfire
);
275 const char* arch
= pakfire_get_arch(self
->pakfire
);
277 return PyUnicode_FromFormat("<_pakfire.Pakfire %s (%s)>", path
, arch
);
280 static PyObject
* Pakfire_get_path(PakfireObject
* self
) {
281 const char* path
= pakfire_get_path(self
->pakfire
);
283 return PyUnicode_FromString(path
);
286 static PyObject
* Pakfire_get_arch(PakfireObject
* self
) {
287 const char* arch
= pakfire_get_arch(self
->pakfire
);
289 return PyUnicode_FromString(arch
);
292 static PyObject
* Pakfire_get_repo(PakfireObject
* self
, PyObject
* args
) {
293 const char* name
= NULL
;
295 if (!PyArg_ParseTuple(args
, "s", &name
))
298 struct pakfire_repo
* repo
= pakfire_get_repo(self
->pakfire
, name
);
302 PyObject
* obj
= new_repo(&RepoType
, repo
);
303 pakfire_repo_unref(repo
);
308 static void Pakfire_status_callback(struct pakfire
* pakfire
, void* data
,
309 int progress
, const char* status
) {
310 PyObject
* callback
= (PyObject
*)data
;
312 // Do not attempt to call nothing
317 PyGILState_STATE state
= PyGILState_Ensure();
320 PyObject
* args
= Py_BuildValue("(is)", progress
, status
);
323 PyObject
* result
= PyObject_CallObject(callback
, args
);
330 PyGILState_Release(state
);
333 static int convert_packages(PyObject
* object
, void* address
) {
334 char*** packages
= (char***)address
;
336 // Called for cleanup
340 // Nothing to do when object is None
341 if (object
== Py_None
)
342 return Py_CLEANUP_SUPPORTED
;
344 if (!PySequence_Check(object
)) {
345 PyErr_SetString(PyExc_ValueError
, "Packages must be a sequence");
349 const unsigned int length
= PySequence_Length(object
);
351 return Py_CLEANUP_SUPPORTED
;
354 *packages
= calloc(length
+ 1, sizeof(*packages
));
356 PyErr_SetFromErrno(PyExc_OSError
);
360 for (unsigned int i
= 0; i
< length
; i
++) {
361 PyObject
* item
= PySequence_GetItem(object
, i
);
363 // Check if input is a string
364 if (!PyUnicode_Check(item
)) {
367 PyErr_SetString(PyExc_AttributeError
, "Expected a string");
372 const char* package
= PyUnicode_AsUTF8(item
);
378 // Add package to array
379 (*packages
)[i
] = strdup(package
);
380 if (!(*packages
)[i
]) {
389 return Py_CLEANUP_SUPPORTED
;
393 for (char** package
= *packages
; *package
; package
++)
401 static PyObject
* Pakfire_install(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
405 "without_recommended",
411 char** packages
= NULL
;
413 int without_recommended
= 0;
414 int allow_uninstall
= 0;
415 int allow_downgrade
= 0;
416 int solver_flags
= 0;
417 int transaction_flags
= 0;
418 PyObject
* status_callback
= NULL
;
421 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "O&|$ppppO", kwlist
,
422 convert_packages
, &packages
, &dryrun
, &without_recommended
, &allow_uninstall
,
423 &allow_downgrade
, &status_callback
))
426 // Check if callback is callable
427 if (status_callback
&& !PyCallable_Check(status_callback
)) {
428 PyErr_SetString(PyExc_TypeError
, "status_callback must be callable");
432 // Enable dry-run mode
434 transaction_flags
|= PAKFIRE_TRANSACTION_DRY_RUN
;
436 // Do not install recommended packages
437 if (without_recommended
)
438 solver_flags
|= PAKFIRE_REQUEST_WITHOUT_RECOMMENDED
;
440 // Can the solver uninstall packages?
442 solver_flags
|= PAKFIRE_REQUEST_ALLOW_UNINSTALL
;
444 // Can the solver downgrade packages?
446 solver_flags
|= PAKFIRE_REQUEST_ALLOW_DOWNGRADE
;
448 Py_BEGIN_ALLOW_THREADS
450 // Run pakfire_install
451 r
= pakfire_install(self
->pakfire
, transaction_flags
, solver_flags
,
452 (const char**)packages
, NULL
, 0, NULL
, Pakfire_status_callback
, status_callback
);
457 PyErr_SetFromErrno(PyExc_OSError
);
460 for (char** package
= packages
; *package
; package
++)
471 static PyObject
* Pakfire_erase(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
479 char** packages
= NULL
;
481 int keep_dependencies
= 0;
482 int transaction_flags
= 0;
484 PyObject
* status_callback
= NULL
;
487 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "O&|$ppO", kwlist
,
488 convert_packages
, &packages
, &dryrun
, &keep_dependencies
, &status_callback
))
491 // Check if callback is callable
492 if (status_callback
&& !PyCallable_Check(status_callback
)) {
493 PyErr_SetString(PyExc_TypeError
, "status_callback must be callable");
498 transaction_flags
|= PAKFIRE_TRANSACTION_DRY_RUN
;
500 if (keep_dependencies
)
501 flags
|= PAKFIRE_REQUEST_KEEP_DEPS
;
503 Py_BEGIN_ALLOW_THREADS
506 r
= pakfire_erase(self
->pakfire
, transaction_flags
, 0, (const char**)packages
,
507 NULL
, flags
, NULL
, Pakfire_status_callback
, status_callback
);
512 PyErr_SetFromErrno(PyExc_OSError
);
515 for (char** package
= packages
; *package
; package
++)
526 static PyObject
* Pakfire_update(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
536 char** packages
= NULL
;
537 char** excludes
= NULL
;
539 int allow_uninstall
= 0;
540 int allow_downgrade
= 0;
541 int solver_flags
= 0;
542 int transaction_flags
= 0;
543 PyObject
* status_callback
= NULL
;
546 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "O&|$pO&ppO", kwlist
,
547 convert_packages
, &packages
, &dryrun
, convert_packages
, &excludes
,
548 &allow_uninstall
, &allow_downgrade
, &status_callback
))
551 // Check if callback is callable
552 if (status_callback
&& !PyCallable_Check(status_callback
)) {
553 PyErr_SetString(PyExc_TypeError
, "status_callback must be callable");
558 transaction_flags
= PAKFIRE_TRANSACTION_DRY_RUN
;
560 // Can the solver uninstall packages?
562 solver_flags
|= PAKFIRE_REQUEST_ALLOW_UNINSTALL
;
564 // Can the solver downgrade packages?
566 solver_flags
|= PAKFIRE_REQUEST_ALLOW_DOWNGRADE
;
568 Py_BEGIN_ALLOW_THREADS
570 // Run pakfire_update
571 r
= pakfire_update(self
->pakfire
, transaction_flags
, solver_flags
,
572 (const char**)packages
, (const char**)excludes
, 0, NULL
,
573 Pakfire_status_callback
, status_callback
);
578 PyErr_SetFromErrno(PyExc_OSError
);
581 for (char** package
= packages
; *package
; package
++)
587 for (char** exclude
= excludes
; *exclude
; exclude
++)
598 static PyObject
* Pakfire_generate_key(PakfireObject
* self
, PyObject
* args
, PyObject
* kwds
) {
599 char* kwlist
[] = { "algorithm", NULL
};
600 struct pakfire_key
* key
= NULL
;
601 pakfire_key_algo_t algo
= PAKFIRE_KEY_ALGO_NULL
;
603 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "i", kwlist
, &algo
))
606 // Generate a new key
607 int r
= pakfire_key_generate(&key
, self
->pakfire
, algo
);
609 PyErr_SetFromErrno(PyExc_OSError
);
613 PyObject
* object
= new_key(&KeyType
, key
);
614 pakfire_key_unref(key
);
619 static PyObject
* Pakfire_import_key(PakfireObject
* self
, PyObject
* args
) {
620 struct pakfire_key
* key
= NULL
;
621 PyObject
* object
= NULL
;
622 PyObject
* file
= NULL
;
626 if (!PyArg_ParseTuple(args
, "O", &file
))
629 // Treat the object as a file
630 FILE* f
= PyObject_AsFileHandle(file
, "r");
635 r
= pakfire_key_import(&key
, self
->pakfire
, f
);
637 PyErr_SetFromErrno(PyExc_OSError
);
641 // Convert the key into a Key object
642 object
= new_key(&KeyType
, key
);
648 pakfire_key_unref(key
);
655 static PyObject
* Pakfire_whatprovides(PakfireObject
* self
, PyObject
* args
) {
656 const char* provides
= NULL
;
657 struct pakfire_packagelist
* list
= NULL
;
658 PyObject
* ret
= NULL
;
661 if (!PyArg_ParseTuple(args
, "s", &provides
))
665 r
= pakfire_packagelist_create(&list
, self
->pakfire
);
667 PyErr_SetFromErrno(PyExc_OSError
);
671 r
= pakfire_whatprovides(self
->pakfire
, provides
, 0, list
);
673 PyErr_SetFromErrno(PyExc_OSError
);
677 // Create a Python list from the package list
678 ret
= PyList_FromPackageList(list
);
682 pakfire_packagelist_unref(list
);
687 static PyObject
* Pakfire_whatrequires(PakfireObject
* self
, PyObject
* args
) {
688 const char* requires
= NULL
;
689 struct pakfire_packagelist
* list
= NULL
;
690 PyObject
* ret
= NULL
;
693 if (!PyArg_ParseTuple(args
, "s", &requires
))
696 Py_BEGIN_ALLOW_THREADS
699 r
= pakfire_packagelist_create(&list
, self
->pakfire
);
702 PyErr_SetFromErrno(PyExc_OSError
);
706 r
= pakfire_whatrequires(self
->pakfire
, requires
, 0, list
);
709 PyErr_SetFromErrno(PyExc_OSError
);
715 // Create a Python list from the package list
716 ret
= PyList_FromPackageList(list
);
720 pakfire_packagelist_unref(list
);
725 static PyObject
* Pakfire_search(PakfireObject
* self
, PyObject
* args
, PyObject
* kwds
) {
726 char* kwlist
[] = { "pattern", "name_only", NULL
};
727 struct pakfire_packagelist
* list
= NULL
;
728 const char* pattern
= NULL
;
731 PyObject
* ret
= NULL
;
734 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "s|$p", kwlist
, &pattern
, &name_only
))
737 // Search for package names only
739 flags
|= PAKFIRE_SEARCH_NAME_ONLY
;
741 r
= pakfire_packagelist_create(&list
, self
->pakfire
);
743 PyErr_SetFromErrno(PyExc_OSError
);
747 r
= pakfire_search(self
->pakfire
, pattern
, flags
, list
);
749 PyErr_SetFromErrno(PyExc_OSError
);
753 ret
= PyList_FromPackageList(list
);
757 pakfire_packagelist_unref(list
);
762 static PyObject
* Pakfire_version_compare(PakfireObject
* self
, PyObject
* args
) {
763 const char* evr1
= NULL
;
764 const char* evr2
= NULL
;
766 if (!PyArg_ParseTuple(args
, "ss", &evr1
, &evr2
))
769 int cmp
= pakfire_version_compare(self
->pakfire
, evr1
, evr2
);
771 return PyLong_FromLong(cmp
);
774 static int Pakfire_execute_output_callback(struct pakfire
* pakfire
, void* data
,
775 int priority
, const char* line
, size_t length
) {
776 PyObject
* callback
= (PyObject
*)data
;
779 // Do nothing if callback isn't set
783 // Translate priority to Python logging priorities
794 // Remove the trailing newline
795 if (line
&& line
[length
- 1] == '\n')
798 // Create tuple with arguments for the callback function
799 PyObject
* args
= Py_BuildValue("(is#)", priority
, line
, (Py_ssize_t
)length
);
803 PyObject
* result
= PyObject_CallObject(callback
, args
);
804 if (result
&& PyLong_Check(result
)) {
805 r
= PyLong_AsLong(result
);
814 static PyObject
* Pakfire_execute(PakfireObject
* self
, PyObject
* args
, PyObject
* kwds
) {
824 struct pakfire_jail
* jail
= NULL
;
825 const char** argv
= NULL
;
827 PyObject
* ret
= NULL
;
829 PyObject
* command
= NULL
;
830 PyObject
* environ
= NULL
;
831 PyObject
* bind
= NULL
;
832 PyObject
* callback
= NULL
;
835 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "O|OOOi", kwlist
, &command
, &environ
,
836 &bind
, &callback
, &nice
))
839 // Check if command is a list
840 if (!PyList_Check(command
)) {
841 PyErr_SetString(PyExc_TypeError
, "command must be a list");
845 const ssize_t command_length
= PyList_Size(command
);
847 // Check if command is not empty
848 if (command_length
== 0) {
849 PyErr_SetString(PyExc_ValueError
, "command is empty");
854 argv
= calloc(command_length
+ 1, sizeof(*argv
));
858 // All arguments in command must be strings
859 for (unsigned int i
= 0; i
< command_length
; i
++) {
860 PyObject
* item
= PyList_GET_ITEM(command
, i
);
862 if (!PyUnicode_Check(item
)) {
863 PyErr_Format(PyExc_TypeError
, "Item %u in command is not a string", i
);
868 argv
[i
] = PyUnicode_AsUTF8(item
);
871 // Check if bind is a sequence
872 if (bind
&& !PySequence_Check(bind
)) {
873 PyErr_SetString(PyExc_ValueError
, "bind is not a sequence");
878 if (callback
&& !PyCallable_Check(callback
)) {
879 PyErr_SetString(PyExc_TypeError
, "callback must be callable\n");
884 r
= pakfire_jail_create(&jail
, self
->pakfire
);
886 PyErr_SetFromErrno(PyExc_OSError
);
891 if (callback
&& !PyCallable_Check(callback
)) {
892 PyErr_SetString(PyExc_TypeError
, "callback must be callable\n");
898 r
= pakfire_jail_nice(jail
, nice
);
900 PyErr_SetFromErrno(PyExc_OSError
);
905 PyObject
* key
= NULL
;
906 PyObject
* value
= NULL
;
909 // Parse the environment
911 // Check if environ is a dictionary
912 if (!PyDict_Check(environ
)) {
913 PyErr_SetString(PyExc_TypeError
, "environ must be a dictionary");
917 // All keys and values must be strings
918 while (PyDict_Next(environ
, &p
, &key
, &value
)) {
919 if (!PyUnicode_Check(key
) || !PyUnicode_Check(value
)) {
920 PyErr_SetString(PyExc_TypeError
, "Environment contains a non-string object");
924 // Set environment value
925 r
= pakfire_jail_set_env(jail
, PyUnicode_AsUTF8(key
), PyUnicode_AsUTF8(value
));
927 PyErr_SetFromErrno(PyExc_OSError
);
933 const Py_ssize_t num_bind
= PySequence_Length(bind
);
936 for (unsigned int i
= 0; i
< num_bind
; i
++) {
937 PyObject
* b
= PySequence_ITEM(bind
, i
);
941 // Check if this is a Unicode object
942 if (!PyUnicode_Check(b
)) {
943 PyErr_SetString(PyExc_ValueError
, "bind contains a non-Unicode object");
948 const char* path
= PyUnicode_AsUTF8(b
);
951 r
= pakfire_jail_bind(jail
, path
, path
, 0);
953 PyErr_SetFromErrno(PyExc_OSError
);
961 Py_BEGIN_ALLOW_THREADS
964 r
= pakfire_jail_exec(jail
, argv
,
965 NULL
, Pakfire_execute_output_callback
, callback
, 0);
969 // If the return code was negative, we had some internal error
971 PyErr_SetFromErrno(PyExc_OSError
);
974 // Otherwise the executed command returned some error code
976 PyObject
* code
= PyLong_FromLong(r
);
978 // Raise CommandExecutionError
979 PyErr_SetObject(PyExc_CommandExecutionError
, code
);
985 // The process has exited successfully
995 pakfire_jail_unref(jail
);
1000 static PyObject
* Pakfire_dist(PakfireObject
* self
, PyObject
* args
) {
1001 const char* path
= NULL
;
1002 const char* target
= NULL
;
1003 char* result
= NULL
;
1006 if (!PyArg_ParseTuple(args
, "s|z", &path
, &target
))
1009 Py_BEGIN_ALLOW_THREADS
1011 r
= pakfire_dist(self
->pakfire
, path
, target
, &result
);
1014 PyErr_SetFromErrno(PyExc_OSError
);
1018 Py_END_ALLOW_THREADS
1020 PyObject
* ret
= PyUnicode_FromString(result
);
1026 static PyObject
* Pakfire_copy_in(PakfireObject
* self
, PyObject
* args
) {
1027 const char* src
= NULL
;
1028 const char* dst
= NULL
;
1030 if (!PyArg_ParseTuple(args
, "ss", &src
, &dst
))
1033 Py_BEGIN_ALLOW_THREADS
1035 int r
= pakfire_copy_in(self
->pakfire
, src
, dst
);
1038 PyErr_SetFromErrno(PyExc_OSError
);
1042 Py_END_ALLOW_THREADS
1047 static PyObject
* Pakfire_copy_out(PakfireObject
* self
, PyObject
* args
) {
1048 const char* src
= NULL
;
1049 const char* dst
= NULL
;
1051 if (!PyArg_ParseTuple(args
, "ss", &src
, &dst
))
1054 Py_BEGIN_ALLOW_THREADS
1056 int r
= pakfire_copy_out(self
->pakfire
, src
, dst
);
1059 PyErr_SetFromErrno(PyExc_OSError
);
1063 Py_END_ALLOW_THREADS
1068 static PyObject
* Pakfire_get_repos(PakfireObject
* self
) {
1069 struct pakfire_repolist
* repos
= pakfire_get_repos(self
->pakfire
);
1071 PyErr_SetFromErrno(PyExc_OSError
);
1075 const size_t l
= pakfire_repolist_size(repos
);
1077 PyObject
* list
= PyList_New(l
);
1081 for (unsigned int i
= 0; i
< l
; i
++) {
1082 struct pakfire_repo
* repo
= pakfire_repolist_get(repos
, i
);
1086 PyObject
* obj
= new_repo(&RepoType
, repo
);
1087 PyList_SET_ITEM(list
, i
, obj
);
1089 pakfire_repo_unref(repo
);
1093 pakfire_repolist_unref(repos
);
1098 static PyObject
* execute_return_value(int r
) {
1099 // Raise an OS error if r < 0
1103 PyErr_SetFromErrno(PyExc_OSError
);
1106 // Raise exception when the command failed
1108 PyObject
* code
= PyLong_FromLong(r
);
1110 PyErr_SetObject(PyExc_CommandExecutionError
, code
);
1119 static PyObject
* Pakfire_build(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
1131 struct pakfire_build
* build
= NULL
;
1132 const char* path
= NULL
;
1133 const char* target
= NULL
;
1134 const char* build_id
= NULL
;
1135 const char* ccache_path
= NULL
;
1136 int interactive
= 0;
1137 int disable_snapshot
= 0;
1138 int disable_ccache
= 0;
1139 int disable_tests
= 0;
1142 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s|zzzpppp", kwlist
,
1143 &path
, &target
, &build_id
, &ccache_path
, &interactive
,
1144 &disable_snapshot
, &disable_ccache
, &disable_tests
))
1150 flags
|= PAKFIRE_BUILD_INTERACTIVE
;
1152 // Disable snapshot if requested
1153 if (disable_snapshot
)
1154 flags
|= PAKFIRE_BUILD_DISABLE_SNAPSHOT
;
1156 // Disable ccache if requested
1158 flags
|= PAKFIRE_BUILD_DISABLE_CCACHE
;
1160 // Disable tests if requested
1162 flags
|= PAKFIRE_BUILD_DISABLE_TESTS
;
1164 // Create a new build environment
1165 r
= pakfire_build_create(&build
, self
->pakfire
, build_id
, flags
);
1167 PyErr_SetFromErrno(PyExc_OSError
);
1173 r
= pakfire_build_set_target(build
, target
);
1175 PyErr_SetFromErrno(PyExc_OSError
);
1182 r
= pakfire_build_set_ccache_path(build
, ccache_path
);
1184 PyErr_SetFromErrno(PyExc_OSError
);
1189 Py_BEGIN_ALLOW_THREADS
1192 r
= pakfire_build_exec(build
, path
);
1197 PyErr_SetFromErrno(PyExc_OSError
);
1199 // Raise a command execution error
1201 PyObject
* code
= PyLong_FromLong(r
);
1203 PyErr_SetObject(PyExc_CommandExecutionError
, code
);
1210 Py_END_ALLOW_THREADS
1214 pakfire_build_unref(build
);
1222 static PyObject
* Pakfire_shell(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
1228 char** packages
= NULL
;
1229 int disable_snapshot
= 0;
1233 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|O&p", kwlist
,
1234 convert_packages
, &packages
, &disable_snapshot
))
1239 if (disable_snapshot
)
1240 flags
|= PAKFIRE_BUILD_DISABLE_SNAPSHOT
;
1242 Py_BEGIN_ALLOW_THREADS
1244 r
= pakfire_shell(self
->pakfire
, (const char**)packages
, flags
);
1246 Py_END_ALLOW_THREADS
1248 return execute_return_value(r
);
1251 static PyObject
* Pakfire_clean(PakfireObject
* self
) {
1254 Py_BEGIN_ALLOW_THREADS
1256 r
= pakfire_clean(self
->pakfire
, 0);
1259 PyErr_SetFromErrno(PyExc_OSError
);
1263 Py_END_ALLOW_THREADS
1268 static PyObject
* Pakfire_refresh(PakfireObject
* self
, PyObject
* args
) {
1272 if (!PyArg_ParseTuple(args
, "|p", &force
))
1275 Py_BEGIN_ALLOW_THREADS
1277 r
= pakfire_refresh(self
->pakfire
, force
);
1280 PyErr_SetFromErrno(PyExc_OSError
);
1284 Py_END_ALLOW_THREADS
1289 static PyObject
* Pakfire_check(PakfireObject
* self
) {
1290 struct pakfire_filelist
* errors
= NULL
;
1293 // Allocate a filelist for errors
1294 r
= pakfire_filelist_create(&errors
, self
->pakfire
);
1298 Py_BEGIN_ALLOW_THREADS
1301 r
= pakfire_check(self
->pakfire
, errors
);
1303 Py_END_ALLOW_THREADS
1308 const size_t num_errors
= pakfire_filelist_length(errors
);
1310 // Did we find any errors?
1312 PyObject
* _errors
= PyList_FromFileList(errors
);
1316 pakfire_filelist_unref(errors
);
1318 // Raise CheckFileVerificationError
1319 PyErr_SetObject(PyExc_CheckFileVerificationError
, _errors
);
1324 pakfire_filelist_unref(errors
);
1330 pakfire_filelist_unref(errors
);
1332 // Raise exception from errno
1333 PyErr_SetFromErrno(PyExc_OSError
);
1337 static PyObject
* Pakfire_sync(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
1343 int keep_orphaned
= 0;
1345 PyObject
* status_callback
= NULL
;
1348 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|$pO", kwlist
,
1349 &keep_orphaned
, &status_callback
))
1353 flags
|= PAKFIRE_REQUEST_KEEP_ORPHANED
;
1355 Py_BEGIN_ALLOW_THREADS
1357 r
= pakfire_sync(self
->pakfire
, 0, flags
, NULL
,
1358 Pakfire_status_callback
, status_callback
);
1361 PyErr_SetFromErrno(PyExc_OSError
);
1365 Py_END_ALLOW_THREADS
1370 static PyObject
* Pakfire_open(PakfireObject
* self
, PyObject
* args
) {
1371 struct pakfire_archive
* archive
= NULL
;
1372 const char* path
= NULL
;
1374 if (!PyArg_ParseTuple(args
, "s", &path
))
1377 Py_BEGIN_ALLOW_THREADS
1379 int r
= pakfire_archive_open(&archive
, self
->pakfire
, path
);
1382 PyErr_SetFromErrno(PyExc_OSError
);
1386 Py_END_ALLOW_THREADS
1388 // Create Python object
1389 PyObject
* object
= new_archive(&ArchiveType
, archive
);
1390 pakfire_archive_unref(archive
);
1395 static PyObject
* Pakfire_repo_compose(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
1396 char* kwlist
[] = { "path", "files", "key", NULL
};
1397 const char* path
= NULL
;
1398 PyObject
* list
= NULL
;
1399 KeyObject
* key
= NULL
;
1401 PyObject
* ret
= NULL
;
1403 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "sO|O!", kwlist
, &path
, &list
, &KeyType
, &key
))
1406 // List must be a sequence
1407 if (!PySequence_Check(list
)) {
1408 PyErr_SetString(PyExc_ValueError
, "Expected a sequence.");
1412 // How many new files do we have?
1413 ssize_t num_files
= PySequence_Length(list
);
1417 // Allocate files array
1418 const char** files
= calloc(num_files
+ 1, sizeof(*files
));
1420 PyErr_SetFromErrno(PyExc_OSError
);
1424 for (int i
= 0; i
< num_files
; i
++) {
1425 PyObject
* file
= PySequence_GetItem(list
, i
);
1429 // Check if file is a Unicode object
1430 if (!PyUnicode_Check(file
)) {
1431 PyErr_SetString(PyExc_ValueError
, "Expected a string.");
1435 // Add pointer to string to files array
1436 files
[i
] = PyUnicode_AsUTF8(file
);
1443 Py_BEGIN_ALLOW_THREADS
1445 int r
= pakfire_repo_compose(self
->pakfire
, path
, (key
) ? key
->key
: NULL
, files
);
1448 PyErr_SetFromErrno(PyExc_OSError
);
1452 Py_END_ALLOW_THREADS
1454 // Return None on success
1465 static struct PyMethodDef Pakfire_methods
[] = {
1468 (PyCFunction
)Pakfire_build
,
1469 METH_VARARGS
|METH_KEYWORDS
,
1474 (PyCFunction
)Pakfire_check
,
1480 (PyCFunction
)Pakfire_clean
,
1486 (PyCFunction
)Pakfire_copy_in
,
1492 (PyCFunction
)Pakfire_copy_out
,
1498 (PyCFunction
)Pakfire_dist
,
1504 (PyCFunction
)Pakfire_erase
,
1505 METH_VARARGS
|METH_KEYWORDS
,
1510 (PyCFunction
)Pakfire_execute
,
1511 METH_VARARGS
|METH_KEYWORDS
,
1516 (PyCFunction
)Pakfire_generate_key
,
1517 METH_VARARGS
|METH_KEYWORDS
,
1522 (PyCFunction
)Pakfire_get_repo
,
1528 (PyCFunction
)Pakfire_import_key
,
1534 (PyCFunction
)Pakfire_install
,
1535 METH_VARARGS
|METH_KEYWORDS
,
1540 (PyCFunction
)Pakfire_open
,
1546 (PyCFunction
)Pakfire_refresh
,
1552 (PyCFunction
)Pakfire_repo_compose
,
1553 METH_VARARGS
|METH_KEYWORDS
,
1558 (PyCFunction
)Pakfire_search
,
1559 METH_VARARGS
|METH_KEYWORDS
,
1564 (PyCFunction
)Pakfire_shell
,
1565 METH_VARARGS
|METH_KEYWORDS
,
1570 (PyCFunction
)Pakfire_sync
,
1571 METH_VARARGS
|METH_KEYWORDS
,
1576 (PyCFunction
)Pakfire_update
,
1577 METH_VARARGS
|METH_KEYWORDS
,
1582 (PyCFunction
)Pakfire_version_compare
,
1588 (PyCFunction
)Pakfire_whatprovides
,
1594 (PyCFunction
)Pakfire_whatrequires
,
1601 static struct PyGetSetDef Pakfire_getsetters
[] = {
1604 (getter
)Pakfire_get_arch
,
1611 (getter
)Pakfire_get_path
,
1618 (getter
)Pakfire_get_repos
,
1626 PyTypeObject PakfireType
= {
1627 PyVarObject_HEAD_INIT(NULL
, 0)
1628 tp_name
: "_pakfire.Pakfire",
1629 tp_basicsize
: sizeof(PakfireObject
),
1630 tp_flags
: Py_TPFLAGS_DEFAULT
|Py_TPFLAGS_BASETYPE
,
1631 tp_new
: Pakfire_new
,
1632 tp_dealloc
: (destructor
)Pakfire_dealloc
,
1633 tp_init
: (initproc
)Pakfire_init
,
1634 tp_doc
: "Pakfire object",
1635 tp_methods
: Pakfire_methods
,
1636 tp_getset
: Pakfire_getsetters
,
1637 tp_repr
: (reprfunc
)Pakfire_repr
,