pacman/lib/libalpm/deps.c

807 lines
22 KiB
C
Raw Normal View History

2005-03-14 20:51:43 -05:00
/*
* deps.c
*
* Copyright (c) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org>
* 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>
*
2005-03-14 20:51:43 -05:00
* 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, see <http://www.gnu.org/licenses/>.
2005-03-14 20:51:43 -05:00
*/
#include "config.h"
2005-03-14 20:51:43 -05:00
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* libalpm */
#include "deps.h"
#include "alpm_list.h"
2005-03-14 20:51:43 -05:00
#include "util.h"
#include "log.h"
#include "graph.h"
2005-03-14 20:51:43 -05:00
#include "package.h"
#include "db.h"
#include "cache.h"
#include "handle.h"
void _alpm_dep_free(pmdepend_t *dep)
{
FREE(dep->name);
FREE(dep->version);
FREE(dep);
}
pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdepend_t *dep,
const char *causingpkg)
{
pmdepmissing_t *miss;
ALPM_LOG_FUNC;
MALLOC(miss, sizeof(pmdepmissing_t), RET_ERR(PM_ERR_MEMORY, NULL));
STRDUP(miss->target, target, RET_ERR(PM_ERR_MEMORY, NULL));
miss->depend = _alpm_dep_dup(dep);
STRDUP(miss->causingpkg, causingpkg, RET_ERR(PM_ERR_MEMORY, NULL));
return(miss);
}
void _alpm_depmiss_free(pmdepmissing_t *miss)
{
_alpm_dep_free(miss->depend);
FREE(miss->target);
FREE(miss->causingpkg);
FREE(miss);
}
/* Convert a list of pmpkg_t * to a graph structure,
* with a edge for each dependency.
* Returns a list of vertices (one vertex = one package)
* (used by alpm_sortbydeps)
*/
static alpm_list_t *dep_graph_init(alpm_list_t *targets)
{
alpm_list_t *i, *j;
alpm_list_t *vertices = NULL;
/* We create the vertices */
for(i = targets; i; i = i->next) {
pmgraph_t *vertex = _alpm_graph_new();
vertex->data = (void *)i->data;
vertices = alpm_list_add(vertices, vertex);
}
/* We compute the edges */
for(i = vertices; i; i = i->next) {
pmgraph_t *vertex_i = i->data;
pmpkg_t *p_i = vertex_i->data;
/* TODO this should be somehow combined with alpm_checkdeps */
for(j = vertices; j; j = j->next) {
pmgraph_t *vertex_j = j->data;
pmpkg_t *p_j = vertex_j->data;
if(_alpm_dep_edge(p_i, p_j)) {
vertex_i->children =
alpm_list_add(vertex_i->children, vertex_j);
}
}
vertex_i->childptr = vertex_i->children;
}
return(vertices);
}
2005-03-14 20:51:43 -05:00
/* Re-order a list of target packages with respect to their dependencies.
*
* Example (reverse == 0):
2005-03-14 20:51:43 -05:00
* A depends on C
* B depends on A
* Target order is A,B,C,D
*
* Should be re-ordered to C,A,B,D
*
* if reverse is > 0, the dependency order will be reversed.
*
* This function returns the new alpm_list_t* target list.
2005-03-14 20:51:43 -05:00
*
*/
alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, int reverse)
2005-03-14 20:51:43 -05:00
{
alpm_list_t *newtargs = NULL;
alpm_list_t *vertices = NULL;
alpm_list_t *vptr;
pmgraph_t *vertex;
2005-03-14 20:51:43 -05:00
ALPM_LOG_FUNC;
2005-03-14 20:51:43 -05:00
if(targets == NULL) {
return(NULL);
}
_alpm_log(PM_LOG_DEBUG, "started sorting dependencies\n");
vertices = dep_graph_init(targets);
vptr = vertices;
vertex = vertices->data;
while(vptr) {
/* mark that we touched the vertex */
vertex->state = -1;
int found = 0;
while(vertex->childptr && !found) {
pmgraph_t *nextchild = (vertex->childptr)->data;
vertex->childptr = (vertex->childptr)->next;
if (nextchild->state == 0) {
found = 1;
nextchild->parent = vertex;
vertex = nextchild;
}
else if(nextchild->state == -1) {
pmpkg_t *vertexpkg = vertex->data;
pmpkg_t *childpkg = nextchild->data;
_alpm_log(PM_LOG_WARNING, _("dependency cycle detected:\n"));
if(reverse) {
_alpm_log(PM_LOG_WARNING, _("%s will be removed after its %s dependency\n"), vertexpkg->name, childpkg->name);
} else {
_alpm_log(PM_LOG_WARNING, _("%s will be installed before its %s dependency\n"), vertexpkg->name, childpkg->name);
}
}
2005-03-14 20:51:43 -05:00
}
if(!found) {
newtargs = alpm_list_add(newtargs, vertex->data);
/* mark that we've left this vertex */
vertex->state = 1;
vertex = vertex->parent;
if(!vertex) {
vptr = vptr->next;
while(vptr) {
vertex = vptr->data;
if (vertex->state == 0) break;
vptr = vptr->next;
2005-03-14 20:51:43 -05:00
}
}
}
}
_alpm_log(PM_LOG_DEBUG, "sorting dependencies finished\n");
if(reverse) {
/* reverse the order */
alpm_list_t *tmptargs = alpm_list_reverse(newtargs);
/* free the old one */
alpm_list_free(newtargs);
newtargs = tmptargs;
}
alpm_list_free_inner(vertices, _alpm_graph_free);
alpm_list_free(vertices);
return(newtargs);
2005-03-14 20:51:43 -05:00
}
pmpkg_t *_alpm_find_dep_satisfier(alpm_list_t *pkgs, pmdepend_t *dep)
{
alpm_list_t *i;
for(i = pkgs; i; i = alpm_list_next(i)) {
pmpkg_t *pkg = i->data;
if(alpm_depcmp(pkg, dep)) {
return(pkg);
}
}
return(NULL);
}
/** Checks dependencies and returns missing ones in a list.
* Dependencies can include versions with depmod operators.
* @param db pointer to the local package database
* @param targets an alpm_list_t* of dependencies strings to satisfy
* @return an alpm_list_t* of missing dependencies strings
*/
alpm_list_t SYMEXPORT *alpm_deptest(pmdb_t *db, alpm_list_t *targets)
{
alpm_list_t *i, *ret = NULL;
for(i = targets; i; i = alpm_list_next(i)) {
pmdepend_t *dep;
char *target;
target = alpm_list_getdata(i);
dep = _alpm_splitdep(target);
if(!_alpm_find_dep_satisfier(_alpm_db_get_pkgcache(db), dep)) {
ret = alpm_list_add(ret, target);
}
_alpm_dep_free(dep);
}
return(ret);
}
/** Checks dependencies and returns missing ones in a list.
* Dependencies can include versions with depmod operators.
* @param pkglist the list of local packages
* @param reversedeps handles the backward dependencies
* @param remove an alpm_list_t* of packages to be removed
* @param upgrade an alpm_list_t* of packages to be upgraded (remove-then-upgrade)
* @return an alpm_list_t* of pmpkg_t* of missing_t pointers.
2005-03-14 20:51:43 -05:00
*/
alpm_list_t SYMEXPORT *alpm_checkdeps(alpm_list_t *pkglist, int reversedeps,
alpm_list_t *remove, alpm_list_t *upgrade)
2005-03-14 20:51:43 -05:00
{
alpm_list_t *i, *j;
alpm_list_t *targets, *dblist = NULL, *modified = NULL;
alpm_list_t *baddeps = NULL;
2005-03-14 20:51:43 -05:00
pmdepmissing_t *miss = NULL;
ALPM_LOG_FUNC;
targets = alpm_list_join(alpm_list_copy(remove), alpm_list_copy(upgrade));
for(i = pkglist; i; i = i->next) {
void *pkg = i->data;
if(alpm_list_find(targets, pkg, _alpm_pkg_cmp)) {
modified = alpm_list_add(modified, pkg);
} else {
dblist = alpm_list_add(dblist, pkg);
}
}
alpm_list_free(targets);
/* look for unsatisfied dependencies of the upgrade list */
for(i = upgrade; i; i = i->next) {
pmpkg_t *tp = i->data;
_alpm_log(PM_LOG_DEBUG, "checkdeps: package %s-%s\n",
alpm_pkg_get_name(tp), alpm_pkg_get_version(tp));
for(j = alpm_pkg_get_depends(tp); j; j = j->next) {
pmdepend_t *depend = j->data;
/* 1. we check the upgrade list */
/* 2. we check database for untouched satisfying packages */
if(!_alpm_find_dep_satisfier(upgrade, depend) &&
!_alpm_find_dep_satisfier(dblist, depend)) {
/* Unsatisfied dependency in the upgrade list */
char *missdepstring = alpm_dep_compute_string(depend);
_alpm_log(PM_LOG_DEBUG, "checkdeps: missing dependency '%s' for package '%s'\n",
missdepstring, alpm_pkg_get_name(tp));
free(missdepstring);
miss = _alpm_depmiss_new(alpm_pkg_get_name(tp), depend, NULL);
baddeps = alpm_list_add(baddeps, miss);
}
}
}
if(reversedeps) {
/* reversedeps handles the backwards dependencies, ie,
* the packages listed in the requiredby field. */
for(i = dblist; i; i = i->next) {
pmpkg_t *lp = i->data;
for(j = alpm_pkg_get_depends(lp); j; j = j->next) {
pmdepend_t *depend = j->data;
pmpkg_t *causingpkg = _alpm_find_dep_satisfier(modified, depend);
/* we won't break this depend, if it is already broken, we ignore it */
/* 1. check upgrade list for satisfiers */
/* 2. check dblist for satisfiers */
if(causingpkg &&
!_alpm_find_dep_satisfier(upgrade, depend) &&
!_alpm_find_dep_satisfier(dblist, depend)) {
char *missdepstring = alpm_dep_compute_string(depend);
_alpm_log(PM_LOG_DEBUG, "checkdeps: transaction would break '%s' dependency of '%s'\n",
missdepstring, alpm_pkg_get_name(lp));
free(missdepstring);
miss = _alpm_depmiss_new(lp->name, depend, alpm_pkg_get_name(causingpkg));
baddeps = alpm_list_add(baddeps, miss);
2005-03-14 20:51:43 -05:00
}
}
}
}
alpm_list_free(modified);
alpm_list_free(dblist);
2005-03-14 20:51:43 -05:00
return(baddeps);
}
static int dep_vercmp(const char *version1, pmdepmod_t mod,
const char *version2)
{
int equal = 0;
if(mod == PM_DEP_MOD_ANY) {
equal = 1;
} else {
int cmp = alpm_pkg_vercmp(version1, version2);
switch(mod) {
case PM_DEP_MOD_EQ: equal = (cmp == 0); break;
case PM_DEP_MOD_GE: equal = (cmp >= 0); break;
case PM_DEP_MOD_LE: equal = (cmp <= 0); break;
case PM_DEP_MOD_LT: equal = (cmp < 0); break;
case PM_DEP_MOD_GT: equal = (cmp > 0); break;
default: equal = 1; break;
}
}
return(equal);
}
int SYMEXPORT alpm_depcmp(pmpkg_t *pkg, pmdepend_t *dep)
{
alpm_list_t *i;
ALPM_LOG_FUNC;
const char *pkgname = alpm_pkg_get_name(pkg);
const char *pkgversion = alpm_pkg_get_version(pkg);
int satisfy = 0;
/* check (pkg->name, pkg->version) */
satisfy = (strcmp(pkgname, dep->name) == 0
&& dep_vercmp(pkgversion, dep->mod, dep->version));
/* check provisions, format : "name=version" */
for(i = alpm_pkg_get_provides(pkg); i && !satisfy; i = i->next) {
char *provname = strdup(i->data);
char *provver = strchr(provname, '=');
if(provver == NULL) { /* no provision version */
satisfy = (dep->mod == PM_DEP_MOD_ANY
&& strcmp(provname, dep->name) == 0);
} else {
*provver = '\0';
provver += 1;
satisfy = (strcmp(provname, dep->name) == 0
&& dep_vercmp(provver, dep->mod, dep->version));
}
free(provname);
}
return(satisfy);
}
pmdepend_t *_alpm_splitdep(const char *depstring)
2005-03-14 20:51:43 -05:00
{
pmdepend_t *depend;
char *ptr = NULL;
char *newstr = NULL;
2005-03-14 20:51:43 -05:00
if(depstring == NULL) {
return(NULL);
}
STRDUP(newstr, depstring, RET_ERR(PM_ERR_MEMORY, NULL));
CALLOC(depend, 1, sizeof(pmdepend_t), RET_ERR(PM_ERR_MEMORY, NULL));
2005-03-14 20:51:43 -05:00
/* Find a version comparator if one exists. If it does, set the type and
* increment the ptr accordingly so we can copy the right strings. */
if((ptr = strstr(newstr, ">="))) {
depend->mod = PM_DEP_MOD_GE;
*ptr = '\0';
ptr += 2;
} else if((ptr = strstr(newstr, "<="))) {
depend->mod = PM_DEP_MOD_LE;
*ptr = '\0';
ptr += 2;
} else if((ptr = strstr(newstr, "="))) { /* Note: we must do =,<,> checks after <=, >= checks */
depend->mod = PM_DEP_MOD_EQ;
*ptr = '\0';
ptr += 1;
} else if((ptr = strstr(newstr, "<"))) {
depend->mod = PM_DEP_MOD_LT;
*ptr = '\0';
ptr += 1;
} else if((ptr = strstr(newstr, ">"))) {
depend->mod = PM_DEP_MOD_GT;
*ptr = '\0';
ptr += 1;
2005-03-14 20:51:43 -05:00
} else {
/* no version specified - copy the name and return it */
depend->mod = PM_DEP_MOD_ANY;
STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL));
depend->version = NULL;
free(newstr);
return(depend);
2005-03-14 20:51:43 -05:00
}
/* if we get here, we have a version comparator, copy the right parts
* to the right places */
STRDUP(depend->name, newstr, RET_ERR(PM_ERR_MEMORY, NULL));
STRDUP(depend->version, ptr, RET_ERR(PM_ERR_MEMORY, NULL));
free(newstr);
2005-03-14 20:51:43 -05:00
return(depend);
2005-03-14 20:51:43 -05:00
}
pmdepend_t *_alpm_dep_dup(const pmdepend_t *dep)
{
pmdepend_t *newdep;
CALLOC(newdep, 1, sizeof(pmdepend_t), RET_ERR(PM_ERR_MEMORY, NULL));
STRDUP(newdep->name, dep->name, RET_ERR(PM_ERR_MEMORY, NULL));
STRDUP(newdep->version, dep->version, RET_ERR(PM_ERR_MEMORY, NULL));
newdep->mod = dep->mod;
return(newdep);
}
/* 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, or if if the package was explictly installed and
* include_explicit == 0 */
static int can_remove_package(pmdb_t *db, pmpkg_t *pkg, alpm_list_t *targets,
int include_explicit)
{
alpm_list_t *i;
if(_alpm_pkg_find(targets, alpm_pkg_get_name(pkg))) {
return(0);
}
if(!include_explicit) {
/* 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\n",
alpm_pkg_get_name(pkg));
return(0);
}
}
/* TODO: checkdeps could be used here, it handles multiple providers
* better, but that also makes it slower.
* Also this would require to first add the package to the targets list,
* then call checkdeps with it, then remove the package from the targets list
* if checkdeps detected it would break something */
/* see if other packages need it */
for(i = _alpm_db_get_pkgcache(db); i; i = i->next) {
pmpkg_t *lpkg = i->data;
if(_alpm_dep_edge(lpkg, pkg) && !_alpm_pkg_find(targets, lpkg->name)) {
return(0);
}
}
/* it's ok to remove */
return(1);
}
/**
* @brief Adds unneeded dependencies to an existing list of packages.
* By unneeded, we mean dependencies that are only required by packages in the
* target list, so they can be safely removed.
* If the input list was topo sorted, the output list will be topo sorted too.
*
* @param db package database to do dependency tracing in
* @param *targs pointer to a list of packages
* @param include_explicit if 0, explicitly installed packages are not included
2005-03-14 20:51:43 -05:00
*/
void _alpm_recursedeps(pmdb_t *db, alpm_list_t *targs, int include_explicit)
2005-03-14 20:51:43 -05:00
{
alpm_list_t *i, *j;
2005-03-14 20:51:43 -05:00
ALPM_LOG_FUNC;
if(db == NULL || targs == NULL) {
return;
2005-03-14 20:51:43 -05:00
}
for(i = targs; i; i = i->next) {
pmpkg_t *pkg = i->data;
for(j = _alpm_db_get_pkgcache(db); j; j = j->next) {
pmpkg_t *deppkg = j->data;
if(_alpm_dep_edge(pkg, deppkg)
&& can_remove_package(db, deppkg, targs, include_explicit)) {
_alpm_log(PM_LOG_DEBUG, "adding '%s' to the targets\n",
alpm_pkg_get_name(deppkg));
/* add it to the target list */
targs = alpm_list_add(targs, _alpm_pkg_dup(deppkg));
2005-03-14 20:51:43 -05:00
}
}
}
}
/**
* helper function for resolvedeps: search for dep satisfier in dbs
*
* @param dep is the dependency to search for
* @param dbs are the databases to search
* @param excluding are the packages to exclude from the search
* @param prompt if true, will cause an unresolvable dependency to issue an
* interactive prompt asking whether the package should be removed from
* the transaction or the transaction aborted; if false, simply returns
* an error code without prompting
* @return the resolved package
**/
pmpkg_t *_alpm_resolvedep(pmdepend_t *dep, alpm_list_t *dbs,
alpm_list_t *excluding, int prompt)
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
{
alpm_list_t *i, *j;
int ignored = 0;
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
/* 1. literals */
for(i = dbs; i; i = i->next) {
pmpkg_t *pkg = _alpm_db_get_pkgfromcache(i->data, dep->name);
if(pkg && alpm_depcmp(pkg, dep) && !_alpm_pkg_find(excluding, pkg->name)) {
if(_alpm_pkg_should_ignore(pkg)) {
int install = 0;
if (prompt) {
QUESTION(handle->trans, PM_TRANS_CONV_INSTALL_IGNOREPKG, pkg,
NULL, NULL, &install);
} else {
_alpm_log(PM_LOG_WARNING, _("ignoring package %s-%s\n"), pkg->name, pkg->version);
}
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
if(!install) {
ignored = 1;
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
continue;
}
}
return(pkg);
}
}
/* 2. satisfiers (skip literals here) */
for(i = dbs; i; i = i->next) {
for(j = _alpm_db_get_pkgcache(i->data); j; j = j->next) {
pmpkg_t *pkg = j->data;
if(alpm_depcmp(pkg, dep) && strcmp(pkg->name, dep->name) &&
!_alpm_pkg_find(excluding, pkg->name)) {
if(_alpm_pkg_should_ignore(pkg)) {
int install = 0;
if (prompt) {
QUESTION(handle->trans, PM_TRANS_CONV_INSTALL_IGNOREPKG,
pkg, NULL, NULL, &install);
} else {
_alpm_log(PM_LOG_WARNING, _("ignoring package %s-%s\n"), pkg->name, pkg->version);
}
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
if(!install) {
ignored = 1;
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
continue;
}
}
_alpm_log(PM_LOG_WARNING, _("provider package was selected (%s provides %s)\n"),
pkg->name, dep->name);
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
return(pkg);
}
}
}
if(ignored) { /* resolvedeps will override these */
pm_errno = PM_ERR_PKG_IGNORED;
} else {
pm_errno = PM_ERR_PKG_NOT_FOUND;
}
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
return(NULL);
}
/* Computes resolvable dependencies for a given package and adds that package
* and those resolvable dependencies to a list.
2005-03-14 20:51:43 -05:00
*
* @param local is the local database
* @param dbs_sync are the sync databases
* @param pkg is the package to resolve
* @param packages is a pointer to a list of packages which will be
* searched first for any dependency packages needed to complete the
* resolve, and to which will be added any [pkg] and all of its
* dependencies not already on the list
* @param remove is the set of packages which will be removed in this
* transaction
* @param data returns the dependency which could not be satisfied in the
* event of an error
* @return 0 on success, with [pkg] and all of its dependencies not already on
* the [*packages] list added to that list, or -1 on failure due to an
* unresolvable dependency, in which case the [*packages] list will be
* unmodified by this function
2005-03-14 20:51:43 -05:00
*/
int _alpm_resolvedeps(pmdb_t *local, alpm_list_t *dbs_sync, pmpkg_t *pkg,
alpm_list_t *preferred, alpm_list_t **packages,
alpm_list_t *remove, alpm_list_t **data)
2005-03-14 20:51:43 -05:00
{
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
alpm_list_t *i, *j;
alpm_list_t *targ;
alpm_list_t *deps = NULL;
alpm_list_t *packages_copy;
2005-03-14 20:51:43 -05:00
ALPM_LOG_FUNC;
Use sync.c for upgrade transaction prepare and commit This patch utilizes the power of sync.c to fix FS#3492 and FS#5798. Now an upgrade transaction is just a sync transaction internally (in alpm), so all sync features are available with -U as well: * conflict resolving * sync dependencies from sync repos * remove unresolvable targets See http://www.archlinux.org/pipermail/pacman-dev/2009-June/008725.html for the concept. We use "mixed" target list, where PKG_FROM_FILE origin indicates local package file, PKG_FROM_CACHE indicates sync package. The front-end can add only one type of packages (depending on transaction type) atm, but if alpm resolves dependencies for -U, we may get a real mixed trans->packages list. _alpm_pkg_free_trans() was modified so that it can handle both target types _alpm_add_prepare() was removed, we use _alpm_sync_prepare() instead _alpm_add_commit() was renamed to _alpm_upgrade_targets() sync.c (and deps.c) was modified slightly to handle mixed target lists, the modifications are straightforward. There is one notable change here: We don't create new upgrade trans in sync.c, we replace the pkgcache entries with the loaded package files in the target list (this is a bit hackish) and call _alpm_upgrade_targets(). This implies a TODO (pkg->origin_data.db is not accessible anymore), but it doesn't hurt anything with pacman front-end, so it will be fixed later (otherwise this patch would be huge). I updated the documentation of -U and I added a new pactest, upgrade090.py, to test the syncdeps feature of -U. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2009-06-09 11:23:46 -04:00
if(local == NULL) {
return(-1);
}
2005-03-30 17:32:43 -05:00
if(_alpm_pkg_find(*packages, pkg->name) != NULL) {
return(0);
}
/* Create a copy of the packages list, so that it can be restored
on error */
packages_copy = alpm_list_copy(*packages);
/* [pkg] has not already been resolved into the packages list, so put it
on that list */
*packages = alpm_list_add(*packages, pkg);
_alpm_log(PM_LOG_DEBUG, "started resolving dependencies\n");
for(i = alpm_list_last(*packages); i; i = i->next) {
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
pmpkg_t *tpkg = i->data;
targ = alpm_list_add(NULL, tpkg);
deps = alpm_checkdeps(_alpm_db_get_pkgcache(local), 0, remove, targ);
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
alpm_list_free(targ);
for(j = deps; j; j = j->next) {
pmdepmissing_t *miss = j->data;
pmdepend_t *missdep = alpm_miss_get_dep(miss);
/* check if one of the packages in the [*packages] list already satisfies this dependency */
if(_alpm_find_dep_satisfier(*packages, missdep)) {
continue;
}
/* check if one of the packages in the [preferred] list already satisfies this dependency */
pmpkg_t *spkg = _alpm_find_dep_satisfier(preferred, missdep);
if(!spkg) {
/* find a satisfier package in the given repositories */
spkg = _alpm_resolvedep(missdep, dbs_sync, *packages, 0);
}
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
if(!spkg) {
pm_errno = PM_ERR_UNSATISFIED_DEPS;
char *missdepstring = alpm_dep_compute_string(missdep);
_alpm_log(PM_LOG_WARNING, _("cannot resolve \"%s\", a dependency of \"%s\"\n"),
missdepstring, tpkg->name);
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
free(missdepstring);
if(data) {
pmdepmissing_t *missd = _alpm_depmiss_new(miss->target,
miss->depend, miss->causingpkg);
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
if(missd) {
*data = alpm_list_add(*data, missd);
}
}
alpm_list_free(*packages);
*packages = packages_copy;
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free);
alpm_list_free(deps);
return(-1);
} else {
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
_alpm_log(PM_LOG_DEBUG, "pulling dependency %s (needed by %s)\n",
alpm_pkg_get_name(spkg), alpm_pkg_get_name(tpkg));
*packages = alpm_list_add(*packages, spkg);
2005-03-14 20:51:43 -05:00
}
}
Resolvedeps rework I divided resolvedeps into 2 functions. The new _alpm_resolvedep function will resolve one dependency, for example the 'foo>=1.0-1' dependency. It can be useful in sync_addtarget refactoring. The resolvedeps parameters were changed, to be coherent with recursedeps: * the target-list is an alpm_list* instead of alpm_list**. This is OK, because alpm_list_add == alpm_list_add_last * syncpkg param was removed. list contains the to-be-installed packages, resolvedeps will add the required dependencies into this list * trans param was removed, it was used in QUESTION() only, which can be used on the main (handle->trans) transaction only (because the front-end cannot access our pseudo-transactions at all!). The patch fixes some wrong dynamic pmdepmissing_t usage. I did a behavior change (and sync1003.py was modified accordingly), which needs some explanation: The old resolvedeps didn't elect packages from 'remove' list. I've dropped this because I don't want that 2nd excluding list param. In fact, in real life, we ~never need this rule. Resolvedeps is called before checkconflicts, so only -Su's %REPLACES% packages are sitting in 'remove' list. This means, that we have the replacement packages in our target list. Usually "foo replaces bar" means, that bar isn't in our repos any more, so resolvedeps *cannot* elect it; but usually it won't try it at all, because foo is in the target list, and it is expected to satisfy 'bar>=1.0-1'-like dependencies too. Since checkdeps and checkconflicts is done after resolvedeps, this cannot cause any harm. Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu> Signed-off-by: Dan McGee <dan@archlinux.org>
2008-07-05 19:22:13 -04:00
alpm_list_free_inner(deps, (alpm_list_fn_free)_alpm_depmiss_free);
alpm_list_free(deps);
2005-03-14 20:51:43 -05:00
}
alpm_list_free(packages_copy);
_alpm_log(PM_LOG_DEBUG, "finished resolving dependencies\n");
2005-03-14 20:51:43 -05:00
return(0);
}
/* Does pkg1 depend on pkg2, ie. does pkg2 satisfy a dependency of pkg1? */
int _alpm_dep_edge(pmpkg_t *pkg1, pmpkg_t *pkg2)
{
alpm_list_t *i;
for(i = alpm_pkg_get_depends(pkg1); i; i = i->next) {
if(alpm_depcmp(pkg2, i->data)) {
return(1);
}
}
return(0);
}
const char SYMEXPORT *alpm_miss_get_target(const pmdepmissing_t *miss)
{
ALPM_LOG_FUNC;
/* Sanity checks */
ASSERT(miss != NULL, return(NULL));
return(miss->target);
}
const char SYMEXPORT *alpm_miss_get_causingpkg(const pmdepmissing_t *miss)
{
ALPM_LOG_FUNC;
/* Sanity checks */
ASSERT(miss != NULL, return(NULL));
return miss->causingpkg;
}
pmdepend_t SYMEXPORT *alpm_miss_get_dep(pmdepmissing_t *miss)
{
ALPM_LOG_FUNC;
/* Sanity checks */
ASSERT(miss != NULL, return(NULL));
return(miss->depend);
}
pmdepmod_t SYMEXPORT alpm_dep_get_mod(const pmdepend_t *dep)
{
ALPM_LOG_FUNC;
/* Sanity checks */
ASSERT(dep != NULL, return(-1));
return(dep->mod);
}
const char SYMEXPORT *alpm_dep_get_name(const pmdepend_t *dep)
{
ALPM_LOG_FUNC;
/* Sanity checks */
ASSERT(dep != NULL, return(NULL));
return(dep->name);
}
const char SYMEXPORT *alpm_dep_get_version(const pmdepend_t *dep)
{
ALPM_LOG_FUNC;
/* Sanity checks */
ASSERT(dep != NULL, return(NULL));
return(dep->version);
}
/** Reverse of splitdep; make a dep string from a pmdepend_t struct.
* The string must be freed!
* @param dep the depend to turn into a string
* @return a string-formatted dependency with operator if necessary
*/
char SYMEXPORT *alpm_dep_compute_string(const pmdepend_t *dep)
{
char *name, *opr, *ver, *str = NULL;
size_t len;
ALPM_LOG_FUNC;
/* Sanity checks */
ASSERT(dep != NULL, return(NULL));
if(dep->name) {
name = dep->name;
} else {
name = "";
}
switch(dep->mod) {
case PM_DEP_MOD_ANY:
opr = "";
break;
case PM_DEP_MOD_GE:
opr = ">=";
break;
case PM_DEP_MOD_LE:
opr = "<=";
break;
case PM_DEP_MOD_EQ:
opr = "=";
break;
case PM_DEP_MOD_LT:
opr = "<";
break;
case PM_DEP_MOD_GT:
opr = ">";
break;
default:
opr = "";
break;
}
if(dep->version) {
ver = dep->version;
} else {
ver = "";
}
/* we can always compute len and print the string like this because opr
* and ver will be empty when PM_DEP_MOD_ANY is the depend type. the
* reassignments above also ensure we do not do a strlen(NULL). */
len = strlen(name) + strlen(opr) + strlen(ver) + 1;
MALLOC(str, len, RET_ERR(PM_ERR_MEMORY, NULL));
snprintf(str, len, "%s%s%s", name, opr, ver);
return(str);
}
2005-03-14 20:51:43 -05:00
/* vim: set ts=2 sw=2 noet: */