From: Michael Tremer Date: Sat, 3 Jul 2021 14:11:00 +0000 (+0000) Subject: request: Implement picking a solution X-Git-Tag: 0.9.28~1117 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4c0e3aa4c5da3dda61432f6e065dc5dc33d65aca;p=pakfire.git request: Implement picking a solution Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/include/pakfire/request.h b/src/libpakfire/include/pakfire/request.h index 6ad4fb79f..aa327b14e 100644 --- a/src/libpakfire/include/pakfire/request.h +++ b/src/libpakfire/include/pakfire/request.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -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 diff --git a/src/libpakfire/ui.c b/src/libpakfire/ui.c index c7c777a72..4f3331e1c 100644 --- a/src/libpakfire/ui.c +++ b/src/libpakfire/ui.c @@ -19,6 +19,7 @@ #############################################################################*/ #include +#include #include #include @@ -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; }