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 #############################################################################*/
22 #include <solv/transaction.h>
24 #include <pakfire/i18n.h>
25 #include <pakfire/logging.h>
26 #include <pakfire/package.h>
27 #include <pakfire/packagelist.h>
28 #include <pakfire/pakfire.h>
29 #include <pakfire/pool.h>
30 #include <pakfire/private.h>
31 #include <pakfire/repo.h>
32 #include <pakfire/step.h>
33 #include <pakfire/transaction.h>
34 #include <pakfire/types.h>
35 #include <pakfire/util.h>
37 struct _PakfireTransaction
{
39 Transaction
* transaction
;
45 PAKFIRE_EXPORT PakfireTransaction
pakfire_transaction_create(Pakfire pakfire
, Transaction
* trans
) {
46 PakfireTransaction transaction
= pakfire_calloc(1, sizeof(*transaction
));
48 DEBUG("Allocated Transaction at %p\n", transaction
);
49 transaction
->nrefs
= 1;
51 transaction
->pakfire
= pakfire_ref(pakfire
);
53 // Clone the transaction, so we get independent from what ever called this.
55 transaction
->transaction
= transaction_create_clone(trans
);
56 transaction_order(transaction
->transaction
, 0);
58 transaction
->transaction
= transaction_create(trans
->pool
);
61 // Save total number of steps
62 transaction
->num_steps
= transaction
->transaction
->steps
.count
;
65 PakfireStep
* steps
= transaction
->steps
= pakfire_calloc(transaction
->num_steps
+ 1, sizeof(*steps
));
66 for (unsigned int i
= 0; i
< transaction
->num_steps
; i
++)
67 *steps
++ = pakfire_step_create(transaction
, transaction
->transaction
->steps
.elements
[i
]);
73 PAKFIRE_EXPORT PakfireTransaction
pakfire_transaction_ref(PakfireTransaction transaction
) {
81 void pakfire_transaction_free(PakfireTransaction transaction
) {
82 pakfire_unref(transaction
->pakfire
);
85 while (*transaction
->steps
)
86 pakfire_step_unref(*transaction
->steps
++);
88 transaction_free(transaction
->transaction
);
89 pakfire_free(transaction
);
91 DEBUG("Released Transaction at %p\n", transaction
);
94 PAKFIRE_EXPORT PakfireTransaction
pakfire_transaction_unref(PakfireTransaction transaction
) {
98 if (--transaction
->nrefs
> 0)
101 pakfire_transaction_free(transaction
);
105 PAKFIRE_EXPORT PakfirePool
pakfire_transaction_get_pool(PakfireTransaction transaction
) {
106 return pakfire_get_pool(transaction
->pakfire
);
109 Transaction
* pakfire_transaction_get_transaction(PakfireTransaction transaction
) {
110 return transaction
->transaction
;
113 PAKFIRE_EXPORT
size_t pakfire_transaction_count(PakfireTransaction transaction
) {
114 return transaction
->num_steps
;
117 PAKFIRE_EXPORT ssize_t
pakfire_transaction_installsizechange(PakfireTransaction transaction
) {
118 ssize_t sizechange
= transaction_calc_installsizechange(transaction
->transaction
);
120 // Convert from kbytes to bytes
121 return sizechange
* 1024;
124 PAKFIRE_EXPORT ssize_t
pakfire_transaction_downloadsize(PakfireTransaction transaction
) {
127 PakfireStep
* steps
= transaction
->steps
;
129 PakfireStep step
= *steps
++;
131 size
+= pakfire_step_get_downloadsize(step
);
137 PAKFIRE_EXPORT PakfireStep
pakfire_transaction_get_step(PakfireTransaction transaction
, unsigned int index
) {
138 PakfireStep
* steps
= transaction
->steps
;
140 while (index
-- && *steps
)
144 return pakfire_step_ref(*steps
);
149 PAKFIRE_EXPORT PakfirePackageList
pakfire_transaction_get_packages(PakfireTransaction transaction
, pakfire_step_type_t type
) {
150 PakfirePackageList packagelist
= pakfire_packagelist_create();
152 PakfireStep
* steps
= transaction
->steps
;
154 PakfireStep step
= *steps
++;
156 if (pakfire_step_get_type(step
) == type
) {
157 PakfirePackage package
= pakfire_step_get_package(step
);
158 pakfire_packagelist_push(packagelist
, package
);
160 pakfire_package_unref(package
);
164 // Sort list in place
165 pakfire_packagelist_sort(packagelist
);
170 static void pakfire_transaction_add_headline(char** str
, size_t width
, const char* headline
) {
173 asprintf(str
, "%s%s\n", *str
, headline
);
176 static void pakfire_transaction_add_newline(char** str
, size_t width
) {
177 asprintf(str
, "%s\n", *str
);
180 static void pakfire_transaction_add_line(char** str
, size_t width
, const char* name
,
181 const char* arch
, const char* version
, const char* repo
, const char* size
) {
182 // XXX need to adapt to size
183 asprintf(str
, "%s %-21s %-8s %-21s %-18s %6s \n", *str
, name
, arch
, version
, repo
, size
);
186 static void pakfire_transaction_add_package(char** str
, size_t width
, PakfirePackage pkg
) {
187 PakfireRepo repo
= pakfire_package_get_repo(pkg
);
189 unsigned long long size
= pakfire_package_get_size(pkg
);
190 char* size_str
= pakfire_format_size(size
);
192 pakfire_transaction_add_line(str
, width
,
193 pakfire_package_get_name(pkg
),
194 pakfire_package_get_arch(pkg
),
195 pakfire_package_get_evr(pkg
),
196 pakfire_repo_get_name(repo
),
200 pakfire_repo_unref(repo
);
201 pakfire_free(size_str
);
204 static void pakfire_transaction_add_separator(char** str
, size_t width
) {
206 asprintf(str
, "%s=", *str
);
209 asprintf(str
, "%s\n", *str
);
212 static size_t pakfire_transaction_add_section(char** str
, size_t width
, PakfireTransaction transaction
,
213 const char* headline
, pakfire_step_type_t type
) {
214 PakfirePackageList list
= pakfire_transaction_get_packages(transaction
, type
);
216 // Nothing to do if there are no packages in this stage
217 size_t c
= pakfire_packagelist_count(list
);
222 pakfire_transaction_add_headline(str
, width
, headline
);
225 for (unsigned int i
= 0; i
< c
; i
++) {
226 PakfirePackage pkg
= pakfire_packagelist_get(list
, i
);
227 pakfire_transaction_add_package(str
, width
, pkg
);
228 pakfire_package_unref(pkg
);
232 pakfire_transaction_add_newline(str
, width
);
235 pakfire_packagelist_unref(list
);
240 static void pakfire_transaction_add_summary_line(char** str
, size_t width
, const char* headline
, size_t pkgs
) {
242 asprintf(str
, "%s%-20s %-4zu %s\n", *str
, headline
, pkgs
, _("package(s)"));
245 static void pakfire_transaction_add_usage_line(char** str
, size_t width
, const char* headline
, ssize_t size
) {
246 char* s
= pakfire_format_size(size
);
248 asprintf(str
, "%s%-21s: %s\n", *str
, headline
, s
);
253 PAKFIRE_EXPORT
char* pakfire_transaction_dump(PakfireTransaction transaction
, size_t width
) {
257 pakfire_transaction_add_separator(&string
, width
);
258 pakfire_transaction_add_line(&string
, width
,
265 pakfire_transaction_add_separator(&string
, width
);
267 // Show what we are doing
268 size_t installing
= pakfire_transaction_add_section(&string
, width
, transaction
,
269 _("Installing:"), PAKFIRE_STEP_INSTALL
);
270 size_t reinstalling
= pakfire_transaction_add_section(&string
, width
, transaction
,
271 _("Reinstalling:"), PAKFIRE_STEP_REINSTALL
);
272 size_t updating
= pakfire_transaction_add_section(&string
, width
, transaction
,
273 _("Updating:"), PAKFIRE_STEP_UPGRADE
);
274 size_t downgrading
= pakfire_transaction_add_section(&string
, width
, transaction
,
275 _("Downgrading:"), PAKFIRE_STEP_DOWNGRADE
);
276 size_t removing
= pakfire_transaction_add_section(&string
, width
, transaction
,
277 _("Removing:"), PAKFIRE_STEP_ERASE
);
278 size_t obsoleting
= pakfire_transaction_add_section(&string
, width
, transaction
,
279 _("Obsoleting:"), PAKFIRE_STEP_OBSOLETE
);
282 pakfire_transaction_add_headline(&string
, width
, _("Transaction Summary"));
283 pakfire_transaction_add_separator(&string
, width
);
285 pakfire_transaction_add_summary_line(&string
, width
, _("Installing:"), installing
);
286 pakfire_transaction_add_summary_line(&string
, width
, _("Reinstalling:"), reinstalling
);
287 pakfire_transaction_add_summary_line(&string
, width
, _("Updating:"), updating
);
288 pakfire_transaction_add_summary_line(&string
, width
, _("Downgrading:"), downgrading
);
289 pakfire_transaction_add_summary_line(&string
, width
, _("Removing:"), removing
);
290 pakfire_transaction_add_summary_line(&string
, width
, _("Obsoleting:"), obsoleting
);
292 // How much do we need to download?
293 size_t downloadsize
= pakfire_transaction_downloadsize(transaction
);
294 if (downloadsize
> 0)
295 pakfire_transaction_add_usage_line(&string
, width
,
296 _("Total Download Size"), downloadsize
);
298 // How much more space do we need?
299 ssize_t sizechange
= pakfire_transaction_installsizechange(transaction
);
301 pakfire_transaction_add_usage_line(&string
, width
,
302 (sizechange
>= 0) ? _("Installed Size") : _("Freed Size"), sizechange
);
304 // Remove trailing newline
305 size_t l
= strlen(string
) - 1;
307 if (l
> 0 && string
[l
] == '\n')
310 DEBUG("Transaction: %s\n", string
);
315 static int pakfire_transaction_run_steps(PakfireTransaction transaction
, const pakfire_action_type_t action
) {
318 // Walk through all steps
319 PakfireStep
* steps
= transaction
->steps
;
321 PakfireStep step
= *steps
++;
324 r
= pakfire_step_run(step
, action
);
326 // End loop if action was unsuccessful
334 PAKFIRE_EXPORT
int pakfire_transaction_run(PakfireTransaction transaction
) {
335 DEBUG("Running Transaction %p\n", transaction
);
340 r
= pakfire_transaction_run_steps(transaction
, PAKFIRE_ACTION_VERIFY
);
344 // Execute all pre transaction actions
345 r
= pakfire_transaction_run_steps(transaction
, PAKFIRE_ACTION_PRETRANS
);
349 r
= pakfire_transaction_run_steps(transaction
, PAKFIRE_ACTION_EXECUTE
);
353 // Execute all post transaction actions
354 r
= pakfire_transaction_run_steps(transaction
, PAKFIRE_ACTION_POSTTRANS
);
358 DEBUG("Transaction %p has finished successfully\n", transaction
);