deps.c

Go to the documentation of this file.
00001 /*
00002  *  deps.c
00003  *
00004  *  Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org>
00005  *  Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
00006  *  Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
00007  *
00008  *  This program is free software; you can redistribute it and/or modify
00009  *  it under the terms of the GNU General Public License as published by
00010  *  the Free Software Foundation; either version 2 of the License, or
00011  *  (at your option) any later version.
00012  *
00013  *  This program is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *  GNU General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU General Public License
00019  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 #include "config.h"
00023 
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027 
00028 /* libalpm */
00029 #include "deps.h"
00030 #include "alpm_list.h"
00031 #include "util.h"
00032 #include "log.h"
00033 #include "error.h"
00034 #include "package.h"
00035 #include "db.h"
00036 #include "cache.h"
00037 #include "handle.h"
00038 
00039 void _alpm_dep_free(pmdepend_t *dep)
00040 {
00041     FREE(dep->name);
00042     FREE(dep->version);
00043     FREE(dep);
00044 }
00045 
00046 static pmgraph_t *_alpm_graph_new(void)
00047 {
00048     pmgraph_t *graph = NULL;
00049 
00050     ALPM_LOG_FUNC;
00051 
00052     MALLOC(graph, sizeof(pmgraph_t), RET_ERR(PM_ERR_MEMORY, NULL));
00053 
00054     if(graph) {
00055         graph->state = 0;
00056         graph->data = NULL;
00057         graph->parent = NULL;
00058         graph->children = NULL;
00059         graph->childptr = NULL;
00060     }
00061     return(graph);
00062 }
00063 
00064 static void _alpm_graph_free(void *data)
00065 {
00066     pmgraph_t *graph = data;
00067     alpm_list_free(graph->children);
00068     free(graph);
00069 }
00070 
00071 pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepend_t *dep)
00072 {
00073     pmdepmissing_t *miss;
00074 
00075     ALPM_LOG_FUNC;
00076 
00077     MALLOC(miss, sizeof(pmdepmissing_t), RET_ERR(PM_ERR_MEMORY, NULL));
00078 
00079     STRDUP(miss->target, target, RET_ERR(PM_ERR_MEMORY, NULL));
00080     miss->depend = _alpm_dep_dup(dep);
00081 
00082     return(miss);
00083 }
00084 
00085 void _alpm_depmiss_free(pmdepmissing_t *miss)
00086 {
00087     _alpm_dep_free(miss->depend);
00088     FREE(miss->target);
00089     FREE(miss);
00090 }
00091 
00092 /* Convert a list of pmpkg_t * to a graph structure,
00093  * with a edge for each dependency.
00094  * Returns a list of vertices (one vertex = one package)
00095  * (used by alpm_sortbydeps)
00096  */
00097 static alpm_list_t *_alpm_graph_init(alpm_list_t *targets)
00098 {
00099     alpm_list_t *i, *j, *k;
00100     alpm_list_t *vertices = NULL;
00101     /* We create the vertices */
00102     for(i = targets; i; i = i->next) {
00103         pmgraph_t *vertex = _alpm_graph_new();
00104         vertex->data = (void *)i->data;
00105         vertices = alpm_list_add(vertices, vertex);
00106     }
00107 
00108     /* We compute the edges */
00109     for(i = vertices; i; i = i->next) {
00110         pmgraph_t *vertex_i = i->data;
00111         pmpkg_t *p_i = vertex_i->data;
00112         /* TODO this should be somehow combined with alpm_checkdeps */
00113         for(j = vertices; j; j = j->next) {
00114             pmgraph_t *vertex_j = j->data;
00115             pmpkg_t *p_j = vertex_j->data;
00116             int child = 0;
00117             for(k = alpm_pkg_get_depends(p_i); k && !child; k = k->next) {
00118                 pmdepend_t *depend = k->data;
00119                 child = alpm_depcmp(p_j, depend);
00120             }
00121             if(child) {
00122                 vertex_i->children =
00123                     alpm_list_add(vertex_i->children, vertex_j);
00124             }
00125         }
00126         vertex_i->childptr = vertex_i->children;
00127     }
00128     return(vertices);
00129 }
00130 
00131 /* Re-order a list of target packages with respect to their dependencies.
00132  *
00133  * Example (PM_TRANS_TYPE_ADD):
00134  *   A depends on C
00135  *   B depends on A
00136  *   Target order is A,B,C,D
00137  *
00138  *   Should be re-ordered to C,A,B,D
00139  *
00140  * mode should be either PM_TRANS_TYPE_ADD or PM_TRANS_TYPE_REMOVE.  This
00141  * affects the dependency order sortbydeps() will use.
00142  *
00143  * This function returns the new alpm_list_t* target list.
00144  *
00145  */
00146 alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode)
00147 {
00148     alpm_list_t *newtargs = NULL;
00149     alpm_list_t *vertices = NULL;
00150     alpm_list_t *vptr;
00151     pmgraph_t *vertex;
00152 
00153     ALPM_LOG_FUNC;
00154 
00155     if(targets == NULL) {
00156         return(NULL);
00157     }
00158 
00159     _alpm_log(PM_LOG_DEBUG, "started sorting dependencies\n");
00160 
00161     vertices = _alpm_graph_init(targets);
00162 
00163     vptr = vertices;
00164     vertex = vertices->data;
00165     while(vptr) {
00166         /* mark that we touched the vertex */
00167         vertex->state = -1;
00168         int found = 0;
00169         while(vertex->childptr && !found) {
00170             pmgraph_t *nextchild = (vertex->childptr)->data;
00171             vertex->childptr = (vertex->childptr)->next;
00172             if (nextchild->state == 0) {
00173                 found = 1;
00174                 nextchild->parent = vertex;
00175                 vertex = nextchild;
00176             }
00177             else if(nextchild->state == -1) {
00178                 pmpkg_t *vertexpkg = vertex->data;
00179                 pmpkg_t *childpkg = nextchild->data;
00180                 _alpm_log(PM_LOG_WARNING, _("dependency cycle detected:\n"));
00181                 if(mode == PM_TRANS_TYPE_REMOVE) {
00182                     _alpm_log(PM_LOG_WARNING, _("%s will be removed after its %s dependency\n"), vertexpkg->name, childpkg->name);
00183                 } else {
00184                     _alpm_log(PM_LOG_WARNING, _("%s will be installed before its %s dependency\n"), vertexpkg->name, childpkg->name);
00185                 }
00186             }
00187         }
00188         if(!found) {
00189             newtargs = alpm_list_add(newtargs, vertex->data);
00190             /* mark that we've left this vertex */
00191             vertex->state = 1;
00192             vertex = vertex->parent;
00193             if(!vertex) {
00194                 vptr = vptr->next;
00195                 while(vptr) {
00196                     vertex = vptr->data;
00197                     if (vertex->state == 0) break;
00198                     vptr = vptr->next;
00199                 }
00200             }
00201         }
00202     }
00203 
00204     _alpm_log(PM_LOG_DEBUG, "sorting dependencies finished\n");
00205 
00206     if(mode == PM_TRANS_TYPE_REMOVE) {
00207         /* we're removing packages, so reverse the order */
00208         alpm_list_t *tmptargs = alpm_list_reverse(newtargs);
00209         /* free the old one */
00210         alpm_list_free(newtargs);
00211         newtargs = tmptargs;
00212     }
00213 
00214     alpm_list_free_inner(vertices, _alpm_graph_free);
00215     alpm_list_free(vertices);
00216 
00217     return(newtargs);
00218 }
00219 
00220 /* Little helper function for alpm_list_find */
00221 static int satisfycmp(const void *pkg, const void *depend)
00222 {
00223     return(!alpm_depcmp((pmpkg_t*) pkg, (pmdepend_t*) depend));
00224 }
00225 
00226 /** Checks dependencies and returns missing ones in a list.
00227  * Dependencies can include versions with depmod operators.
00228  * @param db pointer to the local package database
00229  * @param reversedeps handles the backward dependencies
00230  * @param remove an alpm_list_t* of packages to be removed
00231  * @param upgrade an alpm_list_t* of packages to be upgraded (remove-then-upgrade)
00232  * @return an alpm_list_t* of pmpkg_t* of missing_t pointers.
00233  */
00234 alpm_list_t SYMEXPORT *alpm_checkdeps(pmdb_t *db, int reversedeps,
00235         alpm_list_t *remove, alpm_list_t *upgrade)
00236 {
00237     alpm_list_t *i, *j;
00238     alpm_list_t *targets, *dblist = NULL, *modified = NULL;
00239     alpm_list_t *baddeps = NULL;
00240     pmdepmissing_t *miss = NULL;
00241 
00242     ALPM_LOG_FUNC;
00243 
00244     if(db == NULL) {
00245         return(NULL);
00246     }
00247 
00248     targets = alpm_list_join(alpm_list_copy(remove), alpm_list_copy(upgrade));
00249     for(i = _alpm_db_get_pkgcache(db); i; i = i->next) {
00250         void *pkg = i->data;
00251         if(alpm_list_find(targets, pkg, _alpm_pkg_cmp)) {
00252             modified = alpm_list_add(modified, pkg);
00253         } else {
00254             dblist = alpm_list_add(dblist, pkg);
00255         }
00256     }
00257     alpm_list_free(targets);
00258 
00259     /* look for unsatisfied dependencies of the upgrade list */
00260     for(i = upgrade; i; i = i->next) {
00261         pmpkg_t *tp = i->data;
00262         _alpm_log(PM_LOG_DEBUG, "checkdeps: package %s-%s\n",
00263                 alpm_pkg_get_name(tp), alpm_pkg_get_version(tp));
00264 
00265         for(j = alpm_pkg_get_depends(tp); j; j = j->next) {
00266             pmdepend_t *depend = j->data;
00267             /* 1. we check the upgrade list */
00268             /* 2. we check database for untouched satisfying packages */
00269             if(!alpm_list_find(upgrade, depend, satisfycmp) &&
00270                !alpm_list_find(dblist, depend, satisfycmp)) {
00271                 /* Unsatisfied dependency in the upgrade list */
00272                 char *missdepstring = alpm_dep_get_string(depend);
00273                 _alpm_log(PM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n",
00274                         missdepstring, alpm_pkg_get_name(tp));
00275                 free(missdepstring);
00276                 miss = _alpm_depmiss_new(alpm_pkg_get_name(tp), depend);
00277                 baddeps = alpm_list_add(baddeps, miss);
00278             }
00279         }
00280     }
00281 
00282     if(reversedeps) {
00283         /* reversedeps handles the backwards dependencies, ie,
00284          * the packages listed in the requiredby field. */
00285         for(i = dblist; i; i = i->next) {
00286             pmpkg_t *lp = i->data;
00287             for(j = alpm_pkg_get_depends(lp); j; j = j->next) {
00288                 pmdepend_t *depend = j->data;
00289                 /* we won't break this depend, if it is already broken, we ignore it */
00290                 /* 1. check upgrade list for satisfiers */
00291                 /* 2. check dblist for satisfiers */
00292                 if(alpm_list_find(modified, depend, satisfycmp) &&
00293                    !alpm_list_find(upgrade, depend, satisfycmp) &&
00294                    !alpm_list_find(dblist, depend, satisfycmp)) {
00295                     char *missdepstring = alpm_dep_get_string(depend);
00296                     _alpm_log(PM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n",
00297                             missdepstring, alpm_pkg_get_name(lp));
00298                     free(missdepstring);
00299                     miss = _alpm_depmiss_new(lp->name, depend);
00300                     baddeps = alpm_list_add(baddeps, miss);
00301                 }
00302             }
00303         }
00304     }
00305     alpm_list_free(modified);
00306     alpm_list_free(dblist);
00307 
00308     return(baddeps);
00309 }
00310 
00311 static int dep_vercmp(const char *version1, pmdepmod_t mod,
00312         const char *version2)
00313 {
00314     int equal = 0;
00315 
00316     if(mod == PM_DEP_MOD_ANY) {
00317         equal = 1;
00318     } else {
00319         int cmp = _alpm_versioncmp(version1, version2);
00320         switch(mod) {
00321             case PM_DEP_MOD_EQ: equal = (cmp == 0); break;
00322             case PM_DEP_MOD_GE: equal = (cmp >= 0); break;
00323             case PM_DEP_MOD_LE: equal = (cmp <= 0); break;
00324             case PM_DEP_MOD_LT: equal = (cmp < 0); break;
00325             case PM_DEP_MOD_GT: equal = (cmp > 0); break;
00326             default: equal = 1; break;
00327         }
00328     }
00329     return(equal);
00330 }
00331 
00332 int SYMEXPORT alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep)
00333 {
00334     alpm_list_t *i;
00335 
00336     ALPM_LOG_FUNC;
00337 
00338     const char *pkgname = alpm_pkg_get_name(pkg);
00339     const char *pkgversion = alpm_pkg_get_version(pkg);
00340     int satisfy = 0;
00341 
00342     /* check (pkg->name, pkg->version) */
00343     satisfy = (strcmp(pkgname, dep->name) == 0
00344             && dep_vercmp(pkgversion, dep->mod, dep->version));
00345 
00346     /* check provisions, format : "name=version" */
00347     for(i = alpm_pkg_get_provides(pkg); i && !satisfy; i = i->next) {
00348         char *provname = strdup(i->data);
00349         char *provver = strchr(provname, '=');
00350 
00351         if(provver == NULL) { /* no provision version */
00352             satisfy = (dep->mod == PM_DEP_MOD_ANY
00353                     && strcmp(provname, dep->name) == 0);
00354         } else {
00355             /* replace the space with a NULL byte, and advance ptr the version */
00356             *provver = '\0';
00357             provver += 1;
00358             satisfy = (strcmp(provname, dep->name) == 0
00359                     && dep_vercmp(provver, dep->mod, dep->version));
00360         }
00361         free(provname);
00362     }
00363 
00364     return(satisfy);
00365 }
00366 
00367 pmdepend_t SYMEXPORT *alpm_splitdep(const char *depstring)
00368 {
00369     pmdepend_t *depend;
00370     char *ptr = NULL;
00371     char *newstr = NULL;
00372 
00373     if(depstring == NULL) {
00374         return(NULL);
00375     }
00376     STRDUP(newstr, depstring, RET_ERR(PM_ERR_MEMORY, NULL));
00377 
00378     CALLOC(depend, sizeof(pmdepend_t), 1, RET_ERR(PM_ERR_MEMORY, NULL));
00379 
00380     /* Find a version comparator if one exists. If it does, set the type and
00381      * increment the ptr accordingly so we can copy the right strings. */
00382     if((ptr = strstr(newstr, ">="))) {
00383         depend->mod = PM_DEP_MOD_GE;
00384         *ptr = '\0';
00385         ptr += 2;
00386     } else if((ptr = strstr(newstr, "<="))) {
00387         depend->mod = PM_DEP_MOD_LE;
00388         *ptr = '\0';
00389         ptr += 2;
00390     } else if((ptr = strstr(newstr, "="))) { /* Note: we must do =,<,> checks after <=, >= checks */
00391         depend->mod = PM_DEP_MOD_EQ;
00392         *ptr = '\0';
00393         ptr += 1;
00394     } else if((ptr = strstr(newstr, "<"))) {
00395         depend->mod = PM_DEP_MOD_LT;
00396         *ptr = '\0';
00397         ptr += 1;
00398     } else if((ptr = strstr(newstr, ">"))) {
00399         depend->mod = PM_DEP_MOD_GT;
00400         *ptr = '\0';
00401         ptr += 1;
00402     } else {
00403         /* no version specified - copy the name and return it */
00404         depend->mod = PM_DEP_MOD_ANY;
00405         STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL));
00406         depend->version = NULL;
00407         free(newstr);
00408         return(depend);
00409     }
00410 
00411     /* if we get here, we have a version comparator, copy the right parts
00412      * to the right places */
00413     STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL));
00414     STRDUP(depend->version, ptr, RET_ERR(PM_ERR_MEMORY, NULL));
00415     free(newstr);
00416 
00417     return(depend);
00418 }
00419 
00420 pmdepend_t *_alpm_dep_dup(const pmdepend_t *dep)
00421 {
00422     pmdepend_t *newdep;
00423     CALLOC(newdep, sizeof(pmdepend_t), 1, RET_ERR(PM_ERR_MEMORY, NULL));
00424 
00425     STRDUP(newdep->name, dep->name, RET_ERR(PM_ERR_MEMORY, NULL));
00426     STRDUP(newdep->version, dep->version, RET_ERR(PM_ERR_MEMORY, NULL));
00427     newdep->mod = dep->mod;
00428 
00429     return(newdep);
00430 }
00431 
00432 /* These parameters are messy. We check if this package, given a list of
00433  * targets and a db is safe to remove. We do NOT remove it if it is in the
00434  * target list, or if if the package was explictly installed and
00435  * include_explicit == 0 */
00436 static int can_remove_package(pmdb_t *db, pmpkg_t *pkg, alpm_list_t *targets,
00437         int include_explicit)
00438 {
00439     alpm_list_t *i, *requiredby;
00440 
00441     if(_alpm_pkg_find(alpm_pkg_get_name(pkg), targets)) {
00442         return(0);
00443     }
00444 
00445     if(!include_explicit) {
00446         /* see if it was explicitly installed */
00447         if(alpm_pkg_get_reason(pkg) == PM_PKG_REASON_EXPLICIT) {
00448             _alpm_log(PM_LOG_DEBUG, "excluding %s -- explicitly installed\n",
00449                     alpm_pkg_get_name(pkg));
00450             return(0);
00451         }
00452     }
00453 
00454     /* TODO: checkdeps could be used here, it handles multiple providers
00455      * better, but that also makes it slower.
00456      * Also this would require to first add the package to the targets list,
00457      * then call checkdeps with it, then remove the package from the targets list
00458      * if checkdeps detected it would break something */
00459 
00460     /* see if other packages need it */
00461     requiredby = alpm_pkg_compute_requiredby(pkg);
00462     for(i = requiredby; i; i = i->next) {
00463         pmpkg_t *reqpkg = _alpm_db_get_pkgfromcache(db, i->data);
00464         if(reqpkg && !_alpm_pkg_find(alpm_pkg_get_name(reqpkg), targets)) {
00465             FREELIST(requiredby);
00466             return(0);
00467         }
00468     }
00469     FREELIST(requiredby);
00470 
00471     /* it's ok to remove */
00472     return(1);
00473 }
00474 
00475 /**
00476  * @brief Adds unneeded dependencies to an existing list of packages.
00477  * By unneeded, we mean dependencies that are only required by packages in the
00478  * target list, so they can be safely removed.
00479  * If the input list was topo sorted, the output list will be topo sorted too.
00480  *
00481  * @param db package database to do dependency tracing in
00482  * @param *targs pointer to a list of packages
00483  * @param include_explicit if 0, explicitly installed packages are not included
00484  */
00485 void _alpm_recursedeps(pmdb_t *db, alpm_list_t *targs, int include_explicit)
00486 {
00487     alpm_list_t *i, *j, *k;
00488 
00489     ALPM_LOG_FUNC;
00490 
00491     if(db == NULL || targs == NULL) {
00492         return;
00493     }
00494 
00495     for(i = targs; i; i = i->next) {
00496         pmpkg_t *pkg = i->data;
00497         for(j = alpm_pkg_get_depends(pkg); j; j = j->next) {
00498             pmdepend_t *depend = j->data;
00499 
00500             for(k = _alpm_db_get_pkgcache(db); k; k = k->next) {
00501                 pmpkg_t *deppkg = k->data;
00502                 if(alpm_depcmp(deppkg,depend)
00503                         && can_remove_package(db, deppkg, targs, include_explicit)) {
00504                     _alpm_log(PM_LOG_DEBUG, "adding '%s' to the targets\n",
00505                             alpm_pkg_get_name(deppkg));
00506                         /* add it to the target list */
00507                     targs = alpm_list_add(targs, _alpm_pkg_dup(deppkg));
00508                 }
00509             }
00510         }
00511     }
00512 }
00513 
00514 /* populates *list with packages that need to be installed to satisfy all
00515  * dependencies (recursive) for syncpkg
00516  *
00517  * @param remove contains packages elected for removal
00518  * make sure **list is already initialized
00519  */
00520 int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg,
00521                       alpm_list_t **list, alpm_list_t *remove, pmtrans_t *trans, alpm_list_t **data)
00522 {
00523     alpm_list_t *i, *j, *k;
00524     alpm_list_t *targ;
00525     alpm_list_t *deps = NULL;
00526 
00527     ALPM_LOG_FUNC;
00528 
00529     if(local == NULL || dbs_sync == NULL || syncpkg == NULL || list == NULL) {
00530         return(-1);
00531     }
00532 
00533     _alpm_log(PM_LOG_DEBUG, "started resolving dependencies\n");
00534     targ = alpm_list_add(NULL, syncpkg);
00535     deps = alpm_checkdeps(local, 0, remove, targ);
00536     alpm_list_free(targ);
00537 
00538     if(deps == NULL) {
00539         return(0);
00540     }
00541 
00542     for(i = deps; i; i = i->next) {
00543         int found = 0;
00544         pmdepmissing_t *miss = i->data;
00545         pmdepend_t *missdep = alpm_miss_get_dep(miss);
00546         pmpkg_t *sync = NULL;
00547 
00548         /* check if one of the packages in *list already satisfies this dependency */
00549         for(j = *list; j && !found; j = j->next) {
00550             pmpkg_t *sp = j->data;
00551             if(alpm_depcmp(sp, missdep)) {
00552                 char *missdepstring = alpm_dep_get_string(missdep);
00553                 _alpm_log(PM_LOG_DEBUG, "%s satisfies dependency %s -- skipping\n",
00554                           alpm_pkg_get_name(sp), missdepstring);
00555                 free(missdepstring);
00556                 found = 1;
00557             }
00558         }
00559         if(found) {
00560             continue;
00561         }
00562 
00563         /* find the package in one of the repositories */
00564         /* check literals */
00565         for(j = dbs_sync; j && !found; j = j->next) {
00566             sync = _alpm_db_get_pkgfromcache(j->data, missdep->name);
00567             if(!sync) {
00568                 continue;
00569             }
00570             found = alpm_depcmp(sync, missdep) && !_alpm_pkg_find(alpm_pkg_get_name(sync), remove);
00571             if(!found) {
00572                 continue;
00573             }
00574             /* If package is in the ignorepkg list, ask before we pull it */
00575             if(_alpm_pkg_should_ignore(sync)) {
00576                 pmpkg_t *dummypkg = _alpm_pkg_new(miss->target, NULL);
00577                 QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, dummypkg, sync, NULL, &found);
00578                 _alpm_pkg_free(dummypkg);
00579             }
00580         }
00581         /*TODO this autoresolves the first 'satisfier' package... we should fix this
00582          * somehow */
00583         /* check provides */
00584         /* we don't check literals again to avoid duplicated PM_TRANS_CONV_INSTALL_IGNOREPKG messages */
00585         for(j = dbs_sync; j && !found; j = j->next) {
00586             for(k = _alpm_db_get_pkgcache(j->data); k && !found; k = k->next) {
00587                 sync = k->data;
00588                 if(!sync) {
00589                     continue;
00590                 }
00591                 found = alpm_depcmp(sync, missdep) && strcmp(sync->name, missdep->name)
00592                     && !_alpm_pkg_find(alpm_pkg_get_name(sync), remove);
00593                 if(!found) {
00594                     continue;
00595                 }
00596                 if(_alpm_pkg_should_ignore(sync)) {
00597                     pmpkg_t *dummypkg = _alpm_pkg_new(miss->target, NULL);
00598                     QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, dummypkg, sync, NULL, &found);
00599                     _alpm_pkg_free(dummypkg);
00600                 }
00601             }
00602         }
00603 
00604         if(!found) {
00605             char *missdepstring = alpm_dep_get_string(missdep);
00606             _alpm_log(PM_LOG_ERROR, _("cannot resolve \"%s\", a dependency of \"%s\"\n"),
00607                       missdepstring, miss->target);
00608             free(missdepstring);
00609             if(data) {
00610                 MALLOC(miss, sizeof(pmdepmissing_t),/*nothing*/);
00611                 if(!miss) {
00612                     pm_errno = PM_ERR_MEMORY;
00613                     FREELIST(*data);
00614                     goto error;
00615                 }
00616                 *miss = *(pmdepmissing_t *)i->data;
00617                 *data = alpm_list_add(*data, miss);
00618             }
00619             pm_errno = PM_ERR_UNSATISFIED_DEPS;
00620             goto error;
00621         } else {
00622             _alpm_log(PM_LOG_DEBUG, "pulling dependency %s (needed by %s)\n",
00623                     alpm_pkg_get_name(sync), alpm_pkg_get_name(syncpkg));
00624             *list = alpm_list_add(*list, sync);
00625             if(_alpm_resolvedeps(local, dbs_sync, sync, list, remove, trans, data)) {
00626                 goto error;
00627             }
00628         }
00629     }
00630 
00631     _alpm_log(PM_LOG_DEBUG, "finished resolving dependencies\n");
00632 
00633     alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free);
00634     alpm_list_free(deps);
00635 
00636     return(0);
00637 
00638 error:
00639     FREELIST(deps);
00640     return(-1);
00641 }
00642 
00643 const char SYMEXPORT *alpm_miss_get_target(const pmdepmissing_t *miss)
00644 {
00645     ALPM_LOG_FUNC;
00646 
00647     /* Sanity checks */
00648     ASSERT(miss != NULL, return(NULL));
00649 
00650     return(miss->target);
00651 }
00652 
00653 pmdepend_t SYMEXPORT *alpm_miss_get_dep(pmdepmissing_t *miss)
00654 {
00655     ALPM_LOG_FUNC;
00656 
00657     /* Sanity checks */
00658     ASSERT(miss != NULL, return(NULL));
00659 
00660     return(miss->depend);
00661 }
00662 
00663 pmdepmod_t SYMEXPORT alpm_dep_get_mod(const pmdepend_t *dep)
00664 {
00665     ALPM_LOG_FUNC;
00666 
00667     /* Sanity checks */
00668     ASSERT(dep != NULL, return(-1));
00669 
00670     return(dep->mod);
00671 }
00672 
00673 const char SYMEXPORT *alpm_dep_get_name(const pmdepend_t *dep)
00674 {
00675     ALPM_LOG_FUNC;
00676 
00677     /* Sanity checks */
00678     ASSERT(dep != NULL, return(NULL));
00679 
00680     return(dep->name);
00681 }
00682 
00683 const char SYMEXPORT *alpm_dep_get_version(const pmdepend_t *dep)
00684 {
00685     ALPM_LOG_FUNC;
00686 
00687     /* Sanity checks */
00688     ASSERT(dep != NULL, return(NULL));
00689 
00690     return(dep->version);
00691 }
00692 
00693 /** Reverse of splitdep; make a dep string from a pmdepend_t struct.
00694  * The string must be freed!
00695  * @param dep the depend to turn into a string
00696  * @return a string-formatted dependency with operator if necessary
00697  */
00698 char SYMEXPORT *alpm_dep_get_string(const pmdepend_t *dep)
00699 {
00700     char *name, *opr, *ver, *str = NULL;
00701     size_t len;
00702 
00703     ALPM_LOG_FUNC;
00704 
00705     /* Sanity checks */
00706     ASSERT(dep != NULL, return(NULL));
00707 
00708     if(dep->name) {
00709         name = dep->name;
00710     } else {
00711         name = "";
00712     }
00713 
00714     switch(dep->mod) {
00715         case PM_DEP_MOD_ANY:
00716             opr = "";
00717             break;
00718         case PM_DEP_MOD_GE:
00719             opr = ">=";
00720             break;
00721         case PM_DEP_MOD_LE:
00722             opr = "<=";
00723             break;
00724         case PM_DEP_MOD_EQ:
00725             opr = "=";
00726             break;
00727         case PM_DEP_MOD_LT:
00728             opr = "<";
00729             break;
00730         case PM_DEP_MOD_GT:
00731             opr = ">";
00732             break;
00733         default:
00734             opr = "";
00735             break;
00736     }
00737 
00738     if(dep->version) {
00739         ver = dep->version;
00740     } else {
00741         ver = "";
00742     }
00743 
00744     /* we can always compute len and print the string like this because opr
00745      * and ver will be empty when PM_DEP_MOD_ANY is the depend type. the
00746      * reassignments above also ensure we do not do a strlen(NULL). */
00747     len = strlen(name) + strlen(opr) + strlen(ver) + 1;
00748     MALLOC(str, len, RET_ERR(PM_ERR_MEMORY, NULL));
00749     snprintf(str, len, "%s%s%s", name, opr, ver);
00750 
00751     return(str);
00752 }
00753 /* vim: set ts=2 sw=2 noet: */

Generated on Mon Jan 14 23:53:40 2008 for libalpm by  doxygen 1.5.4