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/pool.h>
29 #include <pakfire/private.h>
30 #include <pakfire/repo.h>
31 #include <pakfire/step.h>
32 #include <pakfire/transaction.h>
33 #include <pakfire/types.h>
34 #include <pakfire/util.h>
36 struct _PakfireTransaction
{
38 Transaction
* transaction
;
44 PAKFIRE_EXPORT PakfireTransaction
pakfire_transaction_create(PakfirePool pool
, Transaction
* trans
) {
45 PakfireTransaction transaction
= pakfire_calloc(1, sizeof(*transaction
));
47 DEBUG("Allocated Transaction at %p\n", transaction
);
48 transaction
->nrefs
= 1;
50 transaction
->pool
= pakfire_pool_ref(pool
);
52 // Clone the transaction, so we get independent from what ever called this.
54 transaction
->transaction
= transaction_create_clone(trans
);
55 transaction_order(transaction
->transaction
, 0);
57 transaction
->transaction
= transaction_create(trans
->pool
);
60 // Save total number of steps
61 transaction
->num_steps
= transaction
->transaction
->steps
.count
;
64 PakfireStep
* steps
= transaction
->steps
= pakfire_calloc(transaction
->num_steps
+ 1, sizeof(*steps
));
65 for (unsigned int i
= 0; i
< transaction
->num_steps
; i
++)
66 *steps
++ = pakfire_step_create(transaction
, transaction
->transaction
->steps
.elements
[i
]);
72 PAKFIRE_EXPORT PakfireTransaction
pakfire_transaction_ref(PakfireTransaction transaction
) {
80 void pakfire_transaction_free(PakfireTransaction transaction
) {
81 pakfire_pool_unref(transaction
->pool
);
84 while (*transaction
->steps
)
85 pakfire_step_unref(*transaction
->steps
++);
87 transaction_free(transaction
->transaction
);
88 pakfire_free(transaction
);
90 DEBUG("Released Transaction at %p\n", transaction
);
93 PAKFIRE_EXPORT PakfireTransaction
pakfire_transaction_unref(PakfireTransaction transaction
) {
97 if (--transaction
->nrefs
> 0)
100 pakfire_transaction_free(transaction
);
104 PAKFIRE_EXPORT PakfirePool
pakfire_transaction_get_pool(PakfireTransaction transaction
) {
105 return pakfire_pool_ref(transaction
->pool
);
108 Transaction
* pakfire_transaction_get_transaction(PakfireTransaction transaction
) {
109 return transaction
->transaction
;
112 PAKFIRE_EXPORT
size_t pakfire_transaction_count(PakfireTransaction transaction
) {
113 return transaction
->num_steps
;
116 PAKFIRE_EXPORT ssize_t
pakfire_transaction_installsizechange(PakfireTransaction transaction
) {
117 ssize_t sizechange
= transaction_calc_installsizechange(transaction
->transaction
);
119 // Convert from kbytes to bytes
120 return sizechange
* 1024;
123 PAKFIRE_EXPORT ssize_t
pakfire_transaction_downloadsize(PakfireTransaction transaction
) {
126 PakfireStep
* steps
= transaction
->steps
;
128 PakfireStep step
= *steps
++;
130 size
+= pakfire_step_get_downloadsize(step
);
136 PAKFIRE_EXPORT PakfireStep
pakfire_transaction_get_step(PakfireTransaction transaction
, unsigned int index
) {
137 PakfireStep
* steps
= transaction
->steps
;
139 while (index
-- && *steps
)
143 return pakfire_step_ref(*steps
);
148 PAKFIRE_EXPORT PakfirePackageList
pakfire_transaction_get_packages(PakfireTransaction transaction
, pakfire_step_type_t type
) {
149 PakfirePackageList packagelist
= pakfire_packagelist_create();
151 PakfireStep
* steps
= transaction
->steps
;
153 PakfireStep step
= *steps
++;
155 if (pakfire_step_get_type(step
) == type
) {
156 PakfirePackage package
= pakfire_step_get_package(step
);
157 pakfire_packagelist_push(packagelist
, package
);
159 pakfire_package_unref(package
);
163 // Sort list in place
164 pakfire_packagelist_sort(packagelist
);
169 static void pakfire_transaction_add_headline(char** str
, size_t width
, const char* headline
) {
172 asprintf(str
, "%s%s\n", *str
, headline
);
175 static void pakfire_transaction_add_newline(char** str
, size_t width
) {
176 asprintf(str
, "%s\n", *str
);
179 static void pakfire_transaction_add_line(char** str
, size_t width
, const char* name
,
180 const char* arch
, const char* version
, const char* repo
, const char* size
) {
181 // XXX need to adapt to size
182 asprintf(str
, "%s %-21s %-8s %-21s %-18s %6s \n", *str
, name
, arch
, version
, repo
, size
);
185 static void pakfire_transaction_add_package(char** str
, size_t width
, PakfirePackage pkg
) {
186 PakfireRepo repo
= pakfire_package_get_repo(pkg
);
188 unsigned long long size
= pakfire_package_get_size(pkg
);
189 char* size_str
= pakfire_format_size(size
);
191 pakfire_transaction_add_line(str
, width
,
192 pakfire_package_get_name(pkg
),
193 pakfire_package_get_arch(pkg
),
194 pakfire_package_get_evr(pkg
),
195 pakfire_repo_get_name(repo
),
199 pakfire_repo_free(repo
);
200 pakfire_free(size_str
);
203 static void pakfire_transaction_add_separator(char** str
, size_t width
) {
205 asprintf(str
, "%s=", *str
);
208 asprintf(str
, "%s\n", *str
);
211 static size_t pakfire_transaction_add_section(char** str
, size_t width
, PakfireTransaction transaction
,
212 const char* headline
, pakfire_step_type_t type
) {
213 PakfirePackageList list
= pakfire_transaction_get_packages(transaction
, type
);
215 // Nothing to do if there are no packages in this stage
216 size_t c
= pakfire_packagelist_count(list
);
221 pakfire_transaction_add_headline(str
, width
, headline
);
224 for (unsigned int i
= 0; i
< c
; i
++) {
225 PakfirePackage pkg
= pakfire_packagelist_get(list
, i
);
226 pakfire_transaction_add_package(str
, width
, pkg
);
230 pakfire_transaction_add_newline(str
, width
);
233 pakfire_packagelist_free(list
);
238 static void pakfire_transaction_add_summary_line(char** str
, size_t width
, const char* headline
, size_t pkgs
) {
240 asprintf(str
, "%s%-20s %-4zu %s\n", *str
, headline
, pkgs
, _("package(s)"));
243 static void pakfire_transaction_add_usage_line(char** str
, size_t width
, const char* headline
, ssize_t size
) {
244 char* s
= pakfire_format_size(size
);
246 asprintf(str
, "%s%-21s: %s\n", *str
, headline
, s
);
251 PAKFIRE_EXPORT
char* pakfire_transaction_dump(PakfireTransaction transaction
, size_t width
) {
255 pakfire_transaction_add_separator(&string
, width
);
256 pakfire_transaction_add_line(&string
, width
,
263 pakfire_transaction_add_separator(&string
, width
);
265 // Show what we are doing
266 size_t installing
= pakfire_transaction_add_section(&string
, width
, transaction
,
267 _("Installing:"), PAKFIRE_STEP_INSTALL
);
268 size_t reinstalling
= pakfire_transaction_add_section(&string
, width
, transaction
,
269 _("Reinstalling:"), PAKFIRE_STEP_REINSTALL
);
270 size_t updating
= pakfire_transaction_add_section(&string
, width
, transaction
,
271 _("Updating:"), PAKFIRE_STEP_UPGRADE
);
272 size_t downgrading
= pakfire_transaction_add_section(&string
, width
, transaction
,
273 _("Downgrading:"), PAKFIRE_STEP_DOWNGRADE
);
274 size_t removing
= pakfire_transaction_add_section(&string
, width
, transaction
,
275 _("Removing:"), PAKFIRE_STEP_ERASE
);
276 size_t obsoleting
= pakfire_transaction_add_section(&string
, width
, transaction
,
277 _("Obsoleting:"), PAKFIRE_STEP_OBSOLETE
);
280 pakfire_transaction_add_headline(&string
, width
, _("Transaction Summary"));
281 pakfire_transaction_add_separator(&string
, width
);
283 pakfire_transaction_add_summary_line(&string
, width
, _("Installing:"), installing
);
284 pakfire_transaction_add_summary_line(&string
, width
, _("Reinstalling:"), reinstalling
);
285 pakfire_transaction_add_summary_line(&string
, width
, _("Updating:"), updating
);
286 pakfire_transaction_add_summary_line(&string
, width
, _("Downgrading:"), downgrading
);
287 pakfire_transaction_add_summary_line(&string
, width
, _("Removing:"), removing
);
288 pakfire_transaction_add_summary_line(&string
, width
, _("Obsoleting:"), obsoleting
);
290 // How much do we need to download?
291 size_t downloadsize
= pakfire_transaction_downloadsize(transaction
);
292 if (downloadsize
> 0)
293 pakfire_transaction_add_usage_line(&string
, width
,
294 _("Total Download Size"), downloadsize
);
296 // How much more space do we need?
297 ssize_t sizechange
= pakfire_transaction_installsizechange(transaction
);
299 pakfire_transaction_add_usage_line(&string
, width
,
300 (sizechange
>= 0) ? _("Installed Size") : _("Freed Size"), sizechange
);
302 // Remove trailing newline
303 size_t l
= strlen(string
) - 1;
305 if (l
> 0 && string
[l
] == '\n')
308 DEBUG("Transaction: %s\n", string
);
313 static int pakfire_transaction_run_steps(PakfireTransaction transaction
, const pakfire_action_type action
) {
316 // Walk through all steps
317 PakfireStep
* steps
= transaction
->steps
;
319 PakfireStep step
= *steps
++;
322 r
= pakfire_step_run(step
, action
);
324 // End loop if action was unsuccessful
332 PAKFIRE_EXPORT
int pakfire_transaction_run(PakfireTransaction transaction
) {
336 r
= pakfire_transaction_run_steps(transaction
, PAKFIRE_ACTION_VERIFY
);
340 // Execute all pre transaction actions
341 r
= pakfire_transaction_run_steps(transaction
, PAKFIRE_ACTION_PRETRANS
);
345 r
= pakfire_transaction_run_steps(transaction
, PAKFIRE_ACTION_EXECUTE
);
349 // Execute all post transaction actions
350 r
= pakfire_transaction_run_steps(transaction
, PAKFIRE_ACTION_POSTTRANS
);