From 4df7e8d80cb5bdd49228e50edb5c7793187fbf0f Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Mon, 8 May 2023 13:55:19 +0000 Subject: [PATCH] installcheck: Add a function that checks whether a package can be installed Signed-off-by: Michael Tremer --- src/_pakfire/package.c | 31 +++++++++++ src/libpakfire/build.c | 4 +- src/libpakfire/include/pakfire/package.h | 3 + src/libpakfire/include/pakfire/request.h | 8 ++- src/libpakfire/libpakfire.sym | 1 + src/libpakfire/package.c | 37 ++++++++++++ src/libpakfire/pakfire.c | 4 +- src/libpakfire/request.c | 71 +++++++++++++++++------- 8 files changed, 133 insertions(+), 26 deletions(-) diff --git a/src/_pakfire/package.c b/src/_pakfire/package.c index 1e7f48efb..0cc17b324 100644 --- a/src/_pakfire/package.c +++ b/src/_pakfire/package.c @@ -28,6 +28,7 @@ #include #include +#include "errors.h" #include "package.h" #include "pakfire.h" #include "repo.h" @@ -730,6 +731,30 @@ static PyObject* Package_set_source_arch(PackageObject* self, PyObject* value) { Py_RETURN_NONE; } +static PyObject* Package_installcheck(PackageObject* self) { + char* problem = NULL; + int r; + + // Perform the installcheck + r = pakfire_package_installcheck(self->package, &problem); + + // Success! + if (r == 0) + Py_RETURN_NONE; + + // We did not get the problem + else if (!problem) { + PyErr_SetFromErrno(PyExc_OSError); + + // Otherwise raise a dependency error + } else { + PyErr_SetString(PyExc_DependencyError, problem); + free(problem); + } + + return NULL; +} + static struct PyMethodDef Package_methods[] = { { "dump", @@ -737,6 +762,12 @@ static struct PyMethodDef Package_methods[] = { METH_VARARGS|METH_KEYWORDS, NULL, }, + { + "installcheck", + (PyCFunction)Package_installcheck, + METH_NOARGS, + NULL, + }, { NULL }, }; diff --git a/src/libpakfire/build.c b/src/libpakfire/build.c index f0245f2f6..3b9117ab1 100644 --- a/src/libpakfire/build.c +++ b/src/libpakfire/build.c @@ -1882,7 +1882,7 @@ static int pakfire_build_install_test(struct pakfire_build* build) { r = pakfire_packagelist_walk(build->packages, pakfire_build_install_package, request); // Solve the request - r = pakfire_request_solve(request); + r = pakfire_request_solve(request, 0); switch (r) { // All okay case 0: @@ -2068,7 +2068,7 @@ static int pakfire_build_install_source_package( } // Solve the request - r = pakfire_request_solve(request); + r = pakfire_request_solve(request, 0); if (r) goto ERROR; diff --git a/src/libpakfire/include/pakfire/package.h b/src/libpakfire/include/pakfire/package.h index a24c84876..64074fdf6 100644 --- a/src/libpakfire/include/pakfire/package.h +++ b/src/libpakfire/include/pakfire/package.h @@ -132,6 +132,9 @@ enum pakfire_package_dump_flags { PAKFIRE_PKG_DUMP_LONG = 1 << 1, }; +// Installcheck +int pakfire_package_installcheck(struct pakfire_package* pkg, char** problem); + #ifdef PAKFIRE_PRIVATE #include diff --git a/src/libpakfire/include/pakfire/request.h b/src/libpakfire/include/pakfire/request.h index 89b808cbd..2a206a266 100644 --- a/src/libpakfire/include/pakfire/request.h +++ b/src/libpakfire/include/pakfire/request.h @@ -54,12 +54,16 @@ enum pakfire_request_action { PAKFIRE_REQ_VERIFY, }; +enum pakfire_request_solve_flags { + PAKFIRE_REQ_SOLVE_INTERACTIVE, +}; + int pakfire_request_create(struct pakfire_request** request, struct pakfire* pakfire, int flags); struct pakfire_request* pakfire_request_ref(struct pakfire_request* request); struct pakfire_request* pakfire_request_unref(struct pakfire_request* request); -int pakfire_request_solve(struct pakfire_request* request); +int pakfire_request_solve(struct pakfire_request* request, int flags); int pakfire_request_add(struct pakfire_request* request, const enum pakfire_request_action action, const char* what, int flags); @@ -71,6 +75,8 @@ int pakfire_request_take_solution(struct pakfire_request* request, Solver* pakfire_request_get_solver(struct pakfire_request* request); +char* pakfire_request_get_problem_string(struct pakfire_request* request); + int pakfire_request_next_problem( struct pakfire_request* request, struct pakfire_problem** problem); diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index 7378b053c..619de92a8 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -187,6 +187,7 @@ global: pakfire_package_get_string; pakfire_package_get_uuid; pakfire_package_id; + pakfire_package_installcheck; pakfire_package_ref; pakfire_package_set_checksum; pakfire_package_set_filelist; diff --git a/src/libpakfire/package.c b/src/libpakfire/package.c index 363f17c32..7f4bdfd62 100644 --- a/src/libpakfire/package.c +++ b/src/libpakfire/package.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -2057,3 +2058,39 @@ ERROR: return md; } + +PAKFIRE_EXPORT int pakfire_package_installcheck(struct pakfire_package* pkg, char** problem) { + struct pakfire_request* request = NULL; + int r; + + const char* nevra = pakfire_package_get_string(pkg, PAKFIRE_PKG_NEVRA); + + // Create a new request + r = pakfire_request_create(&request, pkg->pakfire, 0); + if (r) + goto ERROR; + + // Install the package + r = pakfire_request_add_package(request, PAKFIRE_REQ_INSTALL, pkg, 0); + if (r) { + ERROR(pkg->pakfire, "Could not add package %s to the request\n", nevra); + goto ERROR; + } + + // Solve the request + r = pakfire_request_solve(request, 0); + if (r) { + DEBUG(pkg->pakfire, "Could not install %s:\n", nevra); + + // Fetch the problem + *problem = pakfire_request_get_problem_string(request); + if (*problem) + DEBUG(pkg->pakfire, "%s\n", *problem); + } + +ERROR: + if (request) + pakfire_request_unref(request); + + return r; +} diff --git a/src/libpakfire/pakfire.c b/src/libpakfire/pakfire.c index 5809de344..4f28310a6 100644 --- a/src/libpakfire/pakfire.c +++ b/src/libpakfire/pakfire.c @@ -1950,7 +1950,7 @@ static int pakfire_perform_transaction( } // Solve the request - r = pakfire_request_solve(request); + r = pakfire_request_solve(request, PAKFIRE_REQ_SOLVE_INTERACTIVE); if (r) goto ERROR; @@ -2057,7 +2057,7 @@ static int pakfire_perform_transaction_simple(struct pakfire* pakfire, int solve goto ERROR; // Solve the request - r = pakfire_request_solve(request); + r = pakfire_request_solve(request, PAKFIRE_REQ_SOLVE_INTERACTIVE); if (r) goto ERROR; diff --git a/src/libpakfire/request.c b/src/libpakfire/request.c index 99a42b377..d9b15d98d 100644 --- a/src/libpakfire/request.c +++ b/src/libpakfire/request.c @@ -51,9 +51,6 @@ struct pakfire_request { Solver* solver; Queue jobs; - - // Set if the request has been solved - int solved:1; }; static void pakfire_request_free(struct pakfire_request* request) { @@ -173,7 +170,8 @@ static int pakfire_request_pick_solution(struct pakfire_request* request) { return pakfire_ui_pick_solution(request->pakfire, request); } -int pakfire_request_solve(struct pakfire_request* request) { +int pakfire_request_solve(struct pakfire_request* request, int flags) { + int solved = 0; int r; // Prepare pool @@ -191,26 +189,33 @@ int pakfire_request_solve(struct pakfire_request* request) { // Save time when we starting solving clock_t solving_start = clock(); - for (;;) { - r = solver_solve(request->solver, &request->jobs); - if (r == 0) +RETRY: + r = solver_solve(request->solver, &request->jobs); + switch (r) { + // Solved! + case 0: + // Mark as solved + solved = 1; break; - // We land here, if the request could not be solved - + // Not Solved + default: #ifdef ENABLE_DEBUG - // Print all solutions - solver_printallsolutions(request->solver); + // Print all solutions + solver_printallsolutions(request->solver); #endif - // Ask the user to pick a solution - r = pakfire_request_pick_solution(request); - if (r) - return r; - } + // Ask the user to pick a solution + if (flags & PAKFIRE_REQ_SOLVE_INTERACTIVE) { + r = pakfire_request_pick_solution(request); + if (r) + return r; - // Mark the request as solved - request->solved = 1; + // Retry solving + goto RETRY; + } + break; + } // Save time when we finished solving clock_t solving_end = clock(); @@ -219,11 +224,15 @@ int pakfire_request_solve(struct pakfire_request* request) { (double)(solving_end - solving_start) * 1000 / CLOCKS_PER_SEC); #ifdef ENABLE_DEBUG - solver_printdecisions(request->solver); + if (solved) + solver_printdecisions(request->solver); #endif - // All okay - return 0; + // Return zero if solved, otherwise return non-zero + if (solved) + return 0; + + return 2; } static int pakfire_request_is_file(const char* what) { @@ -401,6 +410,26 @@ int pakfire_request_add_package(struct pakfire_request* request, return __pakfire_request_add(request, action, SOLVER_SOLVABLE, id, flags); } +char* pakfire_request_get_problem_string(struct pakfire_request* request) { + struct pakfire_problem* problem = NULL; + char* s = NULL; + int r; + + for (;;) { + r = pakfire_request_next_problem(request, &problem); + if (r || !problem) + break; + + const char* p = pakfire_problem_to_string(problem); + + r = asprintf(&s, "%s%s\n", (s) ? s : "", p); + if (r < 0) + return NULL; + } + + return s; +} + int pakfire_request_next_problem( struct pakfire_request* request, struct pakfire_problem** problem) { Id id = 0; -- 2.39.5