mirror of
https://github.com/moparisthebest/pacman
synced 2024-12-22 15:58:50 -05:00
Implement simple topological sort algorithm for sortbydeps
Based on the "depth first search" algorithm, for more infos visit: http://en.wikipedia.org/wiki/Topological_sorting The previous algorithm used by sortbydeps was too slow, and to work around it the number of steps needed to get correct result was reduced greatly. So it produced wrong results in several cases : 1) smoke001.py 2) http://bugs.archlinux.org/task/7229 More here: http://archlinux.org/pipermail/pacman-dev/2007-April/008057.html Signed-off-by: Chantry Xavier <shiningxc@gmail.com> Signed-off-by: Dan McGee <dan@archlinux.org>
This commit is contained in:
parent
8588b4823b
commit
544bcbe664
@ -43,7 +43,7 @@ libalpm_la_SOURCES = \
|
||||
versioncmp.h versioncmp.c
|
||||
|
||||
libalpm_la_LDFLAGS = -no-undefined -version-info $(LIB_VERSION_INFO)
|
||||
libalpm_la_LIBADD = -larchive -ldownload -lm
|
||||
libalpm_la_LIBADD = -larchive -ldownload
|
||||
|
||||
if HAS_DOXYGEN
|
||||
all: doxygen.in
|
||||
|
@ -50,6 +50,7 @@ typedef struct __pmsyncpkg_t pmsyncpkg_t;
|
||||
typedef struct __pmdepend_t pmdepend_t;
|
||||
typedef struct __pmdepmissing_t pmdepmissing_t;
|
||||
typedef struct __pmconflict_t pmconflict_t;
|
||||
typedef struct __pmgraph_t pmgraph_t;
|
||||
|
||||
/*
|
||||
* Library
|
||||
|
@ -29,7 +29,6 @@
|
||||
#ifdef __sun__
|
||||
#include <strings.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
|
||||
/* libalpm */
|
||||
#include "deps.h"
|
||||
@ -46,6 +45,28 @@
|
||||
|
||||
extern pmhandle_t *handle;
|
||||
|
||||
static pmgraph_t *_alpm_graph_new(void)
|
||||
{
|
||||
pmgraph_t *graph = NULL;
|
||||
|
||||
graph = (pmgraph_t *)malloc(sizeof(pmgraph_t));
|
||||
if(graph) {
|
||||
graph->state = 0;
|
||||
graph->data = NULL;
|
||||
graph->parent = NULL;
|
||||
graph->children = NULL;
|
||||
graph->childptr = NULL;
|
||||
}
|
||||
return(graph);
|
||||
}
|
||||
|
||||
static void _alpm_graph_free(void *data)
|
||||
{
|
||||
pmgraph_t *graph = data;
|
||||
alpm_list_free(graph->children);
|
||||
free(graph);
|
||||
}
|
||||
|
||||
pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdeptype_t type,
|
||||
pmdepmod_t depmod, const char *depname,
|
||||
const char *depversion)
|
||||
@ -108,11 +129,10 @@ int _alpm_depmiss_isin(pmdepmissing_t *needle, alpm_list_t *haystack)
|
||||
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_list_t *i, *j, *k;
|
||||
alpm_list_t *vertices = NULL;
|
||||
alpm_list_t *vptr;
|
||||
pmgraph_t *vertex;
|
||||
|
||||
ALPM_LOG_FUNC;
|
||||
|
||||
@ -120,65 +140,69 @@ alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode)
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
_alpm_log(PM_LOG_DEBUG, _("started sorting dependencies"));
|
||||
|
||||
/* We create the vertices */
|
||||
for(i = targets; i; i = i->next) {
|
||||
newtargs = alpm_list_add(newtargs, i->data);
|
||||
numtargs++;
|
||||
pmgraph_t *vertex = _alpm_graph_new();
|
||||
vertex->data = (void *)i->data;
|
||||
vertices = alpm_list_add(vertices, vertex);
|
||||
}
|
||||
|
||||
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 = i->data;
|
||||
_alpm_log(PM_LOG_DEBUG, " sorting %s", alpm_pkg_get_name(p));
|
||||
for(j = alpm_pkg_get_depends(p); j; j = j->next) {
|
||||
pmdepend_t *depend = alpm_splitdep(j->data);
|
||||
pmpkg_t *q = NULL;
|
||||
if(depend == NULL) {
|
||||
continue;
|
||||
}
|
||||
/* look for depend->name -- if it's farther down in the list, then
|
||||
* move it up above p
|
||||
*/
|
||||
for(k = i->next; k; k = k->next) {
|
||||
q = k->data;
|
||||
const char *qname = alpm_pkg_get_name(q);
|
||||
if(!strcmp(depend->name, qname)) {
|
||||
if(!_alpm_pkg_find(qname, tmptargs)) {
|
||||
change = 1;
|
||||
tmptargs = alpm_list_add(tmptargs, q);
|
||||
}
|
||||
break;
|
||||
}
|
||||
for(l = alpm_pkg_get_provides(q); l; l = l->next) {
|
||||
const char *provname = l->data;
|
||||
if(!strcmp(depend->name, provname)) {
|
||||
if(!_alpm_pkg_find(qname, tmptargs)) {
|
||||
change = 1;
|
||||
tmptargs = alpm_list_add(tmptargs, q);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* 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;
|
||||
int child = 0;
|
||||
for(k = alpm_pkg_get_depends(p_i); k && !child; k = k->next) {
|
||||
pmdepend_t *depend = alpm_splitdep(k->data);
|
||||
child = alpm_depcmp(p_j, depend);
|
||||
free(depend);
|
||||
}
|
||||
if(!_alpm_pkg_find(alpm_pkg_get_name(p), tmptargs)) {
|
||||
tmptargs = alpm_list_add(tmptargs, p);
|
||||
if(child) vertex_i->children =
|
||||
alpm_list_add(vertex_i->children, vertex_j);
|
||||
}
|
||||
vertex_i->childptr = vertex_i->children;
|
||||
}
|
||||
|
||||
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) {
|
||||
_alpm_log(PM_LOG_WARNING, _("dependency cycle detected\n"));
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
alpm_list_free(newtargs);
|
||||
newtargs = tmptargs;
|
||||
}
|
||||
|
||||
_alpm_log(PM_LOG_DEBUG, _("sorting dependencies finished"));
|
||||
|
||||
if(mode == PM_TRANS_TYPE_REMOVE) {
|
||||
@ -189,6 +213,8 @@ alpm_list_t *_alpm_sortbydeps(alpm_list_t *targets, pmtranstype_t mode)
|
||||
newtargs = tmptargs;
|
||||
}
|
||||
|
||||
alpm_list_free_inner(vertices, _alpm_graph_free);
|
||||
|
||||
return(newtargs);
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,15 @@ struct __pmdepmissing_t {
|
||||
pmdepend_t depend;
|
||||
};
|
||||
|
||||
/* Graphs */
|
||||
struct __pmgraph_t {
|
||||
int state; /* 0: untouched, -1: entered, other: leaving time */
|
||||
void *data;
|
||||
struct __pmgraph_t *parent; /* where did we come from? */
|
||||
alpm_list_t *children;
|
||||
alpm_list_t *childptr; /* points to a child in children list */
|
||||
};
|
||||
|
||||
pmdepmissing_t *_alpm_depmiss_new(const char *target, pmdeptype_t type,
|
||||
pmdepmod_t depmod, const char *depname,
|
||||
const char *depversion);
|
||||
|
@ -26,11 +26,11 @@ pacman_SOURCES = \
|
||||
util.h util.c
|
||||
|
||||
pacman_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la \
|
||||
-ldownload
|
||||
-ldownload -lm
|
||||
|
||||
pacman_static_SOURCES = $(pacman_SOURCES)
|
||||
pacman_static_LDFLAGS = $(LDFLAGS) -all-static
|
||||
pacman_static_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la \
|
||||
-ldownload
|
||||
-ldownload -lm
|
||||
|
||||
# vim:set ts=2 sw=2 noet:
|
||||
|
Loading…
Reference in New Issue
Block a user