Merge branch 'master' of gitorious.org:opensuse/sat-solver
authorKlaus Kämpf <kkaempf@suse.de>
Thu, 11 Nov 2010 20:17:01 +0000 (21:17 +0100)
committerKlaus Kämpf <kkaempf@suse.de>
Thu, 11 Nov 2010 20:17:01 +0000 (21:17 +0100)
34 files changed:
CMakeLists.txt
VERSION.cmake
examples/CMakeLists.txt
examples/solv.c
ext/CMakeLists.txt
ext/repo_deb.c
ext/repo_products.c
ext/repo_rpmdb.c
ext/repo_updateinfoxml.c
package/libsatsolver.changes
package/libsatsolver.spec.in
src/evr.c
src/evr.h
src/policy.c
src/policy.h
src/pool.c
src/pool.h
src/poolarch.c
src/problems.c
src/repo.h
src/repodata.c
src/repopage.c
src/rules.c
src/rules.h
src/solvable.c
src/solver.c
src/solver.h
src/solverdebug.c
src/solverdebug.h
tools/CMakeLists.txt
tools/installcheck.c
tools/patchcheck.c
tools/repo2solv.sh
tools/susetags2solv.c

index 6f710ab..24234db 100644 (file)
@@ -40,15 +40,32 @@ MESSAGE(STATUS "Building for Fedora")
 ADD_DEFINITIONS( -DFEDORA )
 ENDIF ( FEDORA)
 
+IF ( DEBIAN )
+MESSAGE(STATUS "Building for Debian")
+ADD_DEFINITIONS( -DDEBIAN -DDEBIAN_SEMANTICS)
+ENDIF ( DEBIAN )
+
 IF ( MULTI_SEMANTICS )
 MESSAGE(STATUS "Enabling multi dist support")
 ADD_DEFINITIONS( -DMULTI_SEMANTICS)
 ENDIF ( MULTI_SEMANTICS )
 
+IF ( NOT DEBIAN )
 FIND_LIBRARY(RPMDB_LIBRARY NAMES rpmdb)
 IF ( NOT RPMDB_LIBRARY )
 FIND_LIBRARY(RPMDB_LIBRARY NAMES rpm)
 ENDIF( NOT RPMDB_LIBRARY )
+FIND_LIBRARY(RPMIO_LIBRARY NAMES rpmio)
+IF ( RPMIO_LIBRARY )
+SET( RPMDB_LIBRARY ${RPMIO_LIBRARY} ${RPMDB_LIBRARY} )
+ENDIF ( RPMIO_LIBRARY )
+IF ( FEDORA )
+FIND_LIBRARY(DB_LIBRARY NAMES db)
+IF ( DB_LIBRARY )
+SET( RPMDB_LIBRARY ${DB_LIBRARY} ${RPMDB_LIBRARY} )
+ENDIF ( DB_LIBRARY )
+ENDIF ( FEDORA )
+ENDIF ( NOT DEBIAN )
 
 SET( PACKAGE "satsolver" )
 SET( VERSION "${LIBSATSOLVER_MAJOR}.${LIBSATSOLVER_MINOR}.${LIBSATSOLVER_PATCH}" )
index 9e997af..7a544ad 100644 (file)
@@ -45,7 +45,7 @@
 #
 
 SET(LIBSATSOLVER_MAJOR "0")
-SET(LIBSATSOLVER_MINOR "14")
-SET(LIBSATSOLVER_PATCH "16")
+SET(LIBSATSOLVER_MINOR "16")
+SET(LIBSATSOLVER_PATCH "1")
 
-# last released 0.14.16
+# last released 0.16.0
index 9d53c3d..4e2491f 100644 (file)
@@ -1,5 +1,9 @@
 ADD_EXECUTABLE(solv solv.c)
+IF ( DEBIAN )
+TARGET_LINK_LIBRARIES(solv satsolverext satsolver ${EXPAT_LIBRARY} ${ZLIB_LIBRARY})
+ELSE ( DEBIAN )
 TARGET_LINK_LIBRARIES(solv satsolverext satsolver ${RPMDB_LIBRARY} ${EXPAT_LIBRARY} ${ZLIB_LIBRARY})
+ENDIF ( DEBIAN )
 
 install(TARGETS
     solv
index 46aea12..636e9ca 100644 (file)
@@ -7,7 +7,18 @@
 
 /* solv, a little software installer demoing the sat solver library */
 
-/* things available in the library but missing from solv:
+/* things it does:
+ * - understands globs for package names / dependencies
+ * - understands .arch suffix
+ * - installation of commandline packages
+ * - repository data caching
+ * - on demand loading of secondary repository data
+ * - gpg and checksum verification
+ * - file conflicts
+ * - deltarpm support
+ * - fastestmirror implementation
+ *
+ * things available in the library but missing from solv:
  * - vendor policy loading
  * - soft locks file handling
  * - multi version handling
@@ -28,6 +39,8 @@
 #include <sys/wait.h>
 #include <time.h>
 #include <sys/time.h>
+#include <sys/dir.h>
+#include <sys/stat.h>
 
 #include <sys/socket.h>
 #include <netdb.h>
 #include "repo_solv.h"
 
 #include "repo_write.h"
+#ifndef DEBIAN
 #include "repo_rpmdb.h"
+#else
+#include "repo_deb.h"
+#endif
 #include "repo_products.h"
 #include "repo_rpmmd.h"
 #include "repo_susetags.h"
@@ -86,6 +103,8 @@ struct repoinfo {
   int priority;
   int keeppackages;
   int metadata_expire;
+  char **components;
+  int ncomponents;
 
   unsigned char cookie[32];
   unsigned char extcookie[32];
@@ -170,6 +189,7 @@ yum_substitute(Pool *pool, char *line)
 #define TYPE_SUSETAGS  1
 #define TYPE_RPMMD     2
 #define TYPE_PLAINDIR  3
+#define TYPE_DEBIAN     4
 
 static int
 read_repoinfos_sort(const void *ap, const void *bp)
@@ -179,6 +199,8 @@ read_repoinfos_sort(const void *ap, const void *bp)
   return strcmp(a->alias, b->alias);
 }
 
+#ifndef DEBIAN
+
 struct repoinfo *
 read_repoinfos(Pool *pool, const char *reposdir, int *nrepoinfosp)
 {
@@ -200,6 +222,8 @@ read_repoinfos(Pool *pool, const char *reposdir, int *nrepoinfosp)
     }
   while ((ent = readdir(dir)) != 0)
     {
+      if (ent->d_name[0] == '.')
+       continue;
       l = strlen(ent->d_name);
       if (l < 6 || rdlen + 2 + l >= sizeof(buf) || strcmp(ent->d_name + l - 5, ".repo") != 0)
        continue;
@@ -308,10 +332,126 @@ read_repoinfos(Pool *pool, const char *reposdir, int *nrepoinfosp)
   return repoinfos;
 }
 
+#else
+
+struct repoinfo *
+read_repoinfos(Pool *pool, const char *reposdir, int *nrepoinfosp)
+{
+  FILE *fp;
+  char buf[4096];
+  char buf2[4096];
+  int l;
+  char *kp, *url, *distro;
+  struct repoinfo *repoinfos = 0, *cinfo;
+  int nrepoinfos = 0;
+  DIR *dir = 0;
+  struct dirent *ent;
+
+  fp = fopen("/etc/apt/sources.list", "r");
+  while (1)
+    {
+      if (!fp)
+       {
+         if (!dir)
+           {
+             dir = opendir("/etc/apt/sources.list.d");
+             if (!dir)
+               break;
+           }
+         if ((ent = readdir(dir)) == 0)
+           {
+             closedir(dir);
+             break;
+           }
+         if (ent->d_name[0] == '.')
+           continue;
+         l = strlen(ent->d_name);
+         if (l < 5 || strcmp(ent->d_name + l - 5, ".list") != 0)
+           continue;
+         snprintf(buf, sizeof(buf), "%s/%s", "/etc/apt/sources.list.d", ent->d_name);
+         if (!(fp = fopen(buf, "r")))
+           continue;
+       }
+      while(fgets(buf2, sizeof(buf2), fp))
+       {
+         l = strlen(buf2);
+         if (l == 0)
+           continue;
+         while (l && (buf2[l - 1] == '\n' || buf2[l - 1] == ' ' || buf2[l - 1] == '\t'))
+           buf2[--l] = 0;
+         kp = buf2;
+         while (*kp == ' ' || *kp == '\t')
+           kp++;
+         if (!*kp || *kp == '#')
+           continue;
+         if (strncmp(kp, "deb", 3) != 0)
+           continue;
+         kp += 3;
+         if (*kp != ' ' && *kp != '\t')
+           continue;
+         while (*kp == ' ' || *kp == '\t')
+           kp++;
+         if (!*kp)
+           continue;
+         url = kp;
+         while (*kp && *kp != ' ' && *kp != '\t')
+           kp++;
+         if (*kp)
+           *kp++ = 0;
+         while (*kp == ' ' || *kp == '\t')
+           kp++;
+         if (!*kp)
+           continue;
+         distro = kp;
+         while (*kp && *kp != ' ' && *kp != '\t')
+           kp++;
+         if (*kp)
+           *kp++ = 0;
+         while (*kp == ' ' || *kp == '\t')
+           kp++;
+         if (!*kp)
+           continue;
+         repoinfos = sat_extend(repoinfos, nrepoinfos, 1, sizeof(*repoinfos), 15);
+         cinfo = repoinfos + nrepoinfos++;
+         memset(cinfo, 0, sizeof(*cinfo));
+         cinfo->baseurl = strdup(url);
+         cinfo->alias = sat_dupjoin(url, "/", distro);
+         cinfo->name = strdup(distro);
+         cinfo->type = TYPE_DEBIAN;
+         cinfo->enabled = 1;
+         cinfo->autorefresh = 1;
+         cinfo->repo_gpgcheck = 1;
+         cinfo->metadata_expire = METADATA_EXPIRE;
+         while (*kp)
+           {
+             char *compo;
+             while (*kp == ' ' || *kp == '\t')
+               kp++;
+             if (!*kp)
+               break;
+             compo = kp;
+             while (*kp && *kp != ' ' && *kp != '\t')
+               kp++;
+             if (*kp)
+               *kp++ = 0;
+             cinfo->components = sat_extend(cinfo->components, cinfo->ncomponents, 1, sizeof(*cinfo->components), 15);
+             cinfo->components[cinfo->ncomponents++] = strdup(compo);
+           }
+       }
+      fclose(fp);
+      fp = 0;
+    }
+  qsort(repoinfos, nrepoinfos, sizeof(*repoinfos), read_repoinfos_sort);
+  *nrepoinfosp = nrepoinfos;
+  return repoinfos;
+}
+
+#endif
+
 void
 free_repoinfos(struct repoinfo *repoinfos, int nrepoinfos)
 {
-  int i;
+  int i, j;
   for (i = 0; i < nrepoinfos; i++)
     {
       struct repoinfo *cinfo = repoinfos + i;
@@ -321,6 +461,9 @@ free_repoinfos(struct repoinfo *repoinfos, int nrepoinfos)
       sat_free(cinfo->metalink);
       sat_free(cinfo->mirrorlist);
       sat_free(cinfo->baseurl);
+      for (j = 0; j < cinfo->ncomponents; j++)
+        sat_free(cinfo->components[j]);
+      sat_free(cinfo->components);
     }
   sat_free(repoinfos);
 }
@@ -749,6 +892,8 @@ curlfopen(struct repoinfo *cinfo, const char *file, int uncompress, const unsign
   return fdopen(fd, "r");
 }
 
+#ifndef DEBIAN
+
 static void
 cleanupgpg(char *gpgdir)
 {
@@ -831,6 +976,25 @@ checksig(Pool *sigpool, FILE *fp, FILE *sigfp)
   return r == 0 ? 1 : 0;
 }
 
+#else
+
+int
+checksig(Pool *sigpool, FILE *fp, FILE *sigfp)
+{
+  char cmd[256];
+  int r;
+
+  snprintf(cmd, sizeof(cmd), "gpgv -q --keyring /etc/apt/trusted.gpg /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", fileno(sigfp), fileno(fp));
+  fcntl(fileno(fp), F_SETFD, 0);       /* clear CLOEXEC */
+  fcntl(fileno(sigfp), F_SETFD, 0);    /* clear CLOEXEC */
+  r = system(cmd);
+  fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
+  fcntl(fileno(sigfp), F_SETFD, FD_CLOEXEC);
+  return r == 0 ? 1 : 0;
+}
+
+#endif
+
 #define CHKSUM_IDENT "1.1"
 
 void
@@ -924,9 +1088,11 @@ usecachedrepo(Repo *repo, const char *repoext, unsigned char *cookie, int mark)
 
   flags = 0;
   if (repoext)
-    flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES;
-  if (repoext && strcmp(repoext, "DL") != 0)
-    flags |= REPO_LOCALPOOL;   /* no local pool for DL so that we can compare IDs */
+    {
+      flags = REPO_USE_LOADING|REPO_EXTEND_SOLVABLES;
+      if (strcmp(repoext, "DL") != 0)
+        flags |= REPO_LOCALPOOL;       /* no local pool for DL so that we can compare IDs */
+    }
 
   if (repo_add_solv_flags(repo, fp, flags))
     {
@@ -1071,8 +1237,10 @@ static Pool *
 read_sigs()
 {
   Pool *sigpool = pool_create();
+#ifndef DEBIAN
   Repo *repo = repo_create(sigpool, "rpmdbkeys");
   repo_add_rpmdb_pubkeys(repo, 0, 0);
+#endif
   return sigpool;
 }
 
@@ -1339,6 +1507,159 @@ load_stub(Pool *pool, Repodata *data, void *dp)
 
 static unsigned char installedcookie[32];
 
+#ifdef DEBIAN
+void
+repo_add_debdb(Repo *repo, int flags)
+{
+  FILE *fp;
+  if ((fp = fopen("/var/lib/dpkg/status", "r")) == 0)
+    {
+      perror("/var/lib/dpkg/status");
+      exit(1);
+    }
+  repo_add_debpackages(repo, fp, flags);
+  fclose(fp);
+}
+
+static int
+hexstr2bytes(unsigned char *buf, const char *str, int buflen)
+{
+  int i;
+  for (i = 0; i < buflen; i++) 
+    {    
+#define c2h(c) (((c)>='0' && (c)<='9') ? ((c)-'0')              \
+                : ((c)>='a' && (c)<='f') ? ((c)-('a'-10))       \
+                : ((c)>='A' && (c)<='F') ? ((c)-('A'-10))       \
+                : -1)
+      int v = c2h(*str);
+      str++;
+      if (v < 0) 
+        return 0;
+      buf[i] = v; 
+      v = c2h(*str);
+      str++;
+      if (v < 0) 
+        return 0;
+      buf[i] = (buf[i] << 4) | v; 
+#undef c2h
+    }    
+  return buflen;
+}
+
+const char *
+debian_find_component(struct repoinfo *cinfo, FILE *fp, char *comp, const unsigned char **chksump, Id *chksumtypep)
+{
+  char buf[4096];
+  Id chksumtype;
+  unsigned char *chksum;
+  Id curchksumtype;
+  int l, compl;
+  char *ch, *fn, *bp;
+  char *filename;
+  static char *basearch;
+  char *binarydir;
+  int lbinarydir;
+
+  if (!basearch)
+    {
+      struct utsname un;
+      if (uname(&un))
+       {
+         perror("uname");
+         exit(1);
+       }
+      basearch = strdup(un.machine);
+      if (basearch[0] == 'i' && basearch[1] && !strcmp(basearch + 2, "86"))
+       basearch[1] = '3';
+    }
+  binarydir = sat_dupjoin("binary-", basearch, "/");
+  lbinarydir = strlen(binarydir);
+  compl = strlen(comp);
+  rewind(fp);
+  curchksumtype = 0;
+  filename = 0;
+  chksum = sat_malloc(32);
+  chksumtype = 0;
+  while(fgets(buf, sizeof(buf), fp))
+    {
+      l = strlen(buf);
+      if (l == 0)
+       continue;
+      while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t'))
+       buf[--l] = 0;
+      if (!strncasecmp(buf, "MD5Sum:", 7))
+       {
+         curchksumtype = REPOKEY_TYPE_MD5;
+         continue;
+       }
+      if (!strncasecmp(buf, "SHA1:", 5))
+       {
+         curchksumtype = REPOKEY_TYPE_SHA1;
+         continue;
+       }
+      if (!strncasecmp(buf, "SHA256:", 7))
+       {
+         curchksumtype = REPOKEY_TYPE_SHA256;
+         continue;
+       }
+      if (!curchksumtype)
+       continue;
+      bp = buf;
+      if (*bp++ != ' ')
+       {
+         curchksumtype = 0;
+         continue;
+       }
+      ch = bp;
+      while (*bp && *bp != ' ' && *bp != '\t')
+       bp++;
+      if (!*bp)
+       continue;
+      *bp++ = 0;
+      while (*bp == ' ' || *bp == '\t')
+       bp++;
+      while (*bp && *bp != ' ' && *bp != '\t')
+       bp++;
+      if (!*bp)
+       continue;
+      while (*bp == ' ' || *bp == '\t')
+       bp++;
+      fn = bp;
+      if (strncmp(fn, comp, compl) != 0 || fn[compl] != '/')
+       continue;
+      bp += compl + 1;
+      if (strncmp(bp, binarydir, lbinarydir))
+       continue;
+      bp += lbinarydir;
+      if (!strcmp(bp, "Packages") || !strcmp(bp, "Packages.gz"))
+       {
+         if (filename && !strcmp(bp, "Packages"))
+           continue;
+         if (chksumtype && sat_chksum_len(chksumtype) > sat_chksum_len(curchksumtype))
+           continue;
+         if (!hexstr2bytes(chksum, ch, sat_chksum_len(curchksumtype)))
+           continue;
+         sat_free(filename);
+         filename = strdup(fn);
+         chksumtype = curchksumtype;
+       }
+    }
+  free(binarydir);
+  if (filename)
+    {
+      fn = sat_dupjoin("/", filename, 0);
+      sat_free(filename);
+      filename = sat_dupjoin("dists/", cinfo->name, fn);
+      sat_free(fn);
+    }
+  if (!chksumtype)
+    chksum = sat_free(chksum);
+  *chksump = chksum;
+  *chksumtypep = chksumtype;
+  return filename;
+}
+#endif
+
 void
 read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
 {
@@ -1357,23 +1678,36 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
   Repodata *data;
   int badchecksum;
   int dorefresh;
+#ifdef DEBIAN
+  FILE *fpr;
+  int j;
+#endif
 
   repo = repo_create(pool, "@System");
+#ifndef DEBIAN
   printf("rpm database:");
   if (stat("/var/lib/rpm/Packages", &stb))
     memset(&stb, 0, sizeof(&stb));
+#else
+  printf("dpgk database:");
+  if (stat("/var/lib/dpkg/status", &stb))
+    memset(&stb, 0, sizeof(&stb));
+#endif
   calc_checksum_stat(&stb, REPOKEY_TYPE_SHA256, installedcookie);
   if (usecachedrepo(repo, 0, installedcookie, 0))
     printf(" cached\n");
   else
     {
+#ifndef DEBIAN
       FILE *ofp;
-      printf(" reading\n");
       int done = 0;
+#endif
+      printf(" reading\n");
 
 #ifdef PRODUCTS_PATH
       repo_add_products(repo, PRODUCTS_PATH, 0, REPO_NO_INTERNALIZE);
 #endif
+#ifndef DEBIAN
       if ((ofp = fopen(calccachepath(repo, 0), "r")) != 0)
        {
          Repo *ref = repo_create(pool, "@System.old");
@@ -1387,6 +1721,9 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
        }
       if (!done)
         repo_add_rpmdb(repo, 0, 0, REPO_REUSE_REPODATA);
+#else
+        repo_add_debdb(repo, REPO_REUSE_REPODATA);
+#endif
       writecachedrepo(repo, 0, 0, installedcookie);
     }
   pool_set_installed(pool, repo);
@@ -1564,6 +1901,72 @@ read_repos(Pool *pool, struct repoinfo *repoinfos, int nrepoinfos)
            writecachedrepo(repo, 0, 0, cinfo->cookie);
          repodata_create_stubs(repo_last_repodata(repo));
          break;
+
+#ifdef DEBIAN
+        case TYPE_DEBIAN:
+         printf("debian repo '%s':", cinfo->alias);
+         fflush(stdout);
+         filename = sat_dupjoin("dists/", cinfo->name, "/Release");
+         if ((fpr = curlfopen(cinfo, filename, 0, 0, 0, 0)) == 0)
+           {
+             printf(" no Release file, skipped\n");
+             repo_free(repo, 1);
+             cinfo->repo = 0;
+             free((char *)filename);
+             break;
+           }
+         sat_free((char *)filename);
+         if (cinfo->repo_gpgcheck)
+           {
+             filename = sat_dupjoin("dists/", cinfo->name, "/Release.gpg");
+             sigfp = curlfopen(cinfo, filename, 0, 0, 0, 0);
+             sat_free((char *)filename);
+             if (!sigfp)
+               {
+                 printf(" unsigned, skipped\n");
+                 fclose(fpr);
+                 break;
+               }
+             if (!sigpool)
+               sigpool = read_sigs();
+             if (!checksig(sigpool, fpr, sigfp))
+               {
+                 printf(" checksig failed, skipped\n");
+                 fclose(sigfp);
+                 fclose(fpr);
+                 break;
+               }
+             fclose(sigfp);
+           }
+         calc_checksum_fp(fpr, REPOKEY_TYPE_SHA256, cinfo->cookie);
+         if (usecachedrepo(repo, 0, cinfo->cookie, 1))
+           {
+             printf(" cached\n");
+              fclose(fpr);
+             break;
+           }
+         printf(" fetching\n");
+          for (j = 0; j < cinfo->ncomponents; j++)
+           {
+             if (!(filename = debian_find_component(cinfo, fpr, cinfo->components[j], &filechksum, &filechksumtype)))
+               {
+                 printf("[component %s not found]\n", cinfo->components[j]);
+                 continue;
+               }
+             if ((fp = curlfopen(cinfo, filename, iscompressed(filename), filechksum, filechksumtype, &badchecksum)) != 0)
+               {
+                 repo_add_debpackages(repo, fp, 0);
+                 fclose(fp);
+               }
+             sat_free((char *)filechksum);
+             sat_free((char *)filename);
+           }
+         fclose(fpr);
+         if (!badchecksum)
+           writecachedrepo(repo, 0, 0, cinfo->cookie);
+         break;
+#endif
+
        default:
          printf("unsupported repo '%s': skipped\n", cinfo->alias);
          repo_free(repo, 1);
@@ -1590,8 +1993,13 @@ str2archid(Pool *pool, char *arch)
   return id;
 }
 
+
+#define DEPGLOB_NAME     1
+#define DEPGLOB_DEP      2
+#define DEPGLOB_NAMEDEP  3
+
 int
-depglob(Pool *pool, char *name, Queue *job)
+depglob(Pool *pool, char *name, Queue *job, int what)
 {
   Id p, pp;
   Id id = str2id(pool, name, 0);
@@ -1603,7 +2011,7 @@ depglob(Pool *pool, char *name, Queue *job)
        {
          Solvable *s = pool->solvables + p;
          match = 1;
-         if (s->name == id)
+         if (s->name == id && (what & DEPGLOB_NAME) != 0)
            {
              queue_push2(job, SOLVER_SOLVABLE_NAME, id);
              return 1;
@@ -1611,7 +2019,8 @@ depglob(Pool *pool, char *name, Queue *job)
        }
       if (match)
        {
-         printf("[using capability match for '%s']\n", name);
+         if (what == DEPGLOB_NAMEDEP)
+           printf("[using capability match for '%s']\n", name);
          queue_push2(job, SOLVER_SOLVABLE_PROVIDES, id);
          return 1;
        }
@@ -1620,142 +2029,108 @@ depglob(Pool *pool, char *name, Queue *job)
   if (strpbrk(name, "[*?") == 0)
     return 0;
 
-  /* looks like a name glob. hard work. */
-  for (p = 1; p < pool->nsolvables; p++)
+  if ((what & DEPGLOB_NAME) != 0)
     {
-      Solvable *s = pool->solvables + p;
-      if (!s->repo || !pool_installable(pool, s))
-       continue;
-      id = s->name;
-      if (fnmatch(name, id2str(pool, id), 0) == 0)
+      /* looks like a name glob. hard work. */
+      for (p = 1; p < pool->nsolvables; p++)
        {
-         for (i = 0; i < job->count; i += 2)
-           if (job->elements[i] == SOLVER_SOLVABLE_NAME && job->elements[i + 1] == id)
-             break;
-         if (i == job->count)
-           queue_push2(job, SOLVER_SOLVABLE_NAME, id);
-         match = 1;
+         Solvable *s = pool->solvables + p;
+         if (!s->repo || !pool_installable(pool, s))
+           continue;
+         id = s->name;
+         if (fnmatch(name, id2str(pool, id), 0) == 0)
+           {
+             for (i = 0; i < job->count; i += 2)
+               if (job->elements[i] == SOLVER_SOLVABLE_NAME && job->elements[i + 1] == id)
+                 break;
+             if (i == job->count)
+               queue_push2(job, SOLVER_SOLVABLE_NAME, id);
+             match = 1;
+           }
        }
+      if (match)
+       return 1;
     }
-  if (match)
-    return 1;
-  /* looks like a dep glob. really hard work. */
-  for (id = 1; id < pool->ss.nstrings; id++)
+  if ((what & DEPGLOB_DEP))
     {
-      if (!pool->whatprovides[id])
-       continue;
-      if (fnmatch(name, id2str(pool, id), 0) == 0)
+      /* looks like a dep glob. really hard work. */
+      for (id = 1; id < pool->ss.nstrings; id++)
        {
-         if (!match)
-           printf("[using capability match for '%s']\n", name);
-         for (i = 0; i < job->count; i += 2)
-           if (job->elements[i] == SOLVER_SOLVABLE_PROVIDES && job->elements[i + 1] == id)
-             break;
-         if (i == job->count)
-           queue_push2(job, SOLVER_SOLVABLE_PROVIDES, id);
-         match = 1;
+         if (!pool->whatprovides[id])
+           continue;
+         if (fnmatch(name, id2str(pool, id), 0) == 0)
+           {
+             if (!match && what == DEPGLOB_NAMEDEP)
+               printf("[using capability match for '%s']\n", name);
+             for (i = 0; i < job->count; i += 2)
+               if (job->elements[i] == SOLVER_SOLVABLE_PROVIDES && job->elements[i + 1] == id)
+                 break;
+             if (i == job->count)
+               queue_push2(job, SOLVER_SOLVABLE_PROVIDES, id);
+             match = 1;
+           }
        }
+      if (match)
+       return 1;
     }
-  if (match)
-    return 1;
   return 0;
 }
 
-void
-addrelation(Pool *pool, Queue *job, int flags, Id evr)
-{
-  int i;
-  for (i = 0; i < job->count; i += 2)
-    {
-      if (job->elements[i] != SOLVER_SOLVABLE_NAME && job->elements[i] != SOLVER_SOLVABLE_PROVIDES)
-       continue;
-      job->elements[i + 1] = rel2id(pool, job->elements[i + 1], evr, flags, 1);
-    }
-}
-
 int
-limitevr(Pool *pool, char *evr, Queue *job, Id archid)
+limitrelation(Pool *pool, Queue *job, int flags, Id evr)
 {
-  Queue mq;
-  Id p, pp, evrid;
-  int matched = 0;
   int i, j;
-  Solvable *s;
-  const char *sevr;
-
-  queue_init(&mq);
-  for (i = 0; i < job->count; i += 2)
+  Id p, pp;
+  for (i = j = 0; i < job->count; i += 2)
     {
-      queue_empty(&mq);
-      FOR_JOB_SELECT(p, pp, job->elements[i], job->elements[i + 1])
+      Id select = job->elements[i] & SOLVER_SELECTMASK;
+      if (select != SOLVER_SOLVABLE_NAME && select != SOLVER_SOLVABLE_PROVIDES)
        {
-         s = pool_id2solvable(pool, p);
-         if (archid && s->arch != archid)
-           continue;
-          sevr = id2str(pool, s->evr);
-          if (!strchr(evr, ':') && strchr(sevr, ':'))
-           sevr = strchr(sevr, ':') + 1;
-         if (evrcmp_str(pool, sevr, evr, EVRCMP_MATCH) == 0)
-            queue_push(&mq, p);
+         fprintf(stderr, "limitrelation only works on name/provides jobs\n");
+         exit(1);
        }
-      if (mq.count)
-       {
-         if (!matched && i)
-           {
-             queue_deleten(job, 0, i);
-             i = 0;
-           }
-         matched = 1;
-         /* if all solvables have the same evr */
-         s = pool_id2solvable(pool, mq.elements[0]);
-         evrid = s->evr;
-         for (j = 0; j < mq.count; j++)
-           {
-             s = pool_id2solvable(pool, mq.elements[j]);
-             if (s->evr != evrid)
-               break;
-           }
-         if (j == mq.count && j > 1)
-           {
-             prune_to_best_arch(pool, &mq);
-             // prune_to_highest_prio(pool, &mq);
-             mq.count = 1;
-           }
-         if (mq.count > 1)
-           {
-             job->elements[i] = SOLVER_SOLVABLE_ONE_OF;
-             job->elements[i + 1] = pool_queuetowhatprovides(pool, &mq);
-           }
+      job->elements[i + 1] = rel2id(pool, job->elements[i + 1], evr, flags, 1);
+      if (flags == REL_ARCH)
+       job->elements[i] |= SOLVER_SETARCH;
+      if (flags == REL_EQ && select == SOLVER_SOLVABLE_NAME && job->elements[i])
+       {
+#ifndef DEBIAN
+         const char *evrstr = id2str(pool, evr);
+         if (!strchr(evrstr, '-'))
+           job->elements[i] |= SOLVER_SETEV;
          else
-           {
-             job->elements[i] = SOLVER_SOLVABLE;
-             job->elements[i + 1] = mq.elements[0];
-           }
+#endif
+           job->elements[i] |= SOLVER_SETEVR;
        }
-      else if (matched)
+      /* make sure we still have matches */
+      FOR_JOB_SELECT(p, pp, job->elements[i], job->elements[i + 1])
+       break;
+      if (p)
        {
-         queue_deleten(job, i, 2);
-         i -= 2;
+         job->elements[j] = job->elements[i];
+         job->elements[j + 1] = job->elements[i + 1];
+         j += 2;
        }
     }
-  queue_free(&mq);
-  if (matched)
-    return 1;
-  if (!archid)
+  queue_truncate(job, j);
+  return j / 2;
+}
+
+int
+limitrelation_arch(Pool *pool, Queue *job, int flags, char *evr)
+{
+  char *r;
+  Id archid;
+  if ((r = strrchr(evr, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
     {
-      char *r;
-      if ((r = strrchr(evr, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
-       {
-         *r = 0;
-         if (limitevr(pool, evr, job, archid))
-           {
-             *r = '.';
-             return 1;
-           }
-         *r = '.';
-       }
+      *r = 0;
+      limitrelation(pool, job, REL_ARCH, archid);
+      limitrelation(pool, job, flags, str2id(pool, evr, 1));
+      *r = '.';
     }
-  return 0;
+  else
+    limitrelation(pool, job, flags, str2id(pool, evr, 1));
+  return job->count / 2;
 }
 
 int
@@ -1763,12 +2138,11 @@ limitrepo(Pool *pool, Id repofilter, Queue *job)
 {
   Queue mq;
   Id p, pp;
-  int matched = 0;
-  int i;
+  int i, j;
   Solvable *s;
 
   queue_init(&mq);
-  for (i = 0; i < job->count; i += 2)
+  for (i = j = 0; i < job->count; i += 2)
     {
       queue_empty(&mq);
       FOR_JOB_SELECT(p, pp, job->elements[i], job->elements[i + 1])
@@ -1779,34 +2153,26 @@ limitrepo(Pool *pool, Id repofilter, Queue *job)
        }
       if (mq.count)
        {
-         if (!matched && i)
-           {
-             queue_deleten(job, 0, i);
-             i = 0;
-           }
-         matched = 1;
-         if (mq.count > 1)
+         /* here we assume that repo == vendor, so we also set SOLVER_SETVENDOR */
+         if (mq.count == 1)
            {
-             job->elements[i] = SOLVER_SOLVABLE_ONE_OF;
-             job->elements[i + 1] = pool_queuetowhatprovides(pool, &mq);
+             job->elements[j] = SOLVER_SOLVABLE | (job->elements[i] & SOLVER_SETMASK) | SOLVER_SETVENDOR | SOLVER_SETREPO | SOLVER_NOAUTOSET;
+             job->elements[j + 1] = mq.elements[0];
            }
          else
            {
-             job->elements[i] = SOLVER_SOLVABLE;
-             job->elements[i + 1] = mq.elements[0];
+             job->elements[j] = SOLVER_SOLVABLE_ONE_OF | (job->elements[i] & SOLVER_SETMASK) | SOLVER_SETVENDOR | SOLVER_SETREPO;
+             job->elements[j + 1] = pool_queuetowhatprovides(pool, &mq);
            }
-       }
-      else if (matched)
-       {
-         queue_deleten(job, i, 2);
-         i -= 2;
+         j += 2;
        }
     }
+  queue_truncate(job, j);
   queue_free(&mq);
-  return matched;
+  return j / 2;
 }
 
-void
+int
 mkselect(Pool *pool, int mode, char *name, Queue *job)
 {
   char *r, *r2;
@@ -1815,11 +2181,10 @@ mkselect(Pool *pool, int mode, char *name, Queue *job)
   if (*name == '/')
     {
       Dataiterator di;
+      int type = strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
       Queue q;
-      int match = 0;
-
       queue_init(&q);
-      dataiterator_init(&di, pool, mode == SOLVER_ERASE ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, SEARCH_STRING|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
+      dataiterator_init(&di, pool, mode == SOLVER_ERASE ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
       while (dataiterator_step(&di))
        {
          Solvable *s = pool->solvables + di.solvid;
@@ -1832,24 +2197,23 @@ mkselect(Pool *pool, int mode, char *name, Queue *job)
       if (q.count)
        {
          printf("[using file list match for '%s']\n", name);
-         match = 1;
          if (q.count > 1)
            queue_push2(job, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q));
          else
-           queue_push2(job, SOLVER_SOLVABLE, q.elements[0]);
+           queue_push2(job, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
+         queue_free(&q);
+         return job->count / 2;
        }
-      queue_free(&q);
-      if (match)
-       return;
     }
   if ((r = strpbrk(name, "<=>")) != 0)
     {
       /* relation case, support:
        * depglob rel
-       * depglob.rpm rel
+       * depglob.arch rel
        */
       int rflags = 0;
       int nend = r - name;
+      char oldnend;
       for (; *r; r++)
        {
          if (*r == '<')
@@ -1865,79 +2229,84 @@ mkselect(Pool *pool, int mode, char *name, Queue *job)
        r++;
       while (nend && (name[nend - 1] == ' ' || name[nend -1 ] == '\t'))
        nend--;
-      name[nend] = 0;
       if (!*name || !*r)
        {
          fprintf(stderr, "bad relation\n");
          exit(1);
        }
-      if (depglob(pool, name, job))
+      oldnend = name[nend];
+      name[nend] = 0;
+      if (depglob(pool, name, job, DEPGLOB_NAMEDEP))
        {
-         addrelation(pool, job, rflags, str2id(pool, r, 1));
-         return;
+         name[nend] = oldnend;
+         limitrelation(pool, job, rflags, str2id(pool, r, 1));
+         return job->count / 2;
        }
       if ((r2 = strrchr(name, '.')) != 0 && r2[1] && (archid = str2archid(pool, r2 + 1)) != 0)
        {
          *r2 = 0;
-         if (depglob(pool, name, job))
+         if (depglob(pool, name, job, DEPGLOB_NAMEDEP))
            {
+             name[nend] = oldnend;
              *r2 = '.';
-             addrelation(pool, job, REL_ARCH, archid);
-             addrelation(pool, job, rflags, str2id(pool, r, 1));
-             return;
+             limitrelation(pool, job, REL_ARCH, archid);
+             limitrelation(pool, job, rflags, str2id(pool, r, 1));
+             return job->count / 2;
            }
          *r2 = '.';
        }
+      name[nend] = oldnend;
     }
   else
     {
       /* no relation case, support:
        * depglob
        * depglob.arch
-       * depglob-version-release
-       * depglob-version-release.arch
+       * nameglob-version
+       * nameglob-version.arch
+       * nameglob-version-release
+       * nameglob-version-release.arch
        */
-      if (depglob(pool, name, job))
-       return;
-      archid = 0;
+      if (depglob(pool, name, job, DEPGLOB_NAMEDEP))
+       return job->count / 2;
       if ((r = strrchr(name, '.')) != 0 && r[1] && (archid = str2archid(pool, r + 1)) != 0)
        {
          *r = 0;
-         if (depglob(pool, name, job))
+         if (depglob(pool, name, job, DEPGLOB_NAMEDEP))
            {
              *r = '.';
-             addrelation(pool, job, REL_ARCH, archid);
-             return;
+             limitrelation(pool, job, REL_ARCH, archid);
+             return job->count / 2;
            }
          *r = '.';
        }
       if ((r = strrchr(name, '-')) != 0)
        {
          *r = 0;
-         if (depglob(pool, name, job))
+         if (depglob(pool, name, job, DEPGLOB_NAME))
            {
              /* have just the version */
+             limitrelation_arch(pool, job, REL_EQ, r + 1);
              *r = '-';
-             if (limitevr(pool, r + 1, job, 0))
-               return;
+             return job->count / 2;
            }
          if ((r2 = strrchr(name, '-')) != 0)
            {
              *r = '-';
              *r2 = 0;
-             if (depglob(pool, name, job))
+             r = r2;
+             if (depglob(pool, name, job, DEPGLOB_NAME))
                {
-                 *r2 = '-';
-                 if (limitevr(pool, r2 + 1, job, 0))
-                   return;
+                 /* have version-release */
+                 limitrelation_arch(pool, job, REL_EQ, r + 1);
+                 *r = '-';
+                 return job->count / 2;
                }
-             *r2 = '-';
            }
          *r = '-';
        }
     }
-  fprintf(stderr, "nothing matches '%s'\n", name);
-  exit(1);
+  return 0;
 }
 
 
@@ -1968,6 +2337,8 @@ yesno(const char *str)
     }
 }
 
+#ifndef DEBIAN
+
 struct fcstate {
   FILE **newpkgsfps;
   Queue *checkq;
@@ -2011,6 +2382,7 @@ fileconflict_cb(Pool *pool, Id p, void *cbdata)
   return rpm_byfp(fp, solvable2str(pool, s), &fcstate->rpmdbstate);
 }
 
+
 void
 runrpm(const char *arg, const char *name, int dupfd3)
 {
@@ -2047,6 +2419,48 @@ runrpm(const char *arg, const char *name, int dupfd3)
     }
 }
 
+#endif
+
+#ifdef DEBIAN
+
+void
+rundpkg(const char *arg, const char *name, int dupfd3)
+{
+  pid_t pid;
+  int status;
+
+  if ((pid = fork()) == (pid_t)-1)
+    {
+      perror("fork");
+      exit(1);
+    }
+  if (pid == 0)
+    {
+      if (dupfd3 != -1 && dupfd3 != 3)
+       {
+         dup2(dupfd3, 3);
+         close(dupfd3);
+       }
+      if (dupfd3 != -1)
+       fcntl(3, F_SETFD, 0);   /* clear CLOEXEC */
+      if (strcmp(arg, "--install") == 0)
+        execlp("dpkg", "dpkg", "--install", "--force", "all", name, (char *)0);
+      else
+        execlp("dpkg", "dpkg", "--remove", "--force", "all", name, (char *)0);
+      perror("dpkg");
+      _exit(0);
+    }
+  while (waitpid(pid, &status, 0) != pid)
+    ;
+  if (status)
+    {
+      printf("dpkg failed\n");
+      exit(1);
+    }
+}
+
+#endif
+
 static Id
 nscallback(Pool *pool, void *data, Id name, Id evr)
 {
@@ -2170,6 +2584,7 @@ rewrite_repos(Pool *pool, Id *addedfileprovides)
 #define MODE_INFO        7
 #define MODE_REPOLIST    8
 #define MODE_SEARCH     9
+#define MODE_ERASECLEAN  10
 
 void
 usage(int r)
@@ -2207,7 +2622,6 @@ main(int argc, char **argv)
   char inbuf[128], *ip;
   int allpkgs = 0;
   FILE **newpkgsfps;
-  struct fcstate fcstate;
   Id *addedfileprovides = 0;
   Id repofilter = 0;
 
@@ -2230,6 +2644,11 @@ main(int argc, char **argv)
       mainmode = MODE_ERASE;
       mode = SOLVER_ERASE;
     }
+  else if (!strcmp(argv[0], "eraseclean") || !strcmp(argv[0], "rmclean"))
+    {
+      mainmode = MODE_ERASECLEAN;
+      mode = SOLVER_ERASE;
+    }
   else if (!strcmp(argv[0], "list"))
     {
       mainmode = MODE_LIST;
@@ -2378,8 +2797,13 @@ main(int argc, char **argv)
        {
          int l;
           l = strlen(argv[i]);
+#ifndef DEBIAN
          if (l <= 4 || strcmp(argv[i] + l - 4, ".rpm"))
            continue;
+#else
+         if (l <= 4 || strcmp(argv[i] + l - 4, ".deb"))
+           continue;
+#endif
          if (access(argv[i], R_OK))
            {
              perror(argv[i]);
@@ -2389,7 +2813,11 @@ main(int argc, char **argv)
            commandlinepkgs = sat_calloc(argc, sizeof(Id));
          if (!commandlinerepo)
            commandlinerepo = repo_create(pool, "@commandline");
+#ifndef DEBIAN
          repo_add_rpms(commandlinerepo, (const char **)argv + i, 1, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE);
+#else
+         repo_add_debs(commandlinerepo, (const char **)argv + i, 1, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE);
+#endif
          commandlinepkgs[i] = commandlinerepo->end - 1;
        }
       if (commandlinerepo)
@@ -2417,7 +2845,11 @@ main(int argc, char **argv)
          continue;
        }
       queue_init(&job2);
-      mkselect(pool, mode, argv[i], &job2);
+      if (!mkselect(pool, mode, argv[i], &job2))
+       {
+         fprintf(stderr, "nothing matches '%s'\n", argv[i]);
+         exit(1);
+       }
       if (repofilter && !limitrepo(pool, repofilter, &job2))
         {
          fprintf(stderr, "nothing in repo matches '%s'\n", argv[i]);
@@ -2447,11 +2879,16 @@ main(int argc, char **argv)
              Solvable *s = pool_id2solvable(pool, p);
              if (mainmode == MODE_INFO)
                {
+                 const char *str;
                  printf("Name:        %s\n", solvable2str(pool, s));
                  printf("Repo:        %s\n", s->repo->name);
                  printf("Summary:     %s\n", solvable_lookup_str(s, SOLVABLE_SUMMARY));
-                 printf("Url:         %s\n", solvable_lookup_str(s, SOLVABLE_URL));
-                 printf("License:     %s\n", solvable_lookup_str(s, SOLVABLE_LICENSE));
+                 str = solvable_lookup_str(s, SOLVABLE_URL);
+                 if (str)
+                   printf("Url:         %s\n", str);
+                 str = solvable_lookup_str(s, SOLVABLE_LICENSE);
+                 if (str)
+                   printf("License:     %s\n", str);
                  printf("Description:\n%s\n", solvable_lookup_str(s, SOLVABLE_DESCRIPTION));
                  printf("\n");
                }
@@ -2544,6 +2981,8 @@ main(int argc, char **argv)
            }
        }
       job.elements[i] |= mode;
+      if (mainmode == MODE_ERASECLEAN)
+        job.elements[i] |= SOLVER_CLEANDEPS;
     }
 
   if (mainmode == MODE_DISTUPGRADE && allpkgs && repofilter)
@@ -2558,7 +2997,9 @@ main(int argc, char **argv)
   addsoftlocks(pool, &job);
 #endif
 
+#ifndef DEBIAN
 rerunsolver:
+#endif
   for (;;)
     {
       Id problem, solution;
@@ -2576,7 +3017,7 @@ rerunsolver:
          solv->allowarchchange = 1;
          solv->allowvendorchange = 1;
        }
-      if (mainmode == MODE_ERASE)
+      if (mainmode == MODE_ERASE || mainmode == MODE_ERASECLEAN)
        solv->allowuninstall = 1;       /* don't nag */
 
       solver_solve(solv, &job);
@@ -2638,13 +3079,21 @@ rerunsolver:
   if (!trans->steps.count)
     {
       printf("Nothing to do.\n");
+      solver_free(solv);
+      queue_free(&job);
+      pool_free(pool);
+      free_repoinfos(repoinfos, nrepoinfos);
+      sat_free(commandlinepkgs);
+#ifdef FEDORA
+      yum_substitute(pool, 0);
+#endif
       exit(1);
     }
   printf("\n");
   printf("Transaction summary:\n\n");
   solver_printtransaction(solv);
 
-#ifndef FEDORA
+#if !defined(FEDORA) && !defined(DEBIAN)
   if (1)
     {
       DUChanges duc[4];
@@ -2665,6 +3114,14 @@ rerunsolver:
   if (!yesno("OK to continue (y/n)? "))
     {
       printf("Abort.\n");
+      solver_free(solv);
+      queue_free(&job);
+      pool_free(pool);
+      free_repoinfos(repoinfos, nrepoinfos);
+      sat_free(commandlinepkgs);
+#ifdef FEDORA
+      yum_substitute(pool, 0);
+#endif
       exit(1);
     }
 
@@ -2830,9 +3287,11 @@ rerunsolver:
       putchar('\n');
     }
 
+#ifndef DEBIAN
   if (newpkgs)
     {
       Queue conflicts;
+      struct fcstate fcstate;
 
       printf("Searching for file conflicts\n");
       queue_init(&conflicts);
@@ -2861,12 +3320,15 @@ rerunsolver:
        }
       queue_free(&conflicts);
     }
+#endif
 
   printf("Committing transaction:\n\n");
   transaction_order(trans, 0);
   for (i = 0; i < trans->steps.count; i++)
     {
+#ifndef DEBIAN
       const char *evr, *evrp, *nvra;
+#endif
       Solvable *s;
       int j;
       FILE *fp;
@@ -2878,6 +3340,7 @@ rerunsolver:
        {
        case SOLVER_TRANSACTION_ERASE:
          printf("erase %s\n", solvid2str(pool, p));
+#ifndef DEBIAN
          if (!s->repo->rpmdbid || !s->repo->rpmdbid[p - s->repo->start])
            continue;
          /* strip epoch from evr */
@@ -2888,7 +3351,10 @@ rerunsolver:
            evr = evrp + 1;
          nvra = pool_tmpjoin(pool, id2str(pool, s->name), "-", evr);
          nvra = pool_tmpjoin(pool, nvra, ".", id2str(pool, s->arch));
-         runrpm("-e", nvra, -1);       /* to bad that --querybynumber doesn't work */
+         runrpm("-e", nvra, -1);       /* too bad that --querybynumber doesn't work */
+#else
+         rundpkg("--remove", id2str(pool, s->name), 0);
+#endif
          break;
        case SOLVER_TRANSACTION_INSTALL:
        case SOLVER_TRANSACTION_MULTIINSTALL:
@@ -2901,7 +3367,11 @@ rerunsolver:
            continue;
          rewind(fp);
          lseek(fileno(fp), 0, SEEK_SET);
+#ifndef DEBIAN
          runrpm(type == SOLVER_TRANSACTION_MULTIINSTALL ? "-i" : "-U", "/dev/fd/3", fileno(fp));
+#else
+         rundpkg("--install", "/dev/fd/3", fileno(fp));
+#endif
          fclose(fp);
          newpkgsfps[j] = 0;
          break;
index c6bd1bc..8df2339 100644 (file)
@@ -1,8 +1,12 @@
 SET(libsatsolverext_SRCS
-    pool_fileconflicts.c repo_content.c repo_deltainfoxml.c repo_helix.c repo_products.c
-    repo_releasefile_products.c repo_repomdxml.c repo_rpmdb.c repo_rpmmd.c
+    repo_content.c repo_deltainfoxml.c repo_helix.c repo_products.c
+    repo_releasefile_products.c repo_repomdxml.c repo_rpmmd.c
     repo_susetags.c repo_updateinfoxml.c repo_write.c repo_zyppdb.c
     repo_deb.c)
+IF ( NOT DEBIAN )
+SET(libsatsolverext_SRCS
+    ${libsatsolverext_SRCS} pool_fileconflicts.c repo_rpmdb.c)
+ENDIF (NOT DEBIAN)
 
 ADD_LIBRARY(satsolverext STATIC ${libsatsolverext_SRCS})
 
index 6d3d64b..bad3101 100644 (file)
@@ -167,6 +167,8 @@ control2solvable(Solvable *s, Repodata *data, char *control)
   char *p, *q, *end, *tag;
   int x, l;
   int havesource = 0;
+  char checksum[32 * 2 + 1];
+  Id checksumtype = 0;
 
   p = control;
   while (*p)
@@ -239,6 +241,10 @@ control2solvable(Solvable *s, Repodata *data, char *control)
          if (!strcasecmp(tag, "enhances"))
            s->enhances = makedeps(repo, q, s->enhances, 0);
          break;
+       case 'F' << 8 | 'I':
+         if (!strcasecmp(tag, "filename"))
+           repodata_set_location(data, s - pool->solvables, 0, 0, q);
+         break;
        case 'H' << 8 | 'O':
          if (!strcasecmp(tag, "homepage"))
            repodata_set_str(data, s - pool->solvables, SOLVABLE_URL, q);
@@ -247,6 +253,13 @@ control2solvable(Solvable *s, Repodata *data, char *control)
          if (!strcasecmp(tag, "installed-size"))
            repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLSIZE, atoi(q));
          break;
+       case 'M' << 8 | 'D':
+         if (!strcasecmp(tag, "md5sum") && !checksumtype && strlen(q) == 16 * 2)
+           {
+             strcpy(checksum, q);
+             checksumtype = REPOKEY_TYPE_MD5;
+           }
+         break;
        case 'P' << 8 | 'A':
          if (!strcasecmp(tag, "package"))
            s->name = str2id(pool, q, 1);
@@ -263,6 +276,18 @@ control2solvable(Solvable *s, Repodata *data, char *control)
          else if (!strcasecmp(tag, "recommends"))
            s->recommends = makedeps(repo, q, s->recommends, 0);
          break;
+       case 'S' << 8 | 'H':
+         if (!strcasecmp(tag, "sha1") && checksumtype != REPOKEY_TYPE_SHA256 && strlen(q) == 20 * 2)
+           {
+             strcpy(checksum, q);
+             checksumtype = REPOKEY_TYPE_SHA1;
+           }
+         else if (!strcasecmp(tag, "sha256") && strlen(q) == 32 * 2)
+           {
+             strcpy(checksum, q);
+             checksumtype = REPOKEY_TYPE_SHA256;
+           }
+         break;
        case 'S' << 8 | 'O':
          if (!strcasecmp(tag, "source"))
            {
@@ -291,6 +316,8 @@ control2solvable(Solvable *s, Repodata *data, char *control)
          break;
        }
     }
+  if (checksumtype)
+    repodata_set_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, checksumtype, checksum);
   if (!s->arch)
     s->arch = ARCH_ALL;
   if (!s->evr)
@@ -299,6 +326,26 @@ control2solvable(Solvable *s, Repodata *data, char *control)
     s->provides = repo_addid_dep(repo, s->provides, rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
   if (s->name && !havesource)
     repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
+  if (s->obsoletes)
+    {
+      /* obsoletes only count when the packages also conflict */
+      int i, j, k;
+      Id d;
+      for (i = j = s->obsoletes; (d = repo->idarraydata[i]) != 0; i++)
+       {
+         if (s->conflicts)
+           {
+             for (k = s->conflicts; repo->idarraydata[k] != 0; k++)
+               if (repo->idarraydata[k] == d)
+                 break;
+             if (repo->idarraydata[k])
+               {
+                 repo->idarraydata[j++] = d;
+               }
+           }
+       }
+      repo->idarraydata[j] = 0;
+    }
 }
 
 void
index b5e8b96..56e2733 100644 (file)
@@ -45,6 +45,7 @@ enum state {
   STATE_RELEASE,         // 5
   STATE_ARCH,            // 6
   STATE_SUMMARY,         // 7
+  STATE_SHORTSUMMARY,
   STATE_DESCRIPTION,     // 8
   STATE_UPDATEREPOKEY,   // 9 should go away
   STATE_CPEID,         // 9
@@ -77,6 +78,7 @@ static struct stateswitch stateswitches[] = {
   { STATE_PRODUCT,   "arch",          STATE_ARCH,          1 },
   { STATE_PRODUCT,   "productline",   STATE_PRODUCTLINE,   1 },
   { STATE_PRODUCT,   "summary",       STATE_SUMMARY,       1 },
+  { STATE_PRODUCT,   "shortsummary",  STATE_SHORTSUMMARY,  1 },
   { STATE_PRODUCT,   "description",   STATE_DESCRIPTION,   1 },
   { STATE_PRODUCT,   "register",      STATE_REGISTER,      0 },
   { STATE_PRODUCT,   "urls",          STATE_URLS,          0 },
@@ -324,6 +326,9 @@ endElement(void *userData, const char *name)
       repodata_set_str(pd->data, pd->handle, langtag(pd, SOLVABLE_SUMMARY, pd->tmplang), pd->content);
       pd->tmplang = sat_free((void *)pd->tmplang);
       break;
+    case STATE_SHORTSUMMARY:
+      repodata_set_str(pd->data, pd->handle, PRODUCT_SHORTLABEL, pd->content);
+      break;
     case STATE_DESCRIPTION:
       repodata_set_str(pd->data, pd->handle, langtag(pd, SOLVABLE_DESCRIPTION, pd->tmplang), pd->content );
       pd->tmplang = sat_free((void *)pd->tmplang);
@@ -535,7 +540,7 @@ repo_add_products(Repo *repo, const char *proddir, const char *root, int flags)
       join_freemem();
       return;
     }
-  
+
   /* code11 didn't work, try -release files parsing */
   fullpath = root ? join2(root, "", "/etc") : "/etc";
   dir = opendir(fullpath);
index 0214979..34f2b65 100644 (file)
@@ -2754,6 +2754,8 @@ parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl)
              Id htype = 0;
 #endif
              // printf("V3 signature packet\n");
+             if (l < 17)
+               continue;
              if (p[2] != 0x10 && p[2] != 0x11 && p[2] != 0x12 && p[2] != 0x13 && p[2] != 0x1f)
                continue;
              if (!memcmp(keyid, p + 6, 8))
@@ -2797,6 +2799,8 @@ parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl)
              unsigned char issuer[8];
 
              // printf("V4 signature packet\n");
+             if (l < 6)
+               continue;
              if (p[1] != 0x10 && p[1] != 0x11 && p[1] != 0x12 && p[1] != 0x13 && p[1] != 0x1f)
                continue;
              haveissuer = 0;
@@ -2804,8 +2808,18 @@ parsekeydata(Solvable *s, Repodata *data, unsigned char *p, int pl)
              q = p + 4;
              for (j = 0; q && j < 2; j++)
                {
+                 if (q + 2 > p + l)
+                   {
+                     q = 0;
+                     break;
+                   }
                  ql = q[0] << 8 | q[1];
                  q += 2;
+                 if (q + ql > p + l)
+                   {
+                     q = 0;
+                     break;
+                   }
                  while (ql)
                    {
                      int sl;
index c2bf69e..406198d 100644 (file)
@@ -6,6 +6,7 @@
  */
 
 #define _GNU_SOURCE
+#define _XOPEN_SOURCE /* glibc2 needs this */
 #include <sys/types.h>
 #include <limits.h>
 #include <fcntl.h>
@@ -13,6 +14,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <expat.h>
+#include <time.h>
 
 #include "pool.h"
 #include "repo.h"
@@ -119,9 +121,29 @@ struct parsedata {
 };
 
 /*
+ * Convert date strings ("1287746075" or "2010-10-22 13:14:35")
+ * to timestamp.
+ */
+static time_t
+datestr2timestamp(const char *date)
+{
+  if (!date)
+    return 0;
+
+  if (strlen(date) == strspn(date, "0123456789"))
+    return atoi(date);
+
+  struct tm tm;
+  memset(&tm, 0, sizeof(tm));
+  if (!strptime(date, "%F%T", &tm))
+    return 0;
+  return timegm(&tm);
+}
+
+/*
  * if we have seen a <filename>...
  * inside of <package>...
- * 
+ *
  *
  * If not, we must insert an empty filename to UPDATE_COLLECTION_FILENAME
  * at </package> in order to keep all UPDATE_COLLECTION_* arrays in sync
@@ -263,11 +285,11 @@ startElement(void *userData, const char *name, const char **atts)
            else if (!strcmp(*atts, "version"))
              version = atts[1];
          }
-       
+
 
        solvable = pd->solvable = pool_id2solvable(pool, repo_add_solvable(pd->repo));
        pd->datanum = pd->solvable - pool->solvables;
-       
+
        solvable->vendor = str2id(pool, from, 1);
        solvable->evr = str2id(pool, version, 1);
        solvable->arch = ARCH_NOARCH;
@@ -296,13 +318,7 @@ startElement(void *userData, const char *name, const char **atts)
          }
        if (date)
          {
-           if (strlen(date) == strspn(date, "0123456789"))
-             repodata_set_num(pd->data, pd->datanum, SOLVABLE_BUILDTIME, atoi(date));
-           else
-             {
-               /* FIXME: must convert to interger! */
-               repodata_set_str(pd->data, pd->datanum, SOLVABLE_BUILDTIME, date);
-             }
+           repodata_set_num(pd->data, pd->datanum, SOLVABLE_BUILDTIME, datestr2timestamp(date));
          }
       }
       break;
@@ -351,13 +367,13 @@ startElement(void *userData, const char *name, const char **atts)
       /* <collection short="F8" */
     case STATE_COLLECTION:
       break;
-      /* <name>Fedora 8</name> */ 
+      /* <name>Fedora 8</name> */
     case STATE_NAME:
       break;
       /*   <package arch="ppc64" name="imlib-debuginfo" release="6.fc8"
        *            src="http://download.fedoraproject.org/pub/fedora/linux/updates/8/ppc64/imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm"
        *            version="1.9.15">
-       * 
+       *
        *
        * -> patch.conflicts: {name} < {version}.{release}
        */
@@ -397,7 +413,7 @@ startElement(void *userData, const char *name, const char **atts)
        repodata_set_id(pd->data, pd->collhandle, UPDATE_COLLECTION_ARCH, a);
         break;
       }
-      /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */ 
+      /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
       /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
     case STATE_FILENAME:
       break;
@@ -473,7 +489,7 @@ endElement(void *userData, const char *name)
        */
     case STATE_DESCRIPTION:
       repodata_set_str(pd->data, pd->datanum, SOLVABLE_DESCRIPTION, pd->content);
-      break;   
+      break;
       /*
        * <message>Warning! ...</message>
        */
@@ -490,7 +506,7 @@ endElement(void *userData, const char *name)
       repodata_add_flexarray(pd->data, pd->datanum, UPDATE_COLLECTION, pd->collhandle);
       pd->collhandle = 0;
       break;
-      /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */ 
+      /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
       /* <filename>libntlm-0.4.2-1.fc8.x86_64.rpm</filename> */
     case STATE_FILENAME:
       repodata_set_str(pd->data, pd->collhandle, UPDATE_COLLECTION_FILENAME, pd->content);
index 0f63986..053515d 100644 (file)
@@ -1,4 +1,52 @@
 -------------------------------------------------------------------
+Fri Oct 22 15:51:11 CEST 2010 - ma@suse.de
+
+- updateinfoxml: Correctly parse 'issued date' field.
+- 0.16.1
+
+-------------------------------------------------------------------
+Thu Sep  9 17:30:36 CEST 2010 - mls@suse.de
+
+- bump version to 0.16 to make it different from code11_3 branch
+- 0.16.0
+
+-------------------------------------------------------------------
+Mon Sep  6 13:50:02 UTC 2010 - dmacvicar@novell.com
+
+- ruby bindings: fix bugs regarding include path loading
+  (was hardcoded) and refactor the way the library path is defined
+  (only once in a helper)
+
+-------------------------------------------------------------------
+Mon Sep  6 12:38:21 UTC 2010 - dmacvicar@novell.com
+
+- SLE10SP3 also has vendor_ruby 
+
+-------------------------------------------------------------------
+Wed Aug 18 14:11:08 UTC 2010 - kkaempf@novell.com
+
+- refactor ruby-satsolver, pure-Ruby extensions added
+- 0.15.1
+
+-------------------------------------------------------------------
+Thu May  6 17:39:20 CEST 2010 - mls@suse.de
+
+- fix bug in cleandeps code
+- bump version to 0.15 to make it different from code11_2 branch
+- 0.15.0
+
+-------------------------------------------------------------------
+Tue Mar 23 17:24:46 CET 2010 - ma@suse.de
+
+- Parse an installed products <shortsummary> tag [bnc#586303]
+
+-------------------------------------------------------------------
+Mon Mar 22 18:45:42 CET 2010 - mls@suse.de
+
+- dataiterator: reset parent when jumping to a solvid [bnc#589640]
+- 0.14.17
+
+-------------------------------------------------------------------
 Thu Mar 11 22:13:26 CET 2010 - ma@suse.de
 
 - parse global repository ids. [bnc#377568]
index 0568b85..ebc1d5c 100644 (file)
@@ -1,3 +1,8 @@
+%if 0%{?fedora_version}
+%{!?ruby_sitelib: %global ruby_sitelib %(ruby -rrbconfig -e 'puts Config::CONFIG["sitelibdir"] ')}
+%{!?ruby_sitearch: %global ruby_sitearch %(ruby -rrbconfig -e 'puts Config::CONFIG["sitearchdir"] ')}
+%endif
+
 Name:           libsatsolver
 Version:        @VERSION@
 Release:        1
@@ -201,17 +206,29 @@ rm -rf "$RPM_BUILD_ROOT"
 %files -n ruby-satsolver
 %defattr(-,root,root,-)
 %if 0%{?suse_version}
-%if 0%{?suse_version} < 1100
+%if 0%{?suse_version} < 1010
 %dir %{_libdir}/ruby/site_ruby/%{rb_ver}/%{rb_arch}
+%dir %{_libdir}/ruby/site_ruby/%{rb_ver}/satsolver
+%{_libdir}/ruby/site_ruby/%{rb_ver}/satsolver/*.rb
+%{_libdir}/ruby/site_ruby/%{rb_ver}/satsolver.rb
 %{_libdir}/ruby/site_ruby/%{rb_ver}/%{rb_arch}/satsolver.so
 %else
+%dir %{_libdir}/ruby/vendor_ruby/%{rb_ver}/satsolver
+%{_libdir}/ruby/vendor_ruby/%{rb_ver}/satsolver/*.rb
+%{_libdir}/ruby/vendor_ruby/%{rb_ver}/satsolver.rb
 %{_libdir}/ruby/vendor_ruby/%{rb_ver}/%{rb_arch}/satsolver.so
 %endif
 %endif
 %if 0%{?mandriva_version}
+%dir %{ruby_sitelibdir}/satsolver
+%{ruby_sitelibdir}/satsolver/*.rb
+%{ruby_sitelibdir}/satsolver.rb
 %{ruby_sitearchdir}/satsolver.so
 %endif
 %if 0%{?fedora_version}
+%dir %{ruby_sitelib}/satsolver
+%{ruby_sitelib}/satsolver.rb
+%{ruby_sitelib}/satsolver/*.rb
 %{ruby_sitearch}/satsolver.so
 %endif
 %doc bindings/ruby/html
index 4d6318f..a20c7b7 100644 (file)
--- a/src/evr.c
+++ b/src/evr.c
@@ -215,6 +215,8 @@ evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode)
       if (r1 && !r2)
        return 1;
     }
+  if (mode == EVRCMP_COMPARE_EVONLY)
+    return 0;
   if (r1 && r2)
     {
       if (s1 != ++r1 && s2 != ++r2)
index c45cf81..e9a96f4 100644 (file)
--- a/src/evr.h
+++ b/src/evr.h
@@ -19,9 +19,10 @@ extern "C" {
 
 #include "pooltypes.h"
 
-#define EVRCMP_COMPARE                  0
-#define EVRCMP_MATCH_RELEASE            1
-#define EVRCMP_MATCH                    2
+#define EVRCMP_COMPARE                 0
+#define EVRCMP_MATCH_RELEASE           1
+#define EVRCMP_MATCH                   2
+#define EVRCMP_COMPARE_EVONLY          3
 
 extern int vercmp(const char *s1, const char *q1, const char *s2, const char *q2);
 extern int evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode);
index 168400b..55c8677 100644 (file)
@@ -25,7 +25,7 @@
 /*-----------------------------------------------------------------*/
 
 /*
- * prep for prune_best_version_arch
+ * prep for prune_best_version
  *   sort by name
  */
 
@@ -105,6 +105,38 @@ prune_to_highest_prio(Pool *pool, Queue *plist)
   plist->count = j;
 }
 
+static void
+prune_to_highest_prio_per_name(Pool *pool, Queue *plist)
+{
+  Queue pq;
+  int i, j, k;
+  Id name;
+
+  queue_init(&pq);
+  sat_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
+  queue_push(&pq, plist->elements[0]);
+  name = pool->solvables[pq.elements[0]].name;
+  for (i = 1, j = 0; i < plist->count; i++)
+    {
+      if (pool->solvables[plist->elements[i]].name != name)
+       {
+         if (pq.count > 2)
+           prune_to_highest_prio(pool, &pq);
+         for (k = 0; k < pq.count; k++)
+           plist->elements[j++] = pq.elements[k];
+         queue_empty(&pq);
+         queue_push(&pq, plist->elements[i]);
+         name = pool->solvables[pq.elements[0]].name;
+       }
+    }
+  if (pq.count > 2)
+    prune_to_highest_prio(pool, &pq);
+  for (k = 0; k < pq.count; k++)
+    plist->elements[j++] = pq.elements[k];
+  queue_free(&pq);
+  plist->count = j;
+}
+
 
 /*
  * prune to recommended/suggested packages.
@@ -262,26 +294,16 @@ prune_to_best_arch(const Pool *pool, Queue *plist)
 }
 
 /*
- * prune_to_best_version
- *
- * sort list of packages (given through plist) by name and evr
- * return result through plist
+ * remove entries from plist that are obsoleted by other entries
+ * with different name.
+ * plist should be sorted in some way.
  */
-void
-prune_to_best_version(Pool *pool, Queue *plist)
+static void
+prune_obsoleted(Pool *pool, Queue *plist)
 {
-  Id best;
   int i, j;
   Solvable *s;
 
-  if (plist->count < 2)                /* no need to prune for a single entry */
-    return;
-  POOL_DEBUG(SAT_DEBUG_POLICY, "prune_to_best_version %d\n", plist->count);
-
-  /* sort by name first, prefer installed */
-  sat_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
-
-  /* delete obsoleted. hmm, looks expensive! */
   /* FIXME maybe also check provides depending on noupdateprovide? */
   /* FIXME do not prune cycles */
   for (i = 0; i < plist->count; i++)
@@ -302,6 +324,7 @@ prune_to_best_version(Pool *pool, Queue *plist)
                continue;
              if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
                continue;
+             /* hmm, expensive. should use hash if plist is big */
              for (j = 0; j < plist->count; j++)
                {
                  if (i == j)
@@ -317,6 +340,26 @@ prune_to_best_version(Pool *pool, Queue *plist)
     if (plist->elements[i])
       plist->elements[j++] = plist->elements[i];
   plist->count = j;
+}
+
+/*
+ * prune_to_best_version
+ *
+ * sort list of packages (given through plist) by name and evr
+ * return result through plist
+ */
+void
+prune_to_best_version(Pool *pool, Queue *plist)
+{
+  int i, j;
+  Solvable *s, *best;
+
+  if (plist->count < 2)                /* no need to prune for a single entry */
+    return;
+  POOL_DEBUG(SAT_DEBUG_POLICY, "prune_to_best_version %d\n", plist->count);
+
+  /* sort by name first, prefer installed */
+  sat_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
 
   /* now find best 'per name' */
   best = 0;
@@ -328,32 +371,33 @@ prune_to_best_version(Pool *pool, Queue *plist)
                 solvable2str(pool, s),
                 (pool->installed && s->repo == pool->installed) ? "installed" : "not installed");
 
-      if (!best)                      /* if no best yet, the current is best */
+      if (!best)               /* if no best yet, the current is best */
         {
-          best = plist->elements[i];
+          best = s;
           continue;
         }
 
-      /* name switch: re-init */
-      if (pool->solvables[best].name != s->name)   /* new name */
+      /* name switch: finish group, re-init */
+      if (best->name != s->name)   /* new name */
         {
-          plist->elements[j++] = best; /* move old best to front */
-          best = plist->elements[i];   /* take current as new best */
+          plist->elements[j++] = best - pool->solvables; /* move old best to front */
+          best = s;            /* take current as new best */
           continue;
         }
 
-      if (pool->solvables[best].evr != s->evr)   /* compare evr */
+      if (best->evr != s->evr) /* compare evr */
         {
-          if (evrcmp(pool, pool->solvables[best].evr, s->evr, EVRCMP_COMPARE) < 0)
-            best = plist->elements[i];
+          if (evrcmp(pool, best->evr, s->evr, EVRCMP_COMPARE) < 0)
+            best = s;
         }
     }
-
-  if (!best)
-    best = plist->elements[0];
-
-  plist->elements[j++] = best;
+  plist->elements[j++] = best - pool->solvables;       /* finish last group */
   plist->count = j;
+
+  /* we reduced the list to one package per name, now look at
+   * package obsoletes */
+  if (plist->count > 1)
+    prune_obsoleted(pool, plist);
 }
 
 
@@ -375,13 +419,55 @@ prune_best_arch_name_version(const Solver *solv, Pool *pool, Queue *plist)
     prune_to_best_version(pool, plist);
 }
 
+/* installed packages involed in a dup operation can only be kept
+* if they are identical to a non-installed one */
+static void
+prune_installed_dup_packages(Solver *solv, Queue *plist)
+{
+  Pool *pool = solv->pool;
+  int i, j, k;
+
+  for (i = j = 0; i < plist->count; i++)
+    {
+      Id p = plist->elements[i];
+      Solvable *s = pool->solvables + p;
+      if (s->repo == pool->installed && (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))))
+       {
+         for (k = 0; k < plist->count; k++)
+           {
+             Solvable *s2 = pool->solvables + plist->elements[k];
+             if (s2->repo != pool->installed && solvable_identical(s, s2))
+               break;
+           }
+         if (k == plist->count)
+           continue;   /* no identical package found, ignore installed package */
+       }
+      plist->elements[j++] = p;
+    }
+  if (j)
+    plist->count = j;
+}
 
+/*
+ *  POLICY_MODE_CHOOSE:     default, do all pruning steps
+ *  POLICY_MODE_RECOMMEND:  leave out prune_to_recommended
+ *  POLICY_MODE_SUGGEST:    leave out prune_to_recommended, do prio pruning just per name
+ */
 void
 policy_filter_unwanted(Solver *solv, Queue *plist, int mode)
 {
   Pool *pool = solv->pool;
-  if (plist->count > 1 && mode != POLICY_MODE_SUGGEST)
-    prune_to_highest_prio(pool, plist);
+  if (plist->count > 1)
+    {
+      if (mode != POLICY_MODE_SUGGEST)
+        prune_to_highest_prio(pool, plist);
+      else
+        prune_to_highest_prio_per_name(pool, plist);
+      /* installed dup packages need special treatment as prio pruning
+       * does not prune installed packages */
+      if (plist->count > 1 && pool->installed && (solv->dupmap_all || solv->dupinvolvedmap.size))
+       prune_installed_dup_packages(solv, plist);
+    }
   if (plist->count > 1 && mode == POLICY_MODE_CHOOSE)
     prune_to_recommended(solv, plist);
   prune_best_arch_name_version(solv, pool, plist);
@@ -441,6 +527,31 @@ policy_illegal_vendorchange(Solver *solv, Solvable *s1, Solvable *s2)
   return 1;    /* no class matches */
 }
 
+/* check if it is illegal to replace installed
+ * package "is" with package "s" (which must obsolete "is")
+ */
+int
+policy_is_illegal(Solver *solv, Solvable *is, Solvable *s, int ignore)
+{
+  Pool *pool = solv->pool;
+  int ret = 0;
+  if (!(ignore & POLICY_ILLEGAL_DOWNGRADE) && !solv->allowdowngrade)
+    {
+      if (is->name == s->name && evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE) > 0)
+       ret |= POLICY_ILLEGAL_DOWNGRADE;
+    }
+  if (!(ignore & POLICY_ILLEGAL_ARCHCHANGE) && !solv->allowarchchange)
+    {
+      if (is->arch != s->arch && policy_illegal_archchange(solv, s, is))
+       ret |= POLICY_ILLEGAL_ARCHCHANGE;
+    }
+  if (!(ignore & POLICY_ILLEGAL_VENDORCHANGE) && !solv->allowvendorchange)
+    {
+      if (is->vendor != s->vendor && policy_illegal_vendorchange(solv, s, is))
+       ret |= POLICY_ILLEGAL_VENDORCHANGE;
+    }
+  return ret;
+}
 
 /*-------------------------------------------------------------------
  * 
index e52f4f8..b072929 100644 (file)
@@ -56,9 +56,15 @@ extern void prune_to_best_version(Pool *pool, Queue *plist);
  *     candidates : List of candidates (This list depends on other
  *                  restrictions like architecture and vendor policies too)
  */   
+
+#define POLICY_ILLEGAL_DOWNGRADE       1
+#define POLICY_ILLEGAL_ARCHCHANGE      2
+#define POLICY_ILLEGAL_VENDORCHANGE    4
+
 extern void policy_filter_unwanted(Solver *solv, Queue *plist, int mode);
 extern int  policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2);
 extern int  policy_illegal_vendorchange(Solver *solv, Solvable *s1, Solvable *s2);
+extern int  policy_is_illegal(Solver *solv, Solvable *s1, Solvable *s2, int ignore);
 extern void policy_findupdatepackages(Solver *solv,
                                      Solvable *s,
                                      Queue *qs,
index e076a09..854bc68 100644 (file)
@@ -61,6 +61,15 @@ pool_create(void)
   queue_init(&pool->vendormap);
 
   pool->debugmask = SAT_DEBUG_RESULT;  /* FIXME */
+#ifdef FEDORA
+  pool->obsoleteusescolors = 1;
+#endif
+#ifdef DEBIAN 
+  pool->allowselfconflicts = 1;
+# ifdef MULTI_SEMANTICS
+  pool->disttype = DISTTYPE_DEB;
+# endif
+#endif
   return pool;
 }
 
@@ -473,13 +482,36 @@ pool_match_nevr_rel(Pool *pool, Solvable *s, Id d)
   return 0;
 }
 
-/* match two dependencies */
+/* match (flags, evr) against provider (pflags, pevr) */
+static inline int
+pool_match_flags_evr(Pool *pool, int pflags, Id pevr, int flags, int evr)
+{
+  if (!pflags || !flags || pflags >= 8 || flags >= 8)
+    return 0;
+  if (flags == 7 || pflags == 7)
+    return 1;          /* rel provides every version */
+  if ((pflags & flags & 5) != 0)
+    return 1;          /* both rels show in the same direction */
+  if (pevr == evr)
+    {
+      if ((pflags & flags & 2) != 0)
+       return 1;       /* both have '=', match */
+    }
+  else
+    {
+      int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
+      if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_DEPCMP)))) != 0)
+       return 1;
+    }
+  return 0;
+}
+
+/* match two dependencies (d1 = provider) */
 
 int
 pool_match_dep(Pool *pool, Id d1, Id d2)
 {
   Reldep *rd1, *rd2;
-  int pflags, flags;
 
   if (d1 == d2)
     return 1;
@@ -496,28 +528,11 @@ pool_match_dep(Pool *pool, Id d1, Id d2)
       return pool_match_dep(pool, rd1->name, d2);
     }
   rd2 = GETRELDEP(pool, d2);
+  /* first match name */
   if (!pool_match_dep(pool, rd1->name, rd2->name))
     return 0;
-  pflags = rd1->flags;
-  flags = rd2->flags;
-  if (!pflags || !flags || pflags >= 8 || flags >= 8)
-    return 0;
-  if (flags == 7 || pflags == 7)
-    return 1;
-  if ((pflags & flags & 5) != 0)
-    return 1;
-  if (rd1->evr == rd2->evr)
-    {
-      if ((pflags & flags & 2) != 0)
-       return 1;
-    }
-  else
-    {
-      int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
-      if ((f & (1 << (1 + evrcmp(pool, rd1->evr, rd2->evr, EVRCMP_DEPCMP)))) != 0)
-       return 1;
-    }
-  return 0;
+  /* name matches, check flags and evr */
+  return pool_match_flags_evr(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr);
 }
 
 /*
@@ -539,119 +554,134 @@ pool_addrelproviders(Pool *pool, Id d)
   Id evr = rd->evr;
   int flags = rd->flags;
   Id pid, *pidp;
-  Id p, wp, *pp, *pp2, *pp3;
+  Id p, *pp;
 
   d = GETRELID(d);
   queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf));
-  switch (flags)
+
+  if (flags >= 8)
     {
-    case REL_AND:
-    case REL_WITH:
-      pp = pool_whatprovides_ptr(pool, name);
-      pp2 = pool_whatprovides_ptr(pool, evr);
-      while ((p = *pp++) != 0)
-       {
-         for (pp3 = pp2; *pp3;)
-           if (*pp3++ == p)
-             {
-               queue_push(&plist, p);
-               break;
-             }
-       }
-      break;
-    case REL_OR:
-      pp = pool_whatprovides_ptr(pool, name);
-      while ((p = *pp++) != 0)
-       queue_push(&plist, p);
-      pp = pool_whatprovides_ptr(pool, evr);
-      while ((p = *pp++) != 0)
-       queue_pushunique(&plist, p);
-      break;
-    case REL_NAMESPACE:
-      if (name == NAMESPACE_OTHERPROVIDERS)
-       {
-         wp = pool_whatprovides(pool, evr);
-         pool->whatprovides_rel[d] = wp;
-         return wp;
-       }
-      if (pool->nscallback)
+      /* special relation */
+      Id wp = 0;
+      Id *pp2, *pp3;
+
+      switch (flags)
        {
-         /* ask callback which packages provide the dependency
-           * 0:  none
-           * 1:  the system (aka SYSTEMSOLVABLE)
-           * >1: a set of packages, stored as offset on whatprovidesdata
-           */
-         p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
-         if (p > 1)
+       case REL_AND:
+       case REL_WITH:
+         wp = pool_whatprovides(pool, name);
+         pp2 = pool_whatprovides_ptr(pool, evr);
+         pp = pool->whatprovidesdata + wp;
+         while ((p = *pp++) != 0)
            {
-             queue_free(&plist);
-             pool->whatprovides_rel[d] = p;
-             return p;
+             for (pp3 = pp2; *pp3; pp3++)
+               if (*pp3 == p)
+                 break;
+             if (*pp3)
+               queue_push(&plist, p);  /* found it */
+             else
+               wp = 0;
            }
-         if (p == 1)
-           queue_push(&plist, SYSTEMSOLVABLE);
-       }
-      break;
-    case REL_ARCH:
-      /* small hack: make it possible to match <pkg>.src
-       * we have to iterate over the solvables as src packages do not
-       * provide anything, thus they are not indexed in our
-       * whatprovides hash */
-      if (evr == ARCH_SRC)
-       {
-         Solvable *s;
-         for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
+         break;
+       case REL_OR:
+         wp = pool_whatprovides(pool, name);
+         pp = pool->whatprovidesdata + wp;
+         if (!*pp)
+           wp = pool_whatprovides(pool, evr);
+         else
+           {
+             int cnt;
+             while ((p = *pp++) != 0)
+               queue_push(&plist, p);
+             cnt = plist.count;
+             pp = pool_whatprovides_ptr(pool, evr);
+             while ((p = *pp++) != 0)
+               queue_pushunique(&plist, p);
+             if (plist.count != cnt)
+               wp = 0;
+           }
+         break;
+       case REL_NAMESPACE:
+         if (name == NAMESPACE_OTHERPROVIDERS)
+           {
+             wp = pool_whatprovides(pool, evr);
+             break;
+           }
+         if (pool->nscallback)
+           {
+             /* ask callback which packages provide the dependency
+              * 0:  none
+              * 1:  the system (aka SYSTEMSOLVABLE)
+              * >1: set of packages, stored as offset on whatprovidesdata
+              */
+             p = pool->nscallback(pool, pool->nscallbackdata, name, evr);
+             if (p > 1)
+               wp = p;
+             if (p == 1)
+               queue_push(&plist, SYSTEMSOLVABLE);
+           }
+         break;
+       case REL_ARCH:
+         /* small hack: make it possible to match <pkg>.src
+          * we have to iterate over the solvables as src packages do not
+          * provide anything, thus they are not indexed in our
+          * whatprovides hash */
+         if (evr == ARCH_SRC)
            {
-             if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+             Solvable *s;
+             for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++)
+               {
+                 if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+                   continue;
+                 if (pool_match_nevr(pool, s, name))
+                   queue_push(&plist, p);
+               }
+             break;
+           }
+         wp = pool_whatprovides(pool, name);
+         pp = pool->whatprovidesdata + wp;
+         while ((p = *pp++) != 0)
+           {
+             Solvable *s = pool->solvables + p;
+             if (s->arch == evr)
+               queue_push(&plist, p);
+             else
+               wp = 0;
+           }
+         break;
+       case REL_FILECONFLICT:
+         pp = pool_whatprovides_ptr(pool, name);
+         while ((p = *pp++) != 0)
+           {
+             Id origd = MAKERELDEP(d);
+             Solvable *s = pool->solvables + p;
+             if (!s->provides)
                continue;
-             if (pool_match_nevr(pool, s, name))
+             pidp = s->repo->idarraydata + s->provides;
+             while ((pid = *pidp++) != 0)
+               if (pid == origd)
+                 break;
+             if (pid)
                queue_push(&plist, p);
            }
          break;
-       }
-      wp = pool_whatprovides(pool, name);
-      pp = pool->whatprovidesdata + wp;
-      while ((p = *pp++) != 0)
-       {
-         Solvable *s = pool->solvables + p;
-         if (s->arch == evr)
-           queue_push(&plist, p);
-         else
-           wp = 0;
+       default:
+         break;
        }
       if (wp)
        {
-         /* all solvables match, no need to create a new list */
+         /* we can reuse an existing entry */
+         queue_free(&plist);
          pool->whatprovides_rel[d] = wp;
          return wp;
        }
-      break;
-    case REL_FILECONFLICT:
-      pp = pool_whatprovides_ptr(pool, name);
-      while ((p = *pp++) != 0)
-       {
-         Id origd = MAKERELDEP(d);
-         Solvable *s = pool->solvables + p;
-         if (!s->provides)
-           continue;
-         pidp = s->repo->idarraydata + s->provides;
-         while ((pid = *pidp++) != 0)
-           if (pid == origd)
-             break;
-         if (pid)
-           queue_push(&plist, p);
-       }
-      break;
-    default:
-      break;
     }
-
-  /* convert to whatprovides id */
+  else if (flags)
+    {
+      /* simple version comparison relation */
 #if 0
-  POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name));
+      POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name));
 #endif
-  if (flags && flags < 8)
-    {
       pp = pool_whatprovides_ptr(pool, name);
       while (ISRELDEP(name))
        {
@@ -661,9 +691,6 @@ pool_addrelproviders(Pool *pool, Id d)
       while ((p = *pp++) != 0)
        {
          Solvable *s = pool->solvables + p;
-#if 0
-         POOL_DEBUG(DEBUG_1, "addrelproviders: checking package %s\n", id2str(pool, s->name));
-#endif
          if (!s->provides)
            {
              /* no provides - check nevr */
@@ -675,9 +702,6 @@ pool_addrelproviders(Pool *pool, Id d)
          pidp = s->repo->idarraydata + s->provides;
          while ((pid = *pidp++) != 0)
            {
-             int pflags;
-             Id pevr;
-
              if (pid == name)
                {
 #if defined(MULTI_SEMANTICS)
@@ -697,29 +721,12 @@ pool_addrelproviders(Pool *pool, Id d)
              prd = GETRELDEP(pool, pid);
              if (prd->name != name)
                continue;               /* wrong provides name */
-             /* right package, both deps are rels */
-             pflags = prd->flags;
-             if (!pflags)
-               continue;
-             if (flags == 7 || pflags == 7)
-               break; /* included */
-             if ((pflags & flags & 5) != 0)
-               break; /* same direction, match */
-             pevr = prd->evr;
-             if (pevr == evr)
-               {
-                 if ((pflags & flags & 2) != 0)
-                   break; /* both have =, match */
-               }
-             else
-               {
-                 int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5);
-                 if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_DEPCMP)))) != 0)
-                   break;
-               }
+             /* right package, both deps are rels. check flags/evr */
+             if (pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr))
+               break;  /* matches */
            }
          if (!pid)
-           continue;   /* no rel match */
+           continue;   /* none of the providers matched */
          queue_push(&plist, p);
        }
       /* make our system solvable provide all unknown rpmlib() stuff */
index 7459143..f5d1dfb 100644 (file)
@@ -80,6 +80,7 @@ struct _Pool {
   int obsoleteusesprovides;    /* true: obsoletes are matched against provides, not names */
   int implicitobsoleteusesprovides;    /* true: implicit obsoletes due to same name are matched against provides, not names */
   int obsoleteusescolors;      /* true: obsoletes check arch color */
+  int noinstalledobsoletes;    /* true: ignore obsoletes of installed packages */
   int novirtualconflicts;      /* true: conflicts on names, not on provides */
   int allowselfconflicts;      /* true: packages which conflict with itself are installable */
 #ifdef MULTI_SEMANTICS
index 6fc254d..3ea4713 100644 (file)
@@ -31,6 +31,7 @@ const char *archpolicies[] = {
   "ia64",      "ia64:i686:i586:i486:i386",
   "ppc64",     "ppc64:ppc",
   "ppc",       "ppc",
+  "armv7l",    "armv7l:armv6l:armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
   "armv6l",    "armv6l:armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
   "armv5tejl", "armv5tejl:armv5tel:armv5l:armv4tl:armv4l:armv3l",
   "armv5tel",  "armv5tel:armv5l:armv4tl:armv4l:armv3l",
index 70ffde4..866ca11 100644 (file)
@@ -437,7 +437,7 @@ convertsolution(Solver *solv, Id why, Queue *solutionq)
       rr = solv->rules + solv->featurerules + (why - solv->updaterules);
       if (!rr->p)
        rr = solv->rules + why;
-      if (solv->distupgrade && solv->rules[why].p != p && solv->decisionmap[p] > 0)
+      if (solv->dupmap_all && solv->rules[why].p != p && solv->decisionmap[p] > 0)
        {
          /* distupgrade case, allow to keep old package */
          queue_push(solutionq, SOLVER_SOLUTION_DISTUPGRADE);
@@ -564,14 +564,34 @@ create_solutions(Solver *solv, int probnr, int solidx)
        convertsolution(solv, solution.elements[j], &solv->solutions);
       if (solv->solutions.count == solstart + 1)
        {
-         solv->solutions.count--;
-         if (!essentialok && i + 1 == problem.count && !nsol)
+         solv->solutions.count--;      /* this one did not work out */
+         if (nsol || i + 1 < problem.count)
+           continue;                   /* got one or still hope */
+         if (!essentialok)
            {
              /* nothing found, start over */
+             POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "nothing found, re-run with essentialok = 1\n");
              essentialok = 1;
              i = -1;
+             continue;
+           }
+         /* this is bad, we found no solution */
+         /* for now just offer a rule */
+         POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "nothing found, already did essentialok, fake it\n");
+         queue_push(&solv->solutions, 0);
+         for (j = 0; j < problem.count; j++)
+           {
+             queue_empty(&solution);
+             queue_push(&solution, problem.elements[j]);
+             convertsolution(solv, solution.elements[j], &solv->solutions);
+             if (solv->solutions.count > solstart + 1)
+               break;
+           }
+         if (solv->solutions.count == solstart + 1)
+           {
+             solv->solutions.count--;
+             continue;         /* sorry */
            }
-         continue;
        }
       /* patch in number of solution elements */
       solv->solutions.elements[solstart] = (solv->solutions.count - (solstart + 1)) / 2;
index 3d16151..9adce29 100644 (file)
@@ -114,7 +114,7 @@ static inline Id repo_add_solvable_block(Repo *repo, int count)
 
 static inline Repo *pool_id2repo(Pool *pool, Id repoid)
 {
-  return pool->repos[repoid - 1];
+  return repoid ? pool->repos[repoid - 1] : 0;
 }
 
 static inline int pool_installable(const Pool *pool, Solvable *s)
index 551d83a..4fa2aa7 100644 (file)
@@ -1209,7 +1209,10 @@ dataiterator_filelistcheck(Dataiterator *di)
   Repodata *data = di->data;
 
   if ((di->matcher.flags & SEARCH_COMPLETE_FILELIST) != 0)
-    if (!di->matcher.match || (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING || !repodata_filelistfilter_matches(di->data, di->matcher.match))
+    if (!di->matcher.match
+       || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
+           && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
+       || !repodata_filelistfilter_matches(di->data, di->matcher.match))
       needcomplete = 1;
   if (data->state != REPODATA_AVAILABLE)
     return needcomplete ? 1 : 0;
@@ -1595,6 +1598,7 @@ void
 dataiterator_skip_solvable(Dataiterator *di)
 {
   di->nparents = 0;
+  di->kv.parent = 0;
   di->rootlevel = 0;
   di->keyname = di->keynames[0];
   di->state = di_nextsolvable;
@@ -1604,6 +1608,7 @@ void
 dataiterator_skip_repo(Dataiterator *di)
 {
   di->nparents = 0;
+  di->kv.parent = 0;
   di->rootlevel = 0;
   di->keyname = di->keynames[0];
   di->state = di_nextrepo;
@@ -1613,6 +1618,7 @@ void
 dataiterator_jump_to_solvid(Dataiterator *di, Id solvid)
 {
   di->nparents = 0;
+  di->kv.parent = 0;
   di->rootlevel = 0;
   di->keyname = di->keynames[0];
   if (solvid == SOLVID_POS)
@@ -1657,6 +1663,7 @@ void
 dataiterator_jump_to_repo(Dataiterator *di, Repo *repo)
 {
   di->nparents = 0;
+  di->kv.parent = 0;
   di->rootlevel = 0;
   di->repo = repo;
   di->repoid = -1;
index 1ba8f7f..7f9e21e 100644 (file)
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <assert.h>
+#include <fcntl.h>
 #include <time.h>
 
 #include "repo.h"
@@ -779,6 +780,8 @@ repopagestore_read_or_setup_pages(Repopagestore *store, FILE *fp, unsigned int p
     store->pagefd = dup(fileno(fp));
   if (store->pagefd == -1)
     can_seek = 0;
+  else
+    fcntl(store->pagefd, F_SETFD, FD_CLOEXEC);
 
 #ifdef DEBUG_PAGING
   fprintf(stderr, "can %sseek\n", can_seek ? "" : "NOT ");
index 4903d3b..7843231 100644 (file)
 #include "pool.h"
 #include "poolarch.h"
 #include "util.h"
+#include "evr.h"
 #include "policy.h"
 #include "solverdebug.h"
 
 #define RULES_BLOCK 63
 
 static void addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep);
+static void solver_createcleandepsmap(Solver *solv);
 
 /*-------------------------------------------------------------------
  * Check if dependency is possible
@@ -383,9 +385,9 @@ solver_addrule(Solver *solv, Id p, Id d)
 
 /*
  *  special multiversion patch conflict handling:
- *  a patch conflict is also satisfied, if some other
+ *  a patch conflict is also satisfied if some other
  *  version with the same name/arch that doesn't conflict
- *  get's installed. The generated rule is thus:
+ *  gets installed. The generated rule is thus:
  *  -patch|-cpack|opack1|opack2|...
  */
 static Id
@@ -499,9 +501,9 @@ solver_addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
 
       dontfix = 0;
       if (installed                    /* Installed system available */
-         && !solv->fixsystem           /* NOT repair errors in rpm dependency graph */
          && s->repo == installed       /* solvable is installed */
-         && (!solv->fixmap.size || !MAPTST(&solv->fixmap, n - installed->start)))
+         && !solv->fixmap_all          /* NOT repair errors in rpm dependency graph */
+         && !(solv->fixmap.size && MAPTST(&solv->fixmap, n - installed->start)))
         {
          dontfix = 1;                  /* dont care about broken rpm deps */
         }
@@ -656,12 +658,14 @@ solver_addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
        }
 
       /*-----------------------------------------
-       * check obsoletes if not installed
-       * (only installation will trigger the obsoletes in rpm)
+       * check obsoletes and implicit obsoletes of a package
+       * if ignoreinstalledsobsoletes is not set, we're also checking
+       * obsoletes of installed packages (like newer rpm versions)
        */
-      if (!installed || pool->solvables[n].repo != installed)
-       {                              /* not installed */
+      if ((!installed || s->repo != installed) || !pool->noinstalledobsoletes)
+       {
          int noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, n);
+         int isinstalled = (installed && s->repo == installed);
          if (s->obsoletes && !noobs)
            {
              obsp = s->repo->idarraydata + s->obsoletes;
@@ -672,30 +676,49 @@ solver_addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
                  FOR_PROVIDES(p, pp, obs)
                    {
                      Solvable *ps = pool->solvables + p;
+                     if (p == n)
+                       continue;
+                     if (isinstalled && dontfix && ps->repo == installed)
+                       continue;       /* don't repair installed/installed problems */
                      if (!pool->obsoleteusesprovides /* obsoletes are matched names, not provides */
                          && !pool_match_nevr(pool, ps, obs))
                        continue;
                      if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
                        continue;
-                     addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_PACKAGE_OBSOLETES, obs);
+                     if (!isinstalled)
+                       addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_PACKAGE_OBSOLETES, obs);
+                     else
+                       addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES, obs);
                    }
                }
            }
-         FOR_PROVIDES(p, pp, s->name)
+         /* check implicit obsoletes
+           * for installed packages we only need to check installed/installed problems (and
+           * only when dontfix is not set), as the others are picked up when looking at the
+           * uninstalled package.
+           */
+         if (!isinstalled || !dontfix)
            {
-             Solvable *ps = pool->solvables + p;
-             /* we still obsolete packages with same nevra, like rpm does */
-             /* (actually, rpm mixes those packages. yuck...) */
-             if (noobs && (s->name != ps->name || s->evr != ps->evr || s->arch != ps->arch))
-               continue;
-             if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
-               continue;
-             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
-               continue;
-             if (s->name == ps->name)
-               addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_SAME_NAME, 0);
-             else
-               addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_IMPLICIT_OBSOLETES, s->name);
+             FOR_PROVIDES(p, pp, s->name)
+               {
+                 Solvable *ps = pool->solvables + p;
+                 if (p == n)
+                   continue;
+                 if (isinstalled && ps->repo != installed)
+                   continue;
+                 /* we still obsolete packages with same nevra, like rpm does */
+                 /* (actually, rpm mixes those packages. yuck...) */
+                 if (noobs && (s->name != ps->name || s->evr != ps->evr || s->arch != ps->arch))
+                   continue;
+                 if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
+                   continue;
+                 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+                   continue;
+                 if (s->name == ps->name)
+                   addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_SAME_NAME, 0);
+                 else
+                   addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_IMPLICIT_OBSOLETES, s->name);
+               }
            }
        }
 
@@ -904,11 +927,11 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
   p = s - pool->solvables;
   /* find update candidates for 's' */
-  if (solv->distupgrade)
+  if (solv->dupmap_all)
     p = finddistupgradepackages(solv, s, &qs, allow_all);
   else
     policy_findupdatepackages(solv, s, &qs, allow_all);
-  if (!allow_all && !solv->distupgrade && solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
+  if (!allow_all && !solv->dupmap_all && solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
     addduppackages(solv, s, &qs);
 
   if (!allow_all && qs.count && solv->noobsoletes.size)
@@ -930,13 +953,14 @@ solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
        }
       if (j < qs.count)
        {
-         if (d && solv->updatesystem && solv->installed && s->repo == solv->installed)
+         if (d && solv->installed && s->repo == solv->installed &&
+              (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, s - pool->solvables - solv->installed->start))))
            {
              if (!solv->multiversionupdaters)
                solv->multiversionupdaters = sat_calloc(solv->installed->end - solv->installed->start, sizeof(Id));
              solv->multiversionupdaters[s - pool->solvables - solv->installed->start] = d;
            }
-         if (j == 0 && p == -SYSTEMSOLVABLE && solv->distupgrade)
+         if (j == 0 && p == -SYSTEMSOLVABLE && solv->dupmap_all)
            {
              queue_push(&solv->orphaned, s - pool->solvables); /* treat as orphaned */
              j = qs.count;
@@ -1042,7 +1066,7 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
          a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
          if (a != 1 && pool->installed && ps->repo == pool->installed)
            {
-             if (!solv->distupgrade)
+             if (!solv->dupmap_all && !(solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
                queue_pushunique(&allowedarchs, ps->arch);      /* also ok to keep this architecture */
              continue;         /* ignore installed solvables when calculating the best arch */
            }
@@ -1203,7 +1227,8 @@ void
 solver_freedupmaps(Solver *solv)
 {
   map_free(&solv->dupmap);
-  map_free(&solv->dupinvolvedmap);
+  /* we no longer free solv->dupinvolvedmap as we need it in
+   * policy's priority pruning code. sigh. */
 }
 
 void
@@ -1315,17 +1340,50 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
   Id select, p, pp;
   Repo *installed;
   Solvable *s;
-  int i;
+  int i, j, set, qstart, pass;
+  Map omap;
 
   installed = solv->installed;
   select = how & SOLVER_SELECTMASK;
   switch (how & SOLVER_JOBMASK)
     {
     case SOLVER_INSTALL:
-      if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && solv->infarchrules != solv->infarchrules_end && ISRELDEP(what))
+      set = how & SOLVER_SETMASK;
+      if (!(set & SOLVER_NOAUTOSET))
        {
-         Reldep *rd = GETRELDEP(pool, what);
-         if (rd->flags == REL_ARCH)
+         /* automatically add set bits by analysing the job */
+         if (select == SOLVER_SOLVABLE)
+           set |= SOLVER_SETARCH | SOLVER_SETVENDOR | SOLVER_SETREPO | SOLVER_SETEVR;
+         else if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(what))
+           {
+             Reldep *rd = GETRELDEP(pool, what);
+             if (rd->flags == REL_EQ && select == SOLVER_SOLVABLE_NAME)
+               {
+#if !defined(DEBIAN_SEMANTICS)
+                 const char *evr = id2str(pool, rd->evr);
+                 if (strchr(evr, '-'))
+                   set |= SOLVER_SETEVR;
+                 else
+                   set |= SOLVER_SETEV;
+#else
+                 set |= SOLVER_SETEVR;
+#endif
+               }
+             if (rd->flags <= 7 && ISRELDEP(rd->name))
+               rd = GETRELDEP(pool, rd->name);
+             if (rd->flags == REL_ARCH)
+               set |= SOLVER_SETARCH;
+           }
+       }
+      else
+       set &= ~SOLVER_NOAUTOSET;
+      if (!set)
+       return;
+      if ((set & SOLVER_SETARCH) != 0 && solv->infarchrules != solv->infarchrules_end)
+       {
+         if (select == SOLVER_SOLVABLE)
+           queue_push2(q, DISABLE_INFARCH, pool->solvables[what].name);
+         else
            {
              int qcnt = q->count;
              FOR_JOB_SELECT(p, pp, select, what)
@@ -1337,83 +1395,158 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
                      break;
                  if (i < q->count)
                    continue;
-                 queue_push(q, DISABLE_INFARCH);
-                 queue_push(q, s->name);
+                 queue_push2(q, DISABLE_INFARCH, s->name);
                }
            }
        }
-      if (select != SOLVER_SOLVABLE)
-       break;
-      s = pool->solvables + what;
-      if (solv->infarchrules != solv->infarchrules_end)
+      if ((set & SOLVER_SETREPO) != 0 && solv->duprules != solv->duprules_end)
        {
-         queue_push(q, DISABLE_INFARCH);
-         queue_push(q, s->name);
-       }
-      if (solv->duprules != solv->duprules_end)
-       {
-         queue_push(q, DISABLE_DUP);
-         queue_push(q, s->name);
+         if (select == SOLVER_SOLVABLE)
+           queue_push2(q, DISABLE_DUP, pool->solvables[what].name);
+         else
+           {
+             int qcnt = q->count;
+             FOR_JOB_SELECT(p, pp, select, what)
+               {
+                 s = pool->solvables + p;
+                 /* unify names */
+                 for (i = qcnt; i < q->count; i += 2)
+                   if (q->elements[i + 1] == s->name)
+                     break;
+                 if (i < q->count)
+                   continue;
+                 queue_push2(q, DISABLE_DUP, s->name);
+               }
+           }
        }
       if (!installed)
        return;
-      if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, what))
+      /* now the hard part: disable some update rules */
+
+      /* first check if we have noobs or installed packages in the job */
+      FOR_JOB_SELECT(p, pp, select, what)
        {
-         /* XXX: remove if we always do distupgrade with DUP rules */
-         if (solv->distupgrade && s->repo == installed)
+         if (pool->solvables[p].repo == installed)
            {
-             queue_push(q, DISABLE_UPDATE);
-             queue_push(q, what);
+             if (select == SOLVER_SOLVABLE)
+               queue_push2(q, DISABLE_UPDATE, what);
              return;
            }
-         return;
-       }
-      if (s->repo == installed)
-       {
-         queue_push(q, DISABLE_UPDATE);
-         queue_push(q, what);
-         return;
+         if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p))
+           return;
        }
-      if (s->obsoletes)
+
+      /* all job packages obsolete */
+      qstart = q->count;
+      pass = 0;
+      memset(&omap, 0, sizeof(omap));
+      FOR_JOB_SELECT(p, pp, select, what)
        {
-         Id obs, *obsp;
-         obsp = s->repo->idarraydata + s->obsoletes;
-         while ((obs = *obsp++) != 0)
-           FOR_PROVIDES(p, pp, obs)
-             {
-               Solvable *ps = pool->solvables + p;
-               if (ps->repo != installed)
-                 continue;
-               if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
-                 continue;
-               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
-                 continue;
-               queue_push(q, DISABLE_UPDATE);
-               queue_push(q, p);
-             }
+         Id p2, pp2;
+
+         if (pass == 1)
+           map_grow(&omap, installed->end - installed->start);
+         s = pool->solvables + p;
+         if (s->obsoletes)
+           {
+             Id obs, *obsp;
+             obsp = s->repo->idarraydata + s->obsoletes;
+             while ((obs = *obsp++) != 0)
+               FOR_PROVIDES(p2, pp2, obs)
+                 {
+                   Solvable *ps = pool->solvables + p2;
+                   if (ps->repo != installed)
+                     continue;
+                   if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+                     continue;
+                   if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+                     continue;
+                   if (pass)
+                     MAPSET(&omap, p2 - installed->start);
+                   else
+                     queue_push2(q, DISABLE_UPDATE, p2);
+                 }
+           }
+         FOR_PROVIDES(p2, pp2, s->name)
+           {
+             Solvable *ps = pool->solvables + p2;
+             if (ps->repo != installed)
+               continue;
+             if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
+               continue;
+             if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+               continue;
+             if (pass)
+               MAPSET(&omap, p2 - installed->start);
+              else
+               queue_push2(q, DISABLE_UPDATE, p2);
+           }
+         if (pass)
+           {
+             for (i = j = qstart; i < q->count; i += 2)
+               {
+                 if (MAPTST(&omap, q->elements[i + 1] - installed->start))
+                   {
+                     MAPCLR(&omap, q->elements[i + 1] - installed->start);
+                     q->elements[j + 1] = q->elements[i + 1];
+                     j += 2;
+                   }
+               }
+             queue_truncate(q, j);
+           }
+         if (q->count == qstart)
+           break;
+         pass++;
        }
-      FOR_PROVIDES(p, pp, s->name)
+      if (omap.size)
+        map_free(&omap);
+
+      if (qstart == q->count)
+       return;         /* nothing to prune */
+      if ((set & (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR)) == (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR))
+       return;         /* all is set */
+
+      /* now that we know which installed packages are obsoleted check each of them */
+      for (i = j = qstart; i < q->count; i += 2)
        {
-         Solvable *ps = pool->solvables + p;
-         if (ps->repo != installed)
-           continue;
-         if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
-           continue;
-         if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
-           continue;
-         queue_push(q, DISABLE_UPDATE);
-         queue_push(q, p);
+         Solvable *is = pool->solvables + q->elements[i + 1];
+         FOR_JOB_SELECT(p, pp, select, what)
+           {
+             int illegal = 0;
+             s = pool->solvables + p;
+             if ((set & SOLVER_SETEVR) != 0)
+               illegal |= POLICY_ILLEGAL_DOWNGRADE;    /* ignore */
+             if ((set & SOLVER_SETARCH) != 0)
+               illegal |= POLICY_ILLEGAL_ARCHCHANGE;   /* ignore */
+             if ((set & SOLVER_SETVENDOR) != 0)
+               illegal |= POLICY_ILLEGAL_VENDORCHANGE; /* ignore */
+             illegal = policy_is_illegal(solv, is, s, illegal);
+             if (illegal && illegal == POLICY_ILLEGAL_DOWNGRADE && (set & SOLVER_SETEV) != 0)
+               {
+                 /* it's ok if the EV is different */
+                 if (evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE_EVONLY) != 0)
+                   illegal = 0;
+               }
+             if (illegal)
+               break;
+           }
+         if (!p)
+           {   
+             /* no package conflicts with the update rule */
+             /* thus keep the DISABLE_UPDATE */
+             q->elements[j + 1] = q->elements[i + 1];
+             j += 2;
+           }
        }
+      queue_truncate(q, j);
       return;
+
     case SOLVER_ERASE:
       if (!installed)
        break;
       FOR_JOB_SELECT(p, pp, select, what)
        if (pool->solvables[p].repo == installed)
-         {
-           queue_push(q, DISABLE_UPDATE);
-           queue_push(q, p);
-         }
+         queue_push2(q, DISABLE_UPDATE, p);
       return;
     default:
       return;
@@ -1444,6 +1577,13 @@ solver_disablepolicyrules(Solver *solv)
       lastjob = j;
       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
     }
+  if (solv->cleandepsmap.size)
+    {
+      solver_createcleandepsmap(solv);
+      for (i = solv->installed->start; i < solv->installed->end; i++)
+       if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
+         queue_push2(&allq, DISABLE_UPDATE, i);
+    }
   MAPZERO(&solv->noupdate);
   for (i = 0; i < allq.count; i += 2)
     {
@@ -1494,6 +1634,13 @@ solver_reenablepolicyrules(Solver *solv, int jobidx)
       lastjob = j;
       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
     }
+  if (solv->cleandepsmap.size)
+    {
+      solver_createcleandepsmap(solv);
+      for (i = solv->installed->start; i < solv->installed->end; i++)
+       if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
+         queue_push2(&allq, DISABLE_UPDATE, i);
+    }
   for (j = 0; j < q.count; j += 2)
     {
       Id type = q.elements[j], arg = q.elements[j + 1];
@@ -1785,7 +1932,7 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
 }
 
 void
-addchoicerules(Solver *solv)
+solver_addchoicerules(Solver *solv)
 {
   Pool *pool = solv->pool;
   Map m, mneg;
@@ -1851,12 +1998,10 @@ addchoicerules(Solver *solv)
          if (p2)
            {
              /* found installed package p2 that we can update to p */
-             if (!solv->allowarchchange && s->arch != s2->arch && policy_illegal_archchange(solv, s, s2))
-               continue;
-             if (!solv->allowvendorchange && s->vendor != s2->vendor && policy_illegal_vendorchange(solv, s, s2))
-               continue;
              if (MAPTST(&mneg, p))
                continue;
+             if (policy_is_illegal(solv, s2, s, 0))
+               continue;
              queue_push(&qi, p2);
              queue_push(&q, p);
              continue;
@@ -1884,12 +2029,10 @@ addchoicerules(Solver *solv)
              if (obs)
                {
                  /* found installed package p2 that we can update to p */
-                 if (!solv->allowarchchange && s->arch != s2->arch && policy_illegal_archchange(solv, s, s2))
-                   continue;
-                 if (!solv->allowvendorchange && s->vendor != s2->vendor && policy_illegal_vendorchange(solv, s, s2))
-                   continue;
                  if (MAPTST(&mneg, p))
                    continue;
+                 if (policy_is_illegal(solv, s2, s, 0))
+                   continue;
                  queue_push(&qi, p2);
                  queue_push(&q, p);
                  continue;
@@ -1955,9 +2098,8 @@ addchoicerules(Solver *solv)
 /* called when a choice rule is disabled by analyze_unsolvable. We also
  * have to disable all other choice rules so that the best packages get
  * picked */
 void
-disablechoicerules(Solver *solv, Rule *r)
+solver_disablechoicerules(Solver *solv, Rule *r)
 {
   Id rid, p, *pp;
   Pool *pool = solv->pool;
@@ -1986,4 +2128,297 @@ disablechoicerules(Solver *solv, Rule *r)
     }
 }
 
+static void solver_createcleandepsmap(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Queue *job = &solv->job;
+  Map userinstalled;
+  Map im;
+  Map installedm;
+  Rule *r;
+  Id rid, how, what, select;
+  Id p, pp, ip, *jp;
+  Id req, *reqp, sup, *supp;
+  Solvable *s;
+  Queue iq;
+  int i;
+
+  map_init(&userinstalled, installed->end - installed->start);
+  map_init(&im, pool->nsolvables);
+  map_init(&installedm, pool->nsolvables);
+  map_empty(&solv->cleandepsmap);
+  queue_init(&iq);
+
+  for (i = 0; i < job->count; i += 2)
+    {
+      how = job->elements[i];
+      if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
+       {
+         what = job->elements[i + 1];
+         select = how & SOLVER_SELECTMASK;
+         FOR_JOB_SELECT(p, pp, select, what)
+           if (pool->solvables[p].repo == installed)
+             MAPSET(&userinstalled, p - installed->start);
+       }
+    }
+  /* add all positive elements (e.g. locks) to "userinstalled" */
+  for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+    {
+      r = solv->rules + rid;
+      if (r->d < 0)
+       continue;
+      FOR_RULELITERALS(p, jp, r)
+       if (p > 0 && pool->solvables[p].repo == installed)
+         MAPSET(&userinstalled, p - installed->start);
+    }
+  for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+    {
+      r = solv->rules + rid;
+      if (r->p >= 0 || r->d != 0)
+       continue;       /* disabled or not erase */
+      p = -r->p;
+      if (pool->solvables[p].repo != installed)
+       continue;
+      MAPCLR(&userinstalled, p - installed->start);
+      i = solv->ruletojob.elements[rid - solv->jobrules];
+      how = job->elements[i];
+      if ((how & (SOLVER_JOBMASK|SOLVER_CLEANDEPS)) == (SOLVER_ERASE|SOLVER_CLEANDEPS))
+       queue_push(&iq, p);
+    }
+  for (p = installed->start; p < installed->end; p++)
+    {
+      if (pool->solvables[p].repo != installed)
+       continue;
+      MAPSET(&installedm, p);
+      MAPSET(&im, p);
+    }
+
+  while (iq.count)
+    {
+      ip = queue_shift(&iq);
+      s = pool->solvables + ip;
+      if (!MAPTST(&im, ip))
+       continue;
+      if (!MAPTST(&installedm, ip))
+       continue;
+      if (s->repo == installed && MAPTST(&userinstalled, ip - installed->start))
+       continue;
+      MAPCLR(&im, ip);
+#ifdef CLEANDEPSDEBUG
+      printf("hello %s\n", solvable2str(pool, s));
+#endif
+      if (s->requires)
+       {
+         reqp = s->repo->idarraydata + s->requires;
+         while ((req = *reqp++) != 0)
+           {
+             if (req == SOLVABLE_PREREQMARKER)
+               continue;
+#if 0
+             /* count number of installed packages that match */
+             count = 0;
+             FOR_PROVIDES(p, pp, req)
+               if (MAPTST(&installedm, p))
+                 count++;
+             if (count > 1)
+               continue;
+#endif
+             FOR_PROVIDES(p, pp, req)
+               {
+                 if (MAPTST(&im, p))
+                   {
+#ifdef CLEANDEPSDEBUG
+                     printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
+#endif
+                     queue_push(&iq, p);
+                   }
+               }
+           }
+       }
+      if (s->recommends)
+       {
+         reqp = s->repo->idarraydata + s->recommends;
+         while ((req = *reqp++) != 0)
+           {
+#if 0
+             count = 0;
+             FOR_PROVIDES(p, pp, req)
+               if (MAPTST(&installedm, p))
+                 count++;
+             if (count > 1)
+               continue;
+#endif
+             FOR_PROVIDES(p, pp, req)
+               {
+                 if (MAPTST(&im, p))
+                   {
+#ifdef CLEANDEPSDEBUG
+                     printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
+#endif
+                     queue_push(&iq, p);
+                   }
+               }
+           }
+       }
+      if (!iq.count)
+       {
+         /* supplements pass */
+         for (ip = solv->installed->start; ip < solv->installed->end; ip++)
+           {
+             if (!MAPTST(&installedm, ip))
+               continue;
+             s = pool->solvables + ip;
+             if (!s->supplements)
+               continue;
+             if (!MAPTST(&im, ip))
+               continue;
+             supp = s->repo->idarraydata + s->supplements;
+             while ((sup = *supp++) != 0)
+               if (!dep_possible(solv, sup, &im) && dep_possible(solv, sup, &installedm))
+                 break;
+             /* no longer supplemented, also erase */
+             if (sup)
+               {
+#ifdef CLEANDEPSDEBUG
+                 printf("%s supplemented\n", solvid2str(pool, ip));
+#endif
+                 queue_push(&iq, ip);
+               }
+           }
+       }
+    }
+
+  /* turn userinstalled into remove set for pruning */
+  map_empty(&userinstalled);
+  for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+    {
+      r = solv->rules + rid;
+      if (r->p >= 0 || r->d != 0)
+       continue;       /* disabled or not erase */
+      p = -r->p;
+      MAPCLR(&im, p);
+      if (pool->solvables[p].repo == installed)
+        MAPSET(&userinstalled, p - installed->start);
+    }
+  for (p = installed->start; p < installed->end; p++)
+    if (MAPTST(&im, p))
+      queue_push(&iq, p);
+  for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
+    {
+      r = solv->rules + rid;
+      if (r->d < 0)
+       continue;
+      FOR_RULELITERALS(p, jp, r)
+       if (p > 0)
+          queue_push(&iq, p);
+    }
+  /* also put directly addressed packages on the install queue
+   * so we can mark patterns as installed */
+  for (i = 0; i < job->count; i += 2)
+    {
+      how = job->elements[i];
+      if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
+       {
+         what = job->elements[i + 1];
+         select = how & SOLVER_SELECTMASK;
+         if (select == SOLVER_SOLVABLE && pool->solvables[what].repo != installed)
+            queue_push(&iq, what);
+       }
+    }
+  while (iq.count)
+    {
+      ip = queue_shift(&iq);
+      s = pool->solvables + ip;
+#ifdef CLEANDEPSDEBUG
+      printf("bye %s\n", solvable2str(pool, s));
+#endif
+      if (s->requires)
+       {
+         reqp = s->repo->idarraydata + s->requires;
+         while ((req = *reqp++) != 0)
+           {
+             FOR_PROVIDES(p, pp, req)
+               {
+                 if (!MAPTST(&im, p) && MAPTST(&installedm, p))
+                   {
+                     if (p == ip)
+                       continue;
+                     if (MAPTST(&userinstalled, p - installed->start))
+                       continue;
+#ifdef CLEANDEPSDEBUG
+                     printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
+#endif
+                     MAPSET(&im, p);
+                     queue_push(&iq, p);
+                   }
+               }
+           }
+       }
+      if (s->recommends)
+       {
+         reqp = s->repo->idarraydata + s->recommends;
+         while ((req = *reqp++) != 0)
+           {
+             FOR_PROVIDES(p, pp, req)
+               {
+                 if (!MAPTST(&im, p) && MAPTST(&installedm, p))
+                   {
+                     if (p == ip)
+                       continue;
+                     if (MAPTST(&userinstalled, p - installed->start))
+                       continue;
+#ifdef CLEANDEPSDEBUG
+                     printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
+#endif
+                     MAPSET(&im, p);
+                     queue_push(&iq, p);
+                   }
+               }
+           }
+       }
+      if (!iq.count)
+       {
+         /* supplements pass */
+         for (ip = installed->start; ip < installed->end; ip++)
+           {
+             if (!MAPTST(&installedm, ip))
+               continue;
+             if (MAPTST(&userinstalled, ip - installed->start))
+               continue;
+             s = pool->solvables + ip;
+             if (!s->supplements)
+               continue;
+             if (MAPTST(&im, ip) || !MAPTST(&installedm, ip))
+               continue;
+             supp = s->repo->idarraydata + s->supplements;
+             while ((sup = *supp++) != 0)
+               if (dep_possible(solv, sup, &im))
+                 break;
+             if (sup)
+               {
+#ifdef CLEANDEPSDEBUG
+                 printf("%s supplemented\n", solvid2str(pool, ip));
+#endif
+                 MAPSET(&im, ip);
+                 queue_push(&iq, ip);
+               }
+           }
+       }
+    }
+    
+  queue_free(&iq);
+  for (p = installed->start; p < installed->end; p++)
+    {
+      if (pool->solvables[p].repo != installed)
+       continue;
+      if (!MAPTST(&im, p))
+        MAPSET(&solv->cleandepsmap, p - installed->start);
+    }
+  map_free(&im);
+  map_free(&installedm);
+  map_free(&userinstalled);
+}
+
+
 /* EOF */
index 2cd4035..0158223 100644 (file)
@@ -57,6 +57,7 @@ typedef enum {
   SOLVER_RULE_RPM_SAME_NAME,
   SOLVER_RULE_RPM_PACKAGE_OBSOLETES,
   SOLVER_RULE_RPM_IMPLICIT_OBSOLETES,
+  SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES,
   SOLVER_RULE_UPDATE = 0x200,
   SOLVER_RULE_FEATURE = 0x300,
   SOLVER_RULE_JOB = 0x400,
@@ -121,6 +122,9 @@ void solver_reenablepolicyrules(struct _Solver *solv, int jobidx);
 int solver_allruleinfos(struct _Solver *solv, Id rid, Queue *rq);
 SolverRuleinfo solver_ruleinfo(struct _Solver *solv, Id rid, Id *fromp, Id *top, Id *depp);
 
+/* misc functions */
+void solver_addchoicerules(struct _Solver *solv);
+void solver_disablechoicerules(struct _Solver *solv, Rule *r);
 
 #ifdef __cplusplus
 }
index 441af97..c5a1691 100644 (file)
@@ -180,7 +180,7 @@ unsigned int
 solvable_lookup_num(Solvable *s, Id keyname, unsigned int notfound)
 {
   if (!s->repo)
-    return 0;
+    return notfound;
   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
 }
 
@@ -562,10 +562,10 @@ solvable_identical(Solvable *s1, Solvable *s2)
       rq1 = rq2 = 0;
       if (s1->requires)
        for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++)
-         rq1 ^= *reqp++;
+         rq1 ^= *reqp;
       if (s2->requires)
        for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++)
-         rq2 ^= *reqp++;
+         rq2 ^= *reqp;
       if (rq1 != rq2)
         return 0;
     }
index ded4b33..7cefd1a 100644 (file)
@@ -975,7 +975,6 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
   if (lastweak)
     {
       Id v;
-      extern void disablechoicerules(Solver *solv, Rule *r);
       /* disable last weak rule */
       solv->problems.count = oldproblemcount;
       solv->learnt_pool.count = oldlearntpoolcount;
@@ -986,7 +985,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
       POOL_DEBUG(SAT_DEBUG_UNSOLVABLE, "disabling ");
       solver_printruleclass(solv, SAT_DEBUG_UNSOLVABLE, solv->rules + lastweak);
       if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end)
-       disablechoicerules(solv, solv->rules + lastweak);
+       solver_disablechoicerules(solv, solv->rules + lastweak);
       solver_disableproblem(solv, v);
       if (v < 0)
        solver_reenablepolicyrules(solv, -(v + 1));
@@ -1296,6 +1295,7 @@ solver_free(Solver *solv)
   map_free(&solv->dupmap);
   map_free(&solv->dupinvolvedmap);
   map_free(&solv->droporphanedmap);
+  map_free(&solv->cleandepsmap);
 
   sat_free(solv->decisionmap);
   sat_free(solv->rules);
@@ -1412,14 +1412,21 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
              if (l || !dq.count)
                continue;
              /* prune to installed if not updating */
-             if (!solv->updatesystem && solv->installed && dq.count > 1)
+             if (dq.count > 1 && solv->installed && !solv->updatemap_all)
                {
                  int j, k;
                  for (j = k = 0; j < dq.count; j++)
                    {
                      Solvable *s = pool->solvables + dq.elements[j];
                      if (s->repo == solv->installed)
-                       dq.elements[k++] = dq.elements[j];
+                       {
+                         dq.elements[k++] = dq.elements[j];
+                         if (solv->updatemap.size && MAPTST(&solv->updatemap, dq.elements[j] - solv->installed->start))
+                           {
+                             k = 0;    /* package wants to be updated, do not prune */
+                             break;
+                           }
+                       }
                    }
                  if (k)
                    dq.count = k;
@@ -1469,10 +1476,6 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
 
                  if (solv->decisionmap[i] > 0)
                    continue;
-                 /* XXX: noupdate check is probably no longer needed, as all jobs should
-                   * already be satisfied */
-                 if (MAPTST(&solv->noupdate, i - installed->start))
-                   continue;
                  if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start))
                    continue;           /* updates first */
                  r = solv->rules + solv->updaterules + (i - installed->start);
@@ -1484,8 +1487,12 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
                  if (!rr->p)
                    continue;           /* orpaned package */
 
+                 /* XXX: noupdate check is probably no longer needed, as all jobs should
+                  * already be satisfied */
+                 /* Actually we currently still need it because of erase jobs */
+                 /* if noupdate is set we do not look at update candidates */
                  queue_empty(&dq);
-                 if (solv->decisionmap[i] < 0 || solv->updatesystem || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || rr->p != i)
+                 if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || rr->p != i))
                    {
                      if (solv->noobsoletes.size && solv->multiversionupdaters
                             && (d = solv->multiversionupdaters[i - installed->start]) != 0)
@@ -1548,8 +1555,16 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
                  if (solv->decisionmap[i] == 0)
                    {
                      olevel = level;
-                     POOL_DEBUG(SAT_DEBUG_POLICY, "keeping %s\n", solvid2str(pool, i));
-                     level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
+                     if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start))
+                       {
+                         POOL_DEBUG(SAT_DEBUG_POLICY, "cleandeps erasing %s\n", solvid2str(pool, i));
+                         level = setpropagatelearn(solv, level, -i, disablerules, 0);
+                       }
+                     else
+                       {
+                         POOL_DEBUG(SAT_DEBUG_POLICY, "keeping %s\n", solvid2str(pool, i));
+                         level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
+                       }
                      if (level == 0)
                        {
                          queue_free(&dq);
@@ -1925,7 +1940,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
            }
        }
 
-     if (solv->distupgrade && solv->installed)
+     if (solv->dupmap_all && solv->installed)
        {
          int installedone = 0;
 
@@ -1937,7 +1952,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
              if (solv->decisionmap[p])
                continue;       /* already decided */
              olevel = level;
-             if (solv->distupgrade_removeunsupported)
+             if (solv->droporphanedmap_all)
                continue;
              if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))
                continue;
@@ -2421,6 +2436,18 @@ solver_calculate_noobsmap(Pool *pool, Queue *job, Map *noobsmap)
 }
 
 /*
+ * add a rule created by a job, record job number and weak flag
+ */
+static inline void
+solver_addjobrule(Solver *solv, Id p, Id d, Id job, int weak)
+{
+  solver_addrule(solv, p, d);
+  queue_push(&solv->ruletojob, job);
+  if (weak)
+    queue_push(&solv->weakruleq, solv->nrules - 1);
+}
+
+/*
  *
  * solve job queue
  *
@@ -2464,6 +2491,12 @@ solver_solve(Solver *solv, Queue *job)
   queue_free(&solv->job);
   queue_init_clone(&solv->job, job);
 
+  /* initialize with legacy values */
+  solv->fixmap_all = solv->fixsystem;
+  solv->updatemap_all = solv->updatesystem;
+  solv->droporphanedmap_all = solv->distupgrade_removeunsupported;
+  solv->dupmap_all = solv->distupgrade;
+
   /*
    * create basic rule set of all involved packages
    * use addedmap bitmap to make sure we don't create rules twice
@@ -2486,7 +2519,7 @@ solver_solve(Solver *solv, Queue *job)
    */
   if (installed)
     {
-      /* check for verify jobs */
+      /* check for update/verify jobs as they need to be known early */
       for (i = 0; i < job->count; i += 2)
        {
          how = job->elements[i];
@@ -2495,6 +2528,8 @@ solver_solve(Solver *solv, Queue *job)
          switch (how & SOLVER_JOBMASK)
            {
            case SOLVER_VERIFY:
+             if (select == SOLVER_SOLVABLE_ALL)
+               solv->fixmap_all = 1;
              FOR_JOB_SELECT(p, pp, select, what)
                {
                  s = pool->solvables + p;
@@ -2505,6 +2540,19 @@ solver_solve(Solver *solv, Queue *job)
                  MAPSET(&solv->fixmap, p - solv->installed->start);
                }
              break;
+           case SOLVER_UPDATE:
+             if (select == SOLVER_SOLVABLE_ALL)
+               solv->updatemap_all = 1;
+             FOR_JOB_SELECT(p, pp, select, what)
+               {
+                 s = pool->solvables + p;
+                 if (!solv->installed || s->repo != solv->installed)
+                   continue;
+                 if (!solv->updatemap.size)
+                   map_grow(&solv->updatemap, solv->installed->end - solv->installed->start);
+                 MAPSET(&solv->updatemap, p - solv->installed->start);
+               }
+             break;
            default:
              break;
            }
@@ -2545,7 +2593,12 @@ solver_solve(Solver *solv, Queue *job)
            }
          break;
        case SOLVER_DISTUPGRADE:
-         if (!solv->distupgrade)
+         if (select == SOLVER_SOLVABLE_ALL)
+           {
+             solv->dupmap_all = 1;
+             solv->updatemap_all = 1;
+           }
+         if (!solv->dupmap_all)
            hasdupjob = 1;
          break;
        default:
@@ -2660,7 +2713,7 @@ solver_solve(Solver *solv, Queue *job)
            queue_push(&solv->orphaned, i);
           if (!r->p)
            {
-             assert(solv->distupgrade && !sr->p);
+             assert(solv->dupmap_all && !sr->p);
              continue;
            }
          if (!solver_samerule(solv, r, sr))
@@ -2711,7 +2764,7 @@ solver_solve(Solver *solv, Queue *job)
       switch (how & SOLVER_JOBMASK)
        {
        case SOLVER_INSTALL:
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
          if (select == SOLVER_SOLVABLE)
            {
              p = what;
@@ -2730,18 +2783,18 @@ solver_solve(Solver *solv, Queue *job)
              p = queue_shift(&q);      /* get first candidate */
              d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);    /* internalize */
            }
-         solver_addrule(solv, p, d);           /* add install rule */
-         queue_push(&solv->ruletojob, i);
-         if (weak)
-           queue_push(&solv->weakruleq, solv->nrules - 1);
+         solver_addjobrule(solv, p, d, i, weak);
          break;
        case SOLVER_ERASE:
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: %serase %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %s%serase %s\n", weak ? "weak " : "", how & SOLVER_CLEANDEPS ? "clean deps " : "", solver_select2str(pool, select, what));
+         if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && solv->installed)
+           map_grow(&solv->cleandepsmap, solv->installed->end - solv->installed->start);
           if (select == SOLVER_SOLVABLE && solv->installed && pool->solvables[what].repo == solv->installed)
            {
              /* special case for "erase a specific solvable": we also
                * erase all other solvables with that name, so that they
                * don't get picked up as replacement */
+             /* XXX: look also at packages that obsolete this package? */
              name = pool->solvables[what].name;
              FOR_PROVIDES(p, pp, name)
                {
@@ -2756,65 +2809,44 @@ solver_solve(Solver *solv, Queue *job)
                  /* keep installcandidates of other jobs */
                  if (MAPTST(&installcandidatemap, p))
                    continue;
-                 solver_addrule(solv, -p, 0);                  /* remove by Id */
-                 queue_push(&solv->ruletojob, i);
-                 if (weak)
-                   queue_push(&solv->weakruleq, solv->nrules - 1);
+                 solver_addjobrule(solv, -p, 0, i, weak);      /* remove by id */
                }
            }
          FOR_JOB_SELECT(p, pp, select, what)
-           {
-             solver_addrule(solv, -p, 0);
-             queue_push(&solv->ruletojob, i);
-             if (weak)
-               queue_push(&solv->weakruleq, solv->nrules - 1);
-           }
+           solver_addjobrule(solv, -p, 0, i, weak);
          break;
 
        case SOLVER_UPDATE:
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
-         FOR_JOB_SELECT(p, pp, select, what)
-           {
-             s = pool->solvables + p;
-             if (!solv->installed || s->repo != solv->installed)
-               continue;
-             if (!solv->updatemap.size)
-               map_grow(&solv->updatemap, solv->installed->end - solv->installed->start);
-             MAPSET(&solv->updatemap, p - solv->installed->start);
-           }
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
          break;
        case SOLVER_VERIFY:
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sverify %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sverify %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
          break;
        case SOLVER_WEAKENDEPS:
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
          if (select != SOLVER_SOLVABLE)
            break;
          s = pool->solvables + what;
          weaken_solvable_deps(solv, what);
          break;
        case SOLVER_NOOBSOLETES:
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sno obsolete %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %sno obsolete %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
          break;
        case SOLVER_LOCK:
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(solv, select, what));
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
          FOR_JOB_SELECT(p, pp, select, what)
            {
              s = pool->solvables + p;
-             if (installed && s->repo == installed)
-               solver_addrule(solv, p, 0);
-             else
-               solver_addrule(solv, -p, 0);
-             queue_push(&solv->ruletojob, i);
-             if (weak)
-               queue_push(&solv->weakruleq, solv->nrules - 1);
+             solver_addjobrule(solv, installed && s->repo == installed ? p : -p, 0, i, weak);
            }
          break;
        case SOLVER_DISTUPGRADE:
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(solv, select, what));
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
          break;
        case SOLVER_DROP_ORPHANED:
-         POOL_DEBUG(SAT_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(solv, select, what));
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(pool, select, what));
+         if (select == SOLVER_SOLVABLE_ALL)
+           solv->droporphanedmap_all = 1;
          FOR_JOB_SELECT(p, pp, select, what)
            {
              s = pool->solvables + p;
@@ -2825,6 +2857,9 @@ solver_solve(Solver *solv, Queue *job)
              MAPSET(&solv->droporphanedmap, p - installed->start);
            }
          break;
+       case SOLVER_USERINSTALLED:
+         POOL_DEBUG(SAT_DEBUG_JOB, "job: user installed %s\n", solver_select2str(pool, select, what));
+         break;
        default:
          POOL_DEBUG(SAT_DEBUG_JOB, "job: unknown job\n");
          break;
@@ -2873,10 +2908,7 @@ solver_solve(Solver *solv, Queue *job)
     solv->duprules = solv->duprules_end = solv->nrules;
 
   if (1)
-    {
-      extern void addchoicerules(Solver *solv);
-      addchoicerules(solv);
-    }
+    solver_addchoicerules(solv);
   else
     solv->choicerules = solv->choicerules_end = solv->nrules;
 
@@ -2993,237 +3025,3 @@ solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res)
   map_free(&installedmap);
 }
 
-
-#if 0
-#define FIND_INVOLVED_DEBUG 0
-void
-solver_find_involved(Solver *solv, Queue *installedq, Solvable *ts, Queue *q)
-{
-  Pool *pool = solv->pool;
-  Map im;
-  Map installedm;
-  Solvable *s;
-  Queue iq;
-  Queue installedq_internal;
-  Id tp, ip, p, pp, req, *reqp, sup, *supp;
-  int i, count;
-
-  tp = ts - pool->solvables;
-  queue_init(&iq);
-  queue_init(&installedq_internal);
-  map_init(&im, pool->nsolvables);
-  map_init(&installedm, pool->nsolvables);
-
-  if (!installedq)
-    {
-      installedq = &installedq_internal;
-      if (solv->installed)
-       {
-         for (ip = solv->installed->start; ip < solv->installed->end; ip++)
-           {
-             s = pool->solvables + ip;
-             if (s->repo != solv->installed)
-               continue;
-             queue_push(installedq, ip);
-           }
-       }
-    }
-  for (i = 0; i < installedq->count; i++)
-    {
-      ip = installedq->elements[i];
-      MAPSET(&installedm, ip);
-      MAPSET(&im, ip);
-    }
-
-  queue_push(&iq, ts - pool->solvables);
-  while (iq.count)
-    {
-      ip = queue_shift(&iq);
-      if (!MAPTST(&im, ip))
-       continue;
-      if (!MAPTST(&installedm, ip))
-       continue;
-      MAPCLR(&im, ip);
-      s = pool->solvables + ip;
-#if FIND_INVOLVED_DEBUG
-      printf("hello %s\n", solvable2str(pool, s));
-#endif
-      if (s->requires)
-       {
-         reqp = s->repo->idarraydata + s->requires;
-         while ((req = *reqp++) != 0)
-           {
-             if (req == SOLVABLE_PREREQMARKER)
-               continue;
-             /* count number of installed packages that match */
-             count = 0;
-             FOR_PROVIDES(p, pp, req)
-               if (MAPTST(&installedm, p))
-                 count++;
-             if (count > 1)
-               continue;
-             FOR_PROVIDES(p, pp, req)
-               {
-                 if (MAPTST(&im, p))
-                   {
-#if FIND_INVOLVED_DEBUG
-                     printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
-#endif
-                     queue_push(&iq, p);
-                   }
-               }
-           }
-       }
-      if (s->recommends)
-       {
-         reqp = s->repo->idarraydata + s->recommends;
-         while ((req = *reqp++) != 0)
-           {
-             count = 0;
-             FOR_PROVIDES(p, pp, req)
-               if (MAPTST(&installedm, p))
-                 count++;
-             if (count > 1)
-               continue;
-             FOR_PROVIDES(p, pp, req)
-               {
-                 if (MAPTST(&im, p))
-                   {
-#if FIND_INVOLVED_DEBUG
-                     printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
-#endif
-                     queue_push(&iq, p);
-                   }
-               }
-           }
-       }
-      if (!iq.count)
-       {
-         /* supplements pass */
-         for (i = 0; i < installedq->count; i++)
-           {
-             ip = installedq->elements[i];
-             s = pool->solvables + ip;
-             if (!s->supplements)
-               continue;
-             if (!MAPTST(&im, ip))
-               continue;
-             supp = s->repo->idarraydata + s->supplements;
-             while ((sup = *supp++) != 0)
-               if (!dep_possible(solv, sup, &im) && dep_possible(solv, sup, &installedm))
-                 break;
-             /* no longer supplemented, also erase */
-             if (sup)
-               {
-#if FIND_INVOLVED_DEBUG
-                 printf("%s supplemented\n", solvid2str(pool, ip));
-#endif
-                 queue_push(&iq, ip);
-               }
-           }
-       }
-    }
-
-  for (i = 0; i < installedq->count; i++)
-    {
-      ip = installedq->elements[i];
-      if (MAPTST(&im, ip))
-       queue_push(&iq, ip);
-    }
-
-  while (iq.count)
-    {
-      ip = queue_shift(&iq);
-      if (!MAPTST(&installedm, ip))
-       continue;
-      s = pool->solvables + ip;
-#if FIND_INVOLVED_DEBUG
-      printf("bye %s\n", solvable2str(pool, s));
-#endif
-      if (s->requires)
-       {
-         reqp = s->repo->idarraydata + s->requires;
-         while ((req = *reqp++) != 0)
-           {
-             FOR_PROVIDES(p, pp, req)
-               {
-                 if (!MAPTST(&im, p))
-                   {
-                     if (p == tp)
-                       continue;
-#if FIND_INVOLVED_DEBUG
-                     printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
-#endif
-                     MAPSET(&im, p);
-                     queue_push(&iq, p);
-                   }
-               }
-           }
-       }
-      if (s->recommends)
-       {
-         reqp = s->repo->idarraydata + s->recommends;
-         while ((req = *reqp++) != 0)
-           {
-             FOR_PROVIDES(p, pp, req)
-               {
-                 if (!MAPTST(&im, p))
-                   {
-                     if (p == tp)
-                       continue;
-#if FIND_INVOLVED_DEBUG
-                     printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
-#endif
-                     MAPSET(&im, p);
-                     queue_push(&iq, p);
-                   }
-               }
-           }
-       }
-      if (!iq.count)
-       {
-         /* supplements pass */
-         for (i = 0; i < installedq->count; i++)
-           {
-             ip = installedq->elements[i];
-             if (ip == tp)
-               continue;
-             s = pool->solvables + ip;
-             if (!s->supplements)
-               continue;
-             if (MAPTST(&im, ip))
-               continue;
-             supp = s->repo->idarraydata + s->supplements;
-             while ((sup = *supp++) != 0)
-               if (dep_possible(solv, sup, &im))
-                 break;
-             if (sup)
-               {
-#if FIND_INVOLVED_DEBUG
-                 printf("%s supplemented\n", solvid2str(pool, ip));
-#endif
-                 MAPSET(&im, ip);
-                 queue_push(&iq, ip);
-               }
-           }
-       }
-    }
-    
-  queue_free(&iq);
-
-  /* convert map into result */
-  for (i = 0; i < installedq->count; i++)
-    {
-      ip = installedq->elements[i];
-      if (MAPTST(&im, ip))
-       continue;
-      if (ip == ts - pool->solvables)
-       continue;
-      queue_push(q, ip);
-    }
-  map_free(&im);
-  map_free(&installedm);
-  queue_free(&installedq_internal);
-}
-#endif
-
index e8ce937..e672ba5 100644 (file)
@@ -82,11 +82,13 @@ typedef struct _Solver {
 
   Map noupdate;                                /* don't try to update these
                                            installed solvables */
-  Map noobsoletes;                     /* ignore obsoletes for these
-                                          (multiinstall) */
+  Map noobsoletes;                     /* ignore obsoletes for these (multiinstall) */
 
-  Map updatemap;                       /* bring those installed packages to the newest version */
-  Map fixmap;                          /* fix those packages */
+  Map updatemap;                       /* bring these installed packages to the newest version */
+  int updatemap_all;                   /* bring all packages to the newest version */
+
+  Map fixmap;                          /* fix these packages */
+  int fixmap_all;                      /* fix all packages */
 
   Queue weakruleq;                     /* index into 'rules' for weak ones */
   Map weakrulemap;                     /* map rule# to '1' for weak rules, 1..learntrules */
@@ -202,9 +204,14 @@ typedef struct _Solver {
   Queue covenantq;                      /* Covenants honored by this solver (generic locks) */
 
   
-  Map dupmap;                          /* packages from dup repos */
+  Map dupmap;                          /* dup these packages*/
+  int dupmap_all;                      /* dup all packages */
   Map dupinvolvedmap;                  /* packages involved in dup process */
+
   Map droporphanedmap;                 /* packages to drop in dup mode */
+  int droporphanedmap_all;
+
+  Map cleandepsmap;                    /* try to drop these packages as of cleandeps erases */
 
   Queue *ruleinfoq;                    /* tmp space for solver_ruleinfo() */
 } Solver;
@@ -218,6 +225,7 @@ typedef struct _Solver {
 #define SOLVER_SOLVABLE_PROVIDES       0x03
 #define SOLVER_SOLVABLE_ONE_OF         0x04
 #define SOLVER_SOLVABLE_REPO           0x05
+#define SOLVER_SOLVABLE_ALL            0x06
 
 #define SOLVER_SELECTMASK              0xff
 
@@ -231,11 +239,22 @@ typedef struct _Solver {
 #define SOLVER_DISTUPGRADE             0x0700
 #define SOLVER_VERIFY                  0x0800
 #define SOLVER_DROP_ORPHANED           0x0900
+#define SOLVER_USERINSTALLED            0x0a00
 
 #define SOLVER_JOBMASK                 0xff00
 
 #define SOLVER_WEAK                    0x010000
 #define SOLVER_ESSENTIAL               0x020000
+#define SOLVER_CLEANDEPS                0x040000
+
+#define SOLVER_SETEV                   0x01000000
+#define SOLVER_SETEVR                  0x02000000
+#define SOLVER_SETARCH                 0x04000000
+#define SOLVER_SETVENDOR               0x08000000
+#define SOLVER_SETREPO                 0x10000000
+#define SOLVER_NOAUTOSET               0x20000000
+
+#define SOLVER_SETMASK                 0x2f000000
 
 /* old API compatibility, do not use in new code */
 #if 1
@@ -362,12 +381,12 @@ solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap)
          l = r->p; l; l = (dp != &r->w2 + 1 ? *dp++ : 0))
 
 /* iterate over all packages selected by a job */
-#define FOR_JOB_SELECT(p, pp, select, what)                    \
-    if (select == SOLVER_SOLVABLE_REPO)                                \
-       p = pp = 0;                                             \
-    else for (pp = (select == SOLVER_SOLVABLE ? 0 :            \
-               select == SOLVER_SOLVABLE_ONE_OF ? what :       \
-               pool_whatprovides(pool, what)),                         \
+#define FOR_JOB_SELECT(p, pp, select, what)                                    \
+    if (select == SOLVER_SOLVABLE_REPO || select == SOLVER_SOLVABLE_ALL)       \
+       p = pp = 0;                                                             \
+    else for (pp = (select == SOLVER_SOLVABLE ? 0 :                            \
+               select == SOLVER_SOLVABLE_ONE_OF ? what :                       \
+               pool_whatprovides(pool, what)),                                 \
          p = (select == SOLVER_SOLVABLE ? what : pool->whatprovidesdata[pp++]) ; p ; p = pool->whatprovidesdata[pp++]) \
       if (select != SOLVER_SOLVABLE_NAME || pool_match_nevr(pool, pool->solvables + p, what))
 
index c3dfd9b..0d8ad24 100644 (file)
@@ -543,14 +543,12 @@ solver_printtransaction(Solver *solv)
   queue_free(&pkgs);
 }
 
-void
-solver_printprobleminfo(Solver *solv, Id problem)
+static void
+solver_printproblemruleinfo(Solver *solv, Id probr)
 {
   Pool *pool = solv->pool;
-  Id probr;
   Id dep, source, target;
 
-  probr = solver_findproblemrule(solv, problem);
   switch (solver_ruleinfo(solv, probr, &source, &target, &dep))
     {
     case SOLVER_RULE_DISTUPGRADE:
@@ -586,6 +584,9 @@ solver_printprobleminfo(Solver *solv, Id problem)
     case SOLVER_RULE_RPM_PACKAGE_OBSOLETES:
       POOL_DEBUG(SAT_DEBUG_RESULT, "package %s obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
       return;
+    case SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES:
+      POOL_DEBUG(SAT_DEBUG_RESULT, "installed package %s obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
+      return;
     case SOLVER_RULE_RPM_IMPLICIT_OBSOLETES:
       POOL_DEBUG(SAT_DEBUG_RESULT, "package %s implicitely obsoletes %s provided by %s\n", solvid2str(pool, source), dep2str(pool, dep), solvid2str(pool, target));
       return;
@@ -605,6 +606,40 @@ solver_printprobleminfo(Solver *solv, Id problem)
 }
 
 void
+solver_printprobleminfo(Solver *solv, Id problem)
+{
+  solver_printproblemruleinfo(solv, solver_findproblemrule(solv, problem));
+}
+
+void
+solver_printcompleteprobleminfo(Solver *solv, Id problem)
+{
+  Queue q;
+  Id probr;
+  int i, nobad = 0;
+
+  queue_init(&q);
+  solver_findallproblemrules(solv, problem, &q);
+  for (i = 0; i < q.count; i++)
+    {
+      probr = q.elements[i];
+      if (!(probr >= solv->updaterules && probr < solv->updaterules_end) && !(probr >= solv->jobrules && probr < solv->jobrules_end))
+       {
+         nobad = 1;
+         break;
+       }
+    }
+  for (i = 0; i < q.count; i++)
+    {
+      probr = q.elements[i];
+      if (nobad && ((probr >= solv->updaterules && probr < solv->updaterules_end) || (probr >= solv->jobrules && probr < solv->jobrules_end)))
+       continue;
+      solver_printproblemruleinfo(solv, probr);
+    }
+  queue_free(&q);
+}
+
+void
 solver_printsolution(Solver *solv, Id problem, Id solution)
 {
   Pool *pool = solv->pool;
@@ -626,23 +661,23 @@ solver_printsolution(Solver *solv, Id problem, Id solution)
              if (select == SOLVER_SOLVABLE && solv->installed && pool->solvables[what].repo == solv->installed)
                POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not keep %s installed\n", solvid2str(pool, what));
              else if (select == SOLVER_SOLVABLE_PROVIDES)
-               POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not install a solvable %s\n", solver_select2str(solv, select, what));
+               POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not install a solvable %s\n", solver_select2str(pool, select, what));
              else
-               POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not install %s\n", solver_select2str(solv, select, what));
+               POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not install %s\n", solver_select2str(pool, select, what));
              break;
            case SOLVER_ERASE:
              if (select == SOLVER_SOLVABLE && !(solv->installed && pool->solvables[what].repo == solv->installed))
                POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not forbid installation of %s\n", solvid2str(pool, what));
              else if (select == SOLVER_SOLVABLE_PROVIDES)
-               POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not deinstall all solvables %s\n", solver_select2str(solv, select, what));
+               POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not deinstall all solvables %s\n", solver_select2str(pool, select, what));
              else
-               POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not deinstall %s\n", solver_select2str(solv, select, what));
+               POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not deinstall %s\n", solver_select2str(pool, select, what));
              break;
            case SOLVER_UPDATE:
-             POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not install most recent version of %s\n", solver_select2str(solv, select, what));
+             POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not install most recent version of %s\n", solver_select2str(pool, select, what));
              break;
            case SOLVER_LOCK:
-             POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not lock %s\n", solver_select2str(solv, select, what));
+             POOL_DEBUG(SAT_DEBUG_RESULT, "  - do not lock %s\n", solver_select2str(pool, select, what));
              break;
            default:
              POOL_DEBUG(SAT_DEBUG_RESULT, "  - do something different\n");
@@ -670,39 +705,27 @@ solver_printsolution(Solver *solv, Id problem, Id solution)
          /* policy, replace p with rp */
          s = pool->solvables + p;
          sd = rp ? pool->solvables + rp : 0;
-         if (s == sd && solv->distupgrade)
+         if (sd)
            {
-             POOL_DEBUG(SAT_DEBUG_RESULT, "  - keep obsolete %s\n", solvable2str(pool, s));
-           }
-         else if (sd)
-           {
-             int gotone = 0;
-             if (!solv->allowdowngrade && evrcmp(pool, s->evr, sd->evr, EVRCMP_MATCH_RELEASE) > 0)
-               {
-                 POOL_DEBUG(SAT_DEBUG_RESULT, "  - allow downgrade of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
-                 gotone = 1;
-               }
-             if (!solv->allowarchchange && s->name == sd->name && s->arch != sd->arch && policy_illegal_archchange(solv, s, sd))
-               {
-                 POOL_DEBUG(SAT_DEBUG_RESULT, "  - allow architecture change of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
-                 gotone = 1;
-               }
-             if (!solv->allowvendorchange && s->name == sd->name && s->vendor != sd->vendor && policy_illegal_vendorchange(solv, s, sd))
+             int illegal = policy_is_illegal(solv, s, sd, 0);
+             if ((illegal & POLICY_ILLEGAL_DOWNGRADE) != 0)
+               POOL_DEBUG(SAT_DEBUG_RESULT, "  - allow downgrade of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
+             if ((illegal & POLICY_ILLEGAL_ARCHCHANGE) != 0)
+               POOL_DEBUG(SAT_DEBUG_RESULT, "  - allow architecture change of %s to %s\n", solvable2str(pool, s), solvable2str(pool, sd));
+             if ((illegal & POLICY_ILLEGAL_VENDORCHANGE) != 0)
                {
                  if (sd->vendor)
                    POOL_DEBUG(SAT_DEBUG_RESULT, "  - allow vendor change from '%s' (%s) to '%s' (%s)\n", id2str(pool, s->vendor), solvable2str(pool, s), id2str(pool, sd->vendor), solvable2str(pool, sd));
                  else
                    POOL_DEBUG(SAT_DEBUG_RESULT, "  - allow vendor change from '%s' (%s) to no vendor (%s)\n", id2str(pool, s->vendor), solvable2str(pool, s), solvable2str(pool, sd));
-                 gotone = 1;
                }
-             if (!gotone)
+             if (!illegal)
                POOL_DEBUG(SAT_DEBUG_RESULT, "  - allow replacement of %s with %s\n", solvable2str(pool, s), solvable2str(pool, sd));
            }
          else
            {
              POOL_DEBUG(SAT_DEBUG_RESULT, "  - allow deinstallation of %s\n", solvable2str(pool, s));
            }
-
        }
     }
 }
@@ -722,7 +745,11 @@ solver_printallsolutions(Solver *solv)
       pcnt++;
       POOL_DEBUG(SAT_DEBUG_RESULT, "Problem %d:\n", pcnt);
       POOL_DEBUG(SAT_DEBUG_RESULT, "====================================\n");
+#if 1
       solver_printprobleminfo(solv, problem);
+#else
+      solver_printcompleteprobleminfo(solv, problem);
+#endif
       POOL_DEBUG(SAT_DEBUG_RESULT, "\n");
       solution = 0;
       while ((solution = solver_next_solution(solv, problem, solution)) != 0)
@@ -767,9 +794,8 @@ solver_printtrivial(Solver *solv)
 }
 
 const char *
-solver_select2str(Solver *solv, Id select, Id what)
+solver_select2str(Pool *pool, Id select, Id what)
 {
-  Pool *pool = solv->pool;
   const char *s;
   char *b;
   if (select == SOLVER_SOLVABLE)
@@ -803,5 +829,7 @@ solver_select2str(Solver *solv, Id select, Id what)
       sprintf(b, "repo #%d", what);
       return b;
     }
+  if (select == SOLVER_SOLVABLE_ALL)
+    return "all packages";
   return "unknown job select";
 }
index 50fff6b..7be568d 100644 (file)
@@ -27,10 +27,12 @@ extern void solver_printdecisionq(Solver *solv, int type);
 extern void solver_printdecisions(Solver *solv);
 extern void solver_printtransaction(Solver *solv);
 extern void solver_printprobleminfo(Solver *solv, Id problem);
+extern void solver_printcompleteprobleminfo(Solver *solv, Id problem);
 extern void solver_printsolution(Solver *solv, Id problem, Id solution);
 extern void solver_printallsolutions(Solver *solv);
 extern void solver_printtrivial(Solver *solv);
-extern const char *solver_select2str(Solver *solv, Id select, Id what);
+
+extern const char *solver_select2str(Pool *pool, Id select, Id what);
 
 
 #endif /* SATSOLVER_SOLVERDEBUG_H */
index 0ed2fed..2b7f058 100644 (file)
@@ -4,12 +4,18 @@
 
 ADD_LIBRARY(toolstuff STATIC common_write.c)
 
+IF ( NOT DEBIAN )
 ADD_EXECUTABLE(rpmdb2solv rpmdb2solv.c)
 TARGET_LINK_LIBRARIES(rpmdb2solv toolstuff satsolverext satsolver ${RPMDB_LIBRARY} ${EXPAT_LIBRARY})
 
 ADD_EXECUTABLE(rpms2solv rpms2solv.c)
 TARGET_LINK_LIBRARIES(rpms2solv toolstuff satsolverext satsolver ${RPMDB_LIBRARY})
 
+ADD_EXECUTABLE(findfileconflicts findfileconflicts.c)
+TARGET_LINK_LIBRARIES(findfileconflicts satsolverext satsolver ${RPMDB_LIBRARY})
+
+ENDIF ( NOT DEBIAN )
+
 ADD_EXECUTABLE(rpmmd2solv rpmmd2solv.c)
 TARGET_LINK_LIBRARIES(rpmmd2solv toolstuff satsolverext satsolver ${EXPAT_LIBRARY} ${ZLIB_LIBRARY})
 
@@ -40,22 +46,24 @@ TARGET_LINK_LIBRARIES(dumpsolv satsolver)
 ADD_EXECUTABLE(mergesolv mergesolv.c )
 TARGET_LINK_LIBRARIES(mergesolv toolstuff satsolverext satsolver)
 
-ADD_EXECUTABLE(findfileconflicts findfileconflicts.c)
-TARGET_LINK_LIBRARIES(findfileconflicts satsolverext satsolver ${RPMDB_LIBRARY})
-
 install(TARGETS
     mergesolv
     dumpsolv
     susetags2solv
     helix2solv
     rpmmd2solv
-    rpmdb2solv
-    rpms2solv
     updateinfoxml2solv
     deltainfoxml2solv
     repomdxml2solv
     DESTINATION ${BIN_INSTALL_DIR})
 
+IF ( NOT DEBIAN )
+install(TARGETS
+    rpmdb2solv
+    rpms2solv
+    DESTINATION ${BIN_INSTALL_DIR})
+ENDIF ( NOT DEBIAN )
+
 install(PROGRAMS
    repo2solv.sh
    DESTINATION ${BIN_INSTALL_DIR})
index bab686c..b1ebb5e 100644 (file)
 #include "pool.h"
 #include "poolarch.h"
 #include "repo_solv.h"
+#ifndef DEBIAN
 #include "repo_susetags.h"
 #include "repo_rpmmd.h"
+#else
+#include "repo_deb.h"
+#endif
 #include "solver.h"
 
 static ssize_t
@@ -60,7 +64,11 @@ myfopen(const char *fn)
 void
 usage(char** argv)
 {
-  printf("Usage:\n%s: <arch> repo [--nocheck repo]...\n", argv[0]);
+  printf("Usage:\n%s: <arch> [options..] repo [--nocheck repo]...\n"
+         "\t--exclude <pattern>\twhitespace-separated list of (sub-)"
+         "packagenames to ignore\n"
+         "\t--withsrc\t\tAlso check dependencies of src.rpm\n\n"
+         , argv[0]);
   exit(1);
 }
 
@@ -126,6 +134,7 @@ main(int argc, char **argv)
          exit(1);
        }
       Repo *repo = repo_create(pool, argv[i]);
+#ifndef DEBIAN
       if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
        {
          repo_add_susetags(repo, fp, 0, 0, 0);
@@ -138,6 +147,16 @@ main(int argc, char **argv)
        {
          repo_add_rpmmd(repo, fp, 0, 0);
        }
+#else
+      if (l >= 8 && !strcmp(argv[i] + l - 8, "Packages"))
+       {
+         repo_add_debpackages(repo, fp, 0);
+       }
+      else if (l >= 11 && !strcmp(argv[i] + l - 11, "Packages.gz"))
+       {
+         repo_add_debpackages(repo, fp, 0);
+       }
+#endif
       else if (repo_add_solv(repo, fp))
        {
          fprintf(stderr, "could not add repo %s\n", argv[i]);
@@ -151,6 +170,7 @@ main(int argc, char **argv)
   rpmid = str2id(pool, "rpm", 0);
   rpmarch = str2id(pool, arch, 0);
   rpmrel = 0;
+#ifndef DEBIAN
   if (rpmid && rpmarch)
     {
       for (p = 1; p < pool->nsolvables; p++)
@@ -162,6 +182,7 @@ main(int argc, char **argv)
       if (p < pool->nsolvables)
         rpmrel = rel2id(pool, rpmid, rpmarch, REL_ARCH, 1);
     }
+#endif
   
   queue_init(&job);
   queue_init(&rids);
index 74aef3a..1d92da4 100644 (file)
@@ -212,7 +212,8 @@ void
 usage(char** argv)
 {
 
-  printf("%s: <arch> <patchnameprefix> [repos] [--updaterepos] [repos]...\n"
+  printf("%s: <arch> <patchnameprefix>  [--install-available] [repos] [--updaterepos] [repos]...\n"
+      "\t --install-available: installation repository is available during update\n"
       "\t repos: repository ending in\n"
       "\t\tpackages, packages.gz, primary.xml.gz, updateinfo.xml.gz or .solv\n",
       argv[0]);
@@ -220,25 +221,308 @@ usage(char** argv)
   exit(1);
 }
 
+typedef struct {
+  int updatestart;
+  int shown;
+  int status;
+  int install_available;
+  Repo *repo;
+  Repo *instrepo;
+} context_t;
+
+#define SHOW_PATCH(c) if (!(c)->shown++) printf("%s:\n", solvable2str(pool, s));
+#define PERF_DEBUGGING 0
+static Pool *pool;
+
+void
+test_all_old_patches_included(context_t *c, Id pid)
+{
+  Id p, pp;
+  Id con, *conp;
+  Solvable *s = pool->solvables + pid;
+  /* Test 1: are all old patches included */
+  FOR_PROVIDES(p, pp, s->name)
+    {
+      Solvable *s2 = pool->solvables + p;
+      Id con2, *conp2;
+
+      if (!s2->conflicts)
+        continue;
+      if (evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) <= 0)
+        continue;
+      conp2 = s2->repo->idarraydata + s2->conflicts;
+      while ((con2 = *conp2++) != 0)
+        {
+          Reldep *rd2, *rd;
+          if (!ISRELDEP(con2))
+            continue;
+          rd2 = GETRELDEP(pool, con2);
+          conp = s->repo->idarraydata + s->conflicts;
+          while ((con = *conp++) != 0)
+            {
+              if (!ISRELDEP(con))
+                continue;
+              rd = GETRELDEP(pool, con);
+              if (rd->name == rd2->name)
+                break;
+            }
+          if (!con)
+            {
+              SHOW_PATCH(c);
+              printf("  %s contained %s\n", solvable2str(pool, s2), dep2str(pool, rd2->name));
+            }
+          else
+           {
+             if (evrcmp(pool, rd->evr, rd2->evr, EVRCMP_COMPARE) < 0)
+               {
+                 SHOW_PATCH(c);
+                 printf("  %s required newer version %s-%s of %s-%s\n",
+                     solvable2str(pool, s2), dep2str(pool, rd2->name), dep2str(pool, rd2->evr),
+                     dep2str(pool, rd->name), dep2str(pool, rd->evr));
+               }
+           }
+
+        }
+    }
+}
+
+void
+test_all_packages_installable(context_t *c, Id pid)
+{
+  Solver *solv;
+  Queue job;
+  Id p, pp;
+  Id con, *conp;
+  unsigned int now, solver_runs;
+  int i;
+  Solvable *s = pool->solvables + pid;
+
+  queue_init(&job);
+
+  now = sat_timems(0);
+  solver_runs = 0;
+
+  conp = s->repo->idarraydata + s->conflicts;
+  while ((con = *conp++) != 0)
+    {
+      FOR_PROVIDES(p, pp, con)
+        {
+          queue_empty(&job);
+          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
+          queue_push(&job, p);
+
+          /* also set up some minimal system */
+          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
+          queue_push(&job, str2id(pool, "rpm", 1));
+          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
+          queue_push(&job, str2id(pool, "aaa_base", 1));
+
+          solv = solver_create(pool);
+          solv->dontinstallrecommended = 0;
+          ++solver_runs;
+          solver_solve(solv, &job);
+          if (solv->problems.count)
+            {
+              c->status = 1;
+              printf("error installing original package\n");
+              showproblems(solv, s, 0, 0);
+            }
+          toinst(solv, c->repo, c->instrepo);
+          solver_free(solv);
+
+#if 0
+          dump_instrepo(instrepo, pool);
+
+#endif
+          if (!c->install_available)
+            {
+              queue_empty(&job);
+              for (i = 1; i < c->updatestart; i++)
+                {
+                  if (pool->solvables[i].repo != c->repo || i == pid)
+                    continue;
+                  queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
+                  queue_push(&job, i);
+                }
+            }
+          queue_push(&job, SOLVER_INSTALL_SOLVABLE);
+          queue_push(&job, pid);
+          solv = solver_create(pool);
+          /*solv->dontinstallrecommended = 1;*/
+          ++solver_runs;
+          solver_solve(solv, &job);
+          if (solv->problems.count)
+            {
+              c->status = 1;
+              showproblems(solv, s, 0, 0);
+            }
+          frominst(solv, c->repo, c->instrepo);
+          solver_free(solv);
+        }
+    }
+
+  if (PERF_DEBUGGING)
+    printf("  test_all_packages_installable took %d ms in %d runs\n", sat_timems(now), solver_runs);
+}
+
+void
+test_can_upgrade_all_packages(context_t *c, Id pid)
+{
+  Solver *solv;
+  Id p;
+  Id con, *conp;
+  Queue job;
+  Queue cand;
+  Queue badguys;
+  int i, j;
+  unsigned int now, solver_runs;
+  Solvable *s = pool->solvables + pid;
+
+  queue_init(&job);
+  queue_init(&cand);
+  queue_init(&badguys);
+
+  now = sat_timems(0);
+  solver_runs = 0;
+
+  /* Test 3: can we upgrade all packages? */
+  for (p = 1; p < pool->nsolvables; p++)
+    {
+      Solvable *s = pool->solvables + p;
+      if (!s->repo)
+        continue;
+      if (strchr(id2str(pool, s->name), ':'))
+        continue;      /* only packages, please */
+      if (!pool_installable(pool, s))
+        continue;
+      queue_push(&cand, p);
+    }
+  while (cand.count)
+    {
+      solv = solver_create(pool);
+      queue_empty(&job);
+      for (i = 0; i < badguys.count; i++)
+        {
+          queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE|SOLVER_WEAK);
+          queue_push(&job, badguys.elements[i]);
+        }
+      conp = s->repo->idarraydata + s->conflicts;
+      while ((con = *conp++) != 0)
+        {
+          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
+          queue_push(&job, con);
+        }
+      for (i = 0; i < cand.count; i++)
+        {
+          p = cand.elements[i];
+          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
+          queue_push(&job, p);
+        }
+      ++solver_runs;
+      solver_solve(solv, &job);
+#if 0
+      solver_printdecisions(solv);
+#endif
+      /* put packages into installed repo and prune them from cand */
+      toinst(solv, c->repo, c->instrepo);
+      for (i = 0; i < cand.count; i++)
+        {
+          p = cand.elements[i];
+          if (p > 0 && solv->decisionmap[p] > 0)
+            cand.elements[i] = -p;     /* drop candidate */
+        }
+      solver_free(solv);
+
+      /* now the interesting part: test patch */
+      queue_empty(&job);
+      if (!c->install_available)
+        {
+          for (i = 1; i < c->updatestart; i++)
+            {
+              if (pool->solvables[i].repo != c->repo || i == pid)
+                continue;
+              queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
+              queue_push(&job, i);
+            }
+        }
+      queue_push(&job, SOLVER_INSTALL_SOLVABLE);
+      queue_push(&job, pid);
+      solv = solver_create(pool);
+      solv->dontinstallrecommended = 1;
+      ++solver_runs;
+      solver_solve(solv, &job);
+
+      if (solv->problems.count)
+        {
+          c->status = 1;
+          showproblems(solv, s, &cand, &badguys);
+        }
+      frominst(solv, c->repo, c->instrepo);
+      solver_free(solv);
+      /* now drop all negative elements from cand */
+      for (i = j = 0; i < cand.count; i++)
+        {
+          if (cand.elements[i] < 0)
+            continue;
+          cand.elements[j++] = cand.elements[i];
+        }
+      if (i == j)
+        break; /* no progress */
+      cand.count = j;
+    }
+  if (PERF_DEBUGGING)
+    printf("  test_can_upgrade_all_packages took %d ms in %d runs\n", sat_timems(now), solver_runs);
+}
+
+void
+test_no_ga_package_fulfills_dependency(context_t *c, Id pid)
+{
+  Id con, *conp;
+  Solvable *s = pool->solvables + pid;
+
+  /* Test 4: no GA package fulfills patch dependency */
+  conp = s->repo->idarraydata + s->conflicts;
+  while ((con = *conp++) != 0)
+    {
+      Reldep *rd;
+      Id rp, rpp;
+
+      if (!ISRELDEP(con))
+        continue;
+      rd = GETRELDEP(pool, con);
+      FOR_PROVIDES(rp, rpp, rd->name)
+        {
+          Solvable *s2 = pool_id2solvable(pool, rp);
+          if (rp < c->updatestart
+              && evrcmp(pool, rd->evr, s2->evr, EVRCMP_COMPARE) < 0
+              && pool_match_nevr_rel(pool, s2, rd->name)
+             )
+            {
+              SHOW_PATCH(c);
+              printf("  conflict %s < %s satisfied by non-updated package %s\n",
+                  dep2str(pool, rd->name), dep2str(pool, rd->evr), solvable2str(pool, s2));
+              break;
+            }
+        }
+    }
+}
+
 int
 main(int argc, char **argv)
 {
-  Pool *pool;
   char *arch, *mypatch;
   const char *pname;
   int l;
   FILE *fp;
-  int i, j;
-  Queue job;
-  Queue cand;
-  Queue badguys;
+  int i;
   Id pid, p, pp;
-  Id con, *conp;
-  Solver *solv;
-  Repo *repo, *instrepo;
-  int status = 0;
   int tests = 0;
-  int updatestart = 0;
+  context_t c;
+
+  c.install_available = 0;
+  c.updatestart = 0;
+  c.status = 0;
 
   if (argc <= 3)
     usage(argv);
@@ -255,15 +539,22 @@ main(int argc, char **argv)
 
   mypatch = argv[2];
 
-  repo = repo_create(pool, 0);
-  instrepo = repo_create(pool, 0);
+  c.repo = repo_create(pool, 0);
+  c.instrepo = repo_create(pool, 0);
   for (i = 3; i < argc; i++)
     {
       if (!strcmp(argv[i], "--updaterepos"))
        {
-         updatestart = pool->nsolvables;
+         c.updatestart = pool->nsolvables;
          continue;
        }
+
+      if (!strcmp(argv[i], "--install-available"))
+       {
+         c.install_available = 1;
+         continue;
+       }
       l = strlen(argv[i]);
       if (!strcmp(argv[i], "-"))
         fp = stdin;
@@ -274,21 +565,21 @@ main(int argc, char **argv)
         }
       if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
         {
-          repo_add_susetags(repo, fp, 0, 0, 0);
+          repo_add_susetags(c.repo, fp, 0, 0, 0);
         }
       else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz"))
         {
-          repo_add_susetags(repo, fp, 0, 0, 0);
+          repo_add_susetags(c.repo, fp, 0, 0, 0);
         }
       else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz"))
         {
-          repo_add_rpmmd(repo, fp, 0, 0);
+          repo_add_rpmmd(c.repo, fp, 0, 0);
         }
       else if (l >= 17 && !strcmp(argv[i] + l - 17, "updateinfo.xml.gz"))
        {
-          repo_add_updateinfoxml(repo, fp, 0);
+          repo_add_updateinfoxml(c.repo, fp, 0);
        }
-      else if (repo_add_solv(repo, fp))
+      else if (repo_add_solv(c.repo, fp))
         {
           fprintf(stderr, "could not add repo %s\n", argv[i]);
           exit(1);
@@ -300,23 +591,18 @@ main(int argc, char **argv)
   pool_addfileprovides(pool);
 
   /* bad hack ahead: clone repo */
-  instrepo->idarraydata = repo->idarraydata;
-  instrepo->idarraysize = repo->idarraysize;
-  instrepo->start = repo->start;
-  instrepo->end = repo->end;
-  instrepo->nsolvables = repo->nsolvables;     /* sic! */
-  instrepo->lastoff = repo->lastoff;   /* sic! */
-  pool_set_installed(pool, instrepo);
+  c.instrepo->idarraydata = c.repo->idarraydata;
+  c.instrepo->idarraysize = c.repo->idarraysize;
+  c.instrepo->start = c.repo->start;
+  c.instrepo->end = c.repo->end;
+  c.instrepo->nsolvables = c.repo->nsolvables; /* sic! */
+  c.instrepo->lastoff = c.repo->lastoff;       /* sic! */
+  pool_set_installed(pool, c.instrepo);
   pool_createwhatprovides(pool);
 
-  queue_init(&job);
-  queue_init(&cand);
-  queue_init(&badguys);
-
   for (pid = 1; pid < pool->nsolvables; pid++)
     {
-      int shown = 0;
-#define SHOW_PATCH() if (!shown++) printf("%s:\n", solvable2str(pool, s));
+      c.shown = 0;
       Solvable *s = pool->solvables + pid;
       if (!s->repo)
         continue;
@@ -360,230 +646,11 @@ main(int argc, char **argv)
       printf("testing patch %s-%s\n", pname + 6, id2str(pool, s->evr));
 #endif
 
-      if (1) {
-
-      /* Test 1: are all old patches included */
-      FOR_PROVIDES(p, pp, s->name)
-        {
-         Solvable *s2 = pool->solvables + p;
-         Id con2, *conp2;
-
-         if (!s2->conflicts)
-           continue;
-         if (evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) <= 0)
-           continue;
-         conp2 = s2->repo->idarraydata + s2->conflicts;
-          while ((con2 = *conp2++) != 0)
-           {
-             Reldep *rd2, *rd;
-             if (!ISRELDEP(con2))
-               continue;
-             rd2 = GETRELDEP(pool, con2);
-             conp = s->repo->idarraydata + s->conflicts;
-             while ((con = *conp++) != 0)
-               {
-                 if (!ISRELDEP(con))
-                   continue;
-                 rd = GETRELDEP(pool, con);
-                 if (rd->name == rd2->name)
-                   break;
-               }
-             if (!con)
-               {
-                  SHOW_PATCH();
-                 printf("  %s contained %s\n", solvable2str(pool, s2), dep2str(pool, rd2->name));
-               }
-              else
-               {
-                 if (evrcmp(pool, rd->evr, rd2->evr, EVRCMP_COMPARE) < 0)
-                   {
-                     SHOW_PATCH();
-                     printf("  %s required newer version %s-%s of %s-%s\n",
-                         solvable2str(pool, s2), dep2str(pool, rd2->name), dep2str(pool, rd2->evr),
-                         dep2str(pool, rd->name), dep2str(pool, rd->evr));
-                   }
-               }
-       
-           }
-       }
-      }
-
-      if (1) {
-      /* Test 2: are the packages installable */
-      conp = s->repo->idarraydata + s->conflicts;
-      while ((con = *conp++) != 0)
-       {
-         FOR_PROVIDES(p, pp, con)
-           {
-             queue_empty(&job);
-             queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
-             queue_push(&job, p);
-
-             /* also set up some minimal system */
-             queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
-             queue_push(&job, str2id(pool, "rpm", 1));
-             queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
-             queue_push(&job, str2id(pool, "aaa_base", 1));
-
-             solv = solver_create(pool);
-             solv->dontinstallrecommended = 0;
-             solver_solve(solv, &job);
-             if (solv->problems.count)
-               {
-                 status = 1;
-                  printf("error installing original package\n");
-                 showproblems(solv, s, 0, 0);
-               }
-             toinst(solv, repo, instrepo);
-             solver_free(solv);
-
-#if 0
-              dump_instrepo(instrepo, pool);
-
-#endif
-#if 1
-             queue_empty(&job);
-             for (i = 1; i < updatestart; i++)
-               {
-                 if (pool->solvables[i].repo != repo || i == pid)
-                   continue;
-                 queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
-                 queue_push(&job, i);
-               }
-             queue_push(&job, SOLVER_INSTALL_SOLVABLE);
-             queue_push(&job, pid);
-             solv = solver_create(pool);
-             /*solv->dontinstallrecommended = 1;*/
-             solver_solve(solv, &job);
-             if (solv->problems.count)
-               {
-                 status = 1;
-                 showproblems(solv, s, 0, 0);
-               }
-             frominst(solv, repo, instrepo);
-             solver_free(solv);
-#endif
-           }
-       }
-      }
-
-      if (1) {
-
-      /* Test 3: can we upgrade all packages? */
-      queue_empty(&cand);
-      queue_empty(&badguys);
-      for (p = 1; p < pool->nsolvables; p++)
-       {
-         Solvable *s = pool->solvables + p;
-          if (!s->repo)
-           continue;
-          if (strchr(id2str(pool, s->name), ':'))
-           continue;   /* only packages, please */
-         if (!pool_installable(pool, s))
-           continue;
-         queue_push(&cand, p);
-       }
-      while (cand.count)
-       {
-         solv = solver_create(pool);
-         queue_empty(&job);
-         for (i = 0; i < badguys.count; i++)
-           {
-             queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE|SOLVER_WEAK);
-             queue_push(&job, badguys.elements[i]);
-           }
-         conp = s->repo->idarraydata + s->conflicts;
-          while ((con = *conp++) != 0)
-           {
-             queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
-             queue_push(&job, con);
-           }
-         for (i = 0; i < cand.count; i++)
-           {
-             p = cand.elements[i];
-             queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
-             queue_push(&job, p);
-           }
-         solver_solve(solv, &job);
-#if 0
-         solver_printdecisions(solv);
-#endif
-         /* put packages into installed repo and prune them from cand */
-          toinst(solv, repo, instrepo);
-         for (i = 0; i < cand.count; i++)
-           {
-             p = cand.elements[i];
-             if (p > 0 && solv->decisionmap[p] > 0)
-               cand.elements[i] = -p;  /* drop candidate */
-           }
-         solver_free(solv);
-
-         /* now the interesting part: test patch */
-         queue_empty(&job);
-#if 0
-         for (i = 1; i < updatestart; i++)
-           {
-             if (pool->solvables[i].repo != repo || i == pid)
-               continue;
-             queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
-             queue_push(&job, i);
-           }
-#endif
-         queue_push(&job, SOLVER_INSTALL_SOLVABLE);
-         queue_push(&job, pid);
-         solv = solver_create(pool);
-         solv->dontinstallrecommended = 1;
-         solver_solve(solv, &job);
-
-         if (solv->problems.count)
-           {
-             status = 1;
-             showproblems(solv, s, &cand, &badguys);
-           }
-          frominst(solv, repo, instrepo);
-         solver_free(solv);
-         /* now drop all negative elements from cand */
-         for (i = j = 0; i < cand.count; i++)
-           {
-             if (cand.elements[i] < 0)
-               continue;
-             cand.elements[j++] = cand.elements[i];
-           }
-         if (i == j)
-           break;      /* no progress */
-         cand.count = j;
-       }
-      }
-
-      if (1)
-        {
-          /* Test 4: no GA package fulfills patch dependency */
-          conp = s->repo->idarraydata + s->conflicts;
-          while ((con = *conp++) != 0)
-            {
-              Reldep *rd;
-              Id rp, rpp;
-
-              if (!ISRELDEP(con))
-                continue;
-              rd = GETRELDEP(pool, con);
-              FOR_PROVIDES(rp, rpp, rd->name)
-                {
-                  Solvable *s2 = pool_id2solvable(pool, rp);
-                  if (rp < updatestart
-                      && evrcmp(pool, rd->evr, s2->evr, EVRCMP_COMPARE) < 0
-                      && pool_match_nevr_rel(pool, s2, rd->name)
-                      )
-                    {
-                      SHOW_PATCH();
-                      printf("  conflict %s < %s satisfied by non-updated package %s\n",
-                          dep2str(pool, rd->name), dep2str(pool, rd->evr), solvable2str(pool, s2));
-                      break;
-                    }
-                }
-            }
-       }
+      test_all_old_patches_included(&c, pid);
+      test_all_packages_installable(&c, pid);
+      test_can_upgrade_all_packages(&c, pid);
+      test_no_ga_package_fulfills_dependency(&c, pid);
     }
 
-  exit(status);
+  exit(c.status);
 }
index 4af01e8..e07755e 100755 (executable)
@@ -48,10 +48,26 @@ repomd_decompress() {
   case $1 in
    *.gz) gzip -dc "$1" ;;
    *.bz2) bzip2 -dc "$1" ;;
+   *.lzma) lzma -dc "$1" ;;
+   *.xz) xz -dc "$1" ;;
    *) cat "$1" ;;
   esac
 }
 
+susetags_findfile_cat() {
+  if test -s "$1.xz" ; then
+    xz -dc "$1.xz"
+  elif test -s "$1.lzma" ; then
+    lzma -dc "$1.lzma"
+  elif test -s "$1.bz2" ; then
+    bzip2 -dc "$1.bz2"
+  elif test -s "$1.gz" ; then
+    gzip -dc "$1.gz"
+  elif test -s "$1" ; then
+    cat "$1"
+  fi
+}
+
 # signal an error if there is a problem
 set -e
 
@@ -183,52 +199,30 @@ elif test "$repotype" = susetags ; then
   cd ${DESCR} || exit 2
   (
     # First packages
-    if test -s packages.gz; then
-      gzip -dc packages.gz
-    elif test -s packages.bz2; then
-      bzip2 -dc packages.bz2
-    elif test -s packages; then
-      cat packages
-    fi
+    susetags_findfile_cat packages
 
     # DU
-    if test -s packages.DU.gz; then
-      gzip -dc packages.DU.gz
-    elif test -s packages.DU.bz2; then
-      bzip2 -dc packages.DU.bz2
-    elif test -s packages.DU; then
-      cat packages.DU
-    fi
+    susetags_findfile_cat packages.DU
 
     # Now default language
-    if test -s packages.en.gz; then
-      gzip -dc packages.en.gz
-    elif test -s packages.en.bz2; then
-      bzip2 -dc packages.en.bz2
-    elif test -s packages.en; then
-      cat packages.en
-    fi
+    susetags_findfile_cat packages.en
 
     # Now patterns.  Not simply those files matching *.pat{,.gz,bz2},
     # but only those mentioned in the file 'patterns'
-    if test -f patterns; then
+    if test -f patterns ; then
       for i in `cat patterns`; do
-        test -s "$i" || continue
-        case $i in
-          *.gz) gzip -dc "$i" ;;
-         *.bz2) bzip2 -dc "$i" ;;
-         *) cat "$i" ;;
-       esac
+        if test -s "$i" ; then
+         repomd_decompress "$i"
+       fi
       done
     fi
 
     # Now all other packages.{lang}.  Needs to come last as it switches
     # languages for all following susetags files
-    for i in packages.*; do
+    for i in packages.* ; do
       case $i in
-       *.gz) name="${i%.gz}" ; prog="gzip -dc" ;;
-       *.bz2) name="${i%.bz2}" ; prog="bzip2 -dc" ;;
-       *) name="$i"; prog=cat ;;
+       *.gz|*.bz2|*.xz|*.lzma) name="${i%.*}" ;;
+       *) name="$i" ;;
       esac
       case $name in
        # ignore files we handled already
@@ -236,7 +230,7 @@ elif test "$repotype" = susetags ; then
        *)
          suff=${name#packages.}
          echo "=Lan: $suff"
-         $prog "$i" ;;
+         repomd_decompress "$i"
       esac
     done
 
index 77da9c4..daf7249 100644 (file)
@@ -138,7 +138,7 @@ main(int argc, char **argv)
 
   if (contentfile)
     {
-      FILE *fp = fopen (contentfile, "r");
+      FILE *fp = fopen(contentfile, "r");
       if (!fp)
         {
          perror(contentfile);
@@ -146,6 +146,7 @@ main(int argc, char **argv)
        }
       repo_add_content(repo, fp, REPO_REUSE_REPODATA);
       defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
+      fclose(fp);
     }
 
   if (attrname)