]> git.ipfire.org Git - thirdparty/libsolv.git/commitdiff
support yum style obsolete handling for package splits
authorMichael Schroeder <mls@suse.de>
Fri, 25 Jul 2014 16:22:43 +0000 (18:22 +0200)
committerMichael Schroeder <mls@suse.de>
Fri, 25 Jul 2014 16:22:43 +0000 (18:22 +0200)
Actually slightly modified: we insist that the dependencies in
the split group are exactly identical. Let's see how this works
out in practice...

bindings/solv.i
ext/testcase.c
src/policy.c
src/policy.h
src/problems.c
src/rules.c
src/rules.h
src/solver.c
src/solver.h
src/solverdebug.c

index 2d8f77521b3f1fb0efefb4d77f5e48bbce7bfa86..124bdca6d67f708c2867cf1acbc44f5f3d7c9c4f 100644 (file)
@@ -2769,6 +2769,7 @@ rb_eval_string(
   static const int SOLVER_FLAG_KEEP_ORPHANS = SOLVER_FLAG_KEEP_ORPHANS;
   static const int SOLVER_FLAG_BREAK_ORPHANS = SOLVER_FLAG_BREAK_ORPHANS;
   static const int SOLVER_FLAG_FOCUS_INSTALLED = SOLVER_FLAG_FOCUS_INSTALLED;
+  static const int SOLVER_FLAG_YUM_OBSOLETES = SOLVER_FLAG_YUM_OBSOLETES;
 
   static const int SOLVER_REASON_UNRELATED = SOLVER_REASON_UNRELATED;
   static const int SOLVER_REASON_UNIT_RULE = SOLVER_REASON_UNIT_RULE;
index 3da7affe63cbedc53d484a2cc496e4a557f8dd56..6f1c5b46006da28c21a92d2b179df7d0d7546745 100644 (file)
@@ -105,6 +105,7 @@ static struct solverflags2str {
   { SOLVER_FLAG_KEEP_ORPHANS,               "keeporphans", 0 },
   { SOLVER_FLAG_BREAK_ORPHANS,              "breakorphans", 0 },
   { SOLVER_FLAG_FOCUS_INSTALLED,            "focusinstalled", 0 },
+  { SOLVER_FLAG_YUM_OBSOLETES,              "yumobsoletes", 0 },
   { 0, 0, 0 }
 };
 
index 5b72517ac67344e4a17d9a3b6a940cb1611df6b7..9e5a934d18cf73cbfc88793e5660d4d69bc6761c 100644 (file)
@@ -776,7 +776,7 @@ move_installed_to_front(Pool *pool, Queue *plist)
  * sort list of packages (given through plist) by name and evr
  * return result through plist
  */
-static void
+void
 prune_to_best_version(Pool *pool, Queue *plist)
 {
   int i, j;
index d034f0de14384d6ea8354a2fead4c34f296e625d..a4dd4c422359da37e2512218979f2d775c4fc724 100644 (file)
@@ -36,6 +36,9 @@ extern void policy_update_recommendsmap(Solver *solv);
 
 extern void policy_create_obsolete_index(Solver *solv);
 
+/* internal, do not use */
+extern void prune_to_best_version(Pool *pool, Queue *plist);
+
 
 #ifdef __cplusplus
 }
index bb00aa6aa0498979fe1b22b3efe53a8c1c8566e7..b2063a5d1d041482f98558203f89bc4ab7fc5932 100644 (file)
@@ -918,7 +918,7 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp,
          MAPSET(rseen, rid - solv->learntrules);
          findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr, rseen);
        }
-      else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end) || (rid >= solv->bestrules && rid < solv->bestrules_end))
+      else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end) || (rid >= solv->bestrules && rid < solv->bestrules_end) || (rid >= solv->yumobsrules && rid <= solv->yumobsrules_end))
        {
          if (!*jobrp)
            *jobrp = rid;
@@ -1105,6 +1105,10 @@ solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id targ
       return pool_tmpjoin(pool, pool_dep2str(pool, dep), " is provided by the system", 0);
     case SOLVER_RULE_RPM:
       return "some dependency problem";
+    case SOLVER_RULE_BEST:
+      if (source > 0)
+        return pool_tmpjoin(pool, "cannot install the best update candidate for package ", pool_solvid2str(pool, source), 0);
+     return "cannot install the best candidate for the job";
     case SOLVER_RULE_RPM_NOT_INSTALLABLE:
       return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " is not installable");
     case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP:
@@ -1135,6 +1139,10 @@ solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id targ
     case SOLVER_RULE_RPM_SELF_CONFLICT:
       s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " conflicts with ");
       return pool_tmpappend(pool, s, pool_dep2str(pool, dep), " provided by itself");
+    case SOLVER_RULE_YUMOBS:
+      s = pool_tmpjoin(pool, "both package ", pool_solvid2str(pool, source), " and ");
+      s = pool_tmpjoin(pool, s, pool_solvid2str(pool, target), " obsolete ");
+      return pool_tmpappend(pool, s, pool_dep2str(pool, dep), 0);
     default:
       return "bad problem rule type";
     }
index f245533c564ec3861fe1553b3c6b4634e35a8693..8f07bab6a432ef2336b0c941ba6fc4fcb568aa88 100644 (file)
@@ -2652,8 +2652,26 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
     }
   if (rid >= solv->bestrules && rid < solv->bestrules_end)
     {
+      if (fromp && solv->bestrules_pkg[rid - solv->bestrules] > 0)
+       *fromp = solv->bestrules_pkg[rid - solv->bestrules];
       return SOLVER_RULE_BEST;
     }
+  if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)
+    {
+      if (fromp)
+       *fromp = -r->p;
+      if (top)
+       {
+         /* first solvable is enough, we just need it for the name */
+         if (!r->d || r->d == -1)
+           *top = r->w2;
+         else
+           *top = pool->whatprovidesdata[r->d < 0 ? -r->d : r->d];
+       }
+      if (depp)
+       *depp = solv->yumobsrules_info[rid - solv->yumobsrules];
+      return SOLVER_RULE_YUMOBS;
+    }
   if (rid >= solv->choicerules && rid < solv->choicerules_end)
     {
       return SOLVER_RULE_CHOICE;
@@ -2684,6 +2702,8 @@ solver_ruleclass(Solver *solv, Id rid)
     return SOLVER_RULE_INFARCH;
   if (rid >= solv->bestrules && rid < solv->bestrules_end)
     return SOLVER_RULE_BEST;
+  if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)
+    return SOLVER_RULE_YUMOBS;
   if (rid >= solv->choicerules && rid < solv->choicerules_end)
     return SOLVER_RULE_CHOICE;
   if (rid >= solv->learntrules)
@@ -3251,6 +3271,228 @@ solver_addbestrules(Solver *solv, int havebestinstalljobs)
   queue_free(&r2pkg);
 }
 
+
+
+
+/* yumobs rule handling */
+
+static void
+find_obsolete_group(Solver *solv, Id obs, Queue *q)
+{
+  Pool *pool = solv->pool;
+  Queue qn;
+  Id p2, pp2, op, *opp, opp2;
+  int i, j, qnc, ncnt;
+
+  queue_empty(q);
+  FOR_PROVIDES(p2, pp2, obs)
+    {
+      Solvable *s2 = pool->solvables + p2;
+      if (s2->repo != pool->installed)
+       continue;
+      if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
+       continue;
+      /* we obsolete installed package s2 with obs. now find all other packages that have the same dep  */
+      for (opp = solv->obsoletes_data + solv->obsoletes[p2 - solv->installed->start]; (op = *opp++) != 0;)
+       {
+         Solvable *os = pool->solvables + op;
+         Id obs2, *obsp2;
+         if (!os->obsoletes)
+           continue;
+         if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os))
+           continue;
+         obsp2 = os->repo->idarraydata + os->obsoletes; 
+         while ((obs2 = *obsp2++) != 0)
+           if (obs2 == obs)
+             break;
+         if (obs2)
+           queue_pushunique(q, op);
+       }
+      /* also search packages with the same name */
+      FOR_PROVIDES(op, opp2, s2->name)
+       {
+         Solvable *os = pool->solvables + op;
+         Id obs2, *obsp2;
+         if (os->name != s2->name)
+           continue;
+         if (!os->obsoletes)
+           continue;
+         if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os))
+           continue;
+         obsp2 = os->repo->idarraydata + os->obsoletes; 
+         while ((obs2 = *obsp2++) != 0)
+           if (obs2 == obs)
+             break;
+         if (obs2)
+           queue_pushunique(q, op);
+       }
+    }
+  /* find names so that we can build groups */
+  queue_init_clone(&qn, q);
+  prune_to_best_version(solv->pool, &qn);
+#if 0
+{
+  for (i = 0; i < qn.count; i++)
+    printf(" + %s\n", pool_solvid2str(pool, qn.elements[i]));
+}
+#endif
+  /* filter into name groups */
+  qnc = qn.count;
+  if (qnc == 1)
+    {
+      queue_free(&qn);
+      queue_empty(q);
+      return;
+    }
+  ncnt = 0;
+  for (i = 0; i < qnc; i++)
+    {
+      Id n = pool->solvables[qn.elements[i]].name;
+      int got = 0;
+      for (j = 0; j < q->count; j++)
+       {
+         Id p = q->elements[j];
+         if (pool->solvables[p].name == n)
+           {
+             queue_push(&qn, p);
+             got = 1;
+           }
+       }
+      if (got)
+       {
+         queue_push(&qn, 0);
+         ncnt++;
+       }
+    }
+  if (ncnt <= 1)
+    {
+      queue_empty(q);
+    }
+  else
+    {
+      queue_empty(q);
+      queue_insertn(q, 0, qn.count - qnc, qn.elements + qnc);
+    }
+  queue_free(&qn);
+}
+
+void
+solver_addyumobsrules(Solver *solv)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Id p, op, *opp;
+  Solvable *s;
+  Queue qo, qq, yumobsinfoq;
+  int i, j, k;
+  unsigned int now;
+
+  solv->yumobsrules = solv->nrules;
+  if (!installed || !solv->obsoletes)
+    {
+      solv->yumobsrules_end = solv->nrules;
+      return;
+    }
+  now = solv_timems(0);
+  queue_init(&qo);
+  FOR_REPO_SOLVABLES(installed, p, s)
+    {
+      if (!solv->obsoletes[p - installed->start])
+       continue;
+#if 0
+printf("checking yumobs for %s\n", pool_solvable2str(pool, s));
+#endif
+      queue_empty(&qo);
+      for (opp = solv->obsoletes_data + solv->obsoletes[p - installed->start]; (op = *opp++) != 0;)
+       {
+         Solvable *os = pool->solvables + op;
+          Id obs, *obsp = os->repo->idarraydata + os->obsoletes;
+         Id p2, pp2;
+         while ((obs = *obsp++) != 0)
+           {
+             FOR_PROVIDES(p2, pp2, obs)
+               {
+                 Solvable *s2 = pool->solvables + p2;
+                 if (s2->repo != installed)
+                   continue;
+                 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
+                   continue;
+                 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
+                   continue;
+                 queue_pushunique(&qo, obs);
+                 break;
+               }
+           }
+       }
+    }
+  if (!qo.count)
+    {
+      queue_free(&qo);
+      return;
+    }
+  queue_init(&yumobsinfoq);
+  queue_init(&qq);
+  for (i = 0; i < qo.count; i++)
+    {
+      int group, groupk, groupstart;
+      queue_empty(&qq);
+#if 0
+printf("investigating %s\n", pool_dep2str(pool, qo.elements[i]));
+#endif
+      find_obsolete_group(solv, qo.elements[i], &qq);
+#if 0
+printf("result:\n");
+for (j = 0; j < qq.count; j++)
+  if (qq.elements[j] == 0)
+    printf("---\n");
+  else
+    printf("%s\n", pool_solvid2str(pool, qq.elements[j]));
+#endif
+  
+      if (!qq.count)
+       continue;
+      /* at least two goups, build rules */
+      group = 0;
+      for (j = 0; j < qq.count; j++)
+       {
+         p = qq.elements[j];
+         if (!p)
+           {
+             group++;
+             continue;
+           }
+         if (pool->solvables[p].repo == installed)
+           continue;
+         groupk = 0;
+         groupstart = 0;
+         for (k = 0; k < qq.count; k++)
+           {
+             Id pk = qq.elements[k];
+             if (pk)
+               continue;
+             if (group != groupk && k > groupstart)
+               {
+                 /* add the rule */
+                 Queue qhelper;
+                 memset(&qhelper, 0, sizeof(qhelper));
+                 qhelper.count = k - groupstart;
+                 qhelper.elements = qq.elements + groupstart;
+                 solver_addrule(solv, -p, pool_queuetowhatprovides(pool, &qhelper));
+                 queue_push(&yumobsinfoq, qo.elements[i]);
+               }
+             groupstart = k + 1;
+             groupk++;
+           }
+       }
+    }
+  if (yumobsinfoq.count)
+    solv->yumobsrules_info = solv_memdup2(yumobsinfoq.elements, yumobsinfoq.count, sizeof(Id));
+  queue_free(&yumobsinfoq);
+  queue_free(&qq);
+  solv->yumobsrules_end = solv->nrules;
+  POOL_DEBUG(SOLV_DEBUG_STATS, "yumobs rule creation took %d ms\n", solv_timems(now));
+}
+
 #undef CLEANDEPSDEBUG
 
 /*
index 06048e4352ce01ec32088761536fefc36198af04..3be3ea1e7a528815e783d9d1014636b9989c9780 100644 (file)
@@ -69,7 +69,8 @@ typedef enum {
   SOLVER_RULE_INFARCH = 0x600,
   SOLVER_RULE_CHOICE = 0x700,
   SOLVER_RULE_LEARNT = 0x800,
-  SOLVER_RULE_BEST = 0x900
+  SOLVER_RULE_BEST = 0x900,
+  SOLVER_RULE_YUMOBS = 0xa00
 } SolverRuleinfo;
 
 #define SOLVER_RULE_TYPEMASK    0xff00
@@ -127,6 +128,9 @@ extern void solver_disablechoicerules(struct _Solver *solv, Rule *r);
 /* best rules */
 extern void solver_addbestrules(struct _Solver *solv, int havebestinstalljobs);
 
+/* yumobs rules */
+extern void solver_addyumobsrules(struct _Solver *solv);
+
 /* policy rule disabling/reenabling */
 extern void solver_disablepolicyrules(struct _Solver *solv);
 extern void solver_reenablepolicyrules(struct _Solver *solv, int jobidx);
index b0f1bce795a86e6d7cebf95d9c98dfaba80ab056..48b3aaac95054748ecb50f39368bbc828a1fc91d 100644 (file)
@@ -1681,6 +1681,7 @@ solver_free(Solver *solv)
   solv_free(solv->specialupdaters);
   solv_free(solv->choicerules_ref);
   solv_free(solv->bestrules_pkg);
+  solv_free(solv->yumobsrules_info);
   solv_free(solv->instbuddy);
   solv_free(solv);
 }
@@ -1730,6 +1731,8 @@ solver_get_flag(Solver *solv, int flag)
     return solv->break_orphans;
   case SOLVER_FLAG_FOCUS_INSTALLED:
     return solv->focus_installed;
+  case SOLVER_FLAG_YUM_OBSOLETES:
+    return solv->do_yum_obsoletes;
   default:
     break;
   }
@@ -1802,6 +1805,9 @@ solver_set_flag(Solver *solv, int flag, int value)
   case SOLVER_FLAG_FOCUS_INSTALLED:
     solv->focus_installed = value;
     break;
+  case SOLVER_FLAG_YUM_OBSOLETES:
+    solv->do_yum_obsoletes = value;
+    break;
   default:
     break;
   }
@@ -3401,6 +3407,7 @@ solver_solve(Solver *solv, Queue *job)
   queuep_free(&solv->cleandeps_updatepkgs);
   queue_empty(&solv->ruleassertions);
   solv->bestrules_pkg = solv_free(solv->bestrules_pkg);
+  solv->yumobsrules_info = solv_free(solv->yumobsrules_info);
   solv->choicerules_ref = solv_free(solv->choicerules_ref);
   if (solv->noupdate.size)
     map_empty(&solv->noupdate);
@@ -3963,6 +3970,11 @@ solver_solve(Solver *solv, Queue *job)
   if (hasdupjob)
     solver_freedupmaps(solv);  /* no longer needed */
 
+  if (solv->do_yum_obsoletes)
+    solver_addyumobsrules(solv);
+  else
+    solv->yumobsrules = solv->yumobsrules_end = solv->nrules;
+
   if (1)
     solver_addchoicerules(solv);
   else
index 3d63b6fe75e0c9d3c3a729d6241d1c7d56d16c13..49ccec8b1bbea1e05118d5a2923ebc9b91233b14 100644 (file)
@@ -70,6 +70,10 @@ struct _Solver {
   Id bestrules_end;
   Id *bestrules_pkg;
 
+  Id yumobsrules;                      /* rules from yum obsoletes handling */
+  Id yumobsrules_end;
+  Id *yumobsrules_info;                        /* the dependency for each rule */
+
   Id choicerules;                      /* choice rules (always weak) */
   Id choicerules_end;
   Id *choicerules_ref;
@@ -161,6 +165,7 @@ struct _Solver {
   int bestobeypolicy;                  /* true: stay in policy with the best rules */
   int noautotarget;                    /* true: do not assume targeted for up/dup jobs that contain no installed solvable */
   int focus_installed;                 /* true: resolve update rules first */
+  int do_yum_obsoletes;                        /* true: add special yumobs rules */
 
   Map dupmap;                          /* dup these packages*/
   int dupmap_all;                      /* dup all packages */
@@ -289,6 +294,7 @@ typedef struct _Solver Solver;
 #define SOLVER_FLAG_KEEP_ORPHANS               18
 #define SOLVER_FLAG_BREAK_ORPHANS              19
 #define SOLVER_FLAG_FOCUS_INSTALLED            20
+#define SOLVER_FLAG_YUM_OBSOLETES              21
 
 #define GET_USERINSTALLED_NAMES                        (1 << 0)        /* package names instead if ids */
 #define GET_USERINSTALLED_INVERTED             (1 << 1)        /* autoinstalled */
index afec8c5a550af05acf41d859ae88840fbb14e4c6..3e840462f4df03469f066f425434bf50eafffb62 100644 (file)
@@ -126,6 +126,8 @@ solver_printruleclass(Solver *solv, int type, Rule *r)
     POOL_DEBUG(type, "UPDATE ");
   else if (p >= solv->featurerules && p < solv->featurerules_end)
     POOL_DEBUG(type, "FEATURE ");
+  else if (p >= solv->yumobsrules && p < solv->yumobsrules_end)
+    POOL_DEBUG(type, "YUMOBS ");
   solver_printrule(solv, type, r);
 }