do not count problem resolution install jobs as userinstalled
[platform/upstream/libsolv.git] / src / solver.c
index 538b786..f188e3d 100644 (file)
@@ -26,6 +26,7 @@
 #include "poolarch.h"
 #include "solverdebug.h"
 #include "cplxdeps.h"
+#include "linkedpkg.h"
 
 #define RULES_BLOCK 63
 
@@ -1133,7 +1134,7 @@ analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
     {
       v = solv->decisionq.elements[--idx];
       vv = v > 0 ? v : -v;
-      if (!MAPTST(&seen, vv))
+      if (!MAPTST(&seen, vv) || vv == SYSTEMSOLVABLE)
        continue;
       why = solv->decisionq_why.elements[idx];
       assert(why > 0);
@@ -1630,6 +1631,14 @@ solver_get_flag(Solver *solv, int flag)
     return solv->bestobeypolicy;
   case SOLVER_FLAG_NO_AUTOTARGET:
     return solv->noautotarget;
+  case SOLVER_FLAG_DUP_ALLOW_DOWNGRADE:
+    return solv->dup_allowdowngrade;
+  case SOLVER_FLAG_DUP_ALLOW_NAMECHANGE:
+    return solv->dup_allownamechange;
+  case SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE:
+    return solv->dup_allowarchchange;
+  case SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE:
+    return solv->dup_allowvendorchange;
   default:
     break;
   }
@@ -1681,6 +1690,18 @@ solver_set_flag(Solver *solv, int flag, int value)
   case SOLVER_FLAG_NO_AUTOTARGET:
     solv->noautotarget = value;
     break;
+  case SOLVER_FLAG_DUP_ALLOW_DOWNGRADE:
+    solv->dup_allowdowngrade = value;
+    break;
+  case SOLVER_FLAG_DUP_ALLOW_NAMECHANGE:
+    solv->dup_allownamechange = value;
+    break;
+  case SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE:
+    solv->dup_allowarchchange = value;
+    break;
+  case SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE:
+    solv->dup_allowvendorchange = value;
+    break;
   default:
     break;
   }
@@ -2064,7 +2085,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
                    rr -= solv->installed->end - solv->installed->start;
                  if (!rr->p)           /* identical to update rule? */
                    rr = r;
-                 if (!rr->p && (!specialupdaters || !specialupdaters[i - installed->start]))
+                 if (!rr->p && !(specialupdaters && specialupdaters[i - installed->start]))
                    continue;           /* orpaned package */
 
                  /* check if we should update this package to the latest version
@@ -2074,7 +2095,21 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
                  queue_empty(&dq);
                  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 && rr->p != i)))
                    {
-                     if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0)
+                     if (!rr->p)
+                       {
+                         /* specialupdater with no update/feature rule */
+                         for (d = specialupdaters[i - installed->start]; (p = pool->whatprovidesdata[d++]) != 0; )
+                           {
+                             if (solv->decisionmap[p] > 0)
+                               {
+                                 dq.count = 0;
+                                 break;
+                               }
+                             if (!solv->decisionmap[p])
+                               queue_push(&dq, p);
+                           }
+                       }
+                     else if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0)
                        {
                          /* special multiversion handling, make sure best version is chosen */
                          if (rr->p == i && solv->decisionmap[i] >= 0)
@@ -2084,7 +2119,7 @@ solver_run_sat(Solver *solv, int disablerules, int doweak)
                              queue_push(&dq, p);
                          if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
                            prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
-                         if (dq.count && rr->p)
+                         if (dq.count)
                            {
                              policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
                              p = dq.elements[0];
@@ -4446,6 +4481,250 @@ pool_isemptyupdatejob(Pool *pool, Id how, Id what)
   return 1;
 }
 
+static int
+get_userinstalled_cmp(const void *ap, const void *bp, void *dp)
+{
+  return *(Id *)ap - *(Id *)bp;
+}
+
+static int
+get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp)
+{
+  Pool *pool = dp;
+  return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp));
+}
+
+static void
+get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags)
+{
+  Id lastp = -1;
+  int i, j;
+  if ((flags & GET_USERINSTALLED_NAMES) != 0)
+    solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool);
+  else
+    solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0);
+  for (i = j = 0; i < q->count; i++)
+    if (q->elements[i] != lastp)
+      q->elements[j++] = lastp = q->elements[i];
+  queue_truncate(q, j);
+}
+
+void
+solver_get_userinstalled(Solver *solv, Queue *q, int flags)
+{
+  Pool *pool = solv->pool;
+  Id p, p2, pp;
+  Solvable *s;
+  Repo *installed = solv->installed;
+  int i, j;
+  Map userinstalled;
+  
+  map_init(&userinstalled, 0);
+  queue_empty(q);
+  /* first process jobs */
+  for (i = 0; i < solv->job.count; i += 2)
+    {
+      Id how = solv->job.elements[i];
+      Id what, select;
+      if (installed && (how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
+       {
+         if (!userinstalled.size)
+           map_grow(&userinstalled, installed->end - installed->start);
+         what = solv->job.elements[i + 1];
+         select = how & SOLVER_SELECTMASK;
+         if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
+           FOR_REPO_SOLVABLES(installed, p, s)
+             MAPSET(&userinstalled, p - installed->start);
+         FOR_JOB_SELECT(p, pp, select, what)
+           if (pool->solvables[p].repo == installed)
+             MAPSET(&userinstalled, p - installed->start);
+         continue;
+       }
+      if ((how & SOLVER_JOBMASK) != SOLVER_INSTALL)
+       continue;
+      if ((how & SOLVER_NOTBYUSER) != 0)
+       continue;
+      what = solv->job.elements[i + 1];
+      select = how & SOLVER_SELECTMASK;
+      FOR_JOB_SELECT(p, pp, select, what)
+        if (solv->decisionmap[p] > 0)
+         {
+           queue_push(q, p);
+#ifdef ENABLE_LINKED_PKGS
+           if (has_package_link(pool, pool->solvables + p))
+             {
+               int j;
+               Queue lq;
+               queue_init(&lq);
+               find_package_link(pool, pool->solvables + p, 0, &lq, 0, 0);
+               for (j = 0; j < lq.count; j++)
+                 if (solv->decisionmap[lq.elements[j]] > 0)
+                   queue_push(q, lq.elements[j]);
+             }
+#endif
+         }
+    }
+  /* now process updates of userinstalled packages */
+  if (installed && userinstalled.size)
+    {
+      for (i = 1; i < solv->decisionq.count; i++)
+       {
+         p = solv->decisionq.elements[i];
+         if (p <= 0)
+           continue;
+         s = pool->solvables + p;
+         if (!s->repo)
+           continue;
+         if (s->repo == installed)
+           {
+             if (MAPTST(&userinstalled, p - installed->start))
+               queue_push(q, p);
+             continue;
+           }
+         /* new package, check if we replace a userinstalled one */
+         FOR_PROVIDES(p2, pp, s->name)
+           {
+             Solvable *ps = pool->solvables + p2;
+             if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
+               continue;
+             if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
+               continue;
+             if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
+               continue;
+             queue_push(q, p);
+             break;
+           }
+         if (!p2 && s->repo != installed && s->obsoletes)
+           {
+             Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+             while ((obs = *obsp++) != 0)
+               {
+                 FOR_PROVIDES(p2, pp, obs)
+                   {
+                     Solvable *ps = pool->solvables + p2;
+                     if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
+                       continue;
+                     if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+                       continue;
+                     if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) 
+                       continue;
+                     queue_push(q, p); 
+                     break;
+                   }
+                 if (p2)
+                   break;
+               }
+           }
+       }
+    }
+  map_free(&userinstalled);
+  /* convert to names if asked */
+  if ((flags & GET_USERINSTALLED_NAMES) != 0)
+    {
+      for (i = 0; i < q->count; i++)
+       {
+         s = pool->solvables + q->elements[i];
+         q->elements[i] = s->name;
+       }
+    }
+  /* sort and unify */
+  if (q->count > 1)
+    get_userinstalled_sort_uniq(pool, q, flags);
+  /* invert if asked */
+  if ((flags & GET_USERINSTALLED_INVERTED) != 0)
+    {
+      /* first generate queue with all installed packages */
+      Queue invq;
+      queue_init(&invq);
+      for (i = 1; i < solv->decisionq.count; i++)
+       {
+         p = solv->decisionq.elements[i];
+         if (p <= 0)
+           continue;
+         s = pool->solvables + p;
+         if (!s->repo)
+           continue;
+         if ((flags & GET_USERINSTALLED_NAMES) != 0)
+           queue_push(&invq, s->name);
+         else
+           queue_push(&invq, p);
+       }
+      /* push q on invq, just in case... */
+      queue_insertn(&invq, invq.count, q->count, q->elements);
+      if (invq.count > 1)
+       get_userinstalled_sort_uniq(pool, &invq, flags);
+      /* subtract queues (easy as they are sorted and invq is a superset of q) */
+      if (q->count)
+       {
+         for (i = j = 0; i < invq.count; i++)
+           if (invq.elements[i] == q->elements[j])
+             {
+               invq.elements[i] = 0;
+               if (++j >= q->count)
+                 break;
+             }
+         queue_empty(q);
+       }
+      for (i = j = 0; i < invq.count; i++)
+       if (invq.elements[i])
+         queue_push(q, invq.elements[i]);
+      queue_free(&invq);
+    }
+}
+
+void
+pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags)
+{
+  int i;
+
+  if (flags & GET_USERINSTALLED_INVERTED)
+    {
+      Queue invq;
+      Id p, lastid;
+      Solvable *s;
+      int bad;
+      if (!pool->installed)
+       return;
+      queue_init(&invq);
+      FOR_REPO_SOLVABLES(pool->installed, p, s)
+       queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p);
+      queue_insertn(&invq, invq.count, q->count, q->elements);
+      if (invq.count > 1)
+        get_userinstalled_sort_uniq(pool, &invq, flags);
+      /* now the fun part, add q again, sort, and remove all dups */
+      queue_insertn(&invq, invq.count, q->count, q->elements);
+      if (invq.count > 1)
+       {
+         if ((flags & GET_USERINSTALLED_NAMES) != 0)
+           solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp_names, pool);
+         else
+           solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp, 0);
+       }
+      lastid = -1;
+      bad = 1;
+      for (i = 0; i < invq.count; i++)
+       {
+         if (invq.elements[i] == lastid)
+           {
+             bad = 1;
+             continue;
+           }
+         if (!bad)
+           queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
+         bad = 0;
+         lastid = invq.elements[i];
+       }
+      if (!bad)
+       queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
+      queue_free(&invq);
+    }
+  else
+    {
+      for (i = 0; i < q->count; i++)
+       queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]);
+    }
+}
+
 const char *
 solver_select2str(Pool *pool, Id select, Id what)
 {
@@ -4529,7 +4808,7 @@ pool_job2str(Pool *pool, Id how, Id what, Id flagmask)
       strstart = "multi version ";
       break;
     case SOLVER_LOCK:
-      strstart = "update ";
+      strstart = "lock ";
       break;
     case SOLVER_DISTUPGRADE:
       strstart = "dist upgrade ";