Imported Upstream version 0.7.21 upstream/0.7.21
authorDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 21 Sep 2022 00:39:02 +0000 (09:39 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Wed, 21 Sep 2022 00:39:02 +0000 (09:39 +0900)
43 files changed:
NEWS
VERSION.cmake
bindings/solv.i
doc/libsolv-bindings.txt
doc/libsolv-constantids.txt
doc/libsolv-history.txt
doc/libsolv.txt
ext/repo_deb.c
ext/repo_testcase.c
ext/testcase.c
ext/testcase.h
package/libsolv.changes
src/libsolv.ver
src/order.c
src/pool.c
src/pool.h
src/pooltypes.h
src/poolvendor.c
src/problems.c
src/problems.h
src/qsort_r.c
src/repo_solv.c
src/repo_solv.h
src/repo_write.c
src/repo_write.h
src/repodata.h
src/repopage.c
src/repopage.h
src/rules.c
src/rules.h
src/sha2.c
src/solvable.h
src/solver.c
src/solver.h
src/solver_util.c
src/solverdebug.c
src/solvversion.c
src/solvversion.h.in
src/util.h
test/testcases/strictrepoprio/strictrepoprio.t [new file with mode: 0644]
tools/common_write.c
tools/dumpsolv.c
tools/testsolv.c

diff --git a/NEWS b/NEWS
index d99f0ee..6560320 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,23 @@
 
-This file contains the major changes between
-libsolv versions:
+This file contains the major changes between libsolv versions:
+
+Version 0.7.21
+- selected bug fixes:
+  * fix segfault on conflict resolution when using bindings
+  * fix split provides not working if the update includes a forbidden
+    vendor change
+- new features:
+  * support strict repository priorities
+    new solver flag: SOLVER_FLAG_STRICT_REPO_PRIORITY
+  * support zstd compressed control files in debian packages
+  * add an ifdef allowing to rename Solvable dependency members
+    ("requires" is a keyword in C++20)
+  * support setting/reading userdata in solv files
+    new functions: repowriter_set_userdata, solv_read_userdata
+  * support queying of the custom vendor check function
+    new function: pool_get_custom_vendorcheck
+  * support solv files with an idarray block
+  * allow accessing the toolversion at runtime
 
 Version 0.7.20
 - selected bug fixes:
index 5587ccf..f9dbee0 100644 (file)
@@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "1")
 
 SET(LIBSOLV_MAJOR "0")
 SET(LIBSOLV_MINOR "7")
-SET(LIBSOLV_PATCH "20")
+SET(LIBSOLV_PATCH "21")
 
index 61c6fc8..1d35bf6 100644 (file)
@@ -3411,7 +3411,7 @@ returnself(matchsolvable)
     e = solv_calloc(1, sizeof(*e));
     e->solv = solv;
     e->problemid = problemid;
-    e->solutionid = id;
+    e->solutionid = solutionid;
     e->id = id;
     e->type = type;
     e->p = p;
@@ -3571,6 +3571,7 @@ returnself(matchsolvable)
   static const int SOLVER_FLAG_STRONG_RECOMMENDS = SOLVER_FLAG_STRONG_RECOMMENDS;
   static const int SOLVER_FLAG_INSTALL_ALSO_UPDATES = SOLVER_FLAG_INSTALL_ALSO_UPDATES;
   static const int SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED = SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED;
+  static const int SOLVER_FLAG_STRICT_REPO_PRIORITY = SOLVER_FLAG_STRICT_REPO_PRIORITY;
 
   static const int SOLVER_REASON_UNRELATED = SOLVER_REASON_UNRELATED;
   static const int SOLVER_REASON_UNIT_RULE = SOLVER_REASON_UNIT_RULE;
index 0fa313b..cdead65 100644 (file)
@@ -12,10 +12,10 @@ libsolv-bindings - access libsolv from perl/python/ruby
 Description
 -----------
 Libsolv's language bindings offer an abstract, object orientated interface
-to the library. The supported languages are currently perl, python, and ruby.
-All example code (except in the specifics sections, of course) lists first
-the ``C-ish'' interface, then the syntax for perl, python, and ruby (in that
-order).
+to the library. The supported languages are currently perl, python, ruby and
+tcl. All example code (except in the specifics sections, of course) lists
+first the ``C-ish'' interface, then the syntax for perl, python, and ruby
+(in that order).
 
 
 Perl Specifics
index 907a7e5..140f978 100644 (file)
@@ -15,9 +15,9 @@ Constant Ids are Ids of strings that are often needed. They are defined
 to ease programming and reduce the number of pool_str2id calls. The
 constant Ids are part of the binary ABI of libsolv, a minor version 
 update will only add new constants and not change existing Ids to
-maintain compatible. The on-disk solv format works does not use the
-fixed Ids, but instead references the strings, so solv files can still
-be read when the ABI is broken.
+maintain compatibility. The on-disk solv format does not use the fixed
+Ids, but instead references the strings, so solv files can still be
+read when the ABI is broken.
 
 
 Special Strings
@@ -31,7 +31,7 @@ Special Strings
 
 Solvable Attributes
 -------------------
-These are Ids for keyname of attributes. They can be used in the
+These are Ids for keynames of attributes. They can be used in the
 lookup and storage functions to select the correct attribute in the
 solvable. The descriptions below describe the intended semantics
 of the values stored in the attribute with the keyname.
index d0a5e62..62afe20 100644 (file)
@@ -53,12 +53,12 @@ solving on Debian. Looking at the SAT entry in Wikipedia, it was easy
 to see that this indeed was the missing piece: SAT algorithms are well
 researched and there are quite some open source implementations.
 I decided to look at the minisat code, as it is one of the fastest
-solvers while consisting of too many lines of code.
+solvers while consisting of not too many lines of code.
 
 Of course, directly using minisat would not work, as a package solver
 does not need to find just one correct solution, but it also has to
 optimize some metrics, i.e. keep as many packages installed as possible.
-Thus, I needed to write my own solver incorporation the ideas and
+Thus, I needed to write my own solver, incorporating the ideas and
 algorithms used in minisat. This wasn't very hard, and at the end of
 the hack week the solver calculated the first right solutions.
 
index f101808..9f5e385 100644 (file)
@@ -28,7 +28,7 @@ The libsolv documentation is split into multiple parts:
 Pointer Validity
 ----------------
 Note that all pointers to objects that have an Id have only a limited
-validity period, with the exception of Repo pointers. There are only
+validity period, with the exception of Repo pointers. They are only
 guaranteed to be valid until a new object of that type is added or an
 object of that type is removed. Thus pointers to Solvable objects are only 
 valid until another solvable is created, because adding a Solvable may
index 34f40fa..ac01b65 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
+#ifdef ENABLE_ZLIB_COMPRESSION
 #include <zlib.h>
+#endif
+#ifdef ENABLE_LZMA_COMPRESSION
 #include <lzma.h>
-#include <errno.h>
+#endif
+#ifdef ENABLE_ZSTD_COMPRESSION
+#include <zstd.h>
+#endif
 
 #include "pool.h"
 #include "repo.h"
 #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
 #endif
 
+#define MAX_CONTROL_SIZE       0x1000000
+
+#ifdef ENABLE_ZLIB_COMPRESSION
+
 static unsigned char *
 decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
 {
@@ -107,6 +118,18 @@ decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
   return out;
 }
 
+#else
+
+static unsigned char *
+decompress_gz(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+  return 0;
+}
+
+#endif /* ENABLE_ZLIB_COMPRESSION */
+
+#ifdef ENABLE_LZMA_COMPRESSION
+
 static unsigned char *
 decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
 {
@@ -159,6 +182,81 @@ decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
   return out;
 }
 
+#else
+
+static unsigned char *
+decompress_xz(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+  return 0;
+}
+
+#endif /* ENABLE_LZMA_COMPRESSION */
+
+#ifdef ENABLE_ZSTD_COMPRESSION
+
+static unsigned char *
+decompress_zstd(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+  ZSTD_DStream *dstream;
+  ZSTD_inBuffer inbuf;
+  ZSTD_outBuffer outbuf;
+  int ret;
+
+  dstream = ZSTD_createDStream();
+  if (!dstream)
+    return 0;
+  if (ZSTD_isError(ZSTD_initDStream(dstream)))
+    {
+      ZSTD_freeDStream(dstream);
+      return 0;
+    }
+  inbuf.src = in;
+  inbuf.pos = 0;
+  inbuf.size = inl;
+  outbuf.dst = solv_malloc(4096);
+  outbuf.pos = 0;
+  outbuf.size = 4096;
+  for (;;)
+    {
+      if (outbuf.pos == outbuf.size)
+       {
+         outbuf.size += 4096;
+         if (outbuf.size >= maxoutl)
+           {
+             ret = 1;
+             break;
+           }
+         outbuf.dst = solv_realloc(outbuf.dst, outbuf.size + 4096);
+       }
+      ret = ZSTD_decompressStream(dstream, &outbuf, &inbuf);
+      if (ret == 0 && inbuf.pos == inbuf.size)
+       break;
+      if (ZSTD_isError(ret) || (inbuf.pos == inbuf.size && outbuf.pos < outbuf.size))
+       {
+         ret = 1;
+         break;
+       }
+    }
+  ZSTD_freeDStream(dstream);
+  if (ret)
+    {
+      solv_free(outbuf.dst);
+      return 0;
+    }
+  *outlp = outbuf.pos;
+  return outbuf.dst;
+}
+
+#else
+
+static unsigned char *
+decompress_zstd(unsigned char *in, int inl, int *outlp, int maxoutl)
+{
+  return 0;
+}
+
+#endif /* ENABLE_ZSTD_COMPRESSION */
+
 static Id
 parseonedep(Pool *pool, char *p)
 {
@@ -544,6 +642,7 @@ repo_add_debdb(Repo *repo, int flags)
 #define CONTROL_COMP_NONE      0
 #define CONTROL_COMP_GZIP      1
 #define CONTROL_COMP_XZ                2
+#define CONTROL_COMP_ZSTD      3
 
 Id
 repo_add_deb(Repo *repo, const char *deb, int flags)
@@ -599,6 +698,8 @@ repo_add_deb(Repo *repo, const char *deb, int flags)
     control_comp = CONTROL_COMP_GZIP;
   else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz  ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.xz/ ", 16))
     control_comp = CONTROL_COMP_XZ;
+  else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar.zst/", 16))
+    control_comp = CONTROL_COMP_ZSTD;
   else if (!strncmp((char *)buf + 8 + 60 + vlen, "control.tar     ", 16) || !strncmp((char *)buf + 8 + 60 + vlen, "control.tar/    ", 16))
     control_comp = CONTROL_COMP_NONE;
   else
@@ -611,7 +712,7 @@ repo_add_deb(Repo *repo, const char *deb, int flags)
    * just keeps from allocating arbitrarily large amounts of memory.
    */
   clen = atoi((char *)buf + 8 + 60 + vlen + 48);
-  if (clen <= 0 || clen >= 0x1000000)
+  if (clen <= 0 || clen >= MAX_CONTROL_SIZE)
     {
       pool_error(pool, -1, "%s: control.tar has illegal size", deb);
       fclose(fp);
@@ -645,9 +746,11 @@ repo_add_deb(Repo *repo, const char *deb, int flags)
     }
   ctar = 0;
   if (control_comp == CONTROL_COMP_GZIP)
-    ctar = decompress_gz(ctgz, clen, &ctarlen, 0x1000000);
+    ctar = decompress_gz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
   else if (control_comp == CONTROL_COMP_XZ)
-    ctar = decompress_xz(ctgz, clen, &ctarlen, 0x1000000);
+    ctar = decompress_xz(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
+  else if (control_comp == CONTROL_COMP_ZSTD)
+    ctar = decompress_zstd(ctgz, clen, &ctarlen, MAX_CONTROL_SIZE);
   else
     {
       ctarlen = clen;
@@ -656,7 +759,7 @@ repo_add_deb(Repo *repo, const char *deb, int flags)
   solv_free(ctgz);
   if (!ctar)
     {
-      pool_error(pool, -1, "%s: control.tar is corrupt", deb);
+      pool_error(pool, -1, "%s: control.tar decompression error", deb);
       return 0;
     }
   bp = ctar;
index 00f7b54..38676ef 100644 (file)
@@ -489,6 +489,9 @@ testcase_write_testtags(Repo *repo, FILE *fp)
       ti = solvable_lookup_num(s, SOLVABLE_BUILDTIME, 0);
       if (ti)
        fprintf(fp, "=Tim: %u\n", ti);
+      ti = solvable_lookup_num(s, SOLVABLE_INSTALLTIME, 0);
+      if (ti)
+       fprintf(fp, "=Itm: %u\n", ti);
       writefilelist(repo, fp, "Fls:", s);
     }
   queue_free(&q);
@@ -635,6 +638,11 @@ testcase_add_testtags(Repo *repo, FILE *fp, int flags)
          if (t)
            repodata_set_num(data, s - pool->solvables, SOLVABLE_BUILDTIME, t);
          break;
+       case 'I' << 16 | 't' << 8 | 'm':
+         t = atoi(line + 6);
+         if (t)
+           repodata_set_num(data, s - pool->solvables, SOLVABLE_INSTALLTIME, t);
+         break;
        case 'R' << 16 | 'e' << 8 | 'q':
          s->requires = adddep(repo, s->requires, line + 6, -SOLVABLE_PREREQMARKER);
          break;
index 055452f..4262199 100644 (file)
@@ -100,6 +100,7 @@ static struct resultflags2str {
   { TESTCASE_RESULT_CLEANDEPS,         "cleandeps" },
   { TESTCASE_RESULT_JOBS,              "jobs" },
   { TESTCASE_RESULT_USERINSTALLED,     "userinstalled" },
+  { TESTCASE_RESULT_ORDER,             "order" },
   { 0, 0 }
 };
 
@@ -135,6 +136,7 @@ static struct solverflags2str {
   { SOLVER_FLAG_STRONG_RECOMMENDS,          "strongrecommends", 0 },
   { SOLVER_FLAG_INSTALL_ALSO_UPDATES,       "installalsoupdates", 0 },
   { SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED, "onlynamespacerecommended", 0 },
+  { SOLVER_FLAG_STRICT_REPO_PRIORITY,       "strictrepopriority", 0 },
   { 0, 0, 0 }
 };
 
@@ -439,6 +441,45 @@ testcase_str2repo(Pool *pool, const char *str)
   return repo;
 }
 
+static const char *
+testcase_escape(Pool *pool, const char *str)
+{
+  size_t nbad = 0;
+  const char *p;
+  char *new, *np;
+  for (p = str; *p; p++)
+    if (*p == '\\' || *p == ' ' || *p == '\t')
+      nbad++;
+  if (!nbad)
+    return str;
+  new = pool_alloctmpspace(pool, strlen(str) + 1 + nbad * 2);
+  for (np = new, p = str; *p; p++)
+    {
+      *np++ = *p;
+      if (*p == '\\' || *p == ' ' || *p == '\t')
+       {
+         np[-1] = '\\';
+         solv_bin2hex((unsigned char *)p, 1, np);
+         np += 2;
+       }
+    }
+  *np = 0;
+  return new;
+}
+
+static void
+testcase_unescape_inplace(char *str)
+{
+  char *p, *q;
+  for (p = q = str; *p;)
+    {
+      *q++ = *p++;
+      if (p[-1] == '\\')
+       solv_hex2bin((const char **)&p, (unsigned char *)q - 1, 1);
+    }
+  *q = 0;
+}
+
 /* check evr and buildflavors */
 static int
 str2solvid_check(Pool *pool, Solvable *s, const char *start, const char *end, Id evrid)
@@ -1194,6 +1235,7 @@ static struct rclass2str {
   { SOLVER_RULE_YUMOBS, "yumobs" },
   { SOLVER_RULE_BLACK, "black" },
   { SOLVER_RULE_RECOMMENDS, "recommends" },
+  { SOLVER_RULE_STRICT_REPO_PRIORITY, "strictrepoprio" },
   { 0, 0 }
 };
 
@@ -1392,6 +1434,25 @@ testcase_solverresult(Solver *solv, int resultflags)
        }
       queue_free(&q);
     }
+  if ((resultflags & TESTCASE_RESULT_ORDER) != 0)
+    {
+      int i;
+      char buf[256];
+      Id p;
+      Transaction *trans = solver_create_transaction(solv);
+      transaction_order(trans, 0);
+      for (i = 0; i < trans->steps.count; i++)
+       {
+         p = trans->steps.elements[i];
+         if (pool->installed && pool->solvables[p].repo == pool->installed)
+           sprintf(buf, "%4d erase ", i + 1);
+         else
+           sprintf(buf, "%4d install ", i + 1);
+         s = pool_tmpjoin(pool, "order ", buf, testcase_solvid2str(pool, p));
+         strqueue_push(&sq, s);
+       }
+      transaction_free(trans);
+    }
   if ((resultflags & TESTCASE_RESULT_ALTERNATIVES) != 0)
     {
       char *altprefix;
@@ -1582,6 +1643,43 @@ testcase_solverresult(Solver *solv, int resultflags)
   return result;
 }
 
+static void
+dump_custom_vendorcheck(Pool *pool, Strqueue *sq, int (*vendorcheck)(Pool *, Solvable *, Solvable *))
+{
+  Id p, lastvendor = 0;
+  Queue vq;
+  int i, j;
+  char *cmd;
+
+  queue_init(&vq);
+  FOR_POOL_SOLVABLES(p)
+    {
+      Id vendor = pool->solvables[p].vendor;
+      if (!vendor || vendor == lastvendor)
+       continue;
+      lastvendor = vendor;
+      for (i = 0; i < vq.count; i += 2)
+       if (vq.elements[i] == vendor)
+         break;
+      if (i == vq.count)
+        queue_push2(&vq, vendor, p);
+    }
+  for (i = 0; i < vq.count; i += 2)
+    {
+      Solvable *s1 = pool->solvables + vq.elements[i + 1];
+      for (j = i + 2; j < vq.count; j += 2)
+       {
+         Solvable *s2 = pool->solvables + vq.elements[j + 1];
+         if (vendorcheck(pool, s1, s2) || vendorcheck(pool, s2, s1))
+           continue;
+         cmd = pool_tmpjoin(pool, "vendorclass", 0, 0);
+         cmd = pool_tmpappend(pool, cmd, " ", testcase_escape(pool, pool_id2str(pool, vq.elements[i])));
+         cmd = pool_tmpappend(pool, cmd, " ", testcase_escape(pool, pool_id2str(pool, vq.elements[j])));
+         strqueue_push(sq, cmd);
+       }
+    }
+  queue_free(&vq);
+}
 
 static int
 testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const char *testcasename, const char *resultname)
@@ -1595,6 +1693,7 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha
   Strqueue sq;
   char *cmd, *out, *result;
   const char *s;
+  int (*vendorcheck)(Pool *, Solvable *, Solvable *);
 
   if (!testcasename)
     testcasename = "testcase.t";
@@ -1671,12 +1770,15 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha
       strqueue_push(&sq, cmd);
     }
 
-  if (pool->vendorclasses)
+  vendorcheck = pool_get_custom_vendorcheck(pool);
+  if (vendorcheck)
+    dump_custom_vendorcheck(pool, &sq, vendorcheck);
+  else if (pool->vendorclasses)
     {
       cmd = 0;
       for (i = 0; pool->vendorclasses[i]; i++)
        {
-         cmd = pool_tmpappend(pool, cmd ? cmd : "vendorclass", " ", pool->vendorclasses[i]);
+         cmd = pool_tmpappend(pool, cmd ? cmd : "vendorclass", " ", testcase_escape(pool, pool->vendorclasses[i]));
          if (!pool->vendorclasses[i + 1])
            {
              strqueue_push(&sq, cmd);
@@ -2096,7 +2198,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
            }
           repo->priority = prio;
           repo->subpriority = subprio;
-         if (strcmp(pieces[3], "empty") != 0)
+         if (strcmp(pieces[3], "empty") != 0 && npieces > 4)
            {
              const char *repotype = pool_tmpjoin(pool, pieces[3], 0, 0);       /* gets overwritten in <inline> case */
              if (!strcmp(pieces[4], "<inline>"))
@@ -2237,6 +2339,9 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
        }
       else if (!strcmp(pieces[0], "vendorclass") && npieces > 1)
        {
+         int i;
+         for (i = 1; i < npieces; i++)
+           testcase_unescape_inplace(pieces[i]);
          pool_addvendorclass(pool, (const char **)(pieces + 1));
        }
       else if (!strcmp(pieces[0], "namespace") && npieces > 1)
index 5b2e573..c69098d 100644 (file)
@@ -21,6 +21,7 @@
 #define TESTCASE_RESULT_CLEANDEPS      (1 << 9)
 #define TESTCASE_RESULT_JOBS           (1 << 10)
 #define TESTCASE_RESULT_USERINSTALLED  (1 << 11)
+#define TESTCASE_RESULT_ORDER          (1 << 12)
 
 /* reuse solver hack, testsolv use only */
 #define TESTCASE_RESULT_REUSE_SOLVER   (1 << 31)
index c402812..f9d3fb7 100644 (file)
@@ -1,4 +1,23 @@
 -------------------------------------------------------------------
+Fri Feb 25 17:32:20 CET 2022 - mls@suse.de
+
+- fix segfault on conflict resolution when using bindings
+- fix split provides not working if the update includes a forbidden
+  vendor change
+- support strict repository priorities
+  new solver flag: SOLVER_FLAG_STRICT_REPO_PRIORITY
+- support zstd compressed control files in debian packages
+- add an ifdef allowing to rename Solvable dependency members
+  ("requires" is a keyword in C++20)
+- support setting/reading userdata in solv files
+  new functions: repowriter_set_userdata, solv_read_userdata
+- support queying of the custom vendor check function
+  new function: pool_get_custom_vendorcheck
+- support solv files with an idarray block
+- allow accessing the toolversion at runtime
+- bump version to 0.7.21
+
+-------------------------------------------------------------------
 Sat Sep 25 22:45:07 CEST 2021 - mls@suse.de
 
 - fix misparsing of '&' in attributes with libxml2
@@ -6,6 +25,7 @@ Sat Sep 25 22:45:07 CEST 2021 - mls@suse.de
 - fix compatibility with Python 3.10
 - new SOLVER_EXCLUDEFROMWEAK job type
 - support for environments in comps parser
+- bump version to 0.7.20
 
 -------------------------------------------------------------------
 Fri Jul 30 11:43:29 UTC 2021 - Dominique Leuenberger <dimstar@opensuse.org>
index ee40d0a..51819fb 100644 (file)
@@ -70,6 +70,7 @@ SOLV_1.0 {
                pool_freewhatprovides;
                pool_get_flag;
                pool_get_rootdir;
+               pool_get_custom_vendorcheck;
                pool_id2evr;
                pool_id2langid;
                pool_id2rel;
@@ -255,6 +256,7 @@ SOLV_1.0 {
                repowriter_set_keyqueue;
                repowriter_set_repodatarange;
                repowriter_set_solvablerange;
+               repowriter_set_userdata;
                repowriter_write;
                selection_add;
                selection_filter;
@@ -288,6 +290,7 @@ SOLV_1.0 {
                solv_malloc;
                solv_malloc2;
                solv_oom;
+               solv_read_userdata;
                solv_realloc;
                solv_realloc2;
                solv_replacebadutf8;
@@ -304,6 +307,7 @@ SOLV_1.0 {
                solv_version_major;
                solv_version_minor;
                solv_version_patch;
+               solv_toolversion;
                solvable_add_deparray;
                solvable_add_idarray;
                solvable_add_poolstr_array;
index cba977b..a6be968 100644 (file)
@@ -767,6 +767,21 @@ addcycleedges(struct orderdata *od, Id *cycle, Queue *todo)
     }
 }
 
+static int
+share_cycle(struct orderdata *od, Id p1, Id p2)
+{
+  int i, seen = 0;
+  for (i = 0; i < od->cyclesdata.count; i++)
+    {
+      Id p = od->cyclesdata.elements[i];
+      if (p == 0)
+       seen = 0;
+      else if ((p == p1 || p == p2) && ++seen == 2)
+        return 1;
+    }
+  return 0;
+}
+
 void
 transaction_order(Transaction *trans, int flags)
 {
@@ -784,8 +799,9 @@ transaction_order(Transaction *trans, int flags)
   int oldcount;
   int start, now;
   Repo *lastrepo;
-  int lastmedia;
+  int lastmedia, lastte;
   Id *temedianr;
+  unsigned char *incycle;
 
   start = now = solv_timems(0);
   POOL_DEBUG(SOLV_DEBUG_STATS, "ordering transaction\n");
@@ -930,20 +946,30 @@ transaction_order(Transaction *trans, int flags)
   POOL_DEBUG(SOLV_DEBUG_STATS, "cycles broken: %d\n", od.ncycles);
   POOL_DEBUG(SOLV_DEBUG_STATS, "cycle breaking took %d ms\n", solv_timems(now));
 
-  now = solv_timems(0);
-  /* now go through all broken cycles and create cycle edges to help
-     the ordering */
-   for (i = od.cycles.count - 4; i >= 0; i -= 4)
-     {
-       if (od.cycles.elements[i + 2] >= TYPE_REQ)
-         addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
-     }
-   for (i = od.cycles.count - 4; i >= 0; i -= 4)
-     {
-       if (od.cycles.elements[i + 2] < TYPE_REQ)
-         addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
-     }
-  POOL_DEBUG(SOLV_DEBUG_STATS, "cycle edge creation took %d ms\n", solv_timems(now));
+  incycle = 0;
+  if (od.cycles.count)
+    {
+      now = solv_timems(0);
+      incycle = solv_calloc(numte, 1);
+      /* now go through all broken cycles and create cycle edges to help
+        the ordering */
+      for (i = od.cycles.count - 4; i >= 0; i -= 4)
+       {
+         if (od.cycles.elements[i + 2] >= TYPE_REQ)
+           addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
+       }
+      for (i = od.cycles.count - 4; i >= 0; i -= 4)
+       {
+         if (od.cycles.elements[i + 2] < TYPE_REQ)
+           addcycleedges(&od, od.cyclesdata.elements + od.cycles.elements[i], &todo);
+       }
+      for (i = od.cycles.count - 4; i >= 0; i -= 4)
+       {
+         for (j = od.cycles.elements[i]; od.cyclesdata.elements[j]; j++)
+           incycle[od.cyclesdata.elements[j]] = 1;
+       }
+      POOL_DEBUG(SOLV_DEBUG_STATS, "cycle edge creation took %d ms\n", solv_timems(now));
+    }
 
 #if 0
   dump_tes(&od);
@@ -1011,6 +1037,7 @@ transaction_order(Transaction *trans, int flags)
 
   lastrepo = 0;
   lastmedia = 0;
+  lastte = 0;
   temedianr = solv_calloc(numte, sizeof(Id));
   for (i = 1; i < numte; i++)
     {
@@ -1027,7 +1054,22 @@ transaction_order(Transaction *trans, int flags)
       if (uninstq.count)
        i = queue_shift(&uninstq);
       else if (samerepoq.count)
-       i = queue_shift(&samerepoq);
+       {
+         if (lastte && incycle && incycle[lastte])
+           {
+             /* last installed package was in a cycle, prefer packages from the same cycle */
+             for (j = 0; j < samerepoq.count; j++)
+               if (incycle[samerepoq.elements[j]] && share_cycle(&od, lastte, samerepoq.elements[j]))
+                 {
+                   /* yes, bring to front! */
+                   i = samerepoq.elements[j];
+                   queue_delete(&samerepoq, j);
+                   queue_unshift(&samerepoq, i);
+                   break;
+                 }
+           }
+         i = queue_shift(&samerepoq);
+       }
       else if (todo.count)
        {
          /* find next repo/media */
@@ -1060,6 +1102,9 @@ transaction_order(Transaction *trans, int flags)
 
       te = od.tes + i;
       queue_push(tr, te->p);
+      if (pool->solvables[te->p].repo != installed)
+       lastte = i;
+       
 #if 0
 printf("do %s [%d]\n", pool_solvid2str(pool, te->p), temedianr[i]);
 #endif
@@ -1083,6 +1128,7 @@ printf("free %s [%d]\n", pool_solvid2str(pool, te2->p), temedianr[od.invedgedata
        }
     }
   solv_free(temedianr);
+  solv_free(incycle);
   queue_free(&todo);
   queue_free(&samerepoq);
   queue_free(&uninstq);
index 0b4b9dd..54226e9 100644 (file)
@@ -2079,4 +2079,9 @@ pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(Pool *, Solvable *, S
   pool->custom_vendorcheck = vendorcheck;
 }
 
+int (*pool_get_custom_vendorcheck(Pool *pool))(Pool *, Solvable *, Solvable *)
+{
+  return pool->custom_vendorcheck;
+}
+
 /* EOF */
index aa173ea..935a326 100644 (file)
@@ -258,7 +258,7 @@ extern void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct s_Pool *, void
 extern void pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr);
 
 extern void pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(struct s_Pool *, Solvable *, Solvable *));
-
+extern int (*pool_get_custom_vendorcheck(Pool *pool))(struct s_Pool *, Solvable *, Solvable *);
 
 extern char *pool_alloctmpspace(Pool *pool, int len);
 extern void  pool_freetmpspace(Pool *pool, const char *space);
index e1f77b0..c69f375 100644 (file)
 #define SOLV_VERSION_6 6
 #define SOLV_VERSION_7 7
 #define SOLV_VERSION_8 8
+#define SOLV_VERSION_9 9
 
-#define SOLV_FLAG_PREFIX_POOL 4
-#define SOLV_FLAG_SIZE_BYTES  8
+#define SOLV_FLAG_PREFIX_POOL  4
+#define SOLV_FLAG_SIZE_BYTES   8
+#define SOLV_FLAG_USERDATA     16
+#define SOLV_FLAG_IDARRAYBLOCK 32
 
 struct s_Stringpool;
 typedef struct s_Stringpool Stringpool;
index adb84d8..83ee15b 100644 (file)
@@ -53,13 +53,13 @@ Id pool_vendor2mask(Pool *pool, Id vendor)
   vstr = pool_id2str(pool, vendor);
   m = 1;
   mask = 0;
-  for (v = pool->vendorclasses; ; v++)
+  for (v = pool->vendorclasses; ; )
     {
-      vs = *v;
+      vs = *v++;
       if (vs == 0)     /* end of block? */
        {
-         v++;
-         if (*v == 0)
+         vs = *v++;
+         if (vs == 0)
            break;
          if (m == (1 << 31))
            break;      /* sorry, out of bits */
@@ -69,7 +69,7 @@ Id pool_vendor2mask(Pool *pool, Id vendor)
        {
          if (*vs != '!')
            mask |= m;
-         while (v[1])  /* forward to next block */
+         while (*v)    /* forward to next block */
            v++;
        }
     }
index a6b9394..0bd48d4 100644 (file)
@@ -725,6 +725,12 @@ convertsolution(Solver *solv, Id why, Queue *solutionq)
       assert(solv->rules[why].p < 0);
       queue_push(solutionq, -solv->rules[why].p);
     }
+  if (why >= solv->strictrepopriorules && why < solv->strictrepopriorules_end)
+    {
+      queue_push(solutionq, SOLVER_SOLUTION_STRICTREPOPRIORITY);
+      assert(solv->rules[why].p < 0);
+      queue_push(solutionq, -solv->rules[why].p);
+    }
 }
 
 /*
@@ -1068,10 +1074,10 @@ solver_take_solution(Solver *solv, Id problem, Id solution, Queue *job)
  */
 
 static void
-findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp, Id *blkrp, Map *rseen)
+findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp, Id *blkrp, Id *scprp, Map *rseen)
 {
   Id rid, d;
-  Id lreqr, lconr, lsysr, ljobr, lblkr;
+  Id lreqr, lconr, lsysr, ljobr, lblkr, lscpr;
   Rule *r;
   Id jobassert = 0;
   int i, reqset = 0;   /* 0: unset, 1: installed, 2: jobassert, 3: assert */
@@ -1093,7 +1099,7 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp,
 
   /* the problem rules are somewhat ordered from "near to the problem" to
    * "near to the job" */
-  lreqr = lconr = lsysr = ljobr = lblkr = 0;
+  lreqr = lconr = lsysr = ljobr = lblkr = lscpr = 0;
   while ((rid = solv->learnt_pool.elements[idx++]) != 0)
     {
       assert(rid > 0);
@@ -1102,7 +1108,7 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp,
          if (MAPTST(rseen, rid - solv->learntrules))
            continue;
          MAPSET(rseen, rid - solv->learntrules);
-         findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr, &lblkr, rseen);
+         findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr, &lblkr, &lscpr, 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) || (rid >= solv->yumobsrules && rid < solv->yumobsrules_end))
        {
@@ -1119,6 +1125,11 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp,
          if (!*blkrp)
            *blkrp = rid;
        }
+      else if (rid >= solv->strictrepopriorules && rid < solv->strictrepopriorules_end)
+       {
+         if (!*scprp)
+           *scprp = rid;
+       }
       else
        {
          assert(rid < solv->pkgrules_end);
@@ -1148,7 +1159,6 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp,
                      Pool *pool = solv->pool;
                      Id op = -solv->rules[*reqrp].p;
                      if (op > 1 && pool->solvables[op].arch != pool->solvables[-r->p].arch &&
-                         pool->solvables[op].arch != pool->noarchid &&
                          pool->solvables[-r->p].arch != pool->noarchid)
                        continue;       /* different arch, skip */
                    }
@@ -1183,6 +1193,8 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp,
     *sysrp = lsysr;
   if (!*blkrp && lblkr)
     *blkrp = lblkr;
+  if (!*scprp && lscpr)
+    *scprp = lscpr;
 }
 
 /*
@@ -1197,12 +1209,12 @@ findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp,
 Id
 solver_findproblemrule(Solver *solv, Id problem)
 {
-  Id reqr, conr, sysr, jobr, blkr;
+  Id reqr, conr, sysr, jobr, blkr, srpr;
   Id idx = solv->problems.elements[2 * problem - 2];
   Map rseen;
-  reqr = conr = sysr = jobr = blkr = 0;
+  reqr = conr = sysr = jobr = blkr = srpr = 0;
   map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
-  findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr, &blkr, &rseen);
+  findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr, &blkr, &srpr, &rseen);
   map_free(&rseen);
   /* check if the request is about a not-installed package requiring a installed
    * package conflicting with the non-installed package. In that case return the conflict */
@@ -1232,6 +1244,8 @@ solver_findproblemrule(Solver *solv, Id problem)
     return conr;       /* some conflict */
   if (blkr)
     return blkr;       /* a blacklisted package */
+  if (srpr)
+    return srpr;       /* a strict repo priority */
   if (sysr)
     return sysr;       /* an update rule */
   if (jobr)
@@ -1350,6 +1364,8 @@ solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id targ
       return pool_tmpappend(pool, s, pool_dep2str(pool, dep), 0);
     case SOLVER_RULE_BLACK:
       return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " can only be installed by a direct request");
+    case SOLVER_RULE_STRICT_REPO_PRIORITY:
+      return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " is excluded by strict repo priority");
     case SOLVER_RULE_PKG_CONSTRAINS:
       s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), 0);
       s = pool_tmpappend(pool, s, " has constraint ", pool_dep2str(pool, dep));
@@ -1415,6 +1431,11 @@ solver_solutionelement2str(Solver *solv, Id p, Id rp)
     }
   else if (p > 0 && rp == 0)
     return pool_tmpjoin(pool, "allow deinstallation of ", pool_solvid2str(pool, p), 0);
+  else if (p == SOLVER_SOLUTION_STRICTREPOPRIORITY)
+    {
+      Solvable *s = pool->solvables + rp;
+      return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the repo priority");
+    }
   else if (p > 0 && rp > 0)
     {
       const char *sp = pool_solvid2str(pool, p);
index 45e4e7c..f9b1efc 100644 (file)
@@ -28,6 +28,7 @@ struct s_Solver;
 #define SOLVER_SOLUTION_BEST           (-3)
 #define SOLVER_SOLUTION_POOLJOB                (-4)
 #define SOLVER_SOLUTION_BLACK          (-5)
+#define SOLVER_SOLUTION_STRICTREPOPRIORITY     (-6)
 
 void solver_recordproblem(struct s_Solver *solv, Id rid);
 void solver_fixproblem(struct s_Solver *solv, Id rid);
index ffc09dc..441e94d 100644 (file)
@@ -37,9 +37,6 @@
 #if defined(LIBC_SCCS) && !defined(lint)
 static char sccsid[] = "@(#)qsort.c    8.1 (Berkeley) 6/4/93";
 #endif /* LIBC_SCCS and not lint */
-#ifndef _WIN32
-#include <sys/cdefs.h>
-#endif
 
 /* $FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.13.2.1.8.1 2010/12/21 17:10:29 kensmith Exp $ */
 
index 761d06e..629ac68 100644 (file)
@@ -178,6 +178,67 @@ read_idarray(Repodata *data, Id max, Id *map, Id *store, Id *end)
     }
 }
 
+static void
+read_idarray_block(Repodata *data, Id *block, int size)
+{
+  unsigned char buf[65536 + 5 + 1], *bp = buf, *oldbp;
+  unsigned char cbuf[65536 + 4];       /* can overshoot 4 bytes */
+  int left = 0;
+  int eof = 0;
+  int clen, flags;
+  Id x;
+  for (;;)
+    {
+      if (left < 5 && !eof)
+       {
+         if (left)
+           memmove(buf, bp, left);
+         bp = buf + left;
+         flags = read_u8(data);
+          clen = read_u8(data);
+          clen = (clen << 8) | read_u8(data);
+         if (data->error)
+           return;
+         if (!clen)
+           clen = 65536;
+         eof = flags & 0x80;
+         if (fread(flags & 0x40 ? cbuf : bp, clen, 1, data->fp) != 1)
+           {
+             data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "unexpected EOF");
+             return;
+           }
+         if (flags & 0x40)     /* compressed block */
+           clen = repopagestore_decompress_page(cbuf, clen, bp, 65536);
+         bp = buf;
+         left += clen;
+         bp[left] = 0;         /* make data_read_id return */
+         continue;
+       }
+      if (size < 2)
+       {
+         data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "idarray data overrun in block decompression");
+         return;
+       }
+      oldbp = bp;
+      bp = data_read_id(bp, &x);
+      left -= bp - oldbp;
+      if (left < 0)
+       {
+         data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "compression buffer underrun");
+         return;
+       }
+      size--;
+      *block++ = (x & 63) + (((unsigned int)x & ~127) >> 1) + 1;
+      if ((x & 64) == 0)
+       {
+          *block++ = 0;
+         if (--size == 0)
+           break;
+       }
+    }
+  if (left || !eof)
+    data->error = pool_error(data->repo->pool, SOLV_ERROR_EOF, "idarray size overrun in block decompression");
+}
 
 /*******************************************************************************
  * functions to extract data from memory
@@ -234,13 +295,18 @@ data_read_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *da
 }
 
 static unsigned char *
-data_read_rel_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *data, Id marker)
+data_read_rel_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *data, Id keyid)
 {
+  Id marker = 0;
   Id *store = *storep;
   Id old = 0;
   unsigned int x = 0;
   int c;
 
+  if (keyid == SOLVABLE_REQUIRES)
+    marker = SOLVABLE_PREREQMARKER;
+  if (keyid == SOLVABLE_PROVIDES)
+    marker = SOLVABLE_FILEMARKER;
   for (;;)
     {
       c = *dp++;
@@ -386,13 +452,45 @@ incore_map_idarray(Repodata *data, unsigned char *dp, Id *map, Id max)
          data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "incore_map_idarray: id too large (%u/%u)", id, max);
          break;
        }
-      id = map[id];
+      if (map)
+        id = map[id];
       incore_add_ideof(data, id, eof);
       if (eof)
        break;
     }
 }
 
+static int
+convert_idarray_block(Repodata *data, Id *block, Id *map, Id max)
+{
+  int cnt = 0;
+  int old = 0;
+  for (;;)
+    {
+      Id id = *block;
+      cnt++;
+      if (!id)
+       return cnt;
+      id--;    /* idarray_block unpacking added 1 */
+      if (id < 2 * old)
+       {
+         if (id & 1)
+           id = old - (id >> 1) - 1;
+         else
+           id = old + (id >> 1);
+       }
+      old = id;
+      if (id < 0 || (max && id >= max))
+       {
+         data->error = pool_error(data->repo->pool, SOLV_ERROR_ID_RANGE, "convert_idarray_block: id too large (%u/%u)", id, max);
+         return cnt;
+       }
+      if (map)
+        id = map[id];
+      *block++ = id;
+    }
+}
+
 #if 0
 static void
 incore_add_u32(Repodata *data, unsigned int x)
@@ -484,6 +582,8 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
   Repodata data;
 
   int extendstart = 0, extendend = 0;  /* set in case we're extending */
+  int idarray_block_offset = 0;
+  int idarray_block_end = 0;
 
   now = solv_timems(0);
 
@@ -514,6 +614,7 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
   switch (solvversion)
     {
       case SOLV_VERSION_8:
+      case SOLV_VERSION_9:
        break;
       default:
         return pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported SOLV version");
@@ -552,6 +653,18 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
          return pool_error(pool, SOLV_ERROR_CORRUPT, "main repository contains holes, cannot extend");
     }
 
+  /*******  Part 0: skip optional userdata ******************************/
+
+  if (solvflags & SOLV_FLAG_USERDATA)
+    {
+      unsigned int userdatalen = read_u32(&data);
+      if (userdatalen >= 65536)
+        return pool_error(pool, SOLV_ERROR_CORRUPT, "illegal userdata length");
+      while (userdatalen--)
+       if (getc(data.fp) == EOF)
+         return pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
+    }
+
   /*******  Part 1: string IDs  *****************************************/
 
   sizeid = read_u32(&data);           /* size of string space */
@@ -849,6 +962,9 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
   /* keys start at 1 */
   for (i = 1; i < numkeys; i++)
     {
+      Repokey *key;
+      if (data.error)
+       break;
       id = read_id(&data, numid);
       if (idmap)
        id = idmap[id];
@@ -864,42 +980,51 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
          data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported data type '%s'", pool_id2str(pool, type));
          type = REPOKEY_TYPE_VOID;
        }
-      keys[i].name = id;
-      keys[i].type = type;
-      keys[i].size = read_id(&data, keys[i].type == REPOKEY_TYPE_CONSTANTID ? numid + numrel : 0);
-      keys[i].storage = read_id(&data, 0);
+      key = keys + i;
+      key->name = id;
+      key->type = type;
+      key->size = read_id(&data, type == REPOKEY_TYPE_CONSTANTID ? numid + numrel : 0);
+      key->storage = read_id(&data, 0);
       /* old versions used SOLVABLE for main solvable data */
-      if (keys[i].storage == KEY_STORAGE_SOLVABLE)
-       keys[i].storage = KEY_STORAGE_INCORE;
-      if (keys[i].storage != KEY_STORAGE_INCORE && keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
-       data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported storage type %d", keys[i].storage);
+      if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_VERTICAL_OFFSET && key->storage != KEY_STORAGE_SOLVABLE && key->storage != KEY_STORAGE_IDARRAYBLOCK)
+       data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported storage type %d", key->storage);
+      /* change KEY_STORAGE_SOLVABLE to KEY_STORAGE_INCORE */
+      if (key->storage == KEY_STORAGE_SOLVABLE)
+       key->storage = KEY_STORAGE_INCORE;
+      if (key->storage == KEY_STORAGE_IDARRAYBLOCK && type != REPOKEY_TYPE_IDARRAY)
+       data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "typr %d does not support idarrayblock storage\n", type);
       if (id >= SOLVABLE_NAME && id <= RPM_RPMDBID)
        {
-         if (keys[i].storage != KEY_STORAGE_INCORE)
-           data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "main solvable data must use incore storage %d", keys[i].storage);
-         keys[i].storage = KEY_STORAGE_SOLVABLE;
+         /* we will put those directly into the storable */
+         if (key->storage != KEY_STORAGE_INCORE && key->storage != KEY_STORAGE_IDARRAYBLOCK)
+           data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "main solvable data must use incore storage, not %d", key->storage);
        }
-      if ((type == REPOKEY_TYPE_FIXARRAY || type == REPOKEY_TYPE_FLEXARRAY) && keys[i].storage != KEY_STORAGE_INCORE)
+      if ((type == REPOKEY_TYPE_FIXARRAY || type == REPOKEY_TYPE_FLEXARRAY) && key->storage != KEY_STORAGE_INCORE)
        data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "flex/fixarrays must use incore storage\n");
       /* cannot handle rel idarrays in incore/vertical */
-      if (type == REPOKEY_TYPE_REL_IDARRAY && keys[i].storage != KEY_STORAGE_SOLVABLE)
-       data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "type REL_IDARRAY is only supported for STORAGE_SOLVABLE");
+      if (type == REPOKEY_TYPE_REL_IDARRAY && keys[i].storage != KEY_STORAGE_INCORE)
+       data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "type REL_IDARRAY is only supported for STORAGE_INCORE");
       /* cannot handle mapped ids in vertical */
-      if (!(flags & REPO_LOCALPOOL) && keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET && (type == REPOKEY_TYPE_ID || type == REPOKEY_TYPE_IDARRAY))
+      if (!(flags & REPO_LOCALPOOL) && key->storage == KEY_STORAGE_VERTICAL_OFFSET && (type == REPOKEY_TYPE_ID || type == REPOKEY_TYPE_IDARRAY))
        data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "mapped ids are not supported for STORAGE_VERTICAL_OFFSET");
 
-      if (keys[i].type == REPOKEY_TYPE_CONSTANTID && idmap)
-       keys[i].size = idmap[keys[i].size];
+      if (type == REPOKEY_TYPE_CONSTANTID && idmap)
+       key->size = idmap[key->size];
 #if 0
-      fprintf(stderr, "key %d %s %s %d %d\n", i, pool_id2str(pool,id), pool_id2str(pool, keys[i].type),
-               keys[i].size, keys[i].storage);
+      fprintf(stderr, "key %d %s %s %d %d\n", i, pool_id2str(pool, id), pool_id2str(pool, type), key->size, key->storage);
 #endif
     }
 
   have_incoredata = 0;
   for (i = 1; i < numkeys; i++)
-    if (keys[i].storage == KEY_STORAGE_INCORE || keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
+    {
+      id = keys[i].name;
+      if (id == REPOSITORY_SOLVABLES && keys[i].type == REPOKEY_TYPE_FLEXARRAY)
+       continue;
+      if (id >= SOLVABLE_NAME && id <= RPM_RPMDBID)
+       continue;
       have_incoredata = 1;
+    }
 
   data.keys = keys;
   data.nkeys = numkeys;
@@ -933,7 +1058,20 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
   data.schemadata = schemadata;
   data.schemadatalen = schemadataend - data.schemadata;
 
-  /*******  Part 6: Data ********************************************/
+  /*******  Part 6: Idarray block ***********************************/
+  if ((solvflags & SOLV_FLAG_IDARRAYBLOCK) != 0)
+    {
+      unsigned int idarray_block_size = read_id(&data, 0x30000000);
+      repo_reserve_ids(repo, 0, idarray_block_size + 1);
+      idarray_block_offset = repo->idarraysize;
+      repo->idarraysize += idarray_block_size;
+      idarray_block_end = repo->idarraysize;
+      repo->idarraydata[repo->idarraysize++] = 0;
+      if (idarray_block_size)
+        read_idarray_block(&data, repo->idarraydata + idarray_block_offset, idarray_block_size);
+    }
+
+  /*******  Part 7: Data ********************************************/
 
   idarraydatap = idarraydataend = 0;
   size_idarray = 0;
@@ -955,7 +1093,8 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
     l = allsize;
   if (!l || fread(buf, l, 1, data.fp) != 1)
     {
-      data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
+      if (!data.error)
+        data.error = pool_error(pool, SOLV_ERROR_EOF, "unexpected EOF");
       id = 0;
     }
   else
@@ -1090,31 +1229,49 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
          break;
        case REPOKEY_TYPE_IDARRAY:
        case REPOKEY_TYPE_REL_IDARRAY:
-         if (!s || id < INTERESTED_START || id > INTERESTED_END)
+         if (keys[key].storage == KEY_STORAGE_IDARRAYBLOCK)
            {
-             dps = dp;
-             dp = data_skip(dp, REPOKEY_TYPE_IDARRAY);
-             if (keys[key].storage != KEY_STORAGE_INCORE)
-               break;
-             if (idmap)
-               incore_map_idarray(&data, dps, idmap, numid + numrel);
-             else
-               incore_add_blob(&data, dps, dp - dps);
-             break;
+             int cnt = convert_idarray_block(&data, repo->idarraydata + idarray_block_offset, idmap, numid + numrel);
+             ido = idarray_block_offset;
+             idarray_block_offset += cnt;
+             if (idarray_block_offset > idarray_block_end)
+               {
+                 data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "idarray block underflow");
+                 idarray_block_offset = idarray_block_end;
+                 break;
+               }
+             if (!s || id < INTERESTED_START || id > INTERESTED_END)
+               {
+                 do
+                   incore_add_ideof(&data, repo->idarraydata[ido++], --cnt > 1 ? 0 : 1);
+                 while (cnt > 1);
+                 break;
+               }
            }
-         ido = idarraydatap - repo->idarraydata;
-         if (keys[key].type == REPOKEY_TYPE_IDARRAY)
-           dp = data_read_idarray(dp, &idarraydatap, idmap, numid + numrel, &data);
-         else if (id == SOLVABLE_REQUIRES)
-           dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, SOLVABLE_PREREQMARKER);
-         else if (id == SOLVABLE_PROVIDES)
-           dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, SOLVABLE_FILEMARKER);
          else
-           dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, 0);
-         if (idarraydatap > idarraydataend)
            {
-             data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "idarray overflow");
-             break;
+             if (!s || id < INTERESTED_START || id > INTERESTED_END)
+               {
+                 dps = dp;
+                 dp = data_skip(dp, REPOKEY_TYPE_IDARRAY);
+                 if (keys[key].storage != KEY_STORAGE_INCORE)
+                   break;
+                 if (idmap)
+                   incore_map_idarray(&data, dps, idmap, numid + numrel);
+                 else
+                   incore_add_blob(&data, dps, dp - dps);
+                 break;
+               }
+             ido = idarraydatap - repo->idarraydata;
+             if (keys[key].type == REPOKEY_TYPE_IDARRAY)
+               dp = data_read_idarray(dp, &idarraydatap, idmap, numid + numrel, &data);
+             else
+               dp = data_read_rel_idarray(dp, &idarraydatap, idmap, numid + numrel, &data, id);
+             if (idarraydatap > idarraydataend)
+               {
+                 data.error = pool_error(pool, SOLV_ERROR_OVERFLOW, "idarray overflow");
+                 break;
+               }
            }
          if (id == SOLVABLE_PROVIDES)
            s->provides = ido;
@@ -1216,9 +1373,7 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
              incore_add_sizek(&data, (unsigned int)id);
              break;
            }
-         /* FALLTHROUGH */
-       default:
-         if (id == RPM_RPMDBID && s && keys[key].type == REPOKEY_TYPE_NUM)
+         if (s && id == RPM_RPMDBID)
            {
              dp = data_read_id(dp, &id);
              if (!repo->rpmdbid)
@@ -1226,6 +1381,8 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
              repo->rpmdbid[(s - pool->solvables) - repo->start] = id;
              break;
            }
+         /* FALLTHROUGH */
+       default:
          dps = dp;
          dp = data_skip(dp, keys[key].type);
          if (keys[key].storage == KEY_STORAGE_INCORE)
@@ -1241,6 +1398,8 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
     {
       if (dp > bufend)
        data.error = pool_error(pool, SOLV_ERROR_EOF, "buffer overrun");
+      else if (idarray_block_offset != idarray_block_end)
+       data.error = pool_error(pool, SOLV_ERROR_EOF, "unconsumed idarray block entries");
     }
   solv_free(buf);
 
@@ -1263,10 +1422,16 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
     }
   solv_free(idmap);
 
-  /* fixup the special idarray type */
+  /* fixup key data */
   for (i = 1; i < numkeys; i++)
-    if (keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
-      keys[i].type = REPOKEY_TYPE_IDARRAY;
+    {
+      if (keys[i].type == REPOKEY_TYPE_REL_IDARRAY)
+        keys[i].type = REPOKEY_TYPE_IDARRAY;
+      if (keys[i].storage == KEY_STORAGE_IDARRAYBLOCK)
+        keys[i].storage = KEY_STORAGE_INCORE;
+      if (keys[i].name >= SOLVABLE_NAME && keys[i].name <= RPM_RPMDBID)
+        keys[i].storage = KEY_STORAGE_SOLVABLE;
+    }
 
   for (i = 1; i < numkeys; i++)
     if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET && keys[i].size)
@@ -1353,3 +1518,44 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
   return 0;
 }
 
+int
+solv_read_userdata(FILE *fp, unsigned char **datap, int *lenp)
+{
+  unsigned char d[4 * 10], *ud = 0;
+  unsigned int n;
+  if (fread(d, sizeof(d), 1, fp) != 1)
+    return SOLV_ERROR_EOF;
+  n = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
+  if (n != ('S' << 24 | 'O' << 16 | 'L' << 8 | 'V'))
+    return SOLV_ERROR_NOT_SOLV;
+  n = d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7];
+  switch(n)
+    {
+    case SOLV_VERSION_8:
+    case SOLV_VERSION_9:
+      break;
+    default:
+      return SOLV_ERROR_UNSUPPORTED;
+    }
+  n = d[32] << 24 | d[33] << 16 | d[34] << 8 | d[35];
+  if (!(n & SOLV_FLAG_USERDATA))
+    n = 0;
+  else
+    n = d[36] << 24 | d[37] << 16 | d[38] << 8 | d[39];
+  if (n >= 65536)
+    return SOLV_ERROR_CORRUPT;
+  if (n)
+    {
+      ud = solv_malloc(n + 1);
+      if (fread(ud, n, 1, fp) != 1)
+       {
+         solv_free(ud);
+         return SOLV_ERROR_EOF;
+       }
+      ud[n] = 0;
+    }
+  *datap = ud;
+  if (lenp)
+    *lenp = (int)n;
+  return 0;
+}
index 0c66394..57bf177 100644 (file)
@@ -23,6 +23,7 @@ extern "C" {
 #endif
 
 extern int repo_add_solv(Repo *repo, FILE *fp, int flags);
+extern int solv_read_userdata(FILE *fp, unsigned char **datap, int *lenp);
 
 #define SOLV_ADD_NO_STUBS      (1 << 8)
 
index af4e759..b3a6bbc 100644 (file)
@@ -29,6 +29,9 @@
 #include "repo_write.h"
 #include "repopage.h"
 
+#undef USE_IDARRAYBLOCK
+#define USE_REL_IDARRAY
+
 /*------------------------------------------------------------------*/
 /* Id map optimizations */
 
@@ -160,6 +163,36 @@ write_blob(Repodata *data, void *blob, int len)
     }
 }
 
+static void
+write_compressed_blob(Repodata *data, void *blob, int len)
+{
+  unsigned char cpage[65536];
+  if (data->error)
+    return;
+  while (len > 0)
+    {
+      int chunk = len > sizeof(cpage) ? sizeof(cpage) : len;
+      int flag = (chunk == len ? 0x80 : 0x00);
+      int clen = repopagestore_compress_page(blob, chunk, cpage, sizeof(cpage) - 1);
+      if (!clen)
+       {
+         write_u8(data, flag);
+         write_u8(data, chunk >> 8);
+         write_u8(data, chunk);
+         write_blob(data, blob, chunk);
+       }
+      else
+       {
+         write_u8(data, flag | 0x40);
+         write_u8(data, clen >> 8);
+         write_u8(data, clen);
+         write_blob(data, cpage, clen);
+       }
+      blob += chunk;
+      len -= chunk;
+    }
+}
+
 /*
  * Id
  */
@@ -350,7 +383,6 @@ data_addid64(struct extdata *xd, unsigned int x, unsigned int hx)
     data_addid(xd, (Id)x);
 }
 
-#define USE_REL_IDARRAY
 #ifdef USE_REL_IDARRAY
 
 static int
@@ -368,11 +400,9 @@ data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marke
   Id lids[64], *sids;
   Id id, old;
 
-  if (!ids)
-    return;
-  if (!*ids)
+  if (!ids || !*ids)
     {
-      data_addid(xd, 0);
+      data_addideof(xd, 0, 1);
       return;
     }
   for (len = 0; len < 64 && ids[len]; len++)
@@ -449,13 +479,41 @@ data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marke
 
 #else
 
+#ifdef USE_IDARRAYBLOCK
+
+static void
+data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
+{
+  Id id;
+  Id last = 0, tmp;
+  if (!ids || !*ids)
+    {
+      data_addideof(xd, 0, 1);
+      return;
+    }
+  while ((id = *ids++) != 0)
+    {
+      if (needid)
+        id = needid[NEEDIDOFF(id)].need;
+      tmp = id;
+      if (id < last)
+       id = (last - id) * 2 - 1;       /* [1, 2 * last - 1] odd */
+      else if (id < 2 * last)
+       id = (id - last) * 2;           /* [0, 2 * last - 2] even */
+      last = tmp;
+      data_addideof(xd, id, *ids ? 0 : 1);
+    }
+}
+
+#else
+
 static void
 data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
 {
   Id id;
   if (!ids || !*ids)
     {
-      data_addid(xd, 0);
+      data_addideof(xd, 0, 1);
       return;
     }
   while ((id = *ids++) != 0)
@@ -468,6 +526,8 @@ data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marke
 
 #endif
 
+#endif
+
 static inline void
 data_addblob(struct extdata *xd, unsigned char *blob, int len)
 {
@@ -845,6 +905,12 @@ collect_data_solvable(struct cbdata *cbdata, Solvable *s, Id *keymap)
   Repo *repo = s->repo;
   Pool *pool = repo->pool;
   struct extdata *xd = cbdata->extdata;
+#ifdef USE_IDARRAYBLOCK
+  struct extdata *xda = xd + cbdata->target->nkeys;    /* idarray block */
+#else
+  struct extdata *xda = xd;
+#endif
+
   NeedId *needid = cbdata->needid;
   Id *idarraydata = repo->idarraydata;
 
@@ -857,21 +923,21 @@ collect_data_solvable(struct cbdata *cbdata, Solvable *s, Id *keymap)
   if (s->vendor && keymap[SOLVABLE_VENDOR])
     data_addid(xd, needid[s->vendor].need);
   if (s->provides && keymap[SOLVABLE_PROVIDES])
-    data_adddepids(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
+    data_adddepids(xda, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
   if (s->obsoletes && keymap[SOLVABLE_OBSOLETES])
-    data_adddepids(xd, pool, needid, idarraydata + s->obsoletes, 0);
+    data_adddepids(xda, pool, needid, idarraydata + s->obsoletes, 0);
   if (s->conflicts && keymap[SOLVABLE_CONFLICTS])
-    data_adddepids(xd, pool, needid, idarraydata + s->conflicts, 0);
+    data_adddepids(xda, pool, needid, idarraydata + s->conflicts, 0);
   if (s->requires && keymap[SOLVABLE_REQUIRES])
-    data_adddepids(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
+    data_adddepids(xda, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
   if (s->recommends && keymap[SOLVABLE_RECOMMENDS])
-    data_adddepids(xd, pool, needid, idarraydata + s->recommends, 0);
+    data_adddepids(xda, pool, needid, idarraydata + s->recommends, 0);
   if (s->suggests && keymap[SOLVABLE_SUGGESTS])
-    data_adddepids(xd, pool, needid, idarraydata + s->suggests, 0);
+    data_adddepids(xda, pool, needid, idarraydata + s->suggests, 0);
   if (s->supplements && keymap[SOLVABLE_SUPPLEMENTS])
-    data_adddepids(xd, pool, needid, idarraydata + s->supplements, 0);
+    data_adddepids(xda, pool, needid, idarraydata + s->supplements, 0);
   if (s->enhances && keymap[SOLVABLE_ENHANCES])
-    data_adddepids(xd, pool, needid, idarraydata + s->enhances, 0);
+    data_adddepids(xda, pool, needid, idarraydata + s->enhances, 0);
   if (repo->rpmdbid && keymap[RPM_RPMDBID])
     data_addid(xd, repo->rpmdbid[(s - pool->solvables) - repo->start]);
 }
@@ -1071,6 +1137,7 @@ repowriter_create(Repo *repo)
 Repowriter *
 repowriter_free(Repowriter *writer)
 {
+  solv_free(writer->userdata);
   return solv_free(writer);
 }
 
@@ -1107,6 +1174,17 @@ repowriter_set_solvablerange(Repowriter *writer, int solvablestart, int solvable
   writer->solvableend = solvableend;
 }
 
+void
+repowriter_set_userdata(Repowriter *writer, const void *data, int len)
+{
+  writer->userdata = solv_free(writer->userdata);
+  writer->userdatalen = 0;
+  if (len < 0 || len >= 65536)
+    return;
+  writer->userdata = len ? solv_memdup(data, len) : 0;
+  writer->userdatalen = len;
+}
+
 /*
  * the code works the following way:
  *
@@ -1205,13 +1283,13 @@ repowriter_write(Repowriter *writer, FILE *fp)
          if (i < SOLVABLE_PROVIDES)
            keyd.type = REPOKEY_TYPE_ID;
          else if (i < RPM_RPMDBID)
-#ifdef USE_REL_IDARRAY
-           keyd.type = REPOKEY_TYPE_REL_IDARRAY;
-#else
            keyd.type = REPOKEY_TYPE_IDARRAY;
-#endif
          else
            keyd.type = REPOKEY_TYPE_NUM;
+#ifdef USE_REL_IDARRAY
+         if (keyd.type == REPOKEY_TYPE_IDARRAY)
+           keyd.type = REPOKEY_TYPE_REL_IDARRAY;
+#endif
          keyd.size = 0;
          keyd.storage = KEY_STORAGE_SOLVABLE;
          if (writer->keyfilter)
@@ -1221,6 +1299,10 @@ repowriter_write(Repowriter *writer, FILE *fp)
                continue;
              keyd.storage = KEY_STORAGE_SOLVABLE;
            }
+#ifdef USE_IDARRAYBLOCK
+         if (keyd.type == REPOKEY_TYPE_IDARRAY)
+           keyd.storage = KEY_STORAGE_IDARRAYBLOCK;
+#endif
          poolusage = 1;
          clonepool = 1;
          keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
@@ -1301,6 +1383,8 @@ repowriter_write(Repowriter *writer, FILE *fp)
                      keymap[n] = 0;
                      continue;
                    }
+                 if (keyd.storage != KEY_STORAGE_VERTICAL_OFFSET)
+                   keyd.storage = KEY_STORAGE_INCORE;          /* do not mess with us */
                }
              if (data->state != REPODATA_STUB)
                id = repodata_key2id(&target, &keyd, 1);
@@ -1829,11 +1913,12 @@ for (i = 1; i < target.nkeys; i++)
 
   /* collect all data
    * we use extdata[0] for incore data and extdata[keyid] for vertical data
+   * we use extdata[nkeys] for the idarray_block data
    *
    * this must match the code above that creates the schema data!
    */
 
-  cbdata.extdata = solv_calloc(target.nkeys, sizeof(struct extdata));
+  cbdata.extdata = solv_calloc(target.nkeys + 1, sizeof(struct extdata));
 
   xd = cbdata.extdata;
   cbdata.current_sub = 0;
@@ -1895,11 +1980,20 @@ for (i = 1; i < target.nkeys; i++)
   target.fp = fp;
 
   /* write header */
+  solv_flags = 0;
+  solv_flags |= SOLV_FLAG_PREFIX_POOL;
+  solv_flags |= SOLV_FLAG_SIZE_BYTES;
+  if (writer->userdatalen)
+    solv_flags |= SOLV_FLAG_USERDATA;
+  if (cbdata.extdata[target.nkeys].len)
+    solv_flags |= SOLV_FLAG_IDARRAYBLOCK;
 
   /* write file header */
   write_u32(&target, 'S' << 24 | 'O' << 16 | 'L' << 8 | 'V');
-  write_u32(&target, SOLV_VERSION_8);
-
+  if ((solv_flags & (SOLV_FLAG_USERDATA | SOLV_FLAG_IDARRAYBLOCK)) != 0)
+    write_u32(&target, SOLV_VERSION_9);
+  else
+    write_u32(&target, SOLV_VERSION_8);
 
   /* write counts */
   write_u32(&target, nstrings);
@@ -1908,11 +2002,15 @@ for (i = 1; i < target.nkeys; i++)
   write_u32(&target, anysolvableused ? nsolvables : 0);
   write_u32(&target, target.nkeys);
   write_u32(&target, target.nschemata);
-  solv_flags = 0;
-  solv_flags |= SOLV_FLAG_PREFIX_POOL;
-  solv_flags |= SOLV_FLAG_SIZE_BYTES;
   write_u32(&target, solv_flags);
 
+  /* write userdata */
+  if ((solv_flags & SOLV_FLAG_USERDATA) != 0)
+    {
+      write_u32(&target, writer->userdatalen);
+      write_blob(&target, writer->userdata, writer->userdatalen);
+    }
+
   if (nstrings)
     {
       /*
@@ -1951,8 +2049,8 @@ for (i = 1; i < target.nkeys; i++)
     }
   else
     {
-      write_u32(&target, 0);
-      write_u32(&target, 0);
+      write_u32(&target, 0);   /* unpacked size */
+      write_u32(&target, 0);   /* compressed size */
     }
 
   /*
@@ -2004,14 +2102,36 @@ for (i = 1; i < target.nkeys; i++)
   for (i = 1; i < target.nschemata; i++)
     write_idarray(&target, pool, 0, repodata_id2schema(&target, i));
 
+  /* write idarray_block data if not empty */
+  if (cbdata.extdata[target.nkeys].len)
+    {
+      unsigned int cnt = 0;
+      unsigned char *b;
+      unsigned int l;
+       
+      xd = cbdata.extdata + target.nkeys;
+      /* calculate number of entries */
+      for (l = xd->len, b = xd->buf; l--;)
+       {
+         unsigned char x = *b++;
+         if ((x & 0x80) == 0)
+           cnt += (x & 0x40) ? 1 : 2;
+       }
+      write_id(&target, cnt);
+      if (cnt)
+        write_compressed_blob(&target, xd->buf, xd->len);
+      solv_free(xd->buf);
+    }
+
   /*
    * write incore data
    */
+  xd = cbdata.extdata;
   write_id(&target, cbdata.maxdata);
-  write_id(&target, cbdata.extdata[0].len);
-  if (cbdata.extdata[0].len)
-    write_blob(&target, cbdata.extdata[0].buf, cbdata.extdata[0].len);
-  solv_free(cbdata.extdata[0].buf);
+  write_id(&target, xd->len);
+  if (xd->len)
+    write_blob(&target, xd->buf, xd->len);
+  solv_free(xd->buf);
 
   /*
    * write vertical data if we have any
index 3471670..7734b01 100644 (file)
@@ -32,6 +32,8 @@ typedef struct s_Repowriter {
   int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata);
   void *kfdata;
   Queue *keyq;
+  void *userdata;
+  int userdatalen;
 } Repowriter;
 
 /* repowriter flags */
@@ -46,6 +48,7 @@ void repowriter_set_keyfilter(Repowriter *writer, int (*keyfilter)(Repo *repo, R
 void repowriter_set_keyqueue(Repowriter *writer, Queue *keyq);
 void repowriter_set_repodatarange(Repowriter *writer, int repodatastart, int repodataend);
 void repowriter_set_solvablerange(Repowriter *writer, int solvablestart, int solvableend);
+void repowriter_set_userdata(Repowriter *writer, const void *data, int len);
 int repowriter_write(Repowriter *writer, FILE *fp);
 
 /* convenience functions */
index 7dd5259..2504f2a 100644 (file)
@@ -48,6 +48,7 @@ typedef struct s_Repokey {
 #define KEY_STORAGE_SOLVABLE            1
 #define KEY_STORAGE_INCORE              2
 #define KEY_STORAGE_VERTICAL_OFFSET     3
+#define KEY_STORAGE_IDARRAYBLOCK       4
 
 #ifdef LIBSOLV_INTERNAL
 struct dircache;
index 9e9694f..77c7fcc 100644 (file)
@@ -105,6 +105,8 @@ compress_buf(const unsigned char *in, unsigned int in_len,
   unsigned int litofs = 0;
   memset(htab, -1, sizeof (htab));
   memset(hnext, -1, sizeof (hnext));
+  if (in_len > BLOCK_SIZE)
+    return 0;                  /* Hey! */
   while (io + 2 < in_len)
     {
       /* Search for a match of the string starting at IN, we have at
@@ -119,84 +121,53 @@ compress_buf(const unsigned char *in, unsigned int in_len,
       mlen = 0;
       mofs = 0;
 
-      for (tries = 0; try != -1 && tries < 12; tries++)
+      for (tries = 0; try != (Ref)-1 && tries < 12; tries++, try = hnext[try])
         {
-         if (try < io
-             && in[try] == in[io] && in[try + 1] == in[io + 1])
+         if (in[try] == in[io] && in[try + 1] == in[io + 1])
            {
              mlen = 2;
              mofs = (io - try) - 1;
              break;
            }
-         try = hnext[try];
        }
-      for (; try != -1 && tries < 12; tries++)
+      for (; try != (Ref)-1 && tries < 12; tries++, try = hnext[try])
        {
-         /* assert(mlen >= 2); */
          /* assert(io + mlen < in_len); */
          /* Try a match starting from [io] with the strings at [try].
-            That's only sensible if TRY actually is before IO (can happen
-            with uninit hash table).  If we have a previous match already
-            we're only going to take the new one if it's longer, hence
-            check the potentially last character.  */
-         if (try < io && in[try + mlen] == in[io + mlen])
+            If we have a previous match already we're only going to take
+             the new one if it's longer, hence check the potentially last
+             character first.  */
+         if (in[try + mlen] == in[io + mlen] && !memcmp(in + try, in + io, mlen))
            {
-             unsigned int this_len, this_ofs;
-             if (memcmp(in + try, in + io, mlen))
-               goto no_match;
-             this_len = mlen + 1;
+             /* Found a longer match */
+             mlen++;
              /* Now try extending the match by more characters.  */
-             for (;
-                  io + this_len < in_len
-                  && in[try + this_len] == in[io + this_len]; this_len++)
-               ;
-#if 0
-             unsigned int testi;
-             for (testi = 0; testi < this_len; testi++)
-               assert(in[try + testi] == in[io + testi]);
-#endif
-             this_ofs = (io - try) - 1;
-             /*if (this_ofs > 65535)
-                goto no_match; */
-#if 0
-             assert(this_len >= 2);
-             assert(this_len >= mlen);
-             assert(this_len > mlen || (this_len == mlen && this_ofs > mofs));
-#endif
-             mlen = this_len, mofs = this_ofs;
+             while (io + mlen < in_len && in[try + mlen] == in[io + mlen])
+               mlen++;
+             mofs = (io - try) - 1;
              /* If our match extends up to the end of input, no next
                 match can become better.  This is not just an
-                optimization, it establishes a loop invariant
+                optimization, it establishes the loop invariant
                 (io + mlen < in_len).  */
              if (io + mlen >= in_len)
-               goto match_done;
+               break;
            }
-       no_match:
-         try = hnext[try];
-         /*if (io - try - 1 >= 65536)
-           break;*/
        }
-
-match_done:
+      if (mlen < 3)
+       mlen = 0;
       if (mlen)
        {
          /*fprintf(stderr, "%d %d\n", mlen, mofs);*/
-         if (mlen == 2 && (litofs || mofs >= 1024))
-           mlen = 0;
-         /*else if (mofs >= 65536)
-           mlen = 0;*/
-         else if (mofs >= 65536)
+#if BLOCK_SIZE > 65536
+         if (mofs >= 65536)
            {
              if (mlen >= 2048 + 5)
                mlen = 2047 + 5;
              else if (mlen < 5)
                mlen = 0;
            }
-         else if (mlen < 3)
-           mlen = 0;
-         /*else if (mlen >= 4096 + 19)
-           mlen = 4095 + 19;*/
-         else if (mlen >= 2048 + 19)
+#endif
+         if (mlen >= 2048 + 19)
            mlen = 2047 + 19;
          /* Skip this match if the next character would deliver a better one,
             but only do this if we have the chance to really extend the
@@ -210,16 +181,11 @@ match_done:
              hval = (hval ^ (hval << 5) ^ (hval >> 5)) - hval * 5;
              hval = hval & (HS - 1);
              try = htab[hval];
-             if (try < io + 1
-                 && in[try] == in[io + 1] && in[try + 1] == in[io + 2])
+             if (try != (Ref)-1 && in[try] == in[io + 1] && in[try + 1] == in[io + 2])
                {
-                 unsigned int this_len;
-                 this_len = 2;
-                 for (;
-                      io + 1 + this_len < in_len
-                      && in[try + this_len] == in[io + 1 + this_len];
-                      this_len++)
-                   ;
+                 unsigned int this_len = 2;
+                 while (io + 1 + this_len < in_len && in[try + this_len] == in[io + 1 + this_len])
+                   this_len++;
                  if (this_len >= mlen)
                    mlen = 0;
                }
@@ -227,12 +193,14 @@ match_done:
        }
       if (!mlen)
        {
+         /* Found no match, start/extend literal */
          if (!litofs)
            litofs = io + 1;
          io++;
        }
       else
        {
+         /* Found a match. First dump literals */
          if (litofs)
            {
              unsigned litlen;
@@ -303,6 +271,9 @@ match_done:
            }
          else if (mofs >= 65536)
            {
+#if BLOCK_SIZE <= 65536
+             return 0;
+#else
              assert(mlen >= 5 && mlen < 2048 + 5);
              if (oo + 5 >= out_len)
                return 0;
@@ -311,6 +282,7 @@ match_done:
              out[oo++] = mofs & 0xff;
              out[oo++] = (mofs >> 8) & 0xff;
              out[oo++] = mofs >> 16;
+#endif
            }
          else if (mlen >= 3 && mlen <= 18)
            {
@@ -350,7 +322,7 @@ match_done:
                  htab[hval] = io;
                }
              io++;
-           };
+           }
        }
     }
   /* We might have some characters left.  */
@@ -466,14 +438,12 @@ unchecked_decompress_buf(const unsigned char *in, unsigned int in_len,
          {
            o = in[0] | (in[1] << 8);
            in += 2;
-           first = first & 31;
-           first += 3;
+           first = (first & 15) + 3;
            break;
          }
        case 15:
-         /* f1 1111llll <8o> <8o> <8l> */
-         /* f2 11110lll <8o> <8o> <8l> */
-         /* g 11111lll <8o> <8o> <8o> <8l> */
+         /* f2 11110lll <8l> <8o> <8o> */
+         /* g  11111lll <8l> <8o> <8o> <8o> */
          {
            first = first & 15;
            if (first >= 8)
@@ -557,6 +527,77 @@ unchecked_decompress_buf(const unsigned char *in, unsigned int in_len,
   return out - orig_out;
 }
 
+static unsigned int
+check_decompress_buf(const unsigned char *in, unsigned int in_len)
+{
+  unsigned int out_len = 0;
+  const unsigned char *in_end = in + in_len;
+  while (in < in_end)
+    {
+      unsigned int first = *in++;
+      int o;
+      switch (first >> 4)
+       {
+       default:
+         /* This default case can't happen, but GCCs VRP is not strong
+            enough to see this, so make this explicitely not fall to
+            the end of the switch, so that we don't have to initialize
+            o above.  */
+         continue;
+       case 0: case 1:
+       case 2: case 3:
+       case 4: case 5:
+       case 6: case 7:
+         out_len++;
+         continue;
+       case 8: case 9:
+         /* b 100lllll <l+1 bytes> */
+         first = (first & 31) + 1;
+         in += first;
+         out_len += first;
+         continue;
+       case 10: case 11:
+         /* c 101oolll <8o> */
+         o = (first & (3 << 3)) << 5 | *in++;
+         first = (first & 7) + 2;
+         break;
+       case 12: case 13:
+         /* d 110lllll <8o> */
+         o = *in++;
+         first = (first & 31) + 10;
+         break;
+       case 14:
+         /* e 1110llll <8o> <8o> */
+         o = in[0] | (in[1] << 8);
+         in += 2;
+         first = (first & 15) + 3;
+         break;
+       case 15:
+         /* f1 1111llll <8l> <8o> <8o> */
+         /* g  11111lll <8l> <8o> <8o> <8o> */
+         first = first & 15;
+         if (first >= 8)
+           {
+             first = (((first - 8) << 8) | in[0]) + 5;
+             o = in[1] | (in[2] << 8) | (in[3] << 16);
+             in += 4;
+           }
+         else
+           {
+             first = ((first << 8) | in[0]) + 19;
+             o = in[1] | (in[2] << 8);
+             in += 3;
+           }
+         break;
+       }
+      /* fprintf(stderr, "ref: %d @ %d\n", first, o); */
+      if (o >= out_len)
+       return 0;
+      out_len += first;
+    }
+  return out_len;
+}
+
 /**********************************************************************/
 
 void repopagestore_init(Repopagestore *store)
@@ -757,6 +798,16 @@ repopagestore_compress_page(unsigned char *page, unsigned int len, unsigned char
   return compress_buf(page, len, cpage, max);
 }
 
+unsigned int
+repopagestore_decompress_page(const unsigned char *cpage, unsigned int len, unsigned char *page, unsigned int max)
+{
+  unsigned int l = check_decompress_buf(cpage, len);
+  if (l == 0 || l > max)
+    return 0;
+  return unchecked_decompress_buf(cpage, len, page, max);
+}
+
+
 #define SOLV_ERROR_EOF         3
 #define SOLV_ERROR_CORRUPT     6
 
index b5f2eee..9fb84f0 100644 (file)
@@ -53,6 +53,8 @@ unsigned char *repopagestore_load_page_range(Repopagestore *store, unsigned int
 
 /* compress a page, return compressed len */
 unsigned int repopagestore_compress_page(unsigned char *page, unsigned int len, unsigned char *cpage, unsigned int max);
+/* uncompress a page, return uncompressed len */
+unsigned int repopagestore_decompress_page(const unsigned char *cpage, unsigned int len, unsigned char *page, unsigned int max);
 
 /* setup page data for repodata_load_page_range */
 int repopagestore_read_or_setup_pages(Repopagestore *store, FILE *fp, unsigned int pagesz, unsigned int blobsz);
index 212df32..a260c2d 100644 (file)
@@ -2257,6 +2257,89 @@ solver_addblackrules(Solver *solv)
 
 /***********************************************************************
  ***
+ ***  Strict repo prio rule part
+ ***/
+
+/* add rules to exclude solvables provided by lower
+ * precedence repositories */
+void solver_addstrictrepopriorules(struct s_Solver *solv, Map *addedmap)
+{
+  Pool *pool = solv->pool;
+  Solvable *s;
+  Id p, p2, pp2;
+  Map priomap;
+  int max_prio;
+
+  map_init_clone(&priomap, addedmap);
+  solv->strictrepopriorules = solv->nrules;
+
+  FOR_POOL_SOLVABLES(p)
+  {
+    if (!MAPTST(&priomap, p))
+      continue;
+
+    s = pool->solvables + p;
+    max_prio = s->repo->priority;
+    FOR_PROVIDES(p2, pp2, s->name)
+      {
+       Solvable *s2 = pool->solvables + p2;
+       if (s->name != s2->name)
+         continue;
+       if (s2->repo->priority > max_prio)
+         max_prio = s2->repo->priority;
+      }
+         
+    FOR_PROVIDES(p2, pp2, s->name)
+      {
+       Solvable *s2 = pool->solvables + p2;
+       if (s->name != s2->name || !MAPTST(&priomap, p2))
+         continue;
+       MAPCLR(&priomap, p2);
+       if (pool->installed && s2->repo == pool->installed)
+         continue;
+       if (s2->repo->priority < max_prio)
+         solver_addrule(solv, -p2, 0, 0);
+      }
+  }
+  solv->strictrepopriorules_end = solv->nrules;
+  map_free(&priomap);
+}
+
+static inline void
+disablerepopriorule(Solver *solv, Id name)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  int i;
+  for (i = solv->strictrepopriorules, r = solv->rules + i; i < solv->strictrepopriorules_end; i++, r++)
+    {
+      if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
+       solver_disablerule(solv, r);
+    }
+}
+
+static inline void
+reenablerepopriorule(Solver *solv, Id name)
+{
+  Pool *pool = solv->pool;
+  Rule *r;
+  int i;
+  for (i = solv->strictrepopriorules, r = solv->rules + i; i < solv->strictrepopriorules_end; i++, r++)
+    {
+      if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
+       {
+         solver_enablerule(solv, r);
+         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
+           {
+             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
+             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
+           }
+       }
+    }
+}
+
+/***********************************************************************
+ ***
  ***  Policy rule disabling/reenabling
  ***
  ***  Disable all policy rules that conflict with our jobs. If a job
@@ -2264,10 +2347,11 @@ solver_addblackrules(Solver *solv)
  ***
  ***/
 
-#define DISABLE_UPDATE 1
-#define DISABLE_INFARCH        2
-#define DISABLE_DUP    3
-#define DISABLE_BLACK  4
+#define DISABLE_UPDATE  1
+#define DISABLE_INFARCH         2
+#define DISABLE_DUP     3
+#define DISABLE_BLACK   4
+#define DISABLE_REPOPRIO 5
 
 static void
 jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
@@ -2367,6 +2451,26 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
                }
            }
        }
+      if ((set & SOLVER_SETREPO) != 0 && solv->strictrepopriorules != solv->strictrepopriorules_end)
+       {
+         if (select == SOLVER_SOLVABLE)
+           queue_push2(q, DISABLE_REPOPRIO, 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_REPOPRIO, s->name);
+               }
+           }
+       }
       if ((set & SOLVER_SETEVR) != 0 && solv->blackrules != solv->blackrules_end)
         {
          if (select == SOLVER_SOLVABLE)
@@ -2553,6 +2657,9 @@ solver_disablepolicyrules(Solver *solv)
        case DISABLE_BLACK:
          disableblackrule(solv, arg);
          break;
+       case DISABLE_REPOPRIO:
+         disablerepopriorule(solv, arg);
+         break;
        default:
          break;
        }
@@ -2659,6 +2766,9 @@ solver_reenablepolicyrules(Solver *solv, int jobidx)
        case DISABLE_BLACK:
          reenableblackrule(solv, arg);
          break;
+       case DISABLE_REPOPRIO:
+         reenablerepopriorule(solv, arg);
+         break;
        }
     }
   queue_free(&q);
@@ -2992,6 +3102,12 @@ solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
        *fromp = -r->p;
       return SOLVER_RULE_BLACK;
     }
+  if (rid >= solv->strictrepopriorules && rid < solv->strictrepopriorules_end)
+    {
+      if (fromp)
+       *fromp = -r->p;
+      return SOLVER_RULE_STRICT_REPO_PRIORITY;
+    }
   if (rid >= solv->choicerules && rid < solv->choicerules_end)
     return SOLVER_RULE_CHOICE;
   if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
@@ -3028,8 +3144,8 @@ solver_ruleclass(Solver *solv, Id rid)
     return SOLVER_RULE_CHOICE;
   if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
     return SOLVER_RULE_RECOMMENDS;
-  if (rid >= solv->blackrules && rid < solv->blackrules_end)
-    return SOLVER_RULE_BLACK;
+  if (rid >= solv->strictrepopriorules && rid < solv->strictrepopriorules_end)
+    return SOLVER_RULE_STRICT_REPO_PRIORITY;
   if (rid >= solv->learntrules && rid < solv->nrules)
     return SOLVER_RULE_LEARNT;
   return SOLVER_RULE_UNKNOWN;
index 3fcede0..043d0a0 100644 (file)
@@ -74,7 +74,8 @@ typedef enum {
   SOLVER_RULE_BEST = 0x900,
   SOLVER_RULE_YUMOBS = 0xa00,
   SOLVER_RULE_RECOMMENDS = 0xb00,
-  SOLVER_RULE_BLACK = 0xc00
+  SOLVER_RULE_BLACK = 0xc00,
+  SOLVER_RULE_STRICT_REPO_PRIORITY = 0xd00
 } SolverRuleinfo;
 
 #define SOLVER_RULE_TYPEMASK    0xff00
@@ -142,6 +143,9 @@ extern void solver_addblackrules(struct s_Solver *solv);
 /* recommends rules */
 extern void solver_addrecommendsrules(struct s_Solver *solv);
 
+/* channel priority rules */
+extern void solver_addstrictrepopriorules(struct s_Solver *solv, Map *addedmap);
+
 /* policy rule disabling/reenabling */
 extern void solver_disablepolicyrules(struct s_Solver *solv);
 extern void solver_reenablepolicyrules(struct s_Solver *solv, int jobidx);
index 619cbf4..39a64b3 100644 (file)
@@ -607,7 +607,7 @@ static void SHA256_Last(SHA256_CTX* context) {
        SHA256_Transform(context, context->buffer);
 }
 
-void solv_SHA256_Final(sha2_byte digest[], SHA256_CTX* context) {
+void solv_SHA256_Final(sha2_byte digest[SHA256_DIGEST_LENGTH], SHA256_CTX* context) {
        sha2_word32     *d = (sha2_word32*)digest;
 
        /* Sanity check: */
@@ -904,7 +904,7 @@ static void SHA512_Last(SHA512_CTX* context) {
        SHA512_Transform(context, context->buffer);
 }
 
-void solv_SHA512_Final(sha2_byte digest[], SHA512_CTX* context) {
+void solv_SHA512_Final(sha2_byte digest[SHA512_DIGEST_LENGTH], SHA512_CTX* context) {
        sha2_word64     *d = (sha2_word64*)digest;
 
        /* Sanity check: */
@@ -948,7 +948,7 @@ void solv_SHA384_Update(SHA384_CTX* context, const sha2_byte* data, size_t len)
        solv_SHA512_Update((SHA512_CTX*)context, data, len);
 }
 
-void solv_SHA384_Final(sha2_byte digest[], SHA384_CTX* context) {
+void solv_SHA384_Final(sha2_byte digest[SHA384_DIGEST_LENGTH], SHA384_CTX* context) {
        sha2_word64     *d = (sha2_word64*)digest;
 
        /* Sanity check: */
@@ -993,7 +993,7 @@ void solv_SHA224_Update(SHA224_CTX* context, const sha2_byte* data, size_t len)
        solv_SHA256_Update((SHA256_CTX*)context, data, len);
 }
 
-void solv_SHA224_Final(sha2_byte digest[], SHA224_CTX* context) {
+void solv_SHA224_Final(sha2_byte digest[SHA224_DIGEST_LENGTH], SHA224_CTX* context) {
        sha2_word32     *d = (sha2_word32*)digest;
 
        /* Sanity check: */
index 0298db4..4b26661 100644 (file)
@@ -34,6 +34,19 @@ typedef struct s_Solvable {
   struct s_Repo *repo;         /* repo we belong to */
 
   /* dependencies are offsets into repo->idarraydata */
+  /* the ifdef resolves "requires" conflicting with a C++20 keyword */
+#ifdef LIBSOLV_SOLVABLE_PREPEND_DEP
+  Offset dep_provides;         /* terminated with Id 0 */
+  Offset dep_obsoletes;
+  Offset dep_conflicts;
+
+  Offset dep_requires;
+  Offset dep_recommends;
+  Offset dep_suggests;
+
+  Offset dep_supplements;
+  Offset dep_enhances;
+#else
   Offset provides;             /* terminated with Id 0 */
   Offset obsoletes;
   Offset conflicts;
@@ -44,7 +57,7 @@ typedef struct s_Solvable {
 
   Offset supplements;
   Offset enhances;
-
+#endif
 } Solvable;
 
 /* lookup functions */
index 1dc2c78..23285ff 100644 (file)
@@ -1475,6 +1475,8 @@ solver_get_flag(Solver *solv, int flag)
     return solv->install_also_updates;
   case SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED:
     return solv->only_namespace_recommended;
+  case SOLVER_FLAG_STRICT_REPO_PRIORITY:
+    return solv->strict_repo_priority;
   default:
     break;
   }
@@ -1568,6 +1570,9 @@ solver_set_flag(Solver *solv, int flag, int value)
   case SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED:
     solv->only_namespace_recommended = value;
     break;
+  case SOLVER_FLAG_STRICT_REPO_PRIORITY:
+    solv->strict_repo_priority = value;
+    break;
   default:
     break;
   }
@@ -4124,6 +4129,11 @@ solver_solve(Solver *solv, Queue *job)
   else
     solv->recommendsrules = solv->recommendsrules_end = solv->nrules;
 
+  if (solv->strict_repo_priority)
+    solver_addstrictrepopriorules(solv, &addedmap);
+  else
+    solv->strictrepopriorules = solv->strictrepopriorules_end = solv->nrules;
+
   if (1)
     solver_addchoicerules(solv);
   else
@@ -4139,7 +4149,19 @@ solver_solve(Solver *solv, Queue *job)
   map_free(&installcandidatemap);
   queue_free(&q);
 
-  POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules, %d yumobs rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules, solv->yumobsrules_end - solv->yumobsrules);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules, %d yumobs rules\n",
+   solv->pkgrules_end - 1, 
+   solv->updaterules_end - solv->updaterules, 
+   solv->jobrules_end - solv->jobrules, 
+   solv->infarchrules_end - solv->infarchrules, 
+   solv->duprules_end - solv->duprules, 
+   solv->choicerules_end - solv->choicerules, 
+   solv->bestrules_end - solv->bestrules, 
+   solv->yumobsrules_end - solv->yumobsrules);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "%d black rules, %d recommends rules, %d repo priority rules\n",
+   solv->blackrules_end - solv->blackrules,
+   solv->recommendsrules_end - solv->recommendsrules,
+   solv->strictrepopriorules_end - solv->strictrepopriorules);
   POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
 
   /* create weak map */
index d30ae36..287003c 100644 (file)
@@ -79,6 +79,9 @@ struct s_Solver {
   Id blackrules;                       /* rules from blacklisted packages */
   Id blackrules_end;
 
+  Id strictrepopriorules;                      /* rules from strict priority repositories */
+  Id strictrepopriorules_end;
+
   Id choicerules;                      /* choice rules (always weak) */
   Id choicerules_end;
   Id *choicerules_info;                        /* the rule we used to generate the choice rule */
@@ -175,6 +178,7 @@ struct s_Solver {
   int strongrecommends;                        /* true: create weak rules for recommends */
   int install_also_updates;            /* true: do not prune install job rules to installed packages */
   int only_namespace_recommended;      /* true: only install packages recommended by namespace */
+  int strict_repo_priority;                    /* true: only use packages from highest precedence/priority */
 
   int process_orphans;                 /* true: do special orphan processing */
   Map dupmap;                          /* dup to those packages */
@@ -329,6 +333,7 @@ typedef struct s_Solver Solver;
 #define SOLVER_FLAG_STRONG_RECOMMENDS          25
 #define SOLVER_FLAG_INSTALL_ALSO_UPDATES       26
 #define SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED 27
+#define SOLVER_FLAG_STRICT_REPO_PRIORITY       28
 
 #define GET_USERINSTALLED_NAMES                        (1 << 0)        /* package names instead of ids */
 #define GET_USERINSTALLED_INVERTED             (1 << 1)        /* autoinstalled */
index fb17bf4..79faaf2 100644 (file)
@@ -22,6 +22,7 @@
 #include "pool.h"
 #include "poolarch.h"
 #include "util.h"
+#include "evr.h"
 
 
 /*-------------------------------------------------------------------
@@ -36,10 +37,18 @@ solver_is_updating(Solver *solv, Id p)
   Id l, pp;
   if (solv->decisionmap[p] >= 0)
     return 0;  /* old package stayed */
-  r = solv->rules + solv->updaterules + (p - solv->installed->start);
+  r = solv->rules + solv->featurerules + (p - solv->installed->start);
+  if (!r->p)
+    r = solv->rules + solv->updaterules + (p - solv->installed->start);
   FOR_RULELITERALS(l, pp, r)
     if (l > 0 && l != p && solv->decisionmap[l] > 0)
-      return 1;
+      {
+       /* check that this is really an upgrade */
+       Solvable *si = pool->solvables + p;
+       Solvable *s = pool->solvables + l;
+       if (s->name != si->name || pool_evrcmp(pool, s->evr, si->evr, EVRCMP_COMPARE) > 0)
+          return 1;
+      }
   return 0;
 }
 
index 0b2879b..5902cdb 100644 (file)
@@ -130,6 +130,8 @@ solver_printruleclass(Solver *solv, int type, Rule *r)
     POOL_DEBUG(type, "YUMOBS ");
   else if (p >= solv->blackrules && p < solv->blackrules_end)
     POOL_DEBUG(type, "BLACK ");
+  else if (p >= solv->strictrepopriorules && p < solv->strictrepopriorules_end)
+    POOL_DEBUG(type, "REPOPRIO ");
   else if (p >= solv->recommendsrules && p < solv->recommendsrules_end)
     POOL_DEBUG(type, "RECOMMENDS ");
   solver_printrule(solv, type, r);
index d66e195..51d57a6 100644 (file)
@@ -11,3 +11,4 @@ const char solv_version[] = LIBSOLV_VERSION_STRING;
 int solv_version_major = LIBSOLV_VERSION_MAJOR;
 int solv_version_minor = LIBSOLV_VERSION_MINOR;
 int solv_version_patch = LIBSOLV_VERSION_PATCH;
+const char solv_toolversion[] = LIBSOLV_TOOLVERSION;
index 43b566a..da0ad74 100644 (file)
@@ -23,6 +23,7 @@ extern const char solv_version[];
 extern int solv_version_major;
 extern int solv_version_minor;
 extern int solv_version_patch;
+extern const char solv_toolversion[];
 
 #cmakedefine LIBSOLV_FEATURE_LINKED_PKGS
 #cmakedefine LIBSOLV_FEATURE_COMPLEX_DEPS
@@ -48,6 +49,6 @@ extern int solv_version_patch;
 #cmakedefine LIBSOLVEXT_FEATURE_ZCHUNK_COMPRESSION
 
 /* see tools/common_write.c for toolversion history */
-#define LIBSOLV_TOOLVERSION "1.1"
+#define LIBSOLV_TOOLVERSION "1.2"
 
 #endif
index 1dc5f32..9c2b824 100644 (file)
@@ -92,7 +92,7 @@ static inline void *solv_calloc_block(size_t len, size_t size, size_t block)
   return buf;
 }
 
-static inline void *solv_memdup(void *buf, size_t len)
+static inline void *solv_memdup(const void *buf, size_t len)
 {
   void *newbuf;
   if (!buf)
@@ -103,7 +103,7 @@ static inline void *solv_memdup(void *buf, size_t len)
   return newbuf;
 }
 
-static inline void *solv_memdup2(void *buf, size_t num, size_t len)
+static inline void *solv_memdup2(const void *buf, size_t num, size_t len)
 {
   void *newbuf;
   if (!buf)
diff --git a/test/testcases/strictrepoprio/strictrepoprio.t b/test/testcases/strictrepoprio/strictrepoprio.t
new file mode 100644 (file)
index 0000000..d749d19
--- /dev/null
@@ -0,0 +1,22 @@
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+repo available 1 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Req: B
+system i686 rpm system
+
+solverflags strictrepopriority
+job install name A
+result transaction,problems <inline>
+#>problem 30c1639e info nothing provides B needed by A-1-1.noarch
+#>problem 30c1639e solution 23f73f5b deljob install name A
+#>problem 30c1639e solution 5dd1416b allow A-2-1.noarch@available
+
+nextjob
+
+solverflags strictrepopriority
+job install pkg A-2-1.noarch@available
+result transaction,problems <inline>
+#>install A-2-1.noarch@available
+
index 36f8dd8..8fda3e3 100644 (file)
@@ -19,6 +19,7 @@
 /* toolversion history
  * 1.0: initial tool version
  * 1.1: changed PRODUCT_ENDOFLIFE parsing
+ * 1.2: added UPDATE_COLLECTIONLIST to updateinfo
 */
 
 static int
index 1307657..49651fb 100644 (file)
@@ -13,6 +13,7 @@
 
 static int with_attr;
 static int dump_json;
+static int dump_userdata;
 
 #include "pool.h"
 #include "chksum.h"
@@ -394,10 +395,7 @@ int main(int argc, char **argv)
   int c, i, j, n;
   Solvable *s;
   
-  pool = pool_create();
-  pool_setloadcallback(pool, loadcallback, 0);
-
-  while ((c = getopt(argc, argv, "haj")) >= 0)
+  while ((c = getopt(argc, argv, "uhaj")) >= 0)
     {
       switch(c)
        {
@@ -410,11 +408,55 @@ int main(int argc, char **argv)
        case 'j':
          dump_json = 1;
          break;
+       case 'u':
+         dump_userdata++;
+         break;
        default:
           usage(1);
           break;
        }
     }
+  if (dump_userdata)
+    {
+      if (optind == argc)
+       argc++;
+      for (; optind < argc; optind++)
+       {
+         unsigned char *userdata = 0;
+         int r, userdatalen = 0;
+         if (argv[optind] && freopen(argv[optind], "r", stdin) == 0)
+           {
+             perror(argv[optind]);
+             exit(1);
+           }
+         r = solv_read_userdata(stdin, &userdata, &userdatalen);
+         if (r)
+           {
+             fprintf(stderr, "could not read userdata: error %d\n", r);
+             exit(1);
+           }
+         if (dump_userdata > 1)
+           {
+             /* dump raw */
+             if (userdatalen && fwrite(userdata, userdatalen, 1, stdout) != 1)
+               {
+                 perror("fwrite");
+                 exit(1);
+               }
+           }
+         else
+           {
+             for (r = 0; r < userdatalen; r++)
+               printf("%02x", userdata[r]);
+             printf("\n");
+           }
+         solv_free(userdata);
+       }
+      exit(0);
+    }
+
+  pool = pool_create();
+  pool_setloadcallback(pool, loadcallback, 0);
   if (!dump_json)
     pool_setdebuglevel(pool, 1);
   if (dump_json)
index a9e67ec..9d5d28b 100644 (file)
@@ -298,7 +298,13 @@ main(int argc, char **argv)
            {
              int pcnt = solver_solve(solv, &job);
              if (writetestcase)
-               testcase_write(solv, writetestcase, resultflags, 0, 0);
+               {
+                 if (!testcase_write(solv, writetestcase, resultflags, 0, 0))
+                   {
+                     fprintf(stderr, "Could not write testcase: %s\n", pool_errstr(pool));
+                     exit(1);
+                   }
+               }
              if (pcnt && solq.count)
                {
                  int i, taken = 0;