- add SOLVER_NOAUTOSET to disable automatic SET deduction
[platform/upstream/libsolv.git] / src / pool.c
index 4988b0a..cd649d2 100644 (file)
@@ -61,6 +61,9 @@ pool_create(void)
   queue_init(&pool->vendormap);
 
   pool->debugmask = SAT_DEBUG_RESULT;  /* FIXME */
+#ifdef FEDORA
+  pool->obsoleteusescolors = 1;
+#endif
   return pool;
 }
 
@@ -88,6 +91,14 @@ pool_free(Pool *pool)
   sat_free(pool);
 }
 
+#ifdef MULTI_SEMANTICS
+void
+pool_setdisttype(Pool *pool, int disttype)
+{
+  pool->disttype = disttype;
+}
+#endif
+
 Id
 pool_add_solvable(Pool *pool)
 {
@@ -271,7 +282,7 @@ pool_createwhatprovides(Pool *pool)
   pool->whatprovides_rel = sat_calloc_block(pool->nrels, sizeof(Offset), WHATPROVIDES_BLOCK);
 
   /* count providers for each name */
-  for (i = 1; i < pool->nsolvables; i++)
+  for (i = pool->nsolvables - 1; i > 0; i--)
     {
       Id *pp;
       s = pool->solvables + i;
@@ -282,7 +293,7 @@ pool_createwhatprovides(Pool *pool)
       if (s->repo != installed && !pool_installable(pool, s))
        continue;
       pp = s->repo->idarraydata + s->provides;
-      while ((id = *pp++) != ID_NULL)
+      while ((id = *pp++) != 0)
        {
          while (ISRELDEP(id))
            {
@@ -294,16 +305,15 @@ pool_createwhatprovides(Pool *pool)
     }
 
   off = 2;     /* first entry is undef, second is empty list */
-  idp = whatprovides;
   np = 0;                             /* number of names provided */
-  for (i = 0; i < num; i++, idp++)
+  for (i = 0, idp = whatprovides; i < num; i++, idp++)
     {
       n = *idp;
       if (!n)                         /* no providers */
        continue;
-      *idp = off;                     /* move from counts to offsets into whatprovidesdata */
-      off += n + 1;                   /* make space for all providers + terminating ID_NULL */
-      np++;                           /* inc # of provider 'slots' */
+      off += n;                               /* make space for all providers */
+      *idp = off++;                   /* now idp points to terminating zero */
+      np++;                           /* inc # of provider 'slots' for stats */
     }
 
   POOL_DEBUG(SAT_DEBUG_STATS, "provide ids: %d\n", np);
@@ -319,7 +329,7 @@ pool_createwhatprovides(Pool *pool)
   whatprovidesdata = sat_calloc(off + extra, sizeof(Id));
 
   /* now fill data for all provides */
-  for (i = 1; i < pool->nsolvables; i++)
+  for (i = pool->nsolvables - 1; i > 0; i--)
     {
       Id *pp;
       s = pool->solvables + i;
@@ -338,15 +348,11 @@ pool_createwhatprovides(Pool *pool)
              id = rd->name;
            }
          d = whatprovidesdata + whatprovides[id];   /* offset into whatprovidesdata */
-         if (*d)
+         if (*d != i)          /* don't add same solvable twice */
            {
-             d++;
-             while (*d)               /* find free slot */
-               d++;
-             if (d[-1] == i)          /* solvable already tacked at end ? */
-               continue;              /* Y: skip, on to next provides */
+             d[-1] = i;
+             whatprovides[id]--;
            }
-         *d = i;                      /* put solvable Id into data */
        }
     }
   pool->whatprovidesdata = whatprovidesdata;
@@ -416,6 +422,14 @@ pool_queuetowhatprovides(Pool *pool, Queue *q)
 
 /*************************************************************************/
 
+#if defined(MULTI_SEMANTICS)
+# define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
+#elif defined(DEBIAN_SEMANTICS)
+# define EVRCMP_DEPCMP EVRCMP_COMPARE
+#else
+# define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE
+#endif
+
 /* check if a package's nevr matches a dependency */
 
 int
@@ -457,23 +471,41 @@ pool_match_nevr_rel(Pool *pool, Solvable *s, Id d)
     return 1;
   if (flags != 2 && flags != 5)
     flags ^= 5;
-#ifdef DEBIAN_SEMANTICS
-  if ((flags & (1 << (1 + evrcmp(pool, s->evr, evr, EVRCMP_COMPARE)))) != 0)
-    return 1;
-#else
-  if ((flags & (1 << (1 + evrcmp(pool, s->evr, evr, EVRCMP_MATCH_RELEASE)))) != 0)
+  if ((flags & (1 << (1 + evrcmp(pool, s->evr, evr, EVRCMP_DEPCMP)))) != 0)
     return 1;
-#endif
   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;
@@ -490,33 +522,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);
-#ifdef DEBIAN_SEMANTICS
-      if ((f & (1 << (1 + evrcmp(pool, rd1->evr, rd2->evr, EVRCMP_COMPARE)))) != 0)
-       return 1;
-#else
-      if ((f & (1 << (1 + evrcmp(pool, rd1->evr, rd2->evr, EVRCMP_MATCH_RELEASE)))) != 0)
-       return 1;
-#endif
-    }
-  return 0;
+  /* name matches, check flags and evr */
+  return pool_match_flags_evr(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr);
 }
 
 /*
@@ -674,12 +684,14 @@ pool_addrelproviders(Pool *pool, Id d)
          pidp = s->repo->idarraydata + s->provides;
          while ((pid = *pidp++) != 0)
            {
-             int pflags;
-             Id pevr;
-
              if (pid == name)
                {
-#ifdef DEBIAN_SEMANTICS
+#if defined(MULTI_SEMANTICS)
+                 if (pool->disttype == DISTTYPE_DEB)
+                   continue;
+                 else
+                   break;
+#elif defined(DEBIAN_SEMANTICS)
                  continue;             /* unversioned provides can
                                         * never match versioned deps */
 #else
@@ -691,34 +703,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);
-#ifdef DEBIAN_SEMANTICS
-                 if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_COMPARE)))) != 0)
-                   break;
-#else
-                 if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_MATCH_RELEASE)))) != 0)
-                   break;
-#endif
-               }
+             /* 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 */
@@ -751,7 +741,7 @@ pool_debug(Pool *pool, int type, const char *format, ...)
   va_start(args, format);
   if (!pool->debugcallback)
     {
-      if ((type & (SAT_FATAL|SAT_ERROR)) == 0 || !(pool->debugmask & SAT_DEBUG_TO_STDERR))
+      if ((type & (SAT_FATAL|SAT_ERROR)) == 0 && !(pool->debugmask & SAT_DEBUG_TO_STDERR))
         vprintf(format, args);
       else
         vfprintf(stderr, format, args);
@@ -870,8 +860,10 @@ struct addfileprovides_cbdata {
   char **dirs;
   char **names;
 
-  Repodata *olddata;
   Id *dids;
+
+  Map providedids;
+
   Map useddirs;
 };
 
@@ -881,20 +873,24 @@ addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyV
   struct addfileprovides_cbdata *cbd = cbdata;
   int i;
 
-  if (data != cbd->olddata)
+  if (!cbd->useddirs.size)
     {
-      map_free(&cbd->useddirs);
-      map_init(&cbd->useddirs, data->dirpool.ndirs);
+      map_init(&cbd->useddirs, data->dirpool.ndirs + 1);
       for (i = 0; i < cbd->nfiles; i++)
        {
-         Id did = repodata_str2dir(data, cbd->dirs[i], 0);
-          cbd->dids[i] = did;
+         Id did;
+         if (MAPTST(&cbd->providedids, cbd->ids[i]))
+           {
+             cbd->dids[i] = 0;
+             continue;
+           }
+         did = repodata_str2dir(data, cbd->dirs[i], 0);
+         cbd->dids[i] = did;
          if (did)
            MAPSET(&cbd->useddirs, did);
        }
-      cbd->olddata = data;
     }
-  if (!MAPTST(&cbd->useddirs, value->id))
+  if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id))
     return 0;
   for (i = 0; i < cbd->nfiles; i++)
     {
@@ -909,94 +905,128 @@ addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyV
   return 0;
 }
 
-static int
-addfileprovides_setid_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
-{
-  Map *provideids = cbdata;
-  if (key->type != REPOKEY_TYPE_IDARRAY)
-    return 0;
-  MAPSET(provideids, kv->id);
-  return kv->eof ? SEARCH_NEXT_SOLVABLE : 0;
-}
-
-
 static void
 pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly)
 {
-  Id p, start, end;
-  Solvable *s;
-  Repodata *data = 0, *nextdata;
-  Repo *oldrepo = 0;
-  int dataincludes = 0;
-  int i, j;
-  Map providedids;
+  Id p;
+  Repodata *data;
+  Repo *repo;
+  Queue fileprovidesq;
+  int i, j, repoid, repodataid;
+  int provstart, provend;
+  Map donemap;
+  int ndone, incomplete;
+
+  if (!pool->nrepos)
+    return;
 
   cbd->nfiles = sf->nfiles;
   cbd->ids = sf->ids;
   cbd->dirs = sf->dirs;
   cbd->names = sf->names;
-  cbd->olddata = 0;
   cbd->dids = sat_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
-  if (repoonly)
+  map_init(&cbd->providedids, pool->ss.nstrings);
+
+  repoid = 0;
+  repo = repoonly ? repoonly : pool->repos[0];
+  map_init(&donemap, pool->nsolvables);
+  queue_init(&fileprovidesq);
+  provstart = provend = 0;
+  for (;;)
     {
-      start = repoonly->start;
-      end = repoonly->end;
-    }
-  else
-    {
-      start = 2;       /* skip system solvable */
-      end = pool->nsolvables;
-    }
-  for (p = start, s = pool->solvables + p; p < end; p++, s++)
-    {
-      if (!s->repo || (repoonly && s->repo != repoonly))
-       continue;
-      /* check if p is in (oldrepo,data) */
-      if (s->repo != oldrepo || (data && p >= data->end))
+      if (repo->disabled)
        {
-         data = 0;
-         oldrepo = 0;
+         if (repoonly || ++repoid == pool->nrepos)
+           break;
+         repo = pool->repos[repoid];
+         continue;
        }
-      if (oldrepo == 0)
+      ndone = 0;
+      for (data = repo->repodata, repodataid = 0; repodataid < repo->nrepodata; repodataid++, data++)
        {
-         /* nope, find new repo/repodata */
-          /* if we don't find a match, set data to the next repodata */
-         nextdata = 0;
-         for (i = 0, data = s->repo->repodata; i < s->repo->nrepodata; i++, data++)
+         if (ndone >= repo->nsolvables)
+           break;
+
+         if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
            {
-             if (p >= data->end)
-               continue;
-             if (data->state != REPODATA_AVAILABLE)
-               continue;
-             for (j = 1; j < data->nkeys; j++)
-               if (data->keys[j].name == REPOSITORY_ADDEDFILEPROVIDES && data->keys[j].type == REPOKEY_TYPE_IDARRAY)
+             map_empty(&cbd->providedids);
+             for (i = 0; i < fileprovidesq.count; i++)
+               MAPSET(&cbd->providedids, fileprovidesq.elements[i]);
+             provstart = data->start;
+             provend = data->end;
+             for (i = 0; i < cbd->nfiles; i++)
+               if (!MAPTST(&cbd->providedids, cbd->ids[i]))
                  break;
-             if (j == data->nkeys)
-               continue;
-             /* great, this repodata contains addedfileprovides */
-             if (!nextdata || nextdata->start > data->start)
-               nextdata = data;
-             if (p >= data->start)
-               break;
+             if (i == cbd->nfiles)
+               {
+                 /* great! no need to search files */
+                 for (p = data->start; p < data->end; p++)
+                   if (pool->solvables[p].repo == repo)
+                     {
+                       if (MAPTST(&donemap, p))
+                         continue;
+                       MAPSET(&donemap, p);
+                       ndone++;
+                     }
+                 continue;
+               }
            }
-         if (i == s->repo->nrepodata)
-           data = nextdata;    /* no direct hit, use next repodata */
-         if (data)
+
+         if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
+           continue;
+
+         if (data->start < provstart || data->end > provend)
            {
-             map_init(&providedids, pool->ss.nstrings);
-             repodata_search(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, 0, addfileprovides_setid_cb, &providedids);
-             for (i = 0; i < cbd->nfiles; i++)
-               if (!MAPTST(&providedids, cbd->ids[i]))
+             map_empty(&cbd->providedids);
+             provstart = provend = 0;
+           }
+
+         /* check if the data is incomplete */
+         incomplete = 0;
+         if (data->state == REPODATA_AVAILABLE)
+           {
+             for (j = 1; j < data->nkeys; j++)
+               if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
                  break;
-             map_free(&providedids);
-             dataincludes = i == cbd->nfiles;
+             if (j < data->nkeys)
+               {
+#if 0
+                 for (i = 0; i < cbd->nfiles; i++)
+                   if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, id2str(pool, cbd->ids[i])))
+                     printf("need complete filelist because of %s\n", id2str(pool, cbd->ids[i]));
+#endif
+                 for (i = 0; i < cbd->nfiles; i++)
+                   if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, id2str(pool, cbd->ids[i])))
+                     break;
+                 if (i < cbd->nfiles)
+                   incomplete = 1;
+               }
            }
-         oldrepo = s->repo;
+
+         /* do the search */
+         map_init(&cbd->useddirs, 0);
+         for (p = data->start; p < data->end; p++)
+           if (pool->solvables[p].repo == repo)
+             {
+               if (MAPTST(&donemap, p))
+                 continue;
+               repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd);
+               if (!incomplete)
+                 {
+                   MAPSET(&donemap, p);
+                   ndone++;
+                 }
+             }
+         map_free(&cbd->useddirs);
        }
-      if (data && p >= data->start && dataincludes)
-       continue;
-      repo_search(s->repo, p, SOLVABLE_FILELIST, 0, 0, addfileprovides_cb, cbd);
+
+      if (repoonly || ++repoid == pool->nrepos)
+       break;
+      repo = pool->repos[repoid];
     }
+  map_free(&donemap);
+  queue_free(&fileprovidesq);
+  map_free(&cbd->providedids);
 }
 
 void
@@ -1007,7 +1037,9 @@ pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
   struct searchfiles sf, isf, *isfp;
   struct addfileprovides_cbdata cbd;
   int i;
+  unsigned int now;
 
+  now = sat_timems(0);
   memset(&sf, 0, sizeof(sf));
   map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
   memset(&isf, 0, sizeof(isf));
@@ -1036,10 +1068,8 @@ pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
     }
   map_free(&sf.seen);
   map_free(&isf.seen);
-  POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies\n", sf.nfiles);
-  POOL_DEBUG(SAT_DEBUG_STATS, "found %d installed file dependencies\n", isf.nfiles);
+  POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles);
   cbd.dids = 0;
-  map_init(&cbd.useddirs, 1);
   if (idp)
     *idp = 0;
   if (sf.nfiles)
@@ -1082,9 +1112,9 @@ pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp)
       sat_free(isf.dirs);
       sat_free(isf.names);
     }
-  map_free(&cbd.useddirs);
   sat_free(cbd.dids);
   pool_freewhatprovides(pool); /* as we have added provides */
+  POOL_DEBUG(SAT_DEBUG_STATS, "addfileprovides took %d ms\n", sat_timems(now));
 }
 
 void
@@ -1499,7 +1529,7 @@ static inline Id dep2name(Pool *pool, Id dep)
   return dep;
 }
 
-static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id dep
+static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id con
 {
   Id p, pp;
   Solvable *sn = pool->solvables + n; 
@@ -1509,9 +1539,12 @@ static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n
       Solvable *s = pool->solvables + p; 
       if (s->name != sn->name || s->arch != sn->arch)
         continue;
-      if ((map[p] & 9) == 9)
-        return 1;
-    }    
+      if ((map[p] & 9) != 9)
+        continue;
+      if (pool_match_nevr(pool, pool->solvables + p, con))
+       continue;
+      return 1;                /* found installed package that doesn't conflict */
+    }
   return 0;
 }