]> git.ipfire.org Git - people/stevee/pakfire.git/blob - src/libpakfire/transaction.c
Add scaffolding for running 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/package.h>
26 #include <pakfire/packagelist.h>
27 #include <pakfire/repo.h>
28 #include <pakfire/step.h>
29 #include <pakfire/transaction.h>
30 #include <pakfire/types.h>
31 #include <pakfire/util.h>
32
33 PakfireTransaction pakfire_transaction_create(PakfirePool pool, Transaction* trans) {
34 PakfireTransaction transaction = pakfire_calloc(1, sizeof(*transaction));
35 transaction->pool = pool;
36
37 // Clone the transaction, so we get independent from what ever called this.
38 if (trans) {
39 transaction->transaction = transaction_create_clone(trans);
40 transaction_order(transaction->transaction, 0);
41 } else {
42 transaction->transaction = transaction_create(trans->pool);
43 }
44
45 return transaction;
46 }
47
48 void pakfire_transaction_free(PakfireTransaction transaction) {
49 transaction_free(transaction->transaction);
50 pakfire_free(transaction);
51 }
52
53 size_t pakfire_transaction_count(PakfireTransaction transaction) {
54 return transaction->transaction->steps.count;
55 }
56
57 ssize_t pakfire_transaction_installsizechange(PakfireTransaction transaction) {
58 ssize_t sizechange = transaction_calc_installsizechange(transaction->transaction);
59
60 // Convert from kbytes to bytes
61 return sizechange * 1024;
62 }
63
64 ssize_t pakfire_transaction_downloadsize(PakfireTransaction transaction) {
65 PakfirePool pool = pakfire_transaction_pool(transaction);
66 ssize_t size = 0;
67
68 for (int i = 0; i < transaction->transaction->steps.count; i++) {
69 Id p = transaction->transaction->steps.elements[i];
70 Id t = transaction_type(transaction->transaction, p,
71 SOLVER_TRANSACTION_SHOW_OBSOLETES |
72 SOLVER_TRANSACTION_CHANGE_IS_REINSTALL |
73 SOLVER_TRANSACTION_SHOW_ALL |
74 SOLVER_TRANSACTION_SHOW_ACTIVE);
75
76 // Erasing a package does not require us to download it
77 if (t == SOLVER_TRANSACTION_ERASE)
78 continue;
79
80 // Get the package for this step
81 PakfirePackage pkg = pakfire_package_create(pool, p);
82
83 if (!pakfire_package_is_cached(pkg))
84 size += pakfire_package_get_downloadsize(pkg);
85
86 pakfire_package_free(pkg);
87 }
88
89 return size;
90 }
91
92 PakfireStep pakfire_transaction_get_step(PakfireTransaction transaction, int index) {
93 Transaction* trans = transaction->transaction;
94
95 if (index >= trans->steps.count)
96 return NULL;
97
98 return pakfire_step_create(transaction, trans->steps.elements[index]);
99 }
100
101 PakfirePackageList pakfire_transaction_get_packages(PakfireTransaction transaction, int type) {
102 PakfirePool pool = pakfire_transaction_pool(transaction);
103
104 PakfirePackageList packagelist = pakfire_packagelist_create();
105
106 for (int i = 0; i < transaction->transaction->steps.count; i++) {
107 Id p = transaction->transaction->steps.elements[i];
108 Id t = transaction_type(transaction->transaction, p,
109 SOLVER_TRANSACTION_SHOW_OBSOLETES |
110 SOLVER_TRANSACTION_CHANGE_IS_REINSTALL |
111 SOLVER_TRANSACTION_SHOW_ALL |
112 SOLVER_TRANSACTION_SHOW_ACTIVE);
113
114 if (t == type) {
115 PakfirePackage package = pakfire_package_create(pool, p);
116 pakfire_packagelist_push(packagelist, package);
117 }
118 }
119
120 // Sort list in place
121 pakfire_packagelist_sort(packagelist);
122
123 return packagelist;
124 }
125
126 static void pakfire_transaction_add_headline(char** str, size_t width, const char* headline) {
127 assert(headline);
128
129 asprintf(str, "%s%s\n", *str, headline);
130 }
131
132 static void pakfire_transaction_add_newline(char** str, size_t width) {
133 asprintf(str, "%s\n", *str);
134 }
135
136 static void pakfire_transaction_add_line(char** str, size_t width, const char* name,
137 const char* arch, const char* version, const char* repo, const char* size) {
138 // XXX need to adapt to size
139 asprintf(str, "%s %-21s %-8s %-21s %-18s %6s \n", *str, name, arch, version, repo, size);
140 }
141
142 static void pakfire_transaction_add_package(char** str, size_t width, PakfirePackage pkg) {
143 PakfireRepo repo = pakfire_package_get_repo(pkg);
144
145 unsigned long long size = pakfire_package_get_size(pkg);
146 char* size_str = pakfire_format_size(size);
147
148 pakfire_transaction_add_line(str, width,
149 pakfire_package_get_name(pkg),
150 pakfire_package_get_arch(pkg),
151 pakfire_package_get_evr(pkg),
152 pakfire_repo_get_name(repo),
153 size_str
154 );
155
156 pakfire_repo_free(repo);
157 pakfire_free(size_str);
158 }
159
160 static void pakfire_transaction_add_separator(char** str, size_t width) {
161 while (width-- > 0)
162 asprintf(str, "%s=", *str);
163
164 // newline
165 asprintf(str, "%s\n", *str);
166 }
167
168 static size_t pakfire_transaction_add_section(char** str, size_t width, PakfireTransaction transaction,
169 const char* headline, int type) {
170 PakfirePackageList list = pakfire_transaction_get_packages(transaction, type);
171
172 // Nothing to do if there are no packages in this stage
173 size_t c = pakfire_packagelist_count(list);
174 if (c == 0)
175 goto END;
176
177 // Headline
178 pakfire_transaction_add_headline(str, width, headline);
179
180 // List each package
181 for (unsigned int i = 0; i < c; i++) {
182 PakfirePackage pkg = pakfire_packagelist_get(list, i);
183 pakfire_transaction_add_package(str, width, pkg);
184 }
185
186 // newline
187 pakfire_transaction_add_newline(str, width);
188
189 END:
190 pakfire_packagelist_free(list);
191
192 return c;
193 }
194
195 static void pakfire_transaction_add_summary_line(char** str, size_t width, const char* headline, size_t pkgs) {
196 if (pkgs > 0)
197 asprintf(str, "%s%-20s %-4zu %s\n", *str, headline, pkgs, _("package(s)"));
198 }
199
200 static void pakfire_transaction_add_usage_line(char** str, size_t width, const char* headline, ssize_t size) {
201 char* s = pakfire_format_size(size);
202
203 asprintf(str, "%s%-21s: %s\n", *str, headline, s);
204
205 pakfire_free(s);
206 }
207
208 char* pakfire_transaction_dump(PakfireTransaction transaction, size_t width) {
209 char* string = "";
210
211 // Header
212 pakfire_transaction_add_separator(&string, width);
213 pakfire_transaction_add_line(&string, width,
214 _("Package"),
215 _("Arch"),
216 _("Version"),
217 _("Repository"),
218 _("Size")
219 );
220 pakfire_transaction_add_separator(&string, width);
221
222 // Show what we are doing
223 size_t installing = pakfire_transaction_add_section(&string, width, transaction,
224 _("Installing:"), SOLVER_TRANSACTION_INSTALL);
225 size_t reinstalling = pakfire_transaction_add_section(&string, width, transaction,
226 _("Reinstalling:"), SOLVER_TRANSACTION_REINSTALL);
227 size_t updating = pakfire_transaction_add_section(&string, width, transaction,
228 _("Updating:"), SOLVER_TRANSACTION_UPGRADE);
229 size_t downgrading = pakfire_transaction_add_section(&string, width, transaction,
230 _("Downgrading:"), SOLVER_TRANSACTION_DOWNGRADE);
231 size_t removing = pakfire_transaction_add_section(&string, width, transaction,
232 _("Removing:"), SOLVER_TRANSACTION_ERASE);
233 size_t obsoleting = pakfire_transaction_add_section(&string, width, transaction,
234 _("Obsoleting:"), SOLVER_TRANSACTION_OBSOLETES);
235
236 // Summary
237 pakfire_transaction_add_headline(&string, width, _("Transaction Summary"));
238 pakfire_transaction_add_separator(&string, width);
239
240 pakfire_transaction_add_summary_line(&string, width, _("Installing:"), installing);
241 pakfire_transaction_add_summary_line(&string, width, _("Reinstalling:"), reinstalling);
242 pakfire_transaction_add_summary_line(&string, width, _("Updating:"), updating);
243 pakfire_transaction_add_summary_line(&string, width, _("Downgrading:"), downgrading);
244 pakfire_transaction_add_summary_line(&string, width, _("Removing:"), removing);
245 pakfire_transaction_add_summary_line(&string, width, _("Obsoleting:"), obsoleting);
246
247 // How much do we need to download?
248 size_t downloadsize = pakfire_transaction_downloadsize(transaction);
249 if (downloadsize > 0)
250 pakfire_transaction_add_usage_line(&string, width,
251 _("Total Download Size"), downloadsize);
252
253 // How much more space do we need?
254 ssize_t sizechange = pakfire_transaction_installsizechange(transaction);
255
256 pakfire_transaction_add_usage_line(&string, width,
257 (sizechange >= 0) ? _("Installed Size") : _("Freed Size"), sizechange);
258
259 // Remove trailing newline
260 size_t l = strlen(string) - 1;
261
262 if (l > 0 && string[l] == '\n')
263 string[l] = '\0';
264
265 return string;
266 }
267
268 static int pakfire_transaction_run_steps(PakfireTransaction transaction, const pakfire_action_type action) {
269 size_t steps = pakfire_transaction_count(transaction);
270
271 // Walk through all steps
272 int r = 0;
273 for (unsigned int i = 0; i < steps; i++) {
274 PakfireStep step = pakfire_transaction_get_step(transaction, i);
275
276 // Verify the step
277 r = pakfire_step_run(step, action);
278
279 // Free memory
280 pakfire_step_free(step);
281
282 // End loop if action was unsuccessful
283 if (r)
284 break;
285 }
286
287 return r;
288 }
289
290 int pakfire_transaction_run(PakfireTransaction transaction) {
291 int r = 0;
292
293 // Verify steps
294 r = pakfire_transaction_run_steps(transaction, PAKFIRE_ACTION_VERIFY);
295 if (r)
296 return r;
297
298 // Execute all pre transaction actions
299 r = pakfire_transaction_run_steps(transaction, PAKFIRE_ACTION_PRETRANS);
300 if (r)
301 return r;
302
303 r = pakfire_transaction_run_steps(transaction, PAKFIRE_ACTION_EXECUTE);
304 if (r)
305 return r;
306
307 // Execute all post transaction actions
308 r = pakfire_transaction_run_steps(transaction, PAKFIRE_ACTION_POSTTRANS);
309 if (r)
310 return r;
311
312 return 0;
313 }