Imported Upstream version 0.7.27
[platform/upstream/libsolv.git] / bindings / solv.i
index 4030796..a51ae2b 100644 (file)
 %markfunc Pool "mark_Pool";
 #endif
 
-/*
- * binaryblob handling
- */
+#ifdef SWIGPYTHON
+%begin %{
+#define PY_SSIZE_T_CLEAN
+%}
+#endif
+
+/**
+ ** binaryblob handling
+ **/
 
 %{
 typedef struct {
@@ -22,12 +28,33 @@ typedef struct {
 %}
 
 %typemap(in,noblock=1,fragment="SWIG_AsCharPtrAndSize") (const unsigned char *str, size_t len) (int res, char *buf = 0, size_t size = 0, int alloc = 0) {
+#if defined(SWIGTCL)
+  {
+    int bal;
+    unsigned char *ba;
+    res = SWIG_TypeError;
+    ba = Tcl_GetByteArrayFromObj($input, &bal);
+    if (ba) {
+      buf = (char *)ba;
+      size = bal;
+      res = SWIG_OK;
+      alloc = SWIG_OLDOBJ;
+    }
+  }
+#else
   res = SWIG_AsCharPtrAndSize($input, &buf, &size, &alloc);
+  if (buf && size)
+    size--;
+#endif
   if (!SWIG_IsOK(res)) {
 #if defined(SWIGPYTHON)
     const void *pybuf = 0;
     Py_ssize_t pysize = 0;
+%#if PY_VERSION_HEX >= 0x03000000
+    res = PyBytes_AsStringAndSize($input, (char **)&pybuf, &pysize);
+%#else
     res = PyObject_AsReadBuffer($input, &pybuf, &pysize);
+%#endif
     if (res < 0) {
       %argument_fail(res, "BinaryBlob", $symname, $argnum);
     } else {
@@ -42,13 +69,15 @@ typedef struct {
   $2 = size;
 }
 
-%typemap(freearg,noblock=1,match="in") (const unsigned char *str, int len) {
+%typemap(freearg,noblock=1,match="in") (const unsigned char *str, size_t len) {
   if (alloc$argnum == SWIG_NEWOBJ) %delete_array(buf$argnum);
 }
 
 %typemap(out,noblock=1,fragment="SWIG_FromCharPtrAndSize") BinaryBlob {
 #if defined(SWIGPYTHON) && defined(PYTHON3)
-  $result = $1.data ? Py_BuildValue("y#", $1.data, $1.len) : SWIG_Py_Void();
+  $result = $1.data ? Py_BuildValue("y#", $1.data, (Py_ssize_t)$1.len) : SWIG_Py_Void();
+#elif defined(SWIGTCL)
+  Tcl_SetObjResult(interp, $1.data ? Tcl_NewByteArrayObj($1.data, $1.len) : NULL);
 #else
   $result = SWIG_FromCharPtrAndSize($1.data, $1.len);
 #if defined(SWIGPERL)
@@ -57,29 +86,18 @@ typedef struct {
 #endif
 }
 
-#if defined(SWIGPYTHON)
-%typemap(in) Queue {
-  /* Check if is a list */
+/**
+ ** Queue handling
+ **/
+
+%typemap(arginit) Queue {
   queue_init(&$1);
-  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_free(&$1);
-        return NULL;
-      }
-      queue_push(&$1, v);
-    }
-  } else {
-    PyErr_SetString(PyExc_TypeError,"not a list");
-    return NULL;
-  }
 }
+%typemap(freearg) Queue {
+  queue_free(&$1);
+}
+
+#if defined(SWIGPYTHON)
 
 %typemap(out) Queue {
   int i;
@@ -90,7 +108,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;
@@ -106,31 +124,47 @@ typedef struct {
     }
   queue_free(&$1);
   $result = o;
+}
 %}
-
 %enddef
 
-#endif
-
-#if defined(SWIGPERL)
-%typemap(in) Queue {
-  AV *av;
+%define Array2Queue(asval_meth,typestr) %{ {
   int i, size;
-  queue_init(&$1);
-  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++;
@@ -145,7 +179,8 @@ typedef struct {
   queue_free(&$1);
   $result = 0;
 }
-%define Queue2Array(type, step, con) %{
+
+%define Queue2Array(type, step, con) %{ {
   int i;
   int cnt = $1.count / step;
   Id *idp = $1.elements;
@@ -163,37 +198,52 @@ typedef struct {
     }
   queue_free(&$1);
   $result = 0;
+}
 %}
 %enddef
 
-#endif
-
-%typemap(arginit) Queue {
-  queue_init(&$1);
-}
-%typemap(freearg) Queue {
-  queue_free(&$1);
-}
-
-#if defined(SWIGRUBY)
-%typemap(in) Queue {
-  int size, i;
-  VALUE *o;
-  queue_init(&$1);
-  size = RARRAY_LEN($input);
-  i = 0;
-  o = RARRAY_PTR($input);
-  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_Error(SWIG_RuntimeError, "list must contain only integers");
-        SWIG_fail;
-      }
+      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);
@@ -202,13 +252,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;
@@ -224,16 +269,136 @@ typedef struct {
     }
   queue_free(&$1);
   $result = o;
+}
+%}
+%enddef
+
+%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_TypeError, "list in argument $argnum must contain only " typestr);
+    queue_push(&$1, v);
+  }
+}
 %}
 %enddef
-#endif
 
+%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;
+
+  for (i = 0; i < $1.count; i++) {
+    objvx[i] = SWIG_From_int($1.elements[i]);
+  }
+  Tcl_SetObjResult(interp, Tcl_NewListObj($1.count, objvx));
+  queue_free(&$1);
+}
+
+%define Queue2Array(type, step, con) %{
+  { /* scope is needed to make the goto of SWIG_exception_fail work */
+    int i;
+    int cnt = $1.count / step;
+    Id *idp = $1.elements;
+    Tcl_Obj *objvx[cnt];
+
+    for (i = 0; i < cnt; i++, idp += step) {
+      Id id = *idp;
+#define result resultx
+#define Tcl_SetObjResult(i, x) resultobj = x
+      type result = con;
+      Tcl_Obj *resultobj;
+      $typemap(out, type)
+      objvx[i] = resultobj;
+#undef Tcl_SetObjResult
+#undef result
+    }
+    queue_free(&$1);
+    Tcl_SetObjResult(interp, Tcl_NewListObj(cnt, objvx));
+ }
+%}
+%enddef
+
+%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 $argnum is not a list");
+  for (i = 0; i < size; i++) {
+    Tcl_Obj *o = NULL;
+    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, (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  /* SWIGTCL */
+
+%typemap(in) Queue Array2Queue(SWIG_AsVal_int, "integers")
+%typemap(in) Queue solvejobs ObjArray2Queue(Job *, queue_push2(&$1, obj->how, obj->what))
+%typemap(in) Queue solvables ObjArray2Queue(XSolvable *, queue_push(&$1, obj->id))
 
 
 
 #if defined(SWIGPERL)
 
-/* work around a swig bug */
+/* work around a swig bug for swig versions < 2.0.5 */
+#if SWIG_VERSION < 0x020005
 %{
 #undef SWIG_CALLXS
 #ifdef PERL_OBJECT
@@ -246,6 +411,7 @@ typedef struct {
 #  endif
 #endif
 %}
+#endif
 
 
 %define perliter(class)
@@ -329,27 +495,38 @@ SWIG_Perl_NewArrayObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int f
 %typemap(out) Repo_solvable_iterator * solvables_iter = Perliterator;
 %typemap(out) Dataiterator * = Perliterator;
 
-#endif
+#endif  /* SWIGPERL */
+
 
+/**
+ ** appdata handling
+ **/
 
 #if defined(SWIGPYTHON)
 typedef PyObject *AppObjectPtr;
+%typemap(in) AppObjectPtr {
+  if ($input)
+    Py_INCREF($input);
+  $1 = $input;
+}
 %typemap(out) AppObjectPtr {
   $result = $1 ? $1 : Py_None;
   Py_INCREF($result);
 }
-#endif
-#if defined(SWIGPERL)
+#elif defined(SWIGPERL)
 typedef SV *AppObjectPtr;
 %typemap(in) AppObjectPtr {
-  $1 = SvROK($input) ? SvRV($input) : 0;
+  if ($input) {
+    $1 = newSV(0);
+    sv_setsv((SV *)$1, $input);
+  } else
+    $1 = (void *)0;
 }
 %typemap(out) AppObjectPtr {
-  $result = $1 ? newRV_inc($1) : newSV(0);
+  $result = sv_2mortal($1 ? SvREFCNT_inc($1) : newSV(0));
   argvi++;
 }
-#endif
-#if defined(SWIGRUBY)
+#elif defined(SWIGRUBY)
 typedef VALUE AppObjectPtr;
 %typemap(in) AppObjectPtr {
   $1 = (void *)$input;
@@ -357,8 +534,23 @@ typedef VALUE AppObjectPtr;
 %typemap(out) AppObjectPtr {
   $result = (VALUE)$1;
 }
+#elif defined(SWIGTCL)
+typedef Tcl_Obj *AppObjectPtr;
+%typemap(in) AppObjectPtr {
+  if ($input)
+    Tcl_IncrRefCount($input);
+  $1 = (void *)$input;
+}
+%typemap(out) AppObjectPtr {
+  Tcl_SetObjResult(interp, $1 ? $1 : Tcl_NewObj());
+}
+#else
+#warning AppObjectPtr not defined for this language!
 #endif
 
+/**
+ ** FILE handling
+ **/
 
 #ifdef SWIGPYTHON
 %include "file.i"
@@ -372,6 +564,8 @@ typedef VALUE AppObjectPtr;
 SWIGINTERN int
 #ifdef SWIGRUBY
 SWIG_AsValSolvFpPtr(VALUE obj, FILE **val) {
+#elif defined(SWIGTCL)
+SWIG_AsValSolvFpPtr SWIG_TCL_DECL_ARGS_2(void *obj, FILE **val) {
 #else
 SWIG_AsValSolvFpPtr(void *obj, FILE **val) {
 #endif
@@ -393,14 +587,24 @@ SWIG_AsValSolvFpPtr(void *obj, FILE **val) {
   return SWIG_TypeError;
 }
 
+#if defined(SWIGTCL)
+#define SWIG_AsValSolvFpPtr(x, y) SWIG_AsValSolvFpPtr SWIG_TCL_CALL_ARGS_2(x, y)
+#endif
+
 }
 
 
+/**
+ ** DepId handling
+ **/
+
 %fragment("SWIG_AsValDepId","header") {
 
 SWIGINTERN int
 #ifdef SWIGRUBY
 SWIG_AsValDepId(VALUE obj, int *val) {
+#elif defined(SWIGTCL)
+SWIG_AsValDepId SWIG_TCL_DECL_ARGS_2(void *obj, int *val) {
 #else
 SWIG_AsValDepId(void *obj, int *val) {
 #endif
@@ -408,7 +612,11 @@ SWIG_AsValDepId(void *obj, int *val) {
   void *vptr = 0;
   int ecode;
   if (!desc) desc = SWIG_TypeQuery("Dep *");
+#ifdef SWIGTCL
+  ecode = SWIG_AsVal_int SWIG_TCL_CALL_ARGS_2(obj, val);
+#else
   ecode = SWIG_AsVal_int(obj, val);
+#endif
   if (SWIG_IsOK(ecode))
     return ecode;
   if ((SWIG_ConvertPtr(obj, &vptr, desc, 0)) == SWIG_OK) {
@@ -419,20 +627,66 @@ SWIG_AsValDepId(void *obj, int *val) {
   return SWIG_TypeError;
 }
 
+#ifdef SWIGTCL
+#define SWIG_AsValDepId(x, y) SWIG_AsValDepId SWIG_TCL_CALL_ARGS_2(x, y)
+#endif
 }
 
+/**
+ ** Pool disown helper
+ **/
+
 %typemap(out) disown_helper {
-#ifdef SWIGRUBY
+#if defined(SWIGRUBY)
   SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN |  0 );
-#endif
-#ifdef SWIGPYTHON
-  SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN |  0 );
-#endif
-#ifdef SWIGPERL
+#elif defined(SWIGPYTHON)
+  SWIG_ConvertPtr($self, &argp1,SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN |  0 );
+#elif defined(SWIGPERL)
   SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN |  0 );
+#elif defined(SWIGTCL)
+  SWIG_ConvertPtr(objv[1], &argp1, SWIGTYPE_p_Pool, SWIG_POINTER_DISOWN | 0);
+#else
+#warning disown_helper not implemented for this language, this is likely going to leak memory
 #endif
+
+#ifdef SWIGTCL
+  Tcl_SetObjResult(interp, SWIG_From_int((int)(0)));
+#else
   $result = SWIG_From_int((int)(0));
+#endif
+}
+
+
+/**
+ ** return $self
+ **/
+
+%define returnself(func)
+#if defined(SWIGPYTHON)
+%typemap(out) void func {
+  $result = $self;
+  Py_INCREF($result);
+}
+#elif defined(SWIGPERL)
+%typemap(out) void func {
+  $result = sv_2mortal(SvREFCNT_inc(ST(0)));argvi++;
+}
+#elif defined(SWIGRUBY)
+%typemap(ret) void func {
+  return self;
+}
+#elif defined(SWIGTCL)
+%typemap(out) void func {
+  Tcl_IncrRefCount(objv[1]);
+  Tcl_SetObjResult(interp, objv[1]);
 }
+#endif
+%enddef
+
+
+/**
+ ** misc stuff
+ **/
 
 %include "typemaps.i"
 
@@ -447,6 +701,10 @@ SWIG_AsValDepId(void *obj, int *val) {
 %typemaps_asval(%checkcode(INT32), SWIG_AsValDepId, "SWIG_AsValDepId", DepId);
 
 
+/**
+ ** the C declarations
+ **/
+
 %{
 #include <stdbool.h>
 #include <stdio.h>
@@ -454,6 +712,7 @@ SWIG_AsValDepId(void *obj, int *val) {
 #include <sys/utsname.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 /* argh, swig undefs bool for perl */
 #ifndef bool
@@ -471,7 +730,7 @@ typedef int bool;
 #include "selection.h"
 
 #include "repo_write.h"
-#ifdef ENABLE_RPMDB
+#if defined(ENABLE_RPMDB) || defined(ENABLE_RPMPKG)
 #include "repo_rpmdb.h"
 #endif
 #ifdef ENABLE_PUBKEY
@@ -500,7 +759,11 @@ typedef int bool;
 #ifdef SUSE
 #include "repo_autopattern.h"
 #endif
+#if defined(ENABLE_COMPLEX_DEPS) && (defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_RPMDB) || defined(ENABLE_RPMPKG))
+#include "pool_parserpmrichdep.h"
+#endif
 #include "solv_xfopen.h"
+#include "testcase.h"
 
 /* for old ruby versions */
 #ifndef RARRAY_PTR
@@ -510,13 +773,6 @@ typedef int bool;
 #define RARRAY_LEN(ary) (RARRAY(ary)->len)
 #endif
 
-#define SOLVER_SOLUTION_ERASE                   -100
-#define SOLVER_SOLUTION_REPLACE                 -101
-#define SOLVER_SOLUTION_REPLACE_DOWNGRADE       -102
-#define SOLVER_SOLUTION_REPLACE_ARCHCHANGE      -103
-#define SOLVER_SOLUTION_REPLACE_VENDORCHANGE    -104
-#define SOLVER_SOLUTION_REPLACE_NAMECHANGE      -105
-
 typedef void *AppObjectPtr;
 typedef Id DepId;
 
@@ -576,7 +832,6 @@ typedef struct {
   Solver *solv;
   Id problemid;
   Id solutionid;
-  Id id;
 
   Id type;
   Id p;
@@ -586,7 +841,7 @@ typedef struct {
 typedef struct {
   Solver *solv;
   Id rid;
-  Id type;
+  int type;
   Id source;
   Id target;
   Id dep_id;
@@ -619,6 +874,26 @@ typedef struct {
 } Selection;
 
 typedef struct {
+  Solver *solv;
+  Id p;
+  int reason;
+  Id infoid;
+} Decision;
+
+typedef struct {
+  Solver *solv;
+  Queue decisionlistq;
+  Id p;
+  int reason;
+  Id infoid;
+  int bits;
+  int type;
+  Id source;
+  Id target;
+  Id dep_id;
+} Decisionset;
+
+typedef struct {
   FILE *fp;
 } SolvFp;
 
@@ -626,8 +901,166 @@ typedef Dataiterator Datamatch;
 
 typedef int disown_helper;
 
+struct myappdata {
+  void *appdata;
+  int disowned;
+};
+
+/* special internal decisionset constructor from a prepared decisionlist */
+static Decisionset *decisionset_fromids(Solver *solv, Id *ids, int cnt)
+{
+  Decisionset *d = solv_calloc(1, sizeof(*d));
+  int i;
+  d->solv = solv;
+  queue_init(&d->decisionlistq);
+  d->p = ids[0];
+  d->reason = ids[1];
+  d->infoid = ids[2];
+  d->bits = ids[3];
+  d->type = ids[4];
+  d->source = ids[5];
+  d->target = ids[6];
+  d->dep_id = ids[7];
+  for (i = 0; i < cnt; i += 8)
+    queue_insertn(&d->decisionlistq, d->decisionlistq.count, 3, ids + i);
+  if (cnt > 8)
+    d->infoid = 0;
+  return d;
+}
+
+/* prepare a decisionlist so we can feed it to decisionset_fromids */
+static void prepare_decisionset_queue(Solver *solv, Queue *q) {
+  int i, cnt;
+  for (i = cnt = 0; i < q->count; cnt++)
+    {
+      i += 1 + 8 + 8 * solver_decisionlist_merged(solv, q, i);  /* +1 as we insert one element */
+      queue_insert(q, cnt, i - cnt);
+    }
+  if (cnt)
+    queue_unshift(q, 1);        /* start of first block */
+  for (i = 0; i < cnt; i++)
+    q->elements[i] += cnt - i;
+  q->count = cnt;   /* hack */
+}
+
+%}
+
+/**
+ ** appdata helpers
+ **/
+
+#ifdef SWIGRUBY
+
+%{
+SWIGINTERN void appdata_disown_helper(void *appdata) {
+}
+SWIGINTERN void appdata_clr_helper(void **appdatap) {
+  *appdatap = 0;
+}
+SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) {
+  *appdatap = appdata;
+}
+SWIGINTERN void *appdata_get_helper(void *appdata) {
+  return appdata;
+}
+%}
+
+#elif defined(SWIGTCL)
+
+%{
+SWIGINTERN void appdata_disown_helper(void *appdata) {
+}
+SWIGINTERN void appdata_clr_helper(void **appdatap) {
+  if (*appdatap)
+    Tcl_DecrRefCount((Tcl_Obj *)(*appdatap));
+  *appdatap = 0;
+}
+SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) {
+  appdata_clr_helper(appdatap);
+  *appdatap = appdata;
+}
+SWIGINTERN void *appdata_get_helper(void *appdata) {
+  return appdata;
+}
+%}
+
+#elif defined(SWIGPYTHON)
+
+%{
+SWIGINTERN void appdata_disown_helper(void *appdata) {
+  struct myappdata *myappdata = appdata;
+  if (!myappdata || !myappdata->appdata || myappdata->disowned)
+    return;
+  myappdata->disowned = 1;
+  Py_DECREF((PyObject *)myappdata->appdata);
+}
+SWIGINTERN void appdata_clr_helper(void **appdatap) {
+  struct myappdata *myappdata = *(struct myappdata **)appdatap;
+  if (myappdata && myappdata->appdata && !myappdata->disowned) {
+    Py_DECREF((PyObject *)myappdata->appdata);
+  }
+  *appdatap = solv_free(myappdata);
+}
+SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) {
+  appdata_clr_helper(appdatap);
+  if (appdata) {
+    struct myappdata *myappdata = *appdatap = solv_calloc(sizeof(struct myappdata), 1);
+    myappdata->appdata = appdata;
+  }
+}
+SWIGINTERN void *appdata_get_helper(void *appdata) {
+  return appdata ? ((struct myappdata *)appdata)->appdata : 0;
+}
+
+%}
+
+#elif defined(SWIGPERL)
+
+%{
+SWIGINTERN void appdata_disown_helper(void *appdata) {
+  struct myappdata *myappdata = appdata;
+  SV *rsv;
+  if (!myappdata || !myappdata->appdata || myappdata->disowned)
+    return;
+  rsv = myappdata->appdata;
+  if (!SvROK(rsv))
+    return;
+  myappdata->appdata = SvRV(rsv);
+  myappdata->disowned = 1;
+  SvREFCNT_dec(rsv);
+}
+SWIGINTERN void appdata_clr_helper(void **appdatap) {
+  struct myappdata *myappdata = *(struct myappdata **)appdatap;
+  if (myappdata && myappdata->appdata && !myappdata->disowned) {
+    SvREFCNT_dec((SV *)myappdata->appdata);
+  }
+  *appdatap = solv_free(myappdata);
+}
+SWIGINTERN void appdata_set_helper(void **appdatap, void *appdata) {
+  appdata_clr_helper(appdatap);
+  if (appdata) {
+    struct myappdata *myappdata = *appdatap = solv_calloc(sizeof(struct myappdata), 1);
+    myappdata->appdata = appdata;
+  }
+}
+SWIGINTERN void *appdata_get_helper(void *appdata) {
+  struct myappdata *myappdata = appdata;
+  if (!myappdata || !myappdata->appdata)
+    return 0;
+  return myappdata->disowned ? newRV_noinc((SV *)myappdata->appdata) : myappdata->appdata;
+}
+
 %}
 
+#else
+#warning appdata helpers not implemented for this language
+#endif
+
+
+/**
+ ** the SWIG declarations defining the API
+ **/
+
 #ifdef SWIGRUBY
 %mixin Dataiterator "Enumerable";
 %mixin Pool_solvable_iterator "Enumerable";
@@ -646,10 +1079,25 @@ typedef int Id;
 %constant int REL_EQ;
 %constant int REL_GT;
 %constant int REL_LT;
+%constant int REL_AND;
+%constant int REL_OR;
+%constant int REL_WITH;
+%constant int REL_NAMESPACE;
 %constant int REL_ARCH;
+%constant int REL_FILECONFLICT;
+%constant int REL_COND;
+%constant int REL_COMPAT;
+%constant int REL_KIND;
+%constant int REL_MULTIARCH;
+%constant int REL_ELSE;
+%constant int REL_ERROR;
+%constant int REL_WITHOUT;
+%constant int REL_UNLESS;
+%constant int REL_CONDA;
 
 typedef struct {
   Pool* const pool;
+  int const flags;
 } Selection;
 
 typedef struct {
@@ -668,7 +1116,7 @@ typedef struct {
 
 typedef struct {
   Solver* const solv;
-  Id const type;
+  int const type;
   Id const dep_id;
 } Ruleinfo;
 
@@ -708,7 +1156,6 @@ typedef struct {
 %nodefaultctor Pool;
 %nodefaultdtor Pool;
 typedef struct {
-  AppObjectPtr appdata;
 } Pool;
 
 %nodefaultctor Repo;
@@ -719,9 +1166,28 @@ typedef struct {
   int priority;
   int subpriority;
   int const nsolvables;
-  AppObjectPtr appdata;
 } Repo;
 
+%nodefaultctor Decision;
+typedef struct {
+  Solver *const solv;
+  Id const p;
+  int const reason;
+  Id const infoid;
+} Decision;
+
+%nodefaultctor Decisionset;
+%nodefaultdtor Decisionset;
+typedef struct {
+  Solver *const solv;
+  Id const p;
+  int const reason;
+  Id const infoid;
+  int const bits;
+  int const type;
+  Id const dep_id;
+} Decisionset;
+
 %nodefaultctor Solver;
 %nodefaultdtor Solver;
 typedef struct {
@@ -758,9 +1224,14 @@ SolvFp *solvfp_xfopen_fd(const char *fn, int fd, const char *mode = 0);
     SolvFp *sfp;
     FILE *fp;
     fd = dup(fd);
-    fp = fd == -1 ? 0 : solv_xfopen_fd(fn, fd, mode);
-    if (!fp)
+    if (fd == -1)
+      return 0;
+    solv_setcloexec(fd, 1);
+    fp = solv_xfopen_fd(fn, fd, mode);
+    if (!fp) {
+      close(fd);
       return 0;
+    }
     sfp = solv_calloc(1, sizeof(SolvFp));
     sfp->fp = fp;
     return sfp;
@@ -771,6 +1242,8 @@ SolvFp *solvfp_xfopen_fd(const char *fn, int fd, const char *mode = 0);
     fp = solv_xfopen(fn, mode);
     if (!fp)
       return 0;
+    if (fileno(fp) != -1)
+      solv_setcloexec(fileno(fp), 1);
     sfp = solv_calloc(1, sizeof(SolvFp));
     sfp->fp = fp;
     return sfp;
@@ -792,7 +1265,6 @@ typedef struct {
   Solver *const solv;
   Id const problemid;
   Id const solutionid;
-  Id const id;
   Id const type;
 } Solutionelement;
 
@@ -800,11 +1272,9 @@ typedef struct {
 typedef struct {
   Solver *const solv;
   Id const type;
-  Id const rid;
-  Id const from_id;
   Id const dep_id;
   Id const chosen_id;
-  int level;
+  int const level;
 } Alternative;
 
 %nodefaultctor Transaction;
@@ -833,6 +1303,9 @@ typedef struct {
   int dup() {
     return $self->fp ? dup(fileno($self->fp)) : -1;
   }
+  bool write(const unsigned char *str, size_t len) {
+    return fwrite(str, len, 1, $self->fp) == 1;
+  }
   bool flush() {
     if (!$self->fp)
       return 1;
@@ -846,6 +1319,11 @@ typedef struct {
     $self->fp = 0;
     return ret;
   }
+  void cloexec(bool state) {
+    if (!$self->fp || fileno($self->fp) == -1)
+      return;
+    solv_setcloexec(fileno($self->fp), state);
+  }
 }
 
 %extend Job {
@@ -867,6 +1345,10 @@ typedef struct {
   static const Id SOLVER_VERIFY = SOLVER_VERIFY;
   static const Id SOLVER_DROP_ORPHANED = SOLVER_DROP_ORPHANED;
   static const Id SOLVER_USERINSTALLED = SOLVER_USERINSTALLED;
+  static const Id SOLVER_ALLOWUNINSTALL = SOLVER_ALLOWUNINSTALL;
+  static const Id SOLVER_FAVOR = SOLVER_FAVOR;
+  static const Id SOLVER_DISFAVOR = SOLVER_DISFAVOR;
+  static const Id SOLVER_EXCLUDEFROMWEAK = SOLVER_EXCLUDEFROMWEAK;
   static const Id SOLVER_JOBMASK = SOLVER_JOBMASK;
   static const Id SOLVER_WEAK = SOLVER_WEAK;
   static const Id SOLVER_ESSENTIAL = SOLVER_ESSENTIAL;
@@ -906,18 +1388,27 @@ typedef struct {
     return pool_isemptyupdatejob($self->pool, $self->how, $self->what);
   }
 
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
   bool __eq__(Job *j) {
     return $self->pool == j->pool && $self->how == j->how && $self->what == j->what;
   }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
   bool __ne__(Job *j) {
     return !Job___eq__($self, j);
   }
-#if defined(SWIGPERL)
+#if defined(SWIGPERL) || defined(SWIGTCL)
   %rename("str") __str__;
 #endif
   const char *__str__() {
     return pool_job2str($self->pool, $self->how, $self->what, 0);
   }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
   const char *__repr__() {
     const char *str = pool_job2str($self->pool, $self->how, $self->what, ~0);
     return pool_tmpjoin($self->pool, "<Job ", str, ">");
@@ -935,8 +1426,18 @@ typedef struct {
   static const Id SELECTION_GLOB = SELECTION_GLOB;
   static const Id SELECTION_FLAT = SELECTION_FLAT;
   static const Id SELECTION_NOCASE = SELECTION_NOCASE;
+  static const Id SELECTION_SKIP_KIND = SELECTION_SKIP_KIND;
+  static const Id SELECTION_MATCH_DEPSTR = SELECTION_MATCH_DEPSTR;
   static const Id SELECTION_SOURCE_ONLY = SELECTION_SOURCE_ONLY;
   static const Id SELECTION_WITH_SOURCE = SELECTION_WITH_SOURCE;
+  static const Id SELECTION_WITH_DISABLED = SELECTION_WITH_DISABLED;
+  static const Id SELECTION_WITH_BADARCH = SELECTION_WITH_BADARCH;
+  static const Id SELECTION_WITH_ALL = SELECTION_WITH_ALL;
+  static const Id SELECTION_ADD = SELECTION_ADD;
+  static const Id SELECTION_SUBTRACT = SELECTION_SUBTRACT;
+  static const Id SELECTION_FILTER = SELECTION_FILTER;
+  static const Id SELECTION_FILTER_KEEP_IFEMPTY = SELECTION_FILTER_KEEP_IFEMPTY;
+  static const Id SELECTION_FILTER_SWAPPED = SELECTION_FILTER_SWAPPED;
 
   Selection(Pool *pool) {
     Selection *s;
@@ -949,21 +1450,27 @@ typedef struct {
     queue_free(&$self->q);
     solv_free($self);
   }
-  int flags() {
-    return $self->flags;
-  }
 #ifdef SWIGRUBY
   %rename("isempty?") isempty;
 #endif
   bool isempty() {
     return $self->q.count == 0;
   }
+  %newobject clone;
+  Selection *clone(int flags = 0) {
+    Selection *s = new_Selection($self->pool);
+    queue_init_clone(&s->q, &$self->q);
+    s->flags = $self->flags;
+    return s;
+  }
+returnself(filter)
   void filter(Selection *lsel) {
     if ($self->pool != lsel->pool)
       queue_empty(&$self->q);
     else
       selection_filter($self->pool, &$self->q, &lsel->q);
   }
+returnself(add)
   void add(Selection *lsel) {
     if ($self->pool == lsel->pool)
       {
@@ -971,9 +1478,41 @@ typedef struct {
         $self->flags |= lsel->flags;
       }
   }
+returnself(add_raw)
   void add_raw(Id how, Id what) {
     queue_push2(&$self->q, how, what);
   }
+returnself(subtract)
+  void subtract(Selection *lsel) {
+    if ($self->pool == lsel->pool)
+      selection_subtract($self->pool, &$self->q, &lsel->q);
+  }
+
+returnself(select)
+  void select(const char *name, int flags) {
+    if ((flags & SELECTION_MODEBITS) == 0)
+      flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
+    $self->flags = selection_make($self->pool, &$self->q, name, flags);
+  }
+returnself(matchdeps)
+  void matchdeps(const char *name, int flags, Id keyname, Id marker = -1) {
+    if ((flags & SELECTION_MODEBITS) == 0)
+      flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
+    $self->flags = selection_make_matchdeps($self->pool, &$self->q, name, flags, keyname, marker);
+  }
+returnself(matchdepid)
+  void matchdepid(DepId dep, int flags, Id keyname, Id marker = -1) {
+    if ((flags & SELECTION_MODEBITS) == 0)
+      flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
+    $self->flags = selection_make_matchdepid($self->pool, &$self->q, dep, flags, keyname, marker);
+  }
+returnself(matchsolvable)
+  void matchsolvable(XSolvable *solvable, int flags, Id keyname, Id marker = -1) {
+    if ((flags & SELECTION_MODEBITS) == 0)
+      flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
+    $self->flags = selection_make_matchsolvable($self->pool, &$self->q, solvable->id, flags, keyname, marker);
+  }
+
   %typemap(out) Queue jobs Queue2Array(Job *, 2, new_Job(arg1->pool, id, idp[1]));
   %newobject jobs;
   Queue jobs(int flags) {
@@ -994,12 +1533,15 @@ typedef struct {
     return q;
   }
 
-#if defined(SWIGPERL)
+#if defined(SWIGPERL) || defined(SWIGTCL)
   %rename("str") __str__;
 #endif
   const char *__str__() {
     return pool_selection2str($self->pool, &$self->q, 0);
   }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
   const char *__repr__() {
     const char *str = pool_selection2str($self->pool, &$self->q, ~0);
     return pool_tmpjoin($self->pool, "<Selection ", str, ">");
@@ -1019,6 +1561,20 @@ typedef struct {
       return 0;
     return solv_chksum_create_from_bin(type, buf);
   }
+  %newobject from_bin;
+  static Chksum *from_bin(Id type, const unsigned char *str, size_t len) {
+    return len == solv_chksum_len(type) ? solv_chksum_create_from_bin(type, str) : 0;
+  }
+#if defined(SWIGPERL)
+  %perlcode {
+    undef *solv::Chksum::from_bin;
+    *solv::Chksum::from_bin = sub {
+      my $pkg = shift;
+      my $self = solvc::Chksum_from_bin(@_);
+      bless $self, $pkg if defined $self;
+    };
+  }
+#endif
   ~Chksum() {
     solv_chksum_free($self, 0);
   }
@@ -1087,24 +1643,22 @@ typedef struct {
     return solv_chksum_type2str(solv_chksum_get_type($self));
   }
 
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
   bool __eq__(Chksum *chk) {
-    int l;
-    const unsigned char *b, *bo;
-    if (!chk)
-      return 0;
-    if (solv_chksum_get_type($self) != solv_chksum_get_type(chk))
-      return 0;
-    b = solv_chksum_get($self, &l);
-    bo = solv_chksum_get(chk, 0);
-    return memcmp(b, bo, l) == 0;
+    return solv_chksum_cmp($self, chk);
   }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
   bool __ne__(Chksum *chk) {
-    return !Chksum___eq__($self, chk);
+    return !solv_chksum_cmp($self, chk);
   }
 #if defined(SWIGRUBY)
   %rename("to_s") __str__;
 #endif
-#if defined(SWIGPERL)
+#if defined(SWIGPERL) || defined(SWIGTCL)
   %rename("str") __str__;
 #endif
   %newobject __str__;
@@ -1117,6 +1671,9 @@ typedef struct {
     solv_free((void *)h);
     return str;
   }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
   %newobject __repr__;
   const char *__repr__() {
     const char *h = Chksum___str__($self);
@@ -1136,11 +1693,22 @@ typedef struct {
   static const int POOL_FLAG_NOINSTALLEDOBSOLETES = POOL_FLAG_NOINSTALLEDOBSOLETES;
   static const int POOL_FLAG_HAVEDISTEPOCH = POOL_FLAG_HAVEDISTEPOCH;
   static const int POOL_FLAG_NOOBSOLETESMULTIVERSION = POOL_FLAG_NOOBSOLETESMULTIVERSION;
+  static const int POOL_FLAG_ADDFILEPROVIDESFILTERED = POOL_FLAG_ADDFILEPROVIDESFILTERED;
+  static const int POOL_FLAG_NOWHATPROVIDESAUX = POOL_FLAG_NOWHATPROVIDESAUX;
+  static const int POOL_FLAG_WHATPROVIDESWITHDISABLED = POOL_FLAG_WHATPROVIDESWITHDISABLED;
+  static const int DISTTYPE_RPM = DISTTYPE_RPM;
+  static const int DISTTYPE_DEB = DISTTYPE_DEB;
+  static const int DISTTYPE_ARCH = DISTTYPE_ARCH;
+  static const int DISTTYPE_HAIKU = DISTTYPE_HAIKU;
+  static const int DISTTYPE_CONDA = DISTTYPE_CONDA;
 
   Pool() {
     Pool *pool = pool_create();
     return pool;
   }
+  int setdisttype(int disttype) {
+    return pool_setdisttype($self, disttype);
+  }
   void set_debuglevel(int level) {
     pool_setdebuglevel($self, level);
   }
@@ -1172,18 +1740,21 @@ typedef struct {
     return SWIG_IsOK(ecode) ? vresult : 0;
   }
   %}
-  void set_loadcallback(PyObject *callable) {
+  void clr_loadcallback() {
     if ($self->loadcallback == loadcallback) {
       PyObject *obj = $self->loadcallbackdata;
       Py_DECREF(obj);
+      pool_setloadcallback($self, 0, 0);
     }
+  }
+  void set_loadcallback(PyObject *callable) {
+    Pool_clr_loadcallback($self);
     if (callable) {
       Py_INCREF(callable);
+      pool_setloadcallback($self, loadcallback, callable);
     }
-    pool_setloadcallback($self, callable ? loadcallback : 0, callable);
   }
-#endif
-#if defined(SWIGPERL)
+#elif defined(SWIGPERL)
 %{
   SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
     int count;
@@ -1206,16 +1777,20 @@ typedef struct {
     return ret;
   }
 %}
-  void set_loadcallback(SV *callable) {
-    if ($self->loadcallback == loadcallback)
+  void clr_loadcallback() {
+    if ($self->loadcallback == loadcallback) {
       SvREFCNT_dec($self->loadcallbackdata);
-    if (callable)
+      pool_setloadcallback($self, 0, 0);
+    }
+  }
+  void set_loadcallback(SV *callable) {
+    Pool_clr_loadcallback($self);
+    if (callable) {
       SvREFCNT_inc(callable);
-    pool_setloadcallback($self, callable ? loadcallback : 0, callable);
+      pool_setloadcallback($self, loadcallback, callable);
+    }
   }
-#endif
-
-#if defined(SWIGRUBY)
+#elif defined(SWIGRUBY)
 %{
   SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
     XRepodata *xd = new_XRepodata(data->repo, data->repodataid);
@@ -1232,26 +1807,97 @@ typedef struct {
     }
   }
 %}
+  void clr_loadcallback() {
+    pool_setloadcallback($self, 0, 0);
+  }
   %typemap(in, numinputs=0) VALUE callable {
     $1 = rb_block_given_p() ? rb_block_proc() : 0;
   }
   void set_loadcallback(VALUE callable) {
     pool_setloadcallback($self, callable ? loadcallback : 0, (void *)callable);
   }
+#elif defined(SWIGTCL)
+  %{
+  typedef struct {
+    Tcl_Interp *interp;
+    Tcl_Obj *obj;
+  } tcl_callback_t;
+  SWIGINTERN int loadcallback(Pool *pool, Repodata *data, void *d) {
+    tcl_callback_t *callback_var = (tcl_callback_t *)d;
+    Tcl_Interp *interp = callback_var->interp;
+    XRepodata *xd = new_XRepodata(data->repo, data->repodataid);
+    int result, ecode = 0, vresult = 0;
+    Tcl_Obj *objvx[2];
+    objvx[0] = callback_var->obj;
+    objvx[1] = SWIG_NewInstanceObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, 0);
+    Tcl_IncrRefCount(objvx[1]);
+    result = Tcl_EvalObjv(interp, sizeof(objvx)/sizeof(*objvx), objvx, TCL_EVAL_GLOBAL);
+    Tcl_DecrRefCount(objvx[1]);
+    if (result != TCL_OK)
+      return 0; /* exception */
+    ecode = SWIG_AsVal_int(interp, Tcl_GetObjResult(interp), &vresult);
+    return SWIG_IsOK(ecode) ? vresult : 0;
+  }
+  %}
+  void clr_loadcallback() {
+    if ($self->loadcallback == loadcallback) {
+      tcl_callback_t *callback_var = $self->loadcallbackdata;
+      Tcl_DecrRefCount(callback_var->obj);
+      solv_free(callback_var);
+      pool_setloadcallback($self, 0, 0);
+    }
+  }
+  void set_loadcallback(Tcl_Obj *callable, Tcl_Interp *interp) {
+    Pool_clr_loadcallback($self);
+    if (callable) {
+      tcl_callback_t *callback_var = solv_malloc(sizeof(tcl_callback_t));
+      Tcl_IncrRefCount(callable);
+      callback_var->interp = interp;
+      callback_var->obj = callable;
+      pool_setloadcallback($self, loadcallback, callback_var);
+    }
+  }
+#else
+#warning loadcallback not implemented for this language
 #endif
 
   ~Pool() {
-    Pool_set_loadcallback($self, 0);
-    pool_free($self);
+    Pool *pool = $self;
+    Id repoid;
+    Repo *repo;
+    FOR_REPOS(repoid, repo)
+      appdata_clr_helper(&repo->appdata);
+    Pool_clr_loadcallback(pool);
+    appdata_clr_helper(&pool->appdata);
+    pool_free(pool);
   }
   disown_helper free() {
-    Pool_set_loadcallback($self, 0);
-    pool_free($self);
+    Pool *pool = $self;
+    Id repoid;
+    Repo *repo;
+    FOR_REPOS(repoid, repo)
+      appdata_clr_helper(&repo->appdata);
+    Pool_clr_loadcallback(pool);
+    appdata_clr_helper(&pool->appdata);
+    pool_free(pool);
     return 0;
   }
   disown_helper disown() {
     return 0;
   }
+  AppObjectPtr appdata;
+  %{
+  SWIGINTERN void Pool_appdata_set(Pool *pool, AppObjectPtr appdata) {
+    appdata_set_helper(&pool->appdata, appdata);
+  }
+  SWIGINTERN AppObjectPtr Pool_appdata_get(Pool *pool) {
+    return appdata_get_helper(pool->appdata);
+  }
+  %}
+  void appdata_disown() {
+    appdata_disown_helper($self->appdata);
+  }
+
   Id str2id(const char *str, bool create=1) {
     return pool_str2id($self, str, create);
   }
@@ -1260,6 +1906,13 @@ typedef struct {
     Id id = pool_str2id($self, str, create);
     return new_Dep($self, id);
   }
+#if defined(ENABLE_COMPLEX_DEPS) && (defined(ENABLE_SUSEREPO) || defined(ENABLE_RPMMD) || defined(ENABLE_RPMDB) || defined(ENABLE_RPMPKG))
+  %newobject Dep;
+  Dep *parserpmrichdep(const char *str) {
+    Id id = pool_parserpmrichdep($self, str);
+    return new_Dep($self, id);
+  }
+#endif
   const char *id2str(Id id) {
     return pool_id2str($self, id);
   }
@@ -1316,6 +1969,13 @@ typedef struct {
   const char *solvid2str(Id solvid) {
     return pool_solvid2str($self, solvid);
   }
+  const char *solvidset2str(Queue q) {
+    return pool_solvidset2str($self, &q);
+  }
+  const char *solvableset2str(Queue solvables) {
+    return pool_solvidset2str($self, &solvables);
+  }
+
   void addfileprovides() {
     pool_addfileprovides($self);
   }
@@ -1369,10 +2029,10 @@ typedef struct {
   SWIGINTERN void Pool_installed_set(Pool *pool, Repo *installed) {
     pool_set_installed(pool, installed);
   }
-  Repo *Pool_installed_get(Pool *pool) {
+  SWIGINTERN Repo *Pool_installed_get(Pool *pool) {
     return pool->installed;
   }
-  const char *Pool_errstr_get(Pool *pool) {
+  SWIGINTERN const char *Pool_errstr_get(Pool *pool) {
     return pool_errstr(pool);
   }
   %}
@@ -1414,11 +2074,37 @@ typedef struct {
       queue_push(&q, p);
     return q;
   }
+  %typemap(out) Queue best_solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id));
+  %newobject best_solvables;
+  Queue best_solvables(Queue solvables, int flags=0) {
+    Queue q;
+    queue_init_clone(&q, &solvables);
+    pool_best_solvables($self, &q, flags);
+    return q;
+  }
 
   Id towhatprovides(Queue q) {
     return pool_queuetowhatprovides($self, &q);
   }
 
+  void set_namespaceproviders(DepId ns, DepId evr, bool value=1) {
+    Id dep = pool_rel2id($self, ns, evr, REL_NAMESPACE, 1);
+    pool_set_whatprovides($self, dep, value ? 2 : 1);
+  }
+
+  void flush_namespaceproviders(DepId ns, DepId evr) {
+    pool_flush_namespaceproviders($self, ns, evr);
+  }
+
+  %typemap(out) Queue whatcontainsdep Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id));
+  %newobject whatcontainsdep;
+  Queue whatcontainsdep(Id keyname, DepId dep, Id marker = -1) {
+    Queue q;
+    queue_init(&q);
+    pool_whatcontainsdep($self, keyname, dep, &q, marker);
+    return q;
+  }
+
   %typemap(out) Queue whatmatchesdep Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id));
   %newobject whatmatchesdep;
   Queue whatmatchesdep(Id keyname, DepId dep, Id marker = -1) {
@@ -1428,6 +2114,15 @@ typedef struct {
     return q;
   }
 
+  %typemap(out) Queue whatmatchessolvable Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id));
+  %newobject whatmatchessolvable;
+  Queue whatmatchessolvable(Id keyname, XSolvable *pool_solvable, Id marker = -1) {
+    Queue q;
+    queue_init(&q);
+    pool_whatmatchessolvable($self, keyname, pool_solvable->id, &q, marker);
+    return q;
+  }
+
 #ifdef SWIGRUBY
   %rename("isknownarch?") isknownarch;
 #endif
@@ -1437,7 +2132,7 @@ typedef struct {
       return 0;
     if (id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
       return 1;
-    if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id]))
+    if (pool->id2arch && pool_arch2score(pool, id) == 0)
       return 0;
     return 1;
   }
@@ -1464,9 +2159,90 @@ typedef struct {
     return sel;
   }
 
-  void setpooljobs_helper(Queue jobs) {
+  %newobject matchdeps;
+  Selection *matchdeps(const char *name, int flags, Id keyname, Id marker = -1) {
+    Selection *sel = new_Selection($self);
+    sel->flags = selection_make_matchdeps($self, &sel->q, name, flags, keyname, marker);
+    return sel;
+  }
+
+  %newobject matchdepid;
+  Selection *matchdepid(DepId dep, int flags, Id keyname, Id marker = -1) {
+    Selection *sel = new_Selection($self);
+    sel->flags = selection_make_matchdepid($self, &sel->q, dep, flags, keyname, marker);
+    return sel;
+  }
+
+  %newobject matchsolvable;
+  Selection *matchsolvable(XSolvable *solvable, int flags, Id keyname, Id marker = -1) {
+    Selection *sel = new_Selection($self);
+    sel->flags = selection_make_matchsolvable($self, &sel->q, solvable->id, flags, keyname, marker);
+    return sel;
+  }
+
+  Queue get_considered_list() {
+    Queue q;
+    queue_init(&q);
+    int i;
+    for (i = 2; i < $self->nsolvables; i++) {
+      if ($self->solvables[i].repo && (!$self->considered || MAPTST($self->considered, i)))
+        queue_push(&q, i);
+    }
+    return q;
+  }
+
+  Queue get_disabled_list() {
+    Queue q;
+    queue_init(&q);
+    int i;
+    for (i = 2; i < $self->nsolvables; i++) {
+      if ($self->solvables[i].repo && ($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 set_disabled_list(Queue q) {
+    int i;
+    Id p;
+    if (!q.count) {
+      if ($self->considered) {
+        map_free($self->considered);
+        $self->considered = solv_free($self->considered);
+      }
+      return;
+    }
+    if (!$self->considered) {
+      $self->considered = solv_calloc(1, sizeof(Map));
+      map_init($self->considered, $self->nsolvables);
+    }
+    map_setall($self->considered);
+    for (i = 0; i < q.count; i++) {
+      p = q.elements[i];
+      if (p > 0 && p < $self->nsolvables)
+        MAPCLR($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;
@@ -1476,36 +2252,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 {
@@ -1522,6 +2268,7 @@ rb_eval_string(
 #endif
 
   void free(bool reuseids = 0) {
+    appdata_clr_helper(&$self->appdata);
     repo_free($self, reuseids);
   }
   void empty(bool reuseids = 0) {
@@ -1533,6 +2280,17 @@ rb_eval_string(
   bool isempty() {
     return !$self->nsolvables;
   }
+
+  AppObjectPtr appdata;
+  %{
+  SWIGINTERN void Repo_appdata_set(Repo *repo, AppObjectPtr appdata) {
+    appdata_set_helper(&repo->appdata, appdata);
+  }
+  SWIGINTERN AppObjectPtr Repo_appdata_get(Repo *repo) {
+    return appdata_get_helper(repo->appdata);
+  }
+  %}
+
   bool add_solv(const char *name, int flags = 0) {
     FILE *fp = fopen(name, "r");
     int r;
@@ -1559,6 +2317,8 @@ rb_eval_string(
   bool add_rpmdb_reffp(FILE *reffp, int flags = 0) {
     return repo_add_rpmdb_reffp($self, reffp, flags) == 0;
   }
+#endif
+#ifdef ENABLE_RPMPKG
   %newobject add_rpm;
   XSolvable *add_rpm(const char *name, int flags = 0) {
     return new_XSolvable($self->pool, repo_add_rpm($self, name, flags));
@@ -1753,15 +2513,54 @@ rb_eval_string(
   XSolvable *find_pubkey(const char *keyid) {
     return new_XSolvable($self->pool, repo_find_pubkey($self, keyid));
   }
-#endif
+#endif
+
+  Repo *createshadow(const char *name) {
+    Repo *repo = repo_create($self->pool, name);
+    if ($self->idarraysize) {
+      repo_reserve_ids(repo, 0, $self->idarraysize);
+      memcpy(repo->idarraydata, $self->idarraydata, sizeof(Id) * $self->idarraysize);
+      repo->idarraysize = $self->idarraysize;
+    }
+    repo->start = $self->start;
+    repo->end = $self->end;
+    repo->nsolvables = $self->nsolvables;
+    return repo;
+  }
+
+  void moveshadow(Queue q) {
+    Pool *pool = $self->pool;
+    int i;
+    for (i = 0; i < q.count; i++) {
+      Solvable *s;
+      Id p = q.elements[i];
+      if (p < $self->start || p >= $self->end)
+        continue;
+      s = pool->solvables + p;
+      if ($self->idarraysize != s->repo->idarraysize)
+        continue;
+      s->repo = $self;
+    }
+  }
 
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
   bool __eq__(Repo *repo) {
     return $self == repo;
   }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
   bool __ne__(Repo *repo) {
     return $self != repo;
   }
-#if defined(SWIGPERL)
+#if defined(SWIGPYTHON)
+  int __hash__() {
+    return $self->repoid;
+  }
+#endif
+#if defined(SWIGPERL) || defined(SWIGTCL)
   %rename("str") __str__;
 #endif
   %newobject __str__;
@@ -1772,6 +2571,9 @@ rb_eval_string(
     sprintf(buf, "Repo#%d", $self->repoid);
     return solv_strdup(buf);
   }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
   %newobject __repr__;
   const char *__repr__() {
     char buf[20];
@@ -2038,6 +2840,9 @@ rb_eval_string(
     *solv::Datamatch::str = *solvc::Datamatch_stringify;
   }
 #endif
+#if defined(SWIGTCL)
+  %rename("stringify") __str__;
+#endif
   const char *__str__() {
     KeyValue kv = $self->kv;
     const char *str = repodata_stringify($self->pool, $self->data, $self->key, &kv, SEARCH_FILES | SEARCH_CHECKSUMS);
@@ -2125,7 +2930,6 @@ rb_eval_string(
 #ifdef SWIGPERL
   perliter(solv::Pool_repo_iterator)
 #endif
-  %newobject __next__;
   Repo *__next__() {
     Pool *pool = $self->pool;
     if ($self->id >= pool->nrepos)
@@ -2141,7 +2945,7 @@ rb_eval_string(
   void each() {
     Repo *n;
     while ((n = Pool_repo_iterator___next__($self)) != 0) {
-      rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(n), SWIGTYPE_p_Repo, SWIG_POINTER_OWN | 0));
+      rb_yield(SWIG_NewPointerObj(SWIG_as_voidptr(n), SWIGTYPE_p_Repo, 0 | 0));
     }
   }
 #endif
@@ -2262,18 +3066,32 @@ rb_eval_string(
   const char *str() {
     return pool_dep2str($self->pool, $self->id);
   }
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
   bool __eq__(Dep *s) {
     return $self->pool == s->pool && $self->id == s->id;
   }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
   bool __ne__(Dep *s) {
     return !Dep___eq__($self, s);
   }
-#if defined(SWIGPERL)
+#if defined(SWIGPYTHON)
+  int __hash__() {
+    return $self->id;
+  }
+#endif
+#if defined(SWIGPERL) || defined(SWIGTCL)
   %rename("str") __str__;
 #endif
   const char *__str__() {
     return pool_dep2str($self->pool, $self->id);
   }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
   %newobject __repr__;
   const char *__repr__() {
     char buf[20];
@@ -2332,6 +3150,9 @@ rb_eval_string(
   const char *lookup_location(unsigned int *OUTPUT) {
     return solvable_lookup_location($self->pool->solvables + $self->id, OUTPUT);
   }
+  const char *lookup_sourcepkg() {
+    return solvable_lookup_sourcepkg($self->pool->solvables + $self->id);
+  }
   %newobject Dataiterator;
   Dataiterator *Dataiterator(Id key, const char *match = 0, int flags = 0) {
     return new_Dataiterator($self->pool, 0, $self->id, key, match, flags);
@@ -2499,19 +3320,39 @@ rb_eval_string(
   int evrcmp(XSolvable *s2) {
     return pool_evrcmp($self->pool, $self->pool->solvables[$self->id].evr, s2->pool->solvables[s2->id].evr, EVRCMP_COMPARE);
   }
+#ifdef SWIGRUBY
+  %rename("matchesdep?") matchesdep;
+#endif
+  bool matchesdep(Id keyname, DepId id, Id marker = -1) {
+    return solvable_matchesdep($self->pool->solvables + $self->id, keyname, id, marker);
+  }
 
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
   bool __eq__(XSolvable *s) {
     return $self->pool == s->pool && $self->id == s->id;
   }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
   bool __ne__(XSolvable *s) {
     return !XSolvable___eq__($self, s);
   }
-#if defined(SWIGPERL)
+#if defined(SWIGPYTHON)
+  int __hash__() {
+    return $self->id;
+  }
+#endif
+#if defined(SWIGPERL) || defined(SWIGTCL)
   %rename("str") __str__;
 #endif
   const char *__str__() {
     return pool_solvid2str($self->pool, $self->id);
   }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
   %newobject __repr__;
   const char *__repr__() {
     char buf[20];
@@ -2572,7 +3413,32 @@ rb_eval_string(
       queue_push(&q, i);
     return q;
   }
-#if defined(SWIGPERL)
+  %typemap(out) Queue get_learnt Queue2Array(XRule *, 1, new_XRule(arg1->solv, id));
+  %newobject get_learnt;
+  Queue get_learnt() {
+    Queue q;
+    queue_init(&q);
+    solver_get_learnt($self->solv, $self->id, SOLVER_DECISIONLIST_PROBLEM, &q);
+    return q;
+  }
+  %typemap(out) Queue get_decisionlist Queue2Array(Decision *, 3, new_Decision(arg1->solv, id, idp[1], idp[2]));
+  %newobject get_decisionlist;
+  Queue get_decisionlist() {
+    Queue q;
+    queue_init(&q);
+    solver_get_decisionlist($self->solv, $self->id, SOLVER_DECISIONLIST_PROBLEM | SOLVER_DECISIONLIST_SORTED, &q);
+    return q;
+  }
+  %typemap(out) Queue get_decisionsetlist Queue2Array(Decisionset *, 1, decisionset_fromids(arg1->solv, idp + id, idp[1] - id + 1));
+  %newobject get_decisionsetlist;
+  Queue get_decisionsetlist() {
+    Queue q;
+    queue_init(&q);
+    solver_get_decisionlist($self->solv, $self->id, SOLVER_DECISIONLIST_PROBLEM | SOLVER_DECISIONLIST_SORTED | SOLVER_DECISIONLIST_WITHINFO | SOLVER_DECISIONLIST_MERGEDINFO, &q);
+    prepare_decisionset_queue($self->solv, &q);
+    return q;
+  }
+#if defined(SWIGPERL) || defined(SWIGTCL)
   %rename("str") __str__;
 #endif
   const char *__str__() {
@@ -2592,94 +3458,32 @@ rb_eval_string(
   int element_count() {
     return solver_solutionelement_count($self->solv, $self->problemid, $self->id);
   }
-
-  %typemap(out) Queue elements Queue2Array(Solutionelement *, 4, new_Solutionelement(arg1->solv, arg1->problemid, arg1->id, id, idp[1], idp[2], idp[3]));
+  %typemap(out) Queue elements Queue2Array(Solutionelement *, 3, new_Solutionelement(arg1->solv, arg1->problemid, arg1->id, id, idp[1], idp[2]));
   %newobject elements;
   Queue elements(bool expandreplaces=0) {
     Queue q;
-    int i, cnt;
     queue_init(&q);
-    cnt = solver_solutionelement_count($self->solv, $self->problemid, $self->id);
-    for (i = 1; i <= cnt; i++)
-      {
-        Id p, rp, type;
-        solver_next_solutionelement($self->solv, $self->problemid, $self->id, i - 1, &p, &rp);
-        if (p > 0) {
-          type = rp ? SOLVER_SOLUTION_REPLACE : SOLVER_SOLUTION_ERASE;
-        } else {
-          type = p;
-          p = rp;
-          rp = 0;
-        }
-        if (type == SOLVER_SOLUTION_REPLACE && expandreplaces) {
-          int illegal = policy_is_illegal(self->solv, self->solv->pool->solvables + p, self->solv->pool->solvables + rp, 0);
-          if (illegal) {
-            if ((illegal & POLICY_ILLEGAL_DOWNGRADE) != 0) {
-              queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_DOWNGRADE);
-              queue_push2(&q, p, rp);
-            }
-            if ((illegal & POLICY_ILLEGAL_ARCHCHANGE) != 0) {
-              queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_ARCHCHANGE);
-              queue_push2(&q, p, rp);
-            }
-            if ((illegal & POLICY_ILLEGAL_VENDORCHANGE) != 0) {
-              queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_VENDORCHANGE);
-              queue_push2(&q, p, rp);
-            }
-            if ((illegal & POLICY_ILLEGAL_NAMECHANGE) != 0) {
-              queue_push2(&q, i, SOLVER_SOLUTION_REPLACE_NAMECHANGE);
-              queue_push2(&q, p, rp);
-            }
-            continue;
-          }
-        }
-        queue_push2(&q, i, type);
-        queue_push2(&q, p, rp);
-      }
+    solver_all_solutionelements($self->solv, $self->problemid, $self->id, expandreplaces, &q);
     return q;
   }
 }
 
 %extend Solutionelement {
-  Solutionelement(Solver *solv, Id problemid, Id solutionid, Id id, Id type, Id p, Id rp) {
+  Solutionelement(Solver *solv, Id problemid, Id solutionid, Id type, Id p, Id rp) {
     Solutionelement *e;
     e = solv_calloc(1, sizeof(*e));
     e->solv = solv;
     e->problemid = problemid;
-    e->solutionid = id;
-    e->id = id;
+    e->solutionid = solutionid;
     e->type = type;
     e->p = p;
     e->rp = rp;
     return e;
   }
   const char *str() {
-    Id p = $self->type;
-    Id rp = $self->p;
-    int illegal = 0;
-    if (p == SOLVER_SOLUTION_ERASE)
-      {
-        p = rp;
-        rp = 0;
-      }
-    else if (p == SOLVER_SOLUTION_REPLACE)
-      {
-        p = rp;
-        rp = $self->rp;
-      }
-    else if (p == SOLVER_SOLUTION_REPLACE_DOWNGRADE)
-      illegal = POLICY_ILLEGAL_DOWNGRADE;
-    else if (p == SOLVER_SOLUTION_REPLACE_ARCHCHANGE)
-      illegal = POLICY_ILLEGAL_ARCHCHANGE;
-    else if (p == SOLVER_SOLUTION_REPLACE_VENDORCHANGE)
-      illegal = POLICY_ILLEGAL_VENDORCHANGE;
-    else if (p == SOLVER_SOLUTION_REPLACE_NAMECHANGE)
-      illegal = POLICY_ILLEGAL_NAMECHANGE;
-    if (illegal)
-      return pool_tmpjoin($self->solv->pool, "allow ", policy_illegal2str($self->solv, illegal, $self->solv->pool->solvables + $self->p, $self->solv->pool->solvables + $self->rp), 0);
-    return solver_solutionelement2str($self->solv, p, rp);
-  }
-  %typemap(out) Queue replaceelements Queue2Array(Solutionelement *, 1, new_Solutionelement(arg1->solv, arg1->problemid, arg1->solutionid, arg1->id, id, arg1->p, arg1->rp));
+    return solver_solutionelementtype2str($self->solv, $self->type, $self->p, $self->rp);
+  }
+  %typemap(out) Queue replaceelements Queue2Array(Solutionelement *, 1, new_Solutionelement(arg1->solv, arg1->problemid, arg1->solutionid, id, arg1->p, arg1->rp));
   %newobject replaceelements;
   Queue replaceelements() {
     Queue q;
@@ -2728,7 +3532,7 @@ rb_eval_string(
   %newobject Job;
   Job *Job() {
     Id extraflags = solver_solutionelement_extrajobflags($self->solv, $self->problemid, $self->solutionid);
-    if ($self->type == SOLVER_SOLUTION_JOB || SOLVER_SOLUTION_POOLJOB)
+    if ($self->type == SOLVER_SOLUTION_JOB || $self->type == SOLVER_SOLUTION_POOLJOB)
       return new_Job($self->solv->pool, SOLVER_NOOP, 0);
     if ($self->type == SOLVER_SOLUTION_INFARCH || $self->type == SOLVER_SOLUTION_DISTUPGRADE || $self->type == SOLVER_SOLUTION_BEST)
       return new_Job($self->solv->pool, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_NOTBYUSER|extraflags, $self->p);
@@ -2752,6 +3556,9 @@ rb_eval_string(
   static const int SOLVER_RULE_PKG_OBSOLETES = SOLVER_RULE_PKG_OBSOLETES;
   static const int SOLVER_RULE_PKG_IMPLICIT_OBSOLETES = SOLVER_RULE_PKG_IMPLICIT_OBSOLETES;
   static const int SOLVER_RULE_PKG_INSTALLED_OBSOLETES = SOLVER_RULE_PKG_INSTALLED_OBSOLETES;
+  static const int SOLVER_RULE_PKG_RECOMMENDS = SOLVER_RULE_PKG_RECOMMENDS;
+  static const int SOLVER_RULE_PKG_CONSTRAINS = SOLVER_RULE_PKG_CONSTRAINS;
+  static const int SOLVER_RULE_PKG_SUPPLEMENTS = SOLVER_RULE_PKG_SUPPLEMENTS;
   static const int SOLVER_RULE_UPDATE = SOLVER_RULE_UPDATE;
   static const int SOLVER_RULE_FEATURE = SOLVER_RULE_FEATURE;
   static const int SOLVER_RULE_JOB = SOLVER_RULE_JOB;
@@ -2763,6 +3570,11 @@ rb_eval_string(
   static const int SOLVER_RULE_INFARCH = SOLVER_RULE_INFARCH;
   static const int SOLVER_RULE_CHOICE = SOLVER_RULE_CHOICE;
   static const int SOLVER_RULE_LEARNT = SOLVER_RULE_LEARNT;
+  static const int SOLVER_RULE_BEST  = SOLVER_RULE_BEST;
+  static const int SOLVER_RULE_YUMOBS = SOLVER_RULE_YUMOBS;
+  static const int SOLVER_RULE_RECOMMENDS = SOLVER_RULE_RECOMMENDS;
+  static const int SOLVER_RULE_BLACK = SOLVER_RULE_BLACK;
+  static const int SOLVER_RULE_STRICT_REPO_PRIORITY = SOLVER_RULE_STRICT_REPO_PRIORITY;
 
   static const int SOLVER_SOLUTION_JOB = SOLVER_SOLUTION_JOB;
   static const int SOLVER_SOLUTION_POOLJOB = SOLVER_SOLUTION_POOLJOB;
@@ -2802,6 +3614,11 @@ rb_eval_string(
   static const int SOLVER_FLAG_FOCUS_INSTALLED = SOLVER_FLAG_FOCUS_INSTALLED;
   static const int SOLVER_FLAG_YUM_OBSOLETES = SOLVER_FLAG_YUM_OBSOLETES;
   static const int SOLVER_FLAG_NEED_UPDATEPROVIDE = SOLVER_FLAG_NEED_UPDATEPROVIDE;
+  static const int SOLVER_FLAG_FOCUS_BEST = SOLVER_FLAG_FOCUS_BEST;
+  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;
@@ -2814,6 +3631,8 @@ rb_eval_string(
   static const int SOLVER_REASON_RESOLVE_ORPHAN = SOLVER_REASON_RESOLVE_ORPHAN;
   static const int SOLVER_REASON_RECOMMENDED = SOLVER_REASON_RECOMMENDED;
   static const int SOLVER_REASON_SUPPLEMENTED = SOLVER_REASON_SUPPLEMENTED;
+  static const int SOLVER_REASON_UNSOLVABLE = SOLVER_REASON_UNSOLVABLE;
+  static const int SOLVER_REASON_PREMISE = SOLVER_REASON_PREMISE;
 
   /* legacy */
   static const int SOLVER_RULE_RPM = SOLVER_RULE_RPM;
@@ -2828,66 +3647,77 @@ 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) {
+
+  %typemap(out) Queue solve Queue2Array(Problem *, 1, new_Problem(arg1, id));
+  %newobject solve;
+  Queue solve(Queue solvejobs) {
     Queue q;
     int i, cnt;
     queue_init(&q);
-    solver_solve($self, &jobs);
+    solver_solve($self, &solvejobs);
     cnt = solver_problem_count($self);
     for (i = 1; i <= cnt; i++)
       queue_push(&q, i);
     return q;
   }
+
   %newobject transaction;
   Transaction *transaction() {
     return solver_create_transaction($self);
   }
 
+  /* legacy, use get_decision */
   int describe_decision(XSolvable *s, XRule **OUTPUT) {
-    int ruleid;
+    Id ruleid;
     int reason = solver_describe_decision($self, s->id, &ruleid);
     *OUTPUT = new_XRule($self, ruleid);
     return reason;
   }
+  /* legacy, use get_decision and the info/allinfos method */
+  %newobject describe_weakdep_decision_raw;
+  Queue describe_weakdep_decision_raw(XSolvable *s) {
+    Queue q;
+    queue_init(&q);
+    solver_describe_weakdep_decision($self, s->id, &q);
+    return q;
+  }
+#if defined(SWIGPYTHON)
+  %pythoncode {
+    def describe_weakdep_decision(self, s):
+      d = iter(self.describe_weakdep_decision_raw(s))
+      return [ (t, XSolvable(self.pool, sid), Dep(self.pool, id)) for t, sid, id in zip(d, d, d) ]
+  }
+#endif
+#if defined(SWIGPERL)
+  %perlcode {
+    sub solv::Solver::describe_weakdep_decision {
+      my ($self, $s) = @_;
+      my $pool = $self->{'pool'};
+      my @res;
+      my @d = $self->describe_weakdep_decision_raw($s);
+      push @res, [ splice(@d, 0, 3) ] while @d;
+      return map { [ $_->[0], solv::XSolvable->new($pool, $_->[1]), solv::Dep->new($pool, $_->[2]) ] } @res;
+    }
+  }
+#endif
+#if defined(SWIGRUBY)
+%init %{
+rb_eval_string(
+    "class Solv::Solver\n"
+    "  def describe_weakdep_decision(s)\n"
+    "    self.describe_weakdep_decision_raw(s).each_slice(3).map { |t, sid, id| [ t, Solv::XSolvable.new(self.pool, sid), Solv::Dep.new(self.pool, id)] }\n"
+    "  end\n"
+    "end\n"
+  );
+%}
+#endif
 
   int alternatives_count() {
     return solver_alternatives_count($self);
   }
 
-  %newobject alternative;
-  Alternative *alternative(Id aid) {
+  %newobject get_alternative;
+  Alternative *get_alternative(Id aid) {
     Alternative *a = solv_calloc(1, sizeof(*a));
     a->solv = $self;
     queue_init(&a->choices);
@@ -2904,9 +3734,9 @@ rb_eval_string(
     return a;
   }
 
-  %typemap(out) Queue all_alternatives Queue2Array(Alternative *, 1, Solver_alternative(arg1, id));
-  %newobject all_alternatives;
-  Queue all_alternatives() {
+  %typemap(out) Queue alternatives Queue2Array(Alternative *, 1, Solver_get_alternative(arg1, id));
+  %newobject alternatives;
+  Queue alternatives() {
     Queue q;
     int i, cnt;
     queue_init(&q);
@@ -2915,6 +3745,96 @@ rb_eval_string(
       queue_push(&q, i);
     return q;
   }
+
+  bool write_testcase(const char *dir) {
+    return testcase_write($self, dir, TESTCASE_RESULT_TRANSACTION | TESTCASE_RESULT_PROBLEMS, 0, 0);
+  }
+
+  Queue raw_decisions(int filter=0) {
+    Queue q;
+    queue_init(&q);
+    solver_get_decisionqueue($self, &q);
+    if (filter) {
+      int i, j;
+      for (i = j = 0; i < q.count; i++)
+        if ((filter > 0 && q.elements[i] > 1) ||
+            (filter < 0 && q.elements[i] < 0))
+          q.elements[j++] = q.elements[i];
+      queue_truncate(&q, j);
+    }
+    return q;
+  }
+
+  %typemap(out) Queue all_decisions Queue2Array(Decision *, 3, new_Decision(arg1, id, idp[1], idp[2]));
+  %newobject all_decisions;
+  Queue all_decisions(int filter=0) {
+    int i, j, cnt;
+    Queue q;
+    queue_init(&q);
+    solver_get_decisionqueue($self, &q);
+    if (filter) {
+      for (i = j = 0; i < q.count; i++)
+        if ((filter > 0 && q.elements[i] > 1) ||
+            (filter < 0 && q.elements[i] < 0))
+          q.elements[j++] = q.elements[i];
+      queue_truncate(&q, j);
+    }
+    cnt = q.count;
+    for (i = 0; i < cnt; i++) {
+      Id ruleid, p = q.elements[i];
+      int reason;
+      if (p == 0 || p == 1)
+        continue;       /* ignore system solvable */
+      reason = solver_describe_decision($self, p > 0 ? p : -p, &ruleid);
+      queue_push(&q, p);
+      queue_push2(&q, reason, ruleid);
+    }
+    queue_deleten(&q, 0, cnt);
+    return q;
+  }
+
+  %newobject get_decision;
+  Decision *get_decision(XSolvable *s) {
+    Id info;
+    int lvl = solver_get_decisionlevel($self, s->id);
+    Id p = lvl > 0 ? s->id : -s->id;
+    int reason = solver_describe_decision($self, p, &info);
+    return new_Decision($self, p, reason, info);
+  }
+
+  %typemap(out) Queue get_learnt Queue2Array(XRule *, 1, new_XRule(arg1, id));
+  %newobject get_learnt;
+  Queue get_learnt(XSolvable *s) {
+    Queue q;
+    queue_init(&q);
+    solver_get_learnt($self, s->id, SOLVER_DECISIONLIST_SOLVABLE, &q);
+    return q;
+  }
+  %typemap(out) Queue get_decisionlist Queue2Array(Decision *, 3, new_Decision(arg1, id, idp[1], idp[2]));
+  %newobject get_decisionlist;
+  Queue get_decisionlist(XSolvable *s) {
+    Queue q;
+    queue_init(&q);
+    solver_get_decisionlist($self, s->id, SOLVER_DECISIONLIST_SOLVABLE, &q);
+    return q;
+  }
+
+  %typemap(out) Queue get_recommended Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject get_recommended;
+  Queue get_recommended(bool noselected=0) {
+    Queue q;
+    queue_init(&q);
+    solver_get_recommendations($self, &q, NULL, noselected);
+    return q;
+  }
+  %typemap(out) Queue get_suggested Queue2Array(XSolvable *, 1, new_XSolvable(arg1->pool, id));
+  %newobject get_suggested;
+  Queue get_suggested(bool noselected=0) {
+    Queue q;
+    queue_init(&q);
+    solver_get_recommendations($self, NULL, &q, noselected);
+    return q;
+  }
 }
 
 %extend Transaction {
@@ -3039,7 +3959,7 @@ rb_eval_string(
   int steptype(XSolvable *s, int mode) {
     return transaction_type($self, s->id, mode);
   }
-  int calc_installsizechange() {
+  long long calc_installsizechange() {
     return transaction_calc_installsizechange($self);
   }
   void order(int flags=0) {
@@ -3097,9 +4017,9 @@ rb_eval_string(
   Ruleinfo *info() {
     Id type, source, target, dep;
     type = solver_ruleinfo($self->solv, $self->id, &source, &target, &dep);
-    return new_Ruleinfo($self, type, source, target, dep);
+    return new_Ruleinfo($self->solv, $self->id, type, source, target, dep);
   }
-  %typemap(out) Queue allinfos Queue2Array(Ruleinfo *, 4, new_Ruleinfo(arg1, id, idp[1], idp[2], idp[3]));
+  %typemap(out) Queue allinfos Queue2Array(Ruleinfo *, 4, new_Ruleinfo(arg1->solv, arg1->id, id, idp[1], idp[2], idp[3]));
   %newobject allinfos;
   Queue allinfos() {
     Queue q;
@@ -3108,12 +4028,52 @@ rb_eval_string(
     return q;
   }
 
+  %typemap(out) Queue get_learnt Queue2Array(XRule *, 1, new_XRule(arg1->solv, id));
+  %newobject get_learnt;
+  Queue get_learnt() {
+    Queue q;
+    queue_init(&q);
+    solver_get_learnt($self->solv, $self->id, SOLVER_DECISIONLIST_LEARNTRULE, &q);
+    return q;
+  }
+  %typemap(out) Queue get_decisionlist Queue2Array(Decision *, 3, new_Decision(arg1->solv, id, idp[1], idp[2]));
+  %newobject get_decisionlist;
+  Queue get_decisionlist() {
+    Queue q;
+    queue_init(&q);
+    solver_get_decisionlist($self->solv, $self->id, SOLVER_DECISIONLIST_LEARNTRULE | SOLVER_DECISIONLIST_SORTED, &q);
+    return q;
+  }
+  %typemap(out) Queue get_decisionsetlist Queue2Array(Decisionset *, 1, decisionset_fromids(arg1->solv, idp + id, idp[1] - id + 1));
+  %newobject get_decisionsetlist;
+  Queue get_decisionsetlist() {
+    Queue q;
+    queue_init(&q);
+    solver_get_decisionlist($self->solv, $self->id, SOLVER_DECISIONLIST_LEARNTRULE | SOLVER_DECISIONLIST_SORTED | SOLVER_DECISIONLIST_WITHINFO | SOLVER_DECISIONLIST_MERGEDINFO, &q);
+    prepare_decisionset_queue($self->solv, &q);
+    return q;
+  }
+
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
   bool __eq__(XRule *xr) {
     return $self->solv == xr->solv && $self->id == xr->id;
   }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
   bool __ne__(XRule *xr) {
     return !XRule___eq__($self, xr);
   }
+#if defined(SWIGPYTHON)
+  int __hash__() {
+    return $self->id;
+  }
+#endif
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
   %newobject __repr__;
   const char *__repr__() {
     char buf[20];
@@ -3123,10 +4083,10 @@ rb_eval_string(
 }
 
 %extend Ruleinfo {
-  Ruleinfo(XRule *r, Id type, Id source, Id target, Id dep_id) {
+  Ruleinfo(Solver *solv, Id rid, Id type, Id source, Id target, Id dep_id) {
     Ruleinfo *ri = solv_calloc(1, sizeof(*ri));
-    ri->solv = r->solv;
-    ri->rid = r->id;
+    ri->solv = solv;
+    ri->rid = rid;
     ri->type = type;
     ri->source = source;
     ri->target = target;
@@ -3153,6 +4113,12 @@ rb_eval_string(
   const char *problemstr() {
     return solver_problemruleinfo2str($self->solv, $self->type, $self->source, $self->target, $self->dep_id);
   }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("str") __str__;
+#endif
+  const char *__str__() {
+    return solver_ruleinfo2str($self->solv, $self->type, $self->source, $self->target, $self->dep_id);
+  }
 }
 
 %extend XRepodata {
@@ -3168,9 +4134,15 @@ rb_eval_string(
   void set_id(Id solvid, Id keyname, DepId id) {
     repodata_set_id(repo_id2repodata($self->repo, $self->id), solvid, keyname, id);
   }
+  void set_num(Id solvid, Id keyname, unsigned long long num) {
+    repodata_set_num(repo_id2repodata($self->repo, $self->id), solvid, keyname, num);
+  }
   void set_str(Id solvid, Id keyname, const char *str) {
     repodata_set_str(repo_id2repodata($self->repo, $self->id), solvid, keyname, str);
   }
+  void set_void(Id solvid, Id keyname) {
+    repodata_set_void(repo_id2repodata($self->repo, $self->id), solvid, keyname);
+  }
   void set_poolstr(Id solvid, Id keyname, const char *str) {
     repodata_set_poolstr(repo_id2repodata($self->repo, $self->id), solvid, keyname, str);
   }
@@ -3185,9 +4157,27 @@ rb_eval_string(
     if (buf)
       repodata_set_bin_checksum(repo_id2repodata($self->repo, $self->id), solvid, keyname, solv_chksum_get_type(chksum), buf);
   }
+  void set_sourcepkg(Id solvid, const char *sourcepkg) {
+    repodata_set_sourcepkg(repo_id2repodata($self->repo, $self->id), solvid, sourcepkg);
+  }
+  void set_location(Id solvid, unsigned int mediano, const char *location) {
+    repodata_set_location(repo_id2repodata($self->repo, $self->id), solvid, mediano, 0, location);
+  }
+  void unset(Id solvid, Id keyname) {
+    repodata_unset(repo_id2repodata($self->repo, $self->id), solvid, keyname);
+  }
   const char *lookup_str(Id solvid, Id keyname) {
     return repodata_lookup_str(repo_id2repodata($self->repo, $self->id), solvid, keyname);
   }
+  Id lookup_id(Id solvid, Id keyname) {
+    return repodata_lookup_id(repo_id2repodata($self->repo, $self->id), solvid, keyname);
+  }
+  unsigned long long lookup_num(Id solvid, Id keyname, unsigned long long notfound = 0) {
+    return repodata_lookup_num(repo_id2repodata($self->repo, $self->id), solvid, keyname, notfound);
+  }
+  bool lookup_void(Id solvid, Id keyname) {
+    return repodata_lookup_void(repo_id2repodata($self->repo, $self->id), solvid, keyname);
+  }
   Queue lookup_idarray(Id solvid, Id keyname) {
     Queue r;
     queue_init(&r);
@@ -3211,6 +4201,18 @@ rb_eval_string(
   bool write(FILE *fp) {
     return repodata_write(repo_id2repodata($self->repo, $self->id), fp) == 0;
   }
+  Id str2dir(const char *dir, bool create=1) {
+    Repodata *data = repo_id2repodata($self->repo, $self->id);
+    return repodata_str2dir(data, dir, create);
+  }
+  const char *dir2str(Id did, const char *suf = 0) {
+    Repodata *data = repo_id2repodata($self->repo, $self->id);
+    return repodata_dir2str(data, did, suf);
+  }
+  void add_dirstr(Id solvid, Id keyname, Id dir, const char *str) {
+    Repodata *data = repo_id2repodata($self->repo, $self->id);
+    repodata_add_dirstr(data, solvid, keyname, dir, str);
+  }
   bool add_solv(FILE *fp, int flags = 0) {
     Repodata *data = repo_id2repodata($self->repo, $self->id);
     int r, oldstate = data->state;
@@ -3224,12 +4226,26 @@ rb_eval_string(
     Repodata *data = repo_id2repodata($self->repo, $self->id);
     repodata_extend_block(data, data->repo->start, data->repo->end - data->repo->start);
   }
+#if defined(SWIGTCL)
+  %rename("==") __eq__;
+#endif
   bool __eq__(XRepodata *xr) {
     return $self->repo == xr->repo && $self->id == xr->id;
   }
+#if defined(SWIGTCL)
+  %rename("!=") __ne__;
+#endif
   bool __ne__(XRepodata *xr) {
     return !XRepodata___eq__($self, xr);
   }
+#if defined(SWIGPYTHON)
+  int __hash__() {
+    return $self->id;
+  }
+#endif
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("repr") __repr__;
+#endif
   %newobject __repr__;
   const char *__repr__() {
     char buf[20];
@@ -3291,28 +4307,179 @@ rb_eval_string(
       return new_Dep(a->solv->pool, a->dep_id);
     }
   %}
-
   Queue choices_raw() {
-    Queue r;
-    queue_init_clone(&r, &$self->choices);
-    return r;
+    Queue q;
+    queue_init_clone(&q, &$self->choices);
+    return q;
   }
-
   %typemap(out) Queue choices Queue2Array(XSolvable *, 1, new_XSolvable(arg1->solv->pool, id));
   Queue choices() {
     int i;
-    Queue r;
-    queue_init_clone(&r, &$self->choices);
-    for (i = 0; i < r.count; i++)
-      if (r.elements[i] < 0)
-        r.elements[i] = -r.elements[i];
-    return r;
+    Queue q;
+    queue_init_clone(&q, &$self->choices);
+    for (i = 0; i < q.count; i++)
+      if (q.elements[i] < 0)
+        q.elements[i] = -q.elements[i];
+    return q;
   }
-
-#if defined(SWIGPERL)
+#if defined(SWIGPERL) || defined(SWIGTCL)
   %rename("str") __str__;
 #endif
   const char *__str__() {
     return solver_alternative2str($self->solv, $self->type, $self->type == SOLVER_ALTERNATIVE_TYPE_RULE ? $self->rid : $self->dep_id, $self->from_id);
   }
 }
+
+%extend Decision {
+  Decision(Solver *solv, Id p, int reason, Id infoid) {
+    Decision *d = solv_calloc(1, sizeof(*d));
+    d->solv = solv;
+    d->p = p;
+    d->reason = reason;
+    d->infoid = infoid;
+    return d;
+  }
+  %newobject rule;
+  XRule * const rule;
+  %newobject solvable;
+  XSolvable * const solvable;
+  %{
+    SWIGINTERN XRule *Decision_rule_get(Decision *d) {
+      return d->reason == SOLVER_REASON_WEAKDEP || d->infoid <= 0 ? 0 : new_XRule(d->solv, d->infoid);
+    }
+    SWIGINTERN XSolvable *Decision_solvable_get(Decision *d) {
+      return new_XSolvable(d->solv->pool, d->p >= 0 ? d->p : -d->p);
+    }
+  %}
+  %newobject info;
+  Ruleinfo *info() {
+    Id type, source, target, dep;
+    if ($self->reason == SOLVER_REASON_WEAKDEP) {
+      type = solver_weakdepinfo($self->solv, $self->p, &source, &target, &dep);
+    } else if ($self->infoid) {
+      type = solver_ruleinfo($self->solv, $self->infoid, &source, &target, &dep);
+    } else {
+      return 0;
+    }
+    return new_Ruleinfo($self->solv, $self->infoid, type, source, target, dep);
+  }
+  %typemap(out) Queue allinfos Queue2Array(Ruleinfo *, 4, new_Ruleinfo(arg1->solv, arg1->infoid, id, idp[1], idp[2], idp[3]));
+  %newobject allinfos;
+  Queue allinfos() {
+    Queue q;
+    queue_init(&q);
+    if ($self->reason == SOLVER_REASON_WEAKDEP) {
+      solver_allweakdepinfos($self->solv, $self->p, &q);
+    } else if ($self->infoid) {
+      solver_allruleinfos($self->solv, $self->infoid, &q);
+    }
+    return q;
+  }
+  const char *reasonstr(bool noinfo=0) {
+    if (noinfo)
+      return solver_reason2str($self->solv, $self->reason);
+    return solver_decisionreason2str($self->solv, $self->p, $self->reason, $self->infoid);
+  }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("str") __str__;
+#endif
+  const char *__str__() {
+    Pool *pool = $self->solv->pool;
+    if ($self->p == 0 && $self->reason == SOLVER_REASON_UNSOLVABLE)
+      return "unsolvable";
+    if ($self->p >= 0)
+      return pool_tmpjoin(pool, "install ", pool_solvid2str(pool, $self->p), 0);
+    else
+      return pool_tmpjoin(pool, "conflict ", pool_solvid2str(pool, -$self->p), 0);
+  }
+}
+
+%extend Decisionset {
+  Decisionset(Solver *solv) {
+    Decisionset *d = solv_calloc(1, sizeof(*d));
+    d->solv = solv;
+    queue_init(&d->decisionlistq);
+    return d;
+  }
+  ~Decisionset() {
+    queue_free(&$self->decisionlistq);
+    solv_free($self);
+  }
+  %newobject info;
+  Ruleinfo *info() {
+    return new_Ruleinfo($self->solv, $self->infoid, $self->type, $self->source, $self->target, $self->dep_id);
+  }
+  %newobject dep;
+  Dep * const dep;
+  %{
+    SWIGINTERN Dep *Decisionset_dep_get(Decisionset *d) {
+      return new_Dep(d->solv->pool, d->dep_id);
+    }
+  %}
+  %typemap(out) Queue solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1->solv->pool, id));
+  %newobject solvables;
+  Queue solvables() {
+    Queue q;
+    int i;
+    queue_init(&q);
+    for (i = 0; i < $self->decisionlistq.count; i += 3)
+      if ($self->decisionlistq.elements[i] != 0)
+        queue_push(&q, $self->decisionlistq.elements[i] > 0 ? $self->decisionlistq.elements[i] : -$self->decisionlistq.elements[i]);
+    return q;
+  }
+  %typemap(out) Queue decisions Queue2Array(Decision *, 3, new_Decision(arg1->solv, id, idp[1], idp[2]));
+  %newobject decisions;
+  Queue decisions() {
+    Queue q;
+    queue_init_clone(&q, &$self->decisionlistq);
+    return q;
+  }
+  const char *reasonstr(bool noinfo=0) {
+    if (noinfo || !$self->type)
+      return solver_reason2str($self->solv, $self->reason);
+    return solver_decisioninfo2str($self->solv, $self->bits, $self->type, $self->source, $self->target, $self->dep_id);
+  }
+#if defined(SWIGPERL) || defined(SWIGTCL)
+  %rename("str") __str__;
+#endif
+  const char *__str__() {
+    Pool *pool = $self->solv->pool;
+    Queue q;
+    int i;
+    const char *s;
+    if (!$self->decisionlistq.elements)
+      return "";
+    if ($self->p == 0 && $self->reason == SOLVER_REASON_UNSOLVABLE)
+      return "unsolvable";
+    queue_init(&q);
+    for (i = 0; i < $self->decisionlistq.count; i += 3)
+      if ($self->decisionlistq.elements[i] != 0)
+        queue_push(&q, $self->decisionlistq.elements[i] > 0 ? $self->decisionlistq.elements[i] : -$self->decisionlistq.elements[i]);
+    s = pool_solvidset2str(pool, &q);
+    queue_free(&q);
+    return pool_tmpjoin(pool, $self->p >= 0 ? "install " : "conflict ", s, 0);
+  }
+}
+
+
+#if defined(SWIGTCL)
+%init %{
+  Tcl_Eval(interp,
+"proc solv::iter {varname iter body} {\n"\
+"  while 1 {\n"\
+"    set value [$iter __next__]\n"\
+"    if {$value eq \"NULL\"} { break }\n"\
+"    uplevel [list set $varname $value]\n"\
+"    set code [catch {uplevel $body} result]\n"\
+"    switch -exact -- $code {\n"\
+"      0 {}\n"\
+"      3 { return }\n"\
+"      4 {}\n"\
+"      default { return -code $code $result }\n"\
+"    }\n"\
+"  }\n"\
+"}\n"
+  );
+%}
+#endif
+