]> git.ipfire.org Git - pakfire.git/commitdiff
request: Implement picking a solution
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 3 Jul 2021 14:11:00 +0000 (14:11 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 3 Jul 2021 14:21:01 +0000 (14:21 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/include/pakfire/request.h
src/libpakfire/ui.c

index 6ad4fb79f2e846ebb64abbfd0fa13a0535d28c95..aa327b14e025fd0b07c6c113d7cde6f8f57d0e4d 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <pakfire/package.h>
 #include <pakfire/problem.h>
+#include <pakfire/solution.h>
 #include <pakfire/transaction.h>
 #include <pakfire/types.h>
 
@@ -67,6 +68,9 @@ int pakfire_request_lock_package(struct pakfire_request* request, struct pakfire
 
 int pakfire_request_verify(struct pakfire_request* request, int flags);
 
+int pakfire_request_take_solution(struct pakfire_request* request,
+       struct pakfire_solution* solution);
+
 #ifdef PAKFIRE_PRIVATE
 
 #include <solv/solver.h>
index c7c777a724ba4574a300d05d80ea6a1f3f705405..4f3331e1c3a5d35c4b208b458936b6e34afd9106 100644 (file)
@@ -19,6 +19,7 @@
 #############################################################################*/
 
 #include <errno.h>
+#include <stdlib.h>
 
 #include <pakfire/i18n.h>
 #include <pakfire/pakfire.h>
@@ -63,30 +64,175 @@ int pakfire_ui_confirm(Pakfire pakfire, const char* message, const char* questio
        return 1;
 }
 
-int pakfire_ui_pick_solution(Pakfire pakfire, struct pakfire_request* request,
-               struct pakfire_problem** problems) {
+static int pakfire_ui_enter_number(Pakfire pakfire, const char* question,
+               unsigned int* choice, unsigned int min, unsigned int max) {
        // Skip this, if running in non-interactive mode
        if (pakfire_has_flag(pakfire, PAKFIRE_FLAGS_NON_INTERACTIVE))
-               return 1;
+               return 0;
+
+       char* line = NULL;
+       size_t length = 0;
+       char* remainder = NULL;
+       int r = 1;
+
+       while (1) {
+               // Print question
+               printf("%s ", question);
+
+               // Wait for the user to enter something
+               ssize_t bytes_read = getline(&line, &length, stdin);
+               if (bytes_read < 0)
+                       goto ERROR;
+
+               // Convert input into an integer
+               unsigned long int value = strtoul(line, &remainder, 10);
+
+               // The remainder must point to newline
+               if (!remainder || *remainder != '\n')
+                       goto AGAIN;
+
+               // The value must be within bounds
+               if (value < min || value > max)
+                       goto AGAIN;
+
+               // Store choice
+               *choice = value;
+               r = 0;
+               break;
+
+AGAIN:
+               printf(_("Invalid value\n"));
+       }
+
+ERROR:
+       if (line)
+               free(line);
+
+       return r;
+}
+
+static struct pakfire_solution** pakfire_ui_append_solutions(
+               struct pakfire_solution** list, struct pakfire_solution** solutions) {
+       unsigned int existing_length = 0;
+       unsigned int appended_length = 0;
+
+       // Count lengths of list
+       if (list) {
+               for (struct pakfire_solution** solution = list; *solution; solution++)
+                       existing_length++;
+       }
+
+       // Count what is to be appended
+       for (struct pakfire_solution** solution = solutions; *solution; solution++)
+               appended_length++;
+
+       // Increase array size
+       list = reallocarray(list, existing_length + appended_length + 1, sizeof(*list));
+       if (!list)
+               return NULL;
+
+       // Append all elements to list
+       for (unsigned int i = 0; i < appended_length; i++)
+               list[existing_length + i] = pakfire_solution_ref(solutions[i]);
 
+       // Terminate the list
+       list[existing_length + appended_length] = NULL;
+
+       return list;
+}
+
+int pakfire_ui_pick_solution(Pakfire pakfire, struct pakfire_request* request,
+               struct pakfire_problem** problems) {
        if (!problems) {
                errno = EINVAL;
                return 1;
        }
 
+       struct pakfire_solution** all_solutions = NULL;
+       unsigned int num_solutions = 0;
+       struct pakfire_solution** solutions = NULL;
+       int r;
+
        // Print a headline
-       printf("%s\n\n", _("One or more problems have occurred solving your request:"));
+       printf("%s\n", _("One or more problems have occurred solving your request:"));
 
        // Print all problems
        for (struct pakfire_problem** problem = problems; *problem; problem++) {
                const char* s = pakfire_problem_to_string(*problem);
 
-               printf(" * %s\n", s);
+               printf("  * %s\n", s);
+
+               // Fetch all solutions to this problem
+               r = pakfire_problem_get_solutions(*problem, &solutions);
+               if (r)
+                       goto ERROR;
+
+               // Skip the rest if there are no solutions
+               if (!solutions)
+                       continue;
+
+               // Append solutions to list
+               all_solutions = pakfire_ui_append_solutions(all_solutions, solutions);
+               if (!all_solutions)
+                       goto ERROR;
+
+               // Show a little headline
+               printf("    %s\n", _("Possible solutions:"));
+
+               // Print solutions
+               for (struct pakfire_solution** solution = solutions; *solution; solution++) {
+                       s = pakfire_solution_to_string(*solution);
+                       if (!s) {
+                               for (struct pakfire_solution** solution = solutions; *solution; solution++)
+                                       pakfire_solution_unref(*solution);
+                               free(solutions);
+                               goto ERROR;
+                       }
+
+                       printf("      [%d] %s\n", ++num_solutions, s);
+               }
+
+               // Empty line
+               printf("\n");
+
+               // Free solutions
+               for (struct pakfire_solution** solution = solutions; *solution; solution++)
+                       pakfire_solution_unref(*solution);
+               free(solutions);
+       }
+
+       // Skip this, if running in non-interactive mode
+       if (pakfire_has_flag(pakfire, PAKFIRE_FLAGS_NON_INTERACTIVE)) {
+               r = 1;
+               goto ERROR;
        }
 
-       // Empty line
-       printf("\n");
+       unsigned int choice = 0;
 
-       // Select nothing
-       return 1;
+       // Let the user choose which solution they want
+       r = pakfire_ui_enter_number(pakfire, _("Please select a solution:"),
+               &choice, 1, num_solutions);
+       if (r)
+               goto ERROR;
+
+       // Choice is invalid
+       if (!choice)
+               goto ERROR;
+
+       // Fetch selected solution into the solver
+       r = pakfire_request_take_solution(request, all_solutions[choice - 1]);
+       if (r)
+               goto ERROR;
+
+       // Success
+       r = 0;
+
+ERROR:
+       if (all_solutions) {
+               for (struct pakfire_solution** solution = all_solutions; *solution; solution++)
+                       pakfire_solution_unref(*solution);
+               free(all_solutions);
+       }
+
+       return r;
 }