Imported Upstream version 0.7.4 upstream/0.7.4
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 10 Sep 2019 06:38:51 +0000 (15:38 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 10 Sep 2019 06:38:51 +0000 (15:38 +0900)
26 files changed:
CMakeLists.txt
NEWS
VERSION.cmake
bindings/solv.i
doc/gen/libsolv-bindings.3
doc/libsolv-bindings.txt
doc/rpmdb2solv.txt
ext/repo_rpmdb.c
ext/repo_updateinfoxml.c
ext/testcase.c
package/libsolv.changes
src/CMakeLists.txt
src/conda.c [new file with mode: 0644]
src/conda.h [new file with mode: 0644]
src/evr.c
src/knownid.h
src/policy.c
src/pool.c
src/pool.h
src/poolid.c
src/repodata.c
src/sha2.c
src/solver.c
src/solvversion.h.in
test/testcases/cleandeps/cleandeps_up3.t [new file with mode: 0644]
tools/rpmdb2solv.c

index 1deef57..ab385f1 100644 (file)
@@ -27,6 +27,7 @@ OPTION (ENABLE_MDKREPO "Build with mandriva/mageia repository support?" OFF)
 OPTION (ENABLE_ARCHREPO "Build with archlinux repository support?" OFF)
 OPTION (ENABLE_CUDFREPO "Build with cudf repository support?" OFF)
 OPTION (ENABLE_HAIKU "Build with Haiku package support?" OFF)
+OPTION (ENABLE_CONDA "Build with conda dependency support?" OFF)
 OPTION (ENABLE_APPDATA "Build with AppStream appdata support?" OFF)
 
 OPTION (MULTI_SEMANTICS "Build with support for multiple distribution types?" OFF)
@@ -178,18 +179,23 @@ ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENAB
 
 IF (ENABLE_ZLIB_COMPRESSION)
 FIND_PACKAGE (ZLIB REQUIRED)
+INCLUDE_DIRECTORIES (${ZLIB_INCLUDE_DIRS})
 ENDIF (ENABLE_ZLIB_COMPRESSION)
 
 IF (ENABLE_LZMA_COMPRESSION)
 FIND_PACKAGE (LZMA REQUIRED)
+INCLUDE_DIRECTORIES (${LZMA_INCLUDE_DIR})
 ENDIF (ENABLE_LZMA_COMPRESSION)
 
 IF (ENABLE_BZIP2_COMPRESSION)
 FIND_PACKAGE (BZip2 REQUIRED)
+INCLUDE_DIRECTORIES (${BZIP2_INCLUDE_DIRS})
 ENDIF (ENABLE_BZIP2_COMPRESSION)
 
 IF (ENABLE_ZSTD_COMPRESSION)
 FIND_LIBRARY (ZSTD_LIBRARY NAMES zstd)
+FIND_PATH (ZSTD_INCLUDE_DIRS zstd.h)
+INCLUDE_DIRECTORIES (${ZSTD_INCLUDE_DIRS})
 ENDIF (ENABLE_ZSTD_COMPRESSION)
 
 IF (RPM5)
@@ -202,6 +208,10 @@ PKG_CHECK_MODULES (RPM REQUIRED rpm)
 INCLUDE_DIRECTORIES (${RPM_INCLUDE_DIRS})
 ENDIF (RPM5)
 
+IF (ENABLE_CONDA)
+SET (MULTI_SEMANTICS ON)
+ENDIF (ENABLE_CONDA)
+
 IF (MULTI_SEMANTICS)
 MESSAGE (STATUS "Enabling multi dist support")
 ENDIF (MULTI_SEMANTICS)
@@ -285,7 +295,7 @@ FOREACH (VAR HAVE_STRCHRNUL HAVE_FOPENCOOKIE HAVE_FUNOPEN WORDS_BIGENDIAN
 ENDFOREACH (VAR)
 
 FOREACH (VAR
-  ENABLE_LINKED_PKGS ENABLE_COMPLEX_DEPS MULTI_SEMANTICS)
+  ENABLE_LINKED_PKGS ENABLE_COMPLEX_DEPS MULTI_SEMANTICS ENABLE_CONDA)
   IF(${VAR})
     ADD_DEFINITIONS (-D${VAR}=1)
     SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR})
diff --git a/NEWS b/NEWS
index 4ed1d27..198fca3 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,15 @@
 This file contains the major changes between
 libsolv versions:
 
+Version 0.7.4
+- selected bug fixes:
+  * repo_add_rpmdb: do not copy bad solvables from the old solv file
+  * fix cleandeps updates not updating all packages
+- new features:
+  * bindings: support pool.matchsolvable(), pool.whatmatchessolvable()
+    pool.best_solvables() and selection.matchsolvable()
+  * experimental DISTTYPE_CONDA and REL_CONDA support
+
 Version 0.7.3
 - selected bug fixes:
   * fixed a couple of null pointer derefs and potential memory
index 2cab83b..80d0e03 100644 (file)
@@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "1")
 
 SET(LIBSOLV_MAJOR "0")
 SET(LIBSOLV_MINOR "7")
-SET(LIBSOLV_PATCH "3")
+SET(LIBSOLV_PATCH "4")
 
index adaf1a3..ad265a5 100644 (file)
@@ -381,6 +381,7 @@ typedef struct {
 
 %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))
 
 
 
@@ -1007,6 +1008,7 @@ typedef int Id;
 %constant int REL_ERROR;
 %constant int REL_WITHOUT;
 %constant int REL_UNLESS;
+%constant int REL_CONDA;
 
 typedef struct {
   Pool* const pool;
@@ -1378,7 +1380,7 @@ typedef struct {
     if ($self->pool == lsel->pool)
       selection_subtract($self->pool, &$self->q, &lsel->q);
   }
-  
+
   void select(const char *name, int flags) {
     if ((flags & SELECTION_MODEBITS) == 0)
       flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
@@ -1394,6 +1396,11 @@ typedef struct {
       flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
     $self->flags = selection_make_matchdepid($self->pool, &$self->q, dep, flags, keyname, marker);
   }
+  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;
@@ -1707,7 +1714,7 @@ typedef struct {
     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); 
+    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]);
@@ -1945,6 +1952,14 @@ 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);
@@ -1969,6 +1984,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
@@ -2019,6 +2043,13 @@ typedef struct {
     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);
index 9f84c77..88ab97d 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: Libsolv-Bindings
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 12/06/2018
+.\"      Date: 03/16/2019
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "LIBSOLV\-BINDINGS" "3" "12/06/2018" "libsolv" "LIBSOLV"
+.TH "LIBSOLV\-BINDINGS" "3" "03/16/2019" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -851,6 +851,36 @@ Return all solvables that provide the specified dependency\&. You can use either
 .RS 4
 .\}
 .nf
+\fBSolvable *best_solvables(Solvable *\fR\fIsolvables\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+my \fI@solvables\fR \fB=\fR \fI$pool\fR\fB\->best_solvables(\fR\fI$solvables\fR\fB)\fR;
+\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.best_solvables(\fR\fIsolvables\fR\fB)\fR
+\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.best_solvables(\fR\fIsolvables\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Filter list of solvables by repo priority, architecture and version\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *whatmatchessolvable(Id\fR \fIkeyname\fR\fB, Solvable\fR \fIsolvable\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+my \fI@solvables\fR \fB=\fR \fI$pool\fR\fB\->whatmatchessolvable(\fR\fI$keyname\fR\fB,\fR \fI$solvable\fR\fB)\fR
+\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatmatchessolvable(\fR\fIkeyname\fR\fB,\fR \fIsolvable\fR\fB)\fR
+\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatmatchessolvable(\fR\fIkeyname\fR\fB,\fR \fIsolvable\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return all solvables that match package dependencies against solvable\(cqs provides\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
 \fBId *matchprovidingids(const char *\fR\fImatch\fR\fB, int\fR \fIflags\fR\fB)\fR
 my \fI@ids\fR \fB=\fR \fI$pool\fR\fB\->matchprovidingids(\fR\fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
 \fIids\fR \fB=\fR \fIpool\fR\fB\&.matchprovidingids(\fR\fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
@@ -1017,7 +1047,7 @@ Create a selection by matching package dependencies against the specified string
 .\}
 .nf
 \fBSelection matchdepid(DepId\fR \fIdep\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
-my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->matchdepid(\fR\fIdep\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->matchdepid(\fR\fI$dep\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
 \fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
 \fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
 .fi
@@ -1031,6 +1061,21 @@ Create a selection by matching package dependencies against the specified depend
 .RS 4
 .\}
 .nf
+\fBSelection matchsolvable(Solvable\fR \fIsolvable\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->matchsolvable(\fR\fI$solvable\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchsolvable(\fR\fIsolvable\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchsolvable(\fR\fIsolvable\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a selection by matching package dependencies against the specified solvable\(cqs provides\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
 \fBvoid setpooljobs(Jobs *\fR\fIjobs\fR\fB)\fR
 \fI$pool\fR\fB\->setpooljobs(\e\fR\fI@jobs\fR\fB)\fR;
 \fIpool\fR\fB\&.setpooljobs(\fR\fIjobs\fR\fB)\fR
@@ -3347,6 +3392,21 @@ Do a matchdepid operation and combine the result with the current selection\&.
 .RS 4
 .\}
 .nf
+\fBvoid matchsolvable(Solvable\fR \fIsolvable\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+\fI$sel\fR\fB\->matchsolvable(\fR\fI$solvable\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIsel\fR\fB\&.matchsolvable(\fR\fIsolvable\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIsel\fR\fB\&.matchsolvable(\fR\fIsolvable\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Do a matchsolvable operation and combine the result with the current selection\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
 \fB<stringification>\fR
 my \fI$str\fR \fB=\fR \fI$sel\fR\fB\->str\fR;
 \fIstr\fR \fB= str(\fR\fIsel\fR\fB)\fR
index e458246..7b4f505 100644 (file)
@@ -59,7 +59,7 @@ natural constant subs), so don't forget the leading ``$'' when accessing a
 constant. Also do not forget to prepend the namespace of the constant:
 
        $pool->set_flag($solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1);
-       
+
 
 Python Specifics
 ----------------
@@ -185,7 +185,7 @@ to a libsolv class are prefixed with the class name:
 
        TCL $pool set_flag $solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS 1
        TCL puts [$solvable lookup_str $solv::SOLVABLE_SUMMARY]
-       
+
 
 The Solv Class
 --------------
@@ -248,7 +248,7 @@ Repositories, Dependencies, each indexed by Ids.
        pool = Solv::Pool.new()
 
 Create a new pool instance. In most cases you just need one pool.
-Note that the returned object "owns" the pool, i.e. if the object is 
+Note that the returned object "owns" the pool, i.e. if the object is
 freed, the pool is also freed. You can use the disown method to
 break this ownership relation.
 
@@ -488,6 +488,21 @@ the call to addfileprovides().
 Return all solvables that provide the specified dependency. You can use either
 a Dep object or a simple Id as argument.
 
+       Solvable *best_solvables(Solvable *solvables, int flags = 0)
+       my @solvables = $pool->best_solvables($solvables);
+       solvables = pool.best_solvables(solvables)
+       solvables = pool.best_solvables(solvables)
+
+Filter list of solvables by repo priority, architecture and version.
+
+       Solvable *whatmatchessolvable(Id keyname, Solvable solvable, Id marker = -1)
+       my @solvables = $pool->whatmatchessolvable($keyname, $solvable)
+       solvables = pool.whatmatchessolvable(keyname, solvable)
+       solvables = pool.whatmatchessolvable(keyname, solvable)
+
+Return all solvables that match package dependencies against solvable's
+provides.
+
        Id *matchprovidingids(const char *match, int flags)
        my @ids = $pool->matchprovidingids($match, $flags);
        ids = pool.matchprovidingids(match, flags)
@@ -554,7 +569,7 @@ selections.
        my $sel = $pool->Selection_all();
        sel = pool.Selection_all()
        sel = pool.Selection_all()
-       
+
 Create a selection containing all packages. Useful as starting point for
 intersecting other selections or for update/distupgrade jobs.
 
@@ -576,7 +591,7 @@ 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''.
 
        Selection matchdepid(DepId dep, int flags, Id keyname, Id marker = -1)
-       my $sel = $pool->matchdepid(dep, $flags, $keyname);
+       my $sel = $pool->matchdepid($dep, $flags, $keyname);
        sel = pool.matchdepid(dep, flags, keyname)
        sel = pool.matchdepid(dep, flags, keyname)
 
@@ -585,6 +600,14 @@ dependency. This may be faster than matchdeps and also works with complex
 dependencies. The downside is that you cannot use globs or case insensitive
 matching.
 
+       Selection matchsolvable(Solvable solvable, int flags, Id keyname, Id marker = -1)
+       my $sel = $pool->matchsolvable($solvable, $flags, $keyname);
+       sel = pool.matchsolvable(solvable, flags, keyname)
+       sel = pool.matchsolvable(solvable, flags, keyname)
+
+Create a selection by matching package dependencies against the specified
+solvable's provides.
+
        void setpooljobs(Jobs *jobs)
        $pool->setpooljobs(\@jobs);
        pool.setpooljobs(jobs)
@@ -860,7 +883,7 @@ The id of the repository.
        $repo->{name}
        repo.name
        repo.name
-       
+
 The repositories name. To libsolv, the name is just a string with no specific
 meaning.
 
@@ -1371,7 +1394,7 @@ a specific id and want to avoid the string compare overhead.
        my @deps = $solvable->lookup_deparray($keyname);
        deps = solvable.lookup_deparray(keyname)
        deps = solvable.lookup_deparray(keyname)
-       
+
 Generic lookup methods. Retrieve data stored for the specific keyname.
 The lookup_idarray() method will return an array of Ids, use
 lookup_deparray if you want an array of Dependency objects instead.
@@ -1719,7 +1742,7 @@ the version, and the architecture of a package.
 *SELECTION_DOTARCH*::
 Allow an ".<architecture>" suffix when matching names or
 provides.
+
 *SELECTION_REL*::
 Allow the specification of a relation when matching names
 or dependencies, e.g. "name >= 1.2".
@@ -1886,6 +1909,13 @@ Do a matchdeps operation and combine the result with the current selection.
 
 Do a matchdepid operation and combine the result with the current selection.
 
+       void matchsolvable(Solvable solvable, int flags, Id keyname, Id marker = -1)
+       $sel->matchsolvable($solvable, $flags, $keyname);
+       sel.matchsolvable(solvable, flags, keyname)
+       sel.matchsolvable(solvable, flags, keyname)
+
+Do a matchsolvable operation and combine the result with the current selection.
+
        <stringification>
        my $str = $sel->str;
        str = str(sel)
@@ -1945,7 +1975,7 @@ Update the matching installed packages to their best version. If none
 of the specified packages are installed, try to update the installed
 packages to the specified versions. See the section about targeted
 updates about more information.
+
 *SOLVER_WEAKENDEPS*::
 Allow to break the dependencies of the matching packages. Handle with care.
 
@@ -3164,7 +3194,7 @@ in passive mode, but
   update A-2-1 (other: A-1-1)
   erase  B
 
-in active mode. If the mode contains SOLVER_TRANSACTION_SHOW_ALL, the 
+in active mode. If the mode contains SOLVER_TRANSACTION_SHOW_ALL, the
 passive mode list will be unchanged but the active mode list will just
 contain A-2-1.
 
@@ -3290,7 +3320,7 @@ Add a (binary) string to the checksum.
        chksum.add_fp(file)
 
 Add the contents of a file to the checksum.
-       
+
        void add_stat(const char *filename)
        $chksum->add_stat($filename);
        chksum.add_stat(filename)
@@ -3422,7 +3452,7 @@ The Repodata Class
 The Repodata stores attributes for packages and the repository itself, each
 repository can have multiple repodata areas. You normally only need to
 directly access them if you implement lazy downloading of repository data.
-Repodata areas are created by calling the repository's add_repodata() method 
+Repodata areas are created by calling the repository's add_repodata() method
 or by using repo_add methods without the REPO_REUSE_REPODATA or REPO_USE_LOADING
 flag.
 
index ad8314f..128e179 100644 (file)
@@ -47,6 +47,9 @@ standard directory is */etc/products.d*.
 Do not read any packages from the rpm database. This is useful
 together with *-p* to only convert SUSE products.
 
+*-C*::
+Include the package changelog in the generated solv file.
+
 *-X*::
 Autoexpand SUSE pattern and product provides into packages.
 
index 326c5aa..fb1491b 100644 (file)
@@ -1390,6 +1390,7 @@ struct solvable_copy_cbdata {
   Id handle;
   Id subhandle;
   Id *dircache;
+  int bad;
 };
 
 static int
@@ -1410,6 +1411,11 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K
     case REPOKEY_TYPE_DIRNUMNUMARRAY:
     case REPOKEY_TYPE_DIRSTRARRAY:
       kv->id = repodata_translate_dir(data, fromdata, kv->id, 1, fromdata->repodataid == 1 ? cbdata->dircache : 0);
+      if (!kv->id)
+       {
+         cbdata->bad = 1;      /* oops, cannot copy this */
+         return 0;
+       }
       break;
     case REPOKEY_TYPE_FIXARRAY:
       cbdata->handle = repodata_new_handle(data);
@@ -1430,7 +1436,7 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K
   return 0;
 }
 
-static void
+static int
 solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache, Id **oldkeyskip)
 {
   int p, i;
@@ -1456,25 +1462,36 @@ solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache, Id **oldke
 
   /* copy all attributes */
   if (!data || fromrepo->nrepodata < 2)
-    return;
+    return 1;
   cbdata.data = data;
   cbdata.handle = s - pool->solvables;
   cbdata.subhandle = 0;
   cbdata.dircache = dircache;
+  cbdata.bad = 0;
   p = r - fromrepo->pool->solvables;
   if (fromrepo->nrepodata == 2)
     {
       Repodata *fromdata = repo_id2repodata(fromrepo, 1);
       if (p >= fromdata->start && p < fromdata->end)
         repodata_search(fromdata, p, 0, 0, solvable_copy_cb, &cbdata);
-      return;
     }
-  keyskip = repo_create_keyskip(repo, p, oldkeyskip);
-  FOR_REPODATAS(fromrepo, i, data)
+  else
+    {
+      keyskip = repo_create_keyskip(repo, p, oldkeyskip);
+      FOR_REPODATAS(fromrepo, i, data)
+       {
+         if (p >= data->start && p < data->end)
+           repodata_search_keyskip(data, p, 0, 0, keyskip, solvable_copy_cb, &cbdata);
+       }
+    }
+  if (cbdata.bad)
     {
-      if (p >= data->start && p < data->end)
-        repodata_search_keyskip(data, p, 0, 0, keyskip, solvable_copy_cb, &cbdata);
+      repodata_unset_uninternalized(data, cbdata.handle, 0);
+      memset(s, 0, sizeof(*s));
+      s->repo = repo;
+      return 0;
     }
+  return 1;
 }
 
 /* used to sort entries by package name that got returned in some database order */
@@ -1765,11 +1782,8 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
              if (id)
                {
                  Solvable *r = ref->pool->solvables + ref->start + (id - 1);
-                 if (r->repo == ref)
-                   {
-                     solvable_copy(s, r, data, dircache, &oldkeyskip);
-                     continue;
-                   }
+                 if (r->repo == ref && solvable_copy(s, r, data, dircache, &oldkeyskip))
+                   continue;
                }
            }
          res = getrpm_dbid(&state, dbid);
index ff84d32..f375727 100644 (file)
@@ -37,6 +37,7 @@
  *     <pkglist>
  *       <collection short="F8">
  *         <name>Fedora 8</name>
+ *         <module name="pki-deps" stream="10.6" version="20181019123559" context="9edba152" arch="x86_64"/>
  *         <package arch="ppc64" name="imlib-debuginfo" release="6.fc8" src="http://download.fedoraproject.org/pub/fedora/linux/updates/8/ppc64/imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm" version="1.9.15">
  *           <filename>imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm</filename>
  *           <reboot_suggested>True</reboot_suggested>
@@ -70,6 +71,7 @@ enum state {
   STATE_RELOGIN,
   STATE_RIGHTS,
   STATE_SEVERITY,
+  STATE_MODULE,
   NUMSTATES
 };
 
@@ -92,6 +94,7 @@ static struct solv_xmlparser_element stateswitches[] = {
   { STATE_PKGLIST,     "collection",      STATE_COLLECTION,  0 },
   { STATE_COLLECTION,  "name",            STATE_NAME,        1 },
   { STATE_COLLECTION,  "package",         STATE_PACKAGE,     0 },
+  { STATE_COLLECTION,  "module",          STATE_MODULE,      0 },
   { STATE_PACKAGE,     "filename",        STATE_FILENAME,    1 },
   { STATE_PACKAGE,     "reboot_suggested",STATE_REBOOT,      1 },
   { STATE_PACKAGE,     "restart_suggested",STATE_RESTART,    1 },
@@ -321,6 +324,38 @@ startElement(struct solv_xmlparser *xmlp, int state, const char *name, const cha
          repodata_set_id(pd->data, pd->collhandle, UPDATE_COLLECTION_ARCH, a);
         break;
       }
+    case STATE_MODULE:
+      {
+        const char *name = 0, *stream = 0, *version = 0, *context = 0, *arch = 0;
+        Id module_handle;
+
+        for (; *atts; atts += 2)
+          {
+            if (!strcmp(*atts, "arch"))
+              arch = atts[1];
+            else if (!strcmp(*atts, "name"))
+              name = atts[1];
+            else if (!strcmp(*atts, "stream"))
+              stream = atts[1];
+            else if (!strcmp(*atts, "version"))
+              version = atts[1];
+            else if (!strcmp(*atts, "context"))
+              context = atts[1];
+          }
+        module_handle = repodata_new_handle(pd->data);
+       if (name)
+          repodata_set_poolstr(pd->data, module_handle, UPDATE_MODULE_NAME, name);
+       if (stream)
+          repodata_set_poolstr(pd->data, module_handle, UPDATE_MODULE_STREAM, stream);
+       if (version)
+          repodata_set_poolstr(pd->data, module_handle, UPDATE_MODULE_VERSION, version);
+       if (context)
+          repodata_set_poolstr(pd->data, module_handle, UPDATE_MODULE_CONTEXT, context);
+        if (arch)
+          repodata_set_poolstr(pd->data, module_handle, UPDATE_MODULE_ARCH, arch);
+        repodata_add_flexarray(pd->data, pd->handle, UPDATE_MODULE, module_handle);
+        break;
+      }
 
     default:
       break;
index dad6503..8edf58f 100644 (file)
@@ -153,6 +153,7 @@ static struct disttype2str {
   { DISTTYPE_DEB,  "deb" },
   { DISTTYPE_ARCH, "arch" },
   { DISTTYPE_HAIKU, "haiku" },
+  { DISTTYPE_CONDA, "conda" },
   { 0, 0 }
 };
 
@@ -405,6 +406,7 @@ struct oplist {
   { REL_ELSE, "<ELSE>" },
   { REL_ERROR, "<ERROR>" },
   { REL_UNLESS, "<UNLESS>" },
+  { REL_CONDA, "<CONDA>" },
   { REL_LT, "<" },
   { 0, 0 }
 };
index f7edf4b..897cc04 100644 (file)
@@ -1,4 +1,12 @@
 -------------------------------------------------------------------
+Fri Mar 29 15:58:54 CET 2019 - mls@suse.de
+
+- repo_add_rpmdb: do not copy bad solvables from the old solv file
+- fix cleandeps updates not updating all packages
+- experimental DISTTYPE_CONDA and REL_CONDA support
+- bump version to 0.7.4
+
+-------------------------------------------------------------------
 Wed Jan 30 15:51:36 CET 2019 - mls@suse.de
 
 - fixed a couple of null pointer derefs
index 2e32968..be487a7 100644 (file)
@@ -29,6 +29,11 @@ SET (libsolv_HEADERS
     strpool.h dirpool.h knownid.h transaction.h rules.h problems.h
     chksum.h dataiterator.h ${CMAKE_BINARY_DIR}/src/solvversion.h)
 
+IF (ENABLE_CONDA)
+    SET (libsolv_SRCS ${libsolv_SRCS} conda.c)
+ENDIF (ENABLE_CONDA)
+
+
 SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
 IF (HAVE_LINKER_VERSION_SCRIPT)
 SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/src/libsolv.ver")
diff --git a/src/conda.c b/src/conda.c
new file mode 100644 (file)
index 0000000..5b134dd
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2019, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * conda.c
+ *
+ * evr comparison and package matching for conda
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "conda.h"
+
+static const char *
+endseg(const char *seg, const char *end)
+{
+  for (; seg < end; seg++)
+    if (*seg == '.' || *seg == '-' || *seg == '_')
+      break;
+  return seg;
+}
+
+static const char *
+endpart(const char *seg, const char *end)
+{
+  if (seg == end)
+    return seg;
+  if (*seg >= '0' && *seg <= '9')
+    {
+      for (seg++; seg < end; seg++)
+        if (!(*seg >= '0' && *seg <= '9'))
+         break;
+    }
+  else if (*seg == '*')
+    {
+      for (seg++; seg < end; seg++)
+       if (*seg != '*')
+         break;
+    }
+  else
+    {
+      for (seg++; seg < end; seg++)
+        if ((*seg >= '0' && *seg <= '9') || *seg == '*')
+         break;
+    }
+  return seg;
+}
+
+/* C implementation of the version comparison code in conda/models/version.py */
+/* startswith == 1 : check if s1 starts with s2 */
+static int
+solv_vercmp_conda(const char *s1, const char *q1, const char *s2, const char *q2, int startswith)
+{
+  const char *s1p, *s2p;
+  const char *s1e, *s2e;
+  int r, isfirst;
+  const char *q2end = 0;
+
+  if (startswith)
+    {
+      for (q2end = q2; q2end > s2; q2end--)
+       if (q2end[-1] != '.' && q2end[-1] != '-' && q2end[-1] != '_')
+         break;
+    }
+  for (;;)
+    {
+      while (s1 < q1 && (*s1 == '.' || *s1 == '-' || *s1 == '_'))
+       s1++;
+      while (s2 < q2 && (*s2 == '.' || *s2 == '-' || *s2 == '_'))
+       s2++;
+      if (s1 == q1 && s2 == q2)
+       return 0;
+      if (startswith && s2 == q2)
+       return 0;
+      /* find end of component */
+      s1e = endseg(s1, q1);
+      s2e = endseg(s2, q2);
+      
+      for (isfirst = 1; ; isfirst = 0)
+       {
+         if (s1 == s1e && s2 == s2e)
+           break;
+         if (s2 == q2end)
+           return 0;
+          s1p = endpart(s1, s1e);
+          s2p = endpart(s2, s2e);
+         /* prepend 0 if not numeric */
+         if (isfirst)
+           {
+             if (s1p != s1 && !(*s1 >= '0' && *s1 <= '9'))
+               s1p = s1;
+             if (s2p != s2 && !(*s2 >= '0' && *s2 <= '9'))
+               s2p = s2;
+           }
+         /* special case "post" */
+         if (s1p - s1 == 4 && !strncasecmp(s1, "post", 4))
+           {
+             if (s2p - s2 == 4 && !strncasecmp(s2, "post", 4))
+               {
+                 s1 = s1p;
+                 s2 = s2p;
+                 continue;
+               }
+             return 1;
+           }
+         if (s2p - s2 == 4 && !strncasecmp(s2, "post", 4))
+           return -1;
+
+         if (isfirst || ((s1 == s1p || (*s1 >= '0' && *s1 <= '9')) && (s2 == s2p || (*s2 >= '0' && *s2 <= '9'))))
+           {
+             /* compare numbers */
+             while (s1 < s1p && *s1 == '0')
+               s1++;
+             while (s2 < s2p && *s2 == '0')
+               s2++;
+             if (s1p - s1 < s2p - s2)
+               return -1;
+             if (s1p - s1 > s2p - s2)
+               return 1;
+             r = s1p - s1 ? strncmp(s1, s2, s1p - s1) : 0;
+             if (r)
+               return r;
+           }
+         else if (s1 == s1p || (*s1 >= '0' && *s1 <= '9'))
+           return 1;
+         else if (s2 == s2p || (*s2 >= '0' && *s2 <= '9'))
+           return -1;
+         else
+           {
+             /* special case "dev" */
+             if (*s2 != '*' && s1p - s1 == 3 && !strncasecmp(s1, "dev", 3))
+               {
+                 if (s2p - s2 == 3 && !strncasecmp(s2, "dev", 3))
+                   {
+                     s1 = s1p;
+                     s2 = s2p;
+                     continue;
+                   }
+                 return -1;
+               }
+             if (*s1 != '*' && s2p - s2 == 3 && !strncasecmp(s2, "dev", 3))
+               return 1;
+             /* compare strings */
+             r = s2p - s2 > s1p - s1 ? s1p - s1 : s2p - s2;
+             if (r)
+               r = strncasecmp(s1, s2, r);
+             if (r)
+               return r;
+              if (s1p - s1 < s2p - s2) 
+                return -1; 
+              if (s1p - s1 > s2p - s2) 
+                return 1;
+           }
+         s1 = s1p;
+         s2 = s2p;
+       }
+    }
+}
+
+static int
+pool_evrcmp_conda_int(const char *evr1, const char *evr1e, const char *evr2, const char *evr2e, int startswith)
+{
+  static char zero[2] = {'0', 0};
+  const char *s1, *s2;
+  const char *r1, *r2;
+  int r;
+
+  /* split and compare epoch */
+  for (s1 = evr1; s1 < evr1e && *s1 >= '0' && *s1 <= '9'; s1++)
+    ;
+  for (s2 = evr2; s2 < evr2e && *s2 >= '0' && *s2 <= '9'; s2++)
+    ;
+  if (s1 == evr1 || s1 == evr1e || *s1 != '!')
+    s1 = 0;
+  if (s2 == evr1 || s2 == evr2e || *s2 != '!')
+    s2 = 0;
+  if (s1 || s2)
+    {
+      r = solv_vercmp_conda(s1 ? evr1 : zero, s1 ? s1 : zero + 1, 
+                            s2 ? evr2 : zero, s2 ? s2 : zero + 1, 0);
+      if (r)
+       return r;
+      if (s1)
+        evr1 = s1 + 1;
+      if (s2)
+        evr2 = s2 + 1;
+    }
+  /* split into version/localversion */
+  for (s1 = evr1, r1 = 0; s1 < evr1e; s1++)
+    if (*s1 == '+')
+      r1 = s1;
+  for (s2 = evr2, r2 = 0; s2 < evr2e; s2++)
+    if (*s2 == '+')
+      r2 = s2;
+  r = solv_vercmp_conda(evr1, r1 ? r1 : s1, evr2, r2 ? r2 : s2, r2 ? 0 : startswith);
+  if (r)
+    return r;
+  if (!r1 && !r2)
+    return 0;
+  if (!r1 && r2)
+    return -1;
+  if (r1 && !r2)
+    return 1;
+  return solv_vercmp_conda(r1 + 1, s1, r2 + 1, s2, startswith);
+}
+
+int
+pool_evrcmp_conda(const Pool *pool, const char *evr1, const char *evr2, int mode)
+{
+  if (evr1 == evr2)
+    return 0;
+  return pool_evrcmp_conda_int(evr1, evr1 + strlen(evr1), evr2, evr2 + strlen(evr2), 0);
+}
+
+static int
+regexmatch(const char *evr, const char *version, size_t versionlen)
+{
+  regex_t reg;
+  char *buf = solv_malloc(versionlen + 1);
+  int r;
+
+  memcpy(buf, version, versionlen);
+  buf[versionlen] = 0;
+  if (regcomp(&reg, buf, REG_EXTENDED | REG_NOSUB))
+    return 0;
+  r = regexec(&reg, evr, 0, NULL, 0);
+  regfree(&reg);
+  return r == 0;
+}
+
+static int
+globmatch(const char *evr, const char *version, size_t versionlen)
+{
+  regex_t reg;
+  char *buf = solv_malloc(2 * versionlen + 3);
+  size_t i, j;
+  int r;
+
+  buf[0] = '^';
+  j = 1;
+  for (i = 0, j = 1; i < versionlen; i++)
+    {
+      if (version[i] == '.' || version[i] == '+' || version[i] == '*')
+       buf[j++] = version[i] == '*' ? '.' : '\\';
+      buf[j++] = version[i];
+    }
+  buf[j++] = '$';
+  buf[j] = 0;
+  if (regcomp(&reg, buf, REG_EXTENDED | REG_NOSUB))
+    return 0;
+  r = regexec(&reg, evr, 0, NULL, 0);
+  regfree(&reg);
+  return r == 0;
+}
+
+/* return true if solvable s matches the version */
+/* see conda/models/version.py */
+static int
+solvable_conda_matchversion_single(Solvable *s, const char *version, size_t versionlen)
+{
+  const char *evr;
+  size_t i;
+  int r;
+
+  if (versionlen == 0 || (versionlen == 1 && *version == '*'))
+    return 1;  /* matches every version */
+  evr = pool_id2str(s->repo->pool, s->evr);
+  if (versionlen >= 2 && version[0] == '^' && version[versionlen - 1] == '$')
+    return regexmatch(evr, version, versionlen);
+  if (version[0] == '=' || version[0] == '<' || version[0] == '>' || version[0] == '!' || version[0] == '~')
+    {
+      int flags = 0;
+      int oplen;
+      if (version[0] == '=')
+         flags = version[1] == '=' ? REL_EQ : 8;
+      else if (version[0] == '!' || version[0] == '~')
+       {
+         if (version[1] != '=')
+           return 0;
+         flags = version[0] == '!' ? REL_LT | REL_GT : 9;
+       }
+      else if (version[0] == '<' || version[0] == '>')
+       {
+         flags = version[0] == '<' ? REL_LT : REL_GT;
+         if (version[1] == '=')
+           flags |= REL_EQ;
+       }
+      else
+       return 0;
+      oplen = flags == 8 || flags == REL_LT || flags == REL_GT ? 1 : 2;
+      if (versionlen < oplen + 1)
+       return 0;
+      version += oplen;
+      versionlen -= oplen;
+      if (version[0] == '=' || version[0] == '<' || version[0] == '>' || version[0] == '!' || version[0] == '~')
+       return 0;               /* bad chars after op */
+      if (versionlen >= 2 && version[versionlen - 2] == '.' && version[versionlen - 1] == '*')
+       {
+         if (flags == 8 || flags == (REL_GT | REL_EQ))
+           versionlen -= 2;
+         else if (flags == (REL_LT | REL_GT))
+           {
+             versionlen -= 2;
+             flags = 10;
+           }
+         else
+           return 0;
+       }
+      if (flags < 8)
+       {
+         /* we now have an op and a version */
+         r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 0);
+         if (r < 0)
+           return (flags & REL_LT) ? 1 : 0;
+         if (r == 0)
+           return (flags & REL_EQ) ? 1 : 0;
+         if (r > 0)
+           return (flags & REL_GT) ? 1 : 0;
+         return 0;
+       }
+      if (flags == 8 || flags == 10)   /* startswith, not-startswith */
+       {
+         r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 1);
+         return flags == 8 ? r == 0 : r != 0;
+       }
+      else if (flags == 9)             /* compatible release op */
+       {
+         r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 0);
+         if (r < 0)
+           return 0;
+         /* split off last component */
+         while (versionlen > 0 && version[versionlen - 1] != '.')
+           versionlen--;
+         if (versionlen < 2)
+           return 0;
+         versionlen--;
+         r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 1);
+         return r == 0 ? 1 : 0;
+       }
+      return 0;
+    }
+   
+  /* do we have a '*' in the version */
+  for (i = 0; i < versionlen; i++)
+    if (version[i] == '*')
+      {
+        for (i++; i < versionlen; i++)
+          if (version[i] != '*')
+           break;
+       if (i < versionlen)
+         return globmatch(evr, version, versionlen);
+      }
+
+  if (versionlen > 1 && version[versionlen - 1] == '*')
+    {
+      /* startswith */
+      while (versionlen > 0 && version[versionlen - 1] == '*')
+       versionlen--;
+      while (versionlen > 0 && version[versionlen - 1] == '.')
+       versionlen--;
+      r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 1);
+      return r == 0 ? 1 : 0;
+    }
+  /* do we have a '@' in the version? */
+  for (i = 0; i < versionlen; i++)
+    if (version[i] == '@')
+      return strncmp(evr, version, versionlen) == 0 && evr[versionlen] == 0;
+  r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 0);
+  return r == 0 ? 1 : 0;
+}
+
+static int
+solvable_conda_matchversion_rec(Solvable *s, const char **versionp, const char *versionend)
+{
+  const char *version = *versionp;
+  int v, vor = 0, vand = -1;   /* -1: doing OR, 0,1: doing AND */
+
+  if (version == versionend)
+    return -1;
+  for (;;)
+    {
+      if (*version == '(')
+       {
+         version++;
+         v = solvable_conda_matchversion_rec(s, &version, versionend);
+         if (v == -1 || version == versionend || *version != ')')
+           return -1;
+         version++;
+       }
+      else if (*version == ')' || *version == '|' || *version == ',')
+       return -1;
+      else
+       {
+         const char *vstart = version;
+         while (version < versionend && *version != '(' && *version != ')' && *version != '|' && *version != ',')
+           version++;
+         if (vand >= 0 ? !vand : vor)
+           v = 0;              /* no need to call expensive matchversion if the result does not matter */
+         else
+           v = solvable_conda_matchversion_single(s, vstart, version - vstart) ? 1 : 0;
+       }
+      if (version == versionend || *version == ')')
+       {
+         *versionp = version;
+         return vor | (vand >= 0 ? (vand & v) : v);
+       }
+      if (*version == ',')
+       vand = vand >= 0 ? (vand & v) : v;
+      else if (*version == '|')
+       {
+         vor |= vand >= 0 ? (vand & v) : v;
+         vand = -1;
+       }
+      else
+       return -1;
+      version++;
+    }
+}
+
+/* return true if solvable s matches the version */
+/* see conda/models/match_spec.py */
+int
+solvable_conda_matchversion(Solvable *s, const char *version)
+{
+  const char *build, *versionend;
+  int r;
+  /* split off build */
+  if ((build = strchr(version, ' ')) != 0)
+    {
+      versionend = build++;
+      while (*build == ' ')
+       build++;
+    }
+  else
+    versionend = version + strlen(version);
+  r = solvable_conda_matchversion_rec(s, &version, versionend);
+  if (r != 1 || version != versionend)
+    return 0;
+  return r;
+}
+
diff --git a/src/conda.h b/src/conda.h
new file mode 100644 (file)
index 0000000..7233f17
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * conda.h
+ *
+ */
+
+#ifndef LIBSOLV_CONDA_H
+#define LIBSOLV_CONDA_H
+
+int pool_evrcmp_conda(const Pool *pool, const char *evr1, const char *evr2, int mode);
+int solvable_conda_matchversion(Solvable *s, const char *version);
+
+#endif /* LIBSOLV_CONDA_H */
+
index c63878e..afd5fc5 100644 (file)
--- a/src/evr.c
+++ b/src/evr.c
@@ -17,6 +17,9 @@
 #include "evr.h"
 #include "pool.h"
 
+#ifdef ENABLE_CONDA
+#include "conda.h"
+#endif
 
 
 #if defined(DEBIAN) || defined(MULTI_SEMANTICS)
@@ -322,7 +325,7 @@ solv_vercmp(const char *s1, const char *q1, const char *s2, const char *q2)
 
 #if defined(MULTI_SEMANTICS)
 # define solv_vercmp (*(pool->disttype == DISTTYPE_DEB ? &solv_vercmp_deb : \
-                        pool->disttype == DISTTYPE_HAIKU ? solv_vercmp_haiku : \
+                        pool->disttype == DISTTYPE_HAIKU ? &solv_vercmp_haiku : \
                         &solv_ver##cmp_rpm))
 #elif defined(DEBIAN)
 # define solv_vercmp solv_vercmp_deb
@@ -345,6 +348,11 @@ pool_evrcmp_str(const Pool *pool, const char *evr1, const char *evr2, int mode)
   if (evr1 == evr2)
     return 0;
 
+#ifdef ENABLE_CONDA
+  if (pool->disttype == DISTTYPE_CONDA)
+    return pool_evrcmp_conda(pool, evr1, evr2, mode);
+#endif
+
 #if 0
   POOL_DEBUG(DEBUG_EVRCMP, "evrcmp %s %s mode=%d\n", evr1, evr2, mode);
 #endif
index 8e53183..b5b41d6 100644 (file)
@@ -250,6 +250,14 @@ KNOWNID(SIGNATURE_TIME,                    "signature:time"),
 KNOWNID(SIGNATURE_EXPIRES,             "signature:expires"),
 KNOWNID(SIGNATURE_DATA,                        "signature:data"),
 
+/* 'content' of patch, usually list of modules */
+KNOWNID(UPDATE_MODULE,                  "update:module"),              /*  "name stream version context arch" */
+KNOWNID(UPDATE_MODULE_NAME,             "update:module:name"),         /*   name */
+KNOWNID(UPDATE_MODULE_STREAM,           "update:module:stream"),       /*   stream */
+KNOWNID(UPDATE_MODULE_VERSION,          "update:module:version"),      /*   version */
+KNOWNID(UPDATE_MODULE_CONTEXT,          "update:module:context"),      /*   context */
+KNOWNID(UPDATE_MODULE_ARCH,             "update:module:arch"),         /*   architecture */
+
 KNOWNID(ID_NUM_INTERNAL,               0)
 
 #ifdef KNOWNID_INITIALIZE
index 45c7357..5f61115 100644 (file)
@@ -856,9 +856,9 @@ prune_to_best_version(Pool *pool, Queue *plist)
     {
       s = pool->solvables + plist->elements[i];
 
-      POOL_DEBUG(SOLV_DEBUG_POLICY, "- %s[%s]\n",
-                pool_solvable2str(pool, s),
-                (pool->installed && s->repo == pool->installed) ? "installed" : "not installed");
+      POOL_DEBUG(SOLV_DEBUG_POLICY, "- %s [%d]%s\n",
+                pool_solvable2str(pool, s), plist->elements[i], 
+                (pool->installed && s->repo == pool->installed) ? "I" : "");
 
       if (!best)               /* if no best yet, the current is best */
         {
index be6a419..09354ef 100644 (file)
@@ -27,6 +27,9 @@
 #include "util.h"
 #include "bitmap.h"
 #include "evr.h"
+#ifdef ENABLE_CONDA
+#include "conda.h"
+#endif
 
 #define SOLVABLE_BLOCK 255
 
@@ -158,6 +161,9 @@ pool_setdisttype(Pool *pool, int disttype)
     case DISTTYPE_HAIKU:
       pool->noarchid = ARCH_ANY;
       break;
+    case DISTTYPE_CONDA:
+      pool->noarchid = ARCH_ANY;
+      break;
     default:
       return -1;
     }
@@ -1281,6 +1287,23 @@ pool_addrelproviders(Pool *pool, Id d)
                queue_push(&plist, p);
            }
          break;
+#ifdef ENABLE_CONDA
+       case REL_CONDA:
+         wp = pool_whatprovides(pool, name);
+         if (evr)
+           {
+             const char *evrstr = pool_id2str(pool, evr);
+             pp = pool->whatprovidesdata + wp;
+             while ((p = *pp++) != 0)
+               {
+                 if (solvable_conda_matchversion(pool->solvables + p, evrstr))
+                   queue_push(&plist, p);
+                 else
+                   wp = 0;
+               }
+           }
+         break;
+#endif
        default:
          break;
        }
@@ -1598,7 +1621,7 @@ pool_setdebuglevel(Pool *pool, int level)
   if (level > 2)
     mask |= SOLV_DEBUG_PROPAGATE;
   if (level > 3)
-    mask |= SOLV_DEBUG_RULE_CREATION;
+    mask |= SOLV_DEBUG_RULE_CREATION | SOLV_DEBUG_WATCHES;
   mask |= pool->debugmask & SOLV_DEBUG_TO_STDERR;      /* keep bit */
   pool->debugmask = mask;
 }
index 37583a1..c90c29a 100644 (file)
@@ -173,6 +173,7 @@ struct s_Pool {
 #define DISTTYPE_DEB   1
 #define DISTTYPE_ARCH   2
 #define DISTTYPE_HAIKU  3
+#define DISTTYPE_CONDA  4
 
 #define SOLV_FATAL                     (1<<0)
 #define SOLV_ERROR                     (1<<1)
@@ -188,6 +189,7 @@ struct s_Pool {
 #define SOLV_DEBUG_JOB                 (1<<11)
 #define SOLV_DEBUG_SOLVER              (1<<12)
 #define SOLV_DEBUG_TRANSACTION         (1<<13)
+#define SOLV_DEBUG_WATCHES             (1<<14)
 
 #define SOLV_DEBUG_TO_STDERR           (1<<30)
 
@@ -231,6 +233,7 @@ struct s_Pool {
 #define REL_ERROR      27      /* parse errors and the like */
 #define REL_WITHOUT    28
 #define REL_UNLESS     29      /* AND_NOT */
+#define REL_CONDA      30
 
 #if !defined(__GNUC__) && !defined(__attribute__)
 # define __attribute__(x)
index 3b55f76..52d98c3 100644 (file)
@@ -168,6 +168,7 @@ pool_id2rel(const Pool *pool, Id id)
   if (!ISRELDEP(id))
     return "";
   rd = GETRELDEP(pool, id);
+
   switch (rd->flags)
     {
     /* debian special cases < and > */
@@ -217,6 +218,8 @@ pool_id2rel(const Pool *pool, Id id)
       return " KIND ";
     case REL_ELSE:
       return pool->disttype == DISTTYPE_RPM ? " else " : " ELSE ";
+    case REL_CONDA:
+      return " ";
     case REL_ERROR:
       return " ERROR ";
     default:
index 71e8175..ad5aaea 100644 (file)
@@ -2959,6 +2959,11 @@ repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
   ap = *app;
   if (!ap)
     return;
+  if (!keyname)
+    {
+      *app = 0;                /* delete all attributes */
+      return;
+    }
   for (; *ap; ap += 2)
     if (data->keys[*ap].name == keyname)
       break;
index 3ca9404..619cbf4 100644 (file)
@@ -36,7 +36,7 @@
 #include <string.h>     /* memcpy()/memset() or bcopy()/bzero() */
 /* #include <assert.h> */   /* assert() */
 #include <stdio.h>
-#include <sys/uio.h>
+/* #include <sys/uio.h> */
 #include <unistd.h>
 #include <inttypes.h>
 
index a80090d..b335e6a 100644 (file)
@@ -431,7 +431,7 @@ propagate(Solver *solv, int level)
   Id *decisionmap = solv->decisionmap;
   Id *watches = solv->watches + pool->nsolvables;   /* place ptr in middle */
 
-  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n");
+  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate level %d -----\n", level);
 
   /* foreach non-propagated decision */
   while (solv->propagate_index < solv->decisionq.count)
@@ -444,7 +444,7 @@ propagate(Solver *solv, int level)
        
       IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
         {
-         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
+         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate decision %d:", -pkg);
          solver_printruleelement(solv, SOLV_DEBUG_PROPAGATE, 0, -pkg);
         }
 
@@ -462,10 +462,10 @@ propagate(Solver *solv, int level)
              continue;
            }
 
-         IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+         IF_POOLDEBUG (SOLV_DEBUG_WATCHES)
            {
-             POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"  watch triggered ");
-             solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
+             POOL_DEBUG(SOLV_DEBUG_WATCHES, "  watch triggered ");
+             solver_printrule(solv, SOLV_DEBUG_WATCHES, r);
            }
 
          /*
@@ -532,12 +532,12 @@ propagate(Solver *solv, int level)
                   * if we found some p that is UNDEF or TRUE, move
                   * watch to it
                   */
-                 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+                 IF_POOLDEBUG (SOLV_DEBUG_WATCHES)
                    {
                      if (p > 0)
-                       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
+                       POOL_DEBUG(SOLV_DEBUG_WATCHES, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
                      else
-                       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
+                       POOL_DEBUG(SOLV_DEBUG_WATCHES, "    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
                    }
 
                  *rp = *next_rp;
@@ -593,7 +593,7 @@ propagate(Solver *solv, int level)
        
     } /* while we have non-decided decisions */
 
-  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end-----\n");
+  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end -----\n");
 
   return 0;    /* all is well */
 }
@@ -1824,6 +1824,69 @@ resolve_installed(Solver *solv, int level, int disablerules, Queue *dq)
   return level;
 }
 
+/* one or more installed cleandeps packages in dq that are to be updated */
+/* we need to emulate the code in resolve_installed */
+static void
+do_cleandeps_update_filter(Solver *solv, Queue *dq)
+{
+  Pool *pool = solv->pool;
+  Repo *installed = solv->installed;
+  Id *specialupdaters = solv->specialupdaters;
+  Id p, p2, pp, d;
+  Queue q;
+  int i, j, k;
+
+  queue_init(&q);
+  for (i = 0; i < dq->count; i++)
+    {
+      Id p = dq->elements[i];
+      if (p < 0)
+       p = -p;
+      if (pool->solvables[p].repo != installed || !MAPTST(&solv->cleandepsmap, p - installed->start))
+       continue;
+      queue_empty(&q);
+      /* find updaters */
+      if (specialupdaters && (d = specialupdaters[p - installed->start]) != 0)
+       {
+         while ((p2 = pool->whatprovidesdata[d++]) != 0)
+           if (solv->decisionmap[p2] >= 0)
+             queue_push(&q, p2);
+       }
+      else
+       {
+         Rule *r = solv->rules + solv->updaterules + (p - installed->start);
+         if (r->p)
+           {
+             FOR_RULELITERALS(p2, pp, r)
+               if (solv->decisionmap[p2] >= 0)
+                 queue_push(&q, p2);
+           }
+       }
+      if (q.count && solv->update_targets && solv->update_targets->elements[p - installed->start])
+        prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q);
+      /* mark all elements in dq that are in the updaters list */
+      dq->elements[i] = -p;
+      for (j = 0; j < dq->count; j++)
+       {
+          p = dq->elements[j];
+         if (p < 0)
+           continue;
+         for (k = 0; k < q.count; k++)
+           if (q.elements[k] == p)
+             {
+               dq->elements[j] = -p;
+               break;
+             }
+       }
+    }
+  /* now prune to marked elements */
+  for (i = j = 0; i < dq->count; i++)
+    if ((p = dq->elements[i]) < 0)
+      dq->elements[j++] = -p;
+  dq->count = j;
+  queue_free(&q);
+}
+
 static int
 resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
 {
@@ -1919,15 +1982,25 @@ resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
       /* prune to cleandeps packages */
       if (solv->cleandepsmap.size && solv->installed)
        {
+         int cleandeps_update = 0;
          Repo *installed = solv->installed;
          for (j = 0; j < dq->count; j++)
            if (pool->solvables[dq->elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq->elements[j] - installed->start))
-             break;
+             {
+               if (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - installed->start)))
+                 {
+                   cleandeps_update = 1;               /* cleandeps package is marked for update */
+                   continue;
+                 }
+               break;
+             }
          if (j < dq->count)
            {
              dq->elements[0] = dq->elements[j];
              queue_truncate(dq, 1);
            }
+         else if (cleandeps_update)
+           do_cleandeps_update_filter(solv, dq);       /* special update filter */
        }
 
       if (dq->count > 1 && postponed >= 0)
@@ -3920,7 +3993,7 @@ solver_solve(Solver *solv, Queue *job)
   else
     solv->yumobsrules = solv->yumobsrules_end = solv->nrules;
 
-  if (solv->havedisfavored && solv->strongrecommends)
+  if (solv->havedisfavored && solv->strongrecommends && solv->recommendsruleq)
     solver_addrecommendsrules(solv);
   else
     solv->recommendsrules = solv->recommendsrules_end = solv->nrules;
index 4caba47..11e4aa3 100644 (file)
@@ -27,6 +27,7 @@ extern int solv_version_patch;
 #cmakedefine LIBSOLV_FEATURE_LINKED_PKGS
 #cmakedefine LIBSOLV_FEATURE_COMPLEX_DEPS
 #cmakedefine LIBSOLV_FEATURE_MULTI_SEMANTICS
+#cmakedefine LIBSOLV_FEATURE_CONDA
 
 #cmakedefine LIBSOLVEXT_FEATURE_RPMPKG
 #cmakedefine LIBSOLVEXT_FEATURE_RPMDB
diff --git a/test/testcases/cleandeps/cleandeps_up3.t b/test/testcases/cleandeps/cleandeps_up3.t
new file mode 100644 (file)
index 0000000..7a4bfbc
--- /dev/null
@@ -0,0 +1,23 @@
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 x86_64
+#>=Req: b
+#>=Pkg: b 1 1 x86_64
+repo available 0 testtags <inline>
+#>=Pkg: a 2 1 x86_64
+#>=Req: b
+#>=Pkg: b 2 1 x86_64
+#>=Pkg: c 2 1 x86_64
+#>=Prv: b = 4
+repo available2 0 testtags <inline>
+#>=Pkg: b 3 1 x86_64
+system x86_64 rpm system
+
+job update all packages [cleandeps]
+result transaction,problems <inline>
+#>upgrade a-1-1.x86_64@system a-2-1.x86_64@available
+#>upgrade b-1-1.x86_64@system b-3-1.x86_64@available2
+nextjob
+job update repo available [cleandeps]
+result transaction,problems <inline>
+#>upgrade a-1-1.x86_64@system a-2-1.x86_64@available
+#>upgrade b-1-1.x86_64@system b-2-1.x86_64@available
index 58ef567..1a04adf 100644 (file)
@@ -41,11 +41,13 @@ static void
 usage(int status)
 {
   fprintf(stderr, "\nUsage:\n"
-         "rpmdb2solv [-n] [-b <basefile>] [-p <productsdir>] [-r <root>]\n"
+         "rpmdb2solv [-P] [-C] [-n] [-b <basefile>] [-p <productsdir>] [-r <root>]\n"
          " -n : No packages, do not read rpmdb, useful to only parse products\n"
          " -p <productsdir> : Scan <productsdir> for .prod files, representing installed products\n"
          " -r <root> : Prefix rpmdb path and <productsdir> with <root>\n"
          " -o <solv> : Write .solv to file instead of stdout\n"
+          " -P : print percentage done\n"
+          " -C : include the changelog\n"
         );
   exit(status);
 }