1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2013 Pakfire development team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
25 #include <solv/transaction.h>
27 #include <pakfire/db.h>
28 #include <pakfire/downloader.h>
29 #include <pakfire/i18n.h>
30 #include <pakfire/logging.h>
31 #include <pakfire/package.h>
32 #include <pakfire/packagelist.h>
33 #include <pakfire/pakfire.h>
34 #include <pakfire/private.h>
35 #include <pakfire/repo.h>
36 #include <pakfire/step.h>
37 #include <pakfire/transaction.h>
38 #include <pakfire/types.h>
39 #include <pakfire/util.h>
41 struct _PakfireTransaction
{
43 Transaction
* transaction
;
49 static pakfire_step_type_t
transaction_get_step_type(Transaction
* transaction
, Id id
) {
50 int type
= transaction_type(transaction
, id
,
51 SOLVER_TRANSACTION_SHOW_ACTIVE
|SOLVER_TRANSACTION_CHANGE_IS_REINSTALL
);
53 // Translate solver types into our own types
55 case SOLVER_TRANSACTION_INSTALL
:
56 case SOLVER_TRANSACTION_MULTIINSTALL
:
57 return PAKFIRE_STEP_INSTALL
;
59 case SOLVER_TRANSACTION_REINSTALL
:
60 case SOLVER_TRANSACTION_MULTIREINSTALL
:
61 return PAKFIRE_STEP_REINSTALL
;
63 case SOLVER_TRANSACTION_ERASE
:
64 return PAKFIRE_STEP_ERASE
;
66 case SOLVER_TRANSACTION_DOWNGRADE
:
67 return PAKFIRE_STEP_DOWNGRADE
;
69 case SOLVER_TRANSACTION_UPGRADE
:
70 return PAKFIRE_STEP_UPGRADE
;
72 case SOLVER_TRANSACTION_OBSOLETES
:
73 return PAKFIRE_STEP_OBSOLETE
;
75 // Anything we don't care about
76 case SOLVER_TRANSACTION_IGNORE
:
77 case SOLVER_TRANSACTION_REINSTALLED
:
78 case SOLVER_TRANSACTION_DOWNGRADED
:
80 return PAKFIRE_STEP_IGNORE
;
84 PAKFIRE_EXPORT PakfireTransaction
pakfire_transaction_create(Pakfire pakfire
, Transaction
* trans
) {
85 PakfireTransaction transaction
= calloc(1, sizeof(*transaction
));
87 DEBUG(pakfire
, "Allocated Transaction at %p\n", transaction
);
88 transaction
->nrefs
= 1;
90 transaction
->pakfire
= pakfire_ref(pakfire
);
92 // Clone the transaction, so we get independent from what ever called this.
94 transaction
->transaction
= transaction_create_clone(trans
);
95 transaction_order(transaction
->transaction
, 0);
97 transaction
->transaction
= transaction_create(trans
->pool
);
100 // Save total number of steps
101 transaction
->num_steps
= transaction
->transaction
->steps
.count
;
104 PakfireStep
* steps
= transaction
->steps
= calloc(transaction
->num_steps
+ 1, sizeof(*steps
));
105 for (unsigned int i
= 0; i
< transaction
->num_steps
; i
++) {
106 Id id
= transaction
->transaction
->steps
.elements
[i
];
109 pakfire_step_type_t type
= transaction_get_step_type(transaction
->transaction
, id
);
112 PakfirePackage pkg
= pakfire_package_create_from_solvable(pakfire
, id
);
115 *steps
++ = pakfire_step_create(transaction
, type
, pkg
);
117 pakfire_package_unref(pkg
);
124 PAKFIRE_EXPORT PakfireTransaction
pakfire_transaction_ref(PakfireTransaction transaction
) {
128 transaction
->nrefs
++;
132 void pakfire_transaction_free(PakfireTransaction transaction
) {
133 DEBUG(transaction
->pakfire
, "Releasing Transaction at %p\n", transaction
);
134 pakfire_unref(transaction
->pakfire
);
137 while (*transaction
->steps
)
138 pakfire_step_unref(*transaction
->steps
++);
140 transaction_free(transaction
->transaction
);
144 PAKFIRE_EXPORT PakfireTransaction
pakfire_transaction_unref(PakfireTransaction transaction
) {
148 if (--transaction
->nrefs
> 0)
151 pakfire_transaction_free(transaction
);
155 PAKFIRE_EXPORT Pakfire
pakfire_transaction_get_pakfire(PakfireTransaction transaction
) {
156 return pakfire_ref(transaction
->pakfire
);
159 Transaction
* pakfire_transaction_get_transaction(PakfireTransaction transaction
) {
160 return transaction
->transaction
;
163 PAKFIRE_EXPORT
size_t pakfire_transaction_count(PakfireTransaction transaction
) {
164 return transaction
->num_steps
;
167 PAKFIRE_EXPORT ssize_t
pakfire_transaction_installsizechange(PakfireTransaction transaction
) {
168 ssize_t sizechange
= transaction_calc_installsizechange(transaction
->transaction
);
170 // Convert from kbytes to bytes
171 return sizechange
* 1024;
174 PAKFIRE_EXPORT ssize_t
pakfire_transaction_downloadsize(PakfireTransaction transaction
) {
177 PakfireStep
* steps
= transaction
->steps
;
179 PakfireStep step
= *steps
++;
181 size
+= pakfire_step_get_downloadsize(step
);
187 PAKFIRE_EXPORT PakfireStep
pakfire_transaction_get_step(PakfireTransaction transaction
, unsigned int index
) {
188 PakfireStep
* steps
= transaction
->steps
;
190 while (index
-- && *steps
)
194 return pakfire_step_ref(*steps
);
199 PAKFIRE_EXPORT PakfirePackageList
pakfire_transaction_get_packages(PakfireTransaction transaction
, pakfire_step_type_t type
) {
200 PakfirePackageList packagelist
= pakfire_packagelist_create(transaction
->pakfire
);
202 PakfireStep
* steps
= transaction
->steps
;
204 PakfireStep step
= *steps
++;
206 if (pakfire_step_get_type(step
) == type
) {
207 PakfirePackage package
= pakfire_step_get_package(step
);
208 pakfire_packagelist_push(packagelist
, package
);
210 pakfire_package_unref(package
);
214 // Sort list in place
215 pakfire_packagelist_sort(packagelist
);
220 static void pakfire_transaction_add_headline(char** str
, size_t width
, const char* headline
) {
223 asprintf(str
, "%s%s\n", *str
, headline
);
226 static void pakfire_transaction_add_newline(char** str
, size_t width
) {
227 asprintf(str
, "%s\n", *str
);
230 static void pakfire_transaction_add_line(char** str
, size_t width
, const char* name
,
231 const char* arch
, const char* version
, const char* repo
, const char* size
) {
232 // XXX need to adapt to size
233 asprintf(str
, "%s %-21s %-8s %-21s %-18s %6s \n", *str
, name
, arch
, version
, repo
, size
);
236 static void pakfire_transaction_add_package(char** str
, size_t width
, PakfirePackage pkg
) {
237 PakfireRepo repo
= pakfire_package_get_repo(pkg
);
239 unsigned long long size
= pakfire_package_get_size(pkg
);
240 char* size_str
= pakfire_format_size(size
);
242 pakfire_transaction_add_line(str
, width
,
243 pakfire_package_get_name(pkg
),
244 pakfire_package_get_arch(pkg
),
245 pakfire_package_get_evr(pkg
),
246 pakfire_repo_get_name(repo
),
250 pakfire_repo_unref(repo
);
254 static void pakfire_transaction_add_separator(char** str
, size_t width
) {
256 asprintf(str
, "%s=", *str
);
259 asprintf(str
, "%s\n", *str
);
262 static size_t pakfire_transaction_add_section(char** str
, size_t width
, PakfireTransaction transaction
,
263 const char* headline
, pakfire_step_type_t type
) {
264 PakfirePackageList list
= pakfire_transaction_get_packages(transaction
, type
);
266 // Nothing to do if there are no packages in this stage
267 size_t c
= pakfire_packagelist_count(list
);
272 pakfire_transaction_add_headline(str
, width
, headline
);
275 for (unsigned int i
= 0; i
< c
; i
++) {
276 PakfirePackage pkg
= pakfire_packagelist_get(list
, i
);
277 pakfire_transaction_add_package(str
, width
, pkg
);
278 pakfire_package_unref(pkg
);
282 pakfire_transaction_add_newline(str
, width
);
285 pakfire_packagelist_unref(list
);
290 static void pakfire_transaction_add_summary_line(char** str
, size_t width
, const char* headline
, size_t pkgs
) {
292 asprintf(str
, "%s%-20s %-4zu %s\n", *str
, headline
, pkgs
, _("package(s)"));
295 static void pakfire_transaction_add_usage_line(char** str
, size_t width
, const char* headline
, ssize_t size
) {
296 char* s
= pakfire_format_size(size
);
298 asprintf(str
, "%s%-21s: %s\n", *str
, headline
, s
);
303 PAKFIRE_EXPORT
char* pakfire_transaction_dump(PakfireTransaction transaction
, size_t width
) {
307 pakfire_transaction_add_separator(&string
, width
);
308 pakfire_transaction_add_line(&string
, width
,
315 pakfire_transaction_add_separator(&string
, width
);
317 // Show what we are doing
318 size_t installing
= pakfire_transaction_add_section(&string
, width
, transaction
,
319 _("Installing:"), PAKFIRE_STEP_INSTALL
);
320 size_t reinstalling
= pakfire_transaction_add_section(&string
, width
, transaction
,
321 _("Reinstalling:"), PAKFIRE_STEP_REINSTALL
);
322 size_t updating
= pakfire_transaction_add_section(&string
, width
, transaction
,
323 _("Updating:"), PAKFIRE_STEP_UPGRADE
);
324 size_t downgrading
= pakfire_transaction_add_section(&string
, width
, transaction
,
325 _("Downgrading:"), PAKFIRE_STEP_DOWNGRADE
);
326 size_t removing
= pakfire_transaction_add_section(&string
, width
, transaction
,
327 _("Removing:"), PAKFIRE_STEP_ERASE
);
328 size_t obsoleting
= pakfire_transaction_add_section(&string
, width
, transaction
,
329 _("Obsoleting:"), PAKFIRE_STEP_OBSOLETE
);
332 pakfire_transaction_add_headline(&string
, width
, _("Transaction Summary"));
333 pakfire_transaction_add_separator(&string
, width
);
335 pakfire_transaction_add_summary_line(&string
, width
, _("Installing:"), installing
);
336 pakfire_transaction_add_summary_line(&string
, width
, _("Reinstalling:"), reinstalling
);
337 pakfire_transaction_add_summary_line(&string
, width
, _("Updating:"), updating
);
338 pakfire_transaction_add_summary_line(&string
, width
, _("Downgrading:"), downgrading
);
339 pakfire_transaction_add_summary_line(&string
, width
, _("Removing:"), removing
);
340 pakfire_transaction_add_summary_line(&string
, width
, _("Obsoleting:"), obsoleting
);
342 // How much do we need to download?
343 size_t downloadsize
= pakfire_transaction_downloadsize(transaction
);
344 if (downloadsize
> 0)
345 pakfire_transaction_add_usage_line(&string
, width
,
346 _("Total Download Size"), downloadsize
);
348 // How much more space do we need?
349 ssize_t sizechange
= pakfire_transaction_installsizechange(transaction
);
351 pakfire_transaction_add_usage_line(&string
, width
,
352 (sizechange
>= 0) ? _("Installed Size") : _("Freed Size"), sizechange
);
354 // Remove trailing newline
355 size_t l
= strlen(string
) - 1;
357 if (l
> 0 && string
[l
] == '\n')
360 DEBUG(transaction
->pakfire
, "Transaction: %s\n", string
);
365 static int pakfire_transaction_run_steps(PakfireTransaction transaction
,
366 struct pakfire_db
* db
, const pakfire_action_type_t action
) {
369 // Walk through all steps
370 PakfireStep
* steps
= transaction
->steps
;
372 PakfireStep step
= *steps
++;
375 r
= pakfire_step_run(step
, db
, action
);
377 // End loop if action was unsuccessful
379 DEBUG(transaction
->pakfire
, "Step %p failed with code %d\n", step
, r
);
387 PAKFIRE_EXPORT
int pakfire_transaction_run(PakfireTransaction transaction
) {
388 struct pakfire_db
* db
;
391 DEBUG(transaction
->pakfire
, "Running Transaction %p\n", transaction
);
394 r
= pakfire_db_open(&db
, transaction
->pakfire
, PAKFIRE_DB_READWRITE
);
396 ERROR(transaction
->pakfire
, "Could not open the database\n");
401 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_VERIFY
);
405 // Execute all pre transaction actions
406 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_PRETRANS
);
410 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_EXECUTE
);
414 // Execute all post transaction actions
415 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_POSTTRANS
);
419 DEBUG(transaction
->pakfire
, "The transaction has finished successfully\n");
423 pakfire_db_unref(db
);
428 static int pakfire_transaction_download_package(PakfireTransaction transaction
,
429 struct pakfire_downloader
* downloader
, PakfirePackage pkg
) {
431 PakfireRepo repo
= NULL
;
432 struct pakfire_mirrorlist
* mirrors
= NULL
;
433 char* cache_path
= NULL
;
435 // Fetch the repository to download from
436 repo
= pakfire_package_get_repo(pkg
);
441 mirrors
= pakfire_repo_get_mirrors(repo
);
445 // Where to store the package?
446 cache_path
= pakfire_package_get_cache_path(pkg
);
450 // What file to download?
451 const char* filename
= pakfire_package_get_filename(pkg
);
455 // Add transfer to downloader
456 r
= pakfire_downloader_add_transfer(downloader
, mirrors
, filename
, cache_path
);
462 pakfire_mirrorlist_unref(mirrors
);
464 pakfire_repo_unref(repo
);
469 PAKFIRE_EXPORT
int pakfire_transaction_download(PakfireTransaction transaction
) {
470 struct pakfire_downloader
* downloader
;
473 // Initialize the downloader
474 r
= pakfire_downloader_create(&downloader
, transaction
->pakfire
);
476 ERROR(transaction
->pakfire
, "Could not initialize downloader: %s\n",
481 // Add all packages that need to be downloaded
482 for (unsigned int i
= 0; i
< transaction
->num_steps
; i
++) {
483 PakfireStep step
= transaction
->steps
[i
];
485 // Skip all steps that do not require a download
486 if (!pakfire_step_needs_download(step
))
490 PakfirePackage pkg
= pakfire_step_get_package(step
);
493 r
= pakfire_transaction_download_package(transaction
, downloader
, pkg
);
494 pakfire_package_unref(pkg
);
500 // Run the downloader
501 r
= pakfire_downloader_run(downloader
);
504 pakfire_downloader_unref(downloader
);