]>
Commit | Line | Data |
---|---|---|
d04baaba JV |
1 | /* |
2 | * deps.c | |
23229097 | 3 | * |
9781d0d6 | 4 | * Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org> |
d37ad048 AG |
5 | * Copyright (c) 2005 by Aurelien Foret <orelien@chez.com> |
6 | * Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org> | |
23229097 | 7 | * |
d04baaba JV |
8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
9781d0d6 | 19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
d04baaba JV |
20 | */ |
21 | ||
869e81e1 DM |
22 | #include "config.h" |
23 | ||
d04baaba JV |
24 | #include <stdlib.h> |
25 | #include <stdio.h> | |
26 | #include <string.h> | |
869e81e1 DM |
27 | |
28 | /* libalpm */ | |
29 | #include "deps.h" | |
30 | #include "alpm_list.h" | |
d04baaba JV |
31 | #include "util.h" |
32 | #include "log.h" | |
4d21e4f7 | 33 | #include "error.h" |
d04baaba JV |
34 | #include "package.h" |
35 | #include "db.h" | |
36 | #include "cache.h" | |
90b9888d AF |
37 | #include "handle.h" |
38 | ||
544bcbe6 NG |
39 | static pmgraph_t *_alpm_graph_new(void) |
40 | { | |
41 | pmgraph_t *graph = NULL; | |
42 | ||
c8243bb8 DM |
43 | MALLOC(graph, sizeof(pmgraph_t), RET_ERR(PM_ERR_MEMORY, NULL)); |
44 | ||
544bcbe6 NG |
45 | if(graph) { |
46 | graph->state = 0; | |
47 | graph->data = NULL; | |
48 | graph->parent = NULL; | |
49 | graph->children = NULL; | |
50 | graph->childptr = NULL; | |
51 | } | |
52 | return(graph); | |
53 | } | |
54 | ||
55 | static void _alpm_graph_free(void *data) | |
56 | { | |
57 | pmgraph_t *graph = data; | |
58 | alpm_list_free(graph->children); | |
59 | free(graph); | |
60 | } | |
61 | ||
2aa7e69d NG |
62 | pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepmod_t depmod, |
63 | const char *depname, const char *depversion) | |
6dd2ecf4 AF |
64 | { |
65 | pmdepmissing_t *miss; | |
66 | ||
da648bc2 AG |
67 | ALPM_LOG_FUNC; |
68 | ||
cc754bc6 | 69 | MALLOC(miss, sizeof(pmdepmissing_t), RET_ERR(PM_ERR_MEMORY, NULL)); |
6dd2ecf4 | 70 | |
a58e17a1 | 71 | strncpy(miss->target, target, PKG_NAME_LEN); |
6dd2ecf4 | 72 | miss->depend.mod = depmod; |
a58e17a1 | 73 | strncpy(miss->depend.name, depname, PKG_NAME_LEN); |
cf94007a | 74 | if(depversion) { |
a58e17a1 | 75 | strncpy(miss->depend.version, depversion, PKG_VERSION_LEN); |
cf94007a AF |
76 | } else { |
77 | miss->depend.version[0] = 0; | |
78 | } | |
6dd2ecf4 AF |
79 | |
80 | return(miss); | |
81 | } | |
82 | ||
c68d3cc3 CX |
83 | /* Convert a list of pmpkg_t * to a graph structure, |
84 | * with a edge for each dependency. | |
85 | * Returns a list of vertices (one vertex = one package) | |
86 | * (used by alpm_sortbydeps) | |
87 | */ | |
88 | static alpm_list_t *_alpm_graph_init(alpm_list_t *targets) | |
89 | { | |
90 | alpm_list_t *i, *j, *k; | |
91 | alpm_list_t *vertices = NULL; | |
92 | /* We create the vertices */ | |
93 | for(i = targets; i; i = i->next) { | |
94 | pmgraph_t *vertex = _alpm_graph_new(); | |
95 | vertex->data = (void *)i->data; | |
96 | vertices = alpm_list_add(vertices, vertex); | |
97 | } | |
98 | ||
99 | /* We compute the edges */ | |
100 | for(i = vertices; i; i = i->next) { | |
101 | pmgraph_t *vertex_i = i->data; | |
102 | pmpkg_t *p_i = vertex_i->data; | |
7d37d927 | 103 | /* TODO this should be somehow combined with alpm_checkdeps */ |
c68d3cc3 CX |
104 | for(j = vertices; j; j = j->next) { |
105 | pmgraph_t *vertex_j = j->data; | |
106 | pmpkg_t *p_j = vertex_j->data; | |
107 | int child = 0; | |
108 | for(k = alpm_pkg_get_depends(p_i); k && !child; k = k->next) { | |
c244cfec | 109 | pmdepend_t *depend = k->data; |
c68d3cc3 | 110 | child = alpm_depcmp(p_j, depend); |
c68d3cc3 CX |
111 | } |
112 | if(child) { | |
113 | vertex_i->children = | |
114 | alpm_list_add(vertex_i->children, vertex_j); | |
115 | } | |
116 | } | |
117 | vertex_i->childptr = vertex_i->children; | |
118 | } | |
119 | return(vertices); | |
120 | } | |
121 | ||
d04baaba JV |
122 | /* Re-order a list of target packages with respect to their dependencies. |
123 | * | |
7c847fd7 | 124 | * Example (PM_TRANS_TYPE_ADD): |
d04baaba JV |
125 | * A depends on C |
126 | * B depends on A | |
127 | * Target order is A,B,C,D | |
128 | * | |
129 | * Should be re-ordered to C,A,B,D | |
23229097 | 130 | * |
7c847fd7 AF |
131 | * mode should be either PM_TRANS_TYPE_ADD or PM_TRANS_TYPE_REMOVE. This |
132 | * affects the dependency order sortbydeps() will use. | |
133 | * | |
61670172 | 134 | * This function returns the new alpm_list_t* target list. |
d04baaba | 135 | * |
23229097 | 136 | */ |
290b962c | 137 | alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode) |
d04baaba | 138 | { |
61670172 | 139 | alpm_list_t *newtargs = NULL; |
544bcbe6 NG |
140 | alpm_list_t *vertices = NULL; |
141 | alpm_list_t *vptr; | |
142 | pmgraph_t *vertex; | |
d04baaba | 143 | |
da648bc2 AG |
144 | ALPM_LOG_FUNC; |
145 | ||
d04baaba JV |
146 | if(targets == NULL) { |
147 | return(NULL); | |
148 | } | |
149 | ||
5c9eec55 | 150 | _alpm_log(PM_LOG_DEBUG, "started sorting dependencies\n"); |
544bcbe6 | 151 | |
c68d3cc3 | 152 | vertices = _alpm_graph_init(targets); |
0bc06918 | 153 | |
544bcbe6 NG |
154 | vptr = vertices; |
155 | vertex = vertices->data; | |
156 | while(vptr) { | |
157 | /* mark that we touched the vertex */ | |
158 | vertex->state = -1; | |
159 | int found = 0; | |
160 | while(vertex->childptr && !found) { | |
161 | pmgraph_t *nextchild = (vertex->childptr)->data; | |
162 | vertex->childptr = (vertex->childptr)->next; | |
163 | if (nextchild->state == 0) { | |
164 | found = 1; | |
165 | nextchild->parent = vertex; | |
166 | vertex = nextchild; | |
167 | } | |
168 | else if(nextchild->state == -1) { | |
7cf28a75 NG |
169 | pmpkg_t *vertexpkg = vertex->data; |
170 | pmpkg_t *childpkg = nextchild->data; | |
171 | _alpm_log(PM_LOG_WARNING, _("dependency cycle detected:\n")); | |
172 | if(mode == PM_TRANS_TYPE_REMOVE) { | |
173 | _alpm_log(PM_LOG_WARNING, _("%s will be removed after its %s dependency\n"), vertexpkg->name, childpkg->name); | |
174 | } else { | |
175 | _alpm_log(PM_LOG_WARNING, _("%s will be installed before its %s dependency\n"), vertexpkg->name, childpkg->name); | |
176 | } | |
544bcbe6 | 177 | } |
d04baaba | 178 | } |
544bcbe6 NG |
179 | if(!found) { |
180 | newtargs = alpm_list_add(newtargs, vertex->data); | |
181 | /* mark that we've left this vertex */ | |
182 | vertex->state = 1; | |
183 | vertex = vertex->parent; | |
184 | if(!vertex) { | |
185 | vptr = vptr->next; | |
186 | while(vptr) { | |
187 | vertex = vptr->data; | |
188 | if (vertex->state == 0) break; | |
189 | vptr = vptr->next; | |
d04baaba | 190 | } |
d04baaba JV |
191 | } |
192 | } | |
d04baaba | 193 | } |
544bcbe6 | 194 | |
5c9eec55 | 195 | _alpm_log(PM_LOG_DEBUG, "sorting dependencies finished\n"); |
a5e4fec7 | 196 | |
7c847fd7 AF |
197 | if(mode == PM_TRANS_TYPE_REMOVE) { |
198 | /* we're removing packages, so reverse the order */ | |
61670172 | 199 | alpm_list_t *tmptargs = alpm_list_reverse(newtargs); |
7c847fd7 | 200 | /* free the old one */ |
a57b2f23 | 201 | alpm_list_free(newtargs); |
a5e4fec7 | 202 | newtargs = tmptargs; |
7c847fd7 AF |
203 | } |
204 | ||
544bcbe6 | 205 | alpm_list_free_inner(vertices, _alpm_graph_free); |
01e92e9d | 206 | alpm_list_free(vertices); |
544bcbe6 | 207 | |
a5e4fec7 | 208 | return(newtargs); |
d04baaba JV |
209 | } |
210 | ||
2ed6b482 NG |
211 | /* Little helper function for alpm_list_find */ |
212 | static int satisfycmp(const void *pkg, const void *depend) | |
213 | { | |
214 | return(!alpm_depcmp((pmpkg_t*) pkg, (pmdepend_t*) depend)); | |
215 | } | |
216 | ||
f21c45c0 CX |
217 | /** Checks dependencies and returns missing ones in a list. |
218 | * Dependencies can include versions with depmod operators. | |
bd7eb947 | 219 | * @param db pointer to the local package database |
7d37d927 NG |
220 | * @param reversedeps handles the backward dependencies |
221 | * @param remove an alpm_list_t* of packages to be removed | |
222 | * @param upgrade an alpm_list_t* of packages to be upgraded (remove-then-upgrade) | |
c0a7d9d8 | 223 | * @return an alpm_list_t* of pmpkg_t* of missing_t pointers. |
d04baaba | 224 | */ |
7d37d927 NG |
225 | alpm_list_t SYMEXPORT *alpm_checkdeps(pmdb_t *db, int reversedeps, |
226 | alpm_list_t *remove, alpm_list_t *upgrade) | |
d04baaba | 227 | { |
2ed6b482 NG |
228 | alpm_list_t *i, *j; |
229 | alpm_list_t *joined, *dblist; | |
61670172 | 230 | alpm_list_t *baddeps = NULL; |
d04baaba JV |
231 | pmdepmissing_t *miss = NULL; |
232 | ||
da648bc2 AG |
233 | ALPM_LOG_FUNC; |
234 | ||
d04baaba JV |
235 | if(db == NULL) { |
236 | return(NULL); | |
237 | } | |
238 | ||
2ed6b482 NG |
239 | joined = alpm_list_join(alpm_list_copy(remove), alpm_list_copy(upgrade)); |
240 | dblist = alpm_list_diff(_alpm_db_get_pkgcache(db), joined, _alpm_pkg_cmp); | |
241 | alpm_list_free(joined); | |
242 | ||
7d37d927 NG |
243 | /* look for unsatisfied dependencies of the upgrade list */ |
244 | for(i = upgrade; i; i = i->next) { | |
245 | pmpkg_t *tp = i->data; | |
7d37d927 NG |
246 | _alpm_log(PM_LOG_DEBUG, "checkdeps: package %s-%s\n", |
247 | alpm_pkg_get_name(tp), alpm_pkg_get_version(tp)); | |
248 | ||
249 | for(j = alpm_pkg_get_depends(tp); j; j = j->next) { | |
7d37d927 | 250 | pmdepend_t *depend = j->data; |
7d37d927 | 251 | /* 1. we check the upgrade list */ |
7d37d927 | 252 | /* 2. we check database for untouched satisfying packages */ |
2ed6b482 NG |
253 | if(!alpm_list_find(upgrade, depend, satisfycmp) && |
254 | !alpm_list_find(dblist, depend, satisfycmp)) { | |
255 | /* Unsatisfied dependency in the upgrade list */ | |
7d37d927 | 256 | char *missdepstring = alpm_dep_get_string(depend); |
e95e346a | 257 | _alpm_log(PM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n", |
7d37d927 NG |
258 | missdepstring, alpm_pkg_get_name(tp)); |
259 | free(missdepstring); | |
260 | miss = _alpm_depmiss_new(alpm_pkg_get_name(tp), depend->mod, | |
261 | depend->name, depend->version); | |
2ed6b482 | 262 | baddeps = alpm_list_add(baddeps, miss); |
7d37d927 NG |
263 | } |
264 | } | |
265 | } | |
266 | ||
267 | if(reversedeps) { | |
268 | /* reversedeps handles the backwards dependencies, ie, | |
269 | * the packages listed in the requiredby field. */ | |
270 | ||
2ed6b482 | 271 | alpm_list_t *modified = alpm_list_diff(_alpm_db_get_pkgcache(db), dblist, _alpm_pkg_cmp); |
d04baaba | 272 | |
2ed6b482 NG |
273 | for(i = dblist; i; i = i->next) { |
274 | pmpkg_t *lp = i->data; | |
2ed6b482 NG |
275 | for(j = alpm_pkg_get_depends(lp); j; j = j->next) { |
276 | pmdepend_t *depend = j->data; | |
277 | /* we won't break this depend, if it is already broken, we ignore it */ | |
278 | /* 1. check upgrade list for satisfiers */ | |
279 | /* 2. check dblist for satisfiers */ | |
280 | if(alpm_list_find(modified, depend, satisfycmp) && | |
281 | !alpm_list_find(upgrade, depend, satisfycmp) && | |
282 | !alpm_list_find(dblist, depend, satisfycmp)) { | |
7d37d927 | 283 | char *missdepstring = alpm_dep_get_string(depend); |
e95e346a | 284 | _alpm_log(PM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n", |
2ed6b482 | 285 | missdepstring, alpm_pkg_get_name(lp)); |
7d37d927 | 286 | free(missdepstring); |
2ed6b482 | 287 | miss = _alpm_depmiss_new(lp->name, depend->mod, |
2aa7e69d | 288 | depend->name, depend->version); |
2ed6b482 | 289 | baddeps = alpm_list_add(baddeps, miss); |
d04baaba JV |
290 | } |
291 | } | |
d04baaba | 292 | } |
2ed6b482 | 293 | alpm_list_free(modified); |
d04baaba | 294 | } |
2ed6b482 | 295 | alpm_list_free(dblist); |
d04baaba JV |
296 | |
297 | return(baddeps); | |
298 | } | |
299 | ||
fe3a4617 | 300 | static int dep_vercmp(const char *version1, pmdepmod_t mod, |
240bdf59 CX |
301 | const char *version2) |
302 | { | |
303 | int equal = 0; | |
304 | ||
305 | if(mod == PM_DEP_MOD_ANY) { | |
306 | equal = 1; | |
307 | } else { | |
308 | int cmp = _alpm_versioncmp(version1, version2); | |
309 | switch(mod) { | |
310 | case PM_DEP_MOD_EQ: equal = (cmp == 0); break; | |
311 | case PM_DEP_MOD_GE: equal = (cmp >= 0); break; | |
312 | case PM_DEP_MOD_LE: equal = (cmp <= 0); break; | |
313 | default: equal = 1; break; | |
314 | } | |
315 | } | |
316 | return(equal); | |
317 | } | |
318 | ||
20f73d62 DM |
319 | int SYMEXPORT alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep) |
320 | { | |
84ebf823 | 321 | alpm_list_t *i; |
20f73d62 DM |
322 | |
323 | ALPM_LOG_FUNC; | |
324 | ||
240bdf59 CX |
325 | const char *pkgname = alpm_pkg_get_name(pkg); |
326 | const char *pkgversion = alpm_pkg_get_version(pkg); | |
84ebf823 | 327 | int satisfy = 0; |
240bdf59 | 328 | |
84ebf823 NG |
329 | /* check (pkg->name, pkg->version) */ |
330 | satisfy = (strcmp(pkgname, dep->name) == 0 | |
331 | && dep_vercmp(pkgversion, dep->mod, dep->version)); | |
240bdf59 | 332 | |
84ebf823 NG |
333 | /* check provisions, format : "name version" */ |
334 | for(i = alpm_pkg_get_provides(pkg); i && !satisfy; i = i->next) { | |
335 | char *provname = strdup(i->data); | |
336 | char *provver = strchr(provname, ' '); | |
20f73d62 | 337 | |
84ebf823 NG |
338 | if(provver == NULL) { /* no provision version */ |
339 | satisfy = (dep->mod == PM_DEP_MOD_ANY | |
340 | && strcmp(provname, dep->name) == 0); | |
20f73d62 | 341 | } else { |
84ebf823 NG |
342 | /* replace the space with a NULL byte, and advance ptr the version */ |
343 | *provver = '\0'; | |
344 | provver += 1; | |
345 | satisfy = (strcmp(provname, dep->name) == 0 | |
346 | && dep_vercmp(provver, dep->mod, dep->version)); | |
20f73d62 | 347 | } |
84ebf823 | 348 | free(provname); |
20f73d62 DM |
349 | } |
350 | ||
84ebf823 | 351 | return(satisfy); |
20f73d62 DM |
352 | } |
353 | ||
7f7da2b5 | 354 | pmdepend_t SYMEXPORT *alpm_splitdep(const char *depstring) |
d04baaba | 355 | { |
e24c22e3 DM |
356 | pmdepend_t *depend; |
357 | char *ptr = NULL; | |
7653bb93 | 358 | char *newstr = NULL; |
d04baaba | 359 | |
e24c22e3 DM |
360 | if(depstring == NULL) { |
361 | return(NULL); | |
362 | } | |
7653bb93 | 363 | newstr = strdup(depstring); |
23229097 | 364 | |
cc754bc6 | 365 | MALLOC(depend, sizeof(pmdepend_t), return(NULL)); |
d04baaba | 366 | |
e24c22e3 DM |
367 | /* Find a version comparator if one exists. If it does, set the type and |
368 | * increment the ptr accordingly so we can copy the right strings. */ | |
7653bb93 | 369 | if((ptr = strstr(newstr, ">="))) { |
95ea99e1 | 370 | depend->mod = PM_DEP_MOD_GE; |
e24c22e3 DM |
371 | *ptr = '\0'; |
372 | ptr += 2; | |
7653bb93 | 373 | } else if((ptr = strstr(newstr, "<="))) { |
95ea99e1 | 374 | depend->mod = PM_DEP_MOD_LE; |
e24c22e3 DM |
375 | *ptr = '\0'; |
376 | ptr += 2; | |
7653bb93 | 377 | } else if((ptr = strstr(newstr, "="))) { |
95ea99e1 | 378 | depend->mod = PM_DEP_MOD_EQ; |
e24c22e3 DM |
379 | *ptr = '\0'; |
380 | ptr += 1; | |
d04baaba | 381 | } else { |
e24c22e3 | 382 | /* no version specified - copy in the name and return it */ |
95ea99e1 | 383 | depend->mod = PM_DEP_MOD_ANY; |
7653bb93 | 384 | strncpy(depend->name, newstr, PKG_NAME_LEN); |
e24c22e3 | 385 | depend->version[0] = '\0'; |
7653bb93 | 386 | free(newstr); |
e24c22e3 | 387 | return(depend); |
d04baaba | 388 | } |
d35e4894 | 389 | |
e24c22e3 DM |
390 | /* if we get here, we have a version comparator, copy the right parts |
391 | * to the right places */ | |
7653bb93 | 392 | strncpy(depend->name, newstr, PKG_NAME_LEN); |
e24c22e3 | 393 | strncpy(depend->version, ptr, PKG_VERSION_LEN); |
7653bb93 | 394 | free(newstr); |
d04baaba | 395 | |
e24c22e3 | 396 | return(depend); |
d04baaba JV |
397 | } |
398 | ||
1c9f30b9 CX |
399 | /* These parameters are messy. We check if this package, given a list of |
400 | * targets and a db is safe to remove. We do NOT remove it if it is in the | |
401 | * target list, or if if the package was explictly installed and | |
402 | * include_explicit == 0 */ | |
403 | static int can_remove_package(pmdb_t *db, pmpkg_t *pkg, alpm_list_t *targets, | |
404 | int include_explicit) | |
f62f3750 | 405 | { |
7219326d | 406 | alpm_list_t *i, *requiredby; |
f62f3750 | 407 | |
7f5dada8 | 408 | if(_alpm_pkg_find(alpm_pkg_get_name(pkg), targets)) { |
f62f3750 AG |
409 | return(0); |
410 | } | |
411 | ||
1c9f30b9 CX |
412 | if(!include_explicit) { |
413 | /* see if it was explicitly installed */ | |
414 | if(alpm_pkg_get_reason(pkg) == PM_PKG_REASON_EXPLICIT) { | |
5c9eec55 | 415 | _alpm_log(PM_LOG_DEBUG, "excluding %s -- explicitly installed\n", |
1c9f30b9 CX |
416 | alpm_pkg_get_name(pkg)); |
417 | return(0); | |
418 | } | |
f62f3750 AG |
419 | } |
420 | ||
1c9f30b9 CX |
421 | /* TODO: checkdeps could be used here, it handles multiple providers |
422 | * better, but that also makes it slower. | |
423 | * Also this would require to first add the package to the targets list, | |
424 | * then call checkdeps with it, then remove the package from the targets list | |
425 | * if checkdeps detected it would break something */ | |
426 | ||
f62f3750 | 427 | /* see if other packages need it */ |
7219326d DM |
428 | requiredby = alpm_pkg_compute_requiredby(pkg); |
429 | for(i = requiredby; i; i = i->next) { | |
f62f3750 | 430 | pmpkg_t *reqpkg = _alpm_db_get_pkgfromcache(db, i->data); |
7f5dada8 | 431 | if(reqpkg && !_alpm_pkg_find(alpm_pkg_get_name(reqpkg), targets)) { |
4ce13e23 | 432 | FREELIST(requiredby); |
f62f3750 AG |
433 | return(0); |
434 | } | |
435 | } | |
7219326d | 436 | FREELIST(requiredby); |
f62f3750 AG |
437 | |
438 | /* it's ok to remove */ | |
439 | return(1); | |
440 | } | |
441 | ||
1c9f30b9 CX |
442 | /** |
443 | * @brief Adds unneeded dependencies to an existing list of packages. | |
444 | * By unneeded, we mean dependencies that are only required by packages in the | |
445 | * target list, so they can be safely removed. | |
85b06f12 | 446 | * If the input list was topo sorted, the output list will be topo sorted too. |
1c9f30b9 CX |
447 | * |
448 | * @param db package database to do dependency tracing in | |
449 | * @param *targs pointer to a list of packages | |
450 | * @param include_explicit if 0, explicitly installed packages are not included | |
d04baaba | 451 | */ |
85b06f12 | 452 | void _alpm_recursedeps(pmdb_t *db, alpm_list_t *targs, int include_explicit) |
d04baaba | 453 | { |
61670172 | 454 | alpm_list_t *i, *j, *k; |
d04baaba | 455 | |
da648bc2 AG |
456 | ALPM_LOG_FUNC; |
457 | ||
1c9f30b9 CX |
458 | if(db == NULL || targs == NULL) { |
459 | return; | |
d04baaba JV |
460 | } |
461 | ||
85b06f12 NG |
462 | for(i = targs; i; i = i->next) { |
463 | pmpkg_t *pkg = i->data; | |
464 | for(j = alpm_pkg_get_depends(pkg); j; j = j->next) { | |
c244cfec DM |
465 | pmdepend_t *depend = j->data; |
466 | ||
85b06f12 NG |
467 | for(k = _alpm_db_get_pkgcache(db); k; k = k->next) { |
468 | pmpkg_t *deppkg = k->data; | |
469 | if(alpm_depcmp(deppkg,depend) | |
470 | && can_remove_package(db, deppkg, targs, include_explicit)) { | |
471 | _alpm_log(PM_LOG_DEBUG, "adding '%s' to the targets\n", | |
472 | alpm_pkg_get_name(deppkg)); | |
f62f3750 | 473 | /* add it to the target list */ |
85b06f12 | 474 | targs = alpm_list_add(targs, _alpm_pkg_dup(deppkg)); |
d04baaba | 475 | } |
d04baaba JV |
476 | } |
477 | } | |
478 | } | |
d04baaba JV |
479 | } |
480 | ||
481 | /* populates *list with packages that need to be installed to satisfy all | |
3b49720e | 482 | * dependencies (recursive) for syncpkg |
d04baaba | 483 | * |
7d37d927 | 484 | * @param remove contains packages elected for removal |
c2920033 | 485 | * make sure **list is already initialized |
d04baaba | 486 | */ |
1b61cc8c | 487 | int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg, |
7d37d927 | 488 | alpm_list_t **list, alpm_list_t *remove, pmtrans_t *trans, alpm_list_t **data) |
d04baaba | 489 | { |
c2920033 | 490 | alpm_list_t *i, *j, *k; |
61670172 AG |
491 | alpm_list_t *targ; |
492 | alpm_list_t *deps = NULL; | |
d04baaba | 493 | |
da648bc2 AG |
494 | ALPM_LOG_FUNC; |
495 | ||
c2920033 | 496 | if(local == NULL || dbs_sync == NULL || syncpkg == NULL || list == NULL) { |
c5418ebf AF |
497 | return(-1); |
498 | } | |
4d21e4f7 | 499 | |
5c9eec55 | 500 | _alpm_log(PM_LOG_DEBUG, "started resolving dependencies\n"); |
61670172 | 501 | targ = alpm_list_add(NULL, syncpkg); |
7d37d927 | 502 | deps = alpm_checkdeps(local, 0, remove, targ); |
a57b2f23 | 503 | alpm_list_free(targ); |
d04baaba JV |
504 | |
505 | if(deps == NULL) { | |
506 | return(0); | |
507 | } | |
508 | ||
509 | for(i = deps; i; i = i->next) { | |
510 | int found = 0; | |
511 | pmdepmissing_t *miss = i->data; | |
c2920033 | 512 | pmdepend_t *missdep = &(miss->depend); |
6dd2ecf4 | 513 | pmpkg_t *sync = NULL; |
d04baaba | 514 | |
c2920033 NG |
515 | /* check if one of the packages in *list already satisfies this dependency */ |
516 | for(j = *list; j && !found; j = j->next) { | |
7f5dada8 | 517 | pmpkg_t *sp = j->data; |
c2920033 | 518 | if(alpm_depcmp(sp, missdep)) { |
d903fc60 | 519 | char *missdepstring = alpm_dep_get_string(missdep); |
5c9eec55 | 520 | _alpm_log(PM_LOG_DEBUG, "%s satisfies dependency %s -- skipping\n", |
d903fc60 NG |
521 | alpm_pkg_get_name(sp), missdepstring); |
522 | free(missdepstring); | |
cf94007a | 523 | found = 1; |
fa627d47 | 524 | } |
6dd2ecf4 | 525 | } |
cf94007a | 526 | if(found) { |
6dd2ecf4 AF |
527 | continue; |
528 | } | |
fa627d47 | 529 | |
6dd2ecf4 AF |
530 | /* find the package in one of the repositories */ |
531 | /* check literals */ | |
c2920033 | 532 | for(j = dbs_sync; j && !found; j = j->next) { |
55a74551 NG |
533 | sync = _alpm_db_get_pkgfromcache(j->data, missdep->name); |
534 | if(!sync) { | |
535 | continue; | |
536 | } | |
7d37d927 | 537 | found = alpm_depcmp(sync, missdep) && !_alpm_pkg_find(alpm_pkg_get_name(sync), remove); |
55a74551 NG |
538 | if(!found) { |
539 | continue; | |
540 | } | |
541 | /* If package is in the ignorepkg list, ask before we pull it */ | |
542 | if(_alpm_pkg_should_ignore(sync)) { | |
543 | pmpkg_t *dummypkg = _alpm_pkg_new(miss->target, NULL); | |
544 | QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, dummypkg, sync, NULL, &found); | |
545 | _alpm_pkg_free(dummypkg); | |
c2920033 | 546 | } |
6dd2ecf4 | 547 | } |
c2920033 | 548 | /*TODO this autoresolves the first 'satisfier' package... we should fix this |
7f5dada8 | 549 | * somehow */ |
6dd2ecf4 | 550 | /* check provides */ |
43eacf28 | 551 | /* we don't check literals again to avoid duplicated PM_TRANS_CONV_INSTALL_IGNOREPKG messages */ |
c2920033 NG |
552 | for(j = dbs_sync; j && !found; j = j->next) { |
553 | for(k = _alpm_db_get_pkgcache(j->data); k && !found; k = k->next) { | |
554 | sync = k->data; | |
55a74551 NG |
555 | if(!sync) { |
556 | continue; | |
557 | } | |
43eacf28 NG |
558 | found = alpm_depcmp(sync, missdep) && strcmp(sync->name, missdep->name) |
559 | && !_alpm_pkg_find(alpm_pkg_get_name(sync), remove); | |
55a74551 NG |
560 | if(!found) { |
561 | continue; | |
562 | } | |
563 | if(_alpm_pkg_should_ignore(sync)) { | |
564 | pmpkg_t *dummypkg = _alpm_pkg_new(miss->target, NULL); | |
565 | QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, dummypkg, sync, NULL, &found); | |
566 | _alpm_pkg_free(dummypkg); | |
567 | } | |
d04baaba | 568 | } |
6dd2ecf4 | 569 | } |
7f5dada8 | 570 | |
c2920033 | 571 | if(!found) { |
d903fc60 NG |
572 | char *missdepstring = alpm_dep_get_string(missdep); |
573 | _alpm_log(PM_LOG_ERROR, _("cannot resolve \"%s\", a dependency of \"%s\"\n"), | |
574 | missdepstring, miss->target); | |
575 | free(missdepstring); | |
fc8be933 | 576 | if(data) { |
7341d095 | 577 | MALLOC(miss, sizeof(pmdepmissing_t),/*nothing*/); |
22c20431 | 578 | if(!miss) { |
fc8be933 | 579 | pm_errno = PM_ERR_MEMORY; |
22c20431 | 580 | FREELIST(*data); |
fc8be933 AF |
581 | goto error; |
582 | } | |
583 | *miss = *(pmdepmissing_t *)i->data; | |
61670172 | 584 | *data = alpm_list_add(*data, miss); |
fc8be933 AF |
585 | } |
586 | pm_errno = PM_ERR_UNSATISFIED_DEPS; | |
6dd2ecf4 | 587 | goto error; |
55a74551 | 588 | } else { |
5c9eec55 | 589 | _alpm_log(PM_LOG_DEBUG, "pulling dependency %s (needed by %s)\n", |
c2920033 NG |
590 | alpm_pkg_get_name(sync), alpm_pkg_get_name(syncpkg)); |
591 | *list = alpm_list_add(*list, sync); | |
7d37d927 | 592 | if(_alpm_resolvedeps(local, dbs_sync, sync, list, remove, trans, data)) { |
c2920033 | 593 | goto error; |
d04baaba | 594 | } |
d04baaba JV |
595 | } |
596 | } | |
23229097 | 597 | |
5c9eec55 | 598 | _alpm_log(PM_LOG_DEBUG, "finished resolving dependencies\n"); |
d04baaba JV |
599 | |
600 | FREELIST(deps); | |
601 | ||
d04baaba JV |
602 | return(0); |
603 | ||
604 | error: | |
605 | FREELIST(deps); | |
606 | return(-1); | |
607 | } | |
608 | ||
1b2817f5 | 609 | const char SYMEXPORT *alpm_miss_get_target(const pmdepmissing_t *miss) |
986409f9 | 610 | { |
da648bc2 AG |
611 | ALPM_LOG_FUNC; |
612 | ||
986409f9 | 613 | /* Sanity checks */ |
986409f9 AG |
614 | ASSERT(miss != NULL, return(NULL)); |
615 | ||
616 | return miss->target; | |
617 | } | |
618 | ||
99572ed8 | 619 | pmdepend_t SYMEXPORT *alpm_miss_get_dep(pmdepmissing_t *miss) |
986409f9 | 620 | { |
da648bc2 AG |
621 | ALPM_LOG_FUNC; |
622 | ||
986409f9 | 623 | /* Sanity checks */ |
99572ed8 | 624 | ASSERT(miss != NULL, return(NULL)); |
986409f9 | 625 | |
c244cfec | 626 | return &(miss->depend); |
986409f9 AG |
627 | } |
628 | ||
1b2817f5 | 629 | pmdepmod_t SYMEXPORT alpm_dep_get_mod(const pmdepend_t *dep) |
986409f9 | 630 | { |
da648bc2 AG |
631 | ALPM_LOG_FUNC; |
632 | ||
986409f9 | 633 | /* Sanity checks */ |
99572ed8 | 634 | ASSERT(dep != NULL, return(-1)); |
986409f9 | 635 | |
99572ed8 | 636 | return dep->mod; |
986409f9 AG |
637 | } |
638 | ||
1b2817f5 | 639 | const char SYMEXPORT *alpm_dep_get_name(const pmdepend_t *dep) |
986409f9 | 640 | { |
da648bc2 AG |
641 | ALPM_LOG_FUNC; |
642 | ||
986409f9 | 643 | /* Sanity checks */ |
99572ed8 | 644 | ASSERT(dep != NULL, return(NULL)); |
986409f9 | 645 | |
99572ed8 | 646 | return dep->name; |
986409f9 | 647 | } |
5e68e9d4 | 648 | |
1b2817f5 | 649 | const char SYMEXPORT *alpm_dep_get_version(const pmdepend_t *dep) |
5e68e9d4 AF |
650 | { |
651 | ALPM_LOG_FUNC; | |
652 | ||
653 | /* Sanity checks */ | |
5e68e9d4 AF |
654 | ASSERT(dep != NULL, return(NULL)); |
655 | ||
99572ed8 | 656 | return dep->version; |
5e68e9d4 AF |
657 | } |
658 | ||
1b2817f5 DM |
659 | /** Reverse of splitdep; make a dep string from a pmdepend_t struct. |
660 | * The string must be freed! | |
661 | * @param dep the depend to turn into a string | |
662 | * @return a string-formatted dependency with operator if necessary | |
663 | */ | |
664 | char SYMEXPORT *alpm_dep_get_string(const pmdepend_t *dep) | |
0cff7c6b | 665 | { |
1b2817f5 DM |
666 | char *opr, *str = NULL; |
667 | size_t len; | |
668 | ||
0cff7c6b NG |
669 | ALPM_LOG_FUNC; |
670 | ||
671 | /* Sanity checks */ | |
0cff7c6b NG |
672 | ASSERT(dep != NULL, return(NULL)); |
673 | ||
0cff7c6b NG |
674 | switch(dep->mod) { |
675 | case PM_DEP_MOD_ANY: | |
1b2817f5 | 676 | opr = ""; |
0cff7c6b NG |
677 | break; |
678 | case PM_DEP_MOD_GE: | |
1b2817f5 | 679 | opr = ">="; |
0cff7c6b NG |
680 | break; |
681 | case PM_DEP_MOD_LE: | |
1b2817f5 DM |
682 | opr = "<="; |
683 | break; | |
684 | case PM_DEP_MOD_EQ: | |
685 | opr = "="; | |
686 | break; | |
687 | default: | |
688 | opr = ""; | |
0cff7c6b NG |
689 | break; |
690 | } | |
691 | ||
1b2817f5 DM |
692 | /* we can always compute len and print the string like this because opr |
693 | * and ver will be empty when PM_DEP_MOD_ANY is the depend type */ | |
694 | len = strlen(dep->name) + strlen(opr) + strlen(dep->version) + 1; | |
695 | MALLOC(str, len, RET_ERR(PM_ERR_MEMORY, NULL)); | |
696 | snprintf(str, len, "%s%s%s", dep->name, opr, dep->version); | |
697 | ||
698 | return(str); | |
0cff7c6b | 699 | } |
d04baaba | 700 | /* vim: set ts=2 sw=2 noet: */ |