Imported Upstream version 0.7.2 upstream/0.7.2
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 10 Sep 2019 06:38:44 +0000 (15:38 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 10 Sep 2019 06:38:44 +0000 (15:38 +0900)
39 files changed:
NEWS
README
VERSION.cmake
bindings/solv.i
doc/gen/libsolv-bindings.3
doc/libsolv-bindings.txt
examples/tclsolv
ext/repo_appdata.c
ext/repo_arch.c
ext/repo_comps.c
ext/repo_content.c
ext/repo_cudf.c
ext/repo_deb.c
ext/repo_deltainfoxml.c
ext/repo_helix.c
ext/repo_mdk.c
ext/repo_products.c
ext/repo_repomdxml.c
ext/repo_rpmdb.c
ext/repo_rpmmd.c
ext/repo_updateinfoxml.c
ext/repo_zyppdb.c
ext/solv_jsonparser.c [new file with mode: 0644]
ext/solv_jsonparser.h [new file with mode: 0644]
ext/solv_xmlparser.c
ext/solv_xmlparser.h
ext/testcase.c
package/libsolv.changes
src/evr.c
src/problems.c
src/repo.h
src/solver.c
src/solver.h
src/solver_private.h
src/solver_util.c
test/testcases/allowuninstall/conflict.t [new file with mode: 0644]
test/testcases/allowuninstall/forcebest.t [new file with mode: 0644]
test/testcases/evrcmp/caret.t [new file with mode: 0644]
test/testcases/namespace/namespaceprovides.t

diff --git a/NEWS b/NEWS
index 1416a16..812a923 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,14 @@
 This file contains the major changes between
 libsolv versions:
 
+Version 0.7.2
+- bug fixes:
+  * do not autouninstall packages because of forcebest updates
+- new features:
+  * support rpm's new '^' version separator
+  * support set/get_considered_list in bindings
+  * new experimental SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED flag
+
 Version 0.7.1
 - fix nasty off-by-one error in repo_write
 
diff --git a/README b/README
index db680c4..0242459 100644 (file)
--- a/README
+++ b/README
@@ -1,10 +1,13 @@
+Libsolv
+=======
+
 This is libsolv, a free package dependency solver using a satisfiability
 algorithm.
 
 The code is based on two major, but independent, blocks:
 
- 1. Using a dictionary approach to store and retrieve package
-    and dependency information.
+ 1. Using a dictionary approach to store and retrieve package and
+    dependency information in a fast and space efficient manner.
 
  2. Using satisfiability, a well known and researched topic, for
     resolving package dependencies.
index bd4e5e6..507716c 100644 (file)
@@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "1")
 
 SET(LIBSOLV_MAJOR "0")
 SET(LIBSOLV_MINOR "7")
-SET(LIBSOLV_PATCH "1")
+SET(LIBSOLV_PATCH "2")
 
index 1a88917..93a97db 100644 (file)
@@ -88,23 +88,6 @@ typedef struct {
 }
 
 #if defined(SWIGPYTHON)
-%typemap(in) Queue {
-  /* Check if is a list */
-  if (PyList_Check($input)) {
-    int size = PyList_Size($input);
-    int i = 0;
-    for (i = 0; i < size; i++) {
-      PyObject *o = PyList_GetItem($input,i);
-      int v;
-      int e = SWIG_AsVal_int(o, &v);
-      if (!SWIG_IsOK(e))
-        SWIG_exception_fail(SWIG_ArgError(e), "list must contain only integers");
-      queue_push(&$1, v);
-    }
-  } else {
-    SWIG_exception_fail(SWIG_TypeError, "list must contain only integers");
-  }
-}
 
 %typemap(out) Queue {
   int i;
@@ -115,7 +98,7 @@ typedef struct {
   $result = o;
 }
 
-%define Queue2Array(type, step, con) %{
+%define Queue2Array(type, step, con) %{ {
   int i;
   int cnt = $1.count / step;
   Id *idp = $1.elements;
@@ -131,30 +114,47 @@ typedef struct {
     }
   queue_free(&$1);
   $result = o;
+}
 %}
-
 %enddef
 
-#endif  /* SWIGPYTHON */
-
-#if defined(SWIGPERL)
-%typemap(in) Queue {
-  AV *av;
+%define Array2Queue(asval_meth,typestr) %{ {
   int i, size;
-  if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV)
-    SWIG_croak("Argument $argnum is not an array reference.");
-  av = (AV*)SvRV($input);
-  size = av_len(av);
-  for (i = 0; i <= size; i++) {
-    SV **sv = av_fetch(av, i, 0);
+  if (!PyList_Check($input))
+    SWIG_exception_fail(SWIG_TypeError, "argument $argnum is not a list");
+  size = PyList_Size($input);
+  for (i = 0; i < size; i++) {
+    PyObject *o = PyList_GetItem($input,i);
     int v;
-    int e = SWIG_AsVal_int(*sv, &v);
-    if (!SWIG_IsOK(e)) {
-      SWIG_croak("list must contain only integers");
-    }
+    int e = asval_meth(o, &v);
+    if (!SWIG_IsOK(e))
+      SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only" typestr);
     queue_push(&$1, v);
   }
 }
+%}
+%enddef
+
+%define ObjArray2Queue(type, obj2queue) %{ {
+  int i, size;
+  if (!PyList_Check($input))
+    SWIG_exception_fail(SWIG_TypeError, "argument $argnum is not a list");
+  size = PyList_Size($input);
+  for (i = 0; i < size; i++) {
+    PyObject *o = PyList_GetItem($input,i);
+    type obj;
+    int e = SWIG_ConvertPtr(o, (void **)&obj, $descriptor(type), 0 | 0);
+    if (!SWIG_IsOK(e))
+      SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only "`type`);
+    obj2queue;
+  }
+}
+%}
+%enddef
+
+#endif  /* SWIGPYTHON */
+
+#if defined(SWIGPERL)
 /* AV *o = newAV();
  * av_push(o, SvREFCNT_inc(SWIG_From_int($1.elements[i])));
  * $result = newRV_noinc((SV*)o); argvi++;
@@ -170,7 +170,7 @@ typedef struct {
   $result = 0;
 }
 
-%define Queue2Array(type, step, con) %{
+%define Queue2Array(type, step, con) %{ {
   int i;
   int cnt = $1.count / step;
   Id *idp = $1.elements;
@@ -188,28 +188,52 @@ typedef struct {
     }
   queue_free(&$1);
   $result = 0;
+}
 %}
 %enddef
 
-#endif  /* SWIGPERL */
-
-
-#if defined(SWIGRUBY)
-%typemap(in) Queue {
-  int size, i;
-  VALUE *o, ary;
-  ary = rb_Array($input);
-  size = RARRAY_LEN(ary);
-  i = 0;
-  o = RARRAY_PTR(ary);
-  for (i = 0; i < size; i++, o++) {
+%define Array2Queue(asval_meth,typestr) %{ {
+  AV *av;
+  int i, size;
+  if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV)
+    SWIG_croak("argument $argnum is not an array reference.");
+  av = (AV*)SvRV($input);
+  size = av_len(av);
+  for (i = 0; i <= size; i++) {
+    SV **sv = av_fetch(av, i, 0);
     int v;
-    int e = SWIG_AsVal_int(*o, &v);
+    int e = asval_meth(*sv, &v);
     if (!SWIG_IsOK(e))
-      SWIG_exception_fail(SWIG_TypeError, "list must contain only integers");
+      SWIG_croak("array in argument $argnum must contain only " typestr);
     queue_push(&$1, v);
   }
 }
+%}
+%enddef
+
+%define ObjArray2Queue(type, obj2queue) %{ {
+  AV *av;
+  int i, size;
+  if (!SvROK($input) || SvTYPE(SvRV($input)) != SVt_PVAV)
+    SWIG_croak("argument $argnum is not an array reference.");
+  av = (AV*)SvRV($input);
+  size = av_len(av);
+  for (i = 0; i <= size; i++) {
+    SV **sv = av_fetch(av, i, 0);
+    type obj;
+    int e = SWIG_ConvertPtr(*sv, (void **)&obj, $descriptor(type), 0 | 0);
+    if (!SWIG_IsOK(e))
+      SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only "`type`);
+    obj2queue;
+  }
+}
+%}
+%enddef
+
+#endif  /* SWIGPERL */
+
+
+#if defined(SWIGRUBY)
 %typemap(out) Queue {
   int i;
   VALUE o = rb_ary_new2($1.count);
@@ -218,13 +242,8 @@ typedef struct {
   queue_free(&$1);
   $result = o;
 }
-%typemap(arginit) Queue {
-  queue_init(&$1);
-}
-%typemap(freearg) Queue {
-  queue_free(&$1);
-}
-%define Queue2Array(type, step, con) %{
+
+%define Queue2Array(type, step, con) %{ {
   int i;
   int cnt = $1.count / step;
   Id *idp = $1.elements;
@@ -240,32 +259,49 @@ typedef struct {
     }
   queue_free(&$1);
   $result = o;
+}
 %}
 %enddef
 
-#endif  /* SWIGRUBY */
-
-#if defined(SWIGTCL)
-%typemap(in) Queue {
-  /* Check if is a list */
-  int size = 0;
-  int i = 0;
-
-  if (TCL_OK != Tcl_ListObjLength(interp, $input, &size))
-    SWIG_exception_fail(SWIG_TypeError, "argument is not a list");
-  for (i = 0; i < size; i++) {
-    Tcl_Obj *o = NULL;
-    int e, v;
-
-    if (TCL_OK != Tcl_ListObjIndex(interp, $input, i, &o))
-      SWIG_exception_fail(SWIG_IndexError, "failed to retrieve a list member");
-    e = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(o, &v);
+%define Array2Queue(asval_meth,typestr) %{ {
+  int size, i;
+  VALUE *o, ary;
+  ary = rb_Array($input);
+  size = RARRAY_LEN(ary);
+  i = 0;
+  o = RARRAY_PTR(ary);
+  for (i = 0; i < size; i++, o++) {
+    int v;
+    int e = asval_meth(*o, &v);
     if (!SWIG_IsOK(e))
-      SWIG_exception_fail(SWIG_ArgError(e), "list must contain only integers");
+      SWIG_exception_fail(SWIG_TypeError, "list in argument $argnum must contain only " typestr);
     queue_push(&$1, v);
   }
 }
+%}
+%enddef
+
+%define ObjArray2Queue(type, obj2queue) %{ {
+  int size, i;
+  VALUE *o, ary;
+  ary = rb_Array($input);
+  size = RARRAY_LEN(ary);
+  i = 0;
+  o = RARRAY_PTR(ary);
+  for (i = 0; i < size; i++, o++) {
+    type obj;
+    int e = SWIG_ConvertPtr(*o, (void **)&obj, $descriptor(type), 0 | 0);
+    if (!SWIG_IsOK(e))
+      SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only "`type`);
+    obj2queue;
+  }
+}
+%}
+%enddef
 
+#endif  /* SWIGRUBY */
+
+#if defined(SWIGTCL)
 %typemap(out) Queue {
   Tcl_Obj *objvx[$1.count];
   int i;
@@ -297,36 +333,56 @@ typedef struct {
     }
     queue_free(&$1);
     Tcl_SetObjResult(interp, Tcl_NewListObj(cnt, objvx));
 }
+ }
 %}
-
 %enddef
 
-%typemap(in) Queue solvejobs {
-  /* Check if is a list */
+%define Array2Queue(asval_meth,typestr) %{ {
   int size = 0;
   int i = 0;
+  if (TCL_OK != Tcl_ListObjLength(interp, $input, &size))
+    SWIG_exception_fail(SWIG_TypeError, "argument $argnum is not a list");
+  for (i = 0; i < size; i++) {
+    Tcl_Obj *o = NULL;
+    int e, v;
 
+    if (TCL_OK != Tcl_ListObjIndex(interp, $input, i, &o))
+      SWIG_exception_fail(SWIG_IndexError, "failed to retrieve a list member");
+    e = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(o, &v);
+    if (!SWIG_IsOK(e))
+      SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only " typestr);
+    queue_push(&$1, v);
+  }
+}
+%}
+%enddef
+
+%define ObjArray2Queue(type, obj2queue) %{ {
+  int size = 0;
+  int i = 0;
   if (TCL_OK != Tcl_ListObjLength(interp, $input, &size))
-    SWIG_exception_fail(SWIG_TypeError, "argument is not a list");
+    SWIG_exception_fail(SWIG_TypeError, "argument $argnum is not a list");
   for (i = 0; i < size; i++) {
     Tcl_Obj *o = NULL;
-    void *jp;
-    Job *j;
+    type obj;
     int e;
-
     if (TCL_OK != Tcl_ListObjIndex(interp, $input, i, &o))
       SWIG_exception_fail(SWIG_IndexError, "failed to retrieve a list member");
-    e = SWIG_ConvertPtr(o, &jp ,SWIGTYPE_p_Job, 0 |  0 );
+    e = SWIG_ConvertPtr(o, (void **)&obj, $descriptor(type), 0 | 0);
     if (!SWIG_IsOK(e))
-      SWIG_exception_fail(SWIG_ArgError(e), "list member is not a Job");
-    j = (Job *)jp;
-    queue_push2(&$1, j->how, j->what);
+      SWIG_exception_fail(SWIG_ArgError(e), "list in argument $argnum must contain only "`type`);
+    obj2queue;
   }
 }
+%}
+%enddef
 
 #endif  /* SWIGTCL */
 
+%typemap(in) Queue Array2Queue(SWIG_AsVal_int, "integers")
+%typemap(in) Queue solvejobs ObjArray2Queue(Job *, queue_push2(&$1, obj->how, obj->what))
+
+
 
 #if defined(SWIGPERL)
 
@@ -1963,9 +2019,38 @@ typedef struct {
     return sel;
   }
 
-  void setpooljobs_helper(Queue jobs) {
+  Queue get_considered_list() {
+    Queue q;
+    queue_init(&q);
+    int i;
+    for (i = 2; i < $self->nsolvables; i++) {
+      if (!$self->solvables[i].repo)
+        continue;
+      if (!$self->considered || MAPTST($self->considered, i))
+        queue_push(&q, i);
+    }
+    return q;
+  }
+
+  void set_considered_list(Queue q) {
+    int i;
+    Id p;
+    if (!$self->considered) {
+      $self->considered = solv_calloc(1, sizeof(Map));
+      map_init($self->considered, $self->nsolvables);
+    }
+    map_empty($self->considered);
+    MAPSET($self->considered, 1);
+    for (i = 0; i < q.count; i++) {
+      p = q.elements[i];
+      if (p > 0 && p < $self->nsolvables)
+        MAPSET($self->considered, p);
+    }
+  }
+
+  void setpooljobs(Queue solvejobs) {
     queue_free(&$self->pooljobs);
-    queue_init_clone(&$self->pooljobs, &jobs);
+    queue_init_clone(&$self->pooljobs, &solvejobs);
   }
   %typemap(out) Queue getpooljobs Queue2Array(Job *, 2, new_Job(arg1, id, idp[1]));
   %newobject getpooljobs;
@@ -1975,36 +2060,6 @@ typedef struct {
     return q;
   }
 
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def setpooljobs(self, jobs):
-      j = []
-      for job in jobs: j += [job.how, job.what]
-      self.setpooljobs_helper(j)
-  }
-#endif
-#if defined(SWIGPERL)
-  %perlcode {
-    sub solv::Solver::setpooljobs {
-      my ($self, $jobs) = @_;
-      my @j = map {($_->{'how'}, $_->{'what'})} @$jobs;
-      return $self->setpooljobs_helper(\@j);
-    }
-  }
-#endif
-#if defined(SWIGRUBY)
-%init %{
-rb_eval_string(
-    "class Solv::Pool\n"
-    "  def setpooljobs(jobs)\n"
-    "    jl = []\n"
-    "    jobs.each do |j| ; jl << j.how << j.what ; end\n"
-    "    setpooljobs_helper(jl)\n"
-    "  end\n"
-    "end\n"
-  );
-%}
-#endif
 }
 
 %extend Repo {
@@ -3425,49 +3480,7 @@ rb_eval_string(
   int get_flag(int flag) {
     return solver_get_flag($self, flag);
   }
-#if defined(SWIGPYTHON)
-  %pythoncode {
-    def solve(self, jobs):
-      j = []
-      for job in jobs: j += [job.how, job.what]
-      return self.solve_helper(j)
-  }
-#endif
-#if defined(SWIGPERL)
-  %perlcode {
-    sub solv::Solver::solve {
-      my ($self, $jobs) = @_;
-      my @j = map {($_->{'how'}, $_->{'what'})} @$jobs;
-      return $self->solve_helper(\@j);
-    }
-  }
-#endif
-#if defined(SWIGRUBY)
-%init %{
-rb_eval_string(
-    "class Solv::Solver\n"
-    "  def solve(jobs)\n"
-    "    jl = []\n"
-    "    jobs.each do |j| ; jl << j.how << j.what ; end\n"
-    "    solve_helper(jl)\n"
-    "  end\n"
-    "end\n"
-  );
-%}
-#endif
-  %typemap(out) Queue solve_helper Queue2Array(Problem *, 1, new_Problem(arg1, id));
-  %newobject solve_helper;
-  Queue solve_helper(Queue jobs) {
-    Queue q;
-    int i, cnt;
-    queue_init(&q);
-    solver_solve($self, &jobs);
-    cnt = solver_problem_count($self);
-    for (i = 1; i <= cnt; i++)
-      queue_push(&q, i);
-    return q;
-  }
-#if defined(SWIGTCL)
+
   %typemap(out) Queue solve Queue2Array(Problem *, 1, new_Problem(arg1, id));
   %newobject solve;
   Queue solve(Queue solvejobs) {
@@ -3480,7 +3493,6 @@ rb_eval_string(
       queue_push(&q, i);
     return q;
   }
-#endif
 
   %newobject transaction;
   Transaction *transaction() {
index 4bfab9c..9f84c77 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: Libsolv-Bindings
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 10/24/2018
+.\"      Date: 12/06/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "LIBSOLV\-BINDINGS" "3" "10/24/2018" "libsolv" "LIBSOLV"
+.TH "LIBSOLV\-BINDINGS" "3" "12/06/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -87,7 +87,7 @@ my \fI$iter\fR \fB=\fR \fI$pool\fR\fB\->solvables_iter()\fR;
 .sp
 As a downside of this approach, iterator objects cannot have attributes\&.
 .sp
-If an array needs to be passed to a method it is usually done by reference, if a method returns an array it returns it on the stack:
+If an array needs to be passed to a method it is usually done by reference, if a method returns an array it returns it on the perl stack:
 .sp
 .if n \{\
 .RS 4
@@ -200,7 +200,7 @@ The bindings define stringification for many classes, some also have a \fIrepr\f
 .RE
 .\}
 .sp
-Constants are attributes of the classes:
+Constants are attributes of the corresponding classes:
 .sp
 .if n \{\
 .RS 4
@@ -399,7 +399,7 @@ Swig implements all constants as numeric variables, constants belonging to a lib
 .RS 4
 .\}
 .nf
-\fI$pool\fR \fBset_flag\fR \fI$solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS\fR  \fB1\fR
+\fI$pool\fR \fBset_flag\fR \fI$solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS\fR \fB1\fR
 \fBputs [\fR\fI$solvable\fR \fBlookup_str\fR \fI$solv::SOLVABLE_SUMMARY\fR\fB]\fR
 .fi
 .if n \{\
@@ -441,7 +441,7 @@ Access the meta section of a repository or repodata area\&. This is like an extr
 .PP
 \fBSOLVID_POS\fR
 .RS 4
-Use the data position stored inside of the pool instead of accessing some solvable by Id\&. The bindings have the Datapos objects as an abstraction mechanism, so you do not need this constant\&.
+Use the data position stored inside of the pool instead of accessing some solvable by Id\&. The bindings have the Datapos objects as an abstraction mechanism, so you most likely do not need this constant\&.
 .RE
 .sp
 Constant string Ids
@@ -569,7 +569,7 @@ Promote the epoch of the providing dependency to the requesting dependency if it
 .PP
 \fBPOOL_FLAG_FORBIDSELFCONFLICTS\fR
 .RS 4
-Disallow the installation of packages that conflict with themselves\&. Debian always allows self\-conflicting packages, rpm used to forbid them but switched to also allowing them recently\&.
+Disallow the installation of packages that conflict with themselves\&. Debian always allows self\-conflicting packages, rpm used to forbid them but switched to also allowing them since rpm\-4\&.9\&.0\&.
 .RE
 .PP
 \fBPOOL_FLAG_OBSOLETEUSESPROVIDES\fR
@@ -584,7 +584,7 @@ An implicit obsoletes is the internal mechanism to remove the old package on an
 .PP
 \fBPOOL_FLAG_OBSOLETEUSESCOLORS\fR
 .RS 4
-Rpm\(cqs multilib implementation (used in RedHat and Fedora) distinguishes between 32bit and 64bit packages (the terminology is that they have a different color)\&. If obsoleteusescolors is set, packages with different colors will not obsolete each other\&.
+Rpm\(cqs multilib implementation distinguishes between 32bit and 64bit packages (the terminology is that they have a different color)\&. If obsoleteusescolors is set, packages with different colors will not obsolete each other\&.
 .RE
 .PP
 \fBPOOL_FLAG_IMPLICITOBSOLETEUSESCOLORS\fR
@@ -594,7 +594,7 @@ Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if packages of the sa
 .PP
 \fBPOOL_FLAG_NOINSTALLEDOBSOLETES\fR
 .RS 4
-New versions of rpm consider the obsoletes of installed packages when checking for dependency, thus you may not install a package that is obsoleted by some other installed package, unless you also erase the other package\&.
+Since version 4\&.9\&.0 rpm considers the obsoletes of installed packages when checking for dependency conflicts, thus you may not install a package that is obsoleted by some other installed package unless you also erase the other package\&.
 .RE
 .PP
 \fBPOOL_FLAG_HAVEDISTEPOCH\fR
@@ -604,7 +604,7 @@ Mandriva added a new field called distepoch that gets checked in version compari
 .PP
 \fBPOOL_FLAG_NOOBSOLETESMULTIVERSION\fR
 .RS 4
-If a package is installed in multiversionmode, rpm used to ignore both the implicit obsoletes and the obsolete dependency of a package\&. This was changed to ignoring just the implicit obsoletes, thus you may install multiple versions of the same name, but obsoleted packages still get removed\&.
+If a package is installed in multiversion mode, rpm used to ignore both the implicit obsoletes and the obsolete dependency of a package\&. This was changed to ignoring just the implicit obsoletes, thus you may install multiple versions of the same name, but obsoleted packages still get removed\&.
 .RE
 .PP
 \fBPOOL_FLAG_ADDFILEPROVIDESFILTERED\fR
@@ -684,7 +684,7 @@ my \fI$value\fR \fB=\fR \fI$pool\fR\fB\->get_flag(\fR\fI$flag\fR\fB)\fR;
 .RE
 .\}
 .sp
-Set/get a pool specific flag\&. The flags define how the system works, e\&.g\&. how the package manager treats obsoletes\&. The default flags should be sane for most applications, but in some cases you may want to tweak a flag, for example if you want to solv package dependencies for some other system than yours\&.
+Set/get a pool specific flag\&. The flags define how the system works, e\&.g\&. how the package manager treats obsoletes\&. The default flags should be sane for most applications, but in some cases you may want to tweak a flag, for example if you want to solve package dependencies for some other system\&.
 .sp
 .if n \{\
 .RS 4
@@ -830,7 +830,7 @@ Some package managers like rpm allow dependencies on files contained in other pa
 .RE
 .\}
 .sp
-Create the internal \(lqwhatprovides\(rq hash over all of the provides of all packages\&. This method must be called before doing any lookups on provides\&. It\(cqs encouraged to do it right after all repos are set up, usually right after the call to addfileprovides()\&.
+Create the internal \(lqwhatprovides\(rq hash over all of the provides of all installable packages\&. This method must be called before doing any lookups on provides\&. It\(cqs encouraged to do it right after all repos are set up, usually right after the call to addfileprovides()\&.
 .sp
 .if n \{\
 .RS 4
@@ -890,7 +890,7 @@ my \fI$offset\fR \fB=\fR \fI$pool\fR\fB\->towhatprovides(\e\fR\fI@ids\fR\fB)\fR;
 .RE
 .\}
 .sp
-Manually set an namespace provides entry in the whatprovides index\&.
+Manually set a namespace provides entry in the whatprovides index\&.
 .sp
 .if n \{\
 .RS 4
@@ -905,7 +905,7 @@ Manually set an namespace provides entry in the whatprovides index\&.
 .RE
 .\}
 .sp
-Flush the cache of all namespacprovudes matching the specified namespace dependency\&. You can use zero as a wildcard argument\&.
+Flush the cache of all namespaceprovides matching the specified namespace dependency\&. You can use zero as a wildcard argument\&.
 .sp
 .if n \{\
 .RS 4
@@ -950,7 +950,7 @@ my \fI$job\fR \fB=\fR \fI$pool\fR\fB\->Job(\fR\fI$how\fR\fB,\fR \fI$what\fR\fB)\
 .RE
 .\}
 .sp
-Create a new Job object\&. Kind of low level, in most cases you would use a Selection or Dep job constructor instead\&.
+Create a new Job object\&. Kind of low level, in most cases you would instead use a Selection or Dep job constructor\&.
 .sp
 .if n \{\
 .RS 4
@@ -1010,7 +1010,7 @@ my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->matchdeps(\fR\fI$name\fR\fB,\fR \fI$flags
 .RE
 .\}
 .sp
-Create a selection by matching package dependencies against the specified string\&. This can be used if you want to match other dependency types than "provides"\&.
+Create a selection by matching package dependencies against the specified string\&. This can be used if you want to match other dependency types than \(lqprovides\(rq\&.
 .sp
 .if n \{\
 .RS 4
@@ -1053,7 +1053,7 @@ Create a selection by matching package dependencies against the specified depend
 .RE
 .\}
 .sp
-Get/Set fixed jobs stored in the pool\&. Those jobs are automatically appended to all solver jobs, they are meant for fixed configurations like which packages can be multiversion installed, which packages were userinstalled or must not be erased\&.
+Get/Set fixed jobs stored in the pool\&. Those jobs are automatically appended to all solver jobs, they are meant for fixed configurations like which packages can be multiversion installed, which packages were userinstalled, or which packages must not be erased\&.
 .sp
 .if n \{\
 .RS 4
@@ -1311,7 +1311,7 @@ my \fI$id\fR \fB=\fR \fIpool\fR\fB\->rel2id(\fR\fI$nameid\fR\fB,\fR \fI$evrid\fR
 .RE
 .\}
 .sp
-Create a \(lqrelational\(rq dependency\&. Such dependencies consist of a name part, the \fIflags\fR describing the relation, and a version part\&. The flags are:
+Create a \(lqrelational\(rq dependency\&. Such dependencies consist of a name part, \fIflags\fR describing the relation, and a version part\&. The flags are:
 .sp
 .if n \{\
 .RS 4
@@ -1405,7 +1405,7 @@ my \fI$reldep\fR \fB=\fR \fI$dep\fR\fB\->Rel(\fR\fI$flags\fR\fB,\fR \fI$evrdep\f
 .RE
 .\}
 .sp
-Create a relational dependency from to string dependencies and a flags argument\&. See the pool\(cqs rel2id method for a description of the flags\&.
+Create a relational dependency from the caller dependency, the flags, and a dependency describing the \(lqversion\(rq part\&. See the pool\(cqs rel2id method for a description of the flags\&.
 .sp
 .if n \{\
 .RS 4
@@ -1480,7 +1480,7 @@ Same as calling the str() method\&.
 .RE
 .\}
 .sp
-The dependencies are equal if they are part of the same pool and have the same ids\&.
+Two dependencies are equal if they are part of the same pool and have the same ids\&.
 .SH "THE REPOSITORY CLASS"
 .sp
 A Repository describes a group of packages, normally coming from the same source\&. Repositories are created by the Pool\(cqs add_repo() method\&.
@@ -1609,7 +1609,7 @@ Return a Datapos object of the repodata\(cqs metadata\&. You can use the lookup
 .PP
 \fBREPO_REUSE_REPODATA\fR
 .RS 4
-Reuse the last repository data area (\(lqrepodata\(rq) instead of creating a new one\&.
+Reuse the last repository data area (\(lqrepodata\(rq) instead of creating a new area\&.
 .RE
 .PP
 \fBREPO_NO_INTERNALIZE\fR
index d28b8b5..e458246 100644 (file)
@@ -45,7 +45,7 @@ tied arrays so that it is possible to iterate with a for() statement:
 As a downside of this approach, iterator objects cannot have attributes.
 
 If an array needs to be passed to a method it is usually done by reference,
-if a method returns an array it returns it on the stack:
+if a method returns an array it returns it on the perl stack:
 
        my @problems = $solver->solve(\@jobs);
 
@@ -93,7 +93,7 @@ __repr__ method to ease debugging.
        print dep
        print repr(repo)
 
-Constants are attributes of the classes:
+Constants are attributes of the corresponding classes:
 
        pool.set_flag(solv.Pool.POOL_FLAG_OBSOLETEUSESCOLORS, 1);
 
@@ -183,7 +183,7 @@ Some objects also support a ``=='' method for equality tests, and a
 Swig implements all constants as numeric variables, constants belonging
 to a libsolv class are prefixed with the class name:
 
-       TCL $pool set_flag $solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS  1
+       TCL $pool set_flag $solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS 1
        TCL puts [$solvable lookup_str $solv::SOLVABLE_SUMMARY]
        
 
@@ -218,10 +218,10 @@ like an extra Solvable that has the Id SOLVID_META.
 *SOLVID_POS*::
 Use the data position stored inside of the pool instead of accessing
 some solvable by Id. The bindings have the Datapos objects as an
-abstraction mechanism, so you do not need this constant.
+abstraction mechanism, so you most likely do not need this constant.
 
 Constant string Ids
-  
+
 *ID_NULL*::
 Always zero
 
@@ -300,7 +300,7 @@ in old rpm versions, modern systems should never need this.
 *POOL_FLAG_FORBIDSELFCONFLICTS*::
 Disallow the installation of packages that conflict with themselves.
 Debian always allows self-conflicting packages, rpm used to forbid
-them but switched to also allowing them recently.
+them but switched to also allowing them since rpm-4.9.0.
 
 *POOL_FLAG_OBSOLETEUSESPROVIDES*::
 Make obsolete type dependency match against provides instead of
@@ -315,10 +315,10 @@ with the same name, rpm-5 switched to also removing packages
 providing the same name.
 
 *POOL_FLAG_OBSOLETEUSESCOLORS*::
-Rpm's multilib implementation (used in RedHat and Fedora)
-distinguishes between 32bit and 64bit packages (the terminology
-is that they have a different color). If obsoleteusescolors is
-set, packages with different colors will not obsolete each other.
+Rpm's multilib implementation distinguishes between 32bit and 64bit
+packages (the terminology is that they have a different color).
+If obsoleteusescolors is set, packages with different colors will
+not obsolete each other.
 
 *POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS*::
 Same as POOL_FLAG_OBSOLETEUSESCOLORS, but used to find out if
@@ -328,9 +328,9 @@ false and POOL_FLAG_IMPLICITOBSOLETEUSESCOLORS should be true
 (this is the default if FEDORA is defined when libsolv is compiled).
 
 *POOL_FLAG_NOINSTALLEDOBSOLETES*::
-New versions of rpm consider the obsoletes of installed packages
-when checking for dependency, thus you may not install a package
-that is obsoleted by some other installed package, unless you
+Since version 4.9.0 rpm considers the obsoletes of installed packages
+when checking for dependency conflicts, thus you may not install a
+package that is obsoleted by some other installed package unless you
 also erase the other package.
 
 *POOL_FLAG_HAVEDISTEPOCH*::
@@ -339,7 +339,7 @@ version comparison if the epoch/version/release of two packages
 are the same.
 
 *POOL_FLAG_NOOBSOLETESMULTIVERSION*::
-If a package is installed in multiversionmode, rpm used to ignore
+If a package is installed in multiversion mode, rpm used to ignore
 both the implicit obsoletes and the obsolete dependency of a
 package. This was changed to ignoring just the implicit obsoletes,
 thus you may install multiple versions of the same name, but
@@ -393,7 +393,7 @@ value, the more output is generated.
 Set/get a pool specific flag. The flags define how the system works, e.g. how
 the package manager treats obsoletes. The default flags should be sane for most
 applications, but in some cases you may want to tweak a flag, for example if
-you want to solv package dependencies for some other system than yours.
+you want to solve package dependencies for some other system.
 
        void set_rootdir(const char *rootdir)
        $pool->set_rootdir(rootdir);
@@ -475,7 +475,8 @@ repository is loaded and addfileprovides is called.
        pool.createwhatprovides()
 
 Create the internal ``whatprovides'' hash over all of the provides of all
-packages. This method must be called before doing any lookups on provides.
+installable packages. This method must be called before doing any lookups on
+provides.
 It's encouraged to do it right after all repos are set up, usually right after
 the call to addfileprovides().
 
@@ -509,14 +510,14 @@ for more information.
        pool.set_namespaceproviders(ns, evr, True)
        pool.set_namespaceproviders(ns, evr, true)
 
-Manually set an namespace provides entry in the whatprovides index.
+Manually set a namespace provides entry in the whatprovides index.
 
        void flush_namespaceproviders(DepId ns, DepId evr)
-        $pool->flush_namespaceproviders($ns, $evr);
-        $pool.flush_namespaceproviders(ns, evr)
-        $pool.flush_namespaceproviders(ns, evr)
+       $pool->flush_namespaceproviders($ns, $evr);
+       $pool.flush_namespaceproviders(ns, evr)
+       $pool.flush_namespaceproviders(ns, evr)
 
-Flush the cache of all namespacprovudes matching the specified namespace
+Flush the cache of all namespaceprovides matching the specified namespace
 dependency. You can use zero as a wildcard argument.
 
        bool isknownarch(DepId id)
@@ -538,8 +539,8 @@ Create a new solver object.
        job = pool.Job(how, what)
        job = pool.Job(how, what)
 
-Create a new Job object. Kind of low level, in most cases you would use a
-Selection or Dep job constructor instead.
+Create a new Job object. Kind of low level, in most cases you would
+instead use a Selection or Dep job constructor.
 
        Selection Selection()
        my $sel = $pool->Selection();
@@ -572,7 +573,7 @@ selection.
        sel = pool.matchdeps(name, flags, keyname)
 
 Create a selection by matching package dependencies against the specified string.
-This can be used if you want to match other dependency types than "provides".
+This can be used if you want to match other dependency types than ``provides''.
 
        Selection matchdepid(DepId dep, int flags, Id keyname, Id marker = -1)
        my $sel = $pool->matchdepid(dep, $flags, $keyname);
@@ -596,8 +597,8 @@ matching.
 
 Get/Set fixed jobs stored in the pool. Those jobs are automatically appended to
 all solver jobs, they are meant for fixed configurations like which packages
-can be multiversion installed, which packages were userinstalled or must not be
-erased.
+can be multiversion installed, which packages were userinstalled, or which
+packages must not be erased.
 
        void set_loadcallback(Callable *callback)
        $pool->setloadcallback(\&callbackfunction);
@@ -733,7 +734,7 @@ pool and _create_ is false, zero is returned.
        id = pool.rel2id(nameid, evrid, flags)
 
 Create a ``relational'' dependency. Such dependencies consist of a name part,
-the _flags_ describing the relation, and a version part. The flags are:
+_flags_ describing the relation, and a version part. The flags are:
 
        $solv::REL_EQ | $solv::REL_GT | $solv::REL_LT
        solv.REL_EQ | solv.REL_GT | solv.REL_LT
@@ -790,8 +791,9 @@ The id of this dependency.
        reldep = dep.Rel(flags, evrdep)
        reldep = dep.Rel(flags, evrdep)
 
-Create a relational dependency from to string dependencies and a flags
-argument. See the pool's rel2id method for a description of the flags.
+Create a relational dependency from the caller dependency, the flags,
+and a dependency describing the ``version'' part.
+See the pool's rel2id method for a description of the flags.
 
        Selection Selection_name(int setflags = 0)
        my $sel = $dep->Selection_name();
@@ -829,7 +831,7 @@ Same as calling the str() method.
        if dep1 == dep2:
        if dep1 == dep2
 
-The dependencies are equal if they are part of the same pool and have the same
+Two dependencies are equal if they are part of the same pool and have the same
 ids.
 
 
@@ -908,7 +910,7 @@ timestamp.
 
 *REPO_REUSE_REPODATA*::
 Reuse the last repository data area (``repodata'') instead of creating a
-new one.
+new area.
 
 *REPO_NO_INTERNALIZE*::
 Do not internalize the added repository data. This is useful if
@@ -2192,7 +2194,7 @@ Allow the solver to downgrade packages without asking for confirmation
 Allow the solver to change the architecture of an installed package
 without asking for confirmation. Note that changes to/from noarch
 are always considered to be allowed.
-  
+
 *SOLVER_FLAG_ALLOW_VENDORCHANGE*::
 Allow the solver to change the vendor of an installed package
 without asking for confirmation. Each vendor is part of one or more
@@ -2251,7 +2253,7 @@ Install recommended or supplemented packages even if they have no
 connection to the current transaction. You can use this feature
 to implement a simple way for the user to install new recommended
 packages that were not available in the past.
-  
+
 *SOLVER_FLAG_NO_INFARCHCHECK*::
 Turn off the inferior architecture checking that is normally done
 by the solver. Normally, the solver allows only the installation
@@ -3023,7 +3025,7 @@ Use this flag if you want to map OBSOLETE elements to the UPGRADE type.
 *SOLVER_TRANSACTION_MERGE_ARCHCHANGES*::
 Do not add extra categories for every architecture change, instead cumulate
 them in one category.
-  
+
 *SOLVER_TRANSACTION_MERGE_VENDORCHANGES*::
 Do not add extra categories for every vendor change, instead cumulate
 them in one category.
index 8d855be..e24c1d8 100755 (executable)
@@ -636,10 +636,10 @@ foreach arg $::argv {
     puts "nothing matches '$arg'"
     exit 1
   }
-  if {[$sel flags] & $solv::Selection_SELECTION_FILELIST} {
+  if {[$sel cget -flags] & $solv::Selection_SELECTION_FILELIST} {
     puts "\[using file list match for '$arg']"
   }
-  if {[$sel flags] & $solv::Selection_SELECTION_PROVIDES} {
+  if {[$sel cget -flags] & $solv::Selection_SELECTION_PROVIDES} {
     puts "\[using capability match for '$arg']"
   }
   lappend jobs {*}[$sel jobs $cmdactionmap($cmd)]
index 03098e2..3174968 100644 (file)
@@ -420,19 +420,6 @@ endElement(struct solv_xmlparser *xmlp, int state, char *content)
     }
 }
 
-static void
-errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
-{
-  struct parsedata *pd = xmlp->userdata;
-  pool_debug(pd->pool, SOLV_ERROR, "repo_appdata: %s at line %u:%u\n", errstr, line, column);
-  pd->ret = -1;
-  if (pd->solvable)
-    {   
-      repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1); 
-      pd->solvable = 0;
-    }
-}
-
 static int
 repo_add_appdata_fn(Repo *repo, FILE *fp, int flags, const char *filename, Queue *owners)
 {
@@ -448,8 +435,13 @@ repo_add_appdata_fn(Repo *repo, FILE *fp, int flags, const char *filename, Queue
   pd.filename = filename;
   pd.owners = owners;
 
-  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
-  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    {
+      pool_debug(pd.pool, SOLV_ERROR, "repo_appdata: %s at line %u:%u\n", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
+      pd.ret = -1;
+      pd.solvable = solvable_free(pd.solvable, 1);
+    }
   solv_xmlparser_free(&pd.xmlp);
 
   solv_free(pd.desktop_file);
index a0c45ce..698d506 100644 (file)
@@ -444,8 +444,7 @@ repo_add_arch_pkg(Repo *repo, const char *fn, int flags)
   if (s && !s->name)
     {
       pool_error(pool, -1, "%s: package has no name", fn);
-      repo_free_solvable(repo, s - pool->solvables, 1);
-      s = 0;
+      s = solvable_free(s, 1);
     }
   if (s)
     {
@@ -728,7 +727,7 @@ finishsolvable(Repo *repo, Solvable *s)
     return;
   if (!s->name)
     {
-      repo_free_solvable(repo, s - pool->solvables, 1);
+      solvable_free(s, 1);
       return;
     }
   if (!s->arch)
index 255ecb1..9400e1e 100644 (file)
@@ -206,14 +206,6 @@ endElement(struct solv_xmlparser *xmlp, int state, char *content)
     }
 }
 
-static void
-errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
-{
-  struct parsedata *pd = xmlp->userdata;
-  pool_debug(pd->pool, SOLV_ERROR, "repo_comps: %s at line %u:%u\n", errstr, line, column);
-}
-
-
 int
 repo_add_comps(Repo *repo, FILE *fp, int flags)
 {
@@ -226,8 +218,9 @@ repo_add_comps(Repo *repo, FILE *fp, int flags)
   pd.repo = repo;
   pd.pool = repo->pool;
   pd.data = data;
-  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
-  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    pool_debug(pd.pool, SOLV_ERROR, "repo_comps: %s at line %u:%u\n", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
   solv_xmlparser_free(&pd.xmlp);
   join_freemem(&pd.jd);
 
index 68af2d5..f361900 100644 (file)
@@ -517,8 +517,7 @@ repo_add_content(Repo *repo, FILE *fp, int flags)
   if (s && !s->name)
     {
       pool_debug(pool, SOLV_ERROR, "repo_content: 'content' incomplete, no product solvable created!\n");
-      repo_free_solvable(repo, s - pool->solvables, 1);
-      s = 0;
+      s = solvable_free(s, 1);
     }
   if (s)
     {
index 14ddcc9..64bb86f 100644 (file)
@@ -224,10 +224,7 @@ repo_add_cudf(Repo *repo, Repo *installedrepo, FILE *fp, Queue *job, int flags)
       if (!*buf)
        {
          if (s && !repo && !isinstalled)
-           {
-             repo_free_solvable(repo, s - pool->solvables, 1);
-             s = 0;
-           }
+           s = solvable_free(s, 1);
          if (s)
            finishpackage(pool, s, keep, job);
          s = 0;
@@ -323,10 +320,7 @@ repo_add_cudf(Repo *repo, Repo *installedrepo, FILE *fp, Queue *job, int flags)
                {
                  isinstalled = 1;
                  if (!installedrepo)
-                   {
-                     repo_free_solvable(repo, s - pool->solvables, 1);
-                     s = 0;
-                   }
+                   s = solvable_free(s, 1);
                  else if (s->repo != installedrepo)
                    {
                      copysolvabledata(pool, s, installedrepo);
@@ -371,10 +365,7 @@ repo_add_cudf(Repo *repo, Repo *installedrepo, FILE *fp, Queue *job, int flags)
        }
     }
   if (s && !repo && !isinstalled)
-    {
-      repo_free_solvable(repo, s - pool->solvables, 1);
-      s = 0;
-    }
+    s = solvable_free(s, 1);
   if (s)
     finishpackage(pool, s, keep, job);
   solv_free(buf);
index 6af7f10..5dd79f4 100644 (file)
@@ -499,7 +499,7 @@ repo_add_debpackages(Repo *repo, FILE *fp, int flags)
       s = pool_id2solvable(pool, repo_add_solvable(repo));
       control2solvable(s, data, buf);
       if (!s->name)
-       repo_free_solvable(repo, s - pool->solvables, 1);
+       s = solvable_free(s, 1);
       if (l > ll)
         memmove(buf, p + 1, l - ll);
       l -= ll;
@@ -511,7 +511,7 @@ repo_add_debpackages(Repo *repo, FILE *fp, int flags)
       s = pool_id2solvable(pool, repo_add_solvable(repo));
       control2solvable(s, data, buf);
       if (!s->name)
-       repo_free_solvable(repo, s - pool->solvables, 1);
+       s = solvable_free(s, 1);
     }
   solv_free(buf);
   if (!(flags & REPO_NO_INTERNALIZE))
index 4eb340f..ad315da 100644 (file)
@@ -306,13 +306,6 @@ endElement(struct solv_xmlparser *xmlp, int state, char *content)
     }
 }
 
-void
-errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
-{
-  struct parsedata *pd = xmlp->userdata;
-  pd->ret = pool_error(pd->pool, -1, "repo_deltainfoxml: %s at line %u:%u", errstr, line, column);
-}
-
 int
 repo_add_deltainfoxml(Repo *repo, FILE *fp, int flags)
 {
@@ -327,8 +320,9 @@ repo_add_deltainfoxml(Repo *repo, FILE *fp, int flags)
   pd.pool = pool;
   pd.repo = repo;
   pd.data = data;
-  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
-  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+     pd.ret = pool_error(pd.pool, -1, "repo_deltainfoxml: %s at line %u:%u", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
   solv_xmlparser_free(&pd.xmlp);
 
   /* now commit all handles */
index 3c2c6d1..37359bb 100644 (file)
@@ -674,14 +674,6 @@ endElement(struct solv_xmlparser *xmlp, int state, char *content)
     }
 }
 
-static void
-errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
-{
-  struct parsedata *pd = xmlp->userdata;
-  pd->ret = pool_error(pd->pool, -1, "%s at line %u", errstr, line);
-}
-
-
 /*-------------------------------------------------------------------*/
 
 /*
@@ -706,14 +698,14 @@ repo_add_helix(Repo *repo, FILE *fp, int flags)
   pd.pool = pool;
   pd.repo = repo;
   pd.data = data;
-  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
 
   pd.evrspace = (char *)solv_malloc(256);
   pd.aevrspace = 256;
   pd.levrspace = 1;
 
-  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
-  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    pd.ret = pool_error(pd.pool, -1, "repo_helix: %s at line %u", pd.xmlp.errstr, pd.xmlp.line);
   solv_xmlparser_free(&pd.xmlp);
 
   solv_free(pd.evrspace);
index 418bc61..4d3e102 100644 (file)
@@ -230,7 +230,7 @@ repo_add_mdk(Repo *repo, FILE *fp, int flags)
   if (s)
     {
       pool_debug(pool, SOLV_ERROR, "unclosed package at EOF\n");
-      repo_free_solvable(s->repo, s - pool->solvables, 1);
+      s = solvable_free(s, 1);
     }
   solv_free(buf);
   if (!(flags & REPO_NO_INTERNALIZE))
@@ -437,14 +437,6 @@ endElement(struct solv_xmlparser *xmlp, int state, char *content)
     }
 }
 
-static void
-errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
-{
-  struct parsedata *pd = xmlp->userdata;
-  pool_debug(pd->pool, SOLV_ERROR, "%s at line %u:%u\n", errstr, line, column);
-}
-
-
 int
 repo_add_mdk_info(Repo *repo, FILE *fp, int flags)
 {
@@ -463,9 +455,10 @@ repo_add_mdk_info(Repo *repo, FILE *fp, int flags)
   pd.repo = repo;
   pd.pool = repo->pool;
   pd.data = data;
-  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
   pd.joinhash = joinhash_init(repo, &pd.joinhashmask);
-  solv_xmlparser_parse(&pd.xmlp, fp);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    pool_debug(pd.pool, SOLV_ERROR, "%s at line %u:%u\n", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
   solv_xmlparser_free(&pd.xmlp);
   solv_free(pd.joinhash);
   if (!(flags & REPO_NO_INTERNALIZE))
index 154a909..edf15bf 100644 (file)
@@ -291,19 +291,6 @@ endElement(struct solv_xmlparser *xmlp, int state, char *content)
     }
 }
 
-static void
-errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
-{
-  struct parsedata *pd = xmlp->userdata;
-  pool_debug(pd->pool, SOLV_ERROR, "%s: %s at line %u:%u\n", pd->filename, errstr, line, column);
-  if (pd->solvable)
-    {   
-      repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1); 
-      pd->solvable = 0;
-    }   
-}
-
-
 int
 repo_add_code11_products(Repo *repo, const char *dirpath, int flags)
 {
@@ -318,7 +305,7 @@ repo_add_code11_products(Repo *repo, const char *dirpath, int flags)
   pd.pool = repo->pool;
   pd.data = data;
 
-  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
 
   if (flags & REPO_USE_ROOTDIR)
     dirpath = pool_prepend_rootdir(repo->pool, dirpath);
@@ -358,7 +345,11 @@ repo_add_code11_products(Repo *repo, const char *dirpath, int flags)
          pd.ctime = (unsigned int)st.st_ctime;
          pd.filename = fullpath;
          pd.basename = entry->d_name;
-         solv_xmlparser_parse(&pd.xmlp, fp);
+         if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+           {
+             pool_debug(pd.pool, SOLV_ERROR, "%s: %s at line %u:%u\n", pd.filename, pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
+             pd.solvable = solvable_free(pd.solvable, 1);
+           }
          fclose(fp);
        }
       closedir(dir);
index 760d481..fd46272 100644 (file)
@@ -329,13 +329,6 @@ endElement(struct solv_xmlparser *xmlp, int state, char *content)
     }
 }
 
-static void
-errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
-{
-  struct parsedata *pd = xmlp->userdata;
-  pd->ret = pool_error(pd->pool, -1, "repo_repomdxml: %s at line %u:%u", errstr, line, column);
-}
-
 int
 repo_add_repomdxml(Repo *repo, FILE *fp, int flags)
 {
@@ -350,9 +343,9 @@ repo_add_repomdxml(Repo *repo, FILE *fp, int flags)
   pd.pool = pool;
   pd.repo = repo;
   pd.data = data;
-  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
-
-  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    pd.ret = pool_error(pd.pool, -1, "repo_repomdxml: %s at line %u:%u", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
   solv_xmlparser_free(&pd.xmlp);
 
   if (!(flags & REPO_NO_INTERNALIZE))
index a2d518f..9acb400 100644 (file)
@@ -1661,9 +1661,8 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
       if (s)
        {
          /* oops, could not reuse. free it instead */
-          repo_free_solvable(repo, s - pool->solvables, 1);
+          s = solvable_free(s, 1);
          solvend--;
-         s = 0;
        }
       /* now sort all solvables in the new solvstart..solvend block */
       if (solvend - solvstart > 1)
@@ -2044,7 +2043,7 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   s = pool_id2solvable(pool, repo_add_solvable(repo));
   if (!rpmhead2solv(pool, repo, data, s, state.rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID)))
     {
-      repo_free_solvable(repo, s - pool->solvables, 1);
+      s = solvable_free(s, 1);
       solv_chksum_free(chksumh, 0);
       headfree(state.rpmhead);
       return 0;
@@ -2096,7 +2095,7 @@ repo_add_rpm_handle(Repo *repo, void *rpmhandle, int flags)
   s = pool_id2solvable(pool, repo_add_solvable(repo));
   if (!rpmhead2solv(pool, repo, data, s, rpmhead, flags))
     {
-      repo_free_solvable(repo, s - pool->solvables, 1);
+      s = solvable_free(s, 1);
       return 0;
     }
   if (!(flags & REPO_NO_INTERNALIZE))
index 9f49bd3..9bb50a0 100644 (file)
@@ -1091,13 +1091,6 @@ endElement(struct solv_xmlparser *xmlp, int state, char *content)
     }
 }
 
-static void
-errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
-{
-  struct parsedata *pd = xmlp->userdata;
-  pd->ret = pool_error(pd->pool, -1, "repo_rpmmd: %s at line %u:%u", errstr, line, column);
-}
-
 
 /*-----------------------------------------------*/
 
@@ -1135,8 +1128,9 @@ repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags)
       fill_cshash_from_repo(&pd);
     }
 
-  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
-  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    pd.ret = pool_error(pool, -1, "repo_rpmmd: %s at line %u:%u", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
   solv_xmlparser_free(&pd.xmlp);
 
   solv_free(pd.lastdirstr);
index 7ba0062..ff84d32 100644 (file)
@@ -427,13 +427,6 @@ endElement(struct solv_xmlparser *xmlp, int state, char *content)
     }
 }
 
-static void
-errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
-{
-  struct parsedata *pd = xmlp->userdata;
-  pd->ret = pool_error(pd->pool, -1, "repo_updateinfoxml: %s at line %u:%u", errstr, line, column);
-}
-
 int
 repo_add_updateinfoxml(Repo *repo, FILE *fp, int flags)
 {
@@ -447,8 +440,9 @@ repo_add_updateinfoxml(Repo *repo, FILE *fp, int flags)
   pd.pool = pool;
   pd.repo = repo;
   pd.data = data;
-  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
-  solv_xmlparser_parse(&pd.xmlp, fp);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
+  if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+    pd.ret = pool_error(pool, -1, "repo_updateinfoxml: %s at line %u:%u", pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
   solv_xmlparser_free(&pd.xmlp);
   join_freemem(&pd.jd);
 
index d73a900..f6e2bfa 100644 (file)
@@ -138,18 +138,6 @@ endElement(struct solv_xmlparser *xmlp, int state, char *content)
     }
 }
 
-static void
-errorCallback(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
-{
-  struct parsedata *pd = xmlp->userdata;
-  pool_debug(pd->pool, SOLV_ERROR, "repo_zyppdb: %s: %s at line %u:%u\n", pd->filename, errstr, line, column);
-  if (pd->solvable)
-    {
-      repo_free_solvable(pd->repo, pd->solvable - pd->pool->solvables, 1);
-      pd->solvable = 0;
-    }
-}
-
 
 /*
  * read all installed products
@@ -172,7 +160,7 @@ repo_add_zyppdb_products(Repo *repo, const char *dirpath, int flags)
   pd.repo = repo;
   pd.pool = repo->pool;
   pd.data = data;
-  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement, errorCallback);
+  solv_xmlparser_init(&pd.xmlp, stateswitches, &pd, startElement, endElement);
 
   if (flags & REPO_USE_ROOTDIR)
     dirpath = pool_prepend_rootdir(repo->pool, dirpath);
@@ -190,7 +178,11 @@ repo_add_zyppdb_products(Repo *repo, const char *dirpath, int flags)
              continue;
            }
           pd.filename = entry->d_name;
-         solv_xmlparser_parse(&pd.xmlp, fp);
+         if (solv_xmlparser_parse(&pd.xmlp, fp) != SOLV_XMLPARSER_OK)
+           {
+             pool_debug(pd.pool, SOLV_ERROR, "repo_zyppdb: %s: %s at line %u:%u\n", pd.filename, pd.xmlp.errstr, pd.xmlp.line, pd.xmlp.column);
+             pd.solvable = solvable_free(pd.solvable, 1);
+           }
          fclose(fp);
        }
     }
diff --git a/ext/solv_jsonparser.c b/ext/solv_jsonparser.c
new file mode 100644 (file)
index 0000000..053ee6f
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * solv_jsonparser.c
+ *
+ * Simple JSON stream parser
+ *
+ * Copyright (c) 2018, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "solv_jsonparser.h"
+
+struct solv_jsonparser *
+jsonparser_init(struct solv_jsonparser *jp, FILE *fp)
+{
+  memset(jp, 0, sizeof(*jp));
+  jp->fp = fp;
+  jp->state = JP_START;
+  jp->line = jp->nextline = 1;
+  jp->nextc = ' ';
+  queue_init(&jp->stateq);
+  return jp;
+}
+
+struct solv_jsonparser *
+jsonparser_free(struct solv_jsonparser *jp)
+{
+  queue_free(&jp->stateq);
+  return 0;
+}
+
+static void
+savec(struct solv_jsonparser *jp, char c)
+{
+  if (jp->nspace == jp->aspace)
+    {
+      jp->aspace += 256;
+      jp->space = solv_realloc(jp->space, jp->aspace);
+    }
+  jp->space[jp->nspace++] = c;
+}
+
+static void
+saveutf8(struct solv_jsonparser *jp, int c)
+{
+  int i;
+  if (c < 0x80)
+    {
+      savec(jp, c);
+      return;
+    }
+  i = c < 0x800 ? 1 : c < 0x10000 ? 2 : 3;
+  savec(jp, (0x1f80 >> i) | (c >> (6 * i)));
+  while (--i >= 0)
+    savec(jp, 0x80 | ((c >> (6 * i)) & 0x3f));
+}
+
+static inline int
+nextc(struct solv_jsonparser *jp)
+{
+  int c = getc(jp->fp);
+  if (c == '\n')
+    jp->nextline++;
+  return c;
+}
+
+static int
+skipspace(struct solv_jsonparser *jp)
+{
+  int c = jp->nextc;
+  while (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+    c = nextc(jp);
+  jp->line = jp->nextline;
+  return (jp->nextc = c);
+}
+
+static int
+parseliteral(struct solv_jsonparser *jp)
+{
+  size_t nspace = jp->nspace;
+  int c;
+  savec(jp, jp->nextc);
+  for (;;)
+    {
+      c = nextc(jp);
+      if (c < 'a' || c > 'z')
+       break;
+      savec(jp, c);
+    }
+  jp->nextc = c;
+  savec(jp, 0);
+  if (!strcmp(jp->space + nspace, "true"))
+    return JP_BOOL;
+  if (!strcmp(jp->space + nspace, "false"))
+    return JP_BOOL;
+  if (!strcmp(jp->space + nspace, "null"))
+    return JP_NULL;
+  return JP_ERROR;
+}
+
+static int
+parsenumber(struct solv_jsonparser *jp)
+{
+  int c;
+  savec(jp, jp->nextc);
+  for (;;)
+    {
+      c = nextc(jp);
+      if ((c < '0' || c > '9') && c != '+' && c != '-' && c != '.' && c != 'e' && c != 'E')
+       break;
+      savec(jp, c);
+    }
+  jp->nextc = c;
+  savec(jp, 0);
+  return JP_NUMBER;
+}
+
+static int
+parseutf8(struct solv_jsonparser *jp, int surrogate)
+{
+  int c, i, r = 0;
+  /* parse 4-digit hex */
+  for (i = 0; i < 4; i++)
+    {
+      c = nextc(jp);
+      if (c >= '0' && c <= '9')
+       c -= '0';
+      else if (c >= 'a' && c <= 'f')
+       c -= 'a' - 10;
+      else if (c >= 'A' && c <= 'F')
+       c -= 'A' - 10;
+      else
+       return -1;
+      r = (r << 4) | c;
+    }
+  if (!surrogate && r >= 0xd800 && r < 0xdc00)
+    {
+      /* utf16 surrogate pair encodes 0x10000 - 0x10ffff */
+      int r2;
+      if (nextc(jp) != '\\' || nextc(jp) != 'u' || (r2 = parseutf8(jp, 1)) < 0xdc00 || r2 >= 0xe000)
+       return -1;
+      r = 0x10000 + ((r & 0x3ff) << 10 | (r2 & 0x3ff));
+    }
+  return r;
+}
+
+static int
+parsestring(struct solv_jsonparser *jp)
+{
+  int c;
+  for (;;)
+    {
+      if ((c = nextc(jp)) < 32)
+       return JP_ERROR;
+      if (c == '"')
+       break;
+      if (c == '\\')
+       {
+         switch (c = nextc(jp))
+           {
+           case '"':
+           case '\\':
+           case '/':
+           case '\n':
+             break;
+           case 'b':
+             c = '\b';
+             break;
+           case 'f':
+             c = '\f';
+             break;
+           case 'n':
+             c = '\n';
+             break;
+           case 'r':
+             c = '\r';
+             break;
+           case 't':
+             c = '\t';
+             break;
+           case 'u':
+             if ((c = parseutf8(jp, 0)) < 0)
+               return JP_ERROR;
+             saveutf8(jp, c);
+             continue;
+           default:
+             return JP_ERROR;
+           }
+       }
+      savec(jp, c);
+    }
+  jp->nextc = ' ';
+  savec(jp, 0);
+  return JP_STRING;
+}
+
+static int
+parsevalue(struct solv_jsonparser *jp)
+{
+  int c = skipspace(jp);
+  if (c == '"')
+    return parsestring(jp);
+  if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
+    return parsenumber(jp);
+  if ((c >= 'a' && c <= 'z'))
+    return parseliteral(jp);
+  jp->nextc = ' ';
+  if (c == '[')
+    return JP_ARRAY;
+  if (c == '{')
+    return JP_OBJECT;
+  if (c == ']')
+    return JP_ARRAY_END;
+  if (c == '}')
+    return JP_OBJECT_END;
+  return JP_ERROR;
+}
+
+int
+jsonparser_parse(struct solv_jsonparser *jp)
+{
+  int type;
+  size_t nspace;
+
+  jp->depth = jp->stateq.count;
+  jp->key = jp->value = 0;
+  jp->keylen = jp->valuelen = 0;
+  nspace = jp->nspace = 0;
+
+  if (jp->state == JP_END)
+    return JP_END;
+  if (jp->state == JP_START)
+    jp->state = JP_END;
+  type = parsevalue(jp);
+  if (type <= 0)
+    return JP_ERROR;
+  if (type == JP_OBJECT_END || type == JP_ARRAY_END)
+    {
+      if (jp->state != type - 1)
+        return JP_ERROR;
+      jp->state = queue_pop(&jp->stateq);
+    }
+  else if (jp->state == JP_OBJECT)
+    {
+      nspace = jp->nspace;
+      if (type != JP_STRING)
+       return JP_ERROR;
+      if (skipspace(jp) != ':')
+       return JP_ERROR;
+      jp->nextc = ' ';
+      type = parsevalue(jp);
+      if (type == JP_OBJECT_END || type == JP_ARRAY_END)
+       return JP_ERROR;
+      jp->key = jp->space;
+      jp->keylen = nspace - 1;
+    }
+  if (type == JP_STRING || type == JP_NUMBER || type == JP_BOOL || type == JP_NULL)
+    {
+      jp->value = jp->space + nspace;
+      jp->valuelen = jp->nspace - nspace - 1;
+    }
+  if (type == JP_ARRAY || type == JP_OBJECT)
+    {
+      queue_push(&jp->stateq, jp->state);
+      jp->state = type;
+    }
+  else if (jp->state == JP_OBJECT || jp->state == JP_ARRAY)
+    {
+      int c = skipspace(jp);
+      if (c == ',')
+       jp->nextc = ' ';
+      else if (c != (jp->state == JP_OBJECT ? '}' : ']'))
+       return JP_ERROR;
+    }
+  return type;
+}
+
+int
+jsonparser_skip(struct solv_jsonparser *jp, int type)
+{
+  if (type == JP_ARRAY || type == JP_OBJECT)
+    {
+      int depth = jp->depth + 1, endtype = type + 1;
+      while (type > 0 && (type != endtype || jp->depth != depth))
+        type = jsonparser_parse(jp);
+    }
+  return type;
+}
+
diff --git a/ext/solv_jsonparser.h b/ext/solv_jsonparser.h
new file mode 100644 (file)
index 0000000..d58d9e3
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#ifndef SOLV_JSONPARSER_H
+#define SOLV_JSONPARSER_H
+
+#include "queue.h"
+
+struct solv_jsonparser {
+  FILE *fp;
+  int line;
+  int depth;
+
+  char *key;
+  size_t keylen;
+  char *value;
+  size_t valuelen;
+
+  int state;
+  Queue stateq;
+  int nextc;
+  int nextline;
+  char *space;
+  size_t nspace;
+  size_t aspace;
+};
+
+#define JP_ERROR       -1
+#define JP_END         0
+#define JP_START       1
+#define JP_STRING      2
+#define JP_NUMBER      3
+#define JP_BOOL                4
+#define JP_NULL                5
+#define JP_OBJECT      6
+#define JP_OBJECT_END  7
+#define JP_ARRAY       8
+#define JP_ARRAY_END   9
+
+struct solv_jsonparser *jsonparser_init(struct solv_jsonparser *jp, FILE *fp);
+struct solv_jsonparser *jsonparser_free(struct solv_jsonparser *jp);
+int jsonparser_parse(struct solv_jsonparser *jp);
+int jsonparser_skip(struct solv_jsonparser *jp, int type);
+
+#endif /* SOLV_JSONPARSER_H */
index 170520f..6292663 100644 (file)
@@ -132,8 +132,7 @@ solv_xmlparser_init(struct solv_xmlparser *xmlp,
     struct solv_xmlparser_element *elements,
     void *userdata,
     void (*startelement)(struct solv_xmlparser *, int state, const char *name, const char **atts),
-    void (*endelement)(struct solv_xmlparser *, int state, char *content),
-    void (*errorhandler)(struct solv_xmlparser *, const char *errstr, unsigned int line, unsigned int column))
+    void (*endelement)(struct solv_xmlparser *, int state, char *content))
 {
   int i, nstates, nelements;
   struct solv_xmlparser_element *el;
@@ -169,7 +168,6 @@ solv_xmlparser_init(struct solv_xmlparser *xmlp,
   xmlp->userdata = userdata;
   xmlp->startelement = startelement;
   xmlp->endelement = endelement;
-  xmlp->errorhandler = errorhandler;
 }
 
 void
@@ -178,6 +176,16 @@ solv_xmlparser_free(struct solv_xmlparser *xmlp)
   xmlp->elementhelper = solv_free(xmlp->elementhelper);
   queue_free(&xmlp->elementq);
   xmlp->content = solv_free(xmlp->content);
+  xmlp->errstr = solv_free(xmlp->errstr);
+}
+
+static void
+set_error(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column)
+{
+  solv_free(xmlp->errstr);
+  xmlp->errstr = solv_strdup(errstr);
+  xmlp->line = line;
+  xmlp->column = column;
 }
 
 #ifdef WITH_LIBXML2
@@ -197,7 +205,8 @@ free_parser(struct solv_xmlparser *xmlp)
   xmlp->parser = 0;
 }
 
-static xmlParserCtxtPtr create_parser_ctx(struct solv_xmlparser *xmlp, char *buf, int l)
+static xmlParserCtxtPtr
+create_parser_ctx(struct solv_xmlparser *xmlp, char *buf, int l)
 {
   xmlSAXHandler sax;
   memset(&sax, 0, sizeof(sax));
@@ -216,7 +225,7 @@ parse_block(struct solv_xmlparser *xmlp, char *buf, int l)
       xmlp->parser = create_parser_ctx(xmlp, buf, l2);
       if (!xmlp->parser)
        {
-         xmlp->errorhandler(xmlp, "could not create parser", 0, 0);
+         set_error(xmlp, "could not create parser", 0, 0);
          return 0;
        }
       buf += l2;
@@ -227,7 +236,7 @@ parse_block(struct solv_xmlparser *xmlp, char *buf, int l)
   if (xmlParseChunk(xmlp->parser, buf, l, l == 0 ? 1 : 0))
     {
       xmlErrorPtr err = xmlCtxtGetLastError(xmlp->parser);
-      xmlp->errorhandler(xmlp, err->message, err->line, err->int2);
+      set_error(xmlp, err->message, err->line, err->int2);
       return 0;
     }
   return 1;
@@ -265,9 +274,7 @@ parse_block(struct solv_xmlparser *xmlp, char *buf, int l)
 {
   if (XML_Parse(xmlp->parser, buf, l, l == 0) == XML_STATUS_ERROR)
     {
-      unsigned int line = XML_GetCurrentLineNumber(xmlp->parser);
-      unsigned int column = XML_GetCurrentColumnNumber(xmlp->parser);
-      xmlp->errorhandler(xmlp, XML_ErrorString(XML_GetErrorCode(xmlp->parser)), line, column);
+      set_error(xmlp, XML_ErrorString(XML_GetErrorCode(xmlp->parser)), XML_GetCurrentLineNumber(xmlp->parser), XML_GetCurrentColumnNumber(xmlp->parser));
       return 0;
     }
   return 1;
@@ -281,11 +288,11 @@ solv_xmlparser_lineno(struct solv_xmlparser *xmlp)
 
 #endif
 
-void
+int
 solv_xmlparser_parse(struct solv_xmlparser *xmlp, FILE *fp)
 {
   char buf[8192];
-  int l;
+  int l, ret = SOLV_XMLPARSER_OK;
 
   xmlp->state = 0;
   xmlp->unknowncnt = 0;
@@ -295,16 +302,22 @@ solv_xmlparser_parse(struct solv_xmlparser *xmlp, FILE *fp)
 
   if (!create_parser(xmlp))
     {
-      xmlp->errorhandler(xmlp, "could not create xml parser", 0, 0);
-      return;
+      set_error(xmlp, "could not create parser", 0, 0);
+      return SOLV_XMLPARSER_ERROR;
     }
   for (;;)
     {
       l = fread(buf, 1, sizeof(buf), fp);
-      if (!parse_block(xmlp, buf, l) || !l)
+      if (!parse_block(xmlp, buf, l))
+       {
+         ret = SOLV_XMLPARSER_ERROR;
+         break;
+       }
+      if (!l)
        break;
     }
   free_parser(xmlp);
+  return ret;
 }
 
 char *
index 9fb342f..ced0571 100644 (file)
@@ -8,6 +8,9 @@ struct solv_xmlparser_element {
 
 struct solv_xmlparser {
   void *userdata;
+  char *errstr;
+  unsigned int line;
+  unsigned int column;
 
   int state;
   int docontent;
@@ -24,12 +27,14 @@ struct solv_xmlparser {
 
   void (*startelement)(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts);
   void (*endelement)(struct solv_xmlparser *xmlp, int state, char *content);
-  void (*errorhandler)(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column);
 
   Id *elementhelper;
   void *parser;
 };
 
+#define SOLV_XMLPARSER_OK      0
+#define SOLV_XMLPARSER_ERROR   -1
+
 static inline const char *
 solv_xmlparser_find_attr(const char *txt, const char **atts)
 {
@@ -41,11 +46,10 @@ solv_xmlparser_find_attr(const char *txt, const char **atts)
 
 extern void solv_xmlparser_init(struct solv_xmlparser *xmlp, struct solv_xmlparser_element *elements, void *userdata,
     void (*startelement)(struct solv_xmlparser *xmlp, int state, const char *name, const char **atts),
-    void (*endelement)(struct solv_xmlparser *xmlp, int state, char *content),
-    void (*errorhandler)(struct solv_xmlparser *xmlp, const char *errstr, unsigned int line, unsigned int column));
+    void (*endelement)(struct solv_xmlparser *xmlp, int state, char *content));
 
 extern void solv_xmlparser_free(struct solv_xmlparser *xmlp);
-extern void solv_xmlparser_parse(struct solv_xmlparser *xmlp, FILE *fp);
+extern int solv_xmlparser_parse(struct solv_xmlparser *xmlp, FILE *fp);
 unsigned int solv_xmlparser_lineno(struct solv_xmlparser *xmlp);
 char *solv_xmlparser_contentspace(struct solv_xmlparser *xmlp, int l);
 
index ffc8b8a..b815c56 100644 (file)
@@ -15,6 +15,7 @@
 #include "pool.h"
 #include "poolarch.h"
 #include "poolvendor.h"
+#include "evr.h"
 #include "repo.h"
 #include "repo_solv.h"
 #include "solver.h"
@@ -121,6 +122,7 @@ static struct solverflags2str {
   { SOLVER_FLAG_FOCUS_BEST,                 "focusbest", 0 },
   { SOLVER_FLAG_STRONG_RECOMMENDS,          "strongrecommends", 0 },
   { SOLVER_FLAG_INSTALL_ALSO_UPDATES,       "installalsoupdates", 0 },
+  { SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED, "onlynamespacerecommended", 0 },
   { 0, 0, 0 }
 };
 
@@ -1071,7 +1073,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp)
       Queue q;
       job |= SOLVER_SOLVABLE_ONE_OF;
       queue_init(&q);
-      if (npieces > 3 && strcmp(pieces[2], "nothing") != 0)
+      if (npieces > 2 && strcmp(pieces[2], "nothing") != 0)
        {
          for (i = 2; i < npieces; i++)
            {
@@ -2966,6 +2968,14 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
            }
          queue_push(&autoinstq, pool_str2id(pool, pieces[2], 1));
        }
+      else if (!strcmp(pieces[0], "evrcmp") && npieces == 3)
+       {
+         Id evr1 = pool_str2id(pool, pieces[1], 1);
+         Id evr2 = pool_str2id(pool, pieces[2], 1);
+         int r = pool_evrcmp(pool, evr1, evr2, EVRCMP_COMPARE);
+         r = r < 0 ? REL_LT : r > 0 ? REL_GT : REL_EQ;
+         queue_push2(job, SOLVER_NOOP | SOLVER_SOLVABLE_PROVIDES, pool_rel2id(pool, evr1, evr2, r, 1));
+       }
       else
        {
          pool_error(pool, 0, "testcase_read: cannot parse command '%s'", pieces[0]);
index 5467ee3..53bfc30 100644 (file)
@@ -1,4 +1,14 @@
 -------------------------------------------------------------------
+Fri Dec  7 15:10:46 CET 2018 - mls@suse.de
+
+- do not autouninstall packages because of forcebest updates
+- support rpm's new '^' version separator
+- support set/get_considered_list in bindings
+- new experimental SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED flag
+  [fate#325513]
+- bump version to 0.7.2
+
+-------------------------------------------------------------------
 Wed Oct 31 13:50:22 CET 2018 - mls@suse.de
 
 - fix nasty off-by-one error in repo_write
index a7d4311..c63878e 100644 (file)
--- a/src/evr.c
+++ b/src/evr.c
@@ -77,10 +77,10 @@ solv_vercmp_rpm(const char *s1, const char *q1, const char *s2, const char *q2)
   for (;;)
     {
       while (s1 < q1 && !(*s1 >= '0' && *s1 <= '9') &&
-          !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z') && *s1 != '~')
+          !(*s1 >= 'a' && *s1 <= 'z') && !(*s1 >= 'A' && *s1 <= 'Z') && *s1 != '~' && *s1 != '^')
        s1++;
       while (s2 < q2 && !(*s2 >= '0' && *s2 <= '9') &&
-          !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z') && *s2 != '~')
+          !(*s2 >= 'a' && *s2 <= 'z') && !(*s2 >= 'A' && *s2 <= 'Z') && *s2 != '~' && *s2 != '^')
        s2++;
       if (s1 < q1 && *s1 == '~')
         {
@@ -94,6 +94,18 @@ solv_vercmp_rpm(const char *s1, const char *q1, const char *s2, const char *q2)
         }
       if (s2 < q2 && *s2 == '~')
        return 1;
+      if (s1 < q1 && *s1 == '^')
+       {
+         if (s2 < q2 && *s2 == '^')
+           {
+             s1++;
+             s2++;
+             continue;
+           }
+         return s2 < q2 ? -1 : 1;
+       }
+      if (s2 < q2 && *s2 == '^')
+       return s1 < q1 ? 1 : -1;
       if (s1 >= q1 || s2 >= q2)
        break;
       if ((*s1 >= '0' && *s1 <= '9') || (*s2 >= '0' && *s2 <= '9'))
index df751c4..2b5cefd 100644 (file)
@@ -247,8 +247,23 @@ solver_autouninstall(Solver *solv, int start)
       if (v >= solv->updaterules && v < solv->updaterules_end)
        {
          Rule *r;
+         Id p = solv->installed->start + (v - solv->updaterules);
          if (m && !MAPTST(m, v - solv->updaterules))
            continue;
+         if (pool->considered && !MAPTST(pool->considered, p))
+           continue;   /* do not uninstalled disabled packages */
+         if (solv->bestrules_pkg && solv->bestrules_end > solv->bestrules)
+           {
+             int j;
+             for (j = start + 1; j < solv->problems.count - 1; j++)
+               {
+                 Id vv = solv->problems.elements[j];
+                 if (vv >= solv->bestrules && vv < solv->bestrules_end && solv->bestrules_pkg[vv - solv->bestrules] == p)
+                   break;
+               }
+             if (j < solv->problems.count - 1)
+               continue;       /* best rule involved, do not uninstall */
+           }
          /* check if identical to feature rule, we don't like that (except for orphans) */
          r = solv->rules + solv->featurerules + (v - solv->updaterules);
          if (!r->p)
@@ -260,7 +275,7 @@ solver_autouninstall(Solver *solv, int start)
              if (solv->keep_orphans)
                {
                  r = solv->rules + v;
-                 if (!r->d && !r->w2 && r->p == (solv->installed->start + (v - solv->updaterules)))
+                 if (!r->d && !r->w2 && r->p == p)
                    {
                      lastfeature = v;
                      lastupdate = 0;
index 4abfb0f..58704f1 100644 (file)
@@ -101,20 +101,18 @@ static inline int pool_disabled_solvable(const Pool *pool, Solvable *s)
 
 static inline int pool_badarch_solvable(const Pool *pool, Solvable *s)
 {
-  if (!s->arch)
-    return 1;
-  if (pool->id2arch && pool_arch2score(pool, s->arch) == 0)
+  if (pool->id2arch && (!s->arch || pool_arch2score(pool, s->arch) == 0))
     return 1;
   return 0;
 }
 
 static inline int pool_installable(const Pool *pool, Solvable *s)
 {
-  if (!s->arch || s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+  if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
     return 0;
   if (s->repo && s->repo->disabled)
     return 0;
-  if (pool->id2arch && pool_arch2score(pool, s->arch) == 0)
+  if (pool->id2arch && (!s->arch || pool_arch2score(pool, s->arch) == 0))
     return 0;
   if (pool->considered)
     {
@@ -125,6 +123,14 @@ static inline int pool_installable(const Pool *pool, Solvable *s)
   return 1;
 }
 
+/* not in solvable.h because we need the repo definition */
+static inline Solvable *solvable_free(Solvable *s, int reuseids)
+{
+  if (s && s->repo)
+    repo_free_solvable(s->repo, s - s->repo->pool->solvables, reuseids);
+  return 0;
+}
+
 /* search callback values */
 #define SEARCH_NEXT_KEY         1
 #define SEARCH_NEXT_SOLVABLE    2
index a4e0c4b..57fa3e4 100644 (file)
@@ -1443,6 +1443,8 @@ solver_get_flag(Solver *solv, int flag)
     return solv->strongrecommends;
   case SOLVER_FLAG_INSTALL_ALSO_UPDATES:
     return solv->install_also_updates;
+  case SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED:
+    return solv->only_namespace_recommended;
   default:
     break;
   }
@@ -1533,6 +1535,9 @@ solver_set_flag(Solver *solv, int flag, int value)
   case SOLVER_FLAG_INSTALL_ALSO_UPDATES:
     solv->install_also_updates = value;
     break;
+  case SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED:
+    solv->only_namespace_recommended = value;
+    break;
   default:
     break;
   }
@@ -2092,12 +2097,14 @@ resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, i
          Id *recp, rec, pp, p;
          if (!solv->addalreadyrecommended && s->repo == solv->installed)
            continue;
-         /* XXX need to special case AND ? */
          if (s->recommends)
            {
              recp = s->repo->idarraydata + s->recommends;
              while ((rec = *recp++) != 0)
                {
+                 /* cheat: we just look if there is REL_NAMESPACE in the dep */
+                 if (solv->only_namespace_recommended && !solver_is_namespace_dep(solv, rec))
+                   continue;
 #ifdef ENABLE_COMPLEX_DEPS
                  if (pool_is_complex_dep(pool, rec))
                    {
@@ -2186,7 +2193,7 @@ resolve_weak(Solver *solv, int level, int disablerules, Queue *dq, Queue *dqs, i
     }
 
   /* filter out all already supplemented packages if requested */
-  if (!solv->addalreadyrecommended && dqs->count)
+  if ((!solv->addalreadyrecommended || solv->only_namespace_recommended) && dqs->count)
     {
       /* filter out old supplements */
       for (i = j = 0; i < dqs->count; i++)
@@ -3245,7 +3252,7 @@ solver_solve(Solver *solv, Queue *job)
   POOL_DEBUG(SOLV_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allownamechange=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allownamechange, solv->allowarchchange, solv->allowvendorchange);
   POOL_DEBUG(SOLV_DEBUG_STATS, "promoteepoch=%d, forbidselfconflicts=%d\n", pool->promoteepoch, pool->forbidselfconflicts);
   POOL_DEBUG(SOLV_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d, obsoleteusescolors=%d, implicitobsoleteusescolors=%d\n", pool->obsoleteusesprovides, pool->implicitobsoleteusesprovides, pool->obsoleteusescolors, pool->implicitobsoleteusescolors);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended);
+  POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d onlynamespacerecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended, solv->only_namespace_recommended);
 
   /* create whatprovides if not already there */
   if (!pool->whatprovides)
index 4c85b4d..6fc2e9f 100644 (file)
@@ -167,6 +167,7 @@ struct s_Solver {
   int urpmreorder;                     /* true: do special urpm package reordering */
   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 process_orphans;                 /* true: do special orphan processing */
   Map dupmap;                          /* dup to those packages */
@@ -317,6 +318,7 @@ typedef struct s_Solver Solver;
 #define SOLVER_FLAG_FOCUS_BEST                 24
 #define SOLVER_FLAG_STRONG_RECOMMENDS          25
 #define SOLVER_FLAG_INSTALL_ALSO_UPDATES       26
+#define SOLVER_FLAG_ONLY_NAMESPACE_RECOMMENDED 27
 
 #define GET_USERINSTALLED_NAMES                        (1 << 0)        /* package names instead of ids */
 #define GET_USERINSTALLED_INVERTED             (1 << 1)        /* autoinstalled */
index e92617d..406b304 100644 (file)
@@ -21,6 +21,7 @@ extern int solver_dep_possible_slow(Solver *solv, Id dep, Map *m);
 extern int solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd);
 extern int solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s);
 extern void solver_intersect_obsoleted(Solver *solv, Id p, Queue *q, int qstart, Map *m);
+extern int solver_is_namespace_dep_slow(Solver *solv, Reldep *rd);
 
 extern void solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded);
 extern int solver_check_cleandeps_mistakes(Solver *solv);
@@ -92,4 +93,21 @@ solver_is_enhancing(Solver *solv, Solvable *s)
   return 0;
 }
 
+static inline int
+solver_is_namespace_dep(Solver *solv, Id dep)
+{
+  Pool *pool = solv->pool;
+  Reldep *rd;
+  if (!ISRELDEP(dep))
+    return 0;
+  rd = GETRELDEP(pool, dep);
+  if (rd->flags == REL_NAMESPACE)
+    return 1;
+  if (ISRELDEP(rd->name))
+    return solver_is_namespace_dep_slow(solv, rd);
+  if (ISRELDEP(rd->evr))
+    return solver_is_namespace_dep_slow(solv, GETRELDEP(pool, rd->evr));
+  return 0;
+}
+
 #endif /* LIBSOLV_SOLVER_PRIVATE_H */
index bd5d4b4..fb17bf4 100644 (file)
@@ -181,84 +181,91 @@ solver_dep_fulfilled_cplx(Solver *solv, Reldep *rd)
   return 0;
 }
 
-
-/* mirrors solver_dep_fulfilled, but returns 2 if a new package
- * was involved */
 static int
-solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep)
+solver_dep_fulfilled_complex_func(Solver *solv, Reldep *rd, int (*dep_fullfilled)(Solver *, Id))
 {
   Pool *pool = solv->pool;
-  Id p, pp;
-  int r;
-
-  if (ISRELDEP(dep))
+  int r1, r2;
+  if (rd->flags == REL_COND)
     {
-      Reldep *rd = GETRELDEP(pool, dep);
-      if (rd->flags == REL_COND)
+      if (ISRELDEP(rd->evr))
        {
-         int r1, r2;
-         if (ISRELDEP(rd->evr))
+         Reldep *rd2 = GETRELDEP(pool, rd->evr);
+         if (rd2->flags == REL_ELSE)
            {
-             Reldep *rd2 = GETRELDEP(pool, rd->evr);
-             if (rd2->flags == REL_ELSE)
+             r1 = dep_fullfilled(solv, rd2->name);
+             if (r1)
                {
-                 r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
-                 if (r1)
-                   {
-                     r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-                     return r2 && r1 == 2 ? 2 : r2;
-                   }
-                 return solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
+                 r2 = dep_fullfilled(solv, rd->name);
+                 return r2 && r1 == 2 ? 2 : r2;
                }
+             return dep_fullfilled(solv, rd2->evr);
            }
-         r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-         r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r1 && !r2)
-           return 0;
-          return r1 == 2 ? 2 : 1;
        }
-      if (rd->flags == REL_UNLESS)
+      r1 = dep_fullfilled(solv, rd->name);
+      r2 = !dep_fullfilled(solv, rd->evr);
+      if (!r1 && !r2)
+       return 0;
+      return r1 == 2 ? 2 : 1;
+    }
+  if (rd->flags == REL_UNLESS)
+    {
+      if (ISRELDEP(rd->evr))
        {
-         int r1, r2;
-         if (ISRELDEP(rd->evr))
+         Reldep *rd2 = GETRELDEP(pool, rd->evr);
+         if (rd2->flags == REL_ELSE)
            {
-             Reldep *rd2 = GETRELDEP(pool, rd->evr);
-             if (rd2->flags == REL_ELSE)
+             r1 = dep_fullfilled(solv, rd2->name);
+             if (r1)
                {
-                 r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->name);
-                 if (r1)
-                   {
-                     r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd2->evr);
-                     return r2 && r1 == 2 ? 2 : r2;
-                   }
-                 return solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
+                 r2 = dep_fullfilled(solv, rd2->evr);
+                 return r2 && r1 == 2 ? 2 : r2;
                }
+             return dep_fullfilled(solv, rd->name);
            }
-         /* A AND NOT(B) */
-         r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-         r2 = !solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r1 || !r2)
-           return 0;
-          return r1 == 2 ? 2 : 1;
-       }
-      if (rd->flags == REL_AND)
-        {
-         int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-          if (!r1)
-            return 0;
-         r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r2)
-           return 0;
-          return r1 == 2 || r2 == 2 ? 2 : 1;
-        }
-      if (rd->flags == REL_OR)
-       {
-         int r2, r1 = solver_dep_fulfilled_alreadyinstalled(solv, rd->name);
-         r2 = solver_dep_fulfilled_alreadyinstalled(solv, rd->evr);
-         if (!r1 && !r2)
-           return 0;
-          return r1 == 2 || r2 == 2 ? 2 : 1;
        }
+      /* A AND NOT(B) */
+      r1 = dep_fullfilled(solv, rd->name);
+      r2 = !dep_fullfilled(solv, rd->evr);
+      if (!r1 || !r2)
+       return 0;
+      return r1 == 2 ? 2 : 1;
+    }
+  if (rd->flags == REL_AND)
+    {
+      r1 = dep_fullfilled(solv, rd->name);
+      if (!r1)
+       return 0;
+      r2 = dep_fullfilled(solv, rd->evr);
+      if (!r2)
+       return 0;
+      return r1 == 2 || r2 == 2 ? 2 : 1;
+    }
+  if (rd->flags == REL_OR)
+    {
+      r1 = dep_fullfilled(solv, rd->name);
+      r2 = dep_fullfilled(solv, rd->evr);
+      if (!r1 && !r2)
+       return 0;
+      return r1 == 2 || r2 == 2 ? 2 : 1;
+    }
+  return 0;
+}
+
+/* mirrors solver_dep_fulfilled, but returns 2 if a new package
+ * was involved */
+static int
+solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+  int r;
+
+  if (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags == REL_COND || rd->flags == REL_UNLESS || rd->flags == REL_AND || rd->flags == REL_OR)
+       return solver_dep_fulfilled_complex_func(solv, rd, solver_dep_fulfilled_alreadyinstalled);
       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
         return solver_splitprovides(solv, rd->evr, 0) ? 2 : 0;
       if (rd->flags == REL_NAMESPACE && solv->installsuppdepq)
@@ -282,16 +289,61 @@ solver_dep_fulfilled_alreadyinstalled(Solver *solv, Id dep)
   return r;
 }
 
+static int
+solver_dep_fulfilled_namespace(Solver *solv, Id dep)
+{
+  Pool *pool = solv->pool;
+  Id p, pp;
+  int r = 1;
+
+  if (ISRELDEP(dep))
+    {
+      Reldep *rd = GETRELDEP(pool, dep);
+      if (rd->flags == REL_COND || rd->flags == REL_UNLESS || rd->flags == REL_AND || rd->flags == REL_OR)
+       return solver_dep_fulfilled_complex_func(solv, rd, solver_dep_fulfilled_namespace);
+      if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
+        return solver_splitprovides(solv, rd->evr, 0) ? 2 : 0;
+      if (rd->flags == REL_NAMESPACE)
+       r = 2;
+    }
+  FOR_PROVIDES(p, pp, dep)
+    if (solv->decisionmap[p] > 0)
+      return r;
+  return 0;
+}
+
 int
 solver_is_supplementing_alreadyinstalled(Solver *solv, Solvable *s)
 {
   Id sup, *supp;
   supp = s->repo->idarraydata + s->supplements;
   while ((sup = *supp++) != 0)
-    if (solver_dep_fulfilled_alreadyinstalled(solv, sup) == 2)
+    {
+      if (!solv->addalreadyrecommended && solver_dep_fulfilled_alreadyinstalled(solv, sup) != 2)
+       continue;
+      if (solv->only_namespace_recommended && solver_dep_fulfilled_namespace(solv, sup) != 2)
+       continue;
       return 1;
+    }
   return 0;
 }
+
+int
+solver_is_namespace_dep_slow(Solver *solv, Reldep *rd)
+{
+  Pool *pool = solv->pool;
+  for (;;)
+    {
+      if (rd->flags == REL_NAMESPACE)
+       return 1;
+      if (ISRELDEP(rd->name) && solver_is_namespace_dep_slow(solv, GETRELDEP(pool, rd->name)))
+       return 1;
+      if (!ISRELDEP(rd->evr))
+       return 0;
+      rd = GETRELDEP(pool, rd->evr);
+    }
+}
+
 /*
  * add all installed packages that package p obsoletes to Queue q.
  * Package p is not installed. Also, we know that if
diff --git a/test/testcases/allowuninstall/conflict.t b/test/testcases/allowuninstall/conflict.t
new file mode 100644 (file)
index 0000000..a66d322
--- /dev/null
@@ -0,0 +1,14 @@
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 noarch
+#>=Con: b
+repo available 0 testtags <inline>
+#>=Pkg: b 1 1 noarch
+
+system x86_64 rpm system
+solverflags allowuninstall
+disable pkg a-1-1.noarch@system
+job install name b
+result transaction,problems <inline>
+#>problem a658cbaf info package a-1-1.noarch conflicts with b provided by b-1-1.noarch
+#>problem a658cbaf solution 567aa15d erase a-1-1.noarch@system
+#>problem a658cbaf solution e98e1a37 deljob install name b
diff --git a/test/testcases/allowuninstall/forcebest.t b/test/testcases/allowuninstall/forcebest.t
new file mode 100644 (file)
index 0000000..38ade6f
--- /dev/null
@@ -0,0 +1,19 @@
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 noarch
+#>=Req: b = 1-1
+#>=Pkg: b 1 1 noarch
+repo available 0 testtags <inline>
+#>=Pkg: a 2 1 noarch
+#>=Req: b = 2-1
+#>=Pkg: b 2 1 noarch
+
+system x86_64 rpm system
+disable pkg b-1-1.noarch@system
+disable pkg b-2-1.noarch@available
+job allowuninstall pkg a-1-1.noarch@system
+job allowuninstall pkg b-1-1.noarch@system
+job update name a [forcebest]
+result transaction,problems <inline>
+#>problem e6d3911d info nothing provides b = 2-1 needed by a-2-1.noarch
+#>problem e6d3911d solution 0011b04f allow a-1-1.noarch@system
+#>problem e6d3911d solution 44d189a0 erase a-1-1.noarch@system
diff --git a/test/testcases/evrcmp/caret.t b/test/testcases/evrcmp/caret.t
new file mode 100644 (file)
index 0000000..d0c3a07
--- /dev/null
@@ -0,0 +1,74 @@
+repo system 0 empty
+repo available 0 testtags <inline>
+#>=Pkg: A1 1.0 0
+#>=Pkg: A2 1.0^ 0
+system i686 rpm system
+
+evrcmp 1.0~rc1 1.0~rc1
+evrcmp 1.0~rc1 1.0
+evrcmp 1.0 1.0~rc1
+evrcmp 1.0~rc1 1.0~rc2
+evrcmp 1.0~rc2 1.0~rc1
+evrcmp 1.0~rc1~git123 1.0~rc1~git123
+evrcmp 1.0~rc1~git123 1.0~rc1
+evrcmp 1.0~rc1 1.0~rc1~git123
+
+evrcmp 1.0^ 1.0^
+evrcmp 1.0^ 1.0
+evrcmp 1.0 1.0^
+evrcmp 1.0^git1 1.0^git1
+evrcmp 1.0^git1 1.0
+evrcmp 1.0 1.0^git1
+evrcmp 1.0^git1 1.0^git2
+evrcmp 1.0^git2 1.0^git1
+evrcmp 1.0^git1 1.01
+evrcmp 1.01 1.0^git1
+evrcmp 1.0^20160101 1.0^20160101
+evrcmp 1.0^20160101 1.0.1
+evrcmp 1.0.1 1.0^20160101
+evrcmp 1.0^20160101^git1 1.0^20160101^git1
+evrcmp 1.0^20160102 1.0^20160101^git1
+evrcmp 1.0^20160101^git1 1.0^20160102
+
+evrcmp 1.0~rc1^git1 1.0~rc1^git1
+evrcmp 1.0~rc1^git1 1.0~rc1
+evrcmp 1.0~rc1 1.0~rc1^git1
+evrcmp 1.0^git1~pre 1.0^git1~pre
+evrcmp 1.0^git1 1.0^git1~pre
+evrcmp 1.0^git1~pre 1.0^git1
+evrcmp 1.0^1 1.0~1
+evrcmp 1.0~1 1.0^1
+
+result jobs <inline>
+#>job noop provides 1.0~rc1 = 1.0~rc1
+#>job noop provides 1.0~rc1 < 1.0
+#>job noop provides 1.0 > 1.0~rc1
+#>job noop provides 1.0~rc1 < 1.0~rc2
+#>job noop provides 1.0~rc2 > 1.0~rc1
+#>job noop provides 1.0~rc1~git123 = 1.0~rc1~git123
+#>job noop provides 1.0~rc1~git123 < 1.0~rc1
+#>job noop provides 1.0~rc1 > 1.0~rc1~git123
+#>job noop provides 1.0^ = 1.0^
+#>job noop provides 1.0^ > 1.0
+#>job noop provides 1.0 < 1.0^
+#>job noop provides 1.0^git1 = 1.0^git1
+#>job noop provides 1.0^git1 > 1.0
+#>job noop provides 1.0 < 1.0^git1
+#>job noop provides 1.0^git1 < 1.0^git2
+#>job noop provides 1.0^git2 > 1.0^git1
+#>job noop provides 1.0^git1 < 1.01
+#>job noop provides 1.01 > 1.0^git1
+#>job noop provides 1.0^20160101 = 1.0^20160101
+#>job noop provides 1.0^20160101 < 1.0.1
+#>job noop provides 1.0.1 > 1.0^20160101
+#>job noop provides 1.0^20160101^git1 = 1.0^20160101^git1
+#>job noop provides 1.0^20160102 > 1.0^20160101^git1
+#>job noop provides 1.0^20160101^git1 < 1.0^20160102
+#>job noop provides 1.0~rc1^git1 = 1.0~rc1^git1
+#>job noop provides 1.0~rc1^git1 > 1.0~rc1
+#>job noop provides 1.0~rc1 < 1.0~rc1^git1
+#>job noop provides 1.0^git1~pre = 1.0^git1~pre
+#>job noop provides 1.0^git1 > 1.0^git1~pre
+#>job noop provides 1.0^git1~pre < 1.0^git1
+#>job noop provides 1.0^1 > 1.0~1
+#>job noop provides 1.0~1 < 1.0^1
index 62ca982..609b58a 100644 (file)
@@ -11,6 +11,13 @@ repo test 0 testtags <inline>
 #>=Prv: locale(C:de)
 #>=Pkg: C-en 1 1 noarch
 #>=Prv: locale(C:en)
+#>=Pkg: D 1 1 noarch
+#>=Sup: C
+#>=Pkg: E 1 1 noarch
+#>=Prv: locale(F:de)
+#>=Pkg: F 1 1 noarch
+#>=Pkg: G 1 1 noarch
+#>=Sup: F
 system i686 rpm system
 
 # first test an empty job
@@ -24,6 +31,7 @@ solverflags addalreadyrecommended
 result transaction,problems <inline>
 #>install A-1-1.noarch@test
 #>install C-de-1-1.noarch@test
+#>install D-1-1.noarch@test
 
 nextjob
 namespace namespace:language(de) @SYSTEM
@@ -59,3 +67,19 @@ result transaction,problems <inline>
 #>erase B-1-1.noarch@system
 #>install A-1-1.noarch@test
 #>install C-de-1-1.noarch@test
+
+nextjob
+namespace namespace:language(de) @SYSTEM
+solverflags addalreadyrecommended onlynamespacerecommended
+result transaction,problems <inline>
+#>install A-1-1.noarch@test
+#>install C-de-1-1.noarch@test
+
+nextjob
+namespace namespace:language(de) @SYSTEM
+solverflags onlynamespacerecommended
+job install name F
+result transaction,problems <inline>
+#>install E-1-1.noarch@test
+#>install F-1-1.noarch@test
+