]> git.ipfire.org Git - people/stevee/pakfire.git/blob - src/libpakfire/transaction.c
libpakfire: Load all steps when initializing the 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_free(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 }
228
229 // newline
230 pakfire_transaction_add_newline(str, width);
231
232 END:
233 pakfire_packagelist_free(list);
234
235 return c;
236 }
237
238 static void pakfire_transaction_add_summary_line(char** str, size_t width, const char* headline, size_t pkgs) {
239 if (pkgs > 0)
240 asprintf(str, "%s%-20s %-4zu %s\n", *str, headline, pkgs, _("package(s)"));
241 }
242
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);
245
246 asprintf(str, "%s%-21s: %s\n", *str, headline, s);
247
248 pakfire_free(s);
249 }
250
251 PAKFIRE_EXPORT char* pakfire_transaction_dump(PakfireTransaction transaction, size_t width) {
252 char* string = "";
253
254 // Header
255 pakfire_transaction_add_separator(&string, width);
256 pakfire_transaction_add_line(&string, width,
257 _("Package"),
258 _("Arch"),
259 _("Version"),
260 _("Repository"),
261 _("Size")
262 );
263 pakfire_transaction_add_separator(&string, width);
264
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);
278
279 // Summary
280 pakfire_transaction_add_headline(&string, width, _("Transaction Summary"));
281 pakfire_transaction_add_separator(&string, width);
282
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);
289
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);
295
296 // How much more space do we need?
297 ssize_t sizechange = pakfire_transaction_installsizechange(transaction);
298
299 pakfire_transaction_add_usage_line(&string, width,
300 (sizechange >= 0) ? _("Installed Size") : _("Freed Size"), sizechange);
301
302 // Remove trailing newline
303 size_t l = strlen(string) - 1;
304
305 if (l > 0 && string[l] == '\n')
306 string[l] = '\0';
307
308 DEBUG("Transaction: %s\n", string);
309
310 return string;
311 }
312
313 static int pakfire_transaction_run_steps(PakfireTransaction transaction, const pakfire_action_type action) {
314 int r = 0;
315
316 // Walk through all steps
317 PakfireStep* steps = transaction->steps;
318 while (*steps) {
319 PakfireStep step = *steps++;
320
321 // Verify the step
322 r = pakfire_step_run(step, action);
323
324 // End loop if action was unsuccessful
325 if (r)
326 break;
327 }
328
329 return r;
330 }
331
332 PAKFIRE_EXPORT int pakfire_transaction_run(PakfireTransaction transaction) {
333 int r = 0;
334
335 // Verify steps
336 r = pakfire_transaction_run_steps(transaction, PAKFIRE_ACTION_VERIFY);
337 if (r)
338 return r;
339
340 // Execute all pre transaction actions
341 r = pakfire_transaction_run_steps(transaction, PAKFIRE_ACTION_PRETRANS);
342 if (r)
343 return r;
344
345 r = pakfire_transaction_run_steps(transaction, PAKFIRE_ACTION_EXECUTE);
346 if (r)
347 return r;
348
349 // Execute all post transaction actions
350 r = pakfire_transaction_run_steps(transaction, PAKFIRE_ACTION_POSTTRANS);
351 if (r)
352 return r;
353
354 return 0;
355 }