From: Michael Tremer Date: Sat, 23 Sep 2023 09:36:46 +0000 (+0000) Subject: problems: Refactor fetching problems and solutions X-Git-Tag: 0.9.30~1665 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bfe8e8fbfc83d9b370fbfd04bcedc38da3560d71;p=pakfire.git problems: Refactor fetching problems and solutions Signed-off-by: Michael Tremer --- diff --git a/src/_pakfire/problem.c b/src/_pakfire/problem.c index 323cc97b5..393f038a3 100644 --- a/src/_pakfire/problem.c +++ b/src/_pakfire/problem.c @@ -71,44 +71,47 @@ static PyObject* Problem_string(ProblemObject* self) { } static PyObject* Problem_get_solutions(ProblemObject* self) { - struct pakfire_solution* solution = NULL; - PyObject* solution_obj = NULL; + struct pakfire_solution** solutions = NULL; + PyObject* s = NULL; int r; PyObject* list = PyList_New(0); if (!list) return NULL; - for (;;) { - r = pakfire_problem_next_solution(self->problem, &solution); - if (r) - goto ERROR; + // Fetch any solutions + solutions = pakfire_problem_get_solutions(self->problem); - // No more solutions - if (!solution) - break; + if (solutions) { + for (struct pakfire_solution** solution = solutions; *solution; solution++) { + s = new_solution(*solution); + if (!s) + goto ERROR; - // Create a new Solution object - solution_obj = new_solution(solution); - if (!solution_obj) { - pakfire_solution_unref(solution); - goto ERROR; + // Append the solution to the list + r = PyList_Append(list, s); + Py_DECREF(s); + if (r) + goto ERROR; } - // Append the solution to the list - r = PyList_Append(list, solution_obj); - if (r) { - pakfire_solution_unref(solution); - goto ERROR; - } - - Py_DECREF(solution_obj); + // Cleanup + for (struct pakfire_solution** solution = solutions; *solution; solution++) + pakfire_solution_unref(*solution); + free(solutions); } return list; ERROR: + if (solutions) { + for (struct pakfire_solution** solution = solutions; *solution; solution++) + pakfire_solution_unref(*solution); + free(solutions); + } + Py_DECREF(list); + return NULL; } diff --git a/src/libpakfire/build.c b/src/libpakfire/build.c index e470ac56c..863f58868 100644 --- a/src/libpakfire/build.c +++ b/src/libpakfire/build.c @@ -1882,9 +1882,7 @@ static int pakfire_build_install_package(struct pakfire* pakfire, static int pakfire_build_install_test(struct pakfire_build* build) { struct pakfire_transaction* transaction = NULL; - struct pakfire_problem* problem = NULL; - struct pakfire_solution* solution = NULL; - const char* s = NULL; + char* problems = NULL; int r; // Create a new transaction @@ -1896,7 +1894,7 @@ static int pakfire_build_install_test(struct pakfire_build* build) { r = pakfire_packagelist_walk(build->packages, pakfire_build_install_package, transaction); // Solve the request - r = pakfire_transaction_solve(transaction, 0, NULL); + r = pakfire_transaction_solve(transaction, PAKFIRE_SOLVE_SHOW_SOLUTIONS, &problems); switch (r) { // All okay case 0: @@ -1904,58 +1902,18 @@ static int pakfire_build_install_test(struct pakfire_build* build) { // Dependency Error case 2: - ERROR(build->pakfire, "Install test failed:\n"); - - // Walk through all problems - for (;;) { - r = pakfire_transaction_next_problem(transaction, &problem); - if (r) - goto ERROR; - - // There are no more problems - if (!problem) - break; - - // Format the problem into something human-readable - s = pakfire_problem_to_string(problem); - if (!s) - continue; - - ERROR(build->pakfire, " * %s\n", s); - - // Walk through all solutions - for (;;) { - r = pakfire_problem_next_solution(problem, &solution); - if (r) - goto ERROR; - - // There are no more solutions - if (!solution) - break; - - // Format the solution into something human-readable - s = pakfire_solution_to_string(solution); - if (!s) - continue; - - ERROR(build->pakfire, " * %s\n", s); - } - } - + ERROR(build->pakfire, "Install test failed:\n%s\n", problems); break; // Any other errors default: + ERROR(build->pakfire, "Install test failed: %m\n"); goto ERROR; } ERROR: - if (r) - ERROR(build->pakfire, "Install test failed: %m\n"); - if (problem) - pakfire_problem_unref(problem); - if (solution) - pakfire_solution_unref(solution); + if (problems) + free(problems); return r; } diff --git a/src/libpakfire/include/pakfire/problem.h b/src/libpakfire/include/pakfire/problem.h index 6232d3835..2c199fc07 100644 --- a/src/libpakfire/include/pakfire/problem.h +++ b/src/libpakfire/include/pakfire/problem.h @@ -30,11 +30,13 @@ struct pakfire_problem* pakfire_problem_unref(struct pakfire_problem* problem); const char* pakfire_problem_to_string(struct pakfire_problem* problem); -int pakfire_problem_next_solution( - struct pakfire_problem* problem, struct pakfire_solution** solution); +struct pakfire_solution** pakfire_problem_get_solutions( + struct pakfire_problem* problem); #ifdef PAKFIRE_PRIVATE +#include + #include int pakfire_problem_create(struct pakfire_problem** problem, struct pakfire* pakfire, diff --git a/src/libpakfire/include/pakfire/solution.h b/src/libpakfire/include/pakfire/solution.h index 59af326c2..bc6a160de 100644 --- a/src/libpakfire/include/pakfire/solution.h +++ b/src/libpakfire/include/pakfire/solution.h @@ -23,6 +23,7 @@ struct pakfire_solution; +#include #include struct pakfire_solution* pakfire_solution_ref(struct pakfire_solution* solution); @@ -32,8 +33,9 @@ const char* pakfire_solution_to_string(struct pakfire_solution* solution); #ifdef PAKFIRE_PRIVATE +#include -int pakfire_solution_create(struct pakfire_solution** solution, +int pakfire_solution_create(struct pakfire_solution** solution, struct pakfire* pakfire, struct pakfire_problem* problem, Id id); struct pakfire_problem* pakfire_solution_get_problem(struct pakfire_solution* solution); Id pakfire_solution_get_id(struct pakfire_solution* solution); diff --git a/src/libpakfire/include/pakfire/transaction.h b/src/libpakfire/include/pakfire/transaction.h index 651c545e4..b1efabb03 100644 --- a/src/libpakfire/include/pakfire/transaction.h +++ b/src/libpakfire/include/pakfire/transaction.h @@ -34,6 +34,10 @@ enum pakfire_transaction_flags { PAKFIRE_TRANSACTION_ALLOW_DOWNGRADE = 1 << 3, }; +enum pakfire_transaction_solve_flags { + PAKFIRE_SOLVE_SHOW_SOLUTIONS = 1 << 0, +}; + enum pakfire_job_action { PAKFIRE_JOB_INSTALL, PAKFIRE_JOB_ERASE, @@ -68,6 +72,8 @@ int pakfire_transaction_request(struct pakfire_transaction* transaction, int pakfire_transaction_request_package(struct pakfire_transaction* transaction, const enum pakfire_job_action action, struct pakfire_package* package, int flags); +struct pakfire_problem** pakfire_transaction_get_problems(struct pakfire_transaction* transaction); + size_t pakfire_transaction_count(struct pakfire_transaction* transaction); char* pakfire_transaction_dump(struct pakfire_transaction* transaction, size_t width); @@ -92,9 +98,6 @@ enum pakfire_request_solve_flags { Solver* pakfire_transaction_get_solver(struct pakfire_transaction* transaction); -int pakfire_transaction_next_problem( - struct pakfire_transaction* transaction, struct pakfire_problem** problem); - int pakfire_transaction_take_solution(struct pakfire_transaction* transaction, struct pakfire_solution* solution); diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index ed4255889..4c02a57f5 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -204,7 +204,7 @@ global: pakfire_packagelist_unref; # problem - pakfire_problem_next_solution; + pakfire_problem_get_solutions; pakfire_problem_ref; pakfire_problem_to_string; pakfire_problem_unref; @@ -278,6 +278,7 @@ global: pakfire_transaction_create; pakfire_transaction_download; pakfire_transaction_dump; + pakfire_transaction_get_problems; pakfire_transaction_ref; pakfire_transaction_request; pakfire_transaction_request_package; diff --git a/src/libpakfire/problem.c b/src/libpakfire/problem.c index 8da224b1c..71adc3d11 100644 --- a/src/libpakfire/problem.c +++ b/src/libpakfire/problem.c @@ -39,6 +39,8 @@ struct pakfire_problem { struct pakfire_transaction* transaction; Id id; char* string; + + Solver* solver; }; static char* pakfire_problem_make_string(struct pakfire_problem* problem) { @@ -199,6 +201,9 @@ int pakfire_problem_create(struct pakfire_problem** problem, p->transaction = pakfire_transaction_ref(transaction); p->id = id; + // Fetch a reference to the solver + p->solver = pakfire_transaction_get_solver(transaction); + *problem = p; return 0; } @@ -245,31 +250,51 @@ struct pakfire_transaction* pakfire_problem_get_transaction(struct pakfire_probl return pakfire_transaction_ref(problem->transaction); } -PAKFIRE_EXPORT int pakfire_problem_next_solution( - struct pakfire_problem* problem, struct pakfire_solution** solution) { - Solver* solver = pakfire_transaction_get_solver(problem->transaction); - Id id = 0; +PAKFIRE_EXPORT struct pakfire_solution** pakfire_problem_get_solutions( + struct pakfire_problem* problem) { + struct pakfire_solution** solutions = NULL; + struct pakfire_solution* solution = NULL; + unsigned int count = 0; + Id id = ID_NULL; + int r; + + // Fetch how many solutions we have + count = solver_solution_count(problem->solver, problem->id); + if (!count) + return NULL; - // Check input - if (!solution) { - errno = EINVAL; - return 1; + // Allocate some space + solutions = calloc(count + 1, sizeof(*solutions)); + if (!solutions) { + r = -errno; + goto ERROR; } - // Fetch the ID of the previous solution - if (*solution) { - id = pakfire_solution_get_id(*solution); + for (unsigned int i = 0; i < count; i++) { + id = solver_next_solution(problem->solver, problem->id, id); + if (!id) + break; + + // Create a new solution + r = pakfire_solution_create(&solution, problem->pakfire, problem, id); + if (r) + goto ERROR; - // Free the previous solution - pakfire_solution_unref(*solution); - *solution = NULL; + // Store the reference + solutions[i] = solution; } - // Fetch the ID of the next problem - id = solver_next_solution(solver, problem->id, id); - if (!id) - return 0; + return solutions; + +ERROR: + ERROR_ERRNO(problem->pakfire, r, "Could not import solutions: %m\n"); + + if (solutions) { + for (struct pakfire_solution** s = solutions; *s; s++) + pakfire_solution_unref(*s); - // Create solution - return pakfire_solution_create(solution, problem, id); + free(solutions); + } + + return NULL; } diff --git a/src/libpakfire/solution.c b/src/libpakfire/solution.c index 7eaac79ca..ba676cb39 100644 --- a/src/libpakfire/solution.c +++ b/src/libpakfire/solution.c @@ -18,6 +18,7 @@ # # #############################################################################*/ +#include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -42,16 +44,21 @@ struct pakfire_solution { }; int pakfire_solution_create(struct pakfire_solution** solution, - struct pakfire_problem* problem, Id id) { + struct pakfire* pakfire, struct pakfire_problem* problem, Id id) { struct pakfire_solution* s = calloc(1, sizeof(*s)); if (!s) - return 1; + return -errno; - s->pakfire = pakfire_problem_get_pakfire(problem); + // Store a reference to pakfire + s->pakfire = pakfire_ref(pakfire); + + // Initialize the ref counter s->nrefs = 1; // Store a reference to the problem s->problem = pakfire_problem_ref(problem); + + // Store the ID s->id = id; *solution = s; diff --git a/src/libpakfire/transaction.c b/src/libpakfire/transaction.c index eb751942b..c172d67ee 100644 --- a/src/libpakfire/transaction.c +++ b/src/libpakfire/transaction.c @@ -174,7 +174,6 @@ static void pakfire_transaction_free(struct pakfire_transaction* transaction) { if (transaction->transaction) transaction_free(transaction->transaction); - if (transaction->solver) solver_free(transaction->solver); pakfire_unref(transaction->pakfire); @@ -413,35 +412,146 @@ static void pakfire_transaction_status(struct pakfire_transaction* transaction, free(buffer); } -static char* pakfire_transaction_get_problem_string(struct pakfire_transaction* transaction) { +PAKFIRE_EXPORT struct pakfire_problem** pakfire_transaction_get_problems( + struct pakfire_transaction* transaction) { + struct pakfire_problem** problems = NULL; struct pakfire_problem* problem = NULL; - const char* p = NULL; - char* s = NULL; + unsigned int count = 0; + Id id = ID_NULL; int r; - for (;;) { - r = pakfire_transaction_next_problem(transaction, &problem); - if (r || !problem) + // Count problems + count = solver_problem_count(transaction->solver); + + // Return NULL if there are no problems + if (!count) + return NULL; + + // Allocate some space + problems = calloc(count + 1, sizeof(*problems)); + if (!problems) { + r = -errno; + goto ERROR; + } + + for (unsigned int i = 0; i < count; i++) { + // Fetch the ID of the next problem + id = solver_next_problem(transaction->solver, id); + if (!id) break; - p = pakfire_problem_to_string(problem); - if (!p) + // Create a new problem + r = pakfire_problem_create(&problem, transaction->pakfire, transaction, id); + if (r) goto ERROR; - r = asprintf(&s, "%s%s\n", (s) ? s : "", p); - if (r < 0) - goto ERROR; + // Store the reference + problems[i] = problem; } - return s; + return problems; ERROR: - if (s) - free(s); + ERROR_ERRNO(transaction->pakfire, r, "Could not import problems: %m\n"); + + if (problems) { + for (struct pakfire_problem** p = problems; *p; p++) + pakfire_problem_unref(*p); + free(problems); + } return NULL; } +static int pakfire_transaction_append_solutions( + struct pakfire_transaction* transaction, char** buffer, struct pakfire_solution** solutions) { + const char* s = NULL; + int r; + + for (struct pakfire_solution** solution = solutions; *solution; solution++) { + s = pakfire_solution_to_string(*solution); + if (!s) + return -errno; + + // Append the solution + r = asprintf(buffer, "%s - %s\n", *buffer, s); + if (r < 0) + return -errno; + } + + return 0; +} + +static int pakfire_transaction_append_problems( + struct pakfire_transaction* transaction, char** buffer, struct pakfire_problem** problems, int flags) { + struct pakfire_solution** solutions = NULL; + const char* s = NULL; + int r; + + for (struct pakfire_problem** problem = problems; *problem; problem++) { + s = pakfire_problem_to_string(*problem); + if (!s) + return -errno; + + // Append the string to the buffer + r = asprintf(buffer, "%s* %s\n", *buffer, s); + if (r < 0) + return -errno; + + // Show solutions + if (flags & PAKFIRE_SOLVE_SHOW_SOLUTIONS) { + // Fetch any solutions + solutions = pakfire_problem_get_solutions(*problem); + + if (solutions) { + r = pakfire_transaction_append_solutions(transaction, buffer, solutions); + + // Cleanup + for (struct pakfire_solution** solution = solutions; *solution; solution++) + pakfire_solution_unref(*solution); + free(solutions); + + if (r) + return r; + } + } + } + + return 0; +} + +static char* pakfire_transaction_get_problem_string( + struct pakfire_transaction* transaction, int flags) { + struct pakfire_problem** problems = NULL; + char* buffer = ""; + int r; + + // Fetch any problems + problems = pakfire_transaction_get_problems(transaction); + + // Show problems + if (problems) { + // Append all problems + r = pakfire_transaction_append_problems(transaction, &buffer, problems, flags); + if (r) { + if (buffer) + free(buffer); + + buffer = NULL; + } + + // Cleanup + if (problems) { + for (struct pakfire_problem** problem = problems; *problem; problem++) + pakfire_problem_unref(*problem); + + free(problems); + } + } + + return buffer; +} + Solver* pakfire_transaction_get_solver(struct pakfire_transaction* transaction) { return transaction->solver; } @@ -468,6 +578,7 @@ RETRY: // Save time when we starting solving clock_t solving_start = clock(); + // Solve the request and get the number of problems r = solver_solve(transaction->solver, &transaction->jobs); // Save time when we finished solving @@ -503,7 +614,7 @@ RETRY: // Return the problems as string if (problems) - *problems = pakfire_transaction_get_problem_string(transaction); + *problems = pakfire_transaction_get_problem_string(transaction, flags); // Ask the user to pick a solution if (flags & PAKFIRE_REQ_SOLVE_INTERACTIVE) { @@ -515,7 +626,7 @@ RETRY: goto RETRY; } else { - char* s = pakfire_transaction_get_problem_string(transaction); + char* s = pakfire_transaction_get_problem_string(transaction, 0); if (s) ERROR(transaction->pakfire, "%s\n", s); } @@ -726,34 +837,6 @@ PAKFIRE_EXPORT int pakfire_transaction_request_package(struct pakfire_transactio return __pakfire_transaction_add(transaction, action, SOLVER_SOLVABLE, id, flags); } -int pakfire_transaction_next_problem( - struct pakfire_transaction* transaction, struct pakfire_problem** problem) { - Id id = 0; - - // Check input - if (!problem) { - errno = EINVAL; - return 1; - } - - // Fetch the ID of the previous problem - if (*problem) { - id = pakfire_problem_get_id(*problem); - - // Free the previous problem - pakfire_problem_unref(*problem); - *problem = NULL; - } - - // Fetch the ID of the next problem - id = solver_next_problem(transaction->solver, id); - if (!id) - return 0; - - // Create problem - return pakfire_problem_create(problem, transaction->pakfire, transaction, id); -} - int pakfire_transaction_take_solution(struct pakfire_transaction* transaction, struct pakfire_solution* solution) { struct pakfire_problem* problem = pakfire_solution_get_problem(solution); diff --git a/src/libpakfire/ui.c b/src/libpakfire/ui.c index b8c9f095f..1e47500af 100644 --- a/src/libpakfire/ui.c +++ b/src/libpakfire/ui.c @@ -113,6 +113,7 @@ static struct pakfire_solution** pakfire_ui_append_solution( } int pakfire_ui_pick_solution(struct pakfire* pakfire, struct pakfire_transaction* transaction) { +#if 0 struct pakfire_problem* problem = NULL; struct pakfire_solution** solutions = NULL; struct pakfire_solution* solution = NULL; @@ -190,4 +191,7 @@ ERROR: } return r; +#endif + + return 0; }