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
;
65 PyObject
* type
= NULL
;
66 PyObject
* value
= NULL
;
67 PyObject
* traceback
= NULL
;
69 // Do nothing if callback isn't set
73 PyGILState_STATE state
= PyGILState_Ensure();
75 // Translate priority to Python logging priorities
89 // Drop messages of an unknown priority
94 PyObject
* tuple
= NULL
;
95 PyObject
* result
= NULL
;
99 int r
= vasprintf(&buffer
, format
, args
);
103 // Build a tuple with the priority and the log message
104 tuple
= Py_BuildValue("(is)", priority
, buffer
);
109 result
= PyObject_CallObject(callback
, tuple
);
113 We cannot really catch any Python errors here, since we cannot send
114 any error codes up the chain.
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.
119 exception
= PyErr_Occurred();
123 // Fetch the exception and destroy it
124 PyErr_Fetch(&type
, &value
, &traceback
);
128 Py_XDECREF(traceback
);
137 PyGILState_Release(state
);
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
;
146 // Do nothing if callback isn't set
151 PyGILState_STATE state
= PyGILState_Ensure();
153 PyObject
* args
= Py_BuildValue("(ss)", message
, question
);
159 result
= PyObject_CallObject(callback
, args
);
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
168 // Set the return code
169 if (result
== Py_True
)
179 PyGILState_Release(state
);
184 static int Pakfire_init(PakfireObject
* self
, PyObject
* args
, PyObject
* kwds
) {
194 const char* path
= NULL
;
195 const char* arch
= NULL
;
196 PyObject
* conf
= Py_None
;
202 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "|zzOpOO", kwlist
,
203 &path
, &arch
, &self
->callbacks
.log
, &offline
, &conf
, &self
->callbacks
.confirm
))
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");
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");
218 // Map the configuration
219 if (conf
!= Py_None
) {
220 fconf
= PyObject_AsFileHandle(conf
, "r");
227 // Enable offline mode
229 flags
|= PAKFIRE_FLAGS_OFFLINE
;
231 // Configure callbacks
232 if (self
->callbacks
.log
)
233 Py_INCREF(self
->callbacks
.log
);
235 Py_BEGIN_ALLOW_THREADS
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
);
247 // Invalid architecture or path
249 PyErr_SetString(PyExc_ValueError
, "Invalid architecture or path");
254 PyErr_SetFromErrno(PyExc_OSError
);
261 // Configure confirm callback
262 if (self
->callbacks
.confirm
) {
263 pakfire_set_confirm_callback(self
->pakfire
,
264 Pakfire_confirm_callback
, self
->callbacks
.confirm
);
266 Py_INCREF(self
->callbacks
.confirm
);
276 static void Pakfire_dealloc(PakfireObject
* self
) {
278 // Reset log callback
279 if (self
->callbacks
.log
) {
280 pakfire_set_log_callback(self
->pakfire
, NULL
, NULL
);
281 Py_DECREF(self
->callbacks
.log
);
284 // Reset confirm callback
285 if (self
->callbacks
.confirm
) {
286 pakfire_set_confirm_callback(self
->pakfire
, NULL
, NULL
);
287 Py_DECREF(self
->callbacks
.confirm
);
290 Py_BEGIN_ALLOW_THREADS
292 pakfire_unref(self
->pakfire
);
297 Py_TYPE(self
)->tp_free((PyObject
*)self
);
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
);
304 return PyUnicode_FromFormat("<_pakfire.Pakfire %s (%s)>", path
, arch
);
307 static PyObject
* Pakfire_get_path(PakfireObject
* self
) {
308 const char* path
= pakfire_get_path(self
->pakfire
);
310 return PyUnicode_FromString(path
);
313 static PyObject
* Pakfire_get_arch(PakfireObject
* self
) {
314 const char* arch
= pakfire_get_arch(self
->pakfire
);
316 return PyUnicode_FromString(arch
);
319 static PyObject
* Pakfire_get_repo(PakfireObject
* self
, PyObject
* args
) {
320 const char* name
= NULL
;
322 if (!PyArg_ParseTuple(args
, "s", &name
))
325 struct pakfire_repo
* repo
= pakfire_get_repo(self
->pakfire
, name
);
329 PyObject
* obj
= new_repo(&RepoType
, repo
);
330 pakfire_repo_unref(repo
);
335 static void Pakfire_status_callback(struct pakfire
* pakfire
, void* data
,
336 int progress
, const char* status
) {
337 PyObject
* callback
= (PyObject
*)data
;
339 // Do not attempt to call nothing
344 PyGILState_STATE state
= PyGILState_Ensure();
347 PyObject
* args
= Py_BuildValue("(is)", progress
, status
);
350 PyObject
* result
= PyObject_CallObject(callback
, args
);
357 PyGILState_Release(state
);
360 static int convert_packages(PyObject
* object
, void* address
) {
361 char*** packages
= (char***)address
;
363 // Called for cleanup
367 // Nothing to do when object is None
368 if (object
== Py_None
)
369 return Py_CLEANUP_SUPPORTED
;
371 if (!PySequence_Check(object
)) {
372 PyErr_SetString(PyExc_ValueError
, "Packages must be a sequence");
376 const unsigned int length
= PySequence_Length(object
);
378 return Py_CLEANUP_SUPPORTED
;
381 *packages
= calloc(length
+ 1, sizeof(*packages
));
383 PyErr_SetFromErrno(PyExc_OSError
);
387 for (unsigned int i
= 0; i
< length
; i
++) {
388 PyObject
* item
= PySequence_GetItem(object
, i
);
390 // Check if input is a string
391 if (!PyUnicode_Check(item
)) {
394 PyErr_SetString(PyExc_AttributeError
, "Expected a string");
399 const char* package
= PyUnicode_AsUTF8(item
);
405 // Add package to array
406 (*packages
)[i
] = strdup(package
);
407 if (!(*packages
)[i
]) {
416 return Py_CLEANUP_SUPPORTED
;
420 for (char** package
= *packages
; *package
; package
++)
428 static PyObject
* Pakfire_install(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
432 "without_recommended",
438 char** packages
= NULL
;
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
;
448 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "O&|$ppppO", kwlist
,
449 convert_packages
, &packages
, &dryrun
, &without_recommended
, &allow_uninstall
,
450 &allow_downgrade
, &status_callback
))
453 // Check if callback is callable
454 if (status_callback
&& !PyCallable_Check(status_callback
)) {
455 PyErr_SetString(PyExc_TypeError
, "status_callback must be callable");
459 // Enable dry-run mode
461 transaction_flags
|= PAKFIRE_TRANSACTION_DRY_RUN
;
463 // Do not install recommended packages
464 if (without_recommended
)
465 solver_flags
|= PAKFIRE_REQUEST_WITHOUT_RECOMMENDED
;
467 // Can the solver uninstall packages?
469 solver_flags
|= PAKFIRE_REQUEST_ALLOW_UNINSTALL
;
471 // Can the solver downgrade packages?
473 solver_flags
|= PAKFIRE_REQUEST_ALLOW_DOWNGRADE
;
475 Py_BEGIN_ALLOW_THREADS
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
);
484 PyErr_SetFromErrno(PyExc_OSError
);
487 for (char** package
= packages
; *package
; package
++)
498 static PyObject
* Pakfire_erase(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
506 char** packages
= NULL
;
508 int keep_dependencies
= 0;
509 int transaction_flags
= 0;
511 PyObject
* status_callback
= NULL
;
514 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "O&|$ppO", kwlist
,
515 convert_packages
, &packages
, &dryrun
, &keep_dependencies
, &status_callback
))
518 // Check if callback is callable
519 if (status_callback
&& !PyCallable_Check(status_callback
)) {
520 PyErr_SetString(PyExc_TypeError
, "status_callback must be callable");
525 transaction_flags
|= PAKFIRE_TRANSACTION_DRY_RUN
;
527 if (keep_dependencies
)
528 flags
|= PAKFIRE_REQUEST_KEEP_DEPS
;
530 Py_BEGIN_ALLOW_THREADS
533 r
= pakfire_erase(self
->pakfire
, transaction_flags
, 0, (const char**)packages
,
534 NULL
, flags
, NULL
, Pakfire_status_callback
, status_callback
);
539 PyErr_SetFromErrno(PyExc_OSError
);
542 for (char** package
= packages
; *package
; package
++)
553 static PyObject
* Pakfire_update(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
563 char** packages
= NULL
;
564 char** excludes
= NULL
;
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
;
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
))
578 // Check if callback is callable
579 if (status_callback
&& !PyCallable_Check(status_callback
)) {
580 PyErr_SetString(PyExc_TypeError
, "status_callback must be callable");
585 transaction_flags
= PAKFIRE_TRANSACTION_DRY_RUN
;
587 // Can the solver uninstall packages?
589 solver_flags
|= PAKFIRE_REQUEST_ALLOW_UNINSTALL
;
591 // Can the solver downgrade packages?
593 solver_flags
|= PAKFIRE_REQUEST_ALLOW_DOWNGRADE
;
595 Py_BEGIN_ALLOW_THREADS
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
);
605 PyErr_SetFromErrno(PyExc_OSError
);
608 for (char** package
= packages
; *package
; package
++)
614 for (char** exclude
= excludes
; *exclude
; exclude
++)
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
;
631 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "is", kwlist
, &algo
, &comment
))
634 // Generate a new key
635 int r
= pakfire_key_generate(&key
, self
->pakfire
, algo
, comment
);
637 PyErr_SetFromErrno(PyExc_OSError
);
641 PyObject
* object
= new_key(&KeyType
, key
);
642 pakfire_key_unref(key
);
647 static PyObject
* Pakfire_import_key(PakfireObject
* self
, PyObject
* args
) {
648 struct pakfire_key
* key
= NULL
;
649 PyObject
* object
= NULL
;
651 Py_ssize_t data_length
= 0;
655 if (!PyArg_ParseTuple(args
, "s#", &data
, &data_length
))
659 FILE* f
= fmemopen(data
, data_length
, "r");
664 r
= pakfire_key_import(&key
, self
->pakfire
, f
);
666 PyErr_SetFromErrno(PyExc_OSError
);
670 // Convert the key into a Key object
671 object
= new_key(&KeyType
, key
);
677 pakfire_key_unref(key
);
684 static PyObject
* Pakfire_whatprovides(PakfireObject
* self
, PyObject
* args
) {
685 const char* provides
= NULL
;
686 struct pakfire_packagelist
* list
= NULL
;
687 PyObject
* ret
= NULL
;
690 if (!PyArg_ParseTuple(args
, "s", &provides
))
694 r
= pakfire_packagelist_create(&list
, self
->pakfire
);
696 PyErr_SetFromErrno(PyExc_OSError
);
700 r
= pakfire_whatprovides(self
->pakfire
, provides
, 0, list
);
702 PyErr_SetFromErrno(PyExc_OSError
);
706 // Create a Python list from the package list
707 ret
= PyList_FromPackageList(list
);
711 pakfire_packagelist_unref(list
);
716 static PyObject
* Pakfire_whatrequires(PakfireObject
* self
, PyObject
* args
) {
717 const char* requires
= NULL
;
718 struct pakfire_packagelist
* list
= NULL
;
719 PyObject
* ret
= NULL
;
722 if (!PyArg_ParseTuple(args
, "s", &requires
))
725 Py_BEGIN_ALLOW_THREADS
728 r
= pakfire_packagelist_create(&list
, self
->pakfire
);
731 PyErr_SetFromErrno(PyExc_OSError
);
735 r
= pakfire_whatrequires(self
->pakfire
, requires
, 0, list
);
738 PyErr_SetFromErrno(PyExc_OSError
);
744 // Create a Python list from the package list
745 ret
= PyList_FromPackageList(list
);
749 pakfire_packagelist_unref(list
);
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
;
760 PyObject
* ret
= NULL
;
763 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "s|$p", kwlist
, &pattern
, &name_only
))
766 // Search for package names only
768 flags
|= PAKFIRE_SEARCH_NAME_ONLY
;
770 r
= pakfire_packagelist_create(&list
, self
->pakfire
);
772 PyErr_SetFromErrno(PyExc_OSError
);
776 r
= pakfire_search(self
->pakfire
, pattern
, flags
, list
);
778 PyErr_SetFromErrno(PyExc_OSError
);
782 ret
= PyList_FromPackageList(list
);
786 pakfire_packagelist_unref(list
);
791 static PyObject
* Pakfire_version_compare(PakfireObject
* self
, PyObject
* args
) {
792 const char* evr1
= NULL
;
793 const char* evr2
= NULL
;
795 if (!PyArg_ParseTuple(args
, "ss", &evr1
, &evr2
))
798 int cmp
= pakfire_version_compare(self
->pakfire
, evr1
, evr2
);
800 return PyLong_FromLong(cmp
);
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
;
808 // Do nothing if callback isn't set
812 // Translate priority to Python logging priorities
823 // Remove the trailing newline
824 if (line
&& line
[length
- 1] == '\n')
827 // Create tuple with arguments for the callback function
828 PyObject
* args
= Py_BuildValue("(is#)", priority
, line
, (Py_ssize_t
)length
);
832 PyObject
* result
= PyObject_CallObject(callback
, args
);
833 if (result
&& PyLong_Check(result
)) {
834 r
= PyLong_AsLong(result
);
843 static PyObject
* Pakfire_execute(PakfireObject
* self
, PyObject
* args
, PyObject
* kwds
) {
853 struct pakfire_jail
* jail
= NULL
;
854 const char** argv
= NULL
;
856 PyObject
* ret
= NULL
;
858 PyObject
* command
= NULL
;
859 PyObject
* environ
= NULL
;
860 PyObject
* bind
= NULL
;
861 PyObject
* callback
= NULL
;
864 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "O|OOOi", kwlist
, &command
, &environ
,
865 &bind
, &callback
, &nice
))
868 // Check if command is a list
869 if (!PyList_Check(command
)) {
870 PyErr_SetString(PyExc_TypeError
, "command must be a list");
874 const ssize_t command_length
= PyList_Size(command
);
876 // Check if command is not empty
877 if (command_length
== 0) {
878 PyErr_SetString(PyExc_ValueError
, "command is empty");
883 argv
= calloc(command_length
+ 1, sizeof(*argv
));
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
);
891 if (!PyUnicode_Check(item
)) {
892 PyErr_Format(PyExc_TypeError
, "Item %u in command is not a string", i
);
897 argv
[i
] = PyUnicode_AsUTF8(item
);
900 // Check if bind is a sequence
901 if (bind
&& !PySequence_Check(bind
)) {
902 PyErr_SetString(PyExc_ValueError
, "bind is not a sequence");
907 if (callback
&& !PyCallable_Check(callback
)) {
908 PyErr_SetString(PyExc_TypeError
, "callback must be callable\n");
913 r
= pakfire_jail_create(&jail
, self
->pakfire
);
915 PyErr_SetFromErrno(PyExc_OSError
);
920 if (callback
&& !PyCallable_Check(callback
)) {
921 PyErr_SetString(PyExc_TypeError
, "callback must be callable\n");
927 r
= pakfire_jail_nice(jail
, nice
);
929 PyErr_SetFromErrno(PyExc_OSError
);
934 PyObject
* key
= NULL
;
935 PyObject
* value
= NULL
;
938 // Parse the environment
940 // Check if environ is a dictionary
941 if (!PyDict_Check(environ
)) {
942 PyErr_SetString(PyExc_TypeError
, "environ must be a dictionary");
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");
953 // Set environment value
954 r
= pakfire_jail_set_env(jail
, PyUnicode_AsUTF8(key
), PyUnicode_AsUTF8(value
));
956 PyErr_SetFromErrno(PyExc_OSError
);
962 const Py_ssize_t num_bind
= PySequence_Length(bind
);
965 for (unsigned int i
= 0; i
< num_bind
; i
++) {
966 PyObject
* b
= PySequence_ITEM(bind
, i
);
970 // Check if this is a Unicode object
971 if (!PyUnicode_Check(b
)) {
972 PyErr_SetString(PyExc_ValueError
, "bind contains a non-Unicode object");
977 const char* path
= PyUnicode_AsUTF8(b
);
980 r
= pakfire_jail_bind(jail
, path
, path
, 0);
982 PyErr_SetFromErrno(PyExc_OSError
);
990 Py_BEGIN_ALLOW_THREADS
993 r
= pakfire_jail_exec(jail
, argv
,
994 NULL
, Pakfire_execute_output_callback
, callback
, 0);
998 // If the return code was negative, we had some internal error
1000 PyErr_SetFromErrno(PyExc_OSError
);
1003 // Otherwise the executed command returned some error code
1005 PyObject
* code
= PyLong_FromLong(r
);
1007 // Raise CommandExecutionError
1008 PyErr_SetObject(PyExc_CommandExecutionError
, code
);
1014 // The process has exited successfully
1024 pakfire_jail_unref(jail
);
1029 static PyObject
* Pakfire_dist(PakfireObject
* self
, PyObject
* args
) {
1030 const char* path
= NULL
;
1031 const char* target
= NULL
;
1032 char* result
= NULL
;
1035 if (!PyArg_ParseTuple(args
, "s|z", &path
, &target
))
1038 Py_BEGIN_ALLOW_THREADS
1040 r
= pakfire_dist(self
->pakfire
, path
, target
, &result
);
1043 PyErr_SetFromErrno(PyExc_OSError
);
1047 Py_END_ALLOW_THREADS
1049 PyObject
* ret
= PyUnicode_FromString(result
);
1055 static PyObject
* Pakfire_copy_in(PakfireObject
* self
, PyObject
* args
) {
1056 const char* src
= NULL
;
1057 const char* dst
= NULL
;
1059 if (!PyArg_ParseTuple(args
, "ss", &src
, &dst
))
1062 Py_BEGIN_ALLOW_THREADS
1064 int r
= pakfire_copy_in(self
->pakfire
, src
, dst
);
1067 PyErr_SetFromErrno(PyExc_OSError
);
1071 Py_END_ALLOW_THREADS
1076 static PyObject
* Pakfire_copy_out(PakfireObject
* self
, PyObject
* args
) {
1077 const char* src
= NULL
;
1078 const char* dst
= NULL
;
1080 if (!PyArg_ParseTuple(args
, "ss", &src
, &dst
))
1083 Py_BEGIN_ALLOW_THREADS
1085 int r
= pakfire_copy_out(self
->pakfire
, src
, dst
);
1088 PyErr_SetFromErrno(PyExc_OSError
);
1092 Py_END_ALLOW_THREADS
1097 static PyObject
* Pakfire_get_repos(PakfireObject
* self
) {
1098 struct pakfire_repolist
* repos
= pakfire_get_repos(self
->pakfire
);
1100 PyErr_SetFromErrno(PyExc_OSError
);
1104 const size_t l
= pakfire_repolist_size(repos
);
1106 PyObject
* list
= PyList_New(l
);
1110 for (unsigned int i
= 0; i
< l
; i
++) {
1111 struct pakfire_repo
* repo
= pakfire_repolist_get(repos
, i
);
1115 PyObject
* obj
= new_repo(&RepoType
, repo
);
1116 PyList_SET_ITEM(list
, i
, obj
);
1118 pakfire_repo_unref(repo
);
1122 pakfire_repolist_unref(repos
);
1127 static PyObject
* execute_return_value(int r
) {
1128 // Raise an OS error if r < 0
1132 PyErr_SetFromErrno(PyExc_OSError
);
1135 // Raise exception when the command failed
1137 PyObject
* code
= PyLong_FromLong(r
);
1139 PyErr_SetObject(PyExc_CommandExecutionError
, code
);
1148 static PyObject
* Pakfire_build(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
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;
1171 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "s|zzzpppp", kwlist
,
1172 &path
, &target
, &build_id
, &ccache_path
, &interactive
,
1173 &disable_snapshot
, &disable_ccache
, &disable_tests
))
1179 flags
|= PAKFIRE_BUILD_INTERACTIVE
;
1181 // Disable snapshot if requested
1182 if (disable_snapshot
)
1183 flags
|= PAKFIRE_BUILD_DISABLE_SNAPSHOT
;
1185 // Disable ccache if requested
1187 flags
|= PAKFIRE_BUILD_DISABLE_CCACHE
;
1189 // Disable tests if requested
1191 flags
|= PAKFIRE_BUILD_DISABLE_TESTS
;
1193 // Create a new build environment
1194 r
= pakfire_build_create(&build
, self
->pakfire
, build_id
, flags
);
1196 PyErr_SetFromErrno(PyExc_OSError
);
1202 r
= pakfire_build_set_target(build
, target
);
1204 PyErr_SetFromErrno(PyExc_OSError
);
1211 r
= pakfire_build_set_ccache_path(build
, ccache_path
);
1213 PyErr_SetFromErrno(PyExc_OSError
);
1218 Py_BEGIN_ALLOW_THREADS
1221 r
= pakfire_build_exec(build
, path
);
1226 PyErr_SetFromErrno(PyExc_OSError
);
1228 // Raise a command execution error
1230 PyObject
* code
= PyLong_FromLong(r
);
1232 PyErr_SetObject(PyExc_CommandExecutionError
, code
);
1239 Py_END_ALLOW_THREADS
1243 pakfire_build_unref(build
);
1251 static PyObject
* Pakfire_shell(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
1257 char** packages
= NULL
;
1258 int disable_snapshot
= 0;
1262 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|O&p", kwlist
,
1263 convert_packages
, &packages
, &disable_snapshot
))
1268 if (disable_snapshot
)
1269 flags
|= PAKFIRE_BUILD_DISABLE_SNAPSHOT
;
1271 Py_BEGIN_ALLOW_THREADS
1273 r
= pakfire_shell(self
->pakfire
, (const char**)packages
, flags
);
1275 Py_END_ALLOW_THREADS
1277 return execute_return_value(r
);
1280 static PyObject
* Pakfire_clean(PakfireObject
* self
) {
1283 Py_BEGIN_ALLOW_THREADS
1285 r
= pakfire_clean(self
->pakfire
, 0);
1288 PyErr_SetFromErrno(PyExc_OSError
);
1292 Py_END_ALLOW_THREADS
1297 static PyObject
* Pakfire_refresh(PakfireObject
* self
, PyObject
* args
) {
1301 if (!PyArg_ParseTuple(args
, "|p", &force
))
1304 Py_BEGIN_ALLOW_THREADS
1306 r
= pakfire_refresh(self
->pakfire
, force
);
1309 PyErr_SetFromErrno(PyExc_OSError
);
1313 Py_END_ALLOW_THREADS
1318 static PyObject
* Pakfire_check(PakfireObject
* self
) {
1319 struct pakfire_filelist
* errors
= NULL
;
1322 // Allocate a filelist for errors
1323 r
= pakfire_filelist_create(&errors
, self
->pakfire
);
1327 Py_BEGIN_ALLOW_THREADS
1330 r
= pakfire_check(self
->pakfire
, errors
);
1332 Py_END_ALLOW_THREADS
1337 const size_t num_errors
= pakfire_filelist_length(errors
);
1339 // Did we find any errors?
1341 PyObject
* _errors
= PyList_FromFileList(errors
);
1345 pakfire_filelist_unref(errors
);
1347 // Raise CheckFileVerificationError
1348 PyErr_SetObject(PyExc_CheckFileVerificationError
, _errors
);
1353 pakfire_filelist_unref(errors
);
1359 pakfire_filelist_unref(errors
);
1361 // Raise exception from errno
1362 PyErr_SetFromErrno(PyExc_OSError
);
1366 static PyObject
* Pakfire_sync(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
1372 int keep_orphaned
= 0;
1374 PyObject
* status_callback
= NULL
;
1377 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "|$pO", kwlist
,
1378 &keep_orphaned
, &status_callback
))
1382 flags
|= PAKFIRE_REQUEST_KEEP_ORPHANED
;
1384 Py_BEGIN_ALLOW_THREADS
1386 r
= pakfire_sync(self
->pakfire
, 0, flags
, NULL
,
1387 Pakfire_status_callback
, status_callback
);
1390 PyErr_SetFromErrno(PyExc_OSError
);
1394 Py_END_ALLOW_THREADS
1399 static PyObject
* Pakfire_open(PakfireObject
* self
, PyObject
* args
) {
1400 struct pakfire_archive
* archive
= NULL
;
1401 const char* path
= NULL
;
1403 if (!PyArg_ParseTuple(args
, "s", &path
))
1406 Py_BEGIN_ALLOW_THREADS
1408 int r
= pakfire_archive_open(&archive
, self
->pakfire
, path
);
1411 PyErr_SetFromErrno(PyExc_OSError
);
1415 Py_END_ALLOW_THREADS
1417 // Create Python object
1418 PyObject
* object
= new_archive(&ArchiveType
, archive
);
1419 pakfire_archive_unref(archive
);
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
;
1430 PyObject
* ret
= NULL
;
1432 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "sO|O!", kwlist
, &path
, &list
, &KeyType
, &key
))
1435 // List must be a sequence
1436 if (!PySequence_Check(list
)) {
1437 PyErr_SetString(PyExc_ValueError
, "Expected a sequence.");
1441 // How many new files do we have?
1442 ssize_t num_files
= PySequence_Length(list
);
1446 // Allocate files array
1447 const char** files
= calloc(num_files
+ 1, sizeof(*files
));
1449 PyErr_SetFromErrno(PyExc_OSError
);
1453 for (int i
= 0; i
< num_files
; i
++) {
1454 PyObject
* file
= PySequence_GetItem(list
, i
);
1458 // Check if file is a Unicode object
1459 if (!PyUnicode_Check(file
)) {
1460 PyErr_SetString(PyExc_ValueError
, "Expected a string.");
1464 // Add pointer to string to files array
1465 files
[i
] = PyUnicode_AsUTF8(file
);
1472 Py_BEGIN_ALLOW_THREADS
1474 int r
= pakfire_repo_compose(self
->pakfire
, path
, (key
) ? key
->key
: NULL
, files
);
1477 PyErr_SetFromErrno(PyExc_OSError
);
1481 Py_END_ALLOW_THREADS
1483 // Return None on success
1494 static PyObject
* Pakfire_mkimage(PakfireObject
* self
, PyObject
* args
, PyObject
* kwargs
) {
1500 struct pakfire_build
* build
= NULL
;
1501 const char* type
= NULL
;
1502 PyObject
* file
= NULL
;
1506 if (!PyArg_ParseTupleAndKeywords(args
, kwargs
, "sO", kwlist
, &type
, &file
))
1509 // Make a file handle out of file
1510 f
= PyObject_AsFileHandle(file
, "w");
1514 // Create a new build environment
1515 r
= pakfire_build_create(&build
, self
->pakfire
, NULL
, 0);
1517 PyErr_SetFromErrno(PyExc_OSError
);
1521 Py_BEGIN_ALLOW_THREADS
1524 r
= pakfire_build_mkimage(build
, type
, f
);
1529 PyErr_SetFromErrno(PyExc_OSError
);
1534 Py_END_ALLOW_THREADS
1538 pakfire_build_unref(build
);
1547 static struct PyMethodDef Pakfire_methods
[] = {
1550 (PyCFunction
)Pakfire_build
,
1551 METH_VARARGS
|METH_KEYWORDS
,
1556 (PyCFunction
)Pakfire_check
,
1562 (PyCFunction
)Pakfire_clean
,
1568 (PyCFunction
)Pakfire_copy_in
,
1574 (PyCFunction
)Pakfire_copy_out
,
1580 (PyCFunction
)Pakfire_dist
,
1586 (PyCFunction
)Pakfire_erase
,
1587 METH_VARARGS
|METH_KEYWORDS
,
1592 (PyCFunction
)Pakfire_execute
,
1593 METH_VARARGS
|METH_KEYWORDS
,
1598 (PyCFunction
)Pakfire_generate_key
,
1599 METH_VARARGS
|METH_KEYWORDS
,
1604 (PyCFunction
)Pakfire_get_repo
,
1610 (PyCFunction
)Pakfire_import_key
,
1616 (PyCFunction
)Pakfire_install
,
1617 METH_VARARGS
|METH_KEYWORDS
,
1622 (PyCFunction
)Pakfire_mkimage
,
1623 METH_VARARGS
|METH_KEYWORDS
,
1628 (PyCFunction
)Pakfire_open
,
1634 (PyCFunction
)Pakfire_refresh
,
1640 (PyCFunction
)Pakfire_repo_compose
,
1641 METH_VARARGS
|METH_KEYWORDS
,
1646 (PyCFunction
)Pakfire_search
,
1647 METH_VARARGS
|METH_KEYWORDS
,
1652 (PyCFunction
)Pakfire_shell
,
1653 METH_VARARGS
|METH_KEYWORDS
,
1658 (PyCFunction
)Pakfire_sync
,
1659 METH_VARARGS
|METH_KEYWORDS
,
1664 (PyCFunction
)Pakfire_update
,
1665 METH_VARARGS
|METH_KEYWORDS
,
1670 (PyCFunction
)Pakfire_version_compare
,
1676 (PyCFunction
)Pakfire_whatprovides
,
1682 (PyCFunction
)Pakfire_whatrequires
,
1689 static struct PyGetSetDef Pakfire_getsetters
[] = {
1692 (getter
)Pakfire_get_arch
,
1699 (getter
)Pakfire_get_path
,
1706 (getter
)Pakfire_get_repos
,
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
,