From: Michael Tremer Date: Fri, 22 Sep 2023 15:41:18 +0000 (+0000) Subject: transaction: Merge requests into the transaction X-Git-Tag: 0.9.30~1666 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2f269d34f108d6b302b2a250a7108ed29e518df4;p=pakfire.git transaction: Merge requests into the transaction It makes a lot more sense to have one large object that wraps the solving process around libsolv instead of having multiple and passing things around. This is the first step to move things over and allow more flexibility when performing depenedency resolution. Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index c0ae72b58..1225ea9e7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -247,7 +247,6 @@ libpakfire_la_SOURCES = \ src/libpakfire/pwd.c \ src/libpakfire/repo.c \ src/libpakfire/repolist.c \ - src/libpakfire/request.c \ src/libpakfire/scriptlet.c \ src/libpakfire/snapshot.c \ src/libpakfire/solution.c \ @@ -289,7 +288,6 @@ pkginclude_HEADERS += \ src/libpakfire/include/pakfire/pwd.h \ src/libpakfire/include/pakfire/repo.h \ src/libpakfire/include/pakfire/repolist.h \ - src/libpakfire/include/pakfire/request.h \ src/libpakfire/include/pakfire/scriptlet.h \ src/libpakfire/include/pakfire/snapshot.h \ src/libpakfire/include/pakfire/solution.h \ diff --git a/src/_pakfire/package.c b/src/_pakfire/package.c index cf369f2f7..8b5aa0942 100644 --- a/src/_pakfire/package.c +++ b/src/_pakfire/package.c @@ -772,7 +772,7 @@ static PyObject* Package_installcheck(PackageObject* self) { int r; // Perform the installcheck - r = pakfire_package_installcheck(self->package, &problem); + r = pakfire_package_installcheck(self->package, &problem, 0); // Success! if (r == 0) diff --git a/src/_pakfire/pakfire.c b/src/_pakfire/pakfire.c index ce16c3c39..258b3ed3d 100644 --- a/src/_pakfire/pakfire.c +++ b/src/_pakfire/pakfire.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include @@ -462,15 +461,15 @@ static PyObject* Pakfire_install(PakfireObject* self, PyObject* args, PyObject* // Do not install recommended packages if (without_recommended) - solver_flags |= PAKFIRE_REQUEST_WITHOUT_RECOMMENDED; + solver_flags |= PAKFIRE_TRANSACTION_WITHOUT_RECOMMENDED; // Can the solver uninstall packages? if (allow_uninstall) - solver_flags |= PAKFIRE_REQUEST_ALLOW_UNINSTALL; + solver_flags |= PAKFIRE_TRANSACTION_ALLOW_UNINSTALL; // Can the solver downgrade packages? if (allow_downgrade) - solver_flags |= PAKFIRE_REQUEST_ALLOW_DOWNGRADE; + solver_flags |= PAKFIRE_TRANSACTION_ALLOW_DOWNGRADE; Py_BEGIN_ALLOW_THREADS @@ -525,7 +524,7 @@ static PyObject* Pakfire_erase(PakfireObject* self, PyObject* args, PyObject* kw transaction_flags |= PAKFIRE_TRANSACTION_DRY_RUN; if (keep_dependencies) - flags |= PAKFIRE_REQUEST_KEEP_DEPS; + flags |= PAKFIRE_JOB_KEEP_DEPS; Py_BEGIN_ALLOW_THREADS @@ -582,15 +581,15 @@ static PyObject* Pakfire_update(PakfireObject* self, PyObject* args, PyObject* k } if (dryrun) - transaction_flags = PAKFIRE_TRANSACTION_DRY_RUN; + transaction_flags |= PAKFIRE_TRANSACTION_DRY_RUN; // Can the solver uninstall packages? if (allow_uninstall) - solver_flags |= PAKFIRE_REQUEST_ALLOW_UNINSTALL; + solver_flags |= PAKFIRE_TRANSACTION_ALLOW_UNINSTALL; // Can the solver downgrade packages? if (allow_downgrade) - solver_flags |= PAKFIRE_REQUEST_ALLOW_DOWNGRADE; + solver_flags |= PAKFIRE_TRANSACTION_ALLOW_DOWNGRADE; Py_BEGIN_ALLOW_THREADS @@ -1379,7 +1378,7 @@ static PyObject* Pakfire_sync(PakfireObject* self, PyObject* args, PyObject* kwa return NULL; if (keep_orphaned) - flags |= PAKFIRE_REQUEST_KEEP_ORPHANED; + flags |= PAKFIRE_JOB_KEEP_ORPHANED; Py_BEGIN_ALLOW_THREADS diff --git a/src/libpakfire/build.c b/src/libpakfire/build.c index 47986a73f..e470ac56c 100644 --- a/src/libpakfire/build.c +++ b/src/libpakfire/build.c @@ -43,11 +43,11 @@ #include #include #include -#include #include #include #include #include +#include #include #define CCACHE_DIR "/var/cache/ccache" @@ -1874,29 +1874,29 @@ ERROR: static int pakfire_build_install_package(struct pakfire* pakfire, struct pakfire_package* pkg, void* p) { - struct pakfire_request* request = (struct pakfire_request*)p; + struct pakfire_transaction* transaction = (struct pakfire_transaction*)p; - return pakfire_request_add_package(request, PAKFIRE_REQ_INSTALL, pkg, - PAKFIRE_REQUEST_ESSENTIAL); + return pakfire_transaction_request_package(transaction, + PAKFIRE_JOB_INSTALL, pkg, PAKFIRE_JOB_ESSENTIAL); } static int pakfire_build_install_test(struct pakfire_build* build) { - struct pakfire_request* request = NULL; + struct pakfire_transaction* transaction = NULL; struct pakfire_problem* problem = NULL; struct pakfire_solution* solution = NULL; const char* s = NULL; int r; - // Create a new request - r = pakfire_request_create(&request, build->pakfire, 0); + // Create a new transaction + r = pakfire_transaction_create(&transaction, build->pakfire, 0); if (r) goto ERROR; // Add all packages - r = pakfire_packagelist_walk(build->packages, pakfire_build_install_package, request); + r = pakfire_packagelist_walk(build->packages, pakfire_build_install_package, transaction); // Solve the request - r = pakfire_request_solve(request, 0); + r = pakfire_transaction_solve(transaction, 0, NULL); switch (r) { // All okay case 0: @@ -1908,7 +1908,7 @@ static int pakfire_build_install_test(struct pakfire_build* build) { // Walk through all problems for (;;) { - r = pakfire_request_next_problem(request, &problem); + r = pakfire_transaction_next_problem(transaction, &problem); if (r) goto ERROR; @@ -1952,8 +1952,6 @@ static int pakfire_build_install_test(struct pakfire_build* build) { ERROR: if (r) ERROR(build->pakfire, "Install test failed: %m\n"); - if (request) - pakfire_request_unref(request); if (problem) pakfire_problem_unref(problem); if (solution) @@ -2057,37 +2055,37 @@ ERROR: static int pakfire_build_install_source_package( struct pakfire_build* build, struct pakfire_package* package) { - struct pakfire_request* request = NULL; struct pakfire_transaction* transaction = NULL; + char* problems = NULL; int r; - // Create a new request - r = pakfire_request_create(&request, build->pakfire, 0); + // Create a new transaction + r = pakfire_transaction_create(&transaction, build->pakfire, 0); if (r) goto ERROR; - // Add the package - r = pakfire_request_add_package(request, PAKFIRE_REQ_INSTALL, package, - PAKFIRE_REQUEST_ESSENTIAL); - if (r) - goto ERROR; - - // Install all essential packages + // Request to install all essential packages for (const char** p = PAKFIRE_BUILD_PACKAGES; *p; p++) { - r = pakfire_request_add(request, PAKFIRE_REQ_INSTALL, *p, PAKFIRE_REQUEST_ESSENTIAL); + r = pakfire_transaction_request(transaction, + PAKFIRE_JOB_INSTALL, *p, PAKFIRE_JOB_ESSENTIAL); if (r) goto ERROR; } - // Solve the request - r = pakfire_request_solve(request, 0); + // Add the source package + r = pakfire_transaction_request_package(transaction, + PAKFIRE_JOB_INSTALL, package, PAKFIRE_JOB_ESSENTIAL); if (r) goto ERROR; - // Fetch the transaction - r = pakfire_request_get_transaction(request, &transaction); - if (r) + // Solve the transaction + r = pakfire_transaction_solve(transaction, 0, &problems); + if (r) { + if (problems) + ERROR(build->pakfire, "Could not install the source package:\n%s\n", problems); + goto ERROR; + } // Set how many packages have been changed const size_t changes = pakfire_transaction_count(transaction); @@ -2107,8 +2105,8 @@ static int pakfire_build_install_source_package( ERROR: if (transaction) pakfire_transaction_unref(transaction); - if (request) - pakfire_request_unref(request); + if (problems) + free(problems); return r; } @@ -2220,9 +2218,9 @@ ERROR: static int pakfire_build_mkimage_install_deps(struct pakfire_build* build, const char* type) { - struct pakfire_request* request = NULL; struct pakfire_transaction* transaction = NULL; char requires[NAME_MAX]; + char* problems = NULL; int r; // Format requires @@ -2230,32 +2228,25 @@ static int pakfire_build_mkimage_install_deps(struct pakfire_build* build, if (r) goto ERROR; - // Create a new request - r = pakfire_request_create(&request, build->pakfire, 0); + // Create a new transaction + r = pakfire_transaction_create(&transaction, build->pakfire, 0); if (r) { - ERROR(build->pakfire, "Could not create request: %m\n"); + ERROR(build->pakfire, "Could not create transaction: %m\n"); goto ERROR; } // Add requires to the request - r = pakfire_request_add(request, PAKFIRE_REQ_INSTALL, requires, - PAKFIRE_REQUEST_ESSENTIAL); + r = pakfire_transaction_request(transaction, + PAKFIRE_JOB_INSTALL, requires, PAKFIRE_JOB_ESSENTIAL); if (r) { - ERROR(build->pakfire, "Could not add '%s' to the request: %m\n", requires); + ERROR(build->pakfire, "Could not add '%s' to the transaction: %m\n", requires); goto ERROR; } // Solve the request - r = pakfire_request_solve(request, 0); + r = pakfire_transaction_solve(transaction, 0, &problems); if (r) { - ERROR(build->pakfire, "Could not solve the request\n"); - goto ERROR; - } - - // Fetch the transaction - r = pakfire_request_get_transaction(request, &transaction); - if (r) { - ERROR(build->pakfire, "Could not fetch the transaction: %m\n"); + ERROR(build->pakfire, "Could not solve the request:\n%s\n", problems); goto ERROR; } @@ -2265,47 +2256,40 @@ static int pakfire_build_mkimage_install_deps(struct pakfire_build* build, goto ERROR; ERROR: - if (request) - pakfire_request_unref(request); if (transaction) pakfire_transaction_unref(transaction); + if (problems) + free(problems); return r; } static int pakfire_build_collect_packages(struct pakfire_build* build, const char* path) { - struct pakfire_request* request = NULL; struct pakfire_transaction* transaction = NULL; + char* problems = NULL; char* p = NULL; int r; - // Create a new request - r = pakfire_request_create(&request, build->pakfire, 0); + // Create a new transaction + r = pakfire_transaction_create(&transaction, build->pakfire, 0); if (r) { - ERROR(build->pakfire, "Could not create request: %m\n"); + ERROR(build->pakfire, "Could not create transaction: %m\n"); goto ERROR; } // XXX // Install the base system - r = pakfire_request_add(request, PAKFIRE_REQ_INSTALL, "ipfire-release", - PAKFIRE_REQUEST_ESSENTIAL); + r = pakfire_transaction_request(transaction, + PAKFIRE_JOB_INSTALL, "ipfire-release", PAKFIRE_JOB_ESSENTIAL); if (r) { ERROR(build->pakfire, "Could not install 'ipfire-release': %m\n"); goto ERROR; } - // Solve the request - r = pakfire_request_solve(request, 0); - if (r) { - ERROR(build->pakfire, "Could not solve request\n"); - goto ERROR; - } - - // Get the transaction - r = pakfire_request_get_transaction(request, &transaction); + // Solve the transaction + r = pakfire_transaction_solve(transaction, 0, &problems); if (r) { - ERROR(build->pakfire, "Could not fetch transaction: %m\n"); + ERROR(build->pakfire, "Could not solve request:\n%s\n", problems); goto ERROR; } @@ -2346,8 +2330,8 @@ static int pakfire_build_collect_packages(struct pakfire_build* build, const cha ERROR: if (transaction) pakfire_transaction_unref(transaction); - if (request) - pakfire_request_unref(request); + if (problems) + free(problems); if (p) free(p); diff --git a/src/libpakfire/include/pakfire/package.h b/src/libpakfire/include/pakfire/package.h index eb7398843..3558d7dce 100644 --- a/src/libpakfire/include/pakfire/package.h +++ b/src/libpakfire/include/pakfire/package.h @@ -146,7 +146,7 @@ enum pakfire_package_dump_flags { }; // Installcheck -int pakfire_package_installcheck(struct pakfire_package* pkg, char** problem); +int pakfire_package_installcheck(struct pakfire_package* pkg, char** problem, int flags); #ifdef PAKFIRE_PRIVATE diff --git a/src/libpakfire/include/pakfire/problem.h b/src/libpakfire/include/pakfire/problem.h index b9f7e6844..6232d3835 100644 --- a/src/libpakfire/include/pakfire/problem.h +++ b/src/libpakfire/include/pakfire/problem.h @@ -30,17 +30,17 @@ struct pakfire_problem* pakfire_problem_unref(struct pakfire_problem* problem); const char* pakfire_problem_to_string(struct pakfire_problem* problem); -struct pakfire_request* pakfire_problem_get_request(struct pakfire_problem* problem); - int pakfire_problem_next_solution( struct pakfire_problem* problem, struct pakfire_solution** solution); #ifdef PAKFIRE_PRIVATE -#include +#include int pakfire_problem_create(struct pakfire_problem** problem, struct pakfire* pakfire, - struct pakfire_request* request, Id id); + struct pakfire_transaction* transaction, Id id); + +struct pakfire_transaction* pakfire_problem_get_transaction(struct pakfire_problem* problem); struct pakfire* pakfire_problem_get_pakfire(struct pakfire_problem* problem); Id pakfire_problem_get_id(struct pakfire_problem* problem); diff --git a/src/libpakfire/include/pakfire/request.h b/src/libpakfire/include/pakfire/request.h deleted file mode 100644 index 2a206a266..000000000 --- a/src/libpakfire/include/pakfire/request.h +++ /dev/null @@ -1,88 +0,0 @@ -/*############################################################################# -# # -# Pakfire - The IPFire package management system # -# Copyright (C) 2013 Pakfire development team # -# # -# This program is free software: you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation, either version 3 of the License, or # -# (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program. If not, see . # -# # -#############################################################################*/ - -#ifndef PAKFIRE_REQUEST_H -#define PAKFIRE_REQUEST_H - -enum pakfire_request_flags { - PAKFIRE_REQUEST_WITHOUT_RECOMMENDED = 1 << 0, - PAKFIRE_REQUEST_ALLOW_UNINSTALL = 1 << 1, - PAKFIRE_REQUEST_ALLOW_DOWNGRADE = 1 << 2, -}; - -enum pakfire_request_job_flags { - PAKFIRE_REQUEST_KEEP_DEPS = 1 << 0, - PAKFIRE_REQUEST_KEEP_ORPHANED = 1 << 1, - PAKFIRE_REQUEST_ESSENTIAL = 1 << 2, -}; - -#ifdef PAKFIRE_PRIVATE - -#include - -#include -#include -#include -#include - -struct pakfire_request; - -enum pakfire_request_action { - PAKFIRE_REQ_INSTALL, - PAKFIRE_REQ_ERASE, - PAKFIRE_REQ_UPDATE, - PAKFIRE_REQ_UPDATE_ALL, - PAKFIRE_REQ_SYNC, - PAKFIRE_REQ_LOCK, - 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 flags); - -int pakfire_request_add(struct pakfire_request* request, - const enum pakfire_request_action action, const char* what, int flags); -int pakfire_request_add_package(struct pakfire_request* request, - const enum pakfire_request_action action, struct pakfire_package* package, int flags); - -int pakfire_request_take_solution(struct pakfire_request* request, - struct pakfire_solution* solution); - -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); - -int pakfire_request_get_transaction(struct pakfire_request* request, - struct pakfire_transaction** transaction); - -#endif - -#endif /* PAKFIRE_REQUEST_H */ diff --git a/src/libpakfire/include/pakfire/transaction.h b/src/libpakfire/include/pakfire/transaction.h index 3f21d0793..651c545e4 100644 --- a/src/libpakfire/include/pakfire/transaction.h +++ b/src/libpakfire/include/pakfire/transaction.h @@ -23,13 +23,51 @@ struct pakfire_transaction; +#include +#include + enum pakfire_transaction_flags { - PAKFIRE_TRANSACTION_DRY_RUN = (1 << 0), + // XXX DRY_RUN has to be removed + PAKFIRE_TRANSACTION_DRY_RUN = 1 << 0, + PAKFIRE_TRANSACTION_WITHOUT_RECOMMENDED = 1 << 1, + PAKFIRE_TRANSACTION_ALLOW_UNINSTALL = 1 << 2, + PAKFIRE_TRANSACTION_ALLOW_DOWNGRADE = 1 << 3, +}; + +enum pakfire_job_action { + PAKFIRE_JOB_INSTALL, + PAKFIRE_JOB_ERASE, + PAKFIRE_JOB_UPDATE, + PAKFIRE_JOB_UPDATE_ALL, + PAKFIRE_JOB_SYNC, + PAKFIRE_JOB_LOCK, + PAKFIRE_JOB_VERIFY, +}; + +enum pakfire_job_flags { + PAKFIRE_JOB_KEEP_DEPS = 1 << 0, + PAKFIRE_JOB_KEEP_ORPHANED = 1 << 1, + PAKFIRE_JOB_ESSENTIAL = 1 << 2, + PAKFIRE_JOB_BEST = 1 << 3, }; +int pakfire_transaction_create(struct pakfire_transaction** transaction, + struct pakfire* pakfire, int flags); + struct pakfire_transaction* pakfire_transaction_ref(struct pakfire_transaction* transaction); struct pakfire_transaction* pakfire_transaction_unref(struct pakfire_transaction* transaction); +// Callbacks +void pakfire_transaction_set_status_callback( + struct pakfire_transaction* transaction, pakfire_status_callback callback, void* data); + +int pakfire_transaction_solve(struct pakfire_transaction* transaction, int flags, char** problems); + +int pakfire_transaction_request(struct pakfire_transaction* transaction, + const enum pakfire_job_action action, const char* what, int flags); +int pakfire_transaction_request_package(struct pakfire_transaction* transaction, + const enum pakfire_job_action action, struct pakfire_package* package, int flags); + size_t pakfire_transaction_count(struct pakfire_transaction* transaction); char* pakfire_transaction_dump(struct pakfire_transaction* transaction, size_t width); @@ -45,9 +83,20 @@ int pakfire_transaction_download(struct pakfire_transaction* transaction); #include #include +#include -int pakfire_transaction_create(struct pakfire_transaction** transaction, - struct pakfire* pakfire, Solver* solver); +// XXX needs removal +enum pakfire_request_solve_flags { + PAKFIRE_REQ_SOLVE_INTERACTIVE, +}; + +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); int pakfire_transaction_compose_repo(struct pakfire_transaction* transaction, struct pakfire_key* key, const char* path); diff --git a/src/libpakfire/include/pakfire/ui.h b/src/libpakfire/include/pakfire/ui.h index 7bb955873..c319930a6 100644 --- a/src/libpakfire/include/pakfire/ui.h +++ b/src/libpakfire/include/pakfire/ui.h @@ -23,9 +23,9 @@ #ifdef PAKFIRE_PRIVATE -#include +#include -int pakfire_ui_pick_solution(struct pakfire* pakfire, struct pakfire_request* request); +int pakfire_ui_pick_solution(struct pakfire* pakfire, struct pakfire_transaction* transaction); #endif diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index 7c0f96fc6..ed4255889 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -279,7 +279,10 @@ global: pakfire_transaction_download; pakfire_transaction_dump; pakfire_transaction_ref; + pakfire_transaction_request; + pakfire_transaction_request_package; pakfire_transaction_run; + pakfire_transaction_set_status_callback; pakfire_transaction_unref; local: diff --git a/src/libpakfire/package.c b/src/libpakfire/package.c index d2281c351..0209e596f 100644 --- a/src/libpakfire/package.c +++ b/src/libpakfire/package.c @@ -44,8 +44,8 @@ #include #include #include -#include #include +#include #include struct pakfire_package { @@ -2462,38 +2462,42 @@ ERROR: return md; } -PAKFIRE_EXPORT int pakfire_package_installcheck(struct pakfire_package* pkg, char** problem) { - struct pakfire_request* request = NULL; +PAKFIRE_EXPORT int pakfire_package_installcheck(struct pakfire_package* pkg, + char** problem, int flags) { + struct pakfire_transaction* transaction = NULL; + char* p = 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); + // Create a new transaction + r = pakfire_transaction_create(&transaction, pkg->pakfire, flags); if (r) goto ERROR; // Install the package - r = pakfire_request_add_package(request, PAKFIRE_REQ_INSTALL, pkg, 0); + r = pakfire_transaction_request_package(transaction, + PAKFIRE_JOB_INSTALL, pkg, PAKFIRE_JOB_ESSENTIAL); 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); + // Solve the transaction + r = pakfire_transaction_solve(transaction, 0, &p); if (r) { - DEBUG(pkg->pakfire, "Could not install %s:\n", nevra); + DEBUG(pkg->pakfire, "Could not install %s:\n%s\n", nevra, p); - // Fetch the problem - *problem = pakfire_request_get_problem_string(request); - if (*problem) - DEBUG(pkg->pakfire, "%s\n", *problem); + // Copy the problem string + if (p) + *problem = strdup(p); } ERROR: - if (request) - pakfire_request_unref(request); + if (p) + free(p); + if (transaction) + pakfire_transaction_unref(transaction); return r; } diff --git a/src/libpakfire/pakfire.c b/src/libpakfire/pakfire.c index a3c74f20c..2b1691dff 100644 --- a/src/libpakfire/pakfire.c +++ b/src/libpakfire/pakfire.c @@ -57,7 +57,6 @@ #include #include #include -#include #include #include #include @@ -1899,14 +1898,13 @@ static int pakfire_perform_transaction( struct pakfire* pakfire, int transaction_flags, int solver_flags, - const enum pakfire_request_action action, + const enum pakfire_job_action action, const char** packages, const char** locks, int job_flags, int* changed, pakfire_status_callback status_callback, void* status_callback_data) { - struct pakfire_request* request = NULL; struct pakfire_transaction* transaction = NULL; int r = 1; @@ -1921,15 +1919,20 @@ static int pakfire_perform_transaction( if (r) goto ERROR; - // Create a new request - r = pakfire_request_create(&request, pakfire, solver_flags); + // Create a new transaction + r = pakfire_transaction_create(&transaction, pakfire, solver_flags); if (r) goto ERROR; + // Set status callback + if (status_callback) + pakfire_transaction_set_status_callback( + transaction, status_callback, status_callback_data); + // Lock anything that should be locked if (locks) { for (const char** lock = locks; *lock; lock++) { - r = pakfire_request_add(request, PAKFIRE_REQ_LOCK, *lock, 0); + r = pakfire_transaction_request(transaction, PAKFIRE_JOB_LOCK, *lock, 0); if (r) { ERROR(pakfire, "Could not lock '%s': %m\n", *lock); goto ERROR; @@ -1939,20 +1942,15 @@ static int pakfire_perform_transaction( // Perform action on all packages for (const char** package = packages; *package; package++) { - r = pakfire_request_add(request, action, *package, job_flags); + r = pakfire_transaction_request(transaction, action, *package, job_flags); if (r) { ERROR(pakfire, "Could not find '%s': %m\n", *package); goto ERROR; } } - // Solve the request - r = pakfire_request_solve(request, PAKFIRE_REQ_SOLVE_INTERACTIVE); - if (r) - goto ERROR; - - // Fetch the transaction - r = pakfire_request_get_transaction(request, &transaction); + // Solve the transaction + r = pakfire_transaction_solve(transaction, PAKFIRE_REQ_SOLVE_INTERACTIVE, NULL); if (r) goto ERROR; @@ -1960,11 +1958,6 @@ static int pakfire_perform_transaction( if (changed) *changed = pakfire_transaction_count(transaction); - // Set status callback - if (status_callback) - pakfire_transaction_set_status_callback( - transaction, status_callback, status_callback_data); - // Run the transaction r = pakfire_transaction_run(transaction, transaction_flags); if (r) @@ -1979,8 +1972,6 @@ ERROR: if (transaction) pakfire_transaction_unref(transaction); - if (request) - pakfire_request_unref(request); return r; } @@ -1999,7 +1990,7 @@ PAKFIRE_EXPORT int pakfire_install( pakfire, transaction_flags, solver_flags, - PAKFIRE_REQ_INSTALL, + PAKFIRE_JOB_INSTALL, packages, locks, flags, @@ -2022,7 +2013,7 @@ PAKFIRE_EXPORT int pakfire_erase( pakfire, transaction_flags, solver_flags, - PAKFIRE_REQ_ERASE, + PAKFIRE_JOB_ERASE, packages, locks, flags, @@ -2032,9 +2023,8 @@ PAKFIRE_EXPORT int pakfire_erase( } static int pakfire_perform_transaction_simple(struct pakfire* pakfire, int solver_flags, - const enum pakfire_request_action action, int job_flags, int* changed, + const enum pakfire_job_action action, int job_flags, int* changed, pakfire_status_callback status_callback, void* status_callback_data) { - struct pakfire_request* request = NULL; struct pakfire_transaction* transaction = NULL; int r = 1; @@ -2043,23 +2033,23 @@ static int pakfire_perform_transaction_simple(struct pakfire* pakfire, int solve if (r) goto ERROR; - // Create a new request - r = pakfire_request_create(&request, pakfire, solver_flags); + // Create a new transaction + r = pakfire_transaction_create(&transaction, pakfire, solver_flags); if (r) goto ERROR; - // Perform action - r = pakfire_request_add(request, action, NULL, job_flags); - if (r) - goto ERROR; + // Set status callback + if (status_callback) + pakfire_transaction_set_status_callback( + transaction, status_callback, status_callback_data); - // Solve the request - r = pakfire_request_solve(request, PAKFIRE_REQ_SOLVE_INTERACTIVE); + // Perform action + r = pakfire_transaction_request(transaction, action, NULL, job_flags); if (r) goto ERROR; - // Fetch the transaction - r = pakfire_request_get_transaction(request, &transaction); + // Solve the transaction + r = pakfire_transaction_solve(transaction, PAKFIRE_REQ_SOLVE_INTERACTIVE, NULL); if (r) goto ERROR; @@ -2067,11 +2057,6 @@ static int pakfire_perform_transaction_simple(struct pakfire* pakfire, int solve if (changed) *changed = pakfire_transaction_count(transaction); - // Set status callback - if (status_callback) - pakfire_transaction_set_status_callback( - transaction, status_callback, status_callback_data); - // Run the transaction r = pakfire_transaction_run(transaction, 0); if (r) @@ -2086,8 +2071,6 @@ ERROR: if (transaction) pakfire_transaction_unref(transaction); - if (request) - pakfire_request_unref(request); return r; } @@ -2106,16 +2089,16 @@ PAKFIRE_EXPORT int pakfire_update( // XXX add locks if (!packages) return pakfire_perform_transaction_simple( - pakfire, solver_flags, PAKFIRE_REQ_UPDATE_ALL, flags, changed, + pakfire, solver_flags, PAKFIRE_JOB_UPDATE_ALL, flags, changed, status_callback, status_callback_data); return pakfire_perform_transaction(pakfire, transaction_flags, solver_flags, - PAKFIRE_REQ_UPDATE, packages, locks, flags, changed, + PAKFIRE_JOB_UPDATE, packages, locks, flags, changed, status_callback, status_callback_data); } static int pakfire_verify(struct pakfire* pakfire, int *changed) { - return pakfire_perform_transaction_simple(pakfire, 0, PAKFIRE_REQ_VERIFY, + return pakfire_perform_transaction_simple(pakfire, 0, PAKFIRE_JOB_VERIFY, 0, changed, NULL, NULL); } @@ -2173,5 +2156,5 @@ ERROR: PAKFIRE_EXPORT int pakfire_sync(struct pakfire* pakfire, int solver_flags, int flags, int* changed, pakfire_status_callback status_callback, void* status_callback_data) { return pakfire_perform_transaction_simple(pakfire, solver_flags, - PAKFIRE_REQ_SYNC, flags, changed, status_callback, status_callback_data); + PAKFIRE_JOB_SYNC, flags, changed, status_callback, status_callback_data); } diff --git a/src/libpakfire/problem.c b/src/libpakfire/problem.c index 67d403f1e..8da224b1c 100644 --- a/src/libpakfire/problem.c +++ b/src/libpakfire/problem.c @@ -28,21 +28,21 @@ #include #include #include -#include #include +#include #include struct pakfire_problem { struct pakfire* pakfire; int nrefs; - struct pakfire_request* request; + struct pakfire_transaction* transaction; Id id; char* string; }; static char* pakfire_problem_make_string(struct pakfire_problem* problem) { - Solver* solver = pakfire_request_get_solver(problem->request); + Solver* solver = pakfire_transaction_get_solver(problem->transaction); Pool* pool = solver->pool; // Get the problem rule @@ -187,8 +187,8 @@ static char* pakfire_problem_make_string(struct pakfire_problem* problem) { return s; } -PAKFIRE_EXPORT int pakfire_problem_create(struct pakfire_problem** problem, - struct pakfire* pakfire, struct pakfire_request* request, Id id) { +int pakfire_problem_create(struct pakfire_problem** problem, + struct pakfire* pakfire, struct pakfire_transaction* transaction, Id id) { struct pakfire_problem* p = calloc(1, sizeof(*p)); if (!p) return 1; @@ -196,7 +196,7 @@ PAKFIRE_EXPORT int pakfire_problem_create(struct pakfire_problem** problem, p->pakfire = pakfire_ref(pakfire); p->nrefs = 1; - p->request = pakfire_request_ref(request); + p->transaction = pakfire_transaction_ref(transaction); p->id = id; *problem = p; @@ -210,11 +210,10 @@ PAKFIRE_EXPORT struct pakfire_problem* pakfire_problem_ref(struct pakfire_proble } static void pakfire_problem_free(struct pakfire_problem* problem) { - pakfire_request_unref(problem->request); - + if (problem->transaction) + pakfire_transaction_unref(problem->transaction); if (problem->string) free(problem->string); - pakfire_unref(problem->pakfire); free(problem); } @@ -242,13 +241,13 @@ Id pakfire_problem_get_id(struct pakfire_problem* problem) { return problem->id; } -PAKFIRE_EXPORT struct pakfire_request* pakfire_problem_get_request(struct pakfire_problem* problem) { - return pakfire_request_ref(problem->request); +struct pakfire_transaction* pakfire_problem_get_transaction(struct pakfire_problem* problem) { + return pakfire_transaction_ref(problem->transaction); } PAKFIRE_EXPORT int pakfire_problem_next_solution( struct pakfire_problem* problem, struct pakfire_solution** solution) { - Solver* solver = pakfire_request_get_solver(problem->request); + Solver* solver = pakfire_transaction_get_solver(problem->transaction); Id id = 0; // Check input diff --git a/src/libpakfire/request.c b/src/libpakfire/request.c deleted file mode 100644 index a0edf56e9..000000000 --- a/src/libpakfire/request.c +++ /dev/null @@ -1,462 +0,0 @@ -/*############################################################################# -# # -# Pakfire - The IPFire package management system # -# Copyright (C) 2013 Pakfire development team # -# # -# This program is free software: you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation, either version 3 of the License, or # -# (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program. If not, see . # -# # -#############################################################################*/ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef ENABLE_DEBUG -# include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct pakfire_request { - struct pakfire* pakfire; - int nrefs; - - Solver* solver; - Queue jobs; -}; - -static void pakfire_request_free(struct pakfire_request* request) { - if (request->solver) - solver_free(request->solver); - queue_free(&request->jobs); - - pakfire_unref(request->pakfire); - free(request); -} - -static int setup_solver(struct pakfire_request* request, int flags) { - // Obey policy when searching for the best solvable - solver_set_flag(request->solver, SOLVER_FLAG_BEST_OBEY_POLICY, 1); - - // Automatically update when installation is requested - solver_set_flag(request->solver, SOLVER_FLAG_INSTALL_ALSO_UPDATES, 1); - - // Can the solver downgrade packages? - if (flags & PAKFIRE_REQUEST_ALLOW_DOWNGRADE) - solver_set_flag(request->solver, SOLVER_FLAG_ALLOW_DOWNGRADE, 1); - - // Can the solver uninstall packages? - if (flags & PAKFIRE_REQUEST_ALLOW_UNINSTALL) - solver_set_flag(request->solver, SOLVER_FLAG_ALLOW_UNINSTALL, 1); - - // Do not install any recommended packages - if (flags & PAKFIRE_REQUEST_WITHOUT_RECOMMENDED) - solver_set_flag(request->solver, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); - - return 0; -} - -int pakfire_request_create(struct pakfire_request** request, - struct pakfire* pakfire, int flags) { - Pool* pool = pakfire_get_solv_pool(pakfire); - int r = 1; - - // Cannot create a solver when no installed repository has been set - if (!pool->installed) - return -EINVAL; - - // Allocate request - struct pakfire_request* req = calloc(1, sizeof(*req)); - if (!req) - return ENOMEM; - - req->pakfire = pakfire_ref(pakfire); - req->nrefs = 1; - - // Allocate a job queue - queue_init(&req->jobs); - - // Allocate solver - req->solver = solver_create(pool); - if (!req->solver) { - ERROR(pakfire, "Could not allocate solver: %m\n"); - goto ERROR; - } - - // Set up solver - r = setup_solver(req, flags); - if (r) - goto ERROR; - - *request = req; - return 0; - -ERROR: - pakfire_request_free(req); - return r; -} - -struct pakfire_request* pakfire_request_ref(struct pakfire_request* request) { - request->nrefs++; - - return request; -} - -struct pakfire_request* pakfire_request_unref(struct pakfire_request* request) { - if (--request->nrefs > 0) - return request; - - pakfire_request_free(request); - return NULL; -} - -Solver* pakfire_request_get_solver(struct pakfire_request* request) { - return request->solver; -} - -static int pakfire_request_pick_solution(struct pakfire_request* request) { - // XXX TODO this is just a dummy - return pakfire_ui_pick_solution(request->pakfire, request); -} - -int pakfire_request_solve(struct pakfire_request* request, int flags) { - int solved = 0; - int r; - - // Prepare pool - pakfire_pool_internalize(request->pakfire); - -#ifdef ENABLE_DEBUG - Pool* pool = pakfire_get_solv_pool(request->pakfire); - - const char* selection = pool_selection2str(pool, &request->jobs, 0); - if (selection) { - DEBUG(request->pakfire, "Solving: %s\n", selection); - } -#endif - - // Save time when we starting solving - clock_t solving_start = clock(); - -RETRY: - r = solver_solve(request->solver, &request->jobs); - switch (r) { - // Solved! - case 0: - // Mark as solved - solved = 1; - break; - - // Not Solved - default: -#ifdef ENABLE_DEBUG - // Print all solutions - solver_printallsolutions(request->solver); -#endif - - // Ask the user to pick a solution - if (flags & PAKFIRE_REQ_SOLVE_INTERACTIVE) { - r = pakfire_request_pick_solution(request); - if (r) - return r; - - // Retry solving - goto RETRY; - - } else { - char* s = pakfire_request_get_problem_string(request); - if (s) - ERROR(request->pakfire, "%s\n", s); - } - break; - } - - // Save time when we finished solving - clock_t solving_end = clock(); - - DEBUG(request->pakfire, "Solved request in %.4fms\n", - (double)(solving_end - solving_start) * 1000 / CLOCKS_PER_SEC); - -#ifdef ENABLE_DEBUG - if (solved) - solver_printdecisions(request->solver); -#endif - - // Return zero if solved, otherwise return non-zero - if (solved) - return 0; - - return 2; -} - -static int pakfire_request_is_file(const char* what) { - return pakfire_string_endswith(what, ".pfm"); -} - -static int __pakfire_request_add(struct pakfire_request* request, - const enum pakfire_request_action action, const Id type, const Id id, int flags) { - Id job = ID_NULL; - - // Check if type/ID is not set for actions that don't support it - switch (action) { - case PAKFIRE_REQ_INSTALL: - case PAKFIRE_REQ_ERASE: - case PAKFIRE_REQ_UPDATE: - case PAKFIRE_REQ_LOCK: - break; - - default: - if (type || id) { - errno = EINVAL; - return 1; - } - } - - // Essential jobs - if (flags & PAKFIRE_REQUEST_ESSENTIAL) - job |= SOLVER_ESSENTIAL; - - // Select the correct action - switch (action) { - case PAKFIRE_REQ_INSTALL: - job |= SOLVER_INSTALL; - break; - - case PAKFIRE_REQ_ERASE: - job |= SOLVER_ERASE; - - // Should we keep any dependencies? - if (!(flags & PAKFIRE_REQUEST_KEEP_DEPS)) - job |= SOLVER_CLEANDEPS; - break; - - case PAKFIRE_REQ_UPDATE: - job |= SOLVER_UPDATE; - break; - - case PAKFIRE_REQ_UPDATE_ALL: - job |= SOLVER_UPDATE|SOLVER_SOLVABLE_ALL; - break; - - case PAKFIRE_REQ_SYNC: - job |= SOLVER_DISTUPGRADE|SOLVER_SOLVABLE_ALL; - - // Drop orphans? - if (!(flags & PAKFIRE_REQUEST_KEEP_ORPHANED)) - queue_push2(&request->jobs, SOLVER_DROP_ORPHANED, 0); - break; - - case PAKFIRE_REQ_LOCK: - job |= SOLVER_LOCK; - break; - - case PAKFIRE_REQ_VERIFY: - job |= SOLVER_VERIFY|SOLVER_SOLVABLE_ALL; - break; - } - - // Add it to the job queue - queue_push2(&request->jobs, job|type, id); - - return 0; -} - -static int pakfire_request_add_job(struct pakfire_request* request, - const enum pakfire_request_action action, const char* what, int extra_flags) { - Pool* pool = pakfire_get_solv_pool(request->pakfire); - - // Make the pool ready - pakfire_pool_internalize(request->pakfire); - - Queue jobs; - queue_init(&jobs); - - int flags = - // Select packages by name - SELECTION_NAME| - // Select packages by what they provide - SELECTION_PROVIDES| - // Process globbing patterns - SELECTION_GLOB| - // Select packages by their canonical name - SELECTION_CANON| - // Process .arch - SELECTION_DOTARCH| - // Process -release - SELECTION_REL; - - // Process filelists? - if (*what == '/') - flags |= SELECTION_FILELIST; - - // Select all packages - selection_make(pool, &jobs, what, flags); - - // Did we find anything? - if (jobs.count == 0) { - Id id = pakfire_str2dep(request->pakfire, what); - if (!id) - return 1; - - queue_push2(&jobs, SOLVER_SOLVABLE_PROVIDES, id); - } - - DEBUG(request->pakfire, "Found %d match(es) for '%s'\n", jobs.count / 2, what); - - // Set action and global flags - for (int i = 0; i < jobs.count; i += 2) - __pakfire_request_add(request, action, jobs.elements[i], jobs.elements[i+1], extra_flags); - - queue_free(&jobs); - - return 0; -} - -int pakfire_request_add(struct pakfire_request* request, - const enum pakfire_request_action action, const char* what, int flags) { - struct pakfire_package* package = NULL; - int r; - - // Remove leading whitespace - if (what) { - while (*what && isspace(*what)) - what++; - } - - if (!what) { - r = __pakfire_request_add(request, action, ID_NULL, ID_NULL, flags); - if (r) - goto ERROR; - - // Check if we got given a URL or some file - } else if (pakfire_string_is_url(what) || pakfire_request_is_file(what)) { - // Add them to the commandline repository - r = pakfire_commandline_add(request->pakfire, what, &package); - if (r) - goto ERROR; - - // Then add the package - r = pakfire_request_add_package(request, action, package, flags); - if (r) - goto ERROR; - - // Otherwise try adding this as a job - } else { - r = pakfire_request_add_job(request, action, what, flags); - if (r) - goto ERROR; - } - -ERROR: - if (package) - pakfire_package_unref(package); - - return r; -} - -int pakfire_request_add_package(struct pakfire_request* request, - const enum pakfire_request_action action, struct pakfire_package* package, int flags) { - // Get the solvable ID - Id id = pakfire_package_id(package); - - // Add it to the job queue - 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; - - // 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(request->solver, id); - if (!id) - return 0; - - // Create problem - return pakfire_problem_create(problem, request->pakfire, request, id); -} - -int pakfire_request_take_solution(struct pakfire_request* request, - struct pakfire_solution* solution) { - struct pakfire_problem* problem = pakfire_solution_get_problem(solution); - - // Fetch IDs - Id problem_id = pakfire_problem_get_id(problem); - Id solution_id = pakfire_solution_get_id(solution); - - // Feed the solution into the solver - solver_take_solution(request->solver, problem_id, solution_id, &request->jobs); - - pakfire_problem_unref(problem); - return 0; -} - -int pakfire_request_get_transaction(struct pakfire_request* request, - struct pakfire_transaction** transaction) { - // XXX Check if we have solved successfully - - // Create the transaction - return pakfire_transaction_create(transaction, request->pakfire, request->solver); -} diff --git a/src/libpakfire/solution.c b/src/libpakfire/solution.c index cad749a34..7eaac79ca 100644 --- a/src/libpakfire/solution.c +++ b/src/libpakfire/solution.c @@ -27,9 +27,9 @@ #include #include #include -#include #include #include +#include #include struct pakfire_solution { @@ -94,8 +94,8 @@ Id pakfire_solution_get_id(struct pakfire_solution* solution) { } static char* pakfire_solution_make_string(struct pakfire_solution* solution) { - struct pakfire_request* request = pakfire_problem_get_request(solution->problem); - Solver* solver = pakfire_request_get_solver(request); + struct pakfire_transaction* transaction = pakfire_problem_get_transaction(solution->problem); + Solver* solver = pakfire_transaction_get_solver(transaction); Pool* pool = solver->pool; // Fetch the problem ID @@ -104,7 +104,7 @@ static char* pakfire_solution_make_string(struct pakfire_solution* solution) { // How many elements do we have? unsigned int count = solver_solutionelement_count(solver, problem_id, solution->id); if (!count) { - pakfire_request_unref(request); + pakfire_transaction_unref(transaction); return NULL; } @@ -188,7 +188,8 @@ static char* pakfire_solution_make_string(struct pakfire_solution* solution) { s = pakfire_string_join(elements, "\n"); ERROR: - pakfire_request_unref(request); + if (transaction) + pakfire_transaction_unref(transaction); // Free all elements for (char** element = elements; *element; element++) diff --git a/src/libpakfire/transaction.c b/src/libpakfire/transaction.c index a56ebae3b..eb751942b 100644 --- a/src/libpakfire/transaction.c +++ b/src/libpakfire/transaction.c @@ -18,14 +18,17 @@ # # #############################################################################*/ +#include #include #include +#include #include #include #include #include +#include #include #include #include @@ -46,6 +49,18 @@ struct pakfire_transaction { struct pakfire* pakfire; int nrefs; + // Flags + int flags; + + // The solver + Solver* solver; + enum pakfire_transaction_solver_status { + SOLVER_STATUS_UNKNOWN, + } solver_status; + + // The jobs to solve + Queue jobs; + Transaction* transaction; char** userinstalled; @@ -156,34 +171,37 @@ static void pakfire_transaction_free(struct pakfire_transaction* transaction) { free(*userinstalled); free(transaction->userinstalled); } - transaction_free(transaction->transaction); + if (transaction->transaction) + transaction_free(transaction->transaction); + + if (transaction->solver) + solver_free(transaction->solver); pakfire_unref(transaction->pakfire); free(transaction); } -static int pakfire_transaction_import_transaction( - struct pakfire_transaction* transaction, Solver* solver) { +static int pakfire_transaction_import_transaction(struct pakfire_transaction* transaction) { int r; // Clone the transaction to keep a copy of it - Transaction* t = solver_create_transaction(solver); - if (!t) + transaction->transaction = solver_create_transaction(transaction->solver); + if (!transaction->transaction) { + ERROR(transaction->pakfire, "Could not create transaction from solver: %m\n"); return 1; - - transaction->transaction = t; + } // Order the transaction - transaction_order(t, 0); + transaction_order(transaction->transaction, 0); // Log the transaction - transaction_print(t); + transaction_print(transaction->transaction); // Free any previous content pakfire_transaction_free_archives_and_packages(transaction); // How many steps? - transaction->num = t->steps.count; + transaction->num = transaction->transaction->steps.count; // Allocate space for packages transaction->packages = calloc(transaction->num, sizeof(*transaction->packages)); @@ -198,7 +216,7 @@ static int pakfire_transaction_import_transaction( // Create all packages for (unsigned int i = 0; i < transaction->num; i++) { r = pakfire_package_create_from_solvable(&transaction->packages[i], - transaction->pakfire, t->steps.elements[i]); + transaction->pakfire, transaction->transaction->steps.elements[i]); if (r) return r; } @@ -206,8 +224,7 @@ static int pakfire_transaction_import_transaction( return 0; } -static int pakfire_transaction_import_userinstalled( - struct pakfire_transaction* t, Solver* solver) { +static int pakfire_transaction_import_userinstalled(struct pakfire_transaction* transaction) { Queue userinstalled; const char* package = NULL; int r = 0; @@ -215,34 +232,34 @@ static int pakfire_transaction_import_userinstalled( queue_init(&userinstalled); // Cleanup previous content - if (t->userinstalled) { - pakfire_strings_free(t->userinstalled); - t->userinstalled = NULL; + if (transaction->userinstalled) { + pakfire_strings_free(transaction->userinstalled); + transaction->userinstalled = NULL; } // Fetch a list of all packages that are installed by the user - solver_get_userinstalled(solver, &userinstalled, GET_USERINSTALLED_NAMES); + solver_get_userinstalled(transaction->solver, &userinstalled, GET_USERINSTALLED_NAMES); // Skip everything if the queue is empty if (!userinstalled.count) goto OUT; - t->userinstalled = calloc(userinstalled.count + 1, sizeof(*t->userinstalled)); - if (!t->userinstalled) { - ERROR(t->pakfire, "Could not allocate userinstalled: %m\n"); + transaction->userinstalled = calloc(userinstalled.count + 1, sizeof(*transaction->userinstalled)); + if (!transaction->userinstalled) { + ERROR(transaction->pakfire, "Could not allocate userinstalled: %m\n"); r = -errno; goto ERROR; } - Pool* pool = pakfire_get_solv_pool(t->pakfire); + Pool* pool = pakfire_get_solv_pool(transaction->pakfire); // Store the names of all userinstalled packages for (int i = 0; i < userinstalled.count; i++) { package = pool_id2str(pool, userinstalled.elements[i]); - t->userinstalled[i] = strdup(package); + transaction->userinstalled[i] = strdup(package); - if (!t->userinstalled[i]) { + if (!transaction->userinstalled[i]) { r = -errno; goto ERROR; } @@ -252,9 +269,9 @@ static int pakfire_transaction_import_userinstalled( r = 0; ERROR: - if (t->userinstalled) { - pakfire_strings_free(t->userinstalled); - t->userinstalled = NULL; + if (transaction->userinstalled) { + pakfire_strings_free(transaction->userinstalled); + transaction->userinstalled = NULL; } OUT: @@ -263,11 +280,50 @@ OUT: return r; } -int pakfire_transaction_create(struct pakfire_transaction** transaction, - struct pakfire* pakfire, Solver* solver) { +static void pakfire_transaction_default_status_callback( + struct pakfire* pakfire, void* data, int progress, const char* status) { + // XXX perform some default action... +} + +static int pakfire_transaction_setup_solver(struct pakfire_transaction* transaction) { + Pool* pool = pakfire_get_solv_pool(transaction->pakfire); + + // Allocate a new solver + transaction->solver = solver_create(pool); + if (!transaction->solver) { + ERROR(transaction->pakfire, "Could not allocate solver: %m\n"); + return -errno; + } + + // Obey policy when searching for the best solvable + solver_set_flag(transaction->solver, SOLVER_FLAG_BEST_OBEY_POLICY, 1); + + // Automatically update when installation is requested + solver_set_flag(transaction->solver, SOLVER_FLAG_INSTALL_ALSO_UPDATES, 1); + + // Can the solver downgrade packages? + if (transaction->flags & PAKFIRE_TRANSACTION_ALLOW_DOWNGRADE) + solver_set_flag(transaction->solver, SOLVER_FLAG_ALLOW_DOWNGRADE, 1); + + // Can the solver uninstall packages? + if (transaction->flags & PAKFIRE_TRANSACTION_ALLOW_UNINSTALL) + solver_set_flag(transaction->solver, SOLVER_FLAG_ALLOW_UNINSTALL, 1); + + // Do not install any recommended packages + if (transaction->flags & PAKFIRE_TRANSACTION_WITHOUT_RECOMMENDED) + solver_set_flag(transaction->solver, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); + + return 0; +} + +PAKFIRE_EXPORT int pakfire_transaction_create(struct pakfire_transaction** transaction, + struct pakfire* pakfire, int flags) { + int r; + + // Allocate the transaction struct pakfire_transaction* t = calloc(1, sizeof(*t)); if (!t) - return ENOMEM; + return -errno; // Store reference to Pakfire t->pakfire = pakfire_ref(pakfire); @@ -275,22 +331,28 @@ int pakfire_transaction_create(struct pakfire_transaction** transaction, // Initialize the reference counter t->nrefs = 1; - // Import transaction - int r = pakfire_transaction_import_transaction(t, solver); - if (r) - goto ERROR; + // Store flags + t->flags = flags; - // Import userinstalled - r = pakfire_transaction_import_userinstalled(t, solver); + // Set the default status callback + t->callbacks.status = pakfire_transaction_default_status_callback; + + // Setup the solver + r = pakfire_transaction_setup_solver(t); if (r) goto ERROR; + // Allocate a job queue + queue_init(&t->jobs); + + // Return the transaction *transaction = t; + return 0; ERROR: pakfire_transaction_free(t); - return 1; + return r; } PAKFIRE_EXPORT struct pakfire_transaction* pakfire_transaction_ref( @@ -309,8 +371,8 @@ PAKFIRE_EXPORT struct pakfire_transaction* pakfire_transaction_unref( return NULL; } -void pakfire_transaction_set_status_callback(struct pakfire_transaction* transaction, - pakfire_status_callback callback, void* data) { +PAKFIRE_EXPORT void pakfire_transaction_set_status_callback( + struct pakfire_transaction* transaction, pakfire_status_callback callback, void* data) { transaction->callbacks.status = callback; transaction->callbacks.status_data = data; } @@ -351,6 +413,362 @@ static void pakfire_transaction_status(struct pakfire_transaction* transaction, free(buffer); } +static char* pakfire_transaction_get_problem_string(struct pakfire_transaction* transaction) { + struct pakfire_problem* problem = NULL; + const char* p = NULL; + char* s = NULL; + int r; + + for (;;) { + r = pakfire_transaction_next_problem(transaction, &problem); + if (r || !problem) + break; + + p = pakfire_problem_to_string(problem); + if (!p) + goto ERROR; + + r = asprintf(&s, "%s%s\n", (s) ? s : "", p); + if (r < 0) + goto ERROR; + } + + return s; + +ERROR: + if (s) + free(s); + + return NULL; +} + +Solver* pakfire_transaction_get_solver(struct pakfire_transaction* transaction) { + return transaction->solver; +} + +PAKFIRE_EXPORT int pakfire_transaction_solve(struct pakfire_transaction* transaction, + int flags, char** problems) { + int solved = 0; + int r; + + // XXX halt if the request has already been solved + + // Prepare pool + pakfire_pool_internalize(transaction->pakfire); + +#ifdef ENABLE_DEBUG + Pool* pool = pakfire_get_solv_pool(transaction->pakfire); + + const char* selection = pool_selection2str(pool, &transaction->jobs, 0); + if (selection) + DEBUG(transaction->pakfire, "Solving: %s\n", selection); +#endif + +RETRY: + // Save time when we starting solving + clock_t solving_start = clock(); + + r = solver_solve(transaction->solver, &transaction->jobs); + + // Save time when we finished solving + clock_t solving_end = clock(); + + DEBUG(transaction->pakfire, "Solved request in %.4fms\n", + (double)(solving_end - solving_start) * 1000 / CLOCKS_PER_SEC); + + switch (r) { + // Solved! + case 0: + // Mark as solved + solved = 1; + + // Import the transaction + r = pakfire_transaction_import_transaction(transaction); + if (r) + goto ERROR; + + // Import userinstalled packages + r = pakfire_transaction_import_userinstalled(transaction); + if (r) + goto ERROR; + + break; + + // Not Solved + default: +#ifdef ENABLE_DEBUG + // Print all solutions + solver_printallsolutions(transaction->solver); +#endif + + // Return the problems as string + if (problems) + *problems = pakfire_transaction_get_problem_string(transaction); + + // Ask the user to pick a solution + if (flags & PAKFIRE_REQ_SOLVE_INTERACTIVE) { + r = pakfire_ui_pick_solution(transaction->pakfire, transaction); + if (r) + return r; + + // Retry solving + goto RETRY; + + } else { + char* s = pakfire_transaction_get_problem_string(transaction); + if (s) + ERROR(transaction->pakfire, "%s\n", s); + } + break; + } + +#ifdef ENABLE_DEBUG + if (solved) + solver_printdecisions(transaction->solver); +#endif + + // Return zero if solved, otherwise return non-zero + if (solved) + return 0; + + return 2; + +ERROR: + return r; +} + +static int pakfire_transaction_is_file(const char* what) { + return pakfire_string_endswith(what, ".pfm"); +} + +static int __pakfire_transaction_add(struct pakfire_transaction* transaction, + const enum pakfire_job_action action, const Id type, const Id id, int flags) { + Id job = ID_NULL; + + // Check if type/ID is not set for actions that don't support it + switch (action) { + case PAKFIRE_JOB_INSTALL: + case PAKFIRE_JOB_ERASE: + case PAKFIRE_JOB_UPDATE: + case PAKFIRE_JOB_LOCK: + break; + + default: + if (type || id) + return -EINVAL; + } + + // Essential jobs + if (flags & PAKFIRE_JOB_ESSENTIAL) + job |= SOLVER_ESSENTIAL; + + // Install the best package only? + if (flags & PAKFIRE_JOB_BEST) + job |= SOLVER_FORCEBEST; + + // Select the correct action + switch (action) { + case PAKFIRE_JOB_INSTALL: + job |= SOLVER_INSTALL; + break; + + case PAKFIRE_JOB_ERASE: + job |= SOLVER_ERASE; + + // Should we keep any dependencies? + if (!(flags & PAKFIRE_JOB_KEEP_DEPS)) + job |= SOLVER_CLEANDEPS; + break; + + case PAKFIRE_JOB_UPDATE: + job |= SOLVER_UPDATE; + break; + + case PAKFIRE_JOB_UPDATE_ALL: + job |= SOLVER_UPDATE|SOLVER_SOLVABLE_ALL; + break; + + case PAKFIRE_JOB_SYNC: + job |= SOLVER_DISTUPGRADE|SOLVER_SOLVABLE_ALL; + + // Drop orphans? + if (!(flags & PAKFIRE_JOB_KEEP_ORPHANED)) + queue_push2(&transaction->jobs, SOLVER_DROP_ORPHANED, 0); + break; + + case PAKFIRE_JOB_LOCK: + job |= SOLVER_LOCK; + break; + + case PAKFIRE_JOB_VERIFY: + job |= SOLVER_VERIFY|SOLVER_SOLVABLE_ALL; + break; + } + + // Add it to the job queue + queue_push2(&transaction->jobs, job|type, id); + + return 0; +} + +static int pakfire_transaction_add_job(struct pakfire_transaction* transaction, + const enum pakfire_job_action action, const char* what, int extra_flags) { + Queue jobs; + int r; + + Pool* pool = pakfire_get_solv_pool(transaction->pakfire); + + // Make the pool ready + pakfire_pool_internalize(transaction->pakfire); + + // Initialize jobs + queue_init(&jobs); + + int flags = + // Select packages by name + SELECTION_NAME| + // Select packages by what they provide + SELECTION_PROVIDES| + // Process globbing patterns + SELECTION_GLOB| + // Select packages by their canonical name + SELECTION_CANON| + // Process .arch + SELECTION_DOTARCH| + // Process -release + SELECTION_REL; + + // Process filelists? + if (*what == '/') + flags |= SELECTION_FILELIST; + + // Select all packages + selection_make(pool, &jobs, what, flags); + + // Did we find anything? + if (jobs.count == 0) { + Id id = pakfire_str2dep(transaction->pakfire, what); + if (!id) { + r = -errno; + goto ERROR; + } + + queue_push2(&jobs, SOLVER_SOLVABLE_PROVIDES, id); + } + + DEBUG(transaction->pakfire, "Found %d match(es) for '%s'\n", jobs.count / 2, what); + + // Set action and global flags + for (int i = 0; i < jobs.count; i += 2) { + r = __pakfire_transaction_add(transaction, action, + jobs.elements[i], jobs.elements[i+1], extra_flags); + if (r) + goto ERROR; + } + + // Success + r = 0; + +ERROR: + queue_free(&jobs); + + return r; +} + +PAKFIRE_EXPORT int pakfire_transaction_request(struct pakfire_transaction* transaction, + const enum pakfire_job_action action, const char* what, int flags) { + struct pakfire_package* package = NULL; + int r; + + // Remove leading whitespace + if (what) { + while (*what && isspace(*what)) + what++; + } + + if (!what) { + r = __pakfire_transaction_add(transaction, action, ID_NULL, ID_NULL, flags); + if (r) + goto ERROR; + + // Check if we got given a URL or some file + } else if (pakfire_string_is_url(what) || pakfire_transaction_is_file(what)) { + // Add them to the commandline repository + r = pakfire_commandline_add(transaction->pakfire, what, &package); + if (r) + goto ERROR; + + // Then add the package + r = pakfire_transaction_request_package(transaction, action, package, flags); + if (r) + goto ERROR; + + // Otherwise try adding this as a job + } else { + r = pakfire_transaction_add_job(transaction, action, what, flags); + if (r) + goto ERROR; + } + +ERROR: + if (package) + pakfire_package_unref(package); + + return r; +} + +PAKFIRE_EXPORT int pakfire_transaction_request_package(struct pakfire_transaction* transaction, + const enum pakfire_job_action action, struct pakfire_package* package, int flags) { + // Get the solvable ID + Id id = pakfire_package_id(package); + + // Add it to the job queue + 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); + + // Fetch IDs + Id problem_id = pakfire_problem_get_id(problem); + Id solution_id = pakfire_solution_get_id(solution); + + // Feed the solution into the solver + solver_take_solution(transaction->solver, problem_id, solution_id, &transaction->jobs); + + pakfire_problem_unref(problem); + return 0; +} + PAKFIRE_EXPORT size_t pakfire_transaction_count(struct pakfire_transaction* transaction) { return transaction->num; } @@ -1443,6 +1861,9 @@ PAKFIRE_EXPORT int pakfire_transaction_run( struct pakfire_transaction* transaction, int flags) { int r; + // XXX automatically solve + // XXX automatically download + // Skip running an empty transaction if (!transaction->num) { DEBUG(transaction->pakfire, "Empty transaction. Skipping...\n"); diff --git a/src/libpakfire/ui.c b/src/libpakfire/ui.c index ca9223189..b8c9f095f 100644 --- a/src/libpakfire/ui.c +++ b/src/libpakfire/ui.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include static int pakfire_ui_is_interactive(struct pakfire* pakfire) { @@ -112,7 +112,7 @@ static struct pakfire_solution** pakfire_ui_append_solution( return list; } -int pakfire_ui_pick_solution(struct pakfire* pakfire, struct pakfire_request* request) { +int pakfire_ui_pick_solution(struct pakfire* pakfire, struct pakfire_transaction* transaction) { struct pakfire_problem* problem = NULL; struct pakfire_solution** solutions = NULL; struct pakfire_solution* solution = NULL; @@ -124,7 +124,7 @@ int pakfire_ui_pick_solution(struct pakfire* pakfire, struct pakfire_request* re // Print all problems for (;;) { - r = pakfire_request_next_problem(request, &problem); + r = pakfire_transaction_next_problem(transaction, &problem); if (r) goto ERROR; @@ -175,7 +175,7 @@ int pakfire_ui_pick_solution(struct pakfire* pakfire, struct pakfire_request* re goto ERROR; // Fetch selected solution into the solver - r = pakfire_request_take_solution(request, solutions[choice - 1]); + r = pakfire_transaction_take_solution(transaction, solutions[choice - 1]); if (r) goto ERROR;