mirror of
https://github.com/moparisthebest/pacman
synced 2024-11-04 16:45:07 -05:00
746 lines
20 KiB
C
746 lines
20 KiB
C
/*
|
|
* deps.c
|
|
*
|
|
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
|
|
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
|
|
* Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
* USA.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#ifdef __sun__
|
|
#include <strings.h>
|
|
#endif
|
|
#include <libintl.h>
|
|
#include <math.h>
|
|
/* pacman */
|
|
#include "util.h"
|
|
#include "log.h"
|
|
#include "error.h"
|
|
#include "alpm_list.h"
|
|
#include "package.h"
|
|
#include "db.h"
|
|
#include "cache.h"
|
|
#include "provide.h"
|
|
#include "deps.h"
|
|
#include "versioncmp.h"
|
|
#include "handle.h"
|
|
|
|
extern pmhandle_t *handle;
|
|
|
|
pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdeptype_t type,
|
|
pmdepmod_t depmod, const char *depname,
|
|
const char *depversion)
|
|
{
|
|
pmdepmissing_t *miss;
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
miss = (pmdepmissing_t *)malloc(sizeof(pmdepmissing_t));
|
|
if(miss == NULL) {
|
|
_alpm_log(PM_LOG_ERROR, _("malloc failure: could not allocate %d bytes"), sizeof(pmdepmissing_t));
|
|
RET_ERR(PM_ERR_MEMORY, NULL);
|
|
}
|
|
|
|
STRNCPY(miss->target, target, PKG_NAME_LEN);
|
|
miss->type = type;
|
|
miss->depend.mod = depmod;
|
|
STRNCPY(miss->depend.name, depname, PKG_NAME_LEN);
|
|
if(depversion) {
|
|
STRNCPY(miss->depend.version, depversion, PKG_VERSION_LEN);
|
|
} else {
|
|
miss->depend.version[0] = 0;
|
|
}
|
|
|
|
return(miss);
|
|
}
|
|
|
|
int _alpm_depmiss_isin(pmdepmissing_t *needle, alpm_list_t *haystack)
|
|
{
|
|
alpm_list_t *i;
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
for(i = haystack; i; i = i->next) {
|
|
pmdepmissing_t *miss = i->data;
|
|
if(!memcmp(needle, miss, sizeof(pmdepmissing_t))
|
|
&& !memcmp(&needle->depend, &miss->depend, sizeof(pmdepend_t))) {
|
|
return(1);
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* Re-order a list of target packages with respect to their dependencies.
|
|
*
|
|
* Example (PM_TRANS_TYPE_ADD):
|
|
* A depends on C
|
|
* B depends on A
|
|
* Target order is A,B,C,D
|
|
*
|
|
* Should be re-ordered to C,A,B,D
|
|
*
|
|
* mode should be either PM_TRANS_TYPE_ADD or PM_TRANS_TYPE_REMOVE. This
|
|
* affects the dependency order sortbydeps() will use.
|
|
*
|
|
* This function returns the new alpm_list_t* target list.
|
|
*
|
|
*/
|
|
alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode)
|
|
{
|
|
alpm_list_t *newtargs = NULL;
|
|
alpm_list_t *i, *j, *k, *l;
|
|
int change = 1;
|
|
int numscans = 0;
|
|
int numtargs = 0;
|
|
int maxscans;
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
if(targets == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
for(i = targets; i; i = i->next) {
|
|
newtargs = alpm_list_add(newtargs, i->data);
|
|
numtargs++;
|
|
}
|
|
|
|
maxscans = (int)sqrt(numtargs);
|
|
|
|
_alpm_log(PM_LOG_DEBUG, _("started sorting dependencies"));
|
|
while(change) {
|
|
alpm_list_t *tmptargs = NULL;
|
|
change = 0;
|
|
if(numscans > maxscans) {
|
|
_alpm_log(PM_LOG_DEBUG, _("possible dependency cycle detected"));
|
|
continue;
|
|
}
|
|
numscans++;
|
|
/* run thru targets, moving up packages as necessary */
|
|
for(i = newtargs; i; i = i->next) {
|
|
pmpkg_t *p = (pmpkg_t*)i->data;
|
|
_alpm_log(PM_LOG_DEBUG, "sorting %s", p->name);
|
|
for(j = alpm_pkg_get_depends(p); j; j = j->next) {
|
|
pmdepend_t dep;
|
|
pmpkg_t *q = NULL;
|
|
if(_alpm_splitdep(j->data, &dep)) {
|
|
continue;
|
|
}
|
|
/* look for dep.name -- if it's farther down in the list, then
|
|
* move it up above p
|
|
*/
|
|
for(k = i->next; k; k = k->next) {
|
|
q = (pmpkg_t *)k->data;
|
|
if(!strcmp(dep.name, q->name)) {
|
|
if(!_alpm_pkg_find(q->name, tmptargs)) {
|
|
change = 1;
|
|
tmptargs = alpm_list_add(tmptargs, q);
|
|
}
|
|
break;
|
|
}
|
|
for(l = q->provides; l; l = l->next) {
|
|
if(!strcmp(dep.name, (char*)l->data)) {
|
|
if(!_alpm_pkg_find((char*)l->data, tmptargs)) {
|
|
change = 1;
|
|
tmptargs = alpm_list_add(tmptargs, q);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(!_alpm_pkg_find(p->name, tmptargs)) {
|
|
tmptargs = alpm_list_add(tmptargs, p);
|
|
}
|
|
}
|
|
FREELISTPTR(newtargs);
|
|
newtargs = tmptargs;
|
|
}
|
|
_alpm_log(PM_LOG_DEBUG, _("sorting dependencies finished"));
|
|
|
|
if(mode == PM_TRANS_TYPE_REMOVE) {
|
|
/* we're removing packages, so reverse the order */
|
|
alpm_list_t *tmptargs = alpm_list_reverse(newtargs);
|
|
/* free the old one */
|
|
FREELISTPTR(newtargs);
|
|
newtargs = tmptargs;
|
|
}
|
|
|
|
return(newtargs);
|
|
}
|
|
|
|
/** Checks dependencies and returns missing ones in a list. Dependencies can include versions with depmod operators.
|
|
* @param trans pointer to the transaction object
|
|
* @param db pointer to the local package database
|
|
* @param op transaction type
|
|
* @param packages an alpm_list_t* of packages to be checked
|
|
* @return an alpm_list_t* of missing_t pointers.
|
|
*/
|
|
alpm_list_t *_alpm_checkdeps(pmtrans_t *trans, pmdb_t *db, pmtranstype_t op,
|
|
alpm_list_t *packages)
|
|
{
|
|
pmdepend_t depend;
|
|
alpm_list_t *i, *j, *k, *l;
|
|
int found = 0;
|
|
alpm_list_t *baddeps = NULL;
|
|
pmdepmissing_t *miss = NULL;
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
if(db == NULL) {
|
|
return(NULL);
|
|
}
|
|
|
|
if(op == PM_TRANS_TYPE_UPGRADE) {
|
|
/* PM_TRANS_TYPE_UPGRADE handles the backwards dependencies, ie, the packages
|
|
* listed in the requiredby field.
|
|
*/
|
|
for(i = packages; i; i = i->next) {
|
|
pmpkg_t *newpkg = i->data;
|
|
pmpkg_t *oldpkg;
|
|
if(newpkg == NULL) {
|
|
_alpm_log(PM_LOG_DEBUG, _("null package found in package list"));
|
|
continue;
|
|
}
|
|
|
|
if((oldpkg = _alpm_db_get_pkgfromcache(db, newpkg->name)) == NULL) {
|
|
_alpm_log(PM_LOG_DEBUG, _("cannot find package installed '%s'"), newpkg->name);
|
|
continue;
|
|
}
|
|
for(j = alpm_pkg_get_requiredby(oldpkg); j; j = j->next) {
|
|
pmpkg_t *p;
|
|
found = 0;
|
|
if((p = _alpm_db_get_pkgfromcache(db, j->data)) == NULL) {
|
|
/* hmmm... package isn't installed.. */
|
|
continue;
|
|
}
|
|
if(_alpm_pkg_find(p->name, packages)) {
|
|
/* this package also in the upgrade list, so don't worry about it */
|
|
continue;
|
|
}
|
|
for(k = alpm_pkg_get_depends(p); k; k = k->next) {
|
|
/* don't break any existing dependencies (possible provides) */
|
|
_alpm_splitdep(k->data, &depend);
|
|
|
|
/* if oldpkg satisfied this dep, and newpkg doesn't */
|
|
if(_alpm_depcmp(oldpkg, &depend) && !_alpm_depcmp(newpkg, &depend)) {
|
|
/* we've found a dep that was removed... see if any other package
|
|
* still contains/provides the dep */
|
|
int satisfied = 0;
|
|
for(l = packages; l; l = l->next) {
|
|
pmpkg_t *pkg = l->data;
|
|
|
|
if(_alpm_depcmp(pkg, &depend)) {
|
|
_alpm_log(PM_LOG_DEBUG, _("checkdeps: dependency '%s' has moved from '%s' to '%s'"),
|
|
depend.name, oldpkg->name, pkg->name);
|
|
satisfied = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!satisfied) {
|
|
/* worst case... check installed packages to see if anything else
|
|
* satisfies this... */
|
|
for(l = _alpm_db_get_pkgcache(db, INFRQ_DEPENDS); l; l = l->next) {
|
|
pmpkg_t *pkg = l->data;
|
|
|
|
if(strcmp(pkg->name, oldpkg->name) == 0) {
|
|
/* well, we know this one succeeds, but we're removing it... skip it */
|
|
continue;
|
|
}
|
|
|
|
if(_alpm_depcmp(pkg, &depend)) {
|
|
_alpm_log(PM_LOG_DEBUG, _("checkdeps: dependency '%s' satisfied by installed package '%s'"),
|
|
depend.name, pkg->name);
|
|
satisfied = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!satisfied) {
|
|
_alpm_log(PM_LOG_DEBUG, _("checkdeps: updated '%s' won't satisfy a dependency of '%s'"),
|
|
oldpkg->name, p->name);
|
|
miss = _alpm_depmiss_new(p->name, PM_DEP_TYPE_REQUIRED, depend.mod,
|
|
depend.name, depend.version);
|
|
if(!_alpm_depmiss_isin(miss, baddeps)) {
|
|
baddeps = alpm_list_add(baddeps, miss);
|
|
} else {
|
|
FREE(miss);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(op == PM_TRANS_TYPE_ADD || op == PM_TRANS_TYPE_UPGRADE) {
|
|
/* DEPENDENCIES -- look for unsatisfied dependencies */
|
|
for(i = packages; i; i = i->next) {
|
|
pmpkg_t *tp = i->data;
|
|
if(tp == NULL) {
|
|
_alpm_log(PM_LOG_DEBUG, _("null package found in package list"));
|
|
continue;
|
|
}
|
|
|
|
/* ensure package has depends data */
|
|
pmdb_t *pkgdb = tp->data;
|
|
_alpm_db_read(pkgdb, tp, INFRQ_DEPENDS);
|
|
if(!tp->depends) {
|
|
_alpm_log(PM_LOG_DEBUG, _("no dependencies for target '%s'"), tp->name);
|
|
}
|
|
|
|
for(j = tp->depends; j; j = j->next) {
|
|
/* split into name/version pairs */
|
|
_alpm_splitdep((char *)j->data, &depend);
|
|
found = 0;
|
|
/* check database for literal packages */
|
|
for(k = _alpm_db_get_pkgcache(db, INFRQ_DESC|INFRQ_DEPENDS);
|
|
k && !found; k = k->next) {
|
|
pmpkg_t *p = (pmpkg_t *)k->data;
|
|
found = _alpm_depcmp(p, &depend);
|
|
}
|
|
/* check database for provides matches */
|
|
if(!found) {
|
|
alpm_list_t *m;
|
|
k = _alpm_db_whatprovides(db, depend.name);
|
|
for(m = k; m && !found; m = m->next) {
|
|
/* look for a match that isn't one of the packages we're trying
|
|
* to install. this way, if we match against a to-be-installed
|
|
* package, we'll defer to the NEW one, not the one already
|
|
* installed. */
|
|
pmpkg_t *p = m->data;
|
|
alpm_list_t *n;
|
|
int skip = 0;
|
|
for(n = packages; n && !skip; n = n->next) {
|
|
pmpkg_t *ptp = n->data;
|
|
if(!strcmp(ptp->name, p->name)) {
|
|
skip = 1;
|
|
}
|
|
}
|
|
if(skip) {
|
|
continue;
|
|
}
|
|
|
|
found = _alpm_depcmp(p, &depend);
|
|
}
|
|
FREELISTPTR(k);
|
|
}
|
|
/* check other targets */
|
|
for(k = packages; k && !found; k = k->next) {
|
|
pmpkg_t *p = (pmpkg_t *)k->data;
|
|
found = _alpm_depcmp(p, &depend);
|
|
}
|
|
/* else if still not found... */
|
|
if(!found) {
|
|
_alpm_log(PM_LOG_DEBUG, _("missing dependency '%s' for package '%s'"),
|
|
depend.name, tp->name);
|
|
miss = _alpm_depmiss_new(tp->name, PM_DEP_TYPE_DEPEND, depend.mod,
|
|
depend.name, depend.version);
|
|
if(!_alpm_depmiss_isin(miss, baddeps)) {
|
|
baddeps = alpm_list_add(baddeps, miss);
|
|
} else {
|
|
FREE(miss);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if(op == PM_TRANS_TYPE_REMOVE) {
|
|
/* check requiredby fields */
|
|
for(i = packages; i; i = i->next) {
|
|
pmpkg_t *tp = i->data;
|
|
if(tp == NULL) {
|
|
continue;
|
|
}
|
|
|
|
found=0;
|
|
for(j = tp->requiredby; j; j = j->next) {
|
|
/* Search for 'reqname' in packages for removal */
|
|
char *reqname = j->data;
|
|
alpm_list_t *x = NULL;
|
|
for(x = packages; x; x = x->next) {
|
|
pmpkg_t *xp = x->data;
|
|
if(strcmp(reqname, xp->name) == 0) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if(!found) {
|
|
/* check if a package in trans->packages provides this package */
|
|
for(k=trans->packages; !found && k; k=k->next) {
|
|
pmpkg_t *spkg = NULL;
|
|
if(trans->type == PM_TRANS_TYPE_SYNC) {
|
|
pmsyncpkg_t *sync = k->data;
|
|
spkg = sync->pkg;
|
|
} else {
|
|
spkg = k->data;
|
|
}
|
|
if(spkg) {
|
|
if(alpm_list_find_str(spkg->provides, tp->name)) {
|
|
found = 1;
|
|
}
|
|
}
|
|
}
|
|
if(!found) {
|
|
_alpm_log(PM_LOG_DEBUG, _("checkdeps: found %s as required by %s"),
|
|
reqname, tp->name);
|
|
miss = _alpm_depmiss_new(tp->name, PM_DEP_TYPE_REQUIRED,
|
|
PM_DEP_MOD_ANY, j->data, NULL);
|
|
if(!_alpm_depmiss_isin(miss, baddeps)) {
|
|
baddeps = alpm_list_add(baddeps, miss);
|
|
} else {
|
|
FREE(miss);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(baddeps);
|
|
}
|
|
|
|
int _alpm_splitdep(char *depstr, pmdepend_t *depend)
|
|
{
|
|
char *str = NULL, *ptr = NULL;
|
|
|
|
if(depstr == NULL || depend == NULL) {
|
|
return(-1);
|
|
}
|
|
|
|
depend->mod = 0;
|
|
depend->name[0] = 0;
|
|
depend->version[0] = 0;
|
|
|
|
str = strdup(depstr);
|
|
|
|
if((ptr = strstr(str, ">="))) {
|
|
depend->mod = PM_DEP_MOD_GE;
|
|
} else if((ptr = strstr(str, "<="))) {
|
|
depend->mod = PM_DEP_MOD_LE;
|
|
} else if((ptr = strstr(str, "="))) {
|
|
depend->mod = PM_DEP_MOD_EQ;
|
|
} else {
|
|
/* no version specified - accept any */
|
|
depend->mod = PM_DEP_MOD_ANY;
|
|
STRNCPY(depend->name, str, PKG_NAME_LEN);
|
|
}
|
|
|
|
if(ptr == NULL) {
|
|
FREE(str);
|
|
return(0);
|
|
}
|
|
*ptr = '\0';
|
|
STRNCPY(depend->name, str, PKG_NAME_LEN);
|
|
ptr++;
|
|
if(depend->mod != PM_DEP_MOD_EQ) {
|
|
ptr++;
|
|
}
|
|
|
|
STRNCPY(depend->version, ptr, PKG_VERSION_LEN);
|
|
FREE(str);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* These parameters are messy. We check if this package, given a list of
|
|
* targets (and a db), is safe to remove. We do NOT remove it if it is in the
|
|
* target list */
|
|
static int can_remove_package(pmdb_t *db, pmpkg_t *pkg, alpm_list_t *targets)
|
|
{
|
|
alpm_list_t *i;
|
|
|
|
if(_alpm_pkg_find(pkg->name, targets)) {
|
|
return(0);
|
|
}
|
|
|
|
/* see if it was explicitly installed */
|
|
if(alpm_pkg_get_reason(pkg) == PM_PKG_REASON_EXPLICIT) {
|
|
_alpm_log(PM_LOG_DEBUG, _("excluding %s -- explicitly installed"), pkg->name);
|
|
return(0);
|
|
}
|
|
|
|
/* see if other packages need it */
|
|
for(i = alpm_pkg_get_requiredby(pkg); i; i = i->next) {
|
|
pmpkg_t *reqpkg = _alpm_db_get_pkgfromcache(db, i->data);
|
|
if(reqpkg && !_alpm_pkg_find(reqpkg->name, targets)) {
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
/* it's ok to remove */
|
|
return(1);
|
|
}
|
|
|
|
/* return a new alpm_list_t target list containing all packages in the original
|
|
* target list, as well as all their un-needed dependencies. By un-needed,
|
|
* I mean dependencies that are *only* required for packages in the target
|
|
* list, so they can be safely removed. This function is recursive.
|
|
*/
|
|
alpm_list_t *_alpm_removedeps(pmdb_t *db, alpm_list_t *targs)
|
|
{
|
|
alpm_list_t *i, *j, *k;
|
|
alpm_list_t *newtargs = targs;
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
if(db == NULL) {
|
|
return(newtargs);
|
|
}
|
|
|
|
for(i = targs; i; i = i->next) {
|
|
pmpkg_t *pkg = i->data;
|
|
for(j = alpm_pkg_get_depends(pkg); j; j = j->next) {
|
|
pmdepend_t depend;
|
|
pmpkg_t *dep;
|
|
if(_alpm_splitdep(j->data, &depend)) {
|
|
continue;
|
|
}
|
|
|
|
dep = _alpm_db_get_pkgfromcache(db, depend.name);
|
|
if(dep == NULL) {
|
|
/* package not found... look for a provision instead */
|
|
alpm_list_t *provides = _alpm_db_whatprovides(db, depend.name);
|
|
if(!provides) {
|
|
/* Not found, that's fine, carry on */
|
|
_alpm_log(PM_LOG_DEBUG, _("cannot find package \"%s\" or anything that provides it!"), depend.name);
|
|
continue;
|
|
}
|
|
for(k = provides; k; k = k->next) {
|
|
pmpkg_t *provpkg = k->data;
|
|
if(can_remove_package(db, provpkg, newtargs)) {
|
|
pmpkg_t *pkg = _alpm_pkg_new(provpkg->name, provpkg->version);
|
|
_alpm_db_read(db, pkg, INFRQ_ALL);
|
|
|
|
_alpm_log(PM_LOG_DEBUG, _("adding '%s' to the targets"), pkg->name);
|
|
|
|
/* add it to the target list */
|
|
newtargs = alpm_list_add(newtargs, pkg);
|
|
newtargs = _alpm_removedeps(db, newtargs);
|
|
}
|
|
}
|
|
FREELISTPTR(provides);
|
|
} else if(can_remove_package(db, dep, newtargs)) {
|
|
pmpkg_t *pkg = _alpm_pkg_new(dep->name, dep->version);
|
|
_alpm_db_read(db, pkg, INFRQ_ALL);
|
|
|
|
_alpm_log(PM_LOG_DEBUG, _("adding '%s' to the targets"), pkg->name);
|
|
|
|
/* add it to the target list */
|
|
newtargs = alpm_list_add(newtargs, pkg);
|
|
newtargs = _alpm_removedeps(db, newtargs);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(newtargs);
|
|
}
|
|
|
|
/* populates *list with packages that need to be installed to satisfy all
|
|
* dependencies (recursive) for syncpkg
|
|
*
|
|
* make sure *list and *trail are already initialized
|
|
*/
|
|
int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *syncpkg,
|
|
alpm_list_t *list, alpm_list_t *trail, pmtrans_t *trans,
|
|
alpm_list_t **data)
|
|
{
|
|
alpm_list_t *i, *j;
|
|
alpm_list_t *targ;
|
|
alpm_list_t *deps = NULL;
|
|
|
|
ALPM_LOG_FUNC;
|
|
|
|
if(local == NULL || dbs_sync == NULL || syncpkg == NULL) {
|
|
return(-1);
|
|
}
|
|
|
|
_alpm_log(PM_LOG_DEBUG, _("started resolving dependencies"));
|
|
targ = alpm_list_add(NULL, syncpkg);
|
|
deps = _alpm_checkdeps(trans, local, PM_TRANS_TYPE_ADD, targ);
|
|
FREELISTPTR(targ);
|
|
|
|
if(deps == NULL) {
|
|
return(0);
|
|
}
|
|
|
|
for(i = deps; i; i = i->next) {
|
|
int found = 0;
|
|
pmdepmissing_t *miss = i->data;
|
|
pmpkg_t *sync = NULL;
|
|
|
|
/* check if one of the packages in *list already provides this dependency */
|
|
for(j = list; j && !found; j = j->next) {
|
|
pmpkg_t *sp = (pmpkg_t *)j->data;
|
|
if(alpm_list_find_str(sp->provides, miss->depend.name)) {
|
|
_alpm_log(PM_LOG_DEBUG, _("%s provides dependency %s -- skipping"),
|
|
sp->name, miss->depend.name);
|
|
found = 1;
|
|
}
|
|
}
|
|
if(found) {
|
|
continue;
|
|
}
|
|
|
|
/* find the package in one of the repositories */
|
|
/* check literals */
|
|
for(j = dbs_sync; !sync && j; j = j->next) {
|
|
sync = _alpm_db_get_pkgfromcache(j->data, miss->depend.name);
|
|
_alpm_db_read(j->data, sync, INFRQ_DEPENDS);
|
|
}
|
|
/* check provides */
|
|
for(j = dbs_sync; !sync && j; j = j->next) {
|
|
alpm_list_t *provides;
|
|
provides = _alpm_db_whatprovides(j->data, miss->depend.name);
|
|
if(provides) {
|
|
sync = provides->data;
|
|
}
|
|
FREELISTPTR(provides);
|
|
}
|
|
if(sync == NULL) {
|
|
_alpm_log(PM_LOG_ERROR, _("cannot resolve dependencies for \"%s\" (\"%s\" is not in the package set)"),
|
|
miss->target, miss->depend.name);
|
|
if(data) {
|
|
if((miss = (pmdepmissing_t *)malloc(sizeof(pmdepmissing_t))) == NULL) {
|
|
_alpm_log(PM_LOG_ERROR, _("malloc failure: could not allocate %d bytes"), sizeof(pmdepmissing_t));
|
|
FREELIST(*data);
|
|
pm_errno = PM_ERR_MEMORY;
|
|
goto error;
|
|
}
|
|
*miss = *(pmdepmissing_t *)i->data;
|
|
*data = alpm_list_add(*data, miss);
|
|
}
|
|
pm_errno = PM_ERR_UNSATISFIED_DEPS;
|
|
goto error;
|
|
}
|
|
if(_alpm_pkg_find(sync->name, list)) {
|
|
/* this dep is already in the target list */
|
|
_alpm_log(PM_LOG_DEBUG, _("dependency %s is already in the target list -- skipping"),
|
|
sync->name);
|
|
continue;
|
|
}
|
|
|
|
if(!_alpm_pkg_find(sync->name, trail)) {
|
|
/* check pmo_ignorepkg and pmo_s_ignore to make sure we haven't pulled in
|
|
* something we're not supposed to.
|
|
*/
|
|
int usedep = 1;
|
|
if(alpm_list_find_str(handle->ignorepkg, sync->name)) {
|
|
pmpkg_t *dummypkg = _alpm_pkg_new(miss->target, NULL);
|
|
QUESTION(trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, dummypkg, sync, NULL, &usedep);
|
|
FREEPKG(dummypkg);
|
|
}
|
|
if(usedep) {
|
|
trail = alpm_list_add(trail, sync);
|
|
if(_alpm_resolvedeps(local, dbs_sync, sync, list, trail, trans, data)) {
|
|
goto error;
|
|
}
|
|
_alpm_log(PM_LOG_DEBUG, _("pulling dependency %s (needed by %s)"),
|
|
sync->name, syncpkg->name);
|
|
list = alpm_list_add(list, sync);
|
|
} else {
|
|
_alpm_log(PM_LOG_ERROR, _("cannot resolve dependencies for \"%s\""), miss->target);
|
|
if(data) {
|
|
if((miss = (pmdepmissing_t *)malloc(sizeof(pmdepmissing_t))) == NULL) {
|
|
_alpm_log(PM_LOG_ERROR, _("malloc failure: could not allocate %d bytes"), sizeof(pmdepmissing_t));
|
|
FREELIST(*data);
|
|
pm_errno = PM_ERR_MEMORY;
|
|
goto error;
|
|
}
|
|
*miss = *(pmdepmissing_t *)i->data;
|
|
*data = alpm_list_add(*data, miss);
|
|
}
|
|
pm_errno = PM_ERR_UNSATISFIED_DEPS;
|
|
goto error;
|
|
}
|
|
} else {
|
|
/* cycle detected -- skip it */
|
|
_alpm_log(PM_LOG_DEBUG, _("dependency cycle detected: %s"), sync->name);
|
|
}
|
|
}
|
|
|
|
_alpm_log(PM_LOG_DEBUG, _("finished resolving dependencies"));
|
|
|
|
FREELIST(deps);
|
|
|
|
return(0);
|
|
|
|
error:
|
|
FREELIST(deps);
|
|
return(-1);
|
|
}
|
|
|
|
const char SYMEXPORT *alpm_dep_get_target(pmdepmissing_t *miss)
|
|
{
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(handle != NULL, return(NULL));
|
|
ASSERT(miss != NULL, return(NULL));
|
|
|
|
return miss->target;
|
|
}
|
|
|
|
pmdeptype_t SYMEXPORT alpm_dep_get_type(pmdepmissing_t *miss)
|
|
{
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(handle != NULL, return(-1));
|
|
ASSERT(miss != NULL, return(-1));
|
|
|
|
return miss->type;
|
|
}
|
|
|
|
pmdepmod_t SYMEXPORT alpm_dep_get_mod(pmdepmissing_t *miss)
|
|
{
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(handle != NULL, return(-1));
|
|
ASSERT(miss != NULL, return(-1));
|
|
|
|
return miss->depend.mod;
|
|
}
|
|
|
|
const char SYMEXPORT *alpm_dep_get_name(pmdepmissing_t *miss)
|
|
{
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(handle != NULL, return(NULL));
|
|
ASSERT(miss != NULL, return(NULL));
|
|
|
|
return miss->depend.name;
|
|
}
|
|
|
|
const char SYMEXPORT *alpm_dep_get_version(pmdepmissing_t *miss)
|
|
{
|
|
ALPM_LOG_FUNC;
|
|
|
|
/* Sanity checks */
|
|
ASSERT(handle != NULL, return(NULL));
|
|
ASSERT(miss != NULL, return(NULL));
|
|
|
|
return miss->depend.version;
|
|
}
|
|
/* vim: set ts=2 sw=2 noet: */
|