]> git.ipfire.org Git - people/stevee/pakfire.git/blob - src/libpakfire/transaction.c
libpakfire: Add some logging when executing a transaction
[people/stevee/pakfire.git] / src / libpakfire / transaction.c
1 /*#############################################################################
2 # #
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2013 Pakfire development team #
5 # #
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. #
10 # #
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. #
15 # #
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/>. #
18 # #
19 #############################################################################*/
20
21 #include <assert.h>
22 #include <solv/transaction.h>
23
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>
35
36 struct _PakfireTransaction {
37 PakfirePool pool;
38 Transaction* transaction;
39 PakfireStep* steps;
40 size_t num_steps;
41 int nrefs;
42 };
43
44 PAKFIRE_EXPORT PakfireTransaction pakfire_transaction_create(PakfirePool pool, Transaction* trans) {
45 PakfireTransaction transaction = pakfire_calloc(1, sizeof(*transaction));
46 if (transaction) {
47 DEBUG("Allocated Transaction at %p\n", transaction);
48 transaction->nrefs = 1;
49
50 transaction->pool = pakfire_pool_ref(pool);
51
52 // Clone the transaction, so we get independent from what ever called this.
53 if (trans) {
54 transaction->transaction = transaction_create_clone(trans);
55 transaction_order(transaction->transaction, 0);
56 } else {
57 transaction->transaction = transaction_create(trans->pool);
58 }
59
60 // Save total number of steps
61 transaction->num_steps = transaction->transaction->steps.count;
62
63 // Import all steps
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]);
67 }
68
69 return transaction;
70 }
71
72 PAKFIRE_EXPORT PakfireTransaction pakfire_transaction_ref(PakfireTransaction transaction) {
73 if (!transaction)
74 return NULL;
75
76 transaction->nrefs++;
77 return transaction;
78 }
79
80 void pakfire_transaction_free(PakfireTransaction transaction) {
81 pakfire_pool_unref(transaction->pool);
82
83 // Release all steps
84 while (*transaction->steps)
85 pakfire_step_unref(*transaction->steps++);
86
87 transaction_free(transaction->transaction);
88 pakfire_free(transaction);
89
90 DEBUG("Released Transaction at %p\n", transaction);
91 }
92
93 PAKFIRE_EXPORT PakfireTransaction pakfire_transaction_unref(PakfireTransaction transaction) {
94 if (!transaction)
95 return NULL;
96
97 if (--transaction->nrefs > 0)
98 return transaction;
99
100 pakfire_transaction_free(transaction);
101 return NULL;
102 }
103
104 PAKFIRE_EXPORT PakfirePool pakfire_transaction_get_pool(PakfireTransaction transaction) {
105 return pakfire_pool_ref(transaction->pool);
106 }
107
108 Transaction* pakfire_transaction_get_transaction(PakfireTransaction transaction) {
109 return transaction->transaction;
110 }
111
112 PAKFIRE_EXPORT size_t pakfire_transaction_count(PakfireTransaction transaction) {
113 return transaction->num_steps;
114 }
115
116 PAKFIRE_EXPORT ssize_t pakfire_transaction_installsizechange(PakfireTransaction transaction) {
117 ssize_t sizechange = transaction_calc_installsizechange(transaction->transaction);
118
119 // Convert from kbytes to bytes
120 return sizechange * 1024;
121 }
122
123 PAKFIRE_EXPORT ssize_t pakfire_transaction_downloadsize(PakfireTransaction transaction) {
124 ssize_t size = 0;
125
126 PakfireStep* steps = transaction->steps;
127 while (*steps) {
128 PakfireStep step = *steps++;
129
130 size += pakfire_step_get_downloadsize(step);
131 }
132
133 return size;
134 }
135
136 PAKFIRE_EXPORT PakfireStep pakfire_transaction_get_step(PakfireTransaction transaction, unsigned int index) {
137 PakfireStep* steps = transaction->steps;
138
139 while (index-- && *steps)
140 steps++;
141
142 if (*steps)
143 return pakfire_step_ref(*steps);
144
145 return NULL;
146 }
147
148 PAKFIRE_EXPORT PakfirePackageList pakfire_transaction_get_packages(PakfireTransaction transaction, pakfire_step_type_t type) {
149 PakfirePackageList packagelist = pakfire_packagelist_create();
150
151 PakfireStep* steps = transaction->steps;
152 while (*steps) {
153 PakfireStep step = *steps++;
154
155 if (pakfire_step_get_type(step) == type) {
156 PakfirePackage package = pakfire_step_get_package(step);
157 pakfire_packagelist_push(packagelist, package);
158
159 pakfire_package_unref(package);
160 }
161 }
162
163 // Sort list in place
164 pakfire_packagelist_sort(packagelist);
165
166 return packagelist;
167 }
168
169 static void pakfire_transaction_add_headline(char** str, size_t width, const char* headline) {
170 assert(headline);
171
172 asprintf(str, "%s%s\n", *str, headline);
173 }
174
175 static void pakfire_transaction_add_newline(char** str, size_t width) {
176 asprintf(str, "%s\n", *str);
177 }
178
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);
183 }
184
185 static void pakfire_transaction_add_package(char** str, size_t width, PakfirePackage pkg) {
186 PakfireRepo repo = pakfire_package_get_repo(pkg);
187
188 unsigned long long size = pakfire_package_get_size(pkg);
189 char* size_str = pakfire_format_size(size);
190
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),
196 size_str
197 );
198
199 pakfire_repo_unref(repo);
200 pakfire_free(size_str);
201 }
202
203 static void pakfire_transaction_add_separator(char** str, size_t width) {
204 while (width-- > 0)
205 asprintf(str, "%s=", *str);
206
207 // newline
208 asprintf(str, "%s\n", *str);
209 }
210
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);
214
215 // Nothing to do if there are no packages in this stage
216 size_t c = pakfire_packagelist_count(list);
217 if (c == 0)
218 goto END;
219
220 // Headline
221 pakfire_transaction_add_headline(str, width, headline);
222
223 // List each package
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);
227 pakfire_package_unref(pkg);
228 }
229
230 // newline
231 pakfire_transaction_add_newline(str, width);
232
233 END:
234 pakfire_packagelist_unref(list);
235
236 return c;
237 }
238
239 static void pakfire_transaction_add_summary_line(char** str, size_t width, const char* headline, size_t pkgs) {
240 if (pkgs > 0)
241 asprintf(str, "%s%-20s %-4zu %s\n", *str, headline, pkgs, _("package(s)"));
242 }
243
244 static void pakfire_transaction_add_usage_line(char** str, size_t width, const char* headline, ssize_t size) {
245 char* s = pakfire_format_size(size);
246
247 asprintf(str, "%s%-21s: %s\n", *str, headline, s);
248
249 pakfire_free(s);
250 }
251
252 PAKFIRE_EXPORT char* pakfire_transaction_dump(PakfireTransaction transaction, size_t width) {
253 char* string = "";
254
255 // Header
256 pakfire_transaction_add_separator(&string, width);
257 pakfire_transaction_add_line(&string, width,
258 _("Package"),
259 _("Arch"),
260 _("Version"),
261 _("Repository"),
262 _("Size")
263 );
264 pakfire_transaction_add_separator(&string, width);
265
266 // Show what we are doing
267 size_t installing = pakfire_transaction_add_section(&string, width, transaction,
268 _("Installing:"), PAKFIRE_STEP_INSTALL);
269 size_t reinstalling = pakfire_transaction_add_section(&string, width, transaction,
270 _("Reinstalling:"), PAKFIRE_STEP_REINSTALL);
271 size_t updating = pakfire_transaction_add_section(&string, width, transaction,
272 _("Updating:"), PAKFIRE_STEP_UPGRADE);
273 size_t downgrading = pakfire_transaction_add_section(&string, width, transaction,
274 _("Downgrading:"), PAKFIRE_STEP_DOWNGRADE);
275 size_t removing = pakfire_transaction_add_section(&string, width, transaction,
276 _("Removing:"), PAKFIRE_STEP_ERASE);
277 size_t obsoleting = pakfire_transaction_add_section(&string, width, transaction,
278 _("Obsoleting:"), PAKFIRE_STEP_OBSOLETE);
279
280 // Summary
281 pakfire_transaction_add_headline(&string, width, _("Transaction Summary"));
282 pakfire_transaction_add_separator(&string, width);
283
284 pakfire_transaction_add_summary_line(&string, width, _("Installing:"), installing);
285 pakfire_transaction_add_summary_line(&string, width, _("Reinstalling:"), reinstalling);
286 pakfire_transaction_add_summary_line(&string, width, _("Updating:"), updating);
287 pakfire_transaction_add_summary_line(&string, width, _("Downgrading:"), downgrading);
288 pakfire_transaction_add_summary_line(&string, width, _("Removing:"), removing);
289 pakfire_transaction_add_summary_line(&string, width, _("Obsoleting:"), obsoleting);
290
291 // How much do we need to download?
292 size_t downloadsize = pakfire_transaction_downloadsize(transaction);
293 if (downloadsize > 0)
294 pakfire_transaction_add_usage_line(&string, width,
295 _("Total Download Size"), downloadsize);
296
297 // How much more space do we need?
298 ssize_t sizechange = pakfire_transaction_installsizechange(transaction);
299
300 pakfire_transaction_add_usage_line(&string, width,
301 (sizechange >= 0) ? _("Installed Size") : _("Freed Size"), sizechange);
302
303 // Remove trailing newline
304 size_t l = strlen(string) - 1;
305
306 if (l > 0 && string[l] == '\n')
307 string[l] = '\0';
308
309 DEBUG("Transaction: %s\n", string);
310
311 return string;
312 }
313
314 static int pakfire_transaction_run_steps(PakfireTransaction transaction, const pakfire_action_type action) {
315 int r = 0;
316
317 // Walk through all steps
318 PakfireStep* steps = transaction->steps;
319 while (*steps) {
320 PakfireStep step = *steps++;
321
322 // Verify the step
323 r = pakfire_step_run(step, action);
324
325 // End loop if action was unsuccessful
326 if (r)
327 break;
328 }
329
330 return r;
331 }
332
333 PAKFIRE_EXPORT int pakfire_transaction_run(PakfireTransaction transaction) {
334 DEBUG("Running Transaction %p\n", transaction);
335
336 int r = 0;
337
338 // Verify steps
339 r = pakfire_transaction_run_steps(transaction, PAKFIRE_ACTION_VERIFY);
340 if (r)
341 return r;
342
343 // Execute all pre transaction actions
344 r = pakfire_transaction_run_steps(transaction, PAKFIRE_ACTION_PRETRANS);
345 if (r)
346 return r;
347
348 r = pakfire_transaction_run_steps(transaction, PAKFIRE_ACTION_EXECUTE);
349 if (r)
350 return r;
351
352 // Execute all post transaction actions
353 r = pakfire_transaction_run_steps(transaction, PAKFIRE_ACTION_POSTTRANS);
354 if (r)
355 return r;
356
357 DEBUG("Transaction %p has finished successfully\n", transaction);
358
359 return 0;
360 }