Change back Bssolv.xs file with 0.28 version but with zstd support.
authorwang biao <biao716.wang@samsung.com>
Mon, 11 Jul 2022 03:26:20 +0000 (11:26 +0800)
committerbiao716.wang <biao716.wang@samsung.com>
Wed, 13 Jul 2022 06:00:31 +0000 (15:00 +0900)
Change-Id: I463b7465480defa819aa280ed9375469862cc66f
Signed-off-by: wang biao <biao716.wang@samsung.com>
BSSolv.xs

index ffd992c44595b0c6c27fce94c47eb4a6706a5913..e819aa9a2e4d8c7a3c43fef0fd163a6bca54866f 100644 (file)
--- a/BSSolv.xs
+++ b/BSSolv.xs
@@ -1,10 +1,3 @@
-/*
- * Copyright (c) 2009 - 2017 SUSE Linux Products GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the same terms as Perl itself.
- *
- */
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
 
 #define MULTI_SEMANTICS
 
-#include "solvversion.h"
-#if LIBSOLV_VERSION < 623
-#define LIBSOLVEXT_FEATURE_DEBIAN
-#define LIBSOLVEXT_FEATURE_ARCHREPO
-#endif
-
 #include "pool.h"
 #include "repo.h"
 #include "util.h"
 #include "evr.h"
 #include "hash.h"
 #include "chksum.h"
-#include "testcase.h"
 #include "repo_solv.h"
 #include "repo_write.h"
 #include "repo_rpmdb.h"
-#if defined(LIBSOLVEXT_FEATURE_DEBIAN)
 #include "repo_deb.h"
-#endif
-#if defined(LIBSOLVEXT_FEATURE_ARCHREPO)
+#if 1
 #include "repo_arch.h"
 #endif
-#if defined(LIBSOLV_FEATURE_COMPLEX_DEPS)
-#include "pool_parserpmrichdep.h"
-#endif
-
-#ifndef REL_ERROR
-# define REL_ERROR 27          /* for old libsolv versions */
-#endif
-#ifndef REL_UNLESS
-# define REL_UNLESS 29         /* for old libsolv versions */
-#endif
-
-#define EXPANDER_DEBUG_ALL             (1 << 0)
-#define EXPANDER_DEBUG_STDOUT          (1 << 1)
-#define EXPANDER_DEBUG_STR             (1 << 2)
-
-#define EXPANDER_OPTION_IGNOREIGNORE                   (1 << 0)
-#define EXPANDER_OPTION_IGNORECONFLICTS                        (1 << 1)
-#define EXPANDER_OPTION_DORECOMMENDS                   (1 << 2)
-#define EXPANDER_OPTION_DOSUPPLEMENTS                  (1 << 3)
-#define EXPANDER_OPTION_USERECOMMENDSFORCHOICES                (1 << 4)
-#define EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES       (1 << 5)
 
 typedef struct _Expander {
   Pool *pool;
@@ -75,54 +38,17 @@ typedef struct _Expander {
   Queue conflictsq;
   Map conflicts;
 
+  int debug;
   int havefileprovides;
+  int ignoreconflicts;
+  int ignoreignore;
 
-  /* debug support */
-  int debug;
   char *debugstr;
   int debugstrl;
   int debugstrf;
-
-  /* options */
-  int ignoreconflicts;
-  int ignoreignore;
   int userecommendsforchoices;
-  int usesupplementsforchoices;
-  int dorecommends;
-  int dosupplements;
 } Expander;
 
-typedef struct _ExpanderCtx {
-  Pool *pool;
-  Expander *xp;
-  Queue *out;                  /* the result */
-  Map installed;               /* installed packages */
-  Map conflicts;               /* conflicts from installed packages */
-  Queue conflictsinfo;         /* source info for the above */
-  int cidone;                  /* conflictsinfo done position */
-  Queue todo;                  /* requires todo list */
-  Queue errors;                        /* expansion errors */
-  Queue cplxq;                 /* complex dep work queue */
-  Queue cplxblks;              /* complex dep block data, add only */
-  Queue todo_cond;             /* delayed requires/conflicts */
-  Queue pruneq;                        /* multi purpose queue for pruning packages */
-  Map todo_condmap;            /* all neg packages in todo_cond blocks */
-  Map recommended;             /* recommended packages */
-  int recdone;                 /* recommended done position */
-
-  /* options */
-  int ignoreconflicts;
-  int ignoreignore;
-  int userecommendsforchoices;
-  int usesupplementsforchoices;
-  int dorecommends;
-  int dosupplements;
-
-  /* hacks */
-  Solvable *ignore_s;          /* small hack: ignore requires of this solvable */
-} ExpanderCtx;
-
-
 typedef Pool *BSSolv__pool;
 typedef Repo *BSSolv__repo;
 typedef Expander *BSSolv__expander;
@@ -131,14 +57,8 @@ static Id buildservice_id;
 static Id buildservice_repocookie;
 static Id buildservice_external;
 static Id buildservice_dodurl;
-static Id buildservice_dodcookie;
-static Id buildservice_dodresources;
-static Id buildservice_annotation;
-static Id buildservice_modules;
 static Id expander_directdepsend;
-
-static int genmetaalgo;
-static int depsortsccs;
+static Id buildservice_dodcookie;
 
 /* make sure bit n is usable */
 #define MAPEXP(m, n) ((m)->size < (((n) + 8) >> 3) ? map_grow(m, n + 256) : 0)
@@ -229,7 +149,7 @@ id2name(Pool *pool, Id id)
 }
 
 static Id
-dep2id_rec(Pool *pool, char *s)
+dep2id(Pool *pool, char *s)
 {
   char *n;
   Id id;
@@ -237,26 +157,17 @@ dep2id_rec(Pool *pool, char *s)
 
   if ((n = strchr(s, '|')) != 0)
     {
-      id = dep2id_rec(pool, n + 1);
+      id = dep2id(pool, n + 1);
       *n = 0;
-      id = pool_rel2id(pool, dep2id_rec(pool, s), id, REL_OR, 1);
+      id = pool_rel2id(pool, dep2id(pool, s), id, REL_OR, 1);
       *n = '|';
       return id;
     }
   while (*s == ' ' || *s == '\t')
     s++;
   n = s;
-  if (pool->disttype == DISTTYPE_RPM)
-    {
-      /* rpm delimits the name by whitespace only */
-      while (*s && *s != ' ' && *s != '\t')
-        s++;
-    }
-  else
-    {
-      while (*s && *s != ' ' && *s != '\t' && *s != '<' && *s != '=' && *s != '>')
-        s++;
-    }
+  while (*s && *s != ' ' && *s != '\t' && *s != '<' && *s != '=' && *s != '>')
+    s++;
 #ifdef REL_MULTIARCH
   if (s - n > 4 && s[-4] == ':' && !strncmp(s - 4, ":any", 4))
     {
@@ -274,13 +185,13 @@ dep2id_rec(Pool *pool, char *s)
   for (;;s++)
     {
       if (*s == '<')
-       flags |= REL_LT;
+       flags |= REL_LT;
       else if (*s == '=')
-       flags |= REL_EQ;
+       flags |= REL_EQ;
       else if (*s == '>')
-       flags |= REL_GT;
+       flags |= REL_GT;
       else
-       break;
+       break;
     }
   if (!flags)
     return id;
@@ -292,38 +203,11 @@ dep2id_rec(Pool *pool, char *s)
   return pool_rel2id(pool, id, pool_strn2id(pool, n, s - n, 1), flags, 1);
 }
 
-static Id
-parsedep_error(Pool *pool, const char *s)
-{
-  Id id;
-  id = pool_str2id(pool, s, 1);
-  return pool_rel2id(pool, pool_str2id(pool, "dependency parse error", 1), id, REL_ERROR, 1);
-}
-
-static Id
-dep2id(Pool *pool, char *s)
-{
-  Id id;
-  if (pool->disttype == DISTTYPE_RPM && *s == '(')
-    {
-#if defined(LIBSOLV_FEATURE_COMPLEX_DEPS)
-      id = pool_parserpmrichdep(pool, s);
-#else
-      id = 0;
-#endif
-    }
-  else
-    id = dep2id_rec(pool, s);
-  if (!id)
-    id = parsedep_error(pool, s);
-  return id;
-}
-
-static Offset
+static inline Offset
 importdeps(HV *hv, const char *key, int keyl, Repo *repo)
 {
   Pool *pool = repo->pool;
-  SSize_t i;
+  int i;
   AV *av = hvlookupav(hv, key, keyl);
   Offset off = 0;
   if (av)
@@ -332,18 +216,13 @@ importdeps(HV *hv, const char *key, int keyl, Repo *repo)
        {
          char *str = avlookupstr(av, i);
          if (str)
-           {
-             Id id = testcase_str2dep(pool, str);
-             if (!id)
-               id = parsedep_error(pool, str);
-             off = repo_addid_dep(repo, off, id, 0);
-           }
+           off = repo_addid_dep(repo, off, dep2id(pool, str), 0);
        }
     }
   return off;
 }
 
-static void
+void
 exportdeps(HV *hv, const char *key, int keyl, Repo *repo, Offset off, Id skey)
 {
   Pool *pool = repo->pool;
@@ -359,7 +238,64 @@ exportdeps(HV *hv, const char *key, int keyl, Repo *repo, Offset off, Id skey)
     {
       if (id == SOLVABLE_FILEMARKER)
        break;
-      str = testcase_dep2str(pool, id);
+      str = pool_dep2str(pool, id);
+      if (ISRELDEP(id))
+       {
+         Reldep *rd = GETRELDEP(pool, id);
+         if (skey == SOLVABLE_CONFLICTS && rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS)
+           {
+           if (!strncmp(str, "namespace:", 10))
+             str += 10;
+           }
+         if (skey == SOLVABLE_SUPPLEMENTS)
+           {
+             if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_FILESYSTEM)
+               {
+                 if (!strncmp(str, "namespace:", 10))
+                   str += 10;
+               }
+             else if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_MODALIAS)
+               {
+                 if (!strncmp(str, "namespace:", 10))
+                   str += 10;
+               }
+             else if (rd->flags == REL_AND)
+               {
+                 /* either packageand chain or modalias */
+                 str = 0;
+                 if (ISRELDEP(rd->evr))
+                   {
+                     Reldep *mrd = GETRELDEP(pool, rd->evr);
+                     if (mrd->flags == REL_NAMESPACE && mrd->name == NAMESPACE_MODALIAS)
+                       {
+                         str = pool_tmpjoin(pool, "modalias(", pool_dep2str(pool, rd->name), ":");
+                         str = pool_tmpappend(pool, str, pool_dep2str(pool, mrd->evr), ")");
+                       }
+                     else if (mrd->flags >= 8)
+                       continue;
+                   }
+                 if (!str)
+                   {
+                     /* must be and chain */
+                     str = pool_dep2str(pool, rd->evr);
+                     for (;;)
+                       {
+                         id = rd->name;
+                         if (!ISRELDEP(id))
+                           break;
+                         rd = GETRELDEP(pool, id);
+                         if (rd->flags != REL_AND)
+                           break;
+                         str = pool_tmpjoin(pool, pool_dep2str(pool, rd->evr), ":", str);
+                       }
+                     str = pool_tmpjoin(pool, pool_dep2str(pool, id), ":", str);
+                     str = pool_tmpjoin(pool, "packageand(", str, ")");
+                   }
+               }
+             else if (rd->flags >= 8)
+               continue;
+           }
+       }
       if (skey == SOLVABLE_REQUIRES)
        {
          if (id == SOLVABLE_PREREQMARKER)
@@ -375,179 +311,104 @@ exportdeps(HV *hv, const char *key, int keyl, Repo *repo, Offset off, Id skey)
     (void)hv_store(hv, key, keyl, newRV_noinc((SV*)av), 0);
 }
 
-static int
-data2pkg(Repo *repo, Repodata *data, HV *hv, int isdod)
+void
+data2solvables(Repo *repo, Repodata *data, HV *rhv)
 {
   Pool *pool = repo->pool;
-  char *str;
+  SV *sv;
+  HV *hv;
+  char *str, *key;
+  I32 keyl;
   Id p;
   Solvable *s;
-  AV *av;
 
-  str = hvlookupstr(hv, "name", 4);
-  if (!str)
-    return 0;  /* need to have a name */
-  p = repo_add_solvable(repo);
-  s = pool_id2solvable(pool, p);
-  s->name = pool_str2id(pool, str, 1);
-  str = hvlookupstr(hv, "arch", 4);
-  if (!str)
-    str = "";  /* dummy, need to have arch */
-  s->arch = pool_str2id(pool, str, 1);
-  s->evr = makeevr(pool, hvlookupstr(hv, "epoch", 5), hvlookupstr(hv, "version", 7), hvlookupstr(hv, "release", 7));
-  str = hvlookupstr(hv, "path", 4);
-  if (str)
+  hv_iterinit(rhv);
+  while ((sv = hv_iternextsv(rhv, &key, &keyl)) != 0)
     {
-      char *ss = strrchr(str, '/');
-      if (ss)
+      if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVHV)
+       continue;
+      hv = (HV *)SvRV(sv);
+      str = hvlookupstr(hv, "name", 4);
+      if (!str)
+       continue;       /* need to have a name */
+      p = repo_add_solvable(repo);
+      s = pool_id2solvable(pool, p);
+      s->name = pool_str2id(pool, str, 1);
+      str = hvlookupstr(hv, "arch", 4);
+      if (!str)
+       str = "";       /* dummy, need to have arch */
+      s->arch = pool_str2id(pool, str, 1);
+      s->evr = makeevr(pool, hvlookupstr(hv, "epoch", 5), hvlookupstr(hv, "version", 7), hvlookupstr(hv, "release", 7));
+      str = hvlookupstr(hv, "path", 4);
+      if (str)
        {
-         *ss = 0;
-         repodata_set_str(data, p, SOLVABLE_MEDIADIR, str);
-         *ss++ = '/';
+         char *ss = strrchr(str, '/');
+         if (ss)
+           {
+             *ss = 0;
+             repodata_set_str(data, p, SOLVABLE_MEDIADIR, str);
+             *ss++ = '/';
+           }
+         else
+           ss = str;
+         repodata_set_str(data, p, SOLVABLE_MEDIAFILE, ss);
        }
-      else
-       ss = str;
-      repodata_set_str(data, p, SOLVABLE_MEDIAFILE, ss);
-    }
-  if (isdod)
-    repodata_set_str(data, p, buildservice_id, "dod");
-  else
-    {
       str = hvlookupstr(hv, "id", 2);
       if (str)
        repodata_set_str(data, p, buildservice_id, str);
-    }
-  str = hvlookupstr(hv, "source", 6);
-  if (str)
-    repodata_set_poolstr(data, p, SOLVABLE_SOURCENAME, str);
-  if (isdod)
-    {
-      static unsigned char dod_pkgid[16] = { 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0 };
-      repodata_set_bin_checksum(data, p, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, dod_pkgid);
-    }
-  else
-    {
+      str = hvlookupstr(hv, "source", 6);
+      if (str)
+       repodata_set_poolstr(data, p, SOLVABLE_SOURCENAME, str);
       str = hvlookupstr(hv, "hdrmd5", 6);
       if (str && strlen(str) == 32)
        repodata_set_checksum(data, p, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, str);
-    }
-  s->provides    = importdeps(hv, "provides", 8, repo);
-  s->obsoletes   = importdeps(hv, "obsoletes", 9, repo);
-  s->conflicts   = importdeps(hv, "conflicts", 9, repo);
-  s->requires    = importdeps(hv, "requires", 8, repo);
-  s->recommends  = importdeps(hv, "recommends", 10, repo);
-  s->suggests    = importdeps(hv, "suggests", 8, repo);
-  s->supplements = importdeps(hv, "supplements", 11, repo);
-  s->enhances    = importdeps(hv, "enhances", 8, repo);
-  if (!s->evr && s->provides)
-    {
-      /* look for self provides */
-      Id pro, *prop = s->repo->idarraydata + s->provides;
-      while ((pro = *prop++) != 0)
-       {
-         Reldep *rd;
-         if (!ISRELDEP(pro))
-           continue;
-         rd = GETRELDEP(pool, pro);
-         if (rd->name == s->name && rd->flags == REL_EQ)
-           s->evr = rd->evr;
-       }
-    }
-  if (s->evr && s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
-    s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
-  str = hvlookupstr(hv, "checksum", 8);
-  if (str)
-    {
-      char *cp, typebuf[8];
-      Id ctype;
-      if (*str != ':' && (cp = strchr(str, ':')) != 0 && cp - str < sizeof(typebuf))
-       {
-         strncpy(typebuf, str, cp - str);
-         typebuf[cp - str] = 0;
-         ctype = solv_chksum_str2type(typebuf);
-         if (ctype)
-           repodata_set_checksum(data, p, SOLVABLE_CHECKSUM, ctype, cp + 1);
-       }
-    }
-  str = hvlookupstr(hv, "annotation", 10);
-  if (str && strlen(str) < 100000)
-    repodata_set_str(data, p, buildservice_annotation, str);
-  av = hvlookupav(hv, "modules", 7);
-  if (av)
-    {
-      SSize_t i;
-      for (i = 0; i <= av_len(av); i++)
-       {
-         char *str = avlookupstr(av, i);
-         repodata_add_idarray(data, p, buildservice_modules, pool_str2id(pool, str, 1));
-       }
-    }
-  return p;
-}
-
-static void
-data2solvables(Repo *repo, Repodata *data, SV *rsv, int isdod)
-{
-  AV *rav = 0;
-  SSize_t ravi = 0;
-  HV *rhv = 0;
-  SV *sv;
-  char *key;
-  I32 keyl;
-
-  if (SvTYPE(rsv) == SVt_PVAV)
-    rav = (AV *)rsv;
-  else
-    rhv = (HV *)rsv;
-
-  if (rhv)
-    hv_iterinit(rhv);
-  for (;;)
-    {
-      if (rhv)
-       {
-         sv = hv_iternextsv(rhv, &key, &keyl);
-         if (!sv)
-           break;
-       }
-      else
-       {
-         SV **svp;
-         if (ravi > av_len(rav))
-           break;
-         svp = av_fetch(rav, ravi++, 0);
-         if (!svp || !*svp)
-           continue;
-         sv = *svp;
+      s->provides    = importdeps(hv, "provides", 8, repo);
+      s->obsoletes   = importdeps(hv, "obsoletes", 9, repo);
+      s->conflicts   = importdeps(hv, "conflicts", 9, repo);
+      s->requires    = importdeps(hv, "requires", 8, repo);
+      s->recommends  = importdeps(hv, "recommends", 10, repo);
+      s->suggests    = importdeps(hv, "suggests", 8, repo);
+      s->supplements = importdeps(hv, "supplements", 11, repo);
+      s->enhances    = importdeps(hv, "enhances", 8, repo);
+      if (!s->evr && s->provides)
+       {
+         /* look for self provides */
+         Id pro, *prop = s->repo->idarraydata + s->provides;
+         while ((pro = *prop++) != 0)
+           {
+             Reldep *rd;
+             if (!ISRELDEP(pro))
+               continue;
+             rd = GETRELDEP(pool, pro);
+             if (rd->name == s->name && rd->flags == REL_EQ)
+               s->evr = rd->evr;
+           }
        }
-      if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVHV)
-       continue;
-      data2pkg(repo, data, (HV *)SvRV(sv), isdod);
-    }
-
-  /* set meta information */
-  repodata_set_str(data, SOLVID_META, buildservice_repocookie, REPOCOOKIE);
-  if (rhv)
-    {
-      char *str;
-      AV *av;
-      str = hvlookupstr(rhv, "/url", 4);
+      if (s->evr)
+       s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+      str = hvlookupstr(hv, "checksum", 8);
       if (str)
-       repodata_set_str(data, SOLVID_META, buildservice_dodurl, str);
-      str = hvlookupstr(rhv, "/dodcookie", 10);
-      if (str)
-       repodata_set_str(data, SOLVID_META, buildservice_dodcookie, str);
-      av = hvlookupav(rhv, "/dodresources", 13);
-      if (av)
        {
-         SSize_t i;
-         for (i = 0; i <= av_len(av); i++)
+         char *cp, typebuf[8];
+         Id ctype;
+         if (*str != ':' && (cp = strchr(str, ':')) != 0 && cp - str < sizeof(typebuf))
            {
-             Id id = pool_str2id(repo->pool, avlookupstr(av, i), 1);
-             repodata_add_idarray(data, SOLVID_META, buildservice_dodresources, id);
+             strncpy(typebuf, str, cp - str);
+             typebuf[cp - str] = 0;
+             ctype = solv_chksum_str2type(typebuf);
+             if (ctype)
+               repodata_set_checksum(data, p, SOLVABLE_CHECKSUM, ctype, cp + 1);
            }
        }
     }
+
+  repodata_set_str(data, SOLVID_META, buildservice_repocookie, REPOCOOKIE);
+  str = hvlookupstr(rhv, "/url", 4);
+  if (str)
+    repodata_set_str(data, SOLVID_META, buildservice_dodurl, str);
+  str = hvlookupstr(rhv, "/dodcookie", 10);
+  if (str)
+    repodata_set_str(data, SOLVID_META, buildservice_dodcookie, str);
 }
 
 static SV *
@@ -663,858 +524,113 @@ retrieve(unsigned char **srcp, STRLEN *srclp, int depth)
   return sv;
 }
 
-#define CPLXDEPS_TODNF (1 << 0)
-
-static int
-invert_depblocks(ExpanderCtx *xpctx, Queue *bq, int start, int r)
+static void
+expander_dbg(Expander *xp, const char *format, ...)
 {
-  int i, j, end;
-  if (r == 0 || r == 1)
-    return r ? 0 : 1;
-  end = bq->count;
-  for (i = j = start; i < end; i++)
+  va_list args;
+  char buf[1024];
+  int l;
+  if (!xp->debug)
+    return;
+  va_start(args, format);
+  vsnprintf(buf, sizeof(buf), format, args);
+  va_end(args);
+  printf("%s", buf);
+  l = strlen(buf);
+  if (buf[0] != ' ' || (l && buf[l - 1] == '\n'))
+    fflush(stdout);
+  if (l >= xp->debugstrf)      /* >= because of trailing \0 */
     {
-      if (bq->elements[i])
-        {
-          bq->elements[i] = -bq->elements[i];
-          continue;
-        }
-      /* end of block reached, reverse */
-      if (i - 1 > j)
-        {
-          int k;
-          for (k = i - 1; j < k; j++, k--)
-            {
-              Id t = bq->elements[j];
-              bq->elements[j] = bq->elements[k];
-              bq->elements[k] = t;
-            }
-        }
-      j = i + 1;
+      xp->debugstr = solv_realloc(xp->debugstr, xp->debugstrl + l + 1024);
+      xp->debugstrf = l + 1024;
     }
-  return -1;
+  strcpy(xp->debugstr + xp->debugstrl, buf);
+  xp->debugstrl += l;
+  xp->debugstrf -= l;
 }
 
-static int
-distribute_depblocks(ExpanderCtx *xpctx, Queue *bq, int start, int start2, int flags)
+static const char *
+expander_solvid2name(Expander *xp, Id p)
+{
+  const char *n = pool_id2str(xp->pool, xp->pool->solvables[p].name);
+  Repo *r; 
+  if (!xp->debug)
+    return n;
+  r = xp->pool->solvables[p].repo;
+  if (!r) 
+    return n;
+  return pool_tmpjoin(xp->pool, n, "@", r->name);
+}
+
+static inline void
+expander_installed(Expander *xp, Id p, Map *installed, Map *conflicts, Queue *conflictsinfo, int *cidone, Queue *out, Queue *todo)
 {
-  int i, j, end2 = bq->count;
-  for (i = start; i < start2; i++)
+  Pool *pool = xp->pool;
+  Solvable *s = pool->solvables + p;
+  Id req, id, *reqp, con, *conp;
+  const char *n;
+
+  MAPSET(installed, p);
+  queue_push(out, p);
+  if (MAPTST(&xp->conflicts, s->name))
     {
-      for (j = start2; j < end2; j++)
+      int i;
+      for (i = 0; i < xp->conflictsq.count; i++)
        {
-         int a, b;
-         int bqcnt4 = bq->count;
-         int k = i;
-
-         /* distribute i block with j block, both blocks are sorted */
-         while (bq->elements[k] && bq->elements[j])
+         Id p2, pp2;
+         Id id = xp->conflictsq.elements[i];
+         if (id != s->name)
+           continue;
+         id = xp->conflictsq.elements[i ^ 1];
+         FOR_PROVIDES(p2, pp2, id)
            {
-             if (bq->elements[k] < bq->elements[j])
-               queue_push(bq, bq->elements[k++]);
-             else
+             if (pool->solvables[p2].name == id)
                {
-                 if (bq->elements[k] == bq->elements[j])
-                   k++;
-                 queue_push(bq, bq->elements[j++]);
+                 MAPEXP(conflicts, pool->nsolvables);
+                 MAPSET(conflicts, p2);
                }
            }
-         while (bq->elements[j])
-           queue_push(bq, bq->elements[j++]);
-         while (bq->elements[k])
-           queue_push(bq, bq->elements[k++]);
-
-         /* block is finished, check for A + -A */
-         for (a = bqcnt4, b = bq->count - 1; a < b; )
-           {
-             if (-bq->elements[a] == bq->elements[b])
-               break;
-             if (-bq->elements[a] > bq->elements[b])
-               a++;
-             else
-               b--;
-           }
-         if (a < b)
-           queue_truncate(bq, bqcnt4);     /* ignore this block */
-         else
-           queue_push(bq, 0);      /* finish block */
        }
-      /* advance to next block */
-      while (bq->elements[i])
-       i++;
-    }
-  queue_deleten(bq, start, end2 - start);
-  if (start == bq->count)
-    return flags & CPLXDEPS_TODNF ? 0 : 1;
-  return -1;
-}
-
-#if 0
-static void
-print_depblocks(ExpanderCtx *xpctx, Queue *bq, int start, int r)
-{
-  Pool *pool = xpctx->pool;
-  int i;
-
-  if (r == 0)
-    {
-      printf("[NONE]\n");
-      return;
     }
-  if (r == 1)
+  if (s->requires)
     {
-      printf("[ALL]\n");
-      return;
+      reqp = s->repo->idarraydata + s->requires;
+      while ((req = *reqp++) != 0)
+       {
+         if (req == SOLVABLE_PREREQMARKER)
+           continue;
+         id = id2name(pool, req);
+         if (!xp->ignoreignore)
+           {
+             if (MAPTST(&xp->ignored, id))
+               continue;
+             if (MAPTST(&xp->ignoredx, id))
+               {
+                 Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, s->name), ":", pool_id2str(pool, id)), 0);
+                 if (xid && MAPTST(&xp->ignored, xid))
+                   continue;
+               }
+           }
+         n = pool_id2str(pool, id);
+         if (!strncmp(n, "rpmlib(", 7))
+           {
+             MAPEXP(&xp->ignored, id);
+             MAPSET(&xp->ignored, id);
+             continue;
+           }
+         if (*n == '/')
+           {
+             if (!xp->havefileprovides || pool->whatprovides[id] <= 1)
+               {
+                 MAPEXP(&xp->ignored, id);
+                 MAPSET(&xp->ignored, id);
+                 continue;
+               }
+           }
+         queue_push2(todo, req, p);
+       }
     }
-  for (i = start; i < bq->count; i++)
-    {
-      if (bq->elements[i] > 0)
-        printf(" %s", pool_solvid2str(pool, bq->elements[i]));
-      else if (bq->elements[i] < 0)
-        printf(" -%s", pool_solvid2str(pool, -bq->elements[i]));
-      else
-        printf(" ||");
-    }
-  printf("\n");
-}
-#endif
-
-
-static int
-pool_is_complex_dep_rd(Pool *pool, Reldep *rd)
-{
-  for (;;)
-    {
-      if (rd->flags == REL_AND || rd->flags == REL_COND || rd->flags == REL_UNLESS)        /* those are the complex ones */
-        return 1;
-      if (rd->flags != REL_OR)
-        return 0;
-      if (ISRELDEP(rd->name) && pool_is_complex_dep_rd(pool, GETRELDEP(pool, rd->name)))
-        return 1;
-      if (!ISRELDEP(rd->evr))
-        return 0;
-      rd = GETRELDEP(pool, rd->evr);
-    }
-}
-
-static inline int
-pool_is_complex_dep(Pool *pool, Id dep)
-{
-  if (ISRELDEP(dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags >= 8 && pool_is_complex_dep_rd(pool, rd))
-        return 1;
-    }
-  return 0;
-}
-
-static int normalize_dep(ExpanderCtx *xpctx, Id dep, Queue *bq, int flags);
-
-static int
-normalize_dep_or(ExpanderCtx *xpctx, Id dep1, Id dep2, Queue *bq, int flags, int invflags)
-{
-  int r1, r2, bqcnt2, bqcnt = bq->count;
-  r1 = normalize_dep(xpctx, dep1, bq, flags);
-  if (r1 == 1)
-    return 1;          /* early exit */
-  bqcnt2 = bq->count;
-  r2 = normalize_dep(xpctx, dep2, bq, flags ^ invflags);
-  if (invflags)
-    r2 = invert_depblocks(xpctx, bq, bqcnt2, r2);
-  if (r1 == 1 || r2 == 1)
-    {
-      queue_truncate(bq, bqcnt);
-      return 1;
-    }
-  if (r1 == 0)
-    return r2;
-  if (r2 == 0)
-    return r1;
-  if ((flags & CPLXDEPS_TODNF) == 0)
-    return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags);
-  return -1;
-}
-
-static int
-normalize_dep_and(ExpanderCtx *xpctx, Id dep1, Id dep2, Queue *bq, int flags, int invflags)
-{
-  int r1, r2, bqcnt2, bqcnt = bq->count;
-  r1 = normalize_dep(xpctx, dep1, bq, flags);
-  if (r1 == 0)
-    return 0;          /* early exit */
-  bqcnt2 = bq->count;
-  r2 = normalize_dep(xpctx, dep2, bq, flags ^ invflags);
-  if (invflags)
-    r2 = invert_depblocks(xpctx, bq, bqcnt2, r2);
-  if (r1 == 0 || r2 == 0)
-    {
-      queue_truncate(bq, bqcnt);
-      return 0;
-    }
-  if (r1 == 1)
-    return r2;
-  if (r2 == 1)
-    return r1;
-  if ((flags & CPLXDEPS_TODNF) != 0)
-    return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags);
-  return -1;
-}
-
-static int
-normalize_dep_if_else(ExpanderCtx *xpctx, Id dep1, Id dep2, Id dep3, Queue *bq, int flags)
-{
-  /* A IF (B ELSE C) -> (A OR ~B) AND (C OR B) */
-  int r1, r2, bqcnt2, bqcnt = bq->count;
-  r1 = normalize_dep_or(xpctx, dep1, dep2, bq, flags, CPLXDEPS_TODNF);
-  if (r1 == 0)
-    return 0;          /* early exit */
-  bqcnt2 = bq->count;
-  r2 = normalize_dep_or(xpctx, dep2, dep3, bq, flags, 0);
-  if (r1 == 0 || r2 == 0)
-    {
-      queue_truncate(bq, bqcnt);
-      return 0;
-    }
-  if (r1 == 1)
-    return r2;
-  if (r2 == 1)
-    return r1;
-  if ((flags & CPLXDEPS_TODNF) != 0)
-    return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags);
-  return -1;
-}
-
-static int
-normalize_dep_unless_else(ExpanderCtx *xpctx, Id dep1, Id dep2, Id dep3, Queue *bq, int flags)
-{
-  /* A UNLESS (B ELSE C) -> (A AND ~B) OR (C AND B) */
-  int r1, r2, bqcnt2, bqcnt = bq->count;
-  r1 = normalize_dep_and(xpctx, dep1, dep2, bq, flags, CPLXDEPS_TODNF);
-  if (r1 == 1)
-    return 1;          /* early exit */
-  bqcnt2 = bq->count;
-  r2 = normalize_dep_and(xpctx, dep2, dep3, bq, flags, 0);
-  if (r1 == 1 || r2 == 1)
-    {
-      queue_truncate(bq, bqcnt);
-      return 1;
-    }
-  if (r1 == 0)
-    return r2;
-  if (r2 == 0)
-    return r1;
-  if ((flags & CPLXDEPS_TODNF) == 0)
-    return distribute_depblocks(xpctx, bq, bqcnt, bqcnt2, flags);
-  return -1;
-}
-
-static int expander_isignored(Expander *xp, Solvable *s, Id req);
-
-static int
-normalize_dep(ExpanderCtx *xpctx, Id dep, Queue *bq, int flags)
-{
-  Pool *pool = xpctx->pool;
-  Id p, dp;
-  
-  if (pool_is_complex_dep(pool, dep))
-    {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags == REL_COND)
-       {
-         Id evr = rd->evr;
-         if (ISRELDEP(evr))
-           {
-             Reldep *rd2 = GETRELDEP(pool, evr);
-             if (rd2->flags == REL_ELSE)
-               return normalize_dep_if_else(xpctx, rd->name, rd2->name, rd2->evr, bq, flags);
-           }
-         return normalize_dep_or(xpctx, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF);
-       }
-      if (rd->flags == REL_UNLESS)
-       {
-         Id evr = rd->evr;
-         if (ISRELDEP(evr))
-           {
-             Reldep *rd2 = GETRELDEP(pool, evr);
-             if (rd2->flags == REL_ELSE)
-               return normalize_dep_unless_else(xpctx, rd->name, rd2->name, rd2->evr, bq, flags);
-           }
-         return normalize_dep_and(xpctx, rd->name, rd->evr, bq, flags, CPLXDEPS_TODNF);
-       }
-      if (rd->flags == REL_OR)
-       return normalize_dep_or(xpctx, rd->name, rd->evr, bq, flags, 0);
-      if (rd->flags == REL_AND)
-       return normalize_dep_and(xpctx, rd->name, rd->evr, bq, flags, 0);
-    }
-
-  if (xpctx->ignore_s && (flags & CPLXDEPS_TODNF) == 0)
-    {
-      if (expander_isignored(xpctx->xp, xpctx->ignore_s, dep))
-       return 1;
-    }
-
-  dp = pool_whatprovides(pool, dep);
-  if (dp == 2)
-    return 1;
-  if (dp < 2 || !pool->whatprovidesdata[dp])
-    return 0;
-  if (pool->whatprovidesdata[dp] == SYSTEMSOLVABLE)
-    return 1;
-  if ((flags & CPLXDEPS_TODNF) != 0)
-    {
-      while ((p = pool->whatprovidesdata[dp++]) != 0)
-        queue_push2(bq, p, 0);
-    }
-  else
-    {
-      while ((p = pool->whatprovidesdata[dp++]) != 0)
-        queue_push(bq, p);
-      queue_push(bq, 0);
-    }
-  return -1;
-}
-
-#define ISCPLX(pool, d) (ISRELDEP(d) && GETRELID(d) >= pool->nrels)
-#define GETCPLX(pool, d) (GETRELID(d) - pool->nrels)
-#define MAKECPLX(pool, d) (MAKERELDEP(pool->nrels + d))
-
-#define DEPTYPE_REQUIRES               0
-#define DEPTYPE_CONFLICTS              1
-#define DEPTYPE_OBSOLETES              2
-#define DEPTYPE_RECOMMENDS             3
-#define DEPTYPE_PROVIDES               4
-
-#define ERROR_NOPROVIDER               1
-#define ERROR_CHOICE                   2
-#define ERROR_CONFLICTINGPROVIDERS     3
-#define ERROR_PROVIDERINFO             4
-#define ERROR_PROVIDERINFO2            5
-#define ERROR_BADDEPENDENCY            6
-#define ERROR_CONFLICT                 7
-#define ERROR_CONFLICT2                        8
-#define ERROR_ALLCONFLICT              9
-#define ERROR_NOPROVIDERINFO           10
-
-static void
-expander_dbg(Expander *xp, const char *format, ...)
-{
-  va_list args;
-  char buf[1024];
-  int l;
-
-  if (!xp->debug)
-    return;
-  va_start(args, format);
-  vsnprintf(buf, sizeof(buf), format, args);
-  va_end(args);
-  l = strlen(buf);
-  if ((xp->debug & (EXPANDER_DEBUG_ALL | EXPANDER_DEBUG_STDOUT)) != 0)
-    {
-      printf("%s", buf);
-      if (buf[0] != ' ' || (l && buf[l - 1] == '\n'))
-        fflush(stdout);
-    }
-  if ((xp->debug & (EXPANDER_DEBUG_ALL | EXPANDER_DEBUG_STR)) != 0)
-    {
-      if (l >= xp->debugstrf)  /* >= because of trailing \0 */
-       {
-         xp->debugstr = solv_realloc(xp->debugstr, xp->debugstrl + l + 1024);
-         xp->debugstrf = l + 1024;
-       }
-      strcpy(xp->debugstr + xp->debugstrl, buf);
-      xp->debugstrl += l;
-      xp->debugstrf -= l;
-    }
-}
-
-static void
-expander_clrdbg(Expander *xp)
-{
-  if (xp->debugstr)
-    free(xp->debugstr);
-  xp->debugstr = 0;
-  xp->debugstrl = xp->debugstrf = 0;
-}
-
-static const char *
-expander_solvid2name(Expander *xp, Id p)
-{
-  const char *n = pool_id2str(xp->pool, xp->pool->solvables[p].name);
-  Repo *r; 
-  if (!xp->debug)
-    return n;
-  r = xp->pool->solvables[p].repo;
-  if (!r) 
-    return n;
-  return pool_tmpjoin(xp->pool, n, "@", r->name);
-}
-
-static const char *
-expander_solvid2str(Expander *xp, Id p)
-{
-  const char *n = pool_solvid2str(xp->pool, p);
-  Repo *r; 
-  if (!xp->debug)
-    return n;
-  r = xp->pool->solvables[p].repo;
-  if (!r) 
-    return n;
-  return pool_tmpjoin(xp->pool, n, "@", r->name);
-}
-
-static int
-pkgname_sort_cmp(const void *ap, const void *bp, void *dp)
-{
-  Pool *pool = (Pool *)dp;
-  Id a = *(Id *)ap;
-  Id b = *(Id *)bp;
-  return strcmp(pool_id2str(pool, pool->solvables[a].name), pool_id2str(pool, pool->solvables[b].name));
-}
-
-static int
-expander_isignored(Expander *xp, Solvable *s, Id req)
-{
-  Pool *pool = xp->pool;
-  Id id = id2name(pool, req);
-  const char *n;
-
-  if (!xp->ignoreignore)
-    {
-      if (MAPTST(&xp->ignored, id))
-       return 1;
-      if (MAPTST(&xp->ignoredx, id))
-       {
-         Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, s->name), ":", pool_id2str(pool, id)), 0);
-         if (xid && MAPTST(&xp->ignored, xid))
-           return 1;
-       }
-    }
-  n = pool_id2str(pool, id);
-  if (!strncmp(n, "rpmlib(", 7))
-    {
-      MAPEXP(&xp->ignored, id);
-      MAPSET(&xp->ignored, id);
-      return 1;
-    }
-  if (*n == '/')
-    {
-      if (!xp->havefileprovides || pool->whatprovides[id] <= 1)
-       {
-         MAPEXP(&xp->ignored, id);
-         MAPSET(&xp->ignored, id);
-         return 1;
-       }
-    }
-  return 0;
-}
-
-static int
-expander_to_cplxblks(ExpanderCtx *xpctx, Id p, Id dep, int deptype, Id *ptr)
-{
-  int blkoff = xpctx->cplxblks.count;
-  queue_push(&xpctx->cplxblks, p);
-  queue_push(&xpctx->cplxblks, dep);
-  queue_push(&xpctx->cplxblks, deptype);
-  for (;;)
-    {
-      Id pp = *ptr++;
-      queue_push(&xpctx->cplxblks, pp);
-      if (!pp)
-       break;
-    }
-  return blkoff;
-}
-
-static int
-expander_check_cplxblock(ExpanderCtx *xpctx, Id p, Id dep, int deptype, Id *ptr, int blkoff)
-{
-  Pool *pool = xpctx->pool;
-  int posn = 0, posi = 0, negn = 0, negi = 0;
-  Id pp, *ptr2 = ptr;
-  Id lastcon = 0;
-
-  while ((pp = *ptr2++) != 0)
-    {
-      if (pp > 0)
-       {
-         posn++;
-         if (MAPTST(&xpctx->installed, pp))
-           posi++;
-       }
-      else
-       {
-         if (p == -pp)
-           continue;   /* ignore redundant self-entry */
-         negn++;
-         if (MAPTST(&xpctx->installed, -pp))
-           negi++;
-         else
-           lastcon = -pp;
-       }
-    }
-#if 0
-  printf("expander_check_cplxblock pos: %d,%d neg: %d,%d\n", posn, posi, negn, negi);
-#endif
-  if (posi)
-    return -1;
-  if (!posn && deptype == DEPTYPE_RECOMMENDS)
-    return -1;
-  if (negi == negn)
-    {
-      /* all neg installed */
-      if (posn)
-       {
-         /* posn > 0 and all neg installed, add to todo */
-         if (blkoff < 0)
-           blkoff = expander_to_cplxblks(xpctx, p, dep, deptype, ptr);
-#if 0
-         printf("put on todo, blkoff = %d\n", blkoff);
-#endif
-         queue_push2(&xpctx->todo, MAKECPLX(pool, blkoff), p);
-       }
-      else
-       {
-         /* no posn, conflict */
-         for (ptr2 = ptr; (pp = *ptr2++) != 0; )
-           {
-             if (p == -pp)
-               continue;       /* ignore redundant self-entry */
-             if (deptype == DEPTYPE_REQUIRES)
-               {
-                 /* do not report a requires as conflicts */
-                 queue_push(&xpctx->errors, ERROR_NOPROVIDER);
-                 queue_push2(&xpctx->errors, dep, p);
-                 break;
-               }
-             queue_push(&xpctx->errors, ERROR_CONFLICT);
-             queue_push2(&xpctx->errors, p, -pp);
-           }
-       }
-      return -1;
-    }
-  else if (!posn && negn && negi == negn - 1)
-    {
-      /* add conflict */
-#if 0
-      printf("add conflict %d %d\n", lastcon, p);
-#endif
-      MAPEXP(&xpctx->conflicts, pool->nsolvables);
-      MAPSET(&xpctx->conflicts, lastcon);
-      if (p)
-        queue_push2(&xpctx->conflictsinfo, lastcon, p);        /* always do this for rich deps */
-      return -1;
-    }
-  else
-    {
-#ifdef DEBUG_COND
-      printf("put/stay on cond queue, blkoff = %d\n", blkoff);
-#endif
-      /* either posn > 0 and 1 neg not installed or more than 1 neg not installed */
-      if (blkoff < 0)
-       blkoff = expander_to_cplxblks(xpctx, p, dep, deptype, ptr);
-      return blkoff;
-    }
-}
-
-static void
-expander_installed_complexdep(ExpanderCtx *xpctx, Id p, Id dep, int deptype)
-{
-  Queue *cplxq = &xpctx->cplxq;
-  int r, i, start = cplxq->count, blkoff;
-
-#if 0
-  printf("expander_installed_complexdep %s type %d\n", pool_dep2str(xpctx->pool, dep), deptype);
-#endif
-  if (deptype == DEPTYPE_CONFLICTS)
-    {
-      r = normalize_dep(xpctx, dep, cplxq, CPLXDEPS_TODNF);
-      r = invert_depblocks(xpctx, cplxq, start, r);
-    }
-  else
-    r = normalize_dep(xpctx, dep, cplxq, 0);
-#if 0
-  print_depblocks(xpctx, cplxq, start, r);
-#endif
-  if (r == 1)
-    return;
-  if (r == 0)
-    {
-      if (deptype == DEPTYPE_CONFLICTS)
-       {
-         queue_push(&xpctx->errors, ERROR_ALLCONFLICT);
-         queue_push2(&xpctx->errors, dep, p);
-       }
-      else if (deptype != DEPTYPE_RECOMMENDS)
-       {
-         queue_push(&xpctx->errors, ERROR_NOPROVIDER);
-         queue_push2(&xpctx->errors, dep, p);
-       }
-      return;
-    }
-  while (start < cplxq->count)
-    {
-      /* find end */
-      for (i = start; cplxq->elements[i] != 0; i++)
-       ;
-      blkoff = expander_check_cplxblock(xpctx, p, dep, deptype, cplxq->elements + start, -1);
-      if (blkoff >= 0)
-       {
-         Pool *pool = xpctx->pool;
-         Id p;
-         MAPEXP(&xpctx->todo_condmap, pool->nsolvables);
-         for (i = start; (p = cplxq->elements[i]) != 0; i++)
-           if (p < 0)
-             MAPSET(&xpctx->todo_condmap, -p);
-         queue_push(&xpctx->todo_cond, blkoff);
-       }
-      start = i + 1;
-    }
-  queue_truncate(cplxq, start);
-}
-
-static int
-expander_checkconflicts_complexdep(ExpanderCtx *xpctx, Id p, Id dep, int deptype, int recorderrors)
-{
-  Queue *cplxq = &xpctx->cplxq;
-  int r, i, start = cplxq->count;
-  Id pp;
-  int ret = 0;
-
-#if 0
-  printf("expander_checkconflicts_complexdep %s type %d\n", pool_dep2str(xpctx->pool, dep), deptype);
-#endif
-  if (deptype == DEPTYPE_CONFLICTS)
-    {
-      r = normalize_dep(xpctx, dep, cplxq, CPLXDEPS_TODNF);
-      r = invert_depblocks(xpctx, cplxq, start, r);
-    }
-  else
-    r = normalize_dep(xpctx, dep, cplxq, 0);
-#if 0
-  print_depblocks(xpctx, cplxq, start, r);
-#endif
-  /* r == 0: conflict with everything. Ignore here, pick error up when package gets installed */
-  if (r == 0 || r == 1)
-    return 0;
-  while (start < cplxq->count)
-    {
-      for (i = start; (pp = cplxq->elements[i]) != 0; i++)
-        if (pp > 0 || (pp < 0 && !MAPTST(&xpctx->installed, -pp)))
-         break;
-      if (pp == 0)
-       {
-         /* no pos and all neg installed -> conflict */
-         for (i = start; (pp = cplxq->elements[i]) != 0; i++)
-           {
-             pp = -cplxq->elements[i];
-             if (recorderrors)
-               {
-                 queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT : ERROR_PROVIDERINFO);
-                 queue_push2(&xpctx->errors, p, pp);
-               }
-             else if (xpctx->xp->debug)
-               {
-                 Pool *pool = xpctx->pool;
-                 expander_dbg(xpctx->xp, "ignoring provider %s because it conflicts with installed %s\n", pool_solvid2str(pool, p), pool_solvid2str(pool, pp));
-               }
-             ret = ret ? 1 : pp;
-           }
-       }
-      for (; cplxq->elements[i] != 0; i++)
-       ;
-      start = i + 1;
-    }
-  queue_truncate(cplxq, start);
-  return ret;
-}
-
-static void
-updateconflictsinfo(ExpanderCtx *xpctx)
-{
-  int i;
-  Pool *pool = xpctx->pool;
-  Queue *out = xpctx->out;
-  Queue *conflictsinfo = &xpctx->conflictsinfo;
-
-  if (xpctx->ignoreconflicts)
-    return;
-  for (i = xpctx->cidone; i < out->count; i++)
-    {
-      Id p, p2, pp2;
-      Id con, *conp;
-      Solvable *s;
-      p = out->elements[i];
-      s = pool->solvables + p;
-      /* keep in sync with expander_installed! */
-      if (s->conflicts)
-       {
-         conp = s->repo->idarraydata + s->conflicts;
-         while ((con = *conp++) != 0)
-           {
-             if (pool_is_complex_dep(pool, con))
-               continue;       /* already pushed */
-             FOR_PROVIDES(p2, pp2, con)
-               {
-                 if (p2 == p)
-                   continue;
-                 queue_push2(conflictsinfo, p2, p);
-               }
-           }
-       }
-      if (s->obsoletes)
-       {
-         conp = s->repo->idarraydata + s->obsoletes;
-         while ((con = *conp++) != 0)
-           {
-             FOR_PROVIDES(p2, pp2, con)
-               {
-                 if (p2 == p || !pool_match_nevr(pool, pool->solvables + p2, con))
-                   continue;
-                 queue_push2(conflictsinfo, p2, -p);
-               }
-           }
-       }
-    }
-  xpctx->cidone = out->count;
-}
-
-static int
-findconflictsinfo(ExpanderCtx *xpctx, Id p, int recorderrors)
-{
-  Queue *conflictsinfo = &xpctx->conflictsinfo;
-  int i, ret = 0;
-
-  if (xpctx->cidone < xpctx->out->count)
-    updateconflictsinfo(xpctx);
-
-  for (i = 0; i < conflictsinfo->count; i++)
-    if (conflictsinfo->elements[i] == p)
-      {
-       ret = conflictsinfo->elements[i + 1];
-       if (recorderrors)
-         {
-           queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT2 : ERROR_PROVIDERINFO2);
-           queue_push2(&xpctx->errors, p, ret);
-         }
-       else if (xpctx->xp->debug)
-         {
-           Pool *pool = xpctx->pool;
-           expander_dbg(xpctx->xp, "ignoring provider %s because installed %s %s it\n", pool_solvid2str(pool, p), pool_solvid2str(pool, ret > 0 ? ret : -ret), ret > 0 ? "conflicts with" : "obsoletes");
-         }
-      }
-  if (!ret)
-    {
-      /* conflict from our job, i.e. a !xxx dep */
-      if (recorderrors)
-       {
-         queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT2 : ERROR_PROVIDERINFO2);
-         queue_push2(&xpctx->errors, p, 0);
-       }
-      else if (xpctx->xp->debug)
-       {
-         Pool *pool = xpctx->pool;
-         expander_dbg(xpctx->xp, "ignoring conflicted provider %s\n", pool_solvid2str(pool, p));
-       }
-    }
-  return ret;
-}
-
-
-static void
-recheck_conddeps(ExpanderCtx *xpctx)
-{
-  int i;
-  for (i = 0; i < xpctx->todo_cond.count; i++)
-    {
-      int blkoff = xpctx->todo_cond.elements[i];
-#ifdef DEBUG_COND
-      printf("todo_cond %d\n", blkoff);
-#endif
-      Id *ptr = xpctx->cplxblks.elements + blkoff;
-      if (expander_check_cplxblock(xpctx, ptr[0], ptr[1], ptr[2], ptr + 3, blkoff) < 0)
-       {
-#ifdef DEBUG_COND
-         printf("remove no longer needed cond entry\n");
-#endif
-         queue_delete(&xpctx->todo_cond, i);
-         i--;
-       }
-    }
-}
-
-/* install a single package */
-static void
-expander_installed(ExpanderCtx *xpctx, Id p)
-{
-  Pool *pool = xpctx->pool;
-  Expander *xp = xpctx->xp;
-  Solvable *s = pool->solvables + p;
-  Id req, *reqp, con, *conp;
-
-#if 0
-printf("expander_installed %s\n", pool_solvid2str(pool, p));
-#endif
-  MAPSET(&xpctx->installed, p);
-  queue_push(xpctx->out, p);
-
-  if (xpctx->conflicts.size && MAPTST(&xpctx->conflicts, p))
-    findconflictsinfo(xpctx, p, 2);
-
-  /* add synthetic conflicts from the project config */
-  if (MAPTST(&xp->conflicts, s->name))
-    {
-      int i;
-      for (i = 0; i < xp->conflictsq.count; i++)
-       {
-         Id p2, pp2;
-         Id id = xp->conflictsq.elements[i];
-         if (id != s->name)
-           continue;
-         id = xp->conflictsq.elements[i ^ 1];
-         FOR_PROVIDES(p2, pp2, id)
-           {
-             if (pool->solvables[p2].name != id)
-               continue;
-             if (MAPTST(&xpctx->installed, p2))
-               {
-                 queue_push(&xpctx->errors, ERROR_CONFLICT);
-                 queue_push2(&xpctx->errors, p, p2);
-                 continue;
-               }
-             MAPEXP(&xpctx->conflicts, pool->nsolvables);
-             MAPSET(&xpctx->conflicts, p2);
-             queue_push2(&xpctx->conflictsinfo, p2, p);
-           }
-       }
-    }
-
-  if (s->requires)
-    {
-      reqp = s->repo->idarraydata + s->requires;
-      while ((req = *reqp++) != 0)
-       {
-         if (req == SOLVABLE_PREREQMARKER)
-           continue;
-         if (ISRELDEP(req) && GETRELDEP(pool, req)->flags == REL_ERROR)
-           {
-             queue_push(&xpctx->errors, ERROR_BADDEPENDENCY);
-             queue_push2(&xpctx->errors, GETRELDEP(pool, req)->evr, p);
-             continue;
-           }
-         if (pool_is_complex_dep(pool, req))
-           {
-             xpctx->ignore_s = s;
-             expander_installed_complexdep(xpctx, p, req, DEPTYPE_REQUIRES);
-             xpctx->ignore_s = 0;
-             continue;
-           }
-         if (expander_isignored(xp, s, req))
-           continue;
-         queue_push2(&xpctx->todo, req, p);
-       }
-    }
-  if (!xpctx->ignoreconflicts)
+  if (!xp->ignoreconflicts)
     {
       if (s->conflicts)
        {
@@ -1522,31 +638,14 @@ printf("expander_installed %s\n", pool_solvid2str(pool, p));
          while ((con = *conp++) != 0)
            {
              Id p2, pp2;
-             if (ISRELDEP(con) && GETRELDEP(pool, con)->flags == REL_ERROR)
-               {
-                 queue_push(&xpctx->errors, ERROR_BADDEPENDENCY);
-                 queue_push2(&xpctx->errors, GETRELDEP(pool, con)->evr, p);
-                 continue;
-               }
-             if (pool_is_complex_dep(pool, con))
-               {
-                 expander_installed_complexdep(xpctx, p, con, DEPTYPE_CONFLICTS);
-                 continue;
-               }
              FOR_PROVIDES(p2, pp2, con)
                {
                  if (p2 == p)
                    continue;
-                 if (MAPTST(&xpctx->installed, p2))
-                   {
-                     queue_push(&xpctx->errors, ERROR_CONFLICT);
-                     queue_push2(&xpctx->errors, p, p2);
-                     continue;
-                   }
-                 MAPEXP(&xpctx->conflicts, pool->nsolvables);
-                 MAPSET(&xpctx->conflicts, p2);
+                 MAPEXP(conflicts, pool->nsolvables);
+                 MAPSET(conflicts, p2);
                  if (xp->debug)
-                   queue_push2(&xpctx->conflictsinfo, p2, p);
+                   queue_push2(conflictsinfo, p2, p);
                }
            }
        }
@@ -1560,77 +659,28 @@ printf("expander_installed %s\n", pool_solvid2str(pool, p));
                {
                  if (p2 == p || !pool_match_nevr(pool, pool->solvables + p2, con))
                    continue;
-                 if (MAPTST(&xpctx->installed, p2))
-                   {
-                     queue_push(&xpctx->errors, ERROR_CONFLICT);
-                     queue_push2(&xpctx->errors, p, -p2);
-                     continue;
-                   }
-                 MAPEXP(&xpctx->conflicts, pool->nsolvables);
-                 MAPSET(&xpctx->conflicts, p2);
+                 MAPEXP(conflicts, pool->nsolvables);
+                 MAPSET(conflicts, p2);
                  if (xp->debug)
-                   queue_push2(&xpctx->conflictsinfo, p2, -p);
+                   queue_push2(conflictsinfo, p2, -p);
                }
            }
        }
       if (xp->debug)
-       xpctx->cidone = xpctx->out->count;
+       *cidone = out->count;
     }
-  if (xpctx->todo_condmap.size && MAPTST(&xpctx->todo_condmap, p))
-    recheck_conddeps(xpctx);
 }
 
-/* same as expander_installed, but install multiple packages
- * in one block */
-static void
-expander_installed_multiple(ExpanderCtx *xpctx, Queue *toinstall)
-{
-  int i, j, havecond = 0;
-
-  /* unify */
-  for (i = j = 0; i < toinstall->count; i++)
-    {
-      Id p = toinstall->elements[i];
-      if (MAPTST(&xpctx->installed, p))
-       continue;       /* already seen */
-      MAPSET(&xpctx->installed, p);
-      toinstall->elements[j++] = p;
-      if (xpctx->todo_condmap.size && MAPTST(&xpctx->todo_condmap, p))
-       {
-         havecond = 1;
-         MAPCLR(&xpctx->todo_condmap, p);      /* no longer needed */
-       }
-    }
-  queue_truncate(toinstall, j);
-  
-  /* run conditionals first */
-  if (havecond)
-    recheck_conddeps(xpctx);
-
-  if (!xpctx->errors.count)
-    for (i = 0; i < toinstall->count; i++)
-      expander_installed(xpctx, toinstall->elements[i]);
-  queue_empty(toinstall);
-}
-
-static int
-expander_checkconflicts(ExpanderCtx *xpctx, Id p, Id *conflicts, int isobsoletes, int recorderrors)
+static inline int
+expander_checkconflicts(Expander *xp, Id p, Map *installed, Id *conflicts, int isobsoletes)
 {
-  Map *installed = &xpctx->installed;
-  Pool *pool = xpctx->pool;
+  Pool *pool = xp->pool;
   Id con, p2, pp2;
-  int ret = 0;
 
-  if (xpctx->ignoreconflicts)
+  if (xp->ignoreconflicts)
     return 0;
   while ((con = *conflicts++) != 0)
     {
-      if (!isobsoletes && pool_is_complex_dep(pool, con))
-       {
-         p2 = expander_checkconflicts_complexdep(xpctx, p, con, DEPTYPE_CONFLICTS, recorderrors);
-         ret = ret ? 1 : p2;
-         continue;
-       }
       FOR_PROVIDES(p2, pp2, con)
        {
          if (p == p2)
@@ -1638,500 +688,154 @@ expander_checkconflicts(ExpanderCtx *xpctx, Id p, Id *conflicts, int isobsoletes
          if (isobsoletes && !pool_match_nevr(pool, pool->solvables + p2, con))
            continue;
          if (MAPTST(installed, p2))
-           {
-             if (recorderrors)
-               {
-                 queue_push(&xpctx->errors, recorderrors == 2 ? ERROR_CONFLICT : ERROR_PROVIDERINFO);
-                 queue_push2(&xpctx->errors, p, isobsoletes ? -p2 : p2);
-               }
-             else if (xpctx->xp->debug)
-               {
-                 if (isobsoletes)
-                   expander_dbg(xpctx->xp, "ignoring provider %s because it obsoletes installed %s\n", pool_solvid2str(pool, p), pool_solvid2str(pool, p2));
-                 else
-                   expander_dbg(xpctx->xp, "ignoring provider %s because it conflicts with installed %s\n", pool_solvid2str(pool, p), pool_solvid2str(pool, p2));
-               }
-             ret = ret ? 1 : p2;
-           }
+           return p2;
        }
     }
-  return ret;
+  return 0;
 }
 
 static void
-expander_updaterecommendedmap(ExpanderCtx *xpctx)
+expander_updateconflictsinfo(Expander *xp, Queue *conflictsinfo, int *cidone, Queue *out)
 {
-  Pool *pool = xpctx->pool;
-  Queue *out = xpctx->out;
-  Map *recommended = &xpctx->recommended;
-
+  Pool *pool = xp->pool;
   int i;
-  Id p, pp, rec, *recp;
-  for (i = xpctx->recdone; i < out->count; i++)
+  if (xp->ignoreconflicts)
+    return;
+  for (i = *cidone; i < out->count; i++)
     {
+      Id p, p2, pp2;
+      Id con, *conp;
       Solvable *s;
-      s = pool->solvables + out->elements[i];
-      if (s->recommends)
-       {
-          MAPEXP(recommended, pool->nsolvables);
-          for (recp = s->repo->idarraydata + s->recommends; (rec = *recp++) != 0; )
-           FOR_PROVIDES(p, pp, rec)
-             MAPSET(recommended, p);
-       }
-    }
-  xpctx->recdone = out->count;
-}
-
-static int
-expander_dep_fulfilled(ExpanderCtx *xpctx, Id dep)
-{
-  Pool *pool = xpctx->pool;
-  Id p, pp; 
-
-  if (ISRELDEP(dep))
-    {   
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags == REL_COND)
+      p = out->elements[i];
+      s = pool->solvables + p;
+      /* keep in sync with expander_installed! */
+      if (s->conflicts)
        {
-         if (ISRELDEP(rd->evr))
+         conp = s->repo->idarraydata + s->conflicts;
+         while ((con = *conp++) != 0)
            {
-             Reldep *rd2 = GETRELDEP(pool, rd->evr);
-             if (rd2->flags == REL_ELSE)
+             FOR_PROVIDES(p2, pp2, con)
                {
-                 if (expander_dep_fulfilled(xpctx, rd2->name))
-                   return expander_dep_fulfilled(xpctx, rd->name);
-                 return expander_dep_fulfilled(xpctx, rd2->evr);
+                 if (p2 == p)
+                   continue;
+                 queue_push2(conflictsinfo, p2, p);
                }
            }
-         if (expander_dep_fulfilled(xpctx, rd->name))  /* A OR ~B */
-           return 1;
-         return !expander_dep_fulfilled(xpctx, rd->evr);
        }
-      if (rd->flags == REL_UNLESS)
+      if (s->obsoletes)
        {
-         if (ISRELDEP(rd->evr))
+         conp = s->repo->idarraydata + s->obsoletes;
+         while ((con = *conp++) != 0)
            {
-             Reldep *rd2 = GETRELDEP(pool, rd->evr);
-             if (rd2->flags == REL_ELSE)
+             FOR_PROVIDES(p2, pp2, con)
                {
-                 if (!expander_dep_fulfilled(xpctx, rd2->name))
-                   return expander_dep_fulfilled(xpctx, rd->name);
-                 return expander_dep_fulfilled(xpctx, rd2->evr);
+                 if (p2 == p || !pool_match_nevr(pool, pool->solvables + p2, con))
+                   continue;
+                 queue_push2(conflictsinfo, p2, -p);
                }
            }
-         if (!expander_dep_fulfilled(xpctx, rd->name)) /* A AND ~B */
-           return 0;
-         return !expander_dep_fulfilled(xpctx, rd->evr);
-       }
-      if (rd->flags == REL_AND)
-       {
-         if (!expander_dep_fulfilled(xpctx, rd->name))
-           return 0;
-         return expander_dep_fulfilled(xpctx, rd->evr);
-       }
-      if (rd->flags == REL_OR)
-       {
-         if (expander_dep_fulfilled(xpctx, rd->name))
-           return 1;
-         return expander_dep_fulfilled(xpctx, rd->evr);
-       }
-    }
-  FOR_PROVIDES(p, pp, dep)
-    {
-      if (MAPTST(&xpctx->installed, p))
-       return 1;
-    }
-  return 0;
-}
-
-static int
-prune_neg_prefers(ExpanderCtx *xpctx, Id who, Id *e, int n)
-{
-  Expander *xp = xpctx->xp;
-  Pool *pool = xpctx->pool;
-  Id whon = who ? pool->solvables[who].name : 0;
-  int i, j;
-  for (i = j = 0; i < n; i++)
-    {
-      Id p = e[i];
-      Id pn = pool->solvables[p].name;
-      if (MAPTST(&xp->preferneg, pn))
-       continue;
-      if (who && MAPTST(&xp->prefernegx, pn))
-       {
-         Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
-         if (xid && MAPTST(&xp->preferneg, xid))
-           continue;
-       }
-      e[j++] = p;
-    }
-  return j ? j : n;
-}
-
-static int
-prune_pos_prefers(ExpanderCtx *xpctx, Id who, Id *e, int n, int domulti)
-{
-  Expander *xp = xpctx->xp;
-  Queue *pruneq = &xpctx->pruneq;
-  Pool *pool = xpctx->pool;
-  Id whon = who ? pool->solvables[who].name : 0;
-  int i, j;
-
-  if (pruneq->count)
-    queue_empty(pruneq);
-  for (i = j = 0; i < n; i++)
-    {
-      Id p = e[i];
-      Id pn = pool->solvables[p].name;
-      if (MAPTST(&xp->preferpos, pn))
-       queue_push2(pruneq, pn, p);
-      else if (who && MAPTST(&xp->preferposx, pn))
-       {
-         Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
-         if (xid && MAPTST(&xp->preferpos, xid))
-           queue_push2(pruneq, xid, p);
-       }
-    }
-  if (!pruneq->count)
-    return n;
-  if (pruneq->count > 2)
-    {
-      if (!domulti)
-       return n;
-      /* pos prefers are ordered, the first one wins */
-      for (i = 0; i < xp->preferposq.count; i++)
-       {
-         Id xid = xp->preferposq.elements[i];
-         for (j = 0; j < pruneq->count; j += 2)
-           if (pruneq->elements[j] == xid)
-             {
-               e[0] = pruneq->elements[j + 1];
-               return 1;
-             }
        }
     }
-  e[0] = pruneq->elements[1];  /* simple case, just one prefer */
-  return 1;
-}
-
-static int
-prune_or_dep(ExpanderCtx *xpctx, Id dep, Id *e, int n)
-{
-  Pool *pool = xpctx->pool;
-  int i, j;
-  Id p, pp;
-
-  for (;;)
-    {
-      Reldep *rd = 0;
-      if (ISRELDEP(dep))
-       {
-         rd = GETRELDEP(pool, dep);
-         if (rd->flags != REL_OR)
-           rd = 0;
-       }
-      if (rd)
-       dep = rd->name;
-      i = j = 0;
-      /* both sets are ordered */
-      FOR_PROVIDES(p, pp, dep)
-       {
-         if (p < e[i])
-           continue;
-         while (i < n && p > e[i])
-           i++;
-         if (i == n)
-           break;
-         if (p == e[i])
-           e[j++] = p;
-       }
-      if (j)
-       return j;
-      if (rd)
-       dep = rd->evr;
-      else
-       break;
-    }
-  return n;
-}
-
-static int
-prune_supplemented(ExpanderCtx *xpctx, Id *e, int n)
-{
-  Pool *pool = xpctx->pool;
-  int i, j;
-  Id sup, *supp;
-
-  for (i = j = 0; i < n; i++)
-    {
-      Id p = e[i];
-      Solvable *s = pool->solvables + p;
-      if (!s->supplements)
-       continue;
-      supp = s->repo->idarraydata + s->supplements;
-      while ((sup = *supp++) != 0)
-       if (expander_dep_fulfilled(xpctx, sup))
-         break;
-      if (sup)
-        e[j++] = p;
-    }
-  return j ? j : n;
+  *cidone = out->count;
 }
 
 static void
-add_recommended_packages(ExpanderCtx *xpctx, Solvable *s)
+expander_updaterecommendedmap(Expander *xp, Map *recommended, int *recdone, Queue *out)
 {
-  Pool *pool = xpctx->pool;
+  Pool *pool = xp->pool;
+
+  int i;
   Id p, pp, rec, *recp;
-  for (recp = s->repo->idarraydata + s->recommends; (rec = *recp++) != 0; )
+  for (i = *recdone; i < out->count; i++)
     {
-      int haveone = 0;
-      if (pool_is_complex_dep(pool, rec))
-       {
-         expander_installed_complexdep(xpctx, s - pool->solvables, rec, DEPTYPE_RECOMMENDS);
-         continue;
-       }
-      FOR_PROVIDES(p, pp, rec)
-       {
-         if (MAPTST(&xpctx->installed, p))
-           break;
-         if (haveone)
-           continue;
-         if (xpctx->conflicts.size && MAPTST(&xpctx->conflicts, p))
-           continue;
-         if (pool->solvables[p].conflicts && expander_checkconflicts(xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0, 0) != 0)
-           continue;
-         if (pool->solvables[p].obsoletes && expander_checkconflicts(xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1, 0) != 0)
-           continue;
-         haveone = 1;
-       }
-      if (p)
-       continue;       /* already fulfilled */
-      if (haveone)
-       queue_push2(&xpctx->todo, rec, s - pool->solvables);
+      Solvable *s;
+      s = pool->solvables + out->elements[i];
+      if (s->recommends)
+       {
+          MAPEXP(recommended, pool->nsolvables);
+          for (recp = s->repo->idarraydata + s->recommends; (rec = *recp++) != 0; )
+           FOR_PROVIDES(p, pp, rec)
+             MAPSET(recommended, p);
+       }
     }
+  *recdone = out->count;
 }
 
-static void
-expander_growmaps(Expander *xp)
+static inline int
+findconflictsinfo(Queue *conflictsinfo, Id p)
 {
-  Pool *pool = xp->pool;
-  MAPEXP(&xp->ignored, pool->ss.nstrings);
-  MAPEXP(&xp->ignoredx, pool->ss.nstrings);
-  MAPEXP(&xp->preferpos, pool->ss.nstrings);
-  MAPEXP(&xp->preferposx, pool->ss.nstrings);
-  MAPEXP(&xp->preferneg, pool->ss.nstrings);
-  MAPEXP(&xp->prefernegx, pool->ss.nstrings);
-  MAPEXP(&xp->conflicts, pool->ss.nstrings);
-}
+  int i;
 
-static Id
-str2id_dup(Pool *pool, const char *str)
-{
-  char buf[256];
-  size_t l = strlen(str);
-  if (l < 256) {
-    memcpy(buf, str, l + 1);
-    return pool_str2id(pool, buf, 1);
-  } else {
-    return pool_str2id(pool, pool_tmpjoin(pool, str, 0, 0), 1);
-  }
+  for (i = 0; i < conflictsinfo->count; i++)
+    if (conflictsinfo->elements[i] == p)
+      return conflictsinfo->elements[i + 1];
+  return 0;
 }
 
-static void
-add_noproviderinfo(ExpanderCtx *xpctx, Id dep, Id who)
-{
-  Pool *pool = xpctx->pool;
-  Reldep *rd, *prd;
-  Id p, pp, prov, *provp;
-  int nprovinfo;
+#define ERROR_NOPROVIDER               1
+#define ERROR_CHOICE                   2
+#define ERROR_CONFLICTINGPROVIDER      3
+#define ERROR_CONFLICTINGPROVIDERS     4
+#define ERROR_PROVIDERINFO             5
+#define ERROR_PROVIDERINFO2            6
 
-  if (xpctx->xp->debug)
-    {
-      if (who)
-        expander_dbg(xpctx->xp, "nothing provides %s needed by %s\n", pool_dep2str(pool, dep), expander_solvid2str(xpctx->xp, who));
-      else
-        expander_dbg(xpctx->xp, "nothing provides %s\n", pool_dep2str(pool, dep));
-    }
-  if (!ISRELDEP(dep))
-    return;
-  rd = GETRELDEP(pool, dep);
-  if (rd->flags >= 8 || ISRELDEP(rd->name) || ISRELDEP(rd->evr))
-    return;
-  nprovinfo = 0;
-  FOR_PROVIDES(p, pp, rd->name)
-    {
-      Solvable *s = pool->solvables + p;
-      if (!s->repo || !s->provides)
-       continue;
-      for (provp = s->repo->idarraydata + s->provides; (prov = *provp++) != 0; )
-       {
-         if (!ISRELDEP(prov))
-           continue;
-         prd = GETRELDEP(pool, prov);
-         if (prd->name != rd->name || ISRELDEP(prd->evr))
-           continue;
-         queue_push(&xpctx->errors, ERROR_NOPROVIDERINFO);
-         if (prd->name == s->name && prd->evr == s->evr)
-           {
-             if (xpctx->xp->debug)
-               expander_dbg(xpctx->xp, "%s has version %s\n", expander_solvid2str(xpctx->xp, p), pool_id2str(pool, prd->evr));
-             queue_push2(&xpctx->errors, prd->evr, 0);
-           }
-         else
-           {
-             if (xpctx->xp->debug)
-               expander_dbg(xpctx->xp, "%s provides version %s\n", expander_solvid2str(xpctx->xp, p), pool_id2str(pool, prd->evr));
-             queue_push2(&xpctx->errors, prd->evr, p);
-           }
-         if (++nprovinfo >= 4)
-           return;             /* only show the first 4 providers */
-       }
-    }
-}
 
-static int
-expander_expand(Expander *xp, Queue *in, Queue *indep, Queue *out, Queue *ignoreq, int options)
+int
+expander_expand(Expander *xp, Queue *in, Queue *out, Queue *inconfl)
 {
-  ExpanderCtx xpctx;
   Pool *pool = xp->pool;
-  Queue toinstall;
-  Queue qq, choices;
+  Queue todo, errors, cerrors, qq, posfoundq;
+  Map installed;
+  Map conflicts;
+  Map recommended;
+  Queue conflictsinfo;
+  int cidone;
+  int recdone;
   Solvable *s;
   Id q, p, pp;
-  int i, j, nerrors;
-  int ti, tj, tc;
-  Id todoid, id, who, whon;
-  Id conflprovpc;
-  int pass;
-  Queue revertignore;
-  int oldignoreignore = xp->ignoreignore;
-  Map oldignored, oldignoredx;
-  int ignoremapssaved = 0;
-  int dorecstart = 0;
-
-  memset(&xpctx, 0, sizeof(xpctx));
-  xpctx.xp = xp;
-  xpctx.pool = pool;
-  xpctx.out = out;
-  xpctx.ignoreignore = options & EXPANDER_OPTION_IGNOREIGNORE ? 1 : xp->ignoreignore;
-  xpctx.ignoreconflicts = options & EXPANDER_OPTION_IGNORECONFLICTS ? 1 : xp->ignoreconflicts;
-  xpctx.userecommendsforchoices = options & EXPANDER_OPTION_USERECOMMENDSFORCHOICES ? 1 : xp->userecommendsforchoices;
-  xpctx.usesupplementsforchoices = options & EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES ? 1 : xp->usesupplementsforchoices;
-  xpctx.dorecommends = options & EXPANDER_OPTION_DORECOMMENDS ? 1 : xp->dorecommends;
-  xpctx.dosupplements = options & EXPANDER_OPTION_DOSUPPLEMENTS ? 1 : xp->dosupplements;
-  map_init(&xpctx.installed, pool->nsolvables);
-  map_init(&xpctx.conflicts, 0);
-  map_init(&xpctx.recommended, 0);
-  queue_init(&xpctx.conflictsinfo);
-  queue_init(&xpctx.todo);
-  queue_init(&xpctx.todo_cond);
-  map_init(&xpctx.todo_condmap, 0);
-  queue_init(&xpctx.errors);
-  queue_init(&xpctx.cplxq);
-  queue_init(&xpctx.cplxblks);
-  queue_init(&xpctx.pruneq);
-
-  queue_init(&toinstall);
+  int i, j, nerrors, doamb, ambcnt;
+  Id id, who, whon, pn;
+  Id conflprov, conflprovpc;
+  int haverecommended = 0;
+  int haverecommended_done = 0;
+
+  map_init(&installed, pool->nsolvables);
+  map_init(&conflicts, 0);
+  map_init(&recommended, 0);
+  queue_init(&conflictsinfo);
+  queue_init(&todo);
   queue_init(&qq);
-  queue_init(&choices);
-  queue_init(&revertignore);
+  queue_init(&errors);
+  queue_init(&cerrors);
+  queue_init(&posfoundq);
 
   queue_empty(out);
-
-  /* process ignored. hack: we mess with the ignore config in xp */
-  xp->ignoreignore = 0;
-  if (xpctx.ignoreignore && ignoreq->count)
-    {
-      /* bad: have direct ignores and we need to zero the project config ignores */
-      oldignored = xp->ignored;
-      oldignoredx = xp->ignoredx;
-      ignoremapssaved = 1;
-      /* clear project config maps */
-      memset(&xp->ignored, 0, sizeof(xp->ignored));
-      memset(&xp->ignoredx, 0, sizeof(xp->ignoredx));
-    }
-  if (ignoreq->count)
+  cidone = 0;
+  recdone = 0;
+  if (inconfl)
     {
-      /* mix direct ignores with ignores from project config */
-      for (i = 0; i < ignoreq->count; i++)
+      for (i = 0; i < inconfl->count; i += 2)
        {
-         const char *ss;
-         id = ignoreq->elements[i];
-         MAPEXP(&xp->ignored, id);
-         if (MAPTST(&xp->ignored, id))
-           continue;
-         MAPSET(&xp->ignored, id);
-         queue_push(&revertignore, id);
-         if ((ss = strchr(pool_id2str(pool, id), ':')) != 0)
+         Id con = inconfl->elements[i];
+         FOR_PROVIDES(p, pp, con)
            {
-             id = str2id_dup(pool, ss + 1);
-             MAPEXP(&xp->ignoredx, id);
-             if (MAPTST(&xp->ignoredx, id))
+             if (inconfl->elements[i + 1] && !pool_match_nevr(pool, pool->solvables + p, con))
                continue;
-             MAPSET(&xp->ignoredx, id);
-             queue_push(&revertignore, -id);
-           }
-       }
-    }
-  else if (xpctx.ignoreignore)
-    {
-      /* no direct ignores, ignore project config ignores.
-       * easy: just disable ignore processing */
-      xp->ignoreignore = 1;
-    }
-
-  /* grow maps to make bit tests cheaper */
-  expander_growmaps(xp);
-
-  /* process standard dependencies */
-  if (indep)
-    {
-      for (i = 0; i < indep->count; i += 2)
-       {
-         int deptype = indep->elements[i];
-         Id dep = indep->elements[i + 1];
-         if (ISRELDEP(dep) && GETRELDEP(pool, dep)->flags == REL_ERROR)
-           {
-             queue_push(&xpctx.errors, ERROR_BADDEPENDENCY);
-             queue_push2(&xpctx.errors, GETRELDEP(pool, dep)->evr, 0);
-             continue;
-           }
-         if ((deptype == DEPTYPE_REQUIRES || deptype == DEPTYPE_CONFLICTS) && pool_is_complex_dep(pool, dep))
-           {
-             expander_installed_complexdep(&xpctx, 0, dep, deptype);
-             continue;
-           }
-         if (deptype == DEPTYPE_REQUIRES)
-           {
-             queue_push2(&xpctx.todo, dep, 0);
-           }
-         else if (deptype == DEPTYPE_CONFLICTS || deptype == DEPTYPE_OBSOLETES)
-           {
-             FOR_PROVIDES(p, pp, dep)
-               {
-                 if (deptype == DEPTYPE_OBSOLETES && !pool_match_nevr(pool, pool->solvables + p, dep))
-                   continue;
-                 MAPEXP(&xpctx.conflicts, pool->nsolvables);
-                 MAPSET(&xpctx.conflicts, p);
-               }
+             MAPEXP(&conflicts, pool->nsolvables);
+             MAPSET(&conflicts, p);
            }
        }
     }
-  /* process direct dependencies */
+  /* do direct expands */
   for (i = 0; i < in->count; i++)
     {
       id = in->elements[i];
-      if (ISRELDEP(id) && GETRELDEP(pool, id)->flags == REL_ERROR)
+      if (id == expander_directdepsend)
        {
-         queue_push(&xpctx.errors, ERROR_BADDEPENDENCY);
-         queue_push2(&xpctx.errors, GETRELDEP(pool, id)->evr, 0);
-         continue;
-       }
-      if (pool_is_complex_dep(pool, id))
-       {
-         expander_installed_complexdep(&xpctx, 0, id, DEPTYPE_REQUIRES);
-         continue;
+         for (i = i + 1; i < in->count; i++)
+           if (in->elements[i] != expander_directdepsend)
+             queue_push2(&todo, in->elements[i], 0);
+         break;
        }
       q = 0;
       FOR_PROVIDES(p, pp, id)
@@ -2148,738 +852,425 @@ expander_expand(Expander *xp, Queue *in, Queue *indep, Queue *out, Queue *ignore
        }
       if (!q)
        {
-         queue_push2(&xpctx.todo, id, 0);      /* unclear, resolve later */
+         /* unclear, resolve later */
+         queue_push2(&todo, id, 0);
          continue;
        }
-      if (xp->debug)
-       expander_dbg(xp, "added %s because of %s (direct dep)\n", expander_solvid2name(xp, q), pool_dep2str(pool, id));
-      queue_push(&toinstall, q);
-    }
-
-  /* unify toinstall, check against conflicts */
-  for (i = 0; i < toinstall.count; i++)
-    {
-      p = toinstall.elements[i];
-      MAPSET(&xpctx.installed, p);
-    }
-  for (i = j = 0; i < toinstall.count; i++)
-    {
-      p = toinstall.elements[i];
-      if (!MAPTST(&xpctx.installed, p))
+      if (MAPTST(&installed, q))
        continue;
-      MAPCLR(&xpctx.installed, p);
-      toinstall.elements[j++] = p;
-    }
-  queue_truncate(&toinstall, j);
-  if (xpctx.conflicts.size)
-    {
-      for (i = 0; i < toinstall.count; i++)
+      if (conflicts.size && MAPTST(&conflicts, q))
+       {
+         queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
+         queue_push2(&errors, id, 0);
+         if (cidone < out->count)
+           expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out);
+         queue_push(&errors, ERROR_PROVIDERINFO2);
+         queue_push2(&errors, q, findconflictsinfo(&conflictsinfo, q));
+         continue;
+       }
+      if (pool->solvables[q].conflicts && (pp = expander_checkconflicts(xp, q, &installed, pool->solvables[q].repo->idarraydata + pool->solvables[q].conflicts, 0)) != 0)
        {
-         p = toinstall.elements[i];
-         if (MAPTST(&xpctx.conflicts, p))
-           findconflictsinfo(&xpctx, p, 2);
+         queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
+         queue_push2(&errors, id, 0);
+         queue_push(&errors, ERROR_PROVIDERINFO);
+         queue_push2(&errors, q, pp);
+         continue;
        }
-    }
-
-  /* here is the big expansion loop */
-  pass = 0;
-  while (!xpctx.errors.count)
-    {
-      if (toinstall.count)
+      if (pool->solvables[q].obsoletes && (pp = expander_checkconflicts(xp, q, &installed, pool->solvables[q].repo->idarraydata + pool->solvables[q].obsoletes, 1)) != 0)
        {
-         expander_installed_multiple(&xpctx, &toinstall);
-         pass = 0;
+         queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
+         queue_push2(&errors, id, 0);
+         queue_push(&errors, ERROR_PROVIDERINFO);
+         queue_push2(&errors, q, -pp);
          continue;
        }
-
-      if (!xpctx.todo.count)
+      if (xp->debug)
+       expander_dbg(xp, "added %s because of %s (direct dep)\n", expander_solvid2name(xp, q), pool_dep2str(pool, id));
+      expander_installed(xp, q, &installed, &conflicts, &conflictsinfo, &cidone, out, &todo); /* unique match! */
+    }
+
+  doamb = 0;
+  ambcnt = todo.count;
+  while (todo.count)
+    {
+      id = queue_shift(&todo);
+      who = queue_shift(&todo);
+      if (ambcnt == 0)
+       {
+         if (doamb >= 2)
+           break;      /* amb pass had no progress, stop */
+        doamb = xp->userecommendsforchoices ? doamb + 1 : 3;
+         if (doamb == 1 && !haverecommended)
+           {
+             for (i = haverecommended_done; i < out->count; i++)
+               if (pool->solvables[out->elements[i]].recommends)
+                 haverecommended = 1;
+             haverecommended_done = out->count;
+             if (!haverecommended)
+               doamb = 3;
+           }
+         if (xp->debug)
+      {
+        if (doamb == 2)
+                     expander_dbg(xp, "now doing undecided dependencies with recommends\n");
+        else
+          expander_dbg(xp, "now doing undecided dependencies\n");
+      }
+         ambcnt = todo.count;
+       }
+      else
+       ambcnt -= 2;
+// printf("todo %s %s ambcnt %d\n", pool_id2str(pool, pool->solvables[who].name), pool_dep2str(pool, id), ambcnt);
+// fflush(stdout);
+      whon = who ? pool->solvables[who].name : 0;
+      queue_empty(&qq);
+      conflprov = 0;
+      conflprovpc = 0;
+      FOR_PROVIDES(p, pp, id)
        {
-         /* almost finished. now do weak deps if requested */
-         pass = 0;
-         if (xpctx.dorecommends)
+         Id pc;
+         if (MAPTST(&installed, p))
+           break;
+         if (who && !xp->ignoreignore)
            {
-             expander_dbg(xp, "--- now doing recommended packages\n");
-             for (; dorecstart < out->count; dorecstart++)
+             Id pn = pool->solvables[p].name;
+             if (MAPTST(&xp->ignored, pn))
+               break;
+             if (MAPTST(&xp->ignoredx, pn))
                {
-                 s = pool->solvables + out->elements[dorecstart];
-                 if (s->recommends)
-                   add_recommended_packages(&xpctx, s);
+                 Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
+                 if (xid && MAPTST(&xp->ignored, xid))
+                   break;
                }
-             if (xpctx.todo.count)
-               continue;
            }
-         if (xpctx.dosupplements)
+         if (conflicts.size && MAPTST(&conflicts, p))
            {
-             Id sup, *supp;
-             expander_dbg(xp, "--- now doing supplemented packages\n");
-             for (p = 1; p < pool->nsolvables; p++)
+             if (xp->debug)
                {
-                 s = pool->solvables + p;
-                 if (!s->supplements || !s->repo)
-                   continue;
-                 if (MAPTST(&xpctx.installed, p))
-                   continue;
-                 if (!pool_installable(pool, s))
-                   continue;
-                 if (xpctx.conflicts.size && MAPTST(&xpctx.conflicts, p))
-                   continue;
-                 if (s->conflicts && expander_checkconflicts(&xpctx, p, s->repo->idarraydata + s->conflicts, 0, 0) != 0)
-                   continue;
-                 if (s->obsoletes && expander_checkconflicts(&xpctx, p, s->repo->idarraydata + s->obsoletes, 1, 0) != 0)
-                   continue;
-                 supp = s->repo->idarraydata + s->supplements;
-                 while ((sup = *supp++) != 0)
-                   if (expander_dep_fulfilled(&xpctx, sup))
-                     break;
-                 if (!sup)
-                   continue;
-                 expander_dbg(xp, "added %s because it supplements %s\n", expander_solvid2name(xp, p), pool_dep2str(pool, sup));
-                 queue_push(&toinstall, p);
+                 Id pc = findconflictsinfo(&conflictsinfo, p);
+                 if (pc)
+                   expander_dbg(xp, "ignoring provider %s of %s because installed %s %s it\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc > 0 ? pc : -pc), pc > 0 ? "conflicts with" : "obsoletes");
+                 else
+                   expander_dbg(xp, "ignoring conflicted provider %s of %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id));
                }
-             if (toinstall.count)
-               continue;
+             conflprov = conflprov ? 1 : p;
+             conflprovpc = 0;
+             continue;
            }
-         /* no new stuff to do, we're finished! */
-         break;
-       }
-
-      expander_dbg(xp, "--- now doing normal dependencies\n");
-
-      if (pass == 1)
-       queue_empty(&choices);
-       
-      for (ti = tj = 0; ti < xpctx.todo.count; ti += 2)
-       {
-         int deptype = DEPTYPE_REQUIRES;
-         todoid = id = xpctx.todo.elements[ti];
-         who = xpctx.todo.elements[ti + 1];
-         if (!id)                      /* deleted entry? */
-           continue;
-         queue_empty(&qq);
-         if (ISCPLX(pool, id))
+         if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0)) != 0)
            {
-             pp = GETCPLX(pool, id);   /* p, dep, deptype, ids... */
-             id = xpctx.cplxblks.elements[pp + 1];
-             deptype = xpctx.cplxblks.elements[pp + 2];
-             pp += 3;
-             while ((p = xpctx.cplxblks.elements[pp++]))
-               if (p > 0)
-                 queue_push(&qq, p);
+             expander_dbg(xp, "ignoring provider %s of %s because it conflicts with installed %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc));
+             conflprov = conflprov ? 1 : p;
+             conflprovpc = pc;
+             continue;
            }
-         else
+         if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1)) != 0)
            {
-             FOR_PROVIDES(p, pp, id)
-               queue_push(&qq, p);
+             expander_dbg(xp, "ignoring provider %s of %s because it obsoletes installed %s\n", pool_solvid2str(pool, p), pool_dep2str(pool, id), pool_solvid2str(pool, pc));
+             conflprov = conflprov ? 1 : p;
+             conflprovpc = -pc;
+             continue;
            }
-
-         if (qq.count == 0)
+         queue_push(&qq, p);
+       }
+      if (p)
+       continue;
+      if (qq.count == 0)
+       {
+         if (!conflprov)
            {
-             if (deptype == DEPTYPE_RECOMMENDS)
-               continue;
-             queue_push(&xpctx.errors, ERROR_NOPROVIDER);
-             queue_push2(&xpctx.errors, id, who);
-             add_noproviderinfo(&xpctx, id, who);
+             queue_push(&errors, ERROR_NOPROVIDER);
+             queue_push2(&errors, id, who);
              continue;
            }
-
-         /* check installed and ignores */
-         whon = who ? pool->solvables[who].name : 0;
-         for (i = 0; i < qq.count; i++)
+         /* more work for conflicts */
+         if (conflprov != 1)
            {
-             p = qq.elements[i];
-             if (MAPTST(&xpctx.installed, p))
-               break;
-             if (who && deptype == DEPTYPE_REQUIRES && !xp->ignoreignore)
+             /* nice, just one provider */
+             queue_push(&errors, ERROR_CONFLICTINGPROVIDER);
+             queue_push2(&errors, id, who);
+             if (!conflprovpc)
                {
-                 Id pn = pool->solvables[p].name;
-                 if (MAPTST(&xp->ignored, pn))
-                   break;
-                 if (MAPTST(&xp->ignoredx, pn))
-                   {
-                     Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
-                     if (xid && MAPTST(&xp->ignored, xid))
-                       break;
-                   }
+                 if (cidone < out->count)
+                   expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out);
+                 conflprovpc = findconflictsinfo(&conflictsinfo, conflprov);
+                 queue_push(&errors, ERROR_PROVIDERINFO2);
+                 queue_push2(&errors, conflprov, conflprovpc);
+               }
+             else
+               {
+                 queue_push(&errors, ERROR_PROVIDERINFO);
+                 queue_push2(&errors, conflprov, conflprovpc);
                }
-           }
-         if (i < qq.count)
-           continue;           /* ignored dependency or fulfilled */
-
-         if (pass == 0 && qq.count > 1)
-           {
-             xpctx.todo.elements[tj++] = todoid;
-             xpctx.todo.elements[tj++] = who;
              continue;
            }
-
-         /* do conflict pruning */
-         conflprovpc = 0;
-         for (i = j = 0; i < qq.count; i++)
+         /* even more work if all providers conflict */
+         queue_push(&errors, ERROR_CONFLICTINGPROVIDERS);
+         queue_push2(&errors, id, who);
+         if (cidone < out->count)
+           expander_updateconflictsinfo(xp, &conflictsinfo, &cidone, out);
+         FOR_PROVIDES(p, pp, id)
            {
              Id pc;
-             p = qq.elements[i];
-             if (xpctx.conflicts.size && MAPTST(&xpctx.conflicts, p))
-               {
-                 if (xp->debug)
-                   findconflictsinfo(&xpctx, p, 0);
-                 conflprovpc = 0;
-                 continue;
-               }
-             if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0, 0)) != 0)
+             if (conflicts.size && MAPTST(&conflicts, p))
                {
-                 conflprovpc = pc;
+                 pc = findconflictsinfo(&conflictsinfo, p);
+                 queue_push(&errors, ERROR_PROVIDERINFO2);
+                 queue_push2(&errors, p, pc);
                  continue;
                }
-             if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1, 0)) != 0)
+             if (pool->solvables[p].conflicts && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0)) != 0)
                {
-                 conflprovpc = -pc;
+                 queue_push(&errors, ERROR_PROVIDERINFO);
+                 queue_push2(&errors, p, pc);
                  continue;
                }
-             qq.elements[j++] = p;
-           }
-         if (j == 0)
-           {
-             if (deptype == DEPTYPE_RECOMMENDS)
-               continue;
-             queue_push(&xpctx.errors, ERROR_CONFLICTINGPROVIDERS);
-             queue_push2(&xpctx.errors, id, who);
-             if (qq.count == 1 && conflprovpc != 1 && conflprovpc != -1)
+             if (pool->solvables[p].obsoletes && (pc = expander_checkconflicts(xp, p, &installed, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1)) != 0)
                {
-                 p = qq.elements[0];
-                 if (conflprovpc)
-                   {
-                     queue_push(&xpctx.errors, ERROR_PROVIDERINFO);
-                     queue_push2(&xpctx.errors, p, conflprovpc);
-                     continue;
-                   }
-                 findconflictsinfo(&xpctx, p, 1);
+                 queue_push(&errors, ERROR_PROVIDERINFO);
+                 queue_push2(&errors, p, -pc);
                  continue;
                }
-             /* even more work if all providers conflict */
-             for (j = 0; j < qq.count; j++)
-               {
-                 p = qq.elements[j];
-                 if (xpctx.conflicts.size && MAPTST(&xpctx.conflicts, p))
-                   findconflictsinfo(&xpctx, p, 1);
-                 if (pool->solvables[p].conflicts)
-                   expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].conflicts, 0, 1);
-                 if (pool->solvables[p].obsoletes)
-                   expander_checkconflicts(&xpctx, p, pool->solvables[p].repo->idarraydata + pool->solvables[p].obsoletes, 1, 1);
-               }
-             continue;
-           }
-         queue_truncate(&qq, j);
-          if (qq.count == 1)
-           {
-             p = qq.elements[0];
-             if (xp->debug)
-               expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
-             queue_push(&toinstall, p);
-             continue;
            }
-         /* pass is == 1 and we have multiple choices */
+         continue;
+       }
+      if (qq.count > 1 && !doamb)
+       {
+         /* try again later */
+         queue_push2(&todo, id, who);
          if (xp->debug)
            {
              expander_dbg(xp, "undecided about %s:%s:", whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
              for (i = 0; i < qq.count; i++)
-               expander_dbg(xp, " %s", expander_solvid2name(xp, qq.elements[i]));
-              expander_dbg(xp, "\n");
+               expander_dbg(xp, " %s", expander_solvid2name(xp, qq.elements[i]));
+             expander_dbg(xp, "\n");
            }
-         queue_push2(&choices, qq.count + 3, id);
-         queue_push(&choices, qq.count);
-         queue_insertn(&choices, choices.count, qq.count, qq.elements);
-         xpctx.todo.elements[tj++] = todoid;
-         xpctx.todo.elements[tj++] = who;
-       }
-      queue_truncate(&xpctx.todo, tj);
-
-      if (toinstall.count)
-       continue;
-
-      if (!xpctx.todo.count)
-       continue;
-
-      /* did not find a package to install, only choices left on todo list */
-      if (pass == 0)
-       {
-         pass = 1;     /* now do conflict pruning */
          continue;
        }
 
-      expander_dbg(xp, "--- now doing undecided dependencies\n");
-
-      /* prune prefers */
-      for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
+      /* prune neg prefers */
+      if (qq.count > 1)
        {
-         Id who = xpctx.todo.elements[ti + 1];
-         Id *qe = choices.elements + tc + 3;
-         Id id = choices.elements[tc + 1];
-         int qn = choices.elements[tc + 2];
-         whon = who ? pool->solvables[who].name : 0;
-         if (qn > 1)
-           qn = prune_neg_prefers(&xpctx, who, qe, qn);
-         if (qn > 1)
-           qn = prune_pos_prefers(&xpctx, who, qe, qn, 0);
-         if (qn == 1)
+         for (i = j = 0; i < qq.count; i++)
            {
-             p = qe[0];
-             if (xp->debug)
-               expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
-             queue_push(&toinstall, p);
-             xpctx.todo.elements[ti] = 0;      /* kill entry */
+             p = qq.elements[i];
+             pn = pool->solvables[p].name;
+             if (MAPTST(&xp->preferneg, pn))
+               continue;
+             if (who && MAPTST(&xp->prefernegx, pn))
+               {
+                 Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
+                 if (xid && MAPTST(&xp->preferneg, xid))
+                   continue;
+               }
+             qq.elements[j++] = p;
            }
-         choices.elements[tc + 2] = qn;
-         tc += choices.elements[tc];
+         if (j)
+           queue_truncate(&qq, j);
        }
-      if (toinstall.count)
-       continue;
 
-      /* prune pos prefers with domulti and debian or */
-      for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
+      /* prune pos prefers */
+      if (qq.count > 1)
        {
-         Id who = xpctx.todo.elements[ti + 1];
-         Id *qe = choices.elements + tc + 3;
-         Id id = choices.elements[tc + 1];
-         int qn = choices.elements[tc + 2];
-         whon = who ? pool->solvables[who].name : 0;
-         if (qn > 1)
-           qn = prune_pos_prefers(&xpctx, who, qe, qn, 1);
-         if (qn > 1 && pool->disttype != DISTTYPE_RPM)
+         queue_empty(&posfoundq);
+         for (i = j = 0; i < qq.count; i++)
            {
-             if (ISRELDEP(id) && GETRELDEP(pool, id)->flags == REL_OR)
-               qn = prune_or_dep(&xpctx, id, qe, qn);
+             p = qq.elements[i];
+             pn = pool->solvables[p].name;
+             if (MAPTST(&xp->preferpos, pn))
+               {
+                 queue_push2(&posfoundq, pn, p);
+                 qq.elements[j++] = p;
+                 continue;
+               }
+             if (who && MAPTST(&xp->preferposx, pn))
+               {
+                 Id xid = pool_str2id(pool, pool_tmpjoin(pool, pool_id2str(pool, whon), ":", pool_id2str(pool, pn)), 0);
+                 if (xid && MAPTST(&xp->preferpos, xid))
+                   {
+                     queue_push2(&posfoundq, xid, p);
+                     qq.elements[j++] = p;
+                     continue;
+                   }
+               }
            }
-         if (qn == 1)
+         if (posfoundq.count == 2)
            {
-             p = qe[0];
-             if (xp->debug)
-               expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
-             queue_push(&toinstall, p);
-             xpctx.todo.elements[ti] = 0;      /* kill entry */
+             queue_empty(&qq);
+             queue_push(&qq, posfoundq.elements[1]);
            }
-         choices.elements[tc + 2] = qn;
-         tc += choices.elements[tc];
-       }
-      if (toinstall.count)
-       continue;
-
-      /* prune recommended packages */
-      if (xpctx.userecommendsforchoices)
-        expander_updaterecommendedmap(&xpctx);
-      if (xpctx.recommended.size)
-       {
-         expander_dbg(xp, "now doing undecided dependencies with recommends\n");
-         for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
+         else if (posfoundq.count)
            {
-             Id who = xpctx.todo.elements[ti + 1];
-             Id *qe = choices.elements + tc + 3;
-             Id id = choices.elements[tc + 1];
-             int qn = choices.elements[tc + 2];
-             whon = who ? pool->solvables[who].name : 0;
-             for (i = j = 0; i < qn; i++)
-               if (MAPTST(&xpctx.recommended, qe[i]))
-                 qe[j++] = qe[i];
-             if (j)
-               qn = j;
-             if (qn == 1)
+             /* found a pos prefer, now find first hit */
+             /* (prefers are ordered) */
+             for (i = 0; i < xp->preferposq.count; i++)
                {
-                 p = qe[0];
-                 if (xp->debug)
-                   expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
-                 queue_push(&toinstall, p);
-                 xpctx.todo.elements[ti] = 0;  /* kill entry */
+                 Id xid = xp->preferposq.elements[i];
+                 for (j = 0; j < posfoundq.count; j += 2)
+                   if (posfoundq.elements[j] == xid)
+                     break;
+                 if (j < posfoundq.count)
+                   {
+                     queue_empty(&qq);
+                     queue_push(&qq, posfoundq.elements[j + 1]);
+                     break;
+                   }
                }
-             choices.elements[tc + 2] = qn;
-             tc += choices.elements[tc];
            }
-         if (toinstall.count)
-           continue;
        }
-      if (xpctx.usesupplementsforchoices)
+
+      /* prune OR deps */
+      if (qq.count > 1 && ISRELDEP(id) && GETRELDEP(pool, id)->flags == REL_OR)
        {
-         expander_dbg(xp, "now doing undecided dependencies with supplements\n");
-         for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
+         Id rid = id;
+         for (;;)
            {
-             Id who = xpctx.todo.elements[ti + 1];
-             Id *qe = choices.elements + tc + 3;
-             Id id = choices.elements[tc + 1];
-             int qn = choices.elements[tc + 2];
-             whon = who ? pool->solvables[who].name : 0;
-             qn = prune_supplemented(&xpctx, qe, qn);
-             if (qn == 1)
+             Reldep *rd = 0;
+             if (ISRELDEP(rid))
                {
-                 p = qe[0];
-                 if (xp->debug)
-                   expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, p), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
-                 queue_push(&toinstall, p);
-                 xpctx.todo.elements[ti] = 0;  /* kill entry */
+                 rd = GETRELDEP(pool, rid);
+                 if (rd->flags != REL_OR)
+                   rd = 0;
                }
-             choices.elements[tc + 2] = qn;
-             tc += choices.elements[tc];
+             if (rd)
+               rid = rd->name;
+             queue_empty(&qq);
+             FOR_PROVIDES(p, pp, rid)
+               queue_push(&qq, p);
+             if (qq.count)
+               break;
+             if (rd)
+               rid = rd->evr;
+             else
+               break;
            }
-         if (toinstall.count)
-           continue;
        }
 
-      /* nothing more to prune. record errors. */
-      for (ti = tc = 0; ti < xpctx.todo.count; ti += 2)
-       {
-         Id who = xpctx.todo.elements[ti + 1];
-         Id *qe = choices.elements + tc + 3;
-         Id id = choices.elements[tc + 1];
-         int qn = choices.elements[tc + 2];
-         queue_push(&xpctx.errors, ERROR_CHOICE);
-         queue_push2(&xpctx.errors, id, who);
-         for (i = 0; i < qn; i++)
-           queue_push(&xpctx.errors, qe[i]);
-         queue_push(&xpctx.errors, 0);
-         tc += choices.elements[tc];
-       }
-    }
+      if (qq.count > 1 && doamb == 1)
+       {
+         queue_push2(&todo, id, who);
+         continue;
+       }
 
-  /* free data */
-  map_free(&xpctx.installed);
-  map_free(&xpctx.conflicts);
-  map_free(&xpctx.recommended);
-  map_free(&xpctx.todo_condmap);
-  queue_free(&xpctx.conflictsinfo);
-  queue_free(&xpctx.todo_cond);
-  queue_free(&xpctx.todo);
-  queue_free(&toinstall);
-  queue_free(&qq);
-  queue_free(&choices);
-  queue_free(&xpctx.pruneq);
-  queue_free(&xpctx.cplxq);
-  queue_free(&xpctx.cplxblks);
-
-  /* revert ignores */
-  xp->ignoreignore = oldignoreignore;
-  if (ignoremapssaved)
-    {
-      map_free(&xp->ignored);
-      map_free(&xp->ignoredx);
-      xp->ignored = oldignored;
-      xp->ignoredx = oldignoredx;
-    }
-  else
-    {
-      for (i = 0; i < revertignore.count; i++)
+      /* prioritize recommended packages. */
+      if (qq.count > 1 && doamb == 2)
+       {
+         expander_updaterecommendedmap(xp, &recommended, &recdone, out);
+         if (recommended.size)
+           {
+             for (i = j = 0; i < qq.count; i++)
+               if (MAPTST(&recommended, qq.elements[i]))
+                 qq.elements[j++] = qq.elements[i];
+             if (j)
+               queue_truncate(&qq, j);
+           }
+       }
+
+
+      if (qq.count > 1)
        {
-         id = revertignore.elements[i];
-         if (id > 0)
-           MAPCLR(&xp->ignored, id);
-         else
-           MAPCLR(&xp->ignoredx, -id);
+         queue_push(&cerrors, ERROR_CHOICE);
+         queue_push2(&cerrors, id, who);
+         for (i = 0; i < qq.count; i++)
+           queue_push(&cerrors, qq.elements[i]);
+         queue_push(&cerrors, 0);
+         /* try again later */
+         queue_push2(&todo, id, who);
+         continue;
        }
-    }
-  queue_free(&revertignore);
-
-  /* finish return queue, count errors */
+      if (xp->debug)
+       expander_dbg(xp, "added %s because of %s:%s\n", expander_solvid2name(xp, qq.elements[0]), whon ? pool_id2str(pool, whon) : "(direct)", pool_dep2str(pool, id));
+      expander_installed(xp, qq.elements[0], &installed, &conflicts, &conflictsinfo, &cidone, out, &todo);
+      doamb = 0;
+      ambcnt = todo.count;
+      queue_empty(&cerrors);
+    }
+  map_free(&installed);
+  map_free(&conflicts);
+  map_free(&recommended);
+  queue_free(&conflictsinfo);
   nerrors = 0;
-  if (xpctx.errors.count)
+  if (errors.count || cerrors.count)
     {
       queue_empty(out);
-      queue_insertn(out, 0, xpctx.errors.count, xpctx.errors.elements);
-      for (i = 0; i < out->count; i += 3)
+      for (i = 0; i < errors.count; i += 3)
        {
+         queue_push(out, errors.elements[i]);
+         queue_push(out, errors.elements[i + 1]);
+         queue_push(out, errors.elements[i + 2]);
          nerrors++;
-         if (out->elements[i] == ERROR_CHOICE)
-           while (out->elements[i + 3])
-             i++;
        }
-    }
-  queue_free(&xpctx.errors);
-  return nerrors;
-}
-
-static Expander *
-expander_create(Pool *pool, Queue *preferpos, Queue *preferneg, Queue *ignore, Queue *conflict, Queue *fileprovides, int debug, int options)
-{
-  Expander *xp;
-  int i, j;
-  Id id, id2;
-  const char *str;
-  Queue q;
-
-  xp = calloc(sizeof(Expander), 1);
-  xp->pool = pool;
-  xp->debug = debug;
-  xp->ignoreignore = options & EXPANDER_OPTION_IGNOREIGNORE ? 1 : 0;
-  xp->ignoreconflicts = options & EXPANDER_OPTION_IGNORECONFLICTS ? 1 : 0;
-  xp->userecommendsforchoices = options & EXPANDER_OPTION_USERECOMMENDSFORCHOICES ? 1 : 0;
-  xp->usesupplementsforchoices = options & EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES ? 1 : 0;
-  xp->dorecommends = options & EXPANDER_OPTION_DORECOMMENDS ? 1 : 0;
-  xp->dosupplements = options & EXPANDER_OPTION_DOSUPPLEMENTS ? 1 : 0;
-
-  queue_init(&xp->preferposq);
-  for (i = 0; i < preferpos->count; i++)
-    {
-      id = preferpos->elements[i];
-      queue_push(&xp->preferposq, id);
-      MAPEXP(&xp->preferpos, id);
-      MAPSET(&xp->preferpos, id);
-      if ((str = strchr(pool_id2str(pool, id), ':')) != 0)
-        {
-          id = str2id_dup(pool, str + 1);
-         MAPEXP(&xp->preferposx, id);
-         MAPSET(&xp->preferposx, id);
-        }
-    }
-  for (i = 0; i < preferneg->count; i++)
-    {
-      id = preferneg->elements[i];
-      MAPEXP(&xp->preferneg, id);
-      MAPSET(&xp->preferneg, id);
-      if ((str = strchr(pool_id2str(pool, id), ':')) != 0)
-        {
-          id = str2id_dup(pool, str + 1);
-         MAPEXP(&xp->prefernegx, id);
-         MAPSET(&xp->prefernegx, id);
-        }
-    }
-
-  for (i = 0; i < ignore->count; i++)
-    {
-      id = ignore->elements[i];
-      MAPEXP(&xp->ignored, id);
-      MAPSET(&xp->ignored, id);
-      if ((str = strchr(pool_id2str(pool, id), ':')) != 0)
-        {
-          id = str2id_dup(pool, str + 1);
-         MAPEXP(&xp->ignoredx, id);
-         MAPSET(&xp->ignoredx, id);
-        }
-    }
-
-  queue_init(&xp->conflictsq);
-  for (i = 0; i < conflict->count; i += 2)
-    {
-      id = conflict->elements[i];
-      id2 = conflict->elements[i + 1];
-      queue_push2(&xp->conflictsq, id, id2);
-      MAPEXP(&xp->conflicts, id);
-      MAPSET(&xp->conflicts, id);
-      MAPEXP(&xp->conflicts, id2);
-      MAPSET(&xp->conflicts, id2);
-    }
-
-  if (fileprovides->count)
-    xp->havefileprovides = 1;
-  queue_init(&q);
-  for (i = 0; i < fileprovides->count; i++)
-    {
-      Id p, pp;
-      id = fileprovides->elements[i];
-      int havenew = 0;
-
-      /* XXX: this modifies the pool, which is somewhat unclean! */
-      /* get old providers */
-      queue_empty(&q);
-      FOR_PROVIDES(p, pp, id)
-        queue_push(&q, p);
-      for (j = i + 1; j < fileprovides->count && (id2 = fileprovides->elements[j]) != 0; j++)
+      for (i = 0; i < cerrors.count; )
        {
-         FOR_PROVIDES(p, pp, id2)
+         queue_push(out, cerrors.elements[i]);
+         queue_push(out, cerrors.elements[i + 1]);
+         queue_push(out, cerrors.elements[i + 2]);
+         i += 3;
+         while (cerrors.elements[i])
            {
-             int k;
-             if (pool->solvables[p].name != id2)
-               continue;               /* match name only */
-             /* insert sorted */
-             for (k = 0; ; k++)
-               {
-                 if (k == q.count || q.elements[k] > p)
-                   {
-                     queue_insert(&q, k, p);
-                     havenew = 1;
-                     break;
-                   }
-                 if (q.elements[k] == p)
-                   break;
-               }
+             queue_push(out, cerrors.elements[i]);
+             i++;
            }
+         queue_push(out, 0);
+         i++;
+         nerrors++;
        }
-      if (havenew)
-        pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q);
-      i = j;
-    }
-  queue_free(&q);
-  return xp;
-}
-
-static void
-expander_free(Expander *xp)
-{
-  map_free(&xp->ignored);
-  map_free(&xp->ignoredx);
-  queue_free(&xp->preferposq);
-  map_free(&xp->preferpos);
-  map_free(&xp->preferposx);
-  map_free(&xp->preferneg);
-  map_free(&xp->prefernegx);
-  queue_free(&xp->conflictsq);
-  map_free(&xp->conflicts);
-  solv_free(xp->debugstr);
-  solv_free(xp);
-}
-
-
-
-static void
-set_disttype(Pool *pool, int disttype)
-{
-  pool_setdisttype(pool, disttype);
-#ifdef POOL_FLAG_HAVEDISTEPOCH
-  /* make newer mandriva work, hopefully there are no ill effects... */
-  pool_set_flag(pool, POOL_FLAG_HAVEDISTEPOCH, disttype == DISTTYPE_RPM ? 1 : 0);
-#endif
-}
-
-static void
-set_disttype_from_location(Pool *pool, Solvable *so)
-{
-  unsigned int medianr;
-  const char *s = solvable_get_location(so, &medianr);
-  int disttype = -1;
-  int sl;
-  if (!s)
-    return;
-  sl = strlen(s);
-  if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".rpm"))
-    disttype = DISTTYPE_RPM;
-#ifdef DISTTYPE_DEB
-  if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".deb"))
-    disttype = DISTTYPE_DEB;
-#endif
-#ifdef DISTTYPE_ARCH
-  if (disttype < 0 && sl >= 12 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz") || !strcmp(s + sl - 12, ".pkg.tar.zst")))
-    disttype = DISTTYPE_ARCH;
-#endif
-  if (disttype >= 0 && pool->disttype != disttype)
-    set_disttype(pool, disttype);
-}
-
-static inline const char *
-solvid2name(Pool *pool, Id p)
-{
-  return pool_id2str(pool, pool->solvables[p].name);
-}
-
-#define ISNOARCH(arch) (arch == ARCH_NOARCH || arch == ARCH_ALL || arch == ARCH_ANY)
-
-static int
-has_keyname(Repo *repo, Id keyname)
-{
-  Repodata *data;
-  int rdid;
-  FOR_REPODATAS(repo, rdid, data)
-    if (repodata_has_keyname(data, keyname))
-      return 1;
-  return 0;
-}
-
-static inline int
-match_modules_req(Pool *pool, Id id)
-{
-  const char *dep = pool_id2str(pool, id);
-  Id *modules;
-  if (strncmp(dep, "platform", 8) == 0 && (dep[8] == 0 || dep[8] == '-'))
-    return 1;
-  for (modules = pool->appdata; *modules; modules++)
-    {
-      const char *name, *rname;
-      if (*modules == id)
-       return 1;
-      name = pool_id2str(pool, *modules);
-      if ((rname = strrchr(name, '-')) == 0 || rname == name)
-       continue;
-      if (!strncmp(dep, rname, rname - name) && dep[rname - name] == 0)
-       return 1;
-    }
-  return 0;
-}
-
-static void
-create_module_map(Repo *repo, Map *modulemap, Queue *modulemapq)
-{
-  Pool *pool = repo->pool;
-  Id *modules = pool->appdata;
-  int i, have_moduleinfo = 0;
-  Id id, p, *pp;
-  Solvable *s;
-
-  if (!modulemap->size)
-    map_grow(modulemap, pool->ss.nstrings);
-  if (!modules)
-    return;
-  if (!*modules)
-    {
-      map_setall(modulemap);
-      return;
-    }
-  /* clear old bits */
-  if (modulemapq->count)
-    {
-      for (i = 0; i < modulemapq->count; i++)
-       MAPCLR(modulemap, modulemapq->elements[i]);
-      queue_empty(modulemapq);
     }
-  for (modules = pool->appdata; *modules; modules++)
-    MAPSET(modulemap, *modules);
-  /* look for module information stored in "buildservice:modules" solvables */
-  FOR_REPO_SOLVABLES(repo, p, s)
+  else
     {
-      if (s->name != buildservice_modules || s->arch != ARCH_SRC)
-       continue;
-      have_moduleinfo = 1;
-      if (s->evr >= 1 && s->evr < pool->ss.nstrings && MAPTST(modulemap, s->evr))
+      if (todo.count)
        {
-         queue_push(modulemapq, s->evr);       /* directly addressed */
-         continue;
+         fprintf(stderr, "Internal expansion error!\n");
+         queue_empty(out);
+         queue_push(out, ERROR_NOPROVIDER);
+         queue_push(out, 0);
+         queue_push(out, 0);
        }
-      id = s->repo->idarraydata[s->provides];
-      if (id < 1 || id >= pool->ss.nstrings || !MAPTST(modulemap, id))
-       continue;       /* not what we're looking for */
-      for (pp = s->repo->idarraydata + s->requires; (id = *pp) != 0; pp++)
-        {
-          /* check if the dep is fulfilled by any module in the list */
-          if (id < 1 || id >= pool->ss.nstrings)
-           break;      /* hey! */
-          if (!MAPTST(modulemap, id) && !match_modules_req(pool, id))
-           break;      /* could not fulfil requires */
-        }
-      if (id)
-       continue;       /* could not fulfil one of the requires, ignore module */
-      queue_push(modulemapq, s->evr);
-    }
-  if (!have_moduleinfo)
-    {
-      /* old style repo with no moduleinfo at all. simple use the unexpanded ids */
-      for (modules = pool->appdata; *modules; modules++)
-        queue_push(modulemapq, *modules);
-      return;
     }
-  for (modules = pool->appdata; *modules; modules++)
-    MAPCLR(modulemap, *modules);
-  for (i = 0; i < modulemapq->count; i++)
-    MAPSET(modulemap, modulemapq->elements[i]);
+  queue_free(&todo);
+  queue_free(&qq);
+  queue_free(&errors);
+  queue_free(&cerrors);
+  queue_free(&posfoundq);
+  return nerrors;
 }
 
-static int
-in_module_map(Pool *pool, Map *modulemap, Queue *modules)
+static void
+set_disttype(Pool *pool, int disttype)
 {
-  int i;
-  for (i = 0; i < modules->count; i++)
-    { 
-      Id id = modules->elements[i];
-      if (id > 1 && id < pool->ss.nstrings && MAPTST(modulemap, id))
-       return 1;
-    }
-  return 0;
+  pool_setdisttype(pool, disttype);
+#ifdef POOL_FLAG_HAVEDISTEPOCH
+  /* make newer mandriva work, hopefully there are no ill effects... */
+  pool_set_flag(pool, POOL_FLAG_HAVEDISTEPOCH, disttype == DISTTYPE_RPM ? 1 : 0);
+#endif
 }
 
-
 static void
-create_considered(Pool *pool, Repo *repoonly, Map *considered, int unorderedrepos)
+set_disttype_from_location(Pool *pool, Solvable *so)
+{
+  unsigned int medianr;
+  const char *s = solvable_get_location(so, &medianr);
+  int disttype = -1;
+  int sl;
+  if (!s)
+    return;
+  sl = strlen(s);
+  if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".rpm"))
+    disttype = DISTTYPE_RPM;
+#ifdef DISTTYPE_DEB
+  if (disttype < 0 && sl >= 4 && !strcmp(s + sl - 4, ".deb"))
+    disttype = DISTTYPE_DEB;
+#endif
+#ifdef DISTTYPE_ARCH
+  if (disttype < 0 && sl >= 12 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz") || !strcmp(s + sl - 12, ".pkg.tar.zst")))
+    disttype = DISTTYPE_ARCH;
+#endif
+  if (disttype >= 0 && pool->disttype != disttype)
+    set_disttype(pool, disttype);
+}
+
+void
+create_considered(Pool *pool, Repo *repoonly, Map *considered)
 {
   Id p, pb,*best;
   Solvable *s, *sb;
@@ -2887,70 +1278,41 @@ create_considered(Pool *pool, Repo *repoonly, Map *considered, int unorderedrepo
   Repo *repo;
   int olddisttype = -1;
   int dodrepo;
-  int mayhave_modules;
-  Queue modules;
-  Map modulemap;
-  Queue modulemapq;
-  int modulemap_uptodate;
 
   map_init(considered, pool->nsolvables);
   best = solv_calloc(sizeof(Id), pool->ss.nstrings);
   
-  queue_init(&modules);
-  map_init(&modulemap, 0);
-  queue_init(&modulemapq);
   FOR_REPOS(ridx, repo)
     {
       if (repoonly && repo != repoonly)
        continue;
       dodrepo = repo_lookup_str(repo, SOLVID_META, buildservice_dodurl) != 0;
-      mayhave_modules = has_keyname(repo, buildservice_modules) ? 1 : 0;
-      modulemap_uptodate = 0;
       FOR_REPO_SOLVABLES(repo, p, s)
        {
-         int inmodule = 0;
          if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
            continue;
          pb = best[s->name];
-         sb = pb ? pool->solvables + pb : 0;
-         if (mayhave_modules)
-           {
-             solvable_lookup_idarray(s, buildservice_modules, &modules);
-             inmodule = modules.count ? 1 : 0;
-             if (inmodule)
-               {
-                 if (!modulemap_uptodate)
-                   {
-                     create_module_map(repo, &modulemap, &modulemapq);
-                     modulemap_uptodate = 1;
-                   }
-                 if (!in_module_map(pool, &modulemap, &modules))
-                   continue;           /* nope, ignore package */
-               }
-           }
-         if (unorderedrepos && sb && s->repo->priority != sb->repo->priority)
-           {
-             if (s->repo->priority < sb->repo->priority)
-               continue;       /* lower prio, ignore */
-           }
-         else if (sb)
+         if (pb)
            {
-             int sbinmodule = 0;
-             /* we already have that name. decide which one to take */
-             if (!unorderedrepos && s->repo != sb->repo)
+             sb = pool->solvables + pb;
+             if (s->repo != sb->repo)
                continue;       /* first repo wins */
-
-             if (s->repo == sb->repo && mayhave_modules)
-               sbinmodule = solvable_lookup_type(sb, buildservice_modules) ? 1 : 0;
-
-             if (inmodule != sbinmodule)
+             if (s->arch != sb->arch)
                {
-                 if (inmodule < sbinmodule)
+                 int r;
+                 if (s->arch == ARCH_NOARCH || s->arch == ARCH_ALL || s->arch == ARCH_ANY)
                    continue;
+                 if (sb->arch != ARCH_NOARCH && sb->arch != ARCH_ALL && sb->arch != ARCH_ANY)
+                   {
+                     /* the strcmp is kind of silly, but works for most archs */
+                     r = strcmp(pool_id2str(pool, sb->arch), pool_id2str(pool, s->arch));
+                     if (r >= 0)
+                       continue;
+                   }
                }
              else if (s->evr != sb->evr)
                {
-                 /* check versions */
+                 /* same repo, check versions */
                  int r;
                  if (olddisttype < 0)
                    {
@@ -2958,27 +1320,16 @@ create_considered(Pool *pool, Repo *repoonly, Map *considered, int unorderedrepo
                      set_disttype_from_location(pool, s);
                    }
                  r = pool_evrcmp(pool, sb->evr, s->evr, EVRCMP_COMPARE);
-                 if (r == 0)
-                   r = strcmp(pool_id2str(pool, sb->evr), pool_id2str(pool, s->evr));
-                 if (r >= 0)
-                   continue;
-               }
-             else if (s->arch != sb->arch)
-               {
-                 /* same versions, check arch */
-                 if (ISNOARCH(sb->arch) && !ISNOARCH(s->arch))
+                 if (r > 0)
                    continue;
-                 if (ISNOARCH(sb->arch) || !ISNOARCH(s->arch))
+                 else if (r == 0)
                    {
-                     int r;
-                     /* the strcmp is kind of silly, but works for most archs */
-                     r = strcmp(pool_id2str(pool, sb->arch), pool_id2str(pool, s->arch));
+                     r = strcmp(pool_id2str(pool, sb->evr), pool_id2str(pool, s->evr));
                      if (r >= 0)
                        continue;
                    }
                }
            }
-
           if (dodrepo)
            {
              /* we only consider dod packages */
@@ -2991,7 +1342,7 @@ create_considered(Pool *pool, Repo *repoonly, Map *considered, int unorderedrepo
          best[s->name] = p;
          MAPSET(considered, p);
        }
-      /* dodrepos have a second pass: replace dod entries with identical downloaded ones */
+      /* dodrepos have a second pass: replace dod entries with downloaded ones */
       if (dodrepo)
        {
          const char *bsid;
@@ -3015,18 +1366,15 @@ create_considered(Pool *pool, Repo *repoonly, Map *considered, int unorderedrepo
        }
     }
   solv_free(best);
-  queue_free(&modules);
-  map_free(&modulemap);
-  queue_free(&modulemapq);
   if (olddisttype >= 0 && pool->disttype != olddisttype)
     set_disttype(pool, olddisttype);
 }
 
 struct metaline {
-  char *l;             /* pointer to line */
-  int lastoff;         /* line offset of last path element */
-  int nslash;          /* number of slashes */
-  int killed;          /* 1: line has been killed. 2: because of a cycle package */
+  char *l;
+  int lastoff;
+  int nslash;
+  int killed;
 };
 
 static int metacmp(const void *ap, const void *bp)
@@ -3048,87 +1396,6 @@ static int metacmp(const void *ap, const void *bp)
   return a - b;
 }
 
-static char *
-slurp(FILE *fp, int *lenp)
-{
-  int l, ll;
-  char *buf = 0; 
-  int bufl = 0; 
-
-  for (l = 0; ; l += ll)
-    {    
-      if (bufl - l < 4096)
-        {
-          bufl += 4096;
-         if (bufl < 0)
-           {
-             buf = solv_free(buf);
-             l = 0;
-             break;
-           }
-          buf = solv_realloc(buf, bufl);
-        }
-      ll = fread(buf + l, 1, bufl - l, fp); 
-      if (ll < 0) 
-        {
-          buf = solv_free(buf);
-          l = 0; 
-          break;
-        }
-      if (ll == 0)
-        {
-          buf[l] = 0;   /* always zero-terminate */
-          break;
-        }
-    }    
-  if (lenp)
-    *lenp = l; 
-  return buf; 
-}
-
-
-Id
-repo_add_obsbinlnk(Repo *repo, const char *path, int flags)
-{
-  Repodata *data;
-  FILE *fp;
-  char *buf;
-  int len;
-  SV *sv;
-  unsigned char *src;
-  STRLEN srcl;
-  Id p;
-
-  if ((fp = fopen(path, "r")) == 0)
-    return 0;
-  buf = slurp(fp, &len);
-  fclose(fp);
-  if (!buf || len <= 0)
-    return 0;
-  src = (unsigned char *)buf;
-  srcl = len;
-  sv = 0;
-  if (srcl >= 7 && src[0] == 'p' && src[1] == 's' && src[2] == 't' && src[3] == '0' && (src[4] & 1) == 1 && src[4] >= 5) {
-    src += 6;
-    srcl -= 6;
-    sv = retrieve(&src, &srcl, 0);
-  }
-  free(buf);
-  if (!sv)
-    return 0;
-  if (SvTYPE(sv) != SVt_PVHV)
-    {
-      SvREFCNT_dec(sv);
-      return 0;
-    }
-  data = repo_add_repodata(repo, flags);
-  p = data2pkg(repo, data, (HV *)sv, 0);
-  SvREFCNT_dec(sv);
-  if (!(flags & REPO_NO_INTERNALIZE))
-    repodata_internalize(data);
-  return p;
-}
-
 #ifndef REPO_NO_LOCATION
 # define REPO_NO_LOCATION 0
 #endif
@@ -3145,20 +1412,9 @@ repodata_addbin(Repodata *data, char *prefix, char *s, int sl, char *sid)
   path = solv_dupjoin(prefix, "/", s);
   if (sl >= 4 && !strcmp(s + sl - 4, ".rpm"))
     p = repo_add_rpm(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|RPM_ADD_WITH_PKGID|RPM_ADD_NO_FILELIST|RPM_ADD_NO_RPMLIBREQS);
-#if defined(LIBSOLVEXT_FEATURE_DEBIAN)
   else if (sl >= 4 && !strcmp(s + sl - 4, ".deb"))
     p = repo_add_deb(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|DEBS_ADD_WITH_PKGID);
-#endif
-  else if (sl >= 10 && !strcmp(s + sl - 10, ".obsbinlnk"))
-    {
-      p = repo_add_obsbinlnk(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION);
-      /* do not overwrite location from obsbinlnk file */
-      solv_free(path);
-      if (p)
-        repodata_set_str(data, p, buildservice_id, sid);
-      return p;
-    }
-#if defined(LIBSOLVEXT_FEATURE_ARCHREPO) && defined(ARCH_ADD_WITH_PKGID)
+#ifdef ARCH_ADD_WITH_PKGID
   else if (sl >= 12 && (!strcmp(s + sl - 11, ".pkg.tar.gz") || !strcmp(s + sl - 11, ".pkg.tar.xz") || !strcmp(s + sl - 12, ".pkg.tar.zst")))
     p = repo_add_arch_pkg(data->repo, (const char *)path, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|ARCH_ADD_WITH_PKGID);
 #endif
@@ -5229,173 +3485,38 @@ printobscpioinstr(FILE *fp, int fdstore, int withmeta)
   printf("stats file_size %lld\n", (unsigned long long)ftell(fp));
 }
 
-static int
-unifymodules_cmp(const void *ap, const void *bp, void *dp)
-{
-  return *(Id *)ap - *(Id *)bp;
-}
-
-static int
-missingmodules_cmp(const void *ap, const void *bp, void *dp)
-{
-  const Id *a = ap;
-  const Id *b = bp;
-  if (a[0] != b[0])
-    return a[0] - b[0];
-  if (!a[1] && b[1])
-    return -1;
-  if (!b[1] && a[1])
-    return 1;
-  return a[1] - b[1];
-}
-
-static int
-is_dod_package(Solvable *s)
-{
-  const char *str = solvable_lookup_str(s, buildservice_id);
-  return str && !strcmp(str, "dod") ? 1 : 0;
-}
-
-static Solvable *
-find_corresponding_dod(Solvable *s)
-{
-  Repo *repo = s->repo;
-  Id p2;
-  Solvable *s2;
-
-  if (!repo)
-    return 0;
-  FOR_REPO_SOLVABLES(repo, p2, s2)
-    {
-      if (s->name == s2->name && s->evr == s2->evr && s->arch == s2->arch && s != s2 && is_dod_package(s2))
-       return s2;
-    }
-  return 0;
-}
-
-struct scc_data {
-  Id *edata;
-  Id *vedge;
-  Queue *sccs;
-  int *stack;
-  int nstack;
-  int *low;
-  int idx;
-};
-
-static void
-scc_collect(struct scc_data *scc, int node)
-{
-  int *low = scc->low;
-  Id *e;
-  queue_push(scc->sccs, node);
-  low[node] = -1;
-  for (e = scc->edata + scc->vedge[node]; *e; e++)
-    if (*e != -1 && low[*e] > 0)
-      scc_collect(scc, *e);
-}
-
-/* Tarjan's SCC algorithm */
-static int
-scc_visit(struct scc_data *scc, int node)
-{
-  int l, myidx, *low = scc->low, nontrivial = 0;
-  Id *e;
-  low[node] = myidx = scc->idx++;
-  for (e = scc->edata + scc->vedge[node]; *e; e++)
-    {
-      if (*e == -1 || *e == node)
-       continue;
-      if (!(l = low[*e]))
-       l = scc_visit(scc, *e);
-      if (l > 0)
-       nontrivial = 1;
-      if (l > 0 && l < low[node])
-       low[node] = l;
-    }
-  if (low[node] != myidx)
-    return low[node];
-  low[node] = -1;
-  if (nontrivial)
-    {
-      scc_collect(scc, node);
-      queue_push(scc->sccs, 0);
-    }
-  return -1;
-}
-
-static void
-find_sccs(Queue *edata, Queue *vedge, Queue *sccs)
-{
-  struct scc_data scc;
-  int i;
-  scc.edata = edata->elements;
-  scc.vedge = vedge->elements;
-  scc.sccs = sccs;
-  scc.low = solv_calloc(vedge->count, sizeof(int));
-  scc.idx = 1;
-  for (i = 1; i < vedge->count; i++)
-    if (!scc.edata[vedge->elements[i]])
-      scc.low[i] = -1;
-  for (i = 1; i < vedge->count; i++)
-    if (!scc.low[i])
-      scc_visit(&scc, i);
-  solv_free(scc.low);
-}
-
-
 MODULE = BSSolv                PACKAGE = BSSolv
 
 void
 depsort(HV *deps, SV *mapp, SV *cycp, ...)
-    ALIAS:
-       depsort2 = 1
     PPCODE:
        {
            int i, j, k, cy, cycstart, nv;
-           int pkgstart = 3;
            SV *sv, **svp;
-           SV *pkg2srcp = 0;
            Id id, *e;
            Id *mark;
            char **names;
-           char **depnames;
            Hashtable ht;
            Hashval h, hh, hm;
            HV *mhv = 0;
-           HV *pkg2srchv = 0;
 
            Queue edata;
            Queue vedge;
            Queue todo;
            Queue cycles;
-           Map edgeunifymap;
-           int didsccs = 0;
 
-           if (ix)
-             {
-               /* called as depsort2 */
-               if (items < 4)
-                 XSRETURN_EMPTY; /* nothing to sort */
-               pkgstart = 4;
-               pkg2srcp = cycp;
-               cycp = ST(3);
-             }
-           if (items == pkgstart)
+           if (items == 3)
              XSRETURN_EMPTY; /* nothing to sort */
-           if (items == pkgstart + 1)
+           if (items == 4)
              {
                /* only one item */
-               char *s = SvPV_nolen(ST(pkgstart));
+               char *s = SvPV_nolen(ST(3));
                EXTEND(SP, 1);
                sv = newSVpv(s, 0);
                PUSHs(sv_2mortal(sv));
                XSRETURN(1); /* nothing to sort */
              }
 
-           if (pkg2srcp && SvROK(pkg2srcp) && SvTYPE(SvRV(pkg2srcp)) == SVt_PVHV)
-             pkg2srchv = (HV *)SvRV(pkg2srcp);
-
            if (mapp && SvROK(mapp) && SvTYPE(SvRV(mapp)) == SVt_PVHV)
              mhv = (HV *)SvRV(mapp);
 
@@ -5406,11 +3527,9 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...)
 
            hm = mkmask(items);
            ht = solv_calloc(hm + 1, sizeof(*ht));
-           names = depnames = solv_calloc(items, sizeof(char *));
-
-           /* create pkgname -> edge hash, store edge -> pkgname data */
+           names = solv_calloc(items, sizeof(char *));
            nv = 1;
-           for (i = pkgstart; i < items; i++)
+           for (i = 3; i < items; i++)
              {
                char *s = SvPV_nolen(ST(i));
                h = strhash(s) & hm;
@@ -5428,40 +3547,14 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...)
                names[id] = s;
              }
 
-           if (pkg2srchv)
-             {
-               /* redo the hash with src names instead of pkg names */
-               depnames = solv_calloc(nv, sizeof(char *));
-               memset(ht, 0, (hm + 1) * sizeof(*ht));
-               for (i = 1; i < nv; i++)
-                 {
-                   char *s = names[i];
-                   svp = hv_fetch(pkg2srchv, s, strlen(s), 0);
-                   if (svp)
-                     {
-                       char *ns = SvPV_nolen(*svp);
-                       if (ns)
-                         s = ns;
-                     }
-                   depnames[i] = s;
-                   h = strhash(s) & hm;
-                   hh = HASHCHAIN_START;
-                   while ((id = ht[h]) != 0)
-                     h = HASHCHAIN_NEXT(h, hh, hm);
-                   ht[h] = i;
-                 }
-             }
-
            /* we now know all vertices, create edges */
            queue_push(&vedge, 0);
            queue_push(&edata, 0);
-           map_init(&edgeunifymap, nv);
            for (i = 1; i < nv; i++)
              {
-               int edgestart = edata.count;
                svp = hv_fetch(deps, names[i], strlen(names[i]), 0);
                sv = svp ? *svp : 0;
-               queue_push(&vedge, edgestart);
+               queue_push(&vedge, edata.count);
                if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV)
                  {
                    AV *av = (AV *)SvRV(sv);
@@ -5493,35 +3586,20 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...)
                        hh = HASHCHAIN_START;
                        while ((id = ht[h]) != 0)
                          {
-                           if (!strcmp(depnames[id], s))
-                             {
-                               if (id != i && !MAPTST(&edgeunifymap, id))
-                                 {
-                                   MAPSET(&edgeunifymap, id);
-                                   queue_push(&edata, id);
-                                 }
-                               if (names == depnames)
-                                 break;        /* no other entry with same name */
-                             }
+                           if (!strcmp(names[id], s))
+                             break;
                            h = HASHCHAIN_NEXT(h, hh, hm);
                          }
+                       if (!id)
+                         continue;     /* not known, ignore */
+                       if (id == i)
+                         continue;     /* no self edge */
+                       queue_push(&edata, id);
                      }
                  }
-               for (j = edgestart; j < edata.count; j++)
-                 {
-#ifdef MAPCLR_AT
-                   MAPCLR_AT(&edgeunifymap, edata.elements[j]);
-#else
-                   MAPCLR(&edgeunifymap, edata.elements[j]);
-#endif
-                 }
-               queue_push(&edata, 0);  /* terminate edge array */
+               queue_push(&edata, 0);
              }
-           /* free no longer needed stuff */
-           map_free(&edgeunifymap);
            solv_free(ht);
-           if (depnames != names)
-             depnames = solv_free(depnames);
 
            if (0)
              {
@@ -5581,13 +3659,6 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...)
                    continue;
                  }
                /* oh no, we found a cycle, record and break it */
-               if (depsortsccs && !didsccs && cycp)
-                 {
-                   /* use Tarjan's SCC algorithm */
-                   find_sccs(&edata, &vedge, &cycles);
-                   queue_push(&cycles, 0);
-                   didsccs = cycles.count;
-                 }
                cy = cycles.count;
                for (j = todo.count - 1; j >= 0; j--)
                  if (todo.elements[j] == -i)
@@ -5623,10 +3694,7 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...)
                todo.count = cycstart + 1;
              }
 
-           if (didsccs && depsortsccs != 2)
-             queue_truncate(&cycles, didsccs - 1);
-
-           /* record cycles */
+           /* recored cycles */
            if (cycles.count && cycp && SvROK(cycp) && SvTYPE(SvRV(cycp)) == SVt_PVAV)
              {
                AV *av = (AV *)SvRV(cycp);
@@ -5651,27 +3719,6 @@ depsort(HV *deps, SV *mapp, SV *cycp, ...)
            solv_free(names);
        }
 
-int
-setdepsortsccs(int flag)
-    CODE:
-       depsortsccs = flag;
-       RETVAL = flag;
-    OUTPUT:
-       RETVAL
-
-int
-setgenmetaalgo(int algo)
-    CODE:
-       if (algo < 0)
-           algo = 1;
-       if (algo > 1)
-           croak("BSSolv::setgenmetaalgo: unsupported algo %d\n", algo);
-       genmetaalgo = algo;
-       RETVAL = algo;
-    OUTPUT:
-       RETVAL
-
-
 void
 gen_meta(AV *subp, ...)
     PPCODE:
@@ -5757,7 +3804,7 @@ gen_meta(AV *subp, ...)
                  }
                if (cycle)
                  {
-                   lp->killed = 1;     /* killed because line includes a subpackage */
+                   lp->killed = 1;
                    if (cycle > 1)      /* ignore self cycles */
                      queue_push(&cycles, i);
                  }
@@ -5773,9 +3820,9 @@ gen_meta(AV *subp, ...)
                char *cycledata = 0;
                int cycledatalen = 0;
 
-               /* create hash of cycle packages */
                cycledata = solv_extend(cycledata, cycledatalen, 1, 1, 255);
-               cycledata[cycledatalen++] = 0;
+               cycledata[0] = 0;
+               cycledatalen += 1;
                hm = mkmask(cycles.count);
                ht = solv_calloc(hm + 1, sizeof(*ht));
                for (i = 0; i < cycles.count; i++)
@@ -5793,23 +3840,18 @@ gen_meta(AV *subp, ...)
                          break;
                        h = HASHCHAIN_NEXT(h, hh, hm);
                      }
-                   if (!id)
-                     {
-                       int l = strlen(s);
-                       cycledata = solv_extend(cycledata, cycledatalen, l + 1, 1, 255);
-                       ht[h] = cycledatalen;   /* point to name */
-                       strcpy(cycledata + cycledatalen, s);
-                       cycledatalen += l + 1;
-                     }
+                   if (id)
+                     continue;
+                   cycledata = solv_extend(cycledata, cycledatalen, strlen(s) + 1, 1, 255);
+                   ht[h] = cycledatalen;
+                   strcpy(cycledata + cycledatalen, s);
+                   cycledatalen += strlen(s) + 1;
                    if (se)
                      *se = '/';
                  }
-
                for (i = 0, lp = lines; i < nlines; i++, lp++)
                  {
-                   if (!lp->nslash)
-                     continue;
-                   if (lp->killed && genmetaalgo == 0)
+                   if (lp->killed || !lp->nslash)
                      continue;
                    lo = strchr(lp->l + 34, '/') + 1;
                    for (s2 = lo; *s2; s2++)
@@ -5827,12 +3869,12 @@ gen_meta(AV *subp, ...)
                          *s2 = '/';
                          if (id)
                            {
-                             lp->killed = 2;   /* killed because it containes a cycle package */
+                             lp->killed = 1;
                              break;
                            }
                          lo = s2 + 1;
                        }
-                   if (lp->killed == 2)
+                   if (lp->killed)
                      continue;
                    h = strhash(lo) & hm;
                    hh = HASHCHAIN_START;
@@ -5843,12 +3885,14 @@ gen_meta(AV *subp, ...)
                        h = HASHCHAIN_NEXT(h, hh, hm);
                      }
                    if (id)
-                     lp->killed = 2;   /* killed because it containes a cycle package */
+                     {
+                       lp->killed = 1;
+                     }
                  }
                solv_free(ht);
                cycledata = solv_free(cycledata);
+               queue_free(&cycles);
              }
-           queue_free(&cycles);
 
            /* cycles are pruned, now sort array */
            if (nlines > 1)
@@ -5859,10 +3903,7 @@ gen_meta(AV *subp, ...)
            for (i = 0, lp = lines; i < nlines; i++, lp++)
              {
                if (lp->killed)
-                 {
-                   if (genmetaalgo == 0 || lp->killed != 2)
-                     continue;
-                 }
+                 continue;
                s = lp->l;
                h = strnhash(s, 10);
                h = strhash_cont(s + lp->lastoff, h) & hm;
@@ -5874,13 +3915,6 @@ gen_meta(AV *subp, ...)
                      break;
                    h = HASHCHAIN_NEXT(h, hh, hm);
                  }
-               if (id && genmetaalgo == 1 && lp->killed == 2)
-                 {
-                   /* also kill old line of same level */
-                   struct metaline *lp2 = lines + (id - 1);
-                   if (!lp2->killed && lp2->nslash == lp->nslash)
-                     lp2->killed = 1;
-                 }
                if (id)
                  lp->killed = 1;
                else
@@ -5903,66 +3937,6 @@ gen_meta(AV *subp, ...)
            solv_free(lines);
        }
 
-void
-add_meta(AV *new_meta, SV *sv, const char *bin, const char *packid = 0)
-    PPCODE:
-       {
-           const char *p, *np;
-           char *buf;
-           size_t l, bufl, binl, packidl;
-           int first = 1;
-           if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV) {
-               AV *av = (AV *)SvRV(sv);
-               SV **svp = av_fetch(av, 0, 0);
-               sv = svp ? *svp : 0;
-           }
-           if (!sv)
-               XSRETURN_EMPTY;
-           p = SvPV_nolen(sv);
-           binl = strlen(bin);
-           bufl = binl + 256;
-           buf = malloc(bufl);
-           if (!buf) {
-               croak("out of mem\n");
-               XSRETURN_EMPTY;
-           }
-           packidl = packid ? strlen(packid) : 0;
-           for (;;) {
-               np = strchr(p, '\n');
-               l = np ? np - p : strlen(p);
-               if (l > 34) {
-                   if (l + binl + 1 + 1 > bufl) {
-                       bufl = l + binl + 256;
-                       buf = realloc(buf, bufl);
-                       if (!buf) {
-                           croak("out of mem\n");
-                           XSRETURN_EMPTY;
-                       }
-                   }
-                   strncpy(buf, p, 34);
-                   strcpy(buf + 34, bin);
-                   buf[34 + binl] = '/';
-                   strncpy(buf + 34 + binl + 1, p + 34, l - 34);
-                   l += binl + 1;
-                   buf[l] = 0;
-                   if (first) {
-                       if (packidl && l > packidl + 1 && buf[l - packidl - 1] == '/' && !strcmp(buf + l - packidl, packid)) {
-                           free(buf);
-                           XSRETURN_EMPTY;
-                       }
-                       l = 34 + binl;
-                       buf[l] = 0;
-                       first = 0;
-                   }
-                   av_push(new_meta, newSVpvn(buf, l));
-               }
-               if (!np)
-                   break;
-               p = np + 1;
-           }
-           free(buf);
-       }
-
 SV *
 thawcache(SV *sv)
     CODE:
@@ -6292,9 +4266,6 @@ new(char *packname = "BSSolv::pool")
            buildservice_dodurl = pool_str2id(pool, "buildservice:dodurl", 1);
            expander_directdepsend = pool_str2id(pool, "-directdepsend--", 1);
            buildservice_dodcookie = pool_str2id(pool, "buildservice:dodcookie", 1);
-           buildservice_dodresources = pool_str2id(pool, "buildservice:dodresources", 1);
-           buildservice_annotation = pool_str2id(pool, "buildservice:annotation", 1);
-           buildservice_modules = pool_str2id(pool, "buildservice:modules", 1);
            pool_freeidhashes(pool);
            RETVAL = pool;
        }
@@ -6371,7 +4342,6 @@ repofrombins(BSSolv::pool pool, char *name, char *dir, ...)
                  continue;
                if (strcmp(s + sl - 4, ".rpm")
                     && strcmp(s + sl - 4, ".deb")
-                    && (sl < 10 || strcmp(s + sl - 10, ".obsbinlnk"))
 #ifdef ARCH_ADD_WITH_PKGID
                     && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.gz"))
                     && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.xz"))
@@ -6395,16 +4365,14 @@ repofrombins(BSSolv::pool pool, char *name, char *dir, ...)
        RETVAL
 
 BSSolv::repo
-repofromdata(BSSolv::pool pool, char *name, SV *rv)
+repofromdata(BSSolv::pool pool, char *name, HV *rhv)
     CODE:
        {
            Repo *repo;
            Repodata *data;
-           if (!SvROK(rv) || (SvTYPE(SvRV(rv)) != SVt_PVHV && SvTYPE(SvRV(rv)) != SVt_PVAV))
-               croak("BSSolv::pool::repofromdata: rv is not a HASH or ARRAY reference");
            repo = repo_create(pool, name);
            data = repo_add_repodata(repo, 0);
-           data2solvables(repo, data, SvRV(rv), 0);
+           data2solvables(repo, data, rhv);
            if (name && !strcmp(name, "/external/"))
              repodata_set_void(data, SOLVID_META, buildservice_external);
            repo_internalize(repo);
@@ -6414,7 +4382,7 @@ repofromdata(BSSolv::pool pool, char *name, SV *rv)
        RETVAL
 
 void
-createwhatprovides(BSSolv::pool pool, int unorderedrepos = 0)
+createwhatprovides(BSSolv::pool pool)
     CODE:
        if (pool->considered)
          {
@@ -6422,7 +4390,7 @@ createwhatprovides(BSSolv::pool pool, int unorderedrepos = 0)
            solv_free(pool->considered);
          }
        pool->considered = solv_calloc(sizeof(Map), 1);
-       create_considered(pool, 0, pool->considered, unorderedrepos);
+       create_considered(pool, 0, pool->considered);
        pool_createwhatprovides(pool);
 
 void
@@ -6435,7 +4403,7 @@ whatprovides(BSSolv::pool pool, char *str)
     PPCODE:
        {
            Id p, pp, id;
-           id = testcase_str2dep(pool, str);
+           id = dep2id(pool, str);
            if (id)
              FOR_PROVIDES(p, pp, id)
                XPUSHs(sv_2mortal(newSViv((IV)p)));
@@ -6448,7 +4416,7 @@ whatrequires(BSSolv::pool pool, char *str)
            Id p, id;
            Id *pp;
            Solvable *s;
-           id = testcase_str2dep(pool, str);
+           id = dep2id(pool, str);
            if (id)
              {
                for (p = 2; p < pool->nsolvables; p++)
@@ -6502,20 +4470,6 @@ pkg2name(BSSolv::pool pool, int p)
     OUTPUT:
        RETVAL
 
-const char *
-pkg2evr(BSSolv::pool pool, int p)
-    CODE:
-       RETVAL = pool_id2str(pool, pool->solvables[p].evr);
-    OUTPUT:
-       RETVAL
-
-const char *
-pkg2arch(BSSolv::pool pool, int p)
-    CODE:
-       RETVAL = pool_id2str(pool, pool->solvables[p].arch);
-    OUTPUT:
-       RETVAL
-
 const char *
 pkg2srcname(BSSolv::pool pool, int p)
     CODE:
@@ -6601,33 +4555,6 @@ pkg2checksum(BSSolv::pool pool, int p)
     OUTPUT:
        RETVAL
 
-int
-pkg2inmodule(BSSolv::pool pool, int p)
-    CODE:
-       RETVAL = solvable_lookup_type(pool->solvables + p, buildservice_modules) != 0;
-    OUTPUT:
-       RETVAL
-
-void
-pkg2modules(BSSolv::pool pool, int p)
-    PPCODE:
-       {
-         Solvable *s = pool->solvables + p;
-         Queue modules;
-         int i;
-         queue_init(&modules);
-         solvable_lookup_idarray(s, buildservice_modules, &modules);
-         if (!modules.count && !is_dod_package(s))
-           {
-             Solvable *s2 = find_corresponding_dod(s);
-             if (s2)
-               solvable_lookup_idarray(s2, buildservice_modules, &modules);
-           }
-         for (i = 0; i < modules.count; i++)
-           XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, modules.elements[i]), 0)));
-         queue_free(&modules);
-       }
-
 int
 verifypkgchecksum(BSSolv::pool pool, int p, char *path)
     CODE:
@@ -6713,34 +4640,10 @@ pkg2data(BSSolv::pool pool, int p)
            ss = solvable_lookup_str(s, buildservice_id);
            if (ss)
              (void)hv_store(RETVAL, "id", 2, newSVpv(ss, 0), 0);
-           ss = solvable_lookup_str(s, buildservice_annotation);
-           if (ss)
-             (void)hv_store(RETVAL, "annotation", 10, newSVpv(ss, 0), 0);
-           if (solvable_lookup_type(s, buildservice_modules))
-             {
-               Queue modules;
-               int i;
-               queue_init(&modules);
-               solvable_lookup_idarray(s, buildservice_modules, &modules);
-               if (modules.count)
-                 {
-                   AV *av = newAV();
-                   for (i = 0; i < modules.count; i++)
-                     av_push(av, newSVpv(pool_id2str(pool, modules.elements[i]), 0));
-                   (void)hv_store(RETVAL, "modules", 7, newRV_noinc((SV*)av), 0);
-                 }
-             }
        }
     OUTPUT:
        RETVAL
 
-const char *
-pkg2annotation(BSSolv::pool pool, int p)
-    CODE:
-       RETVAL = solvable_lookup_str(pool->solvables + p, buildservice_annotation);
-    OUTPUT:
-       RETVAL
-
 void
 repos(BSSolv::pool pool)
     PPCODE:
@@ -6855,35 +4758,9 @@ preparehashes(BSSolv::pool pool, char *prp, SV *gctxprpnotreadysv = 0)
            sv = newRV_noinc((SV *)notready);
            PUSHs(sv_2mortal(sv));
            sv = newRV_noinc((SV *)subpacks);
-           PUSHs(sv_2mortal(sv));
-       }
-
-void
-setmodules(BSSolv::pool pool, AV *modulesav)
-    CODE:
-       {
-         SSize_t i, n = av_len(modulesav);
-         pool->appdata = solv_free(pool->appdata);
-         if (n >= 0 && n < 1000000)
-           {
-             Id *modules = pool->appdata = solv_calloc(n + 2, sizeof(Id));
-             for (i = 0; i <= n; i++)
-               modules[i] = pool_str2id(pool, avlookupstr(modulesav, i), 1);
-             modules[i] = 0;
-           }
+           PUSHs(sv_2mortal(sv));
        }
 
-void
-getmodules(BSSolv::pool pool)
-    PPCODE:
-       if (pool->appdata)
-         {
-           Id *modules = pool->appdata;
-           int i;
-           for (i = 0; modules[i]; i++)
-             XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, modules[i]), 0)));
-         }
-
 void
 DESTROY(BSSolv::pool pool)
     CODE:
@@ -6892,7 +4769,6 @@ DESTROY(BSSolv::pool pool)
            map_free(pool->considered);
            pool->considered = solv_free(pool->considered);
          }
-       pool->appdata = solv_free(pool->appdata);
        pool_free(pool);
 
 
@@ -6900,24 +4776,6 @@ DESTROY(BSSolv::pool pool)
 
 MODULE = BSSolv                PACKAGE = BSSolv::repo          PREFIX = repo
 
-void
-freerepo(BSSolv::repo repo)
-    CODE:
-       {
-         repo_free(repo, 1);
-       }
-
-void
-allpackages(BSSolv::repo repo)
-    PPCODE:
-       {
-           Id p;
-           Solvable *s;
-           EXTEND(SP, repo->nsolvables);
-           FOR_REPO_SOLVABLES(repo, p, s)
-             PUSHs(sv_2mortal(newSViv(p)));
-       }
-
 void
 pkgnames(BSSolv::repo repo)
     PPCODE:
@@ -6926,8 +4784,8 @@ pkgnames(BSSolv::repo repo)
            Id p;
            Solvable *s;
            Map c;
-
-           create_considered(pool, repo, &c, 0);
+       
+           create_considered(pool, repo, &c);
            EXTEND(SP, 2 * repo->nsolvables);
            FOR_REPO_SOLVABLES(repo, p, s)
              {
@@ -6950,7 +4808,7 @@ pkgpaths(BSSolv::repo repo)
            const char *str;
            unsigned int medianr;
        
-           create_considered(pool, repo, &c, 0);
+           create_considered(pool, repo, &c);
            EXTEND(SP, 2 * repo->nsolvables);
            FOR_REPO_SOLVABLES(repo, p, s)
              {
@@ -7066,7 +4924,7 @@ updatefrombins(BSSolv::repo repo, char *dir, ...)
                      continue;
                    h = strhash(str) & hm;
                    hh = HASHCHAIN_START;
-                   while (ht[h])
+                   while ((id = ht[h]) != 0)
                      h = HASHCHAIN_NEXT(h, hh, hm);
                    ht[h] = p;
                  }
@@ -7082,14 +4940,12 @@ updatefrombins(BSSolv::repo repo, char *dir, ...)
                  continue;
                if (strcmp(s + sl - 4, ".rpm")
                     && strcmp(s + sl - 4, ".deb")
-                    && (sl < 10 || strcmp(s + sl - 10, ".obsbinlnk"))
 #ifdef ARCH_ADD_WITH_PKGID
                     && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.gz"))
                     && (sl < 11 || strcmp(s + sl - 11, ".pkg.tar.xz"))
                     && (sl < 12 || strcmp(s + sl - 12, ".pkg.tar.zst"))
 #endif
                   )
-                 continue;
                if (sl > 10 && !strcmp(s + sl - 10, ".patch.rpm"))
                  continue;
                if (sl > 10 && !strcmp(s + sl - 10, ".nosrc.rpm"))
@@ -7103,12 +4959,12 @@ updatefrombins(BSSolv::repo repo, char *dir, ...)
                    const char *str = solvable_lookup_str(pool->solvables + id, buildservice_id);
                    if (!strcmp(str, sid))
                      {
-                       /* check location (unless it's a obsbinlnk where the location comes from the content) */
+                       /* check location */
                        unsigned int medianr;
                        str = solvable_get_location(pool->solvables + id, &medianr);
                        if (str[0] == '.' && str[1] == '/')
                          str += 2;
-                       if (!strcmp(str, s) || (sl >= 10 && !strcmp(s + sl - 10, ".obsbinlnk")))
+                       if (!strcmp(str, s))
                          break;
                      }
                    h = HASHCHAIN_NEXT(h, hh, hm);
@@ -7166,139 +5022,6 @@ updatefrombins(BSSolv::repo repo, char *dir, ...)
     OUTPUT:
        RETVAL
 
-void
-modulesfrombins(BSSolv::repo repo, ...)
-    PPCODE:
-       {
-           Pool *pool = repo->pool;
-           Hashtable ht;
-           Hashval h, hh, hm;
-           Queue modules;
-           Queue collectedmodules;
-            Id p, lastid;
-           Solvable *s;
-           int i, j;
-
-           queue_init(&collectedmodules);
-           queue_init(&modules);
-           hm = mkmask(2 * repo->nsolvables + 1);
-           ht = solv_calloc(hm + 1, sizeof(*ht));
-           FOR_REPO_SOLVABLES(repo, p, s)
-             {
-               const char *bsid = solvable_lookup_str(s, buildservice_id);
-               if (!bsid)
-                 continue;
-               if (!strcmp(bsid, "dod"))
-                 h = s->name + s->evr * 37 + s->arch * 129;
-               else
-                 h = strhash(bsid);
-               h &= hm;
-               hh = HASHCHAIN_START;
-               while (ht[h])
-                 h = HASHCHAIN_NEXT(h, hh, hm);
-               ht[h] = p;
-             }
-
-           for (i = 1; i + 1 < items; i += 2)
-             {
-               const char *bsid = SvPV_nolen(ST(i + 1));
-               h = strhash(bsid) & hm;
-               hh = HASHCHAIN_START;
-               while ((p = ht[h]) != 0)
-                 {
-                   const char *bsid2 = solvable_lookup_str(pool->solvables + p, buildservice_id);
-                   if (!strcmp(bsid, bsid2))
-                     break;
-                   h = HASHCHAIN_NEXT(h, hh, hm);
-                 }
-               if (!p)
-                 continue;
-               s = pool->solvables + p;
-               h = (s->name + s->evr * 37 + s->arch * 129) & hm;
-               hh = HASHCHAIN_START;
-               while ((p = ht[h]) != 0)
-                 {
-                   Solvable *s2 = pool->solvables + p;
-                   if (s->name == s2->name && s->evr == s2->evr && s->arch == s2->arch)
-                     {
-                       lastid = collectedmodules.count ? collectedmodules.elements[collectedmodules.count - 1] : 0;
-                       solvable_lookup_idarray(s2, buildservice_modules, &modules);
-                       for (j = 0; j < modules.count; j++)
-                         if (modules.elements[j] != lastid)
-                           queue_push(&collectedmodules, modules.elements[j]);
-                     }
-                   h = HASHCHAIN_NEXT(h, hh, hm);
-                 }
-             }
-           solv_free(ht);
-           queue_free(&modules);
-           /* sort and unify */
-           solv_sort(collectedmodules.elements, collectedmodules.count, sizeof(Id), unifymodules_cmp, 0);
-           lastid = -1;
-           for (i = 0; i < collectedmodules.count; i++)
-             {
-               if (collectedmodules.elements[i] == lastid)
-                 continue;
-               lastid = collectedmodules.elements[i];
-               XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid), 0)));
-             }
-           queue_free(&collectedmodules);
-       }
-
-void
-missingmodules(BSSolv::repo repo, ...)
-    PPCODE:
-       {
-           Pool *pool = repo->pool;
-            Id p, *pp, *modules, id, req, lastid1, lastid2;
-           Solvable *s;
-           Queue missingq;
-           int i, missing;
-
-           queue_init(&missingq);
-           if (pool->appdata && ((Id *)pool->appdata)[0] && has_keyname(repo, buildservice_modules))
-             {
-               FOR_REPO_SOLVABLES(repo, p, s)
-                 {
-                   if (s->name != buildservice_modules || s->arch != ARCH_SRC || !s->requires)
-                     continue;
-                   id = s->repo->idarraydata[s->provides];
-                   for (modules = pool->appdata; *modules; modules++)
-                     if (id == *modules)
-                       break;
-                   if (!*modules)
-                     continue;
-                   missing = 0;
-                   for (pp = s->repo->idarraydata + s->requires; (req = *pp) != 0; pp++)
-                     if (!match_modules_req(pool, req))
-                       {
-                         missing = 1;
-                         queue_push2(&missingq, id, req);
-                       }
-                   if (!missing)       /* we're good */
-                     queue_push2(&missingq, id, 0);
-                 }
-               /* sort and unify */
-               solv_sort(missingq.elements, missingq.count / 2, sizeof(Id) * 2, missingmodules_cmp, 0);
-               lastid1 = lastid2 = -1;
-               for (i = 0; i < missingq.count; i += 2)
-                 {
-                   if (missingq.elements[i] == lastid1 && missingq.elements[i + 1] == lastid2)
-                     continue;
-                   if (missingq.elements[i] != lastid1)
-                     {
-                       lastid1 = missingq.elements[i];
-                       lastid2 = missingq.elements[i + 1];
-                     }
-                   if (!lastid2)
-                     continue;
-                   lastid2 = missingq.elements[i + 1];
-                   XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid1), 0)));
-                   XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid2), 0)));
-                 }
-               queue_free(&missingq);
-             }
-       }
 
 void
 getpathid(BSSolv::repo repo)
@@ -7312,11 +5035,6 @@ getpathid(BSSolv::repo repo)
                unsigned int medianr;
                const char *str;
                str = solvable_get_location(s, &medianr);
-               /* We need to special case .obsbinlink here where the location
-                * points back into the package. We currently assume that
-                * the name in the full tree is always <name>.obsbinlnk */
-               if (!strncmp(str, "../", 3))
-                 str = pool_tmpjoin(repo->pool, pool_id2str(repo->pool, s->name), ".obsbinlnk", 0);
                PUSHs(sv_2mortal(newSVpv(str, 0)));
                str = solvable_lookup_str(s, buildservice_id);
                PUSHs(sv_2mortal(newSVpv(str, 0)));
@@ -7351,21 +5069,6 @@ dodcookie(BSSolv::repo repo)
     OUTPUT:
        RETVAL
 
-void
-dodresources(BSSolv::repo repo)
-    PPCODE:
-       {
-         Pool *pool = repo->pool;
-         Queue dodresources;
-         int i;
-
-         queue_init(&dodresources);
-         repo_lookup_idarray(repo, SOLVID_META, buildservice_dodresources, &dodresources);
-         for (i = 0; i < dodresources.count; i++)
-           XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, dodresources.elements[i]), 0)));
-         queue_free(&dodresources);
-       }
-
 void
 updatedoddata(BSSolv::repo repo, HV *rhv = 0)
     CODE:
@@ -7383,131 +5086,28 @@ updatedoddata(BSSolv::repo repo, HV *rhv = 0)
            data = repo_add_repodata(repo, REPO_REUSE_REPODATA);
            repodata_unset(data, SOLVID_META, buildservice_dodurl);
            repodata_unset(data, SOLVID_META, buildservice_dodcookie);
-           repodata_unset(data, SOLVID_META, buildservice_dodresources);
            /* add new data */
            if (rhv)
-               data2solvables(repo, data, (SV *)rhv, 1);
+               data2solvables(repo, data, rhv);
            repo_internalize(repo);
        }
 
-void
-setpriority(BSSolv::repo repo, int priority)
-    PPCODE:
-       repo->priority = priority;
-
-int
-mayhavemodules(BSSolv::repo repo)
-    CODE:
-       RETVAL = has_keyname(repo, buildservice_modules);
-    OUTPUT:
-       RETVAL
-
-void
-getmodules(BSSolv::repo repo)
-    PPCODE:
-       if (has_keyname(repo, buildservice_modules))
-         {
-           Pool *pool = repo->pool;
-           Id p, lastid = -1;
-           Solvable *s;
-           Queue collectedmodules;
-           int i;
-
-           queue_init(&collectedmodules);
-           FOR_REPO_SOLVABLES(repo, p, s)
-             if (s->name == buildservice_modules && s->arch == ARCH_SRC && s->repo->idarraydata[s->provides])
-               queue_push(&collectedmodules, s->repo->idarraydata[s->provides]);
-           if (!collectedmodules.count)
-             {
-               Queue modules;
-               queue_init(&modules);
-               FOR_REPO_SOLVABLES(repo, p, s)
-                 {
-                   solvable_lookup_idarray(pool->solvables + p, buildservice_modules, &modules);
-                   for (i = 0; i < modules.count; i++)
-                     {
-                       if (modules.elements[i] == lastid)
-                         continue;
-                       lastid = modules.elements[i];
-                       queue_push(&collectedmodules, modules.elements[i]);
-                     }
-                 }
-               queue_free(&modules);
-             }
-           /* sort and unify */
-           solv_sort(collectedmodules.elements, collectedmodules.count, sizeof(Id), unifymodules_cmp, 0);
-           lastid = -1;
-           for (i = 0; i < collectedmodules.count; i++)
-             {
-               if (collectedmodules.elements[i] == lastid)
-                 continue;
-               lastid = collectedmodules.elements[i];
-               XPUSHs(sv_2mortal(newSVpv(pool_id2str(pool, lastid), 0)));
-             }
-           queue_free(&collectedmodules);
-         }
-
-void
-getdodblobs(BSSolv::repo repo)
-    PPCODE:
-       {
-           Pool *pool = repo->pool;
-           int i;
-           Id p;
-           Solvable *s;
-           Stringpool ss;
-           stringpool_init_empty(&ss);
-           FOR_REPO_SOLVABLES(repo, p, s)
-             {
-               const char *str = solvable_lookup_str(s, buildservice_id);
-               unsigned int medianr;
-               const char *s, *se;
-               if (!str || strcmp(str, "dod") != 0)
-                 continue;
-               s = solvable_get_location(pool->solvables + p, &medianr);
-               if ((s = strrchr(s, '?')) == 0)
-                 continue;
-               for (++s; s; s = se ? se + 1 : 0)
-                 {
-                   se = strchr(s, ',');
-                   if (se)
-                     stringpool_strn2id(&ss, s, se - s, 1);
-                   else
-                     stringpool_str2id(&ss, s, 1);
-                 }
-             }
-           for (i = 2; i < ss.nstrings; i++)
-             {
-               XPUSHs(sv_2mortal(newSVpv(stringpool_id2str(&ss, i), 0)));
-             }
-           stringpool_free(&ss);
-       }
-
 
 MODULE = BSSolv                PACKAGE = BSSolv::expander      PREFIX = expander
 
+
 BSSolv::expander
 new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
     CODE:
        {
            SV *sv, **svp;
-           char *str, *p;
-           int i;
-           Id id;
+           char *str;
+           int i, neg;
+           Id id, id2;
            Expander *xp;
-           Queue preferpos;
-           Queue preferneg;
-           Queue ignore;
-           Queue conflict;
-           Queue fileprovides;
-           int debug = 0;
-           int options = 0;
-
-           queue_init(&preferpos);
-           queue_init(&preferneg);
-           queue_init(&ignore);
-           queue_init(&conflict);
-           queue_init(&fileprovides);
+
+           xp = calloc(sizeof(Expander), 1);
+           xp->pool = pool;
            svp = hv_fetch(config, "prefer", 6, 0);
            sv = svp ? *svp : 0;
            if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV)
@@ -7522,10 +5122,37 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
                    str = SvPV_nolen(sv);
                    if (!str)
                      continue;
+                   neg = 0;
                    if (*str == '-')
-                     queue_push(&preferneg, pool_str2id(pool, str + 1, 1));
+                     {
+                       neg = 1;
+                       str++;
+                     }
+                   id = pool_str2id(pool, str, 1);
+                   id2 = 0;
+                   if ((str = strchr(str, ':')) != 0)
+                     id2 = pool_str2id(pool, str + 1, 1);
+                   if (neg)
+                     {
+                       MAPEXP(&xp->preferneg, id);
+                       MAPSET(&xp->preferneg, id);
+                       if (id2)
+                         {
+                           MAPEXP(&xp->prefernegx, id2);
+                           MAPSET(&xp->prefernegx, id2);
+                         }
+                     }
                    else
-                     queue_push(&preferpos, pool_str2id(pool, str, 1));
+                     {
+                       queue_push(&xp->preferposq, id);
+                       MAPEXP(&xp->preferpos, id);
+                       MAPSET(&xp->preferpos, id);
+                       if (id2)
+                         {
+                           MAPEXP(&xp->preferposx, id2);
+                           MAPSET(&xp->preferposx, id2);
+                         }
+                     }
                  }
              }
            svp = hv_fetch(config, "ignoreh", 7, 0);
@@ -7534,6 +5161,7 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
              {
                HV *hv = (HV *)SvRV(sv);
                HE *he;
+
                hv_iterinit(hv);
                while ((he = hv_iternext(hv)) != 0)
                  {
@@ -7541,7 +5169,18 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
                    str = hv_iterkey(he, &strl);
                    if (!str)
                      continue;
-                   queue_push(&ignore, pool_str2id(pool, str, 1));
+                
+                   id = pool_str2id(pool, str, 1);
+                   id2 = 0;
+                   if ((str = strchr(str, ':')) != 0)
+                     id2 = pool_str2id(pool, str + 1, 1);
+                   MAPEXP(&xp->ignored, id);
+                   MAPSET(&xp->ignored, id);
+                   if (id2)
+                     {
+                       MAPEXP(&xp->ignoredx, id2);
+                       MAPSET(&xp->ignoredx, id2);
+                     }
                  }
              }
            svp = hv_fetch(config, "conflict", 8, 0);
@@ -7551,6 +5190,9 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
                AV *av = (AV *)SvRV(sv);
                for (i = 0; i <= av_len(av); i++)
                  {
+                   char *p;
+                   Id id2;
+
                    svp = av_fetch(av, i, 0);
                    if (!svp)
                      continue;
@@ -7565,28 +5207,46 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
                    str = p + 1;
                    while ((p = strchr(str, ',')) != 0)
                      {
-                       queue_push2(&conflict, id, pool_strn2id(pool, str, p - str, 1));
+                       id2 = pool_strn2id(pool, str, p - str, 1);
+                       queue_push2(&xp->conflictsq, id, id2);
+                       MAPEXP(&xp->conflicts, id);
+                       MAPSET(&xp->conflicts, id);
+                       MAPEXP(&xp->conflicts, id2);
+                       MAPSET(&xp->conflicts, id2);
                        str = p + 1;
                      }
-                   queue_push2(&conflict, id, pool_str2id(pool, str, 1));
+                   id2 = pool_str2id(pool, str, 1);
+                   queue_push2(&xp->conflictsq, id, id2);
+                   MAPEXP(&xp->conflicts, id);
+                   MAPSET(&xp->conflicts, id);
+                   MAPEXP(&xp->conflicts, id2);
+                   MAPSET(&xp->conflicts, id2);
                  }
              }
+           /* XXX: this modifies the pool, which is a bit unclean! */
            svp = hv_fetch(config, "fileprovides", 12, 0);
            sv = svp ? *svp : 0;
            if (sv && SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVHV)
              {
                HV *hv = (HV *)SvRV(sv);
                I32 strl;
+               Queue q;
 
+               xp->havefileprovides = 1;
                hv_iterinit(hv);
+               queue_init(&q);
                while ((sv = hv_iternextsv(hv, &str, &strl)) != 0)
                  {
                    AV *av;
-                   Id id2;
+                   Id p, pp;
+                   int havenew = 0;
 
                    if (!SvROK(sv) || SvTYPE(SvRV(sv)) != SVt_PVAV)
                      continue;
                    id = pool_str2id(pool, str, 1);
+                   queue_empty(&q);
+                   FOR_PROVIDES(p, pp, id)
+                     queue_push(&q, p);
                    av = (AV *)SvRV(sv);
                    for (i = 0; i <= av_len(av); i++)
                      {
@@ -7598,48 +5258,44 @@ new(char *packname = "BSSolv::expander", BSSolv::pool pool, HV *config)
                        if (!str)
                          continue;
                        id2 = pool_str2id(pool, str, 0);
-                       if (!id2)
-                         continue;
-                       if (id)
+                       FOR_PROVIDES(p, pp, id2)
                          {
-                           queue_push(&fileprovides, id);      /* start name block */
-                           id = 0;
+                           int j;
+                           for (j = 0; j < q.count; j++)
+                             {
+                               if (q.elements[j] == p)
+                                 break;
+                               if (q.elements[j] > p)
+                                 {
+                                   queue_insert(&q, j, p);
+                                   havenew = 1;
+                                   break;
+                                 }
+                             }
+                           if (j == q.count)
+                             {
+                               queue_push(&q, p);
+                               havenew = 1;
+                             }
                          }
-                       queue_push(&fileprovides, id2);
                      }
-                   if (id == 0)
-                     queue_push(&fileprovides, 0);     /* had at least one entry, finish name block */
+                   if (havenew)
+                     pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q);
                  }
+               queue_free(&q);
              }
-           options |= EXPANDER_OPTION_USERECOMMENDSFORCHOICES;
            svp = hv_fetch(config, "expandflags:ignoreconflicts", 27, 0);
            sv = svp ? *svp : 0;
            if (sv && SvTRUE(sv))
-             options |= EXPANDER_OPTION_IGNORECONFLICTS;
-           svp = hv_fetch(config, "expandflags:dorecommends", 24, 0);
+             xp->ignoreconflicts = 1;
+           svp = hv_fetch(config, "expand_dbg", 10, 0);
            sv = svp ? *svp : 0;
            if (sv && SvTRUE(sv))
-             options |= EXPANDER_OPTION_DORECOMMENDS;
-           svp = hv_fetch(config, "expandflags:dosupplements", 25, 0);
-           sv = svp ? *svp : 0;
+             xp->debug = 1;
+           sv = get_sv("Build::expand_dbg", FALSE);
            if (sv && SvTRUE(sv))
-             options |= EXPANDER_OPTION_DOSUPPLEMENTS | EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES;
-           svp = hv_fetch(config, "expand_dbg", 10, 0);
-           sv = svp ? *svp : 0;
-           if (sv && SvOK(sv))
-             debug = SvIV(sv);
-           else
-             {
-               sv = get_sv("Build::expand_dbg", FALSE);
-               if (sv && SvOK(sv))
-                 debug = SvIV(sv);
-             }
-           xp = expander_create(pool, &preferpos, &preferneg, &ignore, &conflict, &fileprovides, debug, options);
-           queue_free(&preferpos);
-           queue_free(&preferneg);
-           queue_free(&ignore);
-           queue_free(&conflict);
-           queue_free(&fileprovides);
+             xp->debug = 1;
+        xp->userecommendsforchoices = 1;
            RETVAL = xp;
        }
     OUTPUT:
@@ -7652,71 +5308,131 @@ expand(BSSolv::expander xp, ...)
        {
            Pool *pool;
            int i, nerrors;
-           Id id, who, indepbuf[64];
-           Queue ignoreq, in, out, indep;
-           int directdepsend = 0;
-           int options = 0;
-
-           queue_init(&ignoreq);
+           Id id, who, conflbuf[16];
+           Queue revertignore, in, out, confl;
+           int oldignoreignore = xp->ignoreignore;
+           int ignoreignore = 0;
+           Map oldignored, oldignoredx;
+           int ignoremapssaved = 0;
+
+           queue_init(&revertignore);
            queue_init(&in);
            queue_init(&out);
-           queue_init_buffer(&indep, indepbuf, sizeof(indepbuf)/sizeof(*indepbuf));
+           queue_init_buffer(&confl, conflbuf, sizeof(conflbuf)/sizeof(*conflbuf));
            pool = xp->pool;
            if (xp->debug)
              expander_dbg(xp, "expand args:");
            for (i = 1; i < items; i++)
              {
                char *s = SvPV_nolen(ST(i));
-               int deptype = DEPTYPE_REQUIRES;
-
                if (xp->debug)
                  expander_dbg(xp, " %s", s);
-               if (*s == '-' && s[1] == '-')
-                 {
-                   /* expand option */
-                   if (!strcmp(s, "--ignoreignore--"))
-                     options |= EXPANDER_OPTION_IGNOREIGNORE;
-                   else if (!strcmp(s, "--directdepsend--"))
-                     directdepsend = 1;
-                   else if (!strcmp(s, "--dorecommends--"))
-                     options |= EXPANDER_OPTION_DORECOMMENDS;
-                   else if (!strcmp(s, "--dosupplements--"))
-                     options |= EXPANDER_OPTION_DOSUPPLEMENTS | EXPANDER_OPTION_USESUPPLEMENTSFORCHOICES;
-                   else if (!strcmp(s, "--ignoreconflicts--"))
-                     options |= EXPANDER_OPTION_IGNORECONFLICTS;
-                   continue;
-                 }
                if (*s == '-')
                  {
-                   /* ignore dependency */
+                   Id id;
+                   if (s[1] == '-' && !strcmp(s, "--ignoreignore--"))
+                     {
+                       ignoreignore = 1;
+                       continue;
+                     }
                    id = pool_str2id(pool, s + 1, 1);
-                   queue_push(&ignoreq, id);
-                   continue;
-                 }
-               if (*s == '!')
-                 {
-                   deptype = DEPTYPE_CONFLICTS;
-                   s++;
-                   if (*s == '!')
+                   if (id == expander_directdepsend)
                      {
-                       deptype = DEPTYPE_OBSOLETES;
-                       s++;
+                       queue_push(&in, id);
+                       continue;
                      }
+                   queue_push(&revertignore, id);
+                 }
+               else if (*s == '!')
+                 {
+                   Id id = dep2id(pool, s + (s[1] == '!' ? 2 : 1));
+                   queue_push2(&confl, id, s[1] == '!' ? 1 : 0);
                  }
-               id = dep2id(pool, s);
-               if (deptype == DEPTYPE_REQUIRES && !directdepsend)
-                 queue_push(&in, id);
                else
-                 queue_push2(&indep, deptype, id);
+                 {
+                   Id id = dep2id(pool, s);
+                   queue_push(&in, id);
+                 }
              }
            if (xp->debug)
              expander_dbg(xp, "\n");
 
-           nerrors = expander_expand(xp, &in, &indep, &out, &ignoreq, options);
+           if (ignoreignore && revertignore.count)
+             {
+               /* bad: have direct ignores and project config ignores */
+               oldignored = xp->ignored;
+               oldignoredx = xp->ignoredx;
+               ignoremapssaved = 1;
+               /* clear project config maps */
+               memset(&xp->ignored, 0, sizeof(xp->ignored));
+               memset(&xp->ignoredx, 0, sizeof(xp->ignoredx));
+             }
+
+           if (revertignore.count)
+             {
+               /* mix direct ignores with ignores from project config */
+               int revertcnt = revertignore.count;
+               for (i = 0; i < revertcnt; i++)
+                 {
+                   const char *ss;
+                   id = revertignore.elements[i];
+                   MAPEXP(&xp->ignored, id);
+                   if (MAPTST(&xp->ignored, id))
+                     continue;
+                   MAPSET(&xp->ignored, id);
+                   queue_push(&revertignore, id);
+                   if ((ss = strchr(pool_id2str(pool, id), ':')) != 0)
+                     {
+                       id = pool_str2id(pool, ss + 1, 1);
+                       MAPEXP(&xp->ignoredx, id);
+                       if (MAPTST(&xp->ignoredx, id))
+                         continue;
+                       MAPSET(&xp->ignoredx, id);
+                       queue_push(&revertignore, -id);
+                     }
+                 }
+               queue_deleten(&revertignore, 0, revertcnt);
+             }
+           else if (ignoreignore)
+             {
+               /* no direct ignores, disable ignore processing */
+               xp->ignoreignore = 1;
+             }
+
+           MAPEXP(&xp->ignored, pool->ss.nstrings);
+           MAPEXP(&xp->ignoredx, pool->ss.nstrings);
+           MAPEXP(&xp->preferpos, pool->ss.nstrings);
+           MAPEXP(&xp->preferposx, pool->ss.nstrings);
+           MAPEXP(&xp->preferneg, pool->ss.nstrings);
+           MAPEXP(&xp->prefernegx, pool->ss.nstrings);
+           MAPEXP(&xp->conflicts, pool->ss.nstrings);
+
+           nerrors = expander_expand(xp, &in, &out, &confl);
+
+           /* revert ignores */
+           xp->ignoreignore = oldignoreignore;
+           if (ignoremapssaved)
+             {
+               map_free(&xp->ignored);
+               map_free(&xp->ignoredx);
+               xp->ignored = oldignored;
+               xp->ignoredx = oldignoredx;
+             }
+           else
+             {
+               for (i = 0; i < revertignore.count; i++)
+                 {
+                   id = revertignore.elements[i];
+                   if (id > 0)
+                     MAPCLR(&xp->ignored, id);
+                   else
+                     MAPCLR(&xp->ignoredx, -id);
+                 }
+             }
+           queue_free(&revertignore);
 
            queue_free(&in);
-           queue_free(&indep);
-           queue_free(&ignoreq);
+           queue_free(&confl);
 
            if (nerrors)
              {
@@ -7731,43 +5447,19 @@ expand(BSSolv::expander xp, ...)
                        id = out.elements[i + 1];
                        who = out.elements[i + 2];
                        if (who)
-                         sv = newSVpvf("nothing provides %s needed by %s", pool_dep2str(pool, id), solvid2name(pool, who));
+                         sv = newSVpvf("nothing provides %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name));
                        else
                          sv = newSVpvf("nothing provides %s", pool_dep2str(pool, id));
                        i += 3;
                      }
-                   else if (type == ERROR_ALLCONFLICT)
+                   else if (type == ERROR_CONFLICTINGPROVIDER)
                      {
                        id = out.elements[i + 1];
                        who = out.elements[i + 2];
                        if (who)
-                         sv = newSVpvf("%s conflicts with always true %s", solvid2name(pool, who), pool_dep2str(pool, id));
-                       else
-                         sv = newSVpvf("conflict with always true %s", pool_dep2str(pool, id));
-                       i += 3;
-                     }
-                   else if (type == ERROR_CONFLICT)
-                     {
-                       Id who2 = out.elements[i + 2];
-                       who = out.elements[i + 1];
-                       if (!who && who2 >= 0)
-                         sv = newSVpvf("conflicts with %s", solvid2name(pool, who2));
-                       else if (who2 < 0)
-                         sv = newSVpvf("%s obsoletes %s", solvid2name(pool, who), solvid2name(pool, -who2));
-                       else
-                         sv = newSVpvf("%s conflicts with %s", solvid2name(pool, who), solvid2name(pool, who2));
-                       i += 3;
-                     }
-                   else if (type == ERROR_CONFLICT2)
-                     {
-                       Id who2 = out.elements[i + 2];
-                       who = out.elements[i + 1];
-                       if (who2 < 0)
-                         sv = newSVpvf("%s is obsoleted by %s", solvid2name(pool, who), solvid2name(pool, -who2));
-                       else if (who2 > 0)
-                         sv = newSVpvf("%s is in conflict with %s", solvid2name(pool, who), solvid2name(pool, who2));
+                         sv = newSVpvf("conflict for provider of %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name));
                        else
-                         sv = newSVpvf("%s is in conflict", solvid2name(pool, who));
+                         sv = newSVpvf("conflict for provider of %s", pool_dep2str(pool, id));
                        i += 3;
                      }
                    else if (type == ERROR_CONFLICTINGPROVIDERS)
@@ -7775,9 +5467,9 @@ expand(BSSolv::expander xp, ...)
                        id = out.elements[i + 1];
                        who = out.elements[i + 2];
                        if (who)
-                         sv = newSVpvf("conflict for providers of %s needed by %s", pool_dep2str(pool, id), solvid2name(pool, who));
+                         sv = newSVpvf("conflict for all providers of %s needed by %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name));
                        else
-                         sv = newSVpvf("conflict for providers of %s", pool_dep2str(pool, id));
+                         sv = newSVpvf("conflict for all providers of %s", pool_dep2str(pool, id));
                        i += 3;
                      }
                    else if (type == ERROR_PROVIDERINFO)
@@ -7785,9 +5477,9 @@ expand(BSSolv::expander xp, ...)
                        Id who2 = out.elements[i + 2];
                        who = out.elements[i + 1];
                        if (who2 < 0)
-                         sv = newSVpvf("(provider %s obsoletes %s)", solvid2name(pool, who), solvid2name(pool, -who2));
+                         sv = newSVpvf("(provider %s obsoletes installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[-who2].name));
                        else
-                         sv = newSVpvf("(provider %s conflicts with %s)", solvid2name(pool, who), solvid2name(pool, who2));
+                         sv = newSVpvf("(provider %s conflicts with installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[who2].name));
                        i += 3;
                      }
                    else if (type == ERROR_PROVIDERINFO2)
@@ -7795,20 +5487,17 @@ expand(BSSolv::expander xp, ...)
                        Id who2 = out.elements[i + 2];
                        who = out.elements[i + 1];
                        if (who2 < 0)
-                         sv = newSVpvf("(provider %s is obsoleted by %s)", solvid2name(pool, who), solvid2name(pool, -who2));
+                         sv = newSVpvf("(provider %s is obsoleted by installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[-who2].name));
                        else if (who2 > 0)
-                         sv = newSVpvf("(provider %s is in conflict with %s)", solvid2name(pool, who), solvid2name(pool, who2));
+                         sv = newSVpvf("(provider %s is conflicted by installed %s)", pool_id2str(pool, pool->solvables[who].name), pool_id2str(pool, pool->solvables[who2].name));
                        else
-                         sv = newSVpvf("(provider %s is in conflict)", solvid2name(pool, who));
+                         sv = newSVpvf("(provider %s is conflicted by the build config)", pool_id2str(pool, pool->solvables[who].name));
                        i += 3;
                      }
                    else if (type == ERROR_CHOICE)
                      {
                        int j;
                        char *str = "";
-                       for (j = i + 3; out.elements[j]; j++)
-                         ;
-                       solv_sort(out.elements + i + 3, j - (i + 3), sizeof(Id), pkgname_sort_cmp, pool);
                        for (j = i + 3; out.elements[j]; j++)
                          {
                            Solvable *s = pool->solvables + out.elements[j];
@@ -7819,31 +5508,11 @@ expand(BSSolv::expander xp, ...)
                        id = out.elements[i + 1];
                        who = out.elements[i + 2];
                        if (who)
-                         sv = newSVpvf("have choice for %s needed by %s: %s", pool_dep2str(pool, id), solvid2name(pool, who), str);
+                         sv = newSVpvf("have choice for %s needed by %s: %s", pool_dep2str(pool, id), pool_id2str(pool, pool->solvables[who].name), str);
                        else
                          sv = newSVpvf("have choice for %s: %s", pool_dep2str(pool, id), str);
                        i = j + 1;
                      }
-                   else if (type == ERROR_BADDEPENDENCY)
-                     {
-                       id = out.elements[i + 1];
-                       who = out.elements[i + 2];
-                       if (who)
-                         sv = newSVpvf("cannot parse dependency %s from %s", pool_dep2str(pool, id), solvid2name(pool, who));
-                       else
-                         sv = newSVpvf("cannot parse dependency %s", pool_dep2str(pool, id));
-                       i += 3;
-                     }
-                   else if (type == ERROR_NOPROVIDERINFO)
-                     {
-                       id = out.elements[i + 1];
-                       who = out.elements[i + 2];
-                       if (who)
-                         sv = newSVpvf("(got version %s provided by %s)", pool_id2str(pool, id), solvid2name(pool, who));
-                       else
-                         sv = newSVpvf("(got version %s)", pool_id2str(pool, id));
-                       i += 3;
-                     }
                    else
                      croak("expander: bad error type\n");
                    PUSHs(sv_2mortal(sv));
@@ -7862,31 +5531,27 @@ expand(BSSolv::expander xp, ...)
            queue_free(&out);
        }
 
-void
-debug(BSSolv::expander xp, const char *str)
-    CODE:
-       expander_dbg(xp, "%s", str);
-
-
 const char *
 debugstr(BSSolv::expander xp)
     CODE:
-       RETVAL = xp->debugstr ? xp->debugstr : "";
+       if (!xp->debugstr)
+         xp->debugstr = calloc(1, 1);
+       RETVAL = xp->debugstr;
     OUTPUT:
        RETVAL
 
-const char *
-debugstrclr(BSSolv::expander xp)
-       
-    CODE:
-       RETVAL = xp->debugstr ? xp->debugstr : "";
-    OUTPUT:
-       RETVAL
-    CLEANUP:
-       expander_clrdbg(xp);
 
 void
 DESTROY(BSSolv::expander xp)
     CODE:
-       expander_free(xp);
-
+       map_free(&xp->ignored);
+       map_free(&xp->ignoredx);
+       queue_free(&xp->preferposq);
+       map_free(&xp->preferpos);
+       map_free(&xp->preferposx);
+       map_free(&xp->preferneg);
+       map_free(&xp->prefernegx);
+       queue_free(&xp->conflictsq);
+       map_free(&xp->conflicts);
+       solv_free(xp->debugstr);
+       solv_free(xp);