]> git.ipfire.org Git - pakfire.git/commitdiff
problems: Refactor fetching problems and solutions
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 23 Sep 2023 09:36:46 +0000 (09:36 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 23 Sep 2023 09:36:46 +0000 (09:36 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/_pakfire/problem.c
src/libpakfire/build.c
src/libpakfire/include/pakfire/problem.h
src/libpakfire/include/pakfire/solution.h
src/libpakfire/include/pakfire/transaction.h
src/libpakfire/libpakfire.sym
src/libpakfire/problem.c
src/libpakfire/solution.c
src/libpakfire/transaction.c
src/libpakfire/ui.c

index 323cc97b568176ac9035de0fa1b157aa33b8503c..393f038a380454e4a1d392c6389ff8770cdd0e7d 100644 (file)
@@ -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;
 }
 
index e470ac56c7bced2ea5484bd6f5ebc353869b1bec..863f5886891e1e4bf41d15ab912a3caf91d17112 100644 (file)
@@ -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;
 }
index 6232d3835f733c1f0a0d23ec7e4c557ff6407f3b..2c199fc07bc8a690ad682436324dfceb004c1227 100644 (file)
@@ -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 <solv/pooltypes.h>
+
 #include <pakfire/transaction.h>
 
 int pakfire_problem_create(struct pakfire_problem** problem, struct pakfire* pakfire,
index 59af326c203d6b2c0e6d5e732c6bfd775ce337b4..bc6a160dee6565f6f694896571c16a930f77da73 100644 (file)
@@ -23,6 +23,7 @@
 
 struct pakfire_solution;
 
+#include <pakfire/pakfire.h>
 #include <pakfire/problem.h>
 
 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 <solv/pooltypes.h>
 
-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);
index 651c545e4e504bf44ab1b1048c890d22ba056e96..b1efabb03ed35c45558479646b5f40a3abd3a0b0 100644 (file)
@@ -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);
 
index ed4255889688ed4cf865382b5c6f30fefda5492f..4c02a57f516c8cd4a6abf4d86d9d1e27721bf097 100644 (file)
@@ -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;
index 8da224b1ce7efda3ca766edbb55748287eaa31e9..71adc3d1112e80d99e647c576c0ac498fe1b88ce 100644 (file)
@@ -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;
 }
index 7eaac79ca0fdd4bfc2b97b2c87ac7475f808e819..ba676cb398fb7acd537bc68dacfdf016d75858e0 100644 (file)
@@ -18,6 +18,7 @@
 #                                                                             #
 #############################################################################*/
 
+#include <errno.h>
 #include <stdlib.h>
 
 #include <solv/policy.h>
@@ -25,6 +26,7 @@
 #include <pakfire/constants.h>
 #include <pakfire/i18n.h>
 #include <pakfire/logging.h>
+#include <pakfire/pakfire.h>
 #include <pakfire/private.h>
 #include <pakfire/problem.h>
 #include <pakfire/solution.h>
@@ -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;
index eb751942b01720b53aa166496338c17c8c9c539f..c172d67eea325646b91199b6049f0be21ccd81df 100644 (file)
@@ -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);
index b8c9f095f71fa427e608b90bda60f68b3848c353..1e47500af11cf96123c3f4b6109a0b74153752fa 100644 (file)
@@ -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;
 }