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
;
623 Py_ssize_t data_length
= 0;
627 if (!PyArg_ParseTuple(args
, "s#", &data
, &data_length
))
631 FILE* f
= fmemopen(data
, data_length
, "r");
636 r
= pakfire_key_import(&key
, self
->pakfire
, f
);
638 PyErr_SetFromErrno(PyExc_OSError
);
642 // Convert the key into a Key object
643 object
= new_key(&KeyType
, key
);
649 pakfire_key_unref(key
);
656 static PyObject
* Pakfire_whatprovides(PakfireObject
* self
, PyObject
* args
) {
657 const char* provides
= NULL
;
658 struct pakfire_packagelist
* list
= NULL
;
659 PyObject
* ret
= NULL
;
662 if (!PyArg_ParseTuple(args
, "s", &provides
))
666 r
= pakfire_packagelist_create(&list
, self
->pakfire
);
668 PyErr_SetFromErrno(PyExc_OSError
);
672 r
= pakfire_whatprovides(self
->pakfire
, provides
, 0, list
);
674 PyErr_SetFromErrno(PyExc_OSError
);
678 // Create a Python list from the package list
679 ret
= PyList_FromPackageList(list
);
683 pakfire_packagelist_unref(list
);
688 static PyObject
* Pakfire_whatrequires(PakfireObject
* self
, PyObject
* args
) {
689 const char* requires
= NULL
;
690 struct pakfire_packagelist
* list
= NULL
;
691 PyObject
* ret
= NULL
;
694 if (!PyArg_ParseTuple(args
, "s", &requires
))
697 Py_BEGIN_ALLOW_THREADS
700 r
= pakfire_packagelist_create(&list
, self
->pakfire
);
703 PyErr_SetFromErrno(PyExc_OSError
);
707 r
= pakfire_whatrequires(self
->pakfire
, requires
, 0, list
);
710 PyErr_SetFromErrno(PyExc_OSError
);
716 // Create a Python list from the package list
717 ret
= PyList_FromPackageList(list
);
721 pakfire_packagelist_unref(list
);
726 static PyObject
* Pakfire_search(PakfireObject
* self
, PyObject
* args
, PyObject
* kwds
) {
727 char* kwlist
[] = { "pattern", "name_only", NULL
};
728 struct pakfire_packagelist
* list
= NULL
;
729 const char* pattern
= NULL
;
732 PyObject
* ret
= NULL
;
735 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "s|$p", kwlist
, &pattern
, &name_only
))
738 // Search for package names only
740 flags
|= PAKFIRE_SEARCH_NAME_ONLY
;
742 r
= pakfire_packagelist_create(&list
, self
->pakfire
);
744 PyErr_SetFromErrno(PyExc_OSError
);
748 r
= pakfire_search(self
->pakfire
, pattern
, flags
, list
);
750 PyErr_SetFromErrno(PyExc_OSError
);
754 ret
= PyList_FromPackageList(list
);
758 pakfire_packagelist_unref(list
);
763 static PyObject
* Pakfire_version_compare(PakfireObject
* self
, PyObject
* args
) {
764 const char* evr1
= NULL
;
765 const char* evr2
= NULL
;
767 if (!PyArg_ParseTuple(args
, "ss", &evr1
, &evr2
))
770 int cmp
= pakfire_version_compare(self
->pakfire
, evr1
, evr2
);
772 return PyLong_FromLong(cmp
);
775 static int Pakfire_execute_output_callback(struct pakfire
* pakfire
, void* data
,
776 int priority
, const char* line
, size_t length
) {
777 PyObject
* callback
= (PyObject
*)data
;
780 // Do nothing if callback isn't set
784 // Translate priority to Python logging priorities
795 // Remove the trailing newline
796 if (line
&& line
[length
- 1] == '\n')
799 // Create tuple with arguments for the callback function
800 PyObject
* args
= Py_BuildValue("(is#)", priority
, line
, (Py_ssize_t
)length
);
804 PyObject
* result
= PyObject_CallObject(callback
, args
);
805 if (result
&& PyLong_Check(result
)) {
806 r
= PyLong_AsLong(result
);
815 static PyObject
* Pakfire_execute(PakfireObject
* self
, PyObject
* args
, PyObject
* kwds
) {
825 struct pakfire_jail
* jail
= NULL
;
826 const char** argv
= NULL
;
828 PyObject
* ret
= NULL
;
830 PyObject
* command
= NULL
;
831 PyObject
* environ
= NULL
;
832 PyObject
* bind
= NULL
;
833 PyObject
* callback
= NULL
;
836 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "O|OOOi", kwlist
, &command
, &environ
,
837 &bind
, &callback
, &nice
))
840 // Check if command is a list
841 if (!PyList_Check(command
)) {
842 PyErr_SetString(PyExc_TypeError
, "command must be a list");
846 const ssize_t command_length
= PyList_Size(command
);
848 // Check if command is not empty
849 if (command_length
== 0) {
850 PyErr_SetString(PyExc_ValueError
, "command is empty");
855 argv
= calloc(command_length
+ 1, sizeof(*argv
));
859 // All arguments in command must be strings
860 for (unsigned int i
= 0; i
< command_length
; i
++) {
861 PyObject
* item
= PyList_GET_ITEM(command
, i
);
863 if (!PyUnicode_Check(item
)) {
864 PyErr_Format(PyExc_TypeError
, "Item %u in command is not a string", i
);
869 argv
[i
] = PyUnicode_AsUTF8(item
);
872 // Check if bind is a sequence
873 if (bind
&& !PySequence_Check(bind
)) {
874 PyErr_SetString(PyExc_ValueError
, "bind is not a sequence");
879 if (callback
&& !PyCallable_Check(callback
)) {
880 PyErr_SetString(PyExc_TypeError
, "callback must be callable\n");
885 r
= pakfire_jail_create(&jail
, self
->pakfire
);
887 PyErr_SetFromErrno(PyExc_OSError
);
892 if (callback
&& !PyCallable_Check(callback
)) {
893 PyErr_SetString(PyExc_TypeError
, "callback must be callable\n");
899 r
= pakfire_jail_nice(jail
, nice
);
901 PyErr_SetFromErrno(PyExc_OSError
);
906 PyObject
* key
= NULL
;
907 PyObject
* value
= NULL
;
910 // Parse the environment
912 // Check if environ is a dictionary
913 if (!PyDict_Check(environ
)) {
914 PyErr_SetString(PyExc_TypeError
, "environ must be a dictionary");
918 // All keys and values must be strings
919 while (PyDict_Next(environ
, &p
, &key
, &value
)) {
920 if (!PyUnicode_Check(key
) || !PyUnicode_Check(value
)) {
921 PyErr_SetString(PyExc_TypeError
, "Environment contains a non-string object");
925 // Set environment value
926 r
= pakfire_jail_set_env(jail
, PyUnicode_AsUTF8(key
), PyUnicode_AsUTF8(value
));
928 PyErr_SetFromErrno(PyExc_OSError
);
934 const Py_ssize_t num_bind
= PySequence_Length(bind
);
937 for (unsigned int i
= 0; i
< num_bind
; i
++) {
938 PyObject
* b
= PySequence_ITEM(bind
, i
);
942 // Check if this is a Unicode object
943 if (!PyUnicode_Check(b
)) {
944 PyErr_SetString(PyExc_ValueError
, "bind contains a non-Unicode object");
949 const char* path
= PyUnicode_AsUTF8(b
);
952 r
= pakfire_jail_bind(jail
, path
, path
, 0);
954 PyErr_SetFromErrno(PyExc_OSError
);
962 Py_BEGIN_ALLOW_THREADS
965 r
= pakfire_jail_exec(jail
, argv
,
966 NULL
, Pakfire_execute_output_callback
, callback
, 0);
970 // If the return code was negative, we had some internal error
972 PyErr_SetFromErrno(PyExc_OSError
);
975 // Otherwise the executed command returned some error code
977 PyObject
* code
= PyLong_FromLong(r
);
979 // Raise CommandExecutionError
980 PyErr_SetObject(PyExc_CommandExecutionError
, code
);
986 // The process has exited successfully
996 pakfire_jail_unref(jail
);
1001 static PyObject
* Pakfire_dist(PakfireObject
* self
, PyObject
* args
) {
1002 const char* path
= NULL
;
1003 const char* target
= NULL
;
1004 char* result
= NULL
;
1007 if (!PyArg_ParseTuple(args
, "s|z", &path
, &target
))
1010 Py_BEGIN_ALLOW_THREADS
1012 r
= pakfire_dist(self
->pakfire
, path
, target
, &result
);
1015 PyErr_SetFromErrno(PyExc_OSError
);
1019 Py_END_ALLOW_THREADS
1021 PyObject
* ret
= PyUnicode_FromString(result
);
1027 static PyObject
* Pakfire_copy_in(PakfireObject
* self
, PyObject
* args
) {
1028 const char* src
= NULL
;
1029 const char* dst
= NULL
;
1031 if (!PyArg_ParseTuple(args
, "ss", &src
, &dst
))
1034 Py_BEGIN_ALLOW_THREADS
1036 int r
= pakfire_copy_in(self
->pakfire
, src
, dst
);
1039 PyErr_SetFromErrno(PyExc_OSError
);
1043 Py_END_ALLOW_THREADS
1048 static PyObject
* Pakfire_copy_out(PakfireObject
* self
, PyObject
* args
) {
1049 const char* src
= NULL
;
1050 const char* dst
= NULL
;
1052 if (!PyArg_ParseTuple(args
, "ss", &src
, &dst
))
1055 Py_BEGIN_ALLOW_THREADS
1057 int r
= pakfire_copy_out(self
->pakfire
, src
, dst
);
1060 PyErr_SetFromErrno(PyExc_OSError
);
1064 Py_END_ALLOW_THREADS
1069 static PyObject
* Pakfire_get_repos(PakfireObject
* self
) {
1070 struct pakfire_repolist
* repos
= pakfire_get_repos(self
->pakfire
);
1072 PyErr_SetFromErrno(PyExc_OSError
);
1076 const size_t l
= pakfire_repolist_size(repos
);
1078 PyObject
* list
= PyList_New(l
);
1082 for (unsigned int i
= 0; i
< l
; i
++) {
1083 struct pakfire_repo
* repo
= pakfire_repolist_get(repos
, i
);
1087 PyObject
* obj
= new_repo(&RepoType
, repo
);
1088 PyList_SET_ITEM(list
, i
, obj
);
1090 pakfire_repo_unref(repo
);
1094 pakfire_repolist_unref(repos
);
1099 static PyObject
* execute_return_value(int r
) {
1100 // Raise an OS error if r < 0
1104 PyErr_SetFromErrno(PyExc_OSError
);
1107 // Raise exception when the command failed
1109 PyObject
* code
= PyLong_FromLong(r
);
1111 PyErr_SetObject(PyExc_CommandExecutionError
, code
);
1120 static PyObject
* Pakfire_build(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
1132 struct pakfire_build
* build
= NULL
;
1133 const char* path
= NULL
;
1134 const char* target
= NULL
;
1135 const char* build_id
= NULL
;
1136 const char* ccache_path
= NULL
;
1137 int interactive
= 0;
1138 int disable_snapshot
= 0;
1139 int disable_ccache
= 0;
1140 int disable_tests
= 0;
1143 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s|zzzpppp", kwlist
,
1144 &path
, &target
, &build_id
, &ccache_path
, &interactive
,
1145 &disable_snapshot
, &disable_ccache
, &disable_tests
))
1151 flags
|= PAKFIRE_BUILD_INTERACTIVE
;
1153 // Disable snapshot if requested
1154 if (disable_snapshot
)
1155 flags
|= PAKFIRE_BUILD_DISABLE_SNAPSHOT
;
1157 // Disable ccache if requested
1159 flags
|= PAKFIRE_BUILD_DISABLE_CCACHE
;
1161 // Disable tests if requested
1163 flags
|= PAKFIRE_BUILD_DISABLE_TESTS
;
1165 // Create a new build environment
1166 r
= pakfire_build_create(&build
, self
->pakfire
, build_id
, flags
);
1168 PyErr_SetFromErrno(PyExc_OSError
);
1174 r
= pakfire_build_set_target(build
, target
);
1176 PyErr_SetFromErrno(PyExc_OSError
);
1183 r
= pakfire_build_set_ccache_path(build
, ccache_path
);
1185 PyErr_SetFromErrno(PyExc_OSError
);
1190 Py_BEGIN_ALLOW_THREADS
1193 r
= pakfire_build_exec(build
, path
);
1198 PyErr_SetFromErrno(PyExc_OSError
);
1200 // Raise a command execution error
1202 PyObject
* code
= PyLong_FromLong(r
);
1204 PyErr_SetObject(PyExc_CommandExecutionError
, code
);
1211 Py_END_ALLOW_THREADS
1215 pakfire_build_unref(build
);
1223 static PyObject
* Pakfire_shell(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
1229 char** packages
= NULL
;
1230 int disable_snapshot
= 0;
1234 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|O&p", kwlist
,
1235 convert_packages
, &packages
, &disable_snapshot
))
1240 if (disable_snapshot
)
1241 flags
|= PAKFIRE_BUILD_DISABLE_SNAPSHOT
;
1243 Py_BEGIN_ALLOW_THREADS
1245 r
= pakfire_shell(self
->pakfire
, (const char**)packages
, flags
);
1247 Py_END_ALLOW_THREADS
1249 return execute_return_value(r
);
1252 static PyObject
* Pakfire_clean(PakfireObject
* self
) {
1255 Py_BEGIN_ALLOW_THREADS
1257 r
= pakfire_clean(self
->pakfire
, 0);
1260 PyErr_SetFromErrno(PyExc_OSError
);
1264 Py_END_ALLOW_THREADS
1269 static PyObject
* Pakfire_refresh(PakfireObject
* self
, PyObject
* args
) {
1273 if (!PyArg_ParseTuple(args
, "|p", &force
))
1276 Py_BEGIN_ALLOW_THREADS
1278 r
= pakfire_refresh(self
->pakfire
, force
);
1281 PyErr_SetFromErrno(PyExc_OSError
);
1285 Py_END_ALLOW_THREADS
1290 static PyObject
* Pakfire_check(PakfireObject
* self
) {
1291 struct pakfire_filelist
* errors
= NULL
;
1294 // Allocate a filelist for errors
1295 r
= pakfire_filelist_create(&errors
, self
->pakfire
);
1299 Py_BEGIN_ALLOW_THREADS
1302 r
= pakfire_check(self
->pakfire
, errors
);
1304 Py_END_ALLOW_THREADS
1309 const size_t num_errors
= pakfire_filelist_length(errors
);
1311 // Did we find any errors?
1313 PyObject
* _errors
= PyList_FromFileList(errors
);
1317 pakfire_filelist_unref(errors
);
1319 // Raise CheckFileVerificationError
1320 PyErr_SetObject(PyExc_CheckFileVerificationError
, _errors
);
1325 pakfire_filelist_unref(errors
);
1331 pakfire_filelist_unref(errors
);
1333 // Raise exception from errno
1334 PyErr_SetFromErrno(PyExc_OSError
);
1338 static PyObject
* Pakfire_sync(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
1344 int keep_orphaned
= 0;
1346 PyObject
* status_callback
= NULL
;
1349 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|$pO", kwlist
,
1350 &keep_orphaned
, &status_callback
))
1354 flags
|= PAKFIRE_REQUEST_KEEP_ORPHANED
;
1356 Py_BEGIN_ALLOW_THREADS
1358 r
= pakfire_sync(self
->pakfire
, 0, flags
, NULL
,
1359 Pakfire_status_callback
, status_callback
);
1362 PyErr_SetFromErrno(PyExc_OSError
);
1366 Py_END_ALLOW_THREADS
1371 static PyObject
* Pakfire_open(PakfireObject
* self
, PyObject
* args
) {
1372 struct pakfire_archive
* archive
= NULL
;
1373 const char* path
= NULL
;
1375 if (!PyArg_ParseTuple(args
, "s", &path
))
1378 Py_BEGIN_ALLOW_THREADS
1380 int r
= pakfire_archive_open(&archive
, self
->pakfire
, path
);
1383 PyErr_SetFromErrno(PyExc_OSError
);
1387 Py_END_ALLOW_THREADS
1389 // Create Python object
1390 PyObject
* object
= new_archive(&ArchiveType
, archive
);
1391 pakfire_archive_unref(archive
);
1396 static PyObject
* Pakfire_repo_compose(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
1397 char* kwlist
[] = { "path", "files", "key", NULL
};
1398 const char* path
= NULL
;
1399 PyObject
* list
= NULL
;
1400 KeyObject
* key
= NULL
;
1402 PyObject
* ret
= NULL
;
1404 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "sO|O!", kwlist
, &path
, &list
, &KeyType
, &key
))
1407 // List must be a sequence
1408 if (!PySequence_Check(list
)) {
1409 PyErr_SetString(PyExc_ValueError
, "Expected a sequence.");
1413 // How many new files do we have?
1414 ssize_t num_files
= PySequence_Length(list
);
1418 // Allocate files array
1419 const char** files
= calloc(num_files
+ 1, sizeof(*files
));
1421 PyErr_SetFromErrno(PyExc_OSError
);
1425 for (int i
= 0; i
< num_files
; i
++) {
1426 PyObject
* file
= PySequence_GetItem(list
, i
);
1430 // Check if file is a Unicode object
1431 if (!PyUnicode_Check(file
)) {
1432 PyErr_SetString(PyExc_ValueError
, "Expected a string.");
1436 // Add pointer to string to files array
1437 files
[i
] = PyUnicode_AsUTF8(file
);
1444 Py_BEGIN_ALLOW_THREADS
1446 int r
= pakfire_repo_compose(self
->pakfire
, path
, (key
) ? key
->key
: NULL
, files
);
1449 PyErr_SetFromErrno(PyExc_OSError
);
1453 Py_END_ALLOW_THREADS
1455 // Return None on success
1466 static struct PyMethodDef Pakfire_methods
[] = {
1469 (PyCFunction
)Pakfire_build
,
1470 METH_VARARGS
|METH_KEYWORDS
,
1475 (PyCFunction
)Pakfire_check
,
1481 (PyCFunction
)Pakfire_clean
,
1487 (PyCFunction
)Pakfire_copy_in
,
1493 (PyCFunction
)Pakfire_copy_out
,
1499 (PyCFunction
)Pakfire_dist
,
1505 (PyCFunction
)Pakfire_erase
,
1506 METH_VARARGS
|METH_KEYWORDS
,
1511 (PyCFunction
)Pakfire_execute
,
1512 METH_VARARGS
|METH_KEYWORDS
,
1517 (PyCFunction
)Pakfire_generate_key
,
1518 METH_VARARGS
|METH_KEYWORDS
,
1523 (PyCFunction
)Pakfire_get_repo
,
1529 (PyCFunction
)Pakfire_import_key
,
1535 (PyCFunction
)Pakfire_install
,
1536 METH_VARARGS
|METH_KEYWORDS
,
1541 (PyCFunction
)Pakfire_open
,
1547 (PyCFunction
)Pakfire_refresh
,
1553 (PyCFunction
)Pakfire_repo_compose
,
1554 METH_VARARGS
|METH_KEYWORDS
,
1559 (PyCFunction
)Pakfire_search
,
1560 METH_VARARGS
|METH_KEYWORDS
,
1565 (PyCFunction
)Pakfire_shell
,
1566 METH_VARARGS
|METH_KEYWORDS
,
1571 (PyCFunction
)Pakfire_sync
,
1572 METH_VARARGS
|METH_KEYWORDS
,
1577 (PyCFunction
)Pakfire_update
,
1578 METH_VARARGS
|METH_KEYWORDS
,
1583 (PyCFunction
)Pakfire_version_compare
,
1589 (PyCFunction
)Pakfire_whatprovides
,
1595 (PyCFunction
)Pakfire_whatrequires
,
1602 static struct PyGetSetDef Pakfire_getsetters
[] = {
1605 (getter
)Pakfire_get_arch
,
1612 (getter
)Pakfire_get_path
,
1619 (getter
)Pakfire_get_repos
,
1627 PyTypeObject PakfireType
= {
1628 PyVarObject_HEAD_INIT(NULL
, 0)
1629 tp_name
: "_pakfire.Pakfire",
1630 tp_basicsize
: sizeof(PakfireObject
),
1631 tp_flags
: Py_TPFLAGS_DEFAULT
|Py_TPFLAGS_BASETYPE
,
1632 tp_new
: Pakfire_new
,
1633 tp_dealloc
: (destructor
)Pakfire_dealloc
,
1634 tp_init
: (initproc
)Pakfire_init
,
1635 tp_doc
: "Pakfire object",
1636 tp_methods
: Pakfire_methods
,
1637 tp_getset
: Pakfire_getsetters
,
1638 tp_repr
: (reprfunc
)Pakfire_repr
,