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 #############################################################################*/
24 #include <solv/transaction.h>
26 #include <pakfire/db.h>
27 #include <pakfire/downloader.h>
28 #include <pakfire/i18n.h>
29 #include <pakfire/logging.h>
30 #include <pakfire/package.h>
31 #include <pakfire/packagelist.h>
32 #include <pakfire/pakfire.h>
33 #include <pakfire/private.h>
34 #include <pakfire/repo.h>
35 #include <pakfire/step.h>
36 #include <pakfire/transaction.h>
37 #include <pakfire/types.h>
38 #include <pakfire/util.h>
40 struct _PakfireTransaction
{
42 Transaction
* transaction
;
48 static pakfire_step_type_t
transaction_get_step_type(Transaction
* transaction
, Id id
) {
49 int type
= transaction_type(transaction
, id
,
50 SOLVER_TRANSACTION_SHOW_ACTIVE
|SOLVER_TRANSACTION_CHANGE_IS_REINSTALL
);
52 // Translate solver types into our own types
54 case SOLVER_TRANSACTION_INSTALL
:
55 case SOLVER_TRANSACTION_MULTIINSTALL
:
56 return PAKFIRE_STEP_INSTALL
;
58 case SOLVER_TRANSACTION_REINSTALL
:
59 case SOLVER_TRANSACTION_MULTIREINSTALL
:
60 return PAKFIRE_STEP_REINSTALL
;
62 case SOLVER_TRANSACTION_ERASE
:
63 return PAKFIRE_STEP_ERASE
;
65 case SOLVER_TRANSACTION_DOWNGRADE
:
66 return PAKFIRE_STEP_DOWNGRADE
;
68 case SOLVER_TRANSACTION_UPGRADE
:
69 return PAKFIRE_STEP_UPGRADE
;
71 case SOLVER_TRANSACTION_OBSOLETES
:
72 return PAKFIRE_STEP_OBSOLETE
;
74 // Anything we don't care about
75 case SOLVER_TRANSACTION_IGNORE
:
76 case SOLVER_TRANSACTION_REINSTALLED
:
77 case SOLVER_TRANSACTION_DOWNGRADED
:
79 return PAKFIRE_STEP_IGNORE
;
83 PAKFIRE_EXPORT PakfireTransaction
pakfire_transaction_create(Pakfire pakfire
, Transaction
* trans
) {
84 PakfireTransaction transaction
= calloc(1, sizeof(*transaction
));
86 DEBUG(pakfire
, "Allocated Transaction at %p\n", transaction
);
87 transaction
->nrefs
= 1;
89 transaction
->pakfire
= pakfire_ref(pakfire
);
91 // Clone the transaction, so we get independent from what ever called this.
93 transaction
->transaction
= transaction_create_clone(trans
);
94 transaction_order(transaction
->transaction
, 0);
96 transaction
->transaction
= transaction_create(trans
->pool
);
99 // Save total number of steps
100 transaction
->num_steps
= transaction
->transaction
->steps
.count
;
103 PakfireStep
* steps
= transaction
->steps
= calloc(transaction
->num_steps
+ 1, sizeof(*steps
));
104 for (unsigned int i
= 0; i
< transaction
->num_steps
; i
++) {
105 Id id
= transaction
->transaction
->steps
.elements
[i
];
108 pakfire_step_type_t type
= transaction_get_step_type(transaction
->transaction
, id
);
111 PakfirePackage pkg
= pakfire_package_create_from_solvable(pakfire
, id
);
114 *steps
++ = pakfire_step_create(transaction
, type
, pkg
);
116 pakfire_package_unref(pkg
);
123 PAKFIRE_EXPORT PakfireTransaction
pakfire_transaction_ref(PakfireTransaction transaction
) {
127 transaction
->nrefs
++;
131 void pakfire_transaction_free(PakfireTransaction transaction
) {
132 DEBUG(transaction
->pakfire
, "Releasing Transaction at %p\n", transaction
);
133 pakfire_unref(transaction
->pakfire
);
136 while (*transaction
->steps
)
137 pakfire_step_unref(*transaction
->steps
++);
139 transaction_free(transaction
->transaction
);
143 PAKFIRE_EXPORT PakfireTransaction
pakfire_transaction_unref(PakfireTransaction transaction
) {
147 if (--transaction
->nrefs
> 0)
150 pakfire_transaction_free(transaction
);
154 PAKFIRE_EXPORT Pakfire
pakfire_transaction_get_pakfire(PakfireTransaction transaction
) {
155 return pakfire_ref(transaction
->pakfire
);
158 Transaction
* pakfire_transaction_get_transaction(PakfireTransaction transaction
) {
159 return transaction
->transaction
;
162 PAKFIRE_EXPORT
size_t pakfire_transaction_count(PakfireTransaction transaction
) {
163 return transaction
->num_steps
;
166 PAKFIRE_EXPORT ssize_t
pakfire_transaction_installsizechange(PakfireTransaction transaction
) {
167 ssize_t sizechange
= transaction_calc_installsizechange(transaction
->transaction
);
169 // Convert from kbytes to bytes
170 return sizechange
* 1024;
173 PAKFIRE_EXPORT ssize_t
pakfire_transaction_downloadsize(PakfireTransaction transaction
) {
176 PakfireStep
* steps
= transaction
->steps
;
178 PakfireStep step
= *steps
++;
180 size
+= pakfire_step_get_downloadsize(step
);
186 PAKFIRE_EXPORT PakfireStep
pakfire_transaction_get_step(PakfireTransaction transaction
, unsigned int index
) {
187 PakfireStep
* steps
= transaction
->steps
;
189 while (index
-- && *steps
)
193 return pakfire_step_ref(*steps
);
198 PAKFIRE_EXPORT PakfirePackageList
pakfire_transaction_get_packages(PakfireTransaction transaction
, pakfire_step_type_t type
) {
199 PakfirePackageList packagelist
= pakfire_packagelist_create(transaction
->pakfire
);
201 PakfireStep
* steps
= transaction
->steps
;
203 PakfireStep step
= *steps
++;
205 if (pakfire_step_get_type(step
) == type
) {
206 PakfirePackage package
= pakfire_step_get_package(step
);
207 pakfire_packagelist_push(packagelist
, package
);
209 pakfire_package_unref(package
);
213 // Sort list in place
214 pakfire_packagelist_sort(packagelist
);
219 static void pakfire_transaction_add_headline(char** str
, size_t width
, const char* headline
) {
220 asprintf(str
, "%s%s\n", *str
, headline
);
223 static void pakfire_transaction_add_newline(char** str
, size_t width
) {
224 asprintf(str
, "%s\n", *str
);
227 static void pakfire_transaction_add_line(char** str
, size_t width
, const char* name
,
228 const char* arch
, const char* version
, const char* repo
, const char* size
) {
229 // XXX need to adapt to size
230 asprintf(str
, "%s %-21s %-8s %-21s %-18s %6s \n", *str
, name
, arch
, version
, repo
, size
);
233 static void pakfire_transaction_add_package(char** str
, size_t width
, PakfirePackage pkg
) {
234 PakfireRepo repo
= pakfire_package_get_repo(pkg
);
236 unsigned long long size
= pakfire_package_get_size(pkg
);
237 char* size_str
= pakfire_format_size(size
);
239 pakfire_transaction_add_line(str
, width
,
240 pakfire_package_get_name(pkg
),
241 pakfire_package_get_arch(pkg
),
242 pakfire_package_get_evr(pkg
),
243 pakfire_repo_get_name(repo
),
247 pakfire_repo_unref(repo
);
251 static void pakfire_transaction_add_separator(char** str
, size_t width
) {
253 asprintf(str
, "%s=", *str
);
256 asprintf(str
, "%s\n", *str
);
259 static size_t pakfire_transaction_add_section(char** str
, size_t width
, PakfireTransaction transaction
,
260 const char* headline
, pakfire_step_type_t type
) {
261 PakfirePackageList list
= pakfire_transaction_get_packages(transaction
, type
);
263 // Nothing to do if there are no packages in this stage
264 size_t c
= pakfire_packagelist_count(list
);
269 pakfire_transaction_add_headline(str
, width
, headline
);
272 for (unsigned int i
= 0; i
< c
; i
++) {
273 PakfirePackage pkg
= pakfire_packagelist_get(list
, i
);
274 pakfire_transaction_add_package(str
, width
, pkg
);
275 pakfire_package_unref(pkg
);
279 pakfire_transaction_add_newline(str
, width
);
282 pakfire_packagelist_unref(list
);
287 static void pakfire_transaction_add_summary_line(char** str
, size_t width
, const char* headline
, size_t pkgs
) {
289 asprintf(str
, "%s%-20s %-4zu %s\n", *str
, headline
, pkgs
, _("package(s)"));
292 static void pakfire_transaction_add_usage_line(char** str
, size_t width
, const char* headline
, ssize_t size
) {
293 char* s
= pakfire_format_size(size
);
295 asprintf(str
, "%s%-21s: %s\n", *str
, headline
, s
);
300 PAKFIRE_EXPORT
char* pakfire_transaction_dump(PakfireTransaction transaction
, size_t width
) {
304 pakfire_transaction_add_separator(&string
, width
);
305 pakfire_transaction_add_line(&string
, width
,
312 pakfire_transaction_add_separator(&string
, width
);
314 // Show what we are doing
315 size_t installing
= pakfire_transaction_add_section(&string
, width
, transaction
,
316 _("Installing:"), PAKFIRE_STEP_INSTALL
);
317 size_t reinstalling
= pakfire_transaction_add_section(&string
, width
, transaction
,
318 _("Reinstalling:"), PAKFIRE_STEP_REINSTALL
);
319 size_t updating
= pakfire_transaction_add_section(&string
, width
, transaction
,
320 _("Updating:"), PAKFIRE_STEP_UPGRADE
);
321 size_t downgrading
= pakfire_transaction_add_section(&string
, width
, transaction
,
322 _("Downgrading:"), PAKFIRE_STEP_DOWNGRADE
);
323 size_t removing
= pakfire_transaction_add_section(&string
, width
, transaction
,
324 _("Removing:"), PAKFIRE_STEP_ERASE
);
325 size_t obsoleting
= pakfire_transaction_add_section(&string
, width
, transaction
,
326 _("Obsoleting:"), PAKFIRE_STEP_OBSOLETE
);
329 pakfire_transaction_add_headline(&string
, width
, _("Transaction Summary"));
330 pakfire_transaction_add_separator(&string
, width
);
332 pakfire_transaction_add_summary_line(&string
, width
, _("Installing:"), installing
);
333 pakfire_transaction_add_summary_line(&string
, width
, _("Reinstalling:"), reinstalling
);
334 pakfire_transaction_add_summary_line(&string
, width
, _("Updating:"), updating
);
335 pakfire_transaction_add_summary_line(&string
, width
, _("Downgrading:"), downgrading
);
336 pakfire_transaction_add_summary_line(&string
, width
, _("Removing:"), removing
);
337 pakfire_transaction_add_summary_line(&string
, width
, _("Obsoleting:"), obsoleting
);
339 // How much do we need to download?
340 size_t downloadsize
= pakfire_transaction_downloadsize(transaction
);
341 if (downloadsize
> 0)
342 pakfire_transaction_add_usage_line(&string
, width
,
343 _("Total Download Size"), downloadsize
);
345 // How much more space do we need?
346 ssize_t sizechange
= pakfire_transaction_installsizechange(transaction
);
348 pakfire_transaction_add_usage_line(&string
, width
,
349 (sizechange
>= 0) ? _("Installed Size") : _("Freed Size"), sizechange
);
351 // Remove trailing newline
352 size_t l
= strlen(string
) - 1;
354 if (l
> 0 && string
[l
] == '\n')
357 DEBUG(transaction
->pakfire
, "Transaction: %s\n", string
);
362 static int pakfire_transaction_run_steps(PakfireTransaction transaction
,
363 struct pakfire_db
* db
, const pakfire_action_type_t action
) {
366 // Walk through all steps
367 PakfireStep
* steps
= transaction
->steps
;
369 PakfireStep step
= *steps
++;
372 r
= pakfire_step_run(step
, db
, action
);
374 // End loop if action was unsuccessful
376 DEBUG(transaction
->pakfire
, "Step %p failed with code %d\n", step
, r
);
384 PAKFIRE_EXPORT
int pakfire_transaction_run(PakfireTransaction transaction
) {
385 struct pakfire_db
* db
;
388 DEBUG(transaction
->pakfire
, "Running Transaction %p\n", transaction
);
391 r
= pakfire_db_open(&db
, transaction
->pakfire
, PAKFIRE_DB_READWRITE
);
393 ERROR(transaction
->pakfire
, "Could not open the database\n");
398 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_VERIFY
);
402 // Execute all pre transaction actions
403 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_PRETRANS
);
407 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_EXECUTE
);
411 // Execute all post transaction actions
412 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_POSTTRANS
);
416 DEBUG(transaction
->pakfire
, "The transaction has finished successfully\n");
420 pakfire_db_unref(db
);
425 static int pakfire_transaction_download_package(PakfireTransaction transaction
,
426 struct pakfire_downloader
* downloader
, PakfirePackage pkg
) {
428 PakfireRepo repo
= NULL
;
429 struct pakfire_mirrorlist
* mirrors
= NULL
;
430 char* cache_path
= NULL
;
432 // Fetch the repository to download from
433 repo
= pakfire_package_get_repo(pkg
);
438 mirrors
= pakfire_repo_get_mirrors(repo
);
442 // Where to store the package?
443 cache_path
= pakfire_package_get_cache_path(pkg
);
447 // What file to download?
448 const char* filename
= pakfire_package_get_filename(pkg
);
452 // Add transfer to downloader
453 r
= pakfire_downloader_add_transfer(downloader
, mirrors
, filename
, cache_path
);
459 pakfire_mirrorlist_unref(mirrors
);
461 pakfire_repo_unref(repo
);
466 PAKFIRE_EXPORT
int pakfire_transaction_download(PakfireTransaction transaction
) {
467 struct pakfire_downloader
* downloader
;
470 // Initialize the downloader
471 r
= pakfire_downloader_create(&downloader
, transaction
->pakfire
);
473 ERROR(transaction
->pakfire
, "Could not initialize downloader: %s\n",
478 // Add all packages that need to be downloaded
479 for (unsigned int i
= 0; i
< transaction
->num_steps
; i
++) {
480 PakfireStep step
= transaction
->steps
[i
];
482 // Skip all steps that do not require a download
483 if (!pakfire_step_needs_download(step
))
487 PakfirePackage pkg
= pakfire_step_get_package(step
);
490 r
= pakfire_transaction_download_package(transaction
, downloader
, pkg
);
491 pakfire_package_unref(pkg
);
497 // Run the downloader
498 r
= pakfire_downloader_run(downloader
);
501 pakfire_downloader_unref(downloader
);