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