Imported Upstream version 0.7.0 upstream/0.7.0
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 10 Sep 2019 06:38:34 +0000 (15:38 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 10 Sep 2019 06:38:34 +0000 (15:38 +0900)
108 files changed:
BUGS [deleted file]
CMakeLists.txt
NEWS
TODO_1.0
VERSION.cmake
bindings/solv.i
doc/gen/helix2solv.1
doc/gen/installcheck.1
doc/gen/libsolv-bindings.3
doc/gen/libsolv-constantids.3
doc/gen/libsolv-history.3
doc/gen/libsolv-pool.3
doc/gen/libsolv.3
doc/gen/mdk2solv.1
doc/gen/mergesolv.1
doc/gen/repo2solv.1
doc/gen/repomdxml2solv.1
doc/gen/rpmdb2solv.1
doc/gen/rpmmd2solv.1
doc/gen/rpms2solv.1
doc/gen/solv.1
doc/gen/susetags2solv.1
doc/gen/testsolv.1
doc/gen/updateinfoxml2solv.1
doc/libsolv-bindings.txt
doc/rpmdb2solv.txt
examples/p5solv
examples/pysolv
examples/solv/fastestmirror.c
examples/solv/solv.c
ext/repo_appdata.c
ext/repo_autopattern.c
ext/repo_pubkey.h
ext/repo_repomdxml.c
ext/repo_rpmdb.c
ext/repo_rpmmd.c
ext/repo_susetags.c
ext/solv_xfopen.c
ext/testcase.c
package/libsolv.changes
package/libsolv.spec.in
src/CMakeLists.txt
src/bitmap.h
src/chksum.c
src/chksum.h
src/cleandeps.c
src/dataiterator.h
src/dirpool.h
src/diskusage.c
src/filelistfilter.c [new file with mode: 0644]
src/fileprovides.c
src/knownid.h
src/libsolv.ver
src/order.c
src/policy.c
src/pool.c
src/pool.h
src/poolarch.c
src/poolid.h
src/pooltypes.h
src/problems.c
src/problems.h
src/queue.h
src/repo.c
src/repo.h
src/repo_solv.c
src/repo_write.c
src/repo_write.h
src/repodata.c
src/repodata.h
src/repopack.h
src/repopage.h
src/rules.c
src/rules.h
src/selection.c
src/selection.h
src/sha2.h
src/solvable.c
src/solvable.h
src/solver.c
src/solver.h
src/strpool.h
src/transaction.c
src/transaction.h
test/testcases/allowuninstall/conflict.t [deleted file]
test/testcases/allowuninstall/forcebest.t [deleted file]
test/testcases/cleandeps/cleandeps_up3.t [deleted file]
test/testcases/selection/selection_matchsolvable.t [new file with mode: 0644]
tools/appdata2solv.c
tools/archpkgs2solv.c
tools/archrepo2solv.c
tools/common_write.c
tools/common_write.h
tools/comps2solv.c
tools/deb2solv.c
tools/deltainfoxml2solv.c
tools/diskusagexml2solv.c
tools/dumpsolv.c
tools/helix2solv.c
tools/mdk2solv.c
tools/mergesolv.c
tools/repo2solv.c
tools/repomdxml2solv.c
tools/rpmdb2solv.c
tools/rpmmd2solv.c
tools/rpms2solv.c
tools/susetags2solv.c
tools/updateinfoxml2solv.c

diff --git a/BUGS b/BUGS
deleted file mode 100644 (file)
index 0e33eb5..0000000
--- a/BUGS
+++ /dev/null
@@ -1,7 +0,0 @@
-
-Having the same key in multiple repodatas of a repo does not work
-- searching will return both entries
-- repo_write will write a broken solv file
-Fixing the search so that it only returns the last entry will also
-fix repo_write.
-
index 8c6a1be..1deef57 100644 (file)
@@ -35,7 +35,7 @@ OPTION (ENABLE_LZMA_COMPRESSION "Build with lzma/xz compression support?" OFF)
 OPTION (ENABLE_BZIP2_COMPRESSION "Build with bzip2 compression support?" OFF)
 OPTION (ENABLE_ZSTD_COMPRESSION "Build with zstd compression support?" OFF)
 OPTION (ENABLE_ZCHUNK_COMPRESSION "Build with zchunk compression support?" OFF)
-
+OPTION (WITH_SYSTEM_ZCHUNK "Use system zchunk library?" OFF)
 OPTION (WITH_LIBXML2  "Build with libxml2 instead of libexpat?" OFF)
 
 # Library
@@ -156,6 +156,12 @@ IF (ENABLE_ARCHREPO OR ENABLE_DEBIAN)
 SET (ENABLE_LZMA_COMPRESSION ON)
 ENDIF (ENABLE_ARCHREPO OR ENABLE_DEBIAN)
 
+IF (WITH_SYSTEM_ZCHUNK)
+SET (ENABLE_ZCHUNK_COMPRESSION ON)
+FIND_PACKAGE(PkgConfig REQUIRED)
+PKG_CHECK_MODULES(ZCHUNK zck REQUIRED)
+ENDIF (WITH_SYSTEM_ZCHUNK)
+
 IF (ENABLE_ZCHUNK_COMPRESSION)
 SET (ENABLE_ZSTD_COMPRESSION ON)
 ENDIF (ENABLE_ZCHUNK_COMPRESSION)
@@ -294,7 +300,8 @@ FOREACH (VAR
   ENABLE_SUSEREPO ENABLE_COMPS ENABLE_TESTCASE_HELIXREPO
   ENABLE_HELIXREPO ENABLE_MDKREPO ENABLE_ARCHREPO ENABLE_DEBIAN ENABLE_HAIKU
   ENABLE_ZLIB_COMPRESSION ENABLE_LZMA_COMPRESSION ENABLE_BZIP2_COMPRESSION
-  ENABLE_ZSTD_COMPRESSION ENABLE_ZCHUNK_COMPRESSION ENABLE_PGPVRFY ENABLE_APPDATA)
+  ENABLE_ZSTD_COMPRESSION ENABLE_ZCHUNK_COMPRESSION ENABLE_PGPVRFY ENABLE_APPDATA
+  WITH_SYSTEM_ZCHUNK)
   IF(${VAR})
     ADD_DEFINITIONS (-D${VAR}=1)
     SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR})
@@ -399,6 +406,9 @@ ENDIF (ENABLE_BZIP2_COMPRESSION)
 IF (ENABLE_ZSTD_COMPRESSION)
 SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${ZSTD_LIBRARY})
 ENDIF (ENABLE_ZSTD_COMPRESSION)
+IF (WITH_SYSTEM_ZCHUNK)
+SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${ZCHUNK_LIBRARIES})
+ENDIF (WITH_SYSTEM_ZCHUNK)
 IF (ENABLE_RPMDB)
 SET (SYSTEM_LIBRARIES ${RPMDB_LIBRARY} ${SYSTEM_LIBRARIES})
 ENDIF (ENABLE_RPMDB)
diff --git a/NEWS b/NEWS
index 5b1a2af..16b79a8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,17 +2,23 @@
 This file contains the major changes between
 libsolv versions:
 
-Version 0.6.36
-- bug fixes:
-  * do not autouninstall packages because of forcebest updates
-  * fixed a couple of null pointer derefs and potential memory
-    leaks
-  * no longer disable infarch rules when they don't conflict with
-    the job
-  * fix cleandeps updates not updating all packages
-  * fix SOLVER_FLAG_FOCUS_BEST updateing packages without reason
-  * be more correct with multiversion packages that obsolete their
-    own name
+Version 0.7.0
+- soname bump to "1"
+- incompatible API changes:
+  * bindings: Selection.flags is now an attribute
+  * repodata_lookup_num now works like the other lookup_num functions
+- new functions:
+  * selection_make_matchsolvable
+  * selection_make_matchsolvablelist
+  * pool_whatmatchessolvable
+  * repodata_search_arrayelement
+  * repodata_lookup_kv_uninternalized
+  * repodata_search_uninternalized
+  * repodata_translate_dir
+- new repowriter interface to write solv files allowing better
+  control over what gets written
+- support for filtered file lists with a custom filter
+- dropped support of (since a long time unused) REPOKEY_TYPE_U32
 
 Version 0.6.35
 - new configuration options:
index 13000fc..d77df67 100644 (file)
--- a/TODO_1.0
+++ b/TODO_1.0
@@ -1,6 +1,4 @@
 
-- make dataiterator only return the last occurance of a key
-
 - implement package priority (for things like Debian's pin feature)
 
 - merge SUSETAGS_FILE_* and  REPOSITORY_REPOMD_* keys into REPOSITORY_RESOURCE
 
 - drop patchcheck
 
-- rename repo2solv.sh to repo2solv (maybe rewrite in C?)
-
-- obey -A option in repo2solv
-
 - make FAVOR handling deal with versions
 
 - write more manpages
 
-- bindings: selection.flags() should be a attribute and not a method
-
-- rename repodata_lookup_id_uninternalized to repodata_lookup_id_voidid_uninternalized
-  and add a notfound argument
-
 IDEAS:
 
+drop SEARCH_FILES and add SEARCH_BASENAME instead?
index d866276..6ed2c6f 100644 (file)
 #    set COMPATMINOR to MINOR. (binary incompatible change)
 #
 
-SET(LIBSOLV_SOVERSION "0")
-SET(LIBSOLVEXT_SOVERSION "0")
+SET(LIBSOLV_SOVERSION "1")
+SET(LIBSOLVEXT_SOVERSION "1")
 
 SET(LIBSOLV_MAJOR "0")
-SET(LIBSOLV_MINOR "6")
-SET(LIBSOLV_PATCH "36")
+SET(LIBSOLV_MINOR "7")
+SET(LIBSOLV_PATCH "0")
 
index 8fb469f..1a88917 100644 (file)
@@ -954,6 +954,7 @@ typedef int Id;
 
 typedef struct {
   Pool* const pool;
+  int const flags;
 } Selection;
 
 typedef struct {
@@ -1288,9 +1289,6 @@ typedef struct {
     queue_free(&$self->q);
     solv_free($self);
   }
-  int flags() {
-    return $self->flags;
-  }
 #ifdef SWIGRUBY
   %rename("isempty?") isempty;
 #endif
@@ -3727,7 +3725,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) {
@@ -3870,9 +3868,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);
   }
@@ -3890,9 +3894,24 @@ rb_eval_string(
   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);
index dacc5fe..1f37339 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: helix2solv
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "HELIX2SOLV" "1" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "HELIX2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 7965f00..492bd80 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: installcheck
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "INSTALLCHECK" "1" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "INSTALLCHECK" "1" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 7ca0bb5..4bfab9c 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: Libsolv-Bindings
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 06/15/2018
+.\"      Date: 10/24/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "LIBSOLV\-BINDINGS" "3" "06/15/2018" "libsolv" "LIBSOLV"
+.TH "LIBSOLV\-BINDINGS" "3" "10/24/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -2392,8 +2392,8 @@ my \fI$string\fR \fB=\fR \fI$solvable\fR\fB\->lookup_str(\fR\fI$keyname\fR\fB)\f
 .nf
 \fBId lookup_id(Id\fR \fIkeyname\fR\fB)\fR
 my \fI$id\fR \fB=\fR \fI$solvable\fR\fB\->lookup_id(\fR\fI$keyname\fR\fB)\fR;
-\fIid\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB)\fR
-\fIid\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB)\fR
+\fIid\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_id(\fR\fIkeyname\fR\fB)\fR
+\fIid\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_id(\fR\fIkeyname\fR\fB)\fR
 .fi
 .if n \{\
 .RE
@@ -2403,7 +2403,7 @@ my \fI$id\fR \fB=\fR \fI$solvable\fR\fB\->lookup_id(\fR\fI$keyname\fR\fB)\fR;
 .RS 4
 .\}
 .nf
-\fBunsigned long long lookup_num(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR \fB= 0)\fR
+\fBunsigned long long lookup_num(Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR \fB= 0)\fR
 my \fI$num\fR \fB=\fR \fI$solvable\fR\fB\->lookup_num(\fR\fI$keyname\fR\fB)\fR;
 \fInum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR
 \fInum\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_num(\fR\fIkeyname\fR\fB)\fR
@@ -2471,9 +2471,9 @@ Generic lookup methods\&. Retrieve data stored for the specific keyname\&. The l
 .\}
 .nf
 \fBconst char *lookup_location(unsigned int *\fR\fIOUTPUT\fR\fB)\fR;
-my \fB(\fR\fI$location\fR\fB,\fR \fI$medianr\fR\fB) =\fR \fI$solvable\fR\fB\->lookup_location()\fR;
-\fIlocation\fR\fB,\fR \fImedianr\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_location()\fR
-\fIlocation\fR\fB,\fR \fImedianr\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_location()\fR
+my \fB(\fR\fI$location\fR\fB,\fR \fI$mediano\fR\fB) =\fR \fI$solvable\fR\fB\->lookup_location()\fR;
+\fIlocation\fR\fB,\fR \fImediano\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_location()\fR
+\fIlocation\fR\fB,\fR \fImediano\fR \fB=\fR \fIsolvable\fR\fB\&.lookup_location()\fR
 .fi
 .if n \{\
 .RE
@@ -3161,22 +3161,22 @@ Intersect the result of the match to the current selection instead of replacing
 .\}
 .sp
 Back pointer to pool\&.
-.SS "METHODS"
 .sp
 .if n \{\
 .RS 4
 .\}
 .nf
-\fBint flags()\fR
-my \fI$flags\fR \fB=\fR \fI$sel\fR\fB\->flags()\fR;
-\fIflags\fR \fB=\fR \fIsel\fR\fB\&.flags()\fR
-\fIflags\fR \fB=\fR \fIsel\fR\fB\&.flags()\fR
+\fBint flags;\fR                              /* read only */
+\fI$sel\fR\fB\->{flags}\fR
+\fIflags\fR \fB=\fR \fIsel\fR\fB\&.flags\fR
+\fIflags\fR \fB=\fR \fIsel\fR\fB\&.flags\fR
 .fi
 .if n \{\
 .RE
 .\}
 .sp
-Return the result flags of the selection\&. The flags are a subset of the ones used when creating the selection, they describe which method was used to get the result\&. For example, if you create the selection with \(lqSELECTION_NAME | SELECTION_PROVIDES\(rq, the resulting flags will either be SELECTION_NAME or SELECTION_PROVIDES depending if there was a package that matched the name or not\&. If there was no match at all, the flags will be zero\&.
+The result flags of the selection\&. The flags are a subset of the ones used when creating the selection, they describe which method was used to get the result\&. For example, if you create the selection with \(lqSELECTION_NAME | SELECTION_PROVIDES\(rq, the resulting flags will either be SELECTION_NAME or SELECTION_PROVIDES depending if there was a package that matched the name or not\&. If there was no match at all, the flags will be zero\&.
+.SS "METHODS"
 .sp
 .if n \{\
 .RS 4
@@ -5049,7 +5049,7 @@ For installed packages, returns all of the packages that replace us\&. For to be
 .RS 4
 .\}
 .nf
-\fBint calc_installsizechange()\fR;
+\fBlong long calc_installsizechange()\fR;
 my \fI$change\fR \fB=\fR \fI$trans\fR\fB\->calc_installsizechange()\fR;
 \fIchange\fR \fB=\fR \fItrans\fR\fB\&.calc_installsizechange()\fR
 \fIchange\fR \fB=\fR \fItrans\fR\fB\&.calc_installsizechange()\fR
@@ -5739,6 +5739,45 @@ my \fI$string\fR \fB=\fR \fI$data\fR\fB\->lookup_str(\fR\fI$solvid\fR\fB,\fR \fI
 .RS 4
 .\}
 .nf
+\fBconst char *lookup_id(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
+my \fI$string\fR \fB=\fR \fI$data\fR\fB\->lookup_id(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIstring\fR \fB=\fR \fIdata\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIstring\fR \fB=\fR \fIdata\fR\fB\&.lookup_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBunsigned long long lookup_num(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInotfound\fR \fB= 0)\fR
+my \fI$num\fR \fB=\fR \fI$data\fR\fB\->lookup_num(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fInum\fR \fB=\fR \fIdata\fR\fB\&.lookup_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fInum\fR \fB=\fR \fIdata\fR\fB\&.lookup_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBbool lookup_void(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
+my \fI$bool\fR \fB=\fR \fI$data\fR\fB\->lookup_void(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIbool\fR \fB=\fR \fIdata\fR\fB\&.lookup_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIbool\fR \fB=\fR \fIdata\fR\fB\&.lookup_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
 \fBId *lookup_idarray(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR
 my \fI@ids\fR \fB=\fR \fI$data\fR\fB\->lookup_idarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
 \fIids\fR \fB=\fR \fIdata\fR\fB\&.lookup_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
@@ -5768,6 +5807,19 @@ Lookup functions\&. Return the data element stored in the specified solvable\&.
 .RS 4
 .\}
 .nf
+\fBvoid set_str(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fIstr\fR\fB)\fR;
+\fI$data\fR\fB\->set_str(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$str\fR\fB)\fR;
+\fIdata\fR\fB\&.set_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR
+\fIdata\fR\fB\&.set_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
 \fBvoid set_id(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, DepId\fR \fIid\fR\fB)\fR;
 \fI$data\fR\fB\->set_id(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$id\fR\fB)\fR;
 \fIdata\fR\fB\&.set_id(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR
@@ -5781,10 +5833,23 @@ Lookup functions\&. Return the data element stored in the specified solvable\&.
 .RS 4
 .\}
 .nf
-\fBvoid set_str(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, const char *\fR\fIstr\fR\fB)\fR;
-\fI$data\fR\fB\->set_str(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$str\fR\fB)\fR;
-\fIdata\fR\fB\&.set_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR
-\fIdata\fR\fB\&.set_str(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIstr\fR\fB)\fR
+\fBvoid set_num(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, unsigned long long\fR \fInum\fR\fB)\fR;
+\fI$data\fR\fB\->set_num(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$num\fR\fB)\fR;
+\fIdata\fR\fB\&.set_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fInum\fR\fB)\fR
+\fIdata\fR\fB\&.set_num(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fInum\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid set_void(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR;
+\fI$data\fR\fB\->set_void(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIdata\fR\fB\&.set_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIdata\fR\fB\&.set_void(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
 .fi
 .if n \{\
 .RE
@@ -5833,6 +5898,19 @@ Lookup functions\&. Return the data element stored in the specified solvable\&.
 .RS 4
 .\}
 .nf
+\fBvoid set_location(Id\fR \fIsolvid\fR\fB, unsigned int\fR \fImediano\fR\fB, const char *\fR\fIlocation\fR\fB)\fR;
+\fI$data\fR\fB\&.set_location(\fR\fI$solvid\fR\fB,\fR \fI$mediano\fR\fB,\fR \fI$location\fR\fB)\fR;
+\fIdata\fR\fB\&.set_location(\fR\fIsolvid\fR\fB,\fR \fImediano\fR\fB,\fR \fIlocation\fR\fB)\fR
+\fIdata\fR\fB\&.set_location(\fR\fIsolvid\fR\fB,\fR \fImediano\fR\fB,\fR \fIlocation\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
 \fBvoid add_idarray(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, DepId\fR \fIid\fR\fB)\fR;
 \fI$data\fR\fB\->add_idarray(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$id\fR\fB)\fR;
 \fIdata\fR\fB\&.add_idarray(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIid\fR\fB)\fR
@@ -5868,6 +5946,19 @@ my \fI$handle\fR \fB=\fR \fI$data\fR\fB\->new_handle()\fR;
 .RE
 .\}
 .sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid unset(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB)\fR;
+\fI$data\fR\fB\->unset(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIdata\fR\fB\&.unset(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIdata\fR\fB\&.unset(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
 Data storage methods\&. Probably only useful to store data in the special SOLVID_META solvid that stores repodata meta information\&. Note that repodata areas can have their own Id pool (see the REPO_LOCALPOOL flag), so be careful if you need to store ids\&. Arrays are created by calling the add function for every element\&. A flexarray is an array of sub\-structures, call new_handle to create a new structure, use the handle as solvid to fill the structure with data and call add_flexarray to put the structure in an array\&.
 .SH "THE DATAPOS CLASS"
 .sp
@@ -5910,9 +6001,9 @@ Create a Dataiterator at the position of the datapos object\&.
 .\}
 .nf
 \fBconst char *lookup_deltalocation(unsigned int *\fR\fIOUTPUT\fR\fB)\fR;
-my \fB(\fR\fI$location\fR\fB,\fR \fI$medianr\fR\fB) =\fR \fI$datapos\fR\fB\->lookup_deltalocation()\fR;
-\fIlocation\fR\fB,\fR \fImedianr\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltalocation()\fR
-\fIlocation\fR\fB,\fR \fImedianr\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltalocation()\fR
+my \fB(\fR\fI$location\fR\fB,\fR \fI$mediano\fR\fB) =\fR \fI$datapos\fR\fB\->lookup_deltalocation()\fR;
+\fIlocation\fR\fB,\fR \fImediano\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltalocation()\fR
+\fIlocation\fR\fB,\fR \fImediano\fR \fB=\fR \fIdatapos\fR\fB\&.lookup_deltalocation()\fR
 .fi
 .if n \{\
 .RE
index 87a14e6..228dfdd 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: Libsolv-Constantids
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "LIBSOLV\-CONSTANTIDS" "3" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "LIBSOLV\-CONSTANTIDS" "3" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 6a600ac..fc2d69b 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: Libsolv-History
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "LIBSOLV\-HISTORY" "3" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "LIBSOLV\-HISTORY" "3" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index c64eeb1..51dc1a4 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: Libsolv-Pool
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 07/16/2018
+.\"      Date: 10/22/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "LIBSOLV\-POOL" "3" "07/16/2018" "libsolv" "LIBSOLV"
+.TH "LIBSOLV\-POOL" "3" "10/22/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index dcebb02..a6ac359 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: Libsolv
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "LIBSOLV" "3" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "LIBSOLV" "3" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 513187a..ac593f1 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: mdk2solv
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "MDK2SOLV" "1" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "MDK2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 1c706c7..65fd756 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: mergesolv
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "MERGESOLV" "1" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "MERGESOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 5f21465..0a8c3cf 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: repo2solv
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 07/16/2018
+.\"      Date: 10/22/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "REPO2SOLV" "1" "07/16/2018" "libsolv" "LIBSOLV"
+.TH "REPO2SOLV" "1" "10/22/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index aeac7bd..5d459cc 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: repomdxml2solv
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "REPOMDXML2SOLV" "1" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "REPOMDXML2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 79c6d26..6f84a7f 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: rpmdb2solv
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "RPMDB2SOLV" "1" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "RPMDB2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 44ea70f..5149a1c 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: rpmmd2solv
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "RPMMD2SOLV" "1" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "RPMMD2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 11b3671..75a89f3 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: rpms2solv
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "RPMS2SOLV" "1" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "RPMS2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index b61538d..aae1c6d 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: solv
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 07/19/2018
+.\"      Date: 10/22/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "SOLV" "1" "07/19/2018" "libsolv" "LIBSOLV"
+.TH "SOLV" "1" "10/22/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 43a616a..8dd83d4 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: susetags2solv
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "SUSETAGS2SOLV" "1" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "SUSETAGS2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 158aedc..50254f7 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: testsolv
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "TESTSOLV" "1" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "TESTSOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index cd0386d..aa60372 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: updateinfoxml2solv
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\"      Date: 08/04/2017
+.\"      Date: 09/14/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "UPDATEINFOXML2SOLV" "1" "08/04/2017" "libsolv" "LIBSOLV"
+.TH "UPDATEINFOXML2SOLV" "1" "09/14/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
index 5db1116..d28b8b5 100644 (file)
@@ -1342,10 +1342,10 @@ a specific id and want to avoid the string compare overhead.
 
        Id lookup_id(Id keyname)
        my $id = $solvable->lookup_id($keyname);
-       id = solvable.lookup_id(solvid)
-       id = solvable.lookup_id(solvid)
+       id = solvable.lookup_id(keyname)
+       id = solvable.lookup_id(keyname)
 
-       unsigned long long lookup_num(Id solvid, Id keyname, unsigned long long notfound = 0)
+       unsigned long long lookup_num(Id keyname, unsigned long long notfound = 0)
        my $num = $solvable->lookup_num($keyname);
        num = solvable.lookup_num(keyname)
        num = solvable.lookup_num(keyname)
@@ -1382,9 +1382,9 @@ array, use 1 to select the second part or 0 to retrieve all ids
 including the marker.
 
        const char *lookup_location(unsigned int *OUTPUT);
-       my ($location, $medianr) = $solvable->lookup_location();
-       location, medianr = solvable.lookup_location()
-       location, medianr = solvable.lookup_location()
+       my ($location, $mediano) = $solvable->lookup_location();
+       location, mediano = solvable.lookup_location()
+       location, mediano = solvable.lookup_location()
 
 Return a tuple containing the on-media location and an optional
 media number for multi-part repositories (e.g. repositories
@@ -1780,14 +1780,12 @@ Intersect the result of the match to the current selection instead of replacing
 
 Back pointer to pool.
 
-=== METHODS ===
-
-       int flags()
-       my $flags = $sel->flags();
-       flags = sel.flags()
-       flags = sel.flags()
+       int flags;                              /* read only */
+       $sel->{flags}
+       flags = sel.flags
+       flags = sel.flags
 
-Return the result flags of the selection. The flags are a subset
+The result flags of the selection. The flags are a subset
 of the ones used when creating the selection, they describe which
 method was used to get the result. For example, if you create the
 selection with ``SELECTION_NAME | SELECTION_PROVIDES'', the resulting
@@ -1795,6 +1793,8 @@ flags will either be SELECTION_NAME or SELECTION_PROVIDES depending
 if there was a package that matched the name or not. If there was
 no match at all, the flags will be zero.
 
+=== METHODS ===
+
        bool isempty()
        $sel->isempty()
        sel.isempty()
@@ -3128,7 +3128,7 @@ be installed packages, returns all of the packages that the new package
 replaces. The special ``other'' solvable is always the first entry of the
 returned array.
 
-       int calc_installsizechange();
+       long long calc_installsizechange();
        my $change = $trans->calc_installsizechange();
        change = trans.calc_installsizechange()
        change = trans.calc_installsizechange()
@@ -3520,6 +3520,21 @@ the same id.
        string = data.lookup_str(solvid, keyname)
        string = data.lookup_str(solvid, keyname)
 
+       const char *lookup_id(Id solvid, Id keyname)
+       my $string = $data->lookup_id($solvid, $keyname);
+       string = data.lookup_id(solvid, keyname)
+       string = data.lookup_id(solvid, keyname)
+
+       unsigned long long lookup_num(Id solvid, Id keyname, unsigned long long notfound = 0)
+       my $num = $data->lookup_num($solvid, $keyname);
+       num = data.lookup_num(solvid, keyname)
+       num = data.lookup_num(solvid, keyname)
+
+       bool lookup_void(Id solvid, Id keyname)
+       my $bool = $data->lookup_void($solvid, $keyname);
+       bool = data.lookup_void(solvid, keyname)
+       bool = data.lookup_void(solvid, keyname)
+
        Id *lookup_idarray(Id solvid, Id keyname)
        my @ids = $data->lookup_idarray($solvid, $keyname);
        ids = data.lookup_idarray(solvid, keyname)
@@ -3536,15 +3551,25 @@ SOLVID_META solvid that stores repodata meta information.
 
 === DATA STORAGE METHODS ===
 
+       void set_str(Id solvid, Id keyname, const char *str);
+       $data->set_str($solvid, $keyname, $str);
+       data.set_str(solvid, keyname, str)
+       data.set_str(solvid, keyname, str)
+
        void set_id(Id solvid, Id keyname, DepId id);
        $data->set_id($solvid, $keyname, $id);
        data.set_id(solvid, keyname, id)
        data.set_id(solvid, keyname, id)
 
-       void set_str(Id solvid, Id keyname, const char *str);
-       $data->set_str($solvid, $keyname, $str);
-       data.set_str(solvid, keyname, str)
-       data.set_str(solvid, keyname, str)
+       void set_num(Id solvid, Id keyname, unsigned long long num);
+       $data->set_num($solvid, $keyname, $num);
+       data.set_num(solvid, keyname, num)
+       data.set_num(solvid, keyname, num)
+
+       void set_void(Id solvid, Id keyname);
+       $data->set_void($solvid, $keyname);
+       data.set_void(solvid, keyname)
+       data.set_void(solvid, keyname)
 
        void set_poolstr(Id solvid, Id keyname, const char *str);
        $data->set_poolstr($solvid, $keyname, $str);
@@ -3561,6 +3586,11 @@ SOLVID_META solvid that stores repodata meta information.
        data.set_sourcepkg(solvid, sourcepkg)
        data.set_sourcepkg(solvid, sourcepkg)
 
+       void set_location(Id solvid, unsigned int mediano, const char *location);
+       $data.set_location($solvid, $mediano, $location);
+       data.set_location(solvid, mediano, location)
+       data.set_location(solvid, mediano, location)
+
        void add_idarray(Id solvid, Id keyname, DepId id);
        $data->add_idarray($solvid, $keyname, $id);
        data.add_idarray(solvid, keyname, id)
@@ -3576,6 +3606,11 @@ SOLVID_META solvid that stores repodata meta information.
        data.add_flexarray(solvid, keyname, handle)
        data.add_flexarray(solvid, keyname, handle)
 
+       void unset(Id solvid, Id keyname);
+       $data->unset($solvid, $keyname);
+       data.unset(solvid, keyname)
+       data.unset(solvid, keyname)
+
 Data storage methods. Probably only useful to store data in the special
 SOLVID_META solvid that stores repodata meta information. Note that
 repodata areas can have their own Id pool (see the REPO_LOCALPOOL flag),
@@ -3612,9 +3647,9 @@ Back pointer to repository object.
 Create a Dataiterator at the position of the datapos object.
 
        const char *lookup_deltalocation(unsigned int *OUTPUT);
-       my ($location, $medianr) = $datapos->lookup_deltalocation();
-       location, medianr = datapos.lookup_deltalocation()
-       location, medianr = datapos.lookup_deltalocation()
+       my ($location, $mediano) = $datapos->lookup_deltalocation();
+       location, mediano = datapos.lookup_deltalocation()
+       location, mediano = datapos.lookup_deltalocation()
 
 Return a tuple containing the on-media location and an optional media number
 for a delta rpm. This obviously only works if the data position points to
index 128e179..ad8314f 100644 (file)
@@ -47,9 +47,6 @@ 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 9e90670..6f54247 100755 (executable)
@@ -582,8 +582,8 @@ for my $arg (@ARGV) {
     print "[ignoring case for '$arg']\n" unless $sel->isempty();
   }
   die("nothing matches '$arg'\n") if $sel->isempty();
-  print "[using file list match for '$arg']\n" if $sel->flags() & $solv::Selection::SELECTION_FILELIST;
-  print "[using capability match for '$arg']\n" if $sel->flags() & $solv::Selection::SELECTION_PROVIDES;
+  print "[using file list match for '$arg']\n" if $sel->{flags} & $solv::Selection::SELECTION_FILELIST;
+  print "[using capability match for '$arg']\n" if $sel->{flags} & $solv::Selection::SELECTION_PROVIDES;
   push @jobs, $sel->jobs($cmdactionmap{$cmd});
 }
 
index 891c237..75067f2 100755 (executable)
@@ -717,9 +717,9 @@ for arg in args:
         if sel.isempty():
             print("nothing matches '%s'" % arg)
             sys.exit(1)
-        if sel.flags() & solv.Selection.SELECTION_FILELIST:
+        if sel.flags & solv.Selection.SELECTION_FILELIST:
             print("[using file list match for '%s']" % arg)
-        if sel.flags() & solv.Selection.SELECTION_PROVIDES:
+        if sel.flags & solv.Selection.SELECTION_PROVIDES:
             print("[using capability match for '%s']" % arg)
         jobs += sel.jobs(cmdactionmap[cmd])
 
index 0ee4e73..d2ebd97 100644 (file)
@@ -68,11 +68,7 @@ findfastest(char **urls, int nurls)
          socks[i] = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
          if (socks[i] >= 0)
            {
-             if (fcntl(socks[i], F_SETFL, O_NONBLOCK) == -1)
-            {
-                     close(socks[i]);
-                     socks[i] = -1;
-            }
+             fcntl(socks[i], F_SETFL, O_NONBLOCK);
              if (connect(socks[i], result->ai_addr, result->ai_addrlen) == -1)
                {
                  if (errno != EINPROGRESS)
index 42ab751..3deb1a0 100644 (file)
@@ -130,7 +130,7 @@ showdiskusagechanges(Transaction *trans)
   duc[3].path = "/etc";
   transaction_calc_duchanges(trans, duc, 4);
   for (i = 0; i < 4; i++)
-    printf("duchanges %s: %d K  %d inodes\n", duc[i].path, duc[i].kbytes, duc[i].files);
+    printf("duchanges %s: %lld K  %lld inodes\n", duc[i].path, duc[i].kbytes, duc[i].files);
 }
 #endif
 
@@ -169,7 +169,6 @@ find_repo(const char *name, Pool *pool, struct repoinfo *repoinfos, int nrepoinf
   return 0;
 }
 
-
 #define MODE_LIST        0
 #define MODE_INSTALL     1
 #define MODE_ERASE       2
@@ -227,6 +226,7 @@ main(int argc, char **argv)
   char *rootdir = 0;
   char *keyname = 0;
   int keyname_depstr = 0;
+  int keyname_alldeps = 0;             /* dnf repoquesy --alldeps */
   int debuglevel = 0;
   int answer, acnt = 0;
   char *testcase = 0;
@@ -316,9 +316,15 @@ main(int argc, char **argv)
          argc--;
          argv++;
        }
+      else if (argc > 1 && !strcmp(argv[1], "--alldeps"))
+       {
+         keyname_alldeps = 1;          /* dnf repoquesy --alldeps */
+         argc--;
+         argv++;
+       }
       else if (argc > 1 && !strcmp(argv[1], "--depstr"))
        {
-         keyname_depstr = 1;
+         keyname_depstr = 1;   /* do literal matching instead of dep intersection */
          argc--;
          argv++;
        }
@@ -539,7 +545,7 @@ main(int argc, char **argv)
        flags |= SELECTION_FILELIST | (mode == MODE_ERASE ? SELECTION_INSTALLED_ONLY : 0);
       if (keyname && keyname_depstr)
        flags |= SELECTION_MATCH_DEPSTR;
-      if (!keyname)
+      if (!keyname || keyname_alldeps)
         rflags = selection_make(pool, &job2, argv[i], flags);
       else
         rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
@@ -552,7 +558,7 @@ main(int argc, char **argv)
       if (!job2.count)
        {
          flags |= SELECTION_NOCASE;
-         if (!keyname)
+         if (!keyname || keyname_alldeps)
             rflags = selection_make(pool, &job2, argv[i], flags);
          else
            rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
@@ -574,6 +580,14 @@ main(int argc, char **argv)
         printf("[using file list match for '%s']\n", argv[i]);
       if (rflags & SELECTION_PROVIDES)
        printf("[using capability match for '%s']\n", argv[i]);
+      if (keyname && keyname_alldeps)
+       {
+         Queue q;
+         queue_init(&q);
+         selection_solvables(pool, &job2, &q);
+         selection_make_matchsolvablelist(pool, &job2, &q, 0, pool_str2id(pool, keyname, 1), 0);
+         queue_free(&q);
+       }
       queue_insertn(&job, job.count, job2.count, job2.elements);
       queue_free(&job2);
     }
@@ -773,7 +787,7 @@ rerunsolver:
 #if defined(SUSE)
   showdiskusagechanges(trans);
 #endif
-  printf("install size change: %d K\n", transaction_calc_installsizechange(trans));
+  printf("install size change: %lld K\n", transaction_calc_installsizechange(trans));
   printf("\n");
 
   acnt = solver_alternatives_count(solv);
index 62faf2d..03098e2 100644 (file)
@@ -467,13 +467,40 @@ repo_add_appdata(Repo *repo, FILE *fp, int flags)
   return repo_add_appdata_fn(repo, fp, flags, 0, 0);
 }
 
+struct uninternalized_filelist_data {
+  Id did;
+  Queue *res;
+};
+
+static int
+search_uninternalized_filelist_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
+{
+  struct uninternalized_filelist_data *uf = cbdata;
+  const char *str;
+  Id id;
+  size_t l;
+  if (key->type != REPOKEY_TYPE_DIRSTRARRAY || kv->id != uf->did)
+    return 0;
+  str = kv->str;
+  l = strlen(str);
+  if (l > 12 && strncmp(str + l - 12, ".appdata.xml", 12))
+    id = pool_str2id(data->repo->pool, str, 1);
+  else if (l > 13 && strncmp(str + l - 13, ".metainfo.xml", 13))
+    id = pool_str2id(data->repo->pool, str, 1);
+  else
+    return 0;
+  queue_push2(uf->res, s - data->repo->pool->solvables, id);
+  return 0;
+}
+
 static void
 search_uninternalized_filelist(Repo *repo, const char *dir, Queue *res)
 {
   Pool *pool = repo->pool;
-  Id rdid, p;
-  Id iter, did, idid;
+  Id did, rdid, p;
+  struct uninternalized_filelist_data uf;
 
+  uf.res = res;
   for (rdid = 1; rdid < repo->nrepodata; rdid++)
     {
       Repodata *data = repo_id2repodata(repo, rdid);
@@ -486,31 +513,12 @@ search_uninternalized_filelist(Repo *repo, const char *dir, Queue *res)
       did = repodata_str2dir(data, dir, 0);
       if (!did)
        continue;
+      uf.did = did;
       for (p = data->start; p < data->end; p++)
        {
-         if (p >= pool->nsolvables)
+         if (p >= pool->nsolvables || pool->solvables[p].repo != repo)
            continue;
-         if (pool->solvables[p].repo != repo)
-           continue;
-         iter = 0;
-         for (;;)
-           {
-             const char *str;
-             int l;
-             Id id;
-             idid = did;
-             str = repodata_lookup_dirstrarray_uninternalized(data, p, SOLVABLE_FILELIST, &idid, &iter);
-             if (!iter)
-               break;
-             l = strlen(str);
-             if (l > 12 && strncmp(str + l - 12, ".appdata.xml", 12))
-               id = pool_str2id(pool, str, 1);
-             else if (l > 13 && strncmp(str + l - 13, ".metainfo.xml", 13))
-               id = pool_str2id(pool, str, 1);
-             else
-               continue;
-             queue_push2(res, p, id);
-           }
+         repodata_search_uninternalized(data, p, SOLVABLE_FILELIST, 0, search_uninternalized_filelist_cb, &uf);
        }
     }
 }
index 7cef78c..f6e1004 100644 (file)
@@ -103,8 +103,8 @@ repo_add_autopattern(Repo *repo, int flags)
   if (repo == pool->installed)
     flags |= ADD_NO_AUTOPRODUCTS;      /* no auto products for installed repos */
 
-  pattern_id = pool_str2id(pool, "pattern()", 1);
-  product_id = pool_str2id(pool, "product()", 1);
+  pattern_id = pool_str2id(pool, "pattern()", 9);
+  product_id = pool_str2id(pool, "product()", 9);
   FOR_REPO_SOLVABLES(repo, p, s)
     {
       const char *n = pool_id2str(pool, s->name);
index dbc7f9c..26cf0e1 100644 (file)
@@ -19,7 +19,7 @@ extern int repo_add_keyring(Repo *repo, FILE *fp, int flags);
 extern int repo_add_keydir(Repo *repo, const char *keydir, const char *suffix, int flags);
 
 /* signature parsing */
-typedef struct _solvsig {
+typedef struct s_Solvsig {
   unsigned char *sigpkt;
   int sigpktl;
   Id htype;
index b2a5b8d..760d481 100644 (file)
@@ -181,7 +181,7 @@ startElement(struct solv_xmlparser *xmlp, int state, const char *name, const cha
             while (value)
              {
                char *p = strchr(value, ',');
-               if (p)
+               if (*p)
                  *p++ = 0;
                if (*value)
                  repodata_add_poolstr_array(pd->data, SOLVID_META, REPOSITORY_UPDATES, value);
index daf22e9..a2d518f 100644 (file)
@@ -1385,44 +1385,6 @@ copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo)
   return ido;
 }
 
-#define COPYDIR_DIRCACHE_SIZE 512
-
-static Id copydir_complex(Repodata *data, Repodata *fromdata, Id did, Id *cache);
-
-static inline Id
-copydir(Repodata *data, Repodata *fromdata, Id did, Id *cache)
-{
-  if (cache && did && cache[did & 255] == did)
-    return cache[(did & 255) + 256];
-  return copydir_complex(data, fromdata, did, cache);
-}
-
-static Id
-copydir_complex(Repodata *data, Repodata *fromdata, Id did, Id *cache)
-{
-  Id parent, compid;
-  if (!did)
-    {
-      /* make sure that the dirpool has an entry */
-      if (!data->dirpool.ndirs)
-        dirpool_add_dir(&data->dirpool, 0, 0, 1);
-      return 0;
-    }
-  parent = dirpool_parent(&fromdata->dirpool, did);
-  compid = dirpool_compid(&fromdata->dirpool, did);
-  if (parent)
-    parent = copydir(data, fromdata, parent, cache);
-  if (data->localpool || fromdata->localpool)
-    compid = repodata_translate_id(data, fromdata, compid, 1);
-  compid = dirpool_add_dir(&data->dirpool, parent, compid, 1);
-  if (cache)
-    {
-      cache[did & 255] = did;
-      cache[(did & 255) + 256] = compid;
-    }
-  return compid;
-}
-
 struct solvable_copy_cbdata {
   Repodata *data;
   Id handle;
@@ -1447,23 +1409,19 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K
       break;
     case REPOKEY_TYPE_DIRNUMNUMARRAY:
     case REPOKEY_TYPE_DIRSTRARRAY:
-      kv->id = copydir(data, fromdata, kv->id, cbdata->dircache);
+      kv->id = repodata_translate_dir(data, fromdata, kv->id, 1, fromdata->repodataid == 1 ? cbdata->dircache : 0);
       break;
+    case REPOKEY_TYPE_FIXARRAY:
+      cbdata->handle = repodata_new_handle(data);
+      repodata_add_fixarray(data, handle, key->name, cbdata->handle);
+      repodata_search_arrayelement(fromdata, 0, 0, 0, kv, &solvable_copy_cb, cbdata);
+      cbdata->handle = handle;
+      return 0;
     case REPOKEY_TYPE_FLEXARRAY:
-      if (kv->eof == 2)
-       {
-         assert(cbdata->subhandle);
-         cbdata->handle = cbdata->subhandle;
-         cbdata->subhandle = 0;
-         break;
-       }
-      if (!kv->entry)
-        {
-         assert(!cbdata->subhandle);
-         cbdata->subhandle = cbdata->handle;
-       }
       cbdata->handle = repodata_new_handle(data);
-      repodata_add_flexarray(data, cbdata->subhandle, key->name, cbdata->handle);
+      repodata_add_flexarray(data, handle, key->name, cbdata->handle);
+      repodata_search_arrayelement(fromdata, 0, 0, 0, kv, &solvable_copy_cb, cbdata);
+      cbdata->handle = handle;
       return 0;
     default:
       break;
@@ -1473,13 +1431,14 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K
 }
 
 static void
-solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache)
+solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache, Id **oldkeyskip)
 {
   int p, i;
   Repo *repo = s->repo;
   Pool *pool = repo->pool;
   Repo *fromrepo = r->repo;
   struct solvable_copy_cbdata cbdata;
+  Id *keyskip;
 
   /* copy solvable data */
   s->name = r->name;
@@ -1507,19 +1466,15 @@ solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache)
     {
       Repodata *fromdata = repo_id2repodata(fromrepo, 1);
       if (p >= fromdata->start && p < fromdata->end)
-        repodata_search(fromdata, p, 0, SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata);
+        repodata_search(fromdata, p, 0, 0, solvable_copy_cb, &cbdata);
       return;
     }
-#if 0
-  repo_search(fromrepo, p, 0, 0, SEARCH_NO_STORAGE_SOLVABLE | SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata);
-#else
+  keyskip = repo_create_keyskip(repo, p, oldkeyskip);
   FOR_REPODATAS(fromrepo, i, data)
     {
       if (p >= data->start && p < data->end)
-        repodata_search(data, p, 0, SEARCH_SUB | SEARCH_ARRAYSENTINEL, solvable_copy_cb, &cbdata);
-      cbdata.dircache = 0;     /* only for first repodata */
+        repodata_search_keyskip(data, p, 0, 0, keyskip, solvable_copy_cb, &cbdata);
     }
-#endif
 }
 
 /* used to sort entries by package name that got returned in some database order */
@@ -1731,7 +1686,8 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
     }
   else
     {
-      Id dircache[COPYDIR_DIRCACHE_SIZE];              /* see copydir */
+      Id *dircache;
+      Id *oldkeyskip = 0;
       struct rpmdbentry *entries = 0, *rp;
       int nentries = 0;
       char *namedata = 0;
@@ -1739,8 +1695,6 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
       Id id, *refhash;
       int res;
 
-      memset(dircache, 0, sizeof(dircache));
-
       /* get ids of installed rpms */
       entries = getinstalledrpmdbids(&state, "Name", 0, &nentries, &namedata, flags & RPMDB_KEEP_GPG_PUBKEY);
       if (!entries)
@@ -1795,10 +1749,11 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
       if (!repo->rpmdbid)
         repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
 
+      dircache = repodata_create_dirtranscache(data);
       for (i = 0, rp = entries; i < nentries; i++, rp++, s++)
        {
          Id dbid = rp->rpmdbid;
-         repo->rpmdbid[(s - pool->solvables) - repo->start] = rp->rpmdbid;
+         repo->rpmdbid[(s - pool->solvables) - repo->start] = dbid;
          if (refhash)
            {
              h = dbid & refmask;
@@ -1813,7 +1768,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
                  Solvable *r = ref->pool->solvables + ref->start + (id - 1);
                  if (r->repo == ref)
                    {
-                     solvable_copy(s, r, data, dircache);
+                     solvable_copy(s, r, data, dircache, &oldkeyskip);
                      continue;
                    }
                }
@@ -1827,6 +1782,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
              solv_free(entries);
              solv_free(namedata);
              solv_free(refhash);
+             dircache = repodata_free_dirtranscache(dircache);
              return -1;
            }
          rpmhead2solv(pool, repo, data, s, state.rpmhead, flags | RPM_ADD_TRIGGERS);
@@ -1838,7 +1794,9 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
                pool_debug(pool, SOLV_ERROR, "%%%% %d\n", done * 100 / count);
            }
        }
+      dircache = repodata_free_dirtranscache(dircache);
 
+      solv_free(oldkeyskip);
       solv_free(entries);
       solv_free(namedata);
       solv_free(refhash);
@@ -1939,8 +1897,6 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   if (fread(lead, 96 + 16, 1, fp) != 1 || getu32(lead) != 0xedabeedb)
     {
       pool_error(pool, -1, "%s: not a rpm", rpm);
-      solv_chksum_free(leadsigchksumh, 0);
-      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
@@ -1953,16 +1909,12 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   if (lead[78] != 0 || lead[79] != 5)
     {
       pool_error(pool, -1, "%s: not a rpm v5 header", rpm);
-      solv_chksum_free(leadsigchksumh, 0);
-      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
   if (getu32(lead + 96) != 0x8eade801)
     {
       pool_error(pool, -1, "%s: bad signature header", rpm);
-      solv_chksum_free(leadsigchksumh, 0);
-      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
@@ -1971,8 +1923,6 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   if (sigcnt >= MAX_SIG_CNT || sigdsize >= MAX_SIG_DSIZE)
     {
       pool_error(pool, -1, "%s: bad signature header", rpm);
-      solv_chksum_free(leadsigchksumh, 0);
-      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
@@ -1983,8 +1933,6 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
     {
       if (!headfromfp(&state, rpm, fp, lead + 96, sigcnt, sigdsize, sigpad, chksumh, leadsigchksumh))
        {
-      solv_chksum_free(leadsigchksumh, 0);
-      solv_chksum_free(chksumh, 0);
          fclose(fp);
          return 0;
        }
@@ -2024,8 +1972,6 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
          if (fread(lead, l, 1, fp) != 1)
            {
              pool_error(pool, -1, "%s: unexpected EOF", rpm);
-             solv_chksum_free(leadsigchksumh, 0);
-             solv_chksum_free(chksumh, 0);
              fclose(fp);
              return 0;
            }
@@ -2046,7 +1992,6 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   if (fread(lead, 16, 1, fp) != 1)
     {
       pool_error(pool, -1, "%s: unexpected EOF", rpm);
-      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
@@ -2055,7 +2000,6 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   if (getu32(lead) != 0x8eade801)
     {
       pool_error(pool, -1, "%s: bad header", rpm);
-      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
@@ -2064,7 +2008,6 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
   if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
     {
       pool_error(pool, -1, "%s: bad header", rpm);
-      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
@@ -2072,7 +2015,6 @@ repo_add_rpm(Repo *repo, const char *rpm, int flags)
 
   if (!headfromfp(&state, rpm, fp, lead, sigcnt, sigdsize, 0, chksumh, 0))
     {
-      solv_chksum_free(chksumh, 0);
       fclose(fp);
       return 0;
     }
index 6c05281..9f49bd3 100644 (file)
@@ -603,17 +603,18 @@ static void
 fill_cshash_from_new_solvables(struct parsedata *pd)
 {
   Pool *pool = pd->pool;
-  Id cstype = 0;
-  unsigned const char *cs;
-  int i;
+  int i, l;
+  KeyValue kv;
+  Repokey *key;
 
   for (i = pd->first; i < pool->nsolvables; i++)
     {
       if (pool->solvables[i].repo != pd->repo)
        continue;
-      cs = repodata_lookup_bin_checksum_uninternalized(pd->data, i, SOLVABLE_CHECKSUM, &cstype);
-      if (cs)
-       put_in_cshash(pd, cs, solv_chksum_len(cstype), i);
+      if ((key = repodata_lookup_kv_uninternalized(pd->data, i, SOLVABLE_CHECKSUM, &kv)) == 0)
+       continue;
+      if ((l = solv_chksum_len(key->type)) != 0)
+       put_in_cshash(pd, (const unsigned char *)kv.str, l, i);
     }
 }
 
@@ -1144,6 +1145,22 @@ repo_add_rpmmd(Repo *repo, FILE *fp, const char *language, int flags)
   repodata_free_dircache(data);
   queue_free(&pd.diskusageq);
 
+  if ((flags & REPO_EXTEND_SOLVABLES) != 0)
+    {
+      /* is this a filelist extension? */
+      if (repodata_has_keyname(data, SOLVABLE_FILELIST))
+       repodata_set_filelisttype(data, REPODATA_FILELIST_EXTENSION);
+    }
+  else
+    {
+      /* is this a primary with a filtered filelist? */
+      if (data->end > data->start)
+       {
+         repodata_set_filelisttype(data, REPODATA_FILELIST_FILTERED);
+         repodata_set_void(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST);
+       }
+    }
+
   if (!(flags & REPO_NO_INTERNALIZE))
     repodata_internalize(data);
   POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_rpmmd took %d ms\n", solv_timems(now));
index 52d5e5e..561c789 100644 (file)
@@ -333,7 +333,16 @@ lookup_shared_id(Repodata *data, Id p, Id keyname, Id voidid, int uninternalized
        return r;
     }
   if (uninternalized)
-    return repodata_lookup_id_uninternalized(data, p, keyname, voidid);
+    {
+      KeyValue kv;
+      Repokey *key = repodata_lookup_kv_uninternalized(data, p, keyname, &kv);
+      if (!key)
+        return 0;
+      if (key->type == REPOKEY_TYPE_VOID)
+       return voidid;
+      if (key->type == REPOKEY_TYPE_ID)
+       return kv.id;
+    }
   return 0;
 }
 
@@ -1062,6 +1071,23 @@ repo_add_susetags(Repo *repo, FILE *fp, Id defvendor, const char *language, int
 
   solv_free(joinhash);
   repodata_free_dircache(data);
+
+    if ((flags & REPO_EXTEND_SOLVABLES) != 0)
+    {    
+      /* is this a filelist extension? */
+      if (repodata_has_keyname(data, SOLVABLE_FILELIST))
+        repodata_set_filelisttype(data, REPODATA_FILELIST_EXTENSION);
+    }    
+  else 
+    {    
+      /* is this a primary with a filtered filelist? */
+      if (data->end > data->start)
+       {
+          repodata_set_filelisttype(data, REPODATA_FILELIST_FILTERED);
+         repodata_set_void(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST);
+       }
+    }  
+
   if (!(flags & REPO_NO_INTERNALIZE))
     repodata_internalize(data);
 
index a74762f..343aed8 100644 (file)
@@ -504,7 +504,69 @@ static inline FILE *myzstdfdopen(int fd, const char *mode)
 
 #ifdef ENABLE_ZCHUNK_COMPRESSION
 
+#ifdef WITH_SYSTEM_ZCHUNK
+/* use the system's zchunk library that supports reading and writing of zchunk files */
+
+#include <zck.h>
+
+static ssize_t cookie_zckread(void *cookie, char *buf, size_t nbytes)
+{
+  return zck_read((zckCtx *)cookie, buf, nbytes);
+}
+
+static ssize_t cookie_zckwrite(void *cookie, const char *buf, size_t nbytes)
+{
+  return zck_write((zckCtx *)cookie, buf, nbytes);
+}
+
+static int cookie_zckclose(void *cookie)
+{
+  zckCtx *zck = (zckCtx *)cookie;
+  int fd = zck_get_fd(zck);
+  if (fd != -1)
+    close(fd);
+  zck_free(&zck);
+  return 0;
+}
+
+static void *zchunkopen(const char *path, const char *mode, int fd)
+{
+  zckCtx *f;
+
+  if (!path && fd < 0)
+    return 0;
+  if (fd == -1)
+    {
+      if (*mode != 'w')
+        fd = open(path, O_RDONLY);
+      else
+        fd = open(path, O_WRONLY | O_CREAT, 0666);
+      if (fd == -1)
+       return 0;
+    }
+  f = zck_create();
+  if (!f)
+    {
+      close(fd);
+      return 0;
+    }
+  if (*mode != 'w')
+    {
+      if(!zck_init_read(f, fd))
+        return 0;
+    }
+   else
+    {
+      if(!zck_init_write(f, fd))
+        return 0;
+    }
+  return cookieopen(f, mode, cookie_zckread, cookie_zckwrite, cookie_zckclose);
+}
+
+#else
+
 #include "solv_zchunk.h"
+/* use the libsolv's limited zchunk implementation that only supports reading of zchunk files */
 
 static void *zchunkopen(const char *path, const char *mode, int fd)
 {
@@ -512,20 +574,22 @@ static void *zchunkopen(const char *path, const char *mode, int fd)
   void *f;
   if (!path && fd < 0)
     return 0;
-  if (strcmp(mode, "r") != 0)
-    return 0;
   if (fd != -1)
     fp = fdopen(fd, mode);
   else
     fp = fopen(path, mode);
   if (!fp)
     return 0;
+  if (strcmp(mode, "r") != 0)
+    return 0;
   f = solv_zchunk_open(fp, 1);
   if (!f)
     fclose(fp);
   return cookieopen(f, mode, (ssize_t (*)(void *, char *, size_t))solv_zchunk_read, 0, (int (*)(void *))solv_zchunk_close);
 }
 
+#endif
+
 static inline FILE *myzchunkfopen(const char *fn, const char *mode)
 {
   return zchunkopen(fn, mode, -1);
@@ -536,7 +600,8 @@ static inline FILE *myzchunkfdopen(int fd, const char *mode)
   return zchunkopen(0, mode, fd);
 }
 
-#endif
+#endif /* ENABLE_ZCHUNK_COMPRESSION */
+
 
 FILE *
 solv_xfopen(const char *fn, const char *mode)
@@ -584,7 +649,7 @@ solv_xfopen(const char *fn, const char *mode)
   if (suf && !strcmp(suf, ".zck"))
     return myzchunkfopen(fn, mode);
 #else
-  if (suf && !strcmp(suf, ".zst"))
+  if (suf && !strcmp(suf, ".zck"))
     return 0;
 #endif
   return fopen(fn, mode);
@@ -649,7 +714,7 @@ solv_xfopen_fd(const char *fn, int fd, const char *mode)
   if (suf && !strcmp(suf, ".zck"))
     return myzchunkfdopen(fd, simplemode);
 #else
-  if (suf && !strcmp(suf, ".zst"))
+  if (suf && !strcmp(suf, ".zck"))
     return 0;
 #endif
   return fdopen(fd, mode);
index 0bac26b..ffc8b8a 100644 (file)
@@ -174,6 +174,9 @@ static struct selflags2str {
   { SELECTION_MATCH_DEPSTR, "depstr" },
   { SELECTION_WITH_DISABLED, "withdisabled" },
   { SELECTION_WITH_BADARCH, "withbadarch" },
+  { SELECTION_ADD, "add" },
+  { SELECTION_SUBTRACT, "subtract" },
+  { SELECTION_FILTER, "filter" },
   { 0, 0 }
 };
 
@@ -571,8 +574,6 @@ testcase_str2dep_complex(Pool *pool, const char **sp, int relop)
   Id flags, id, id2, namespaceid = 0;
   struct oplist *op;
 
-  if (!s)
-    return 0;
   while (*s == ' ' || *s == '\t')
     s++;
   if (!strncmp(s, "namespace:", 10))
@@ -1070,7 +1071,7 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp)
       Queue q;
       job |= SOLVER_SOLVABLE_ONE_OF;
       queue_init(&q);
-      if (npieces > 2 && strcmp(pieces[2], "nothing") != 0)
+      if (npieces > 3 && strcmp(pieces[2], "nothing") != 0)
        {
          for (i = 2; i < npieces; i++)
            {
@@ -1129,11 +1130,15 @@ testcase_str2job(Pool *pool, const char *str, Id *whatp)
   return job;
 }
 
+#define SELECTIONJOB_MATCHDEPS         1
+#define SELECTIONJOB_MATCHDEPID                2
+#define SELECTIONJOB_MATCHSOLVABLE     3
+
 static int
-addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue, int keyname)
+addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue, int type, int keyname)
 {
   Id job;
-  int i, r;
+  int i, r = 0;
   int selflags;
   Queue sel;
   char *sp;
@@ -1163,12 +1168,20 @@ addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue, int key
     if (*sp == 0)
       *sp = ' ';
   queue_init(&sel);
-  if (keyname > 0)
-    r = selection_make_matchdeps(pool, &sel, pieces[2], selflags, keyname, 0);
-  else if (keyname < 0)
-    r = selection_make_matchdepid(pool, &sel, testcase_str2dep(pool, pieces[2]), selflags, -keyname, 0);
-  else
+  if (selflags & (SELECTION_ADD | SELECTION_SUBTRACT | SELECTION_FILTER))
+    {
+      for (i = 0; i < jobqueue->count; i += 2)
+       queue_push2(&sel, jobqueue->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK), jobqueue->elements[i + 1]);
+      queue_empty(jobqueue);
+    }
+  if (!type)
     r = selection_make(pool, &sel, pieces[2], selflags);
+  else if (type == SELECTIONJOB_MATCHDEPS)
+    r = selection_make_matchdeps(pool, &sel, pieces[2], selflags, keyname, 0);
+  else if (type == SELECTIONJOB_MATCHDEPID)
+    r = selection_make_matchdepid(pool, &sel, testcase_str2dep(pool, pieces[2]), selflags, keyname, 0);
+  else if (type == SELECTIONJOB_MATCHSOLVABLE)
+    r = selection_make_matchsolvable(pool, &sel, testcase_str2solvid(pool, pieces[2]), selflags, keyname, 0);
   for (i = 0; i < sel.count; i += 2)
     queue_push2(jobqueue, job | sel.elements[i], sel.elements[i + 1]);
   queue_free(&sel);
@@ -2015,7 +2028,7 @@ testcase_solverresult(Solver *solv, int resultflags)
                  if ((rtype & SOLVER_RULE_TYPEMASK) == SOLVER_RULE_JOB)
                    {
                      const char *js = testcase_job2str(pool, rq.elements[i + 2], rq.elements[i + 3]);
-                     char *s = pool_tmpjoin(pool, altprefix, num, "job ");
+                     char *s = pool_tmpjoin(pool, altprefix, num, " job ");
                      s = pool_tmpappend(pool, s, js, 0);
                      strqueue_push(&sq, s);
                    }
@@ -2025,13 +2038,6 @@ testcase_solverresult(Solver *solv, int resultflags)
                      s = pool_tmpappend(pool, s, " requires ", testcase_dep2str(pool, rq.elements[i + 3]));
                      strqueue_push(&sq, s);
                    }
-                 else if (rtype == SOLVER_RULE_UPDATE || rtype == SOLVER_RULE_FEATURE)
-                   {
-                     const char *js = testcase_solvid2str(pool, rq.elements[i + 1]);
-                     char *s = pool_tmpjoin(pool, altprefix, num, "update ");
-                     s = pool_tmpappend(pool, s, js, 0);
-                     strqueue_push(&sq, s);
-                   }
                }
            }
          for (i = 0; i < q.count; i++)
@@ -2179,7 +2185,7 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha
   Id lowscore;
   FILE *fp;
   Strqueue sq;
-  char *cmd, *out, *result;
+  char *cmd, *out;
   const char *s;
 
   if (!testcasename)
@@ -2314,6 +2320,7 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha
 
   if ((resultflags & ~TESTCASE_RESULT_REUSE_SOLVER) != 0)
     {
+      char *result;
       cmd = 0;
       for (i = 0; resultflags2str[i].str; i++)
        if ((resultflags & resultflags2str[i].flag) != 0)
@@ -2324,6 +2331,7 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha
       result = testcase_solverresult(solv, resultflags);
       if (!strcmp(resultname, "<inline>"))
        {
+         int i;
          Strqueue rsq;
          strqueue_init(&rsq);
          strqueue_split(&rsq, result);
@@ -2355,7 +2363,6 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha
          if (fclose(fp))
            {
              pool_error(solv->pool, 0, "testcase_write: write error");
-             solv_free(result);
              strqueue_free(&sq);
              return 0;
            }
@@ -2363,29 +2370,29 @@ testcase_write_mangled(Solver *solv, const char *dir, int resultflags, const cha
       solv_free(result);
     }
 
-  result = strqueue_join(&sq);
-  strqueue_free(&sq);
+  cmd = strqueue_join(&sq);
   out = pool_tmpjoin(pool, dir, "/", testcasename);
   if (!(fp = fopen(out, "w")))
     {
       pool_error(solv->pool, 0, "testcase_write: could not open '%s' for writing", out);
-      solv_free(result);
+      strqueue_free(&sq);
       return 0;
     }
-  if (*result && fwrite(result, strlen(result), 1, fp) != 1)
+  if (*cmd && fwrite(cmd, strlen(cmd), 1, fp) != 1)
     {
       pool_error(solv->pool, 0, "testcase_write: write error");
-      solv_free(result);
+      strqueue_free(&sq);
       fclose(fp);
       return 0;
     }
   if (fclose(fp))
     {
       pool_error(solv->pool, 0, "testcase_write: write error");
-      solv_free(result);
+      strqueue_free(&sq);
       return 0;
     }
-  solv_free(result);
+  solv_free(cmd);
+  strqueue_free(&sq);
   return 1;
 }
 
@@ -2743,19 +2750,25 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
            }
          if (npieces >= 3 && !strcmp(pieces[2], "selection"))
            {
-             addselectionjob(pool, pieces + 1, npieces - 1, job, 0);
+             addselectionjob(pool, pieces + 1, npieces - 1, job, 0, 0);
              continue;
            }
          if (npieces >= 4 && !strcmp(pieces[2], "selection_matchdeps"))
            {
              pieces[2] = pieces[1];
-             addselectionjob(pool, pieces + 2, npieces - 2, job, pool_str2id(pool, pieces[3], 1));
+             addselectionjob(pool, pieces + 2, npieces - 2, job, SELECTIONJOB_MATCHDEPS, pool_str2id(pool, pieces[3], 1));
              continue;
            }
          if (npieces >= 4 && !strcmp(pieces[2], "selection_matchdepid"))
            {
              pieces[2] = pieces[1];
-             addselectionjob(pool, pieces + 2, npieces - 2, job, -pool_str2id(pool, pieces[3], 1));
+             addselectionjob(pool, pieces + 2, npieces - 2, job, SELECTIONJOB_MATCHDEPID, pool_str2id(pool, pieces[3], 1));
+             continue;
+           }
+         if (npieces >= 4 && !strcmp(pieces[2], "selection_matchsolvable"))
+           {
+             pieces[2] = pieces[1];
+             addselectionjob(pool, pieces + 2, npieces - 2, job, SELECTIONJOB_MATCHSOLVABLE, pool_str2id(pool, pieces[3], 1));
              continue;
            }
          /* rejoin */
@@ -2774,7 +2787,7 @@ testcase_read(Pool *pool, FILE *fp, const char *testcase, Queue *job, char **res
        {
          int i = strlen(pieces[1]);
          s = strchr(pieces[1], '(');
-         if (!s || pieces[1][i - 1] != ')')
+         if (!s && pieces[1][i - 1] != ')')
            {
              pool_error(pool, 0, "testcase_read: bad namespace '%s'", pieces[1]);
            }
index dcdbabd..6146e99 100644 (file)
@@ -1,20 +1,11 @@
 -------------------------------------------------------------------
-Thu Jun 27 16:36:00 CEST 2019 - mls@suse.de
-
-- make cleandeps jobs on patterns work [bnc#1137977]
-- fix SOLVER_FLAG_FOCUS_BEST updateing packages without reason
-- be more correct with multiversion packages that obsolete their
-  own name [bnc#1127155]
-- always prefer to stay with the same package name if there are
-  multiple alternatives [bnc#1131823]
-- fix cleandeps updates not updating all packages
-- fixed a couple of null pointer derefs
-  [bnc#1120629] [bnc#1120630] [bnc#1120631]
-  [CVE-2018-20532] [CVE-2018-20533] [CVE-2018-20534]
-- no longer disable infarch rules when they don't conflict with
-  the job
-- do not autouninstall packages because of forcebest updates
-- bump version to 0.6.36
+Wed Oct 24 10:48:56 CEST 2018 - mls@suse.de
+
+- new repowriter interface
+- new selection_make_matchsolvable function
+- dropped support of REPOKEY_TYPE_U32
+- bindings: Selection.flags is now an attribute
+- bump version to 0.7.0
 
 -------------------------------------------------------------------
 Thu Aug  9 17:09:41 CEST 2018 - mls@suse.de
index 63d8f38..dd35ea9 100644 (file)
@@ -24,7 +24,7 @@
 %bcond_with bz2
 %bcond_with xz
 %endif
-%if 0%{?is_opensuse} && ( 0%{?sle_version} >= 150000 || 0%{?suse_version} >= 1500 )
+%if 0%{?is_opensuse} && (0%{?sle_version} >= 150000 || 0%{?suse_version} >= 1500)
 %bcond_without zstd
 %else
 %bcond_with zstd
index e8951f6..2e32968 100644 (file)
@@ -20,7 +20,7 @@ SET (libsolv_SRCS
     transaction.c order.c rules.c problems.c linkedpkg.c cplxdeps.c
     chksum.c md5.c sha1.c sha2.c solvversion.c selection.c
     fileprovides.c diskusage.c suse.c solver_util.c cleandeps.c
-    userinstalled.c)
+    userinstalled.c filelistfilter.c)
 
 SET (libsolv_HEADERS
     bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h
index 1e89590..6609678 100644 (file)
@@ -19,7 +19,7 @@
 extern "C" {
 #endif
 
-typedef struct _Map {
+typedef struct s_Map {
   unsigned char *map;
   int size;
 } Map;
index 935aea8..df46145 100644 (file)
@@ -19,7 +19,7 @@
 #include "sha1.h"
 #include "sha2.h"
 
-struct _Chksum {
+struct s_Chksum {
   Id type;
   int done;
   unsigned char result[64];
index 479923a..65b775b 100644 (file)
@@ -14,8 +14,8 @@
 extern "C" {
 #endif
 
-struct _Chksum;
-typedef struct _Chksum Chksum;
+struct s_Chksum;
+typedef struct s_Chksum Chksum;
 
 Chksum *solv_chksum_create(Id type);
 Chksum *solv_chksum_create_clone(Chksum *chk);
index ef9a528..1da28f6 100644 (file)
@@ -837,7 +837,7 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded)
                    if (MAPTST(&solv->multiversion, p))
                      break;
                  if (p)
-                   continue;   /* found a multiversion package that will not obsolate anything */
+                   continue;
                }
 
              om.size = 0;
index 3133686..0649258 100644 (file)
@@ -20,9 +20,9 @@
 extern "C" {
 #endif
 
-struct _Repo;
+struct s_Repo;
 
-typedef struct _KeyValue {
+typedef struct s_KeyValue {
   Id id;
   const char *str;
   unsigned int num;
@@ -31,7 +31,7 @@ typedef struct _KeyValue {
   int entry;   /* array entry, starts with 0 */
   int eof;     /* last entry reached */
 
-  struct _KeyValue *parent;
+  struct s_KeyValue *parent;
 } KeyValue;
 
 #define SOLV_KV_NUM64(kv) (((unsigned long long)((kv)->num2)) << 32 | (kv)->num)
@@ -52,7 +52,7 @@ typedef struct _KeyValue {
 #define SEARCH_SUB                     (1<<9)
 #define SEARCH_ARRAYSENTINEL           (1<<10)
 #define SEARCH_DISABLED_REPOS          (1<<11)
-#define SEARCH_COMPLETE_FILELIST       (1<<12)
+#define SEARCH_KEEP_TYPE_DELETED       (1<<12)         /* only has effect if no keyname is given */
 
 /* stringification flags */
 #define SEARCH_SKIP_KIND               (1<<16)
@@ -62,13 +62,17 @@ typedef struct _KeyValue {
 #define SEARCH_FILES                   (1<<17)
 #define SEARCH_CHECKSUMS               (1<<18)
 
-/* dataiterator internal */
+/* internal */
+#define SEARCH_SUBSCHEMA               (1<<30)
 #define SEARCH_THISSOLVID              (1<<31)
 
+/* obsolete */
+#define SEARCH_COMPLETE_FILELIST       0               /* ignored, this is the default */
+
 /*
  * Datamatcher: match a string against a query
  */
-typedef struct _Datamatcher {
+typedef struct s_Datamatcher {
   int flags;           /* see matcher flags above */
   const char *match;   /* the query string */
   void *matchdata;     /* e.g. compiled regexp */
@@ -96,14 +100,14 @@ int  datamatcher_checkbasename(Datamatcher *ma, const char *str);
  *      dosomething(di.solvid, di.key, di.kv);
  *    dataiterator_free(&di);
  */
-typedef struct _Dataiterator
+typedef struct s_Dataiterator
 {
   int state;
   int flags;
 
   Pool *pool;
-  struct _Repo *repo;
-  struct _Repodata *data;
+  struct s_Repo *repo;
+  struct s_Repodata *data;
 
   /* data pointers */
   unsigned char *dp;
@@ -112,7 +116,7 @@ typedef struct _Dataiterator
   Id *keyp;
 
   /* the result */
-  struct _Repokey *key;
+  struct s_Repokey *key;
   KeyValue kv;
 
   /* our matcher */
@@ -146,6 +150,8 @@ typedef struct _Dataiterator
   char *dupstr;
   int dupstrn;
 
+  Id *keyskip;
+  Id *oldkeyskip;
 } Dataiterator;
 
 
@@ -159,9 +165,9 @@ typedef struct _Dataiterator
  * keyname: if non-null, limit search to this keyname
  * match:   if non-null, limit search to this match
  */
-int  dataiterator_init(Dataiterator *di, Pool *pool, struct _Repo *repo, Id p, Id keyname, const char *match, int flags);
+int  dataiterator_init(Dataiterator *di, Pool *pool, struct s_Repo *repo, Id p, Id keyname, const char *match, int flags);
 void dataiterator_init_clone(Dataiterator *di, Dataiterator *from);
-void dataiterator_set_search(Dataiterator *di, struct _Repo *repo, Id p);
+void dataiterator_set_search(Dataiterator *di, struct s_Repo *repo, Id p);
 void dataiterator_set_keyname(Dataiterator *di, Id keyname);
 int  dataiterator_set_match(Dataiterator *di, const char *match, int flags);
 
@@ -175,7 +181,7 @@ void dataiterator_skip_attribute(Dataiterator *di);
 void dataiterator_skip_solvable(Dataiterator *di);
 void dataiterator_skip_repo(Dataiterator *di);
 void dataiterator_jump_to_solvid(Dataiterator *di, Id solvid);
-void dataiterator_jump_to_repo(Dataiterator *di, struct _Repo *repo);
+void dataiterator_jump_to_repo(Dataiterator *di, struct s_Repo *repo);
 void dataiterator_entersub(Dataiterator *di);
 void dataiterator_clonepos(Dataiterator *di, Dataiterator *from);
 void dataiterator_seek(Dataiterator *di, int whence);
index fe05cc6..ca92954 100644 (file)
@@ -15,7 +15,7 @@
 extern "C" {
 #endif
 
-typedef struct _Dirpool {
+typedef struct s_Dirpool {
   Id *dirs;
   int ndirs;
   Id *dirtraverse;
index b764b98..63c43bf 100644 (file)
@@ -308,7 +308,7 @@ pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
        {
          if (MAPTST(installedmap, sp))
            continue;
-         if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start))
+         if (ignoredu.size && MAPTST(&ignoredu, sp - oldinstalled->start))
            continue;
          repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd);
        }
@@ -318,12 +318,12 @@ pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps)
   solv_free(mptree);
 }
 
-int
+long long
 pool_calc_installsizechange(Pool *pool, Map *installedmap)
 {
   Id sp;
   Solvable *s;
-  int change = 0; 
+  long long change = 0; 
   Repo *oldinstalled = pool->installed;
 
   for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) 
diff --git a/src/filelistfilter.c b/src/filelistfilter.c
new file mode 100644 (file)
index 0000000..e698d6f
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2018, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * filelistfilter.c
+ *
+ * Support repodata with a filelist filtered by a custom filter
+ */
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <fnmatch.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "repo.h"
+#include "pool.h"
+#include "util.h"
+
+static Id default_filelist_filter;
+
+#define FF_EXACT       0
+#define FF_END         1
+#define FF_START       2
+#define FF_SUB         3               /* FF_END | FF_START */
+#define FF_GLOB                4
+#define FF_START5      5
+
+void
+repodata_free_filelistfilter(Repodata *data)
+{
+  if (data->filelistfilter)
+    {
+      if (data->filelistfilter != &default_filelist_filter)
+        solv_free(data->filelistfilter);
+      data->filelistfilter = 0;
+    }
+  data->filelistfilterdata = solv_free(data->filelistfilterdata);
+}
+
+static void
+repodata_set_filelistfilter(Repodata *data)
+{
+  Id type;
+  Queue q;
+  int i, j;
+  char *filterdata;
+  int nfilterdata;
+
+  if (data->filelistfilter && data->filelistfilter != &default_filelist_filter)
+    data->filelistfilter = solv_free(data->filelistfilter);
+  data->filelistfilterdata = solv_free(data->filelistfilterdata);
+  type = repodata_lookup_type(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST);
+  if (type != REPOKEY_TYPE_IDARRAY)
+    {
+      data->filelistfilter = &default_filelist_filter;
+      return;
+    }
+  queue_init(&q);
+  repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_FILTEREDFILELIST, &q);
+  if (q.count == 3)
+    {
+      /* check if this is the default filter */
+      int t = 0;
+      for (i = 0; i < 3; i++)
+       {
+         Id id = q.elements[i];
+         const char *g = data->localpool ? stringpool_id2str(&data->spool, id) : pool_id2str(data->repo->pool, id); 
+         if (!strcmp(g, "*bin/*"))
+           t |= 1;
+         else if (!strcmp(g, "/etc/*"))
+           t |= 2;
+         else if (!strcmp(g, "/usr/lib/sendmail"))
+           t |= 4;
+       }
+      if (t == 7)
+       {
+         queue_free(&q);
+         data->filelistfilter = &default_filelist_filter;
+         return;
+       }
+    }
+  data->filelistfilter = solv_calloc(q.count * 2 + 1, sizeof(Id));
+  filterdata = solv_calloc_block(1, 1, 255);
+  nfilterdata = 1;
+  
+  for (i = j = 0; i < q.count; i++)
+    {
+      Id id = q.elements[i];
+      const char *g = data->localpool ? stringpool_id2str(&data->spool, id) : pool_id2str(data->repo->pool, id); 
+      const char *p;
+      int t = FF_EXACT;
+      int gl;
+      if (!id || !g || !*g)
+       continue;
+      for (p = g; *p && t != FF_GLOB; p++)
+       {
+         if (*p == '*')
+           {
+             if (p == g)
+               t |= FF_END;
+             else if (!p[1])
+               t |= FF_START;
+             else
+               t = FF_GLOB;
+           }
+         else if (*p == '[' || *p == '?')
+           t = FF_GLOB;
+       }
+      gl = strlen(g);
+      if (t == FF_END) /* not supported */
+       t = FF_GLOB;
+      if (t == FF_START && gl == 5)
+       t = FF_START5;
+      filterdata = solv_extend(filterdata, nfilterdata, gl + 1, 1, 255);
+      data->filelistfilter[j++] = nfilterdata;
+      data->filelistfilter[j++] = t;
+      switch (t)
+       {
+       case FF_START:
+       case FF_START5:
+         strcpy(filterdata + nfilterdata, g);
+         filterdata[nfilterdata + gl - 1] = 0;
+         nfilterdata += gl;
+         break;
+       case FF_SUB:
+         strcpy(filterdata + nfilterdata, g + 1);
+         filterdata[nfilterdata + gl - 2] = 0;
+         nfilterdata += gl - 1;
+         break;
+       default:
+         strcpy(filterdata + nfilterdata, g);
+         nfilterdata += gl + 1;
+         break;
+       }
+    }
+  filterdata = solv_realloc(filterdata, nfilterdata);
+  data->filelistfilter[j++] = 0;
+  data->filelistfilterdata = filterdata;
+  queue_free(&q);
+}
+
+int
+repodata_filelistfilter_matches(Repodata *data, const char *str)
+{
+  Id *ff;
+  if (data && !data->filelistfilter)
+    repodata_set_filelistfilter(data);
+  if (!data || data->filelistfilter == &default_filelist_filter)
+    {
+      /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
+      if (strstr(str, "bin/"))
+       return 1;
+      if (!strncmp(str, "/etc/", 5))
+       return 1;
+      if (!strcmp(str, "/usr/lib/sendmail"))
+       return 1;
+      return 0;
+    }
+  for (ff = data->filelistfilter; *ff; ff += 2)
+    {
+      const char *g = data->filelistfilterdata + *ff;
+      switch (ff[1])
+       {
+       case FF_EXACT:
+         if (!strcmp(str, g))
+           return 1;
+         break;
+       case FF_START:
+         if (!strncmp(str, g, strlen(g)))
+           return 1;
+         break;
+       case FF_SUB:
+         if (!strstr(str, g))
+           return 1;
+         break;
+       case FF_START5:
+         if (!strncmp(str, g, 5))
+           return 1;
+         break;
+       default:
+         if (!fnmatch(g, str, 0))
+           return 1;
+         break;
+       }
+    }
+  return 0;
+}
+
index 11ff4f5..ec80831 100644 (file)
@@ -22,6 +22,7 @@
 #include "util.h"
 #include "bitmap.h"
 
+
 struct searchfiles {
   Id *ids;
   int nfiles;
@@ -101,188 +102,450 @@ struct addfileprovides_cbdata {
   Id *ids;
   char **dirs;
   char **names;
-
   Id *dids;
 
-  Map providedids;
+  Map *providedids;
+  int provstart;
+  int provend;
 
-  Map useddirs;
+  Map *todo;
+  int todo_start;
+  int todo_end;
 };
 
-static int
-addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value)
+/* split filelist dep into basename and dirname */
+static void
+create_dirs_names_array(struct addfileprovides_cbdata *cbd, Pool *pool)
 {
-  struct addfileprovides_cbdata *cbd = cbdata;
   int i;
+  cbd->dirs = solv_malloc2(cbd->nfiles, sizeof(char *));
+  cbd->names = solv_malloc2(cbd->nfiles, sizeof(char *));
+  for (i = 0; i < cbd->nfiles; i++)
+    {
+      char *s = solv_strdup(pool_id2str(pool, cbd->ids[i]));
+      cbd->dirs[i] = s;
+      s = strrchr(s, '/');
+      *s = 0;
+      cbd->names[i] = s + 1;
+    }
+}
 
-  if (!cbd->useddirs.size)
+static void
+free_dirs_names_array(struct addfileprovides_cbdata *cbd)
+{
+  int i;
+  if (cbd->dirs)
     {
-      map_init(&cbd->useddirs, data->dirpool.ndirs + 1);
-      if (!cbd->dirs)
-       {
-         cbd->dirs = solv_malloc2(cbd->nfiles, sizeof(char *));
-         cbd->names = solv_malloc2(cbd->nfiles, sizeof(char *));
-         for (i = 0; i < cbd->nfiles; i++)
-           {
-             char *s = solv_strdup(pool_id2str(data->repo->pool, cbd->ids[i]));
-             cbd->dirs[i] = s;
-             s = strrchr(s, '/');
-             *s = 0;
-             cbd->names[i] = s + 1;
-           }
-       }
       for (i = 0; i < cbd->nfiles; i++)
-       {
-         Id did;
-         if (MAPTST(&cbd->providedids, cbd->ids[i]))
-           {
-             cbd->dids[i] = 0;
-             continue;
-           }
-         did = repodata_str2dir(data, cbd->dirs[i], 0);
-         cbd->dids[i] = did;
-         if (did)
-           MAPSET(&cbd->useddirs, did);
-       }
-      repodata_free_dircache(data);
+       solv_free(cbd->dirs[i]);
+      cbd->dirs = solv_free(cbd->dirs);
+      cbd->names = solv_free(cbd->names);
     }
-  if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id))
+}
+
+static void
+prune_todo_range(Repo *repo, struct addfileprovides_cbdata *cbd)
+{
+  int start = cbd->todo_start, end = cbd->todo_end;
+  while (start < end && !MAPTST(cbd->todo, start - repo->start))
+    start++;
+  while (end > start && !MAPTST(cbd->todo, end - 1 - repo->start))
+    end--;
+  cbd->todo_start = start;
+  cbd->todo_end = end;
+}
+
+static int
+repodata_intersects_todo(Repodata *data, struct addfileprovides_cbdata *cbd)
+{
+  Repo *repo;
+  int p, start = data->start, end = data->end;
+  if (start >= cbd->todo_end || end <= cbd->todo_start)
     return 0;
-  for (i = 0; i < cbd->nfiles; i++)
-    if (cbd->dids[i] == value->id && !strcmp(cbd->names[i], value->str))
-      s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
+  repo = data->repo;
+  if (start < cbd->todo_start)
+    start = cbd->todo_start;
+  if (end > cbd->todo_end)
+    end = cbd->todo_end;
+  for (p = start; p < end; p++)
+    if (MAPTST(cbd->todo, p - repo->start))
+      return 1;
   return 0;
 }
 
+/* forward declaration */
+static void repodata_addfileprovides_search(Repodata *data, struct addfileprovides_cbdata *cbd);
+
+/* search a subset of the todo range */
 static void
-pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly)
+repodata_addfileprovides_search_limited(Repodata *data, struct addfileprovides_cbdata *cbd, int start, int end)
 {
-  Id p;
-  Repodata *data;
-  Repo *repo;
-  Queue fileprovidesq;
-  int i, j, repoid, repodataid;
-  int provstart, provend;
-  Map donemap;
-  int ndone, incomplete;
 
-  if (!pool->urepos)
+  int old_todo_start = cbd->todo_start;
+  int old_todo_end = cbd->todo_end;
+  if (start < cbd->todo_start)
+    start = cbd->todo_start;
+  if (end > cbd->todo_end)
+    end = cbd->todo_end;
+  if (start >= end)
     return;
+  cbd->todo_start = start;
+  cbd->todo_end = end;
+  repodata_addfileprovides_search(data, cbd);
+  cbd->todo_start = old_todo_start;
+  cbd->todo_end = old_todo_end;
+  prune_todo_range(data->repo, cbd);
+}
 
-  cbd->nfiles = sf->nfiles;
-  cbd->ids = sf->ids;
-  cbd->dirs = 0;
-  cbd->names = 0;
-  cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
-  map_init(&cbd->providedids, pool->ss.nstrings);
-
-  repoid = 1;
-  repo = repoonly ? repoonly : pool->repos[repoid];
-  map_init(&donemap, pool->nsolvables);
-  queue_init(&fileprovidesq);
-  provstart = provend = 0;
-  for (;;)
+static void
+repodata_addfileprovides_search(Repodata *data, struct addfileprovides_cbdata *cbd)
+{
+  Repo *repo = data->repo;
+  int i, p, start, end;
+  Map useddirs;
+  Map *providedids = 0;
+
+  /* make it available */
+  if (data->state == REPODATA_STUB)
+    repodata_load(data);
+  if (data->state != REPODATA_AVAILABLE)
+    return;
+  if (!data->incoredata || !data->dirpool.ndirs)
+    return;
+
+  start = cbd->todo_start > data->start ? cbd->todo_start : data->start;
+  end = cbd->todo_end > data->end ? data->end : cbd->todo_end;
+
+  if (start >= end)
+    return;
+
+  /* deal with provideids overlap */
+  if (cbd->providedids)
     {
-      if (!repo || repo->disabled)
+      if (start >= cbd->provstart && end <= cbd->provend)
+       providedids = cbd->providedids; /* complete overlap */
+      else if (start < cbd->provend && end > cbd->provstart)
        {
-         if (repoonly || ++repoid == pool->nrepos)
-           break;
-         repo = pool->repos[repoid];
+         /* partial overlap, need to split search */
+         if (start < cbd->provstart)
+           {
+             repodata_addfileprovides_search_limited(data, cbd, start, cbd->provstart);
+             start = cbd->provstart;
+           }
+         if (end > cbd->provend)
+           {
+             repodata_addfileprovides_search_limited(data, cbd, cbd->provend, end);
+             end = cbd->provend;
+           }
+         if (start < end)
+           repodata_addfileprovides_search_limited(data, cbd, start, end);
+         return;
+       }
+    }
+
+  /* set up dirs and names array if not already done */
+  if (!cbd->dirs)
+    create_dirs_names_array(cbd, repo->pool);
+
+  /* set up useddirs map and the cbd->dids array */
+  map_init(&useddirs, data->dirpool.ndirs);
+  for (i = 0; i < cbd->nfiles; i++)
+    {
+      Id did;
+      if (providedids && MAPTST(providedids, cbd->ids[i]))
+       {
+         cbd->dids[i] = 0;     /* already included, do not add again */
          continue;
        }
-      ndone = 0;
-      FOR_REPODATAS(repo, repodataid, data)
+      cbd->dids[i] = did = repodata_str2dir(data, cbd->dirs[i], 0);
+      if (did)
+       MAPSET(&useddirs, did);
+    }
+  repodata_free_dircache(data);                /* repodata_str2dir created it */
+
+  for (p = start; p < end; p++)
+    {
+      const unsigned char *dp;
+      Solvable *s;
+      if (!MAPTST(cbd->todo, p - repo->start))
+       continue;
+      dp = repodata_lookup_packed_dirstrarray(data, p, SOLVABLE_FILELIST);
+      if (!dp)
+       continue;
+      /* now iterate through the packed array */
+      s = repo->pool->solvables + p;
+      MAPCLR(cbd->todo, p - repo->start);      /* this entry is done */
+      for (;;)
        {
-         if (ndone >= repo->nsolvables)
+         Id did = 0;
+         int c;
+         while ((c = *dp++) & 0x80)
+           did = (did << 7) ^ c ^ 0x80;
+         did = (did << 6) | (c & 0x3f);
+         if ((unsigned int)did < (unsigned int)data->dirpool.ndirs && MAPTST(&useddirs, did))
+           {
+             /* there is at least one entry with that did */
+             for (i = 0; i < cbd->nfiles; i++)
+               if (cbd->dids[i] == did && !strcmp(cbd->names[i], (const char *)dp))
+                 s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER);
+           }
+         if (!(c & 0x40))
            break;
+         dp += strlen((const char *)dp) + 1;
+       }
+    }
+  map_free(&useddirs);
+  prune_todo_range(repo, cbd);
+}
+
+static void
+repo_addfileprovides_search_filtered(Repo *repo, struct addfileprovides_cbdata *cbd, int filteredid, Map *postpone)
+{
+  Repodata *data = repo->repodata + filteredid;
+  Map *providedids = cbd->providedids;
+  int rdid;
+  int start, end, p, i;
+  Map old_todo;
+  int old_todo_start, old_todo_end;
+
+  start = cbd->todo_start > data->start ? cbd->todo_start : data->start;
+  end = cbd->todo_end > data->end ? data->end : cbd->todo_end;
 
-         if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
+  if (providedids)
+    {
+      /* check if all solvables are in the provide range */
+      if (start < cbd->provstart || end > cbd->provend)
+       {
+         /* unclear, check each solvable */
+         for (p = start; p < end; p++)
            {
-             map_empty(&cbd->providedids);
-             for (i = 0; i < fileprovidesq.count; i++)
-               MAPSET(&cbd->providedids, fileprovidesq.elements[i]);
-             provstart = data->start;
-             provend = data->end;
-             for (i = 0; i < cbd->nfiles; i++)
-               if (!MAPTST(&cbd->providedids, cbd->ids[i]))
-                 break;
-             if (i == cbd->nfiles)
+             if (p >= cbd->provstart && p < cbd->provend)
+               continue;
+             if (data->incoreoffset[p - data->start] && MAPTST(cbd->todo, p - repo->start))
                {
-                 /* great! no need to search files */
-                 for (p = data->start; p < data->end; p++)
-                   if (pool->solvables[p].repo == repo)
-                     {
-                       if (MAPTST(&donemap, p))
-                         continue;
-                       MAPSET(&donemap, p);
-                       ndone++;
-                     }
-                 continue;
+                 providedids = 0;      /* nope, cannot prune with providedids */
+                 break;
                }
            }
+       }
+    }
 
-         if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
-           continue;
+  /* check if the filtered files are enough */
+  for (i = 0; i < cbd->nfiles; i++)
+    {
+      if (providedids && MAPTST(providedids, cbd->ids[i]))     /* this one is already provided */
+       continue;
+      if (!repodata_filelistfilter_matches(data, pool_id2str(repo->pool, cbd->ids[i])))
+        break;
+    }
+  if (i < cbd->nfiles)
+    {
+      /* nope, need to search the extensions as well. postpone. */
+      for (p = start; p < end; p++)
+       {
+         if (data->incoreoffset[p - data->start] && MAPTST(cbd->todo, p - repo->start))
+           {
+             if (!postpone->size)
+               map_grow(postpone, repo->nsolvables);
+             MAPSET(postpone, p - repo->start);
+             MAPCLR(cbd->todo, p - repo->start);
+           }
+       }
+      prune_todo_range(repo, cbd);
+      return;
+    }
+
+  /* now check if there is no data marked withour EXTENSION */
+  /* limit todo to the solvables in this repodata */
+  old_todo_start = cbd->todo_start;
+  old_todo_end = cbd->todo_end;
+  old_todo = *cbd->todo;
+  map_init(cbd->todo, repo->nsolvables);
+  for (p = start; p < end; p++)
+    if (data->incoreoffset[p - data->start] && MAPTST(&old_todo, p - repo->start))
+      {
+        MAPCLR(&old_todo, p - repo->start);
+        MAPSET(cbd->todo, p - repo->start);
+      }
+  prune_todo_range(repo, cbd);
 
-         if (data->start < provstart || data->end > provend)
+  /* do the check */
+  for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > filteredid ; rdid--, data--)
+    {
+      if (data->filelisttype == REPODATA_FILELIST_EXTENSION)
+       continue;
+      if (data->start >= cbd->todo_end || data->end <= cbd->todo_start)
+       continue;
+      if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
+       continue;
+      if (!repodata_intersects_todo(data, cbd))
+       continue;
+      /* oh no, this filelist data is not tagged with REPODATA_FILELIST_EXTENSION! */
+      /* postpone entries that have filelist data */
+      start = cbd->todo_start > data->start ? cbd->todo_start : data->start;
+      end = cbd->todo_end > data->end ? data->end : cbd->todo_end;
+      for (p = start; p < end; p++)
+       if (MAPTST(cbd->todo, p - repo->start))
+         if (repodata_lookup_type(data, p, SOLVABLE_FILELIST))
            {
-             map_empty(&cbd->providedids);
-             provstart = provend = 0;
+             if (!postpone->size)
+               map_grow(postpone, repo->nsolvables);
+             MAPSET(postpone, p - repo->start);
+             MAPCLR(cbd->todo, p - repo->start);
            }
+      prune_todo_range(repo, cbd);
+      if (cbd->todo_start >= cbd->todo_end)
+       break;
+    }
+
+  /* do the search over the filtered file list with the remaining entries*/
+  if (cbd->todo_start < cbd->todo_end)
+    repodata_addfileprovides_search(repo->repodata + filteredid, cbd);
+
+  /* restore todo map */
+  map_free(cbd->todo);
+  *cbd->todo = old_todo;
+  cbd->todo_start = old_todo_start;
+  cbd->todo_end = old_todo_end;
+  prune_todo_range(repo, cbd);
+}
+
+static void
+repo_addfileprovides_search(Repo *repo, struct addfileprovides_cbdata *cbd, struct searchfiles *sf)
+{
+  Repodata *data;
+  int rdid, p, i;
+  int provstart, provend;
+  Map todo;
+  Map providedids;
+
+  if (repo->end <= repo->start || !repo->nsolvables || !sf->nfiles)
+    return;
 
-         /* check if the data is incomplete */
-         incomplete = 0;
-         if (data->state == REPODATA_AVAILABLE)
+  /* update search data if changed */
+  if (cbd->nfiles != sf->nfiles || cbd->ids != sf->ids)
+    {
+      free_dirs_names_array(cbd);
+      cbd->nfiles = sf->nfiles;
+      cbd->ids = sf->ids;
+      cbd->dids = solv_realloc2(cbd->dids, sf->nfiles, sizeof(Id));
+    }
+
+  /* create todo map and range */
+  map_init(&todo, repo->end - repo->start);
+  for (p = repo->start; p < repo->end; p++)
+    if (repo->pool->solvables[p].repo == repo)
+      MAPSET(&todo, p - repo->start);
+  cbd->todo = &todo;
+  cbd->todo_start = repo->start;
+  cbd->todo_end = repo->end;
+  prune_todo_range(repo, cbd);
+
+  provstart = provend = 0;
+  map_init(&providedids, 0);
+  data = repo_lookup_repodata(repo, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES);
+  if (data)
+    {
+      Queue fileprovidesq;
+      queue_init(&fileprovidesq);
+      if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq))
+       {
+         map_grow(&providedids, repo->pool->ss.nstrings);
+         cbd->providedids = &providedids;
+         provstart = data->start;
+         provend = data->end;
+         for (i = 0; i < fileprovidesq.count; i++)
+           MAPSET(&providedids, fileprovidesq.elements[i]);
+         for (i = 0; i < cbd->nfiles; i++)
+           if (!MAPTST(&providedids, cbd->ids[i]))
+             break;
+         if (i == cbd->nfiles)
            {
-             for (j = 1; j < data->nkeys; j++)
-               if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-                 break;
-             if (j < data->nkeys)
+             /* all included, clear entries from todo list */
+             if (provstart <= cbd->todo_start && provend >= cbd->todo_end)
+               cbd->todo_end = cbd->todo_start;        /* clear complete range */
+             else
                {
-#if 0
-                 for (i = 0; i < cbd->nfiles; i++)
-                   if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i])))
-                     printf("need complete filelist because of %s\n", pool_id2str(pool, cbd->ids[i]));
-#endif
-                 for (i = 0; i < cbd->nfiles; i++)
-                   if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, pool_id2str(pool, cbd->ids[i])))
-                     break;
-                 if (i < cbd->nfiles)
-                   incomplete = 1;
+                 for (p = provstart; p < provend; p++)
+                   MAPCLR(&todo, p - repo->start);
+                 prune_todo_range(repo, cbd);
                }
            }
-
-         /* do the search */
-         map_init(&cbd->useddirs, 0);
-         for (p = data->start; p < data->end; p++)
-           if (pool->solvables[p].repo == repo)
-             {
-               if (MAPTST(&donemap, p))
-                 continue;
-               repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd);
-               if (!incomplete)
-                 {
-                   MAPSET(&donemap, p);
-                   ndone++;
-                 }
-             }
-         map_free(&cbd->useddirs);
        }
+      queue_free(&fileprovidesq);
+    }
 
-      if (repoonly || ++repoid == pool->nrepos)
-       break;
-      repo = pool->repos[repoid];
+  if (cbd->todo_start >= cbd->todo_end)
+    {
+      map_free(&todo);
+      cbd->todo = 0;
+      map_free(&providedids);
+      cbd->providedids = 0;
+      return;
     }
-  map_free(&donemap);
-  queue_free(&fileprovidesq);
-  map_free(&cbd->providedids);
-  if (cbd->dirs)
+
+  /* this is similar to repo_lookup_filelist_repodata in repo.c */
+
+  for (rdid = 1, data = repo->repodata + rdid; rdid < repo->nrepodata; rdid++, data++)
+    if (data->filelisttype == REPODATA_FILELIST_FILTERED)
+      break;
+  for (; rdid < repo->nrepodata; rdid++, data++)
+    if (data->filelisttype == REPODATA_FILELIST_EXTENSION)
+      break;
+
+  if (rdid < repo->nrepodata)
     {
-      for (i = 0; i < cbd->nfiles; i++)
-       solv_free(cbd->dirs[i]);
-      cbd->dirs = solv_free(cbd->dirs);
-      cbd->names = solv_free(cbd->names);
+      /* have at least one repodata with REPODATA_FILELIST_FILTERED followed by REPODATA_FILELIST_EXTENSION */
+      Map postpone;
+      map_init(&postpone, 0);
+      for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
+       {
+         if (data->filelisttype != REPODATA_FILELIST_FILTERED)
+           continue;
+         if (!repodata_intersects_todo(data, cbd))
+           continue;
+         if (data->state != REPODATA_AVAILABLE)
+           {
+             if (data->state != REPODATA_STUB)
+               continue;
+             repodata_load(data);
+             if (data->state != REPODATA_AVAILABLE || data->filelisttype != REPODATA_FILELIST_FILTERED)
+               continue;
+           }
+         repo_addfileprovides_search_filtered(repo, cbd, rdid, &postpone);
+       }
+      if (postpone.size)
+       {
+         /* add postponed entries back to todo */
+         map_or(&todo, &postpone);
+         cbd->todo_start = repo->start;
+         cbd->todo_end = repo->end;
+         prune_todo_range(repo, cbd);
+       }
+      map_free(&postpone);
+    }
+
+  /* search remaining entries in the standard way */
+  if (cbd->todo_start < cbd->todo_end)
+    {
+      for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
+       {
+         if (data->start >= cbd->todo_end || data->end <= cbd->todo_start)
+           continue;
+         if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
+           continue;
+         if (!repodata_intersects_todo(data, cbd))
+           continue;
+         repodata_addfileprovides_search(data, cbd);
+         if (cbd->todo_start >= cbd->todo_end)
+           break;
+       }
     }
+
+  map_free(&todo);
+  cbd->todo = 0;
+  map_free(&providedids);
+  cbd->providedids = 0;
 }
 
 void
@@ -297,6 +560,7 @@ pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst)
 
   installed = pool->installed;
   now = solv_timems(0);
+  memset(&cbd, 0, sizeof(cbd));
   memset(&sf, 0, sizeof(sf));
   map_init(&sf.seen, pool->ss.nstrings + pool->nrels);
   memset(&isf, 0, sizeof(isf));
@@ -328,23 +592,22 @@ pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst)
       if (s->enhances)
         pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp);
     }
+
   map_free(&sf.seen);
   map_free(&isf.seen);
   POOL_DEBUG(SOLV_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles);
-  cbd.dids = 0;
   if (sf.nfiles)
     {
 #if 0
       for (i = 0; i < sf.nfiles; i++)
        POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in filelist\n", pool_id2str(pool, sf.ids[i]));
 #endif
-      pool_addfileprovides_search(pool, &cbd, &sf, 0);
+      FOR_REPOS(i, repo)
+        repo_addfileprovides_search(repo, &cbd, &sf);
       if (idq)
-        for (i = 0; i < sf.nfiles; i++)
-         queue_push(idq, sf.ids[i]);
+       queue_insertn(idq, idq->count, sf.nfiles, sf.ids);
       if (idqinst)
-        for (i = 0; i < sf.nfiles; i++)
-         queue_push(idqinst, sf.ids[i]);
+       queue_insertn(idqinst, idqinst->count, sf.nfiles, sf.ids);
       solv_free(sf.ids);
     }
   if (isf.nfiles)
@@ -354,12 +617,13 @@ pool_addfileprovides_queue(Pool *pool, Queue *idq, Queue *idqinst)
        POOL_DEBUG(SOLV_DEBUG_STATS, "looking up %s in installed filelist\n", pool_id2str(pool, isf.ids[i]));
 #endif
       if (installed)
-        pool_addfileprovides_search(pool, &cbd, &isf, installed);
+        repo_addfileprovides_search(installed, &cbd, &isf);
       if (installed && idqinst)
         for (i = 0; i < isf.nfiles; i++)
          queue_pushunique(idqinst, isf.ids[i]);
       solv_free(isf.ids);
     }
+  free_dirs_names_array(&cbd);
   solv_free(cbd.dids);
   pool_freewhatprovides(pool); /* as we have added provides */
   POOL_DEBUG(SOLV_DEBUG_STATS, "addfileprovides took %d ms\n", solv_timems(now));
index 64cc6fc..8e53183 100644 (file)
@@ -76,18 +76,12 @@ KNOWNID(REPOSITORY_EXTERNAL,                "repository:external"),
 KNOWNID(REPOSITORY_KEYS,               "repository:keys"),
 KNOWNID(REPOSITORY_LOCATION,           "repository:location"),
 
-/* file provides already added to our solvables */
-KNOWNID(REPOSITORY_ADDEDFILEPROVIDES,  "repository:addedfileprovides"),
-/* inode of the rpm database for rpm --rebuilddb detection */
-KNOWNID(REPOSITORY_RPMDBCOOKIE,                "repository:rpmdbcookie"),
-
 /* the known data types */
 KNOWNID(REPOKEY_TYPE_VOID,             "repokey:type:void"),
 KNOWNID(REPOKEY_TYPE_CONSTANT,         "repokey:type:constant"),
 KNOWNID(REPOKEY_TYPE_CONSTANTID,       "repokey:type:constantid"),
 KNOWNID(REPOKEY_TYPE_ID,               "repokey:type:id"),
 KNOWNID(REPOKEY_TYPE_NUM,              "repokey:type:num"),
-KNOWNID(REPOKEY_TYPE_U32,              "repokey:type:num32"),
 KNOWNID(REPOKEY_TYPE_DIR,              "repokey:type:dir"),
 KNOWNID(REPOKEY_TYPE_STR,              "repokey:type:str"),
 KNOWNID(REPOKEY_TYPE_BINARY,           "repokey:type:binary"),
@@ -145,6 +139,8 @@ KNOWNID(SOLVABLE_CHANGELOG,         "solvable:changelog"),
 KNOWNID(SOLVABLE_CHANGELOG_AUTHOR,     "solvable:changelog:author"),
 KNOWNID(SOLVABLE_CHANGELOG_TIME,       "solvable:changelog:time"),
 KNOWNID(SOLVABLE_CHANGELOG_TEXT,       "solvable:changelog:text"),
+KNOWNID(SOLVABLE_INSTALLSTATUS,                "solvable:installstatus"),      /* debian install status */
+KNOWNID(SOLVABLE_PREREQ_IGNOREINST,    "solvable:prereq_ignoreinst"),  /* ignore these pre-requires for installed packages */
 
 /* stuff for solvables of type pattern */
 KNOWNID(SOLVABLE_CATEGORY,             "solvable:category"),
@@ -187,6 +183,7 @@ KNOWNID(PRODUCT_URL_TYPE,           "product:url:type"),
 KNOWNID(PRODUCT_FLAGS,                 "product:flags"),               /* e.g. 'update', 'no_you' */
 KNOWNID(PRODUCT_PRODUCTLINE,           "product:productline"),         /* installed product only */
 KNOWNID(PRODUCT_REGISTER_TARGET,       "product:regtarget"),           /* installed and available product */
+KNOWNID(PRODUCT_REGISTER_FLAVOR,       "product:regflavor"),           /* installed and available product */
 KNOWNID(PRODUCT_REGISTER_RELEASE,      "product:regrelease"),          /* installed product only */
 KNOWNID(PRODUCT_UPDATES_REPOID,                "product:updates:repoid"),
 KNOWNID(PRODUCT_UPDATES,               "product:updates"),
@@ -204,21 +201,18 @@ KNOWNID(SUSETAGS_SHARE_NAME,              "susetags:share:name"),
 KNOWNID(SUSETAGS_SHARE_EVR,            "susetags:share:evr"),
 KNOWNID(SUSETAGS_SHARE_ARCH,           "susetags:share:arch"),
 
-/* timestamp then the repository was generated */
-KNOWNID(REPOSITORY_TIMESTAMP,          "repository:timestamp"),
-/* hint when the metadata could be outdated w/respect to generated timestamp */
-KNOWNID(REPOSITORY_EXPIRE,             "repository:expire"),
-/* which things does this repo provides updates for, if it does (array) */
-KNOWNID(REPOSITORY_UPDATES,            "repository:updates"),          /* obsolete? */
-/* which products this repository is supposed to be for (array) */
-KNOWNID(REPOSITORY_DISTROS,            "repository:distros"),
+KNOWNID(REPOSITORY_ADDEDFILEPROVIDES,  "repository:addedfileprovides"),        /* file provides already added to our solvables */
+KNOWNID(REPOSITORY_RPMDBCOOKIE,                "repository:rpmdbcookie"),      /* inode of the rpm database for rpm --rebuilddb detection */
+KNOWNID(REPOSITORY_FILTEREDFILELIST,   "repository:filteredfilelist"), /* filelist in repository is filtered */
+KNOWNID(REPOSITORY_TIMESTAMP,          "repository:timestamp"),        /* timestamp then the repository was generated */
+KNOWNID(REPOSITORY_EXPIRE,             "repository:expire"),           /* hint when the metadata could be outdated w/respect to generated timestamp */
+KNOWNID(REPOSITORY_UPDATES,            "repository:updates"),          /* which things does this repo provides updates for, if it does (array) (obsolete?) */
+KNOWNID(REPOSITORY_DISTROS,            "repository:distros"),          /* which products this repository is supposed to be for (array) */
 KNOWNID(REPOSITORY_PRODUCT_LABEL,       "repository:product:label"),
 KNOWNID(REPOSITORY_PRODUCT_CPEID,      "repository:product:cpeid"),
 KNOWNID(REPOSITORY_REPOID,             "repository:repoid"),           /* obsolete? */
-/* keyword (tags) for this repository */
-KNOWNID(REPOSITORY_KEYWORDS,           "repository:keywords"),
-/* revision of the repository. arbitrary string */
-KNOWNID(REPOSITORY_REVISION,           "repository:revision"),
+KNOWNID(REPOSITORY_KEYWORDS,           "repository:keywords"),         /* keyword (tags) for this repository */
+KNOWNID(REPOSITORY_REVISION,           "repository:revision"),         /* revision of the repository. arbitrary string */
 KNOWNID(REPOSITORY_TOOLVERSION,                "repository:toolversion"),
 
 KNOWNID(DELTA_PACKAGE_NAME,            "delta:pkgname"),
@@ -256,12 +250,6 @@ KNOWNID(SIGNATURE_TIME,                    "signature:time"),
 KNOWNID(SIGNATURE_EXPIRES,             "signature:expires"),
 KNOWNID(SIGNATURE_DATA,                        "signature:data"),
 
-KNOWNID(PRODUCT_REGISTER_FLAVOR,       "product:regflavor"),           /* installed and available product */
-
-KNOWNID(SOLVABLE_INSTALLSTATUS,                "solvable:installstatus"),      /* debian install status */
-
-KNOWNID(SOLVABLE_PREREQ_IGNOREINST,    "solvable:prereq_ignoreinst"),  /* ignore these pre-requires for installed packages */
-
 KNOWNID(ID_NUM_INTERNAL,               0)
 
 #ifdef KNOWNID_INITIALIZE
index a3fa19a..f0e86ff 100644 (file)
@@ -120,6 +120,7 @@ SOLV_1.0 {
                pool_trivial_installable_multiversionmap;
                pool_vendor2mask;
                pool_whatmatchesdep;
+               pool_whatmatchessolvable;
                pool_whatcontainsdep;
                queue_alloc_one;
                queue_alloc_one_head;
@@ -145,6 +146,7 @@ SOLV_1.0 {
                repo_addid;
                repo_addid_dep;
                repo_create;
+               repo_create_keyskip;
                repo_disable_paging;
                repo_empty;
                repo_fix_conflicts;
@@ -165,7 +167,6 @@ SOLV_1.0 {
                repo_lookup_str;
                repo_lookup_type;
                repo_lookup_void;
-               repo_matchvalue;
                repo_reserve_ids;
                repo_rewrite_suse_deps;
                repo_search;
@@ -203,12 +204,10 @@ SOLV_1.0 {
                repodata_key2id;
                repodata_localize_id;
                repodata_lookup_bin_checksum;
-               repodata_lookup_bin_checksum_uninternalized;
                repodata_lookup_binary;
-               repodata_lookup_dirstrarray_uninternalized;
                repodata_lookup_id;
-               repodata_lookup_id_uninternalized;
                repodata_lookup_idarray;
+               repodata_lookup_kv_uninternalized;
                repodata_lookup_num;
                repodata_lookup_str;
                repodata_lookup_type;
@@ -219,12 +218,16 @@ SOLV_1.0 {
                repodata_new_handle;
                repodata_schema2id;
                repodata_search;
+               repodata_search_arrayelement;
+               repodata_search_keyskip;
+               repodata_search_uninternalized;
                repodata_set_binary;
                repodata_set_bin_checksum;
                repodata_set_checksum;
                repodata_set_constant;
                repodata_set_constantid;
                repodata_set_deltalocation;
+               repodata_set_filelisttype;
                repodata_set_id;
                repodata_set_idarray;
                repodata_set_location;
@@ -238,17 +241,28 @@ SOLV_1.0 {
                repodata_str2dir;
                repodata_stringify;
                repodata_swap_attrs;
+               repodata_translate_dir_slow;
                repodata_translate_id;
                repodata_unset;
                repodata_unset_uninternalized;
                repodata_write;
                repodata_write_filtered;
                repopagestore_compress_page;
+               repowriter_create;
+               repowriter_free;
+               repowriter_set_flags;
+               repowriter_set_keyfilter;
+               repowriter_set_keyqueue;
+               repowriter_set_repodatarange;
+               repowriter_set_solvablerange;
+               repowriter_write;
                selection_add;
                selection_filter;
                selection_make;
                selection_make_matchdepid;
                selection_make_matchdeps;
+               selection_make_matchsolvable;
+               selection_make_matchsolvablelist;
                selection_solvables;
                solv_bin2hex;
                solv_calloc;
index c92c332..c0cc07f 100644 (file)
 #include "repo.h"
 #include "util.h"
 
-struct _TransactionElement {
+struct s_TransactionElement {
   Id p;                /* solvable id */
   Id edges;    /* pointer into edges data */
   Id mark;
 };
 
-struct _TransactionOrderdata {
-  struct _TransactionElement *tes;
+struct s_TransactionOrderdata {
+  struct s_TransactionElement *tes;
   int ntes;
   Id *invedgedata;
   int ninvedgedata;
@@ -57,7 +57,7 @@ struct _TransactionOrderdata {
 void
 transaction_clone_orderdata(Transaction *trans, Transaction *srctrans)
 {
-  struct _TransactionOrderdata *od = srctrans->orderdata;
+  struct s_TransactionOrderdata *od = srctrans->orderdata;
   if (!od)
     return;
   trans->orderdata = solv_calloc(1, sizeof(*trans->orderdata));
@@ -77,7 +77,7 @@ transaction_free_orderdata(Transaction *trans)
 {
   if (trans->orderdata)
     {
-      struct _TransactionOrderdata *od = trans->orderdata;
+      struct s_TransactionOrderdata *od = trans->orderdata;
       od->tes = solv_free(od->tes);
       od->invedgedata = solv_free(od->invedgedata);
       if (od->cycles)
@@ -91,7 +91,7 @@ transaction_free_orderdata(Transaction *trans)
 
 struct orderdata {
   Transaction *trans;
-  struct _TransactionElement *tes;
+  struct s_TransactionElement *tes;
   int ntes;
   Id *edgedata;
   int nedgedata;
@@ -106,7 +106,7 @@ static int
 addteedge(struct orderdata *od, int from, int to, int type)
 {
   int i;
-  struct _TransactionElement *te;
+  struct s_TransactionElement *te;
 
   if (from == to)
     return 0;
@@ -154,7 +154,7 @@ addedge(struct orderdata *od, Id from, Id to, int type)
   Transaction *trans = od->trans;
   Pool *pool = trans->pool;
   Solvable *s;
-  struct _TransactionElement *te;
+  struct s_TransactionElement *te;
   int i;
 
   /* printf("addedge %d %d type %d\n", from, to, type); */
@@ -531,7 +531,7 @@ breakcycle(struct orderdata *od, Id *cycle)
   Pool *pool = od->trans->pool;
   Id ddegmin, ddegmax, ddeg;
   int k, l;
-  struct _TransactionElement *te;
+  struct s_TransactionElement *te;
 
   l = 0;
   ddegmin = ddegmax = 0;
@@ -604,7 +604,7 @@ dump_tes(struct orderdata *od)
   Pool *pool = od->trans->pool;
   int i, j;
   Queue obsq;
-  struct _TransactionElement *te, *te2;
+  struct s_TransactionElement *te, *te2;
 
   queue_init(&obsq);
   for (i = 1, te = od->tes + i; i < od->ntes; i++, te++)
@@ -632,7 +632,7 @@ dump_tes(struct orderdata *od)
 static void
 reachable(struct orderdata *od, Id i)
 {
-  struct _TransactionElement *te = od->tes + i;
+  struct s_TransactionElement *te = od->tes + i;
   int j, k;
 
   if (te->mark != 0)
@@ -660,7 +660,7 @@ addcycleedges(struct orderdata *od, Id *cycle, Queue *todo)
   Transaction *trans = od->trans;
   Pool *pool = trans->pool;
 #endif
-  struct _TransactionElement *te;
+  struct s_TransactionElement *te;
   int i, j, k, tail;
   int head;
 
@@ -780,7 +780,7 @@ transaction_order(Transaction *trans, int flags)
   Solvable *s;
   int i, j, k, numte, numedge;
   struct orderdata od;
-  struct _TransactionElement *te;
+  struct s_TransactionElement *te;
   Queue todo, obsq, samerepoq, uninstq;
   int cycstart, cycel;
   Id *cycle;
@@ -795,7 +795,7 @@ transaction_order(Transaction *trans, int flags)
   /* free old data if present */
   if (trans->orderdata)
     {
-      struct _TransactionOrderdata *od = trans->orderdata;
+      struct s_TransactionOrderdata *od = trans->orderdata;
       od->tes = solv_free(od->tes);
       od->invedgedata = solv_free(od->invedgedata);
       trans->orderdata = solv_free(trans->orderdata);
@@ -1069,7 +1069,7 @@ printf("do %s [%d]\n", pool_solvid2str(pool, te->p), temedianr[i]);
       s = pool->solvables + te->p;
       for (j = te->edges; od.invedgedata[j]; j++)
        {
-         struct _TransactionElement *te2 = od.tes + od.invedgedata[j];
+         struct s_TransactionElement *te2 = od.tes + od.invedgedata[j];
          assert(te2->mark > 0);
          if (--te2->mark == 0)
            {
@@ -1103,7 +1103,7 @@ printf("free %s [%d]\n", pool_solvid2str(pool, te2->p), temedianr[od.invedgedata
 
   if ((flags & (SOLVER_TRANSACTION_KEEP_ORDERDATA | SOLVER_TRANSACTION_KEEP_ORDERCYCLES)) != 0)
     {
-      struct _TransactionOrderdata *tod;
+      struct s_TransactionOrderdata *tod;
       trans->orderdata = tod = solv_calloc(1, sizeof(*trans->orderdata));
       if ((flags & SOLVER_TRANSACTION_KEEP_ORDERCYCLES) != 0)
        {
@@ -1137,8 +1137,8 @@ int
 transaction_order_add_choices(Transaction *trans, Id chosen, Queue *choices)
 {
   int i, j;
-  struct _TransactionOrderdata *od = trans->orderdata;
-  struct _TransactionElement *te;
+  struct s_TransactionOrderdata *od = trans->orderdata;
+  struct s_TransactionElement *te;
 
   if (!od)
      return choices->count;
@@ -1349,7 +1349,7 @@ transaction_check_order(Transaction *trans)
 void
 transaction_order_get_cycleids(Transaction *trans, Queue *q, int minseverity)
 {
-  struct _TransactionOrderdata *od = trans->orderdata;
+  struct s_TransactionOrderdata *od = trans->orderdata;
   Queue *cq;
   int i, cid, ncycles;
 
@@ -1377,7 +1377,7 @@ transaction_order_get_cycleids(Transaction *trans, Queue *q, int minseverity)
 int
 transaction_order_get_cycle(Transaction *trans, Id cid, Queue *q)
 {
-  struct _TransactionOrderdata *od = trans->orderdata;
+  struct s_TransactionOrderdata *od = trans->orderdata;
   Queue *cq;
   int cmin, cmax, severity;
   int ncycles;
index e1682f2..191327a 100644 (file)
@@ -866,8 +866,6 @@ move_installed_to_front(Pool *pool, Queue *plist)
   Solvable *s;
   Id p, pp;
 
-  if (!pool->installed)
-    return;
   for (i = j = 0; i < plist->count; i++)
     {
       s = pool->solvables + plist->elements[i];
@@ -926,9 +924,9 @@ prune_to_best_version(Pool *pool, Queue *plist)
     {
       s = pool->solvables + plist->elements[i];
 
-      POOL_DEBUG(SOLV_DEBUG_POLICY, "- %s [%d]%s\n",
-                pool_solvable2str(pool, s), plist->elements[i], 
-                (pool->installed && s->repo == pool->installed) ? "I" : "");
+      POOL_DEBUG(SOLV_DEBUG_POLICY, "- %s[%s]\n",
+                pool_solvable2str(pool, s),
+                (pool->installed && s->repo == pool->installed) ? "installed" : "not installed");
 
       if (!best)               /* if no best yet, the current is best */
         {
@@ -963,6 +961,8 @@ prune_to_best_version(Pool *pool, Queue *plist)
       else
         prune_obsoleted(pool, plist);
     }
+  if (plist->count > 1 && pool->installed)
+    move_installed_to_front(pool, plist);
 }
 
 
@@ -1343,7 +1343,6 @@ policy_filter_unwanted(Solver *solv, Queue *plist, int mode)
 #endif
          dislike_old_versions(pool, plist);
          sort_by_common_dep(pool, plist);
-         move_installed_to_front(pool, plist);
          if (solv->urpmreorder)
            urpm_reorder(solv, plist);
          prefer_suggested(solv, plist);
@@ -1365,7 +1364,6 @@ pool_best_solvables(Pool *pool, Queue *plist, int flags)
     {
       dislike_old_versions(pool, plist);
       sort_by_common_dep(pool, plist);
-      move_installed_to_front(pool, plist);
     }
 }
 
index 279359a..383edb2 100644 (file)
@@ -927,7 +927,7 @@ pool_addstdproviders(Pool *pool, Id d)
       return 1;
     }
   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
-  dataiterator_init(&di, pool, 0, 0, SOLVABLE_FILELIST, str, SEARCH_STRING|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
+  dataiterator_init(&di, pool, 0, 0, SOLVABLE_FILELIST, str, SEARCH_STRING|SEARCH_FILES);
   for (; dataiterator_step(&di); dataiterator_skip_solvable(&di))
     {
       Solvable *s = pool->solvables + di.solvid;
@@ -1485,6 +1485,37 @@ pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker)
   queue_free(&qq);
 }
 
+/* intersect dependencies in keyname with all provides of solvable solvid,
+ * return list of matching packages */
+/* this currently only works for installable packages */
+void
+pool_whatmatchessolvable(Pool *pool, Id keyname, Id solvid, Queue *q, int marker)
+{
+  Id p;
+  Queue qq;
+  Map missc;           /* cache for misses */
+  int reloff;
+
+  queue_empty(q);
+  queue_init(&qq);
+  reloff = pool->ss.nstrings;
+  map_init(&missc, reloff + pool->nrels);
+  FOR_POOL_SOLVABLES(p)
+    {
+      Solvable *s = pool->solvables + p;
+      if (p == solvid)
+       continue;       /* filter out self-matches */
+      if (s->repo->disabled)
+       continue;
+      if (s->repo != pool->installed && !pool_installable(pool, s))
+       continue;
+      if (solvable_matchessolvable_int(s, keyname, marker, solvid, 0, &qq, &missc, reloff))
+        queue_push(q, p);
+    }
+  map_free(&missc);
+  queue_free(&qq);
+}
+
 /*************************************************************************/
 
 void
@@ -1505,7 +1536,6 @@ pool_debug(Pool *pool, int type, const char *format, ...)
         vprintf(format, args);
       else
         vfprintf(stderr, format, args);
-      va_end(args);
       return;
     }
   vsnprintf(buf, sizeof(buf), format, args);
@@ -1567,12 +1597,12 @@ pool_setdebuglevel(Pool *pool, int level)
   if (level > 2)
     mask |= SOLV_DEBUG_PROPAGATE;
   if (level > 3)
-    mask |= SOLV_DEBUG_RULE_CREATION | SOLV_DEBUG_WATCHES;
+    mask |= SOLV_DEBUG_RULE_CREATION;
   mask |= pool->debugmask & SOLV_DEBUG_TO_STDERR;      /* keep bit */
   pool->debugmask = mask;
 }
 
-void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct _Pool *, void *data, int type, const char *str), void *debugcallbackdata)
+void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct s_Pool *, void *data, int type, const char *str), void *debugcallbackdata)
 {
   pool->debugcallback = debugcallback;
   pool->debugcallbackdata = debugcallbackdata;
@@ -1583,20 +1613,20 @@ void pool_setdebugmask(Pool *pool, int mask)
   pool->debugmask = mask;
 }
 
-void pool_setloadcallback(Pool *pool, int (*cb)(struct _Pool *, struct _Repodata *, void *), void *loadcbdata)
+void pool_setloadcallback(Pool *pool, int (*cb)(struct s_Pool *, struct s_Repodata *, void *), void *loadcbdata)
 {
   pool->loadcallback = cb;
   pool->loadcallbackdata = loadcbdata;
 }
 
-void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct _Pool *, void *, Id, Id), void *nscbdata)
+void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct s_Pool *, void *, Id, Id), void *nscbdata)
 {
   pool->nscallback = cb;
   pool->nscallbackdata = nscbdata;
 }
 
 void
-pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct _Repodata *data, struct _Repokey *key, struct _KeyValue *kv), void *cbdata)
+pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct s_Repodata *data, struct s_Repokey *key, struct s_KeyValue *kv), void *cbdata)
 {
   if (p)
     {
index 40e3777..37583a1 100644 (file)
@@ -36,13 +36,13 @@ extern "C" {
 
 /*----------------------------------------------- */
 
-struct _Repo;
-struct _Repodata;
-struct _Repokey;
-struct _KeyValue;
+struct s_Repo;
+struct s_Repodata;
+struct s_Repokey;
+struct s_KeyValue;
 
-typedef struct _Datapos {
-  struct _Repo *repo;
+typedef struct s_Datapos {
+  struct s_Repo *repo;
   Id solvid;
   Id repodataid;
   Id schema;
@@ -55,7 +55,7 @@ typedef struct _Datapos {
 /* how many strings to maintain (round robin) */
 #define POOL_TMPSPACEBUF 16
 
-struct _Pool_tmpspace {
+struct s_Pool_tmpspace {
   char *buf[POOL_TMPSPACEBUF];
   int   len[POOL_TMPSPACEBUF];
   int   n;
@@ -63,19 +63,19 @@ struct _Pool_tmpspace {
 
 #endif
 
-struct _Pool {
+struct s_Pool {
   void *appdata;               /* application private pointer */
 
-  struct _Stringpool ss;
+  struct s_Stringpool ss;
 
   Reldep *rels;                        /* table of rels: Id -> Reldep */
   int nrels;                   /* number of unique rels */
 
-  struct _Repo **repos;
+  struct s_Repo **repos;
   int nrepos;                  /* repos allocated */
   int urepos;                  /* repos in use */
 
-  struct _Repo *installed;     /* packages considered installed */
+  struct s_Repo *installed;    /* packages considered installed */
 
   Solvable *solvables;
   int nsolvables;              /* solvables allocated */
@@ -109,16 +109,16 @@ struct _Pool {
   Map *considered;
 
   /* callback for REL_NAMESPACE dependencies handled by the application  */
-  Id (*nscallback)(struct _Pool *, void *data, Id name, Id evr);
+  Id (*nscallback)(struct s_Pool *, void *data, Id name, Id evr);
   void *nscallbackdata;
 
   /* debug mask and callback */
   int  debugmask;
-  void (*debugcallback)(struct _Pool *, void *data, int type, const char *str);
+  void (*debugcallback)(struct s_Pool *, void *data, int type, const char *str);
   void *debugcallbackdata;
 
   /* load callback */
-  int (*loadcallback)(struct _Pool *, struct _Repodata *, void *);
+  int (*loadcallback)(struct s_Pool *, struct s_Repodata *, void *);
   void *loadcallbackdata;
 
   /* search position */
@@ -148,14 +148,14 @@ struct _Pool {
   int languagecacheother;
 
   /* our tmp space string space */
-  struct _Pool_tmpspace tmpspace;
+  struct s_Pool_tmpspace tmpspace;
 
   char *errstr;                        /* last error string */
   int errstra;                 /* allocated space for errstr */
 
   char *rootdir;
 
-  int (*custom_vendorcheck)(struct _Pool *, Solvable *, Solvable *);
+  int (*custom_vendorcheck)(struct s_Pool *, Solvable *, Solvable *);
 
   int addfileprovidesfiltered; /* 1: only use filtered file list for addfileprovides */
   int addedfileprovides;       /* true: application called addfileprovides */
@@ -188,7 +188,6 @@ struct _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)
 
@@ -247,13 +246,13 @@ extern int  pool_set_flag(Pool *pool, int flag, int value);
 extern int  pool_get_flag(Pool *pool, int flag);
 
 extern void pool_debug(Pool *pool, int type, const char *format, ...) __attribute__((format(printf, 3, 4)));
-extern void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct _Pool *, void *data, int type, const char *str), void *debugcallbackdata);
+extern void pool_setdebugcallback(Pool *pool, void (*debugcallback)(struct s_Pool *, void *data, int type, const char *str), void *debugcallbackdata);
 extern void pool_setdebugmask(Pool *pool, int mask);
-extern void pool_setloadcallback(Pool *pool, int (*cb)(struct _Pool *, struct _Repodata *, void *), void *loadcbdata);
-extern void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct _Pool *, void *, Id, Id), void *nscbdata);
+extern void pool_setloadcallback(Pool *pool, int (*cb)(struct s_Pool *, struct s_Repodata *, void *), void *loadcbdata);
+extern void pool_setnamespacecallback(Pool *pool, Id (*cb)(struct s_Pool *, void *, Id, Id), void *nscbdata);
 extern void pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr);
 
-extern void pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(struct _Pool *, Solvable *, Solvable *));
+extern void pool_set_custom_vendorcheck(Pool *pool, int (*vendorcheck)(struct s_Pool *, Solvable *, Solvable *));
 
 
 extern char *pool_alloctmpspace(Pool *pool, int len);
@@ -262,7 +261,7 @@ extern char *pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const
 extern char *pool_tmpappend(Pool *pool, const char *str1, const char *str2, const char *str3);
 extern const char *pool_bin2hex(Pool *pool, const unsigned char *buf, int len);
 
-extern void pool_set_installed(Pool *pool, struct _Repo *repo);
+extern void pool_set_installed(Pool *pool, struct s_Repo *repo);
 
 extern int  pool_error(Pool *pool, int ret, const char *format, ...) __attribute__((format(printf, 3, 4)));
 extern char *pool_errstr(Pool *pool);
@@ -349,6 +348,7 @@ static inline Id *pool_whatprovides_ptr(Pool *pool, Id d)
 
 void pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker);
 void pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker);
+void pool_whatmatchessolvable(Pool *pool, Id keyname, Id solvid, Queue *q, int marker);
 void pool_set_whatprovides(Pool *pool, Id id, Id providers);
 
 
@@ -357,7 +357,7 @@ void pool_set_whatprovides(Pool *pool, Id id, Id providers);
  *   key   - search only this key
  *   match - key must match this string
  */
-void pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct _Repodata *data, struct _Repokey *key, struct _KeyValue *kv), void *cbdata);
+void pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct s_Repodata *data, struct s_Repokey *key, struct s_KeyValue *kv), void *cbdata);
 
 void pool_clear_pos(Pool *pool);
 
@@ -374,17 +374,17 @@ const char *pool_lookup_deltalocation(Pool *pool, Id entry, unsigned int *median
 
 #define DUCHANGES_ONLYADD      1
 
-typedef struct _DUChanges {
+typedef struct s_DUChanges {
   const char *path;
-  int kbytes;
-  int files;
+  long long kbytes;
+  long long files;
   int flags;
 } DUChanges;
 
 
 void pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap);
 void pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps);
-int  pool_calc_installsizechange(Pool *pool, Map *installedmap);
+long long pool_calc_installsizechange(Pool *pool, Map *installedmap);
 
 void pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts);
 
index 4a1fa50..6727760 100644 (file)
@@ -33,6 +33,10 @@ static const char *archpolicies[] = {
   "ppc64",     "ppc64:ppc",
   "ppc64p7",   "ppc64p7:ppc64:ppc",
   "ia64",      "ia64:i686:i586:i486:i386",
+  "armv8hcnl", "armv8hcnl:armv8hnl:armv8hl:armv7hnl:armv7hl:armv6hl",
+  "armv8hnl",  "armv8hnl:armv8hl:armv7hnl:armv7hl:armv6hl",
+  "armv8hl",   "armv8hl:armv7hl:armv6hl",
+  "armv8l",    "armv8l:armv7l:armv6l:armv5tejl:armv5tel:armv5tl:armv5l:armv4tl:armv4l:armv3l",
   "armv7hnl",  "armv7hnl:armv7hl:armv6hl",
   "armv7hl",   "armv7hl:armv6hl",
   "armv7l",    "armv7l:armv6l:armv5tejl:armv5tel:armv5tl:armv5l:armv4tl:armv4l:armv3l",
index 79a3ccd..f832ff4 100644 (file)
@@ -24,7 +24,7 @@ extern "C" {
  * Ids with relation
  */
 
-typedef struct _Reldep {
+typedef struct s_Reldep {
   Id name;             /* "package" */
   Id evr;              /* "0:42-3" */
   int flags;           /* operation/relation, see REL_x in pool.h */
index 64a3b87..e1f77b0 100644 (file)
 #define SOLV_FLAG_PREFIX_POOL 4
 #define SOLV_FLAG_SIZE_BYTES  8
 
-struct _Stringpool;
-typedef struct _Stringpool Stringpool;
+struct s_Stringpool;
+typedef struct s_Stringpool Stringpool;
 
-struct _Pool;
-typedef struct _Pool Pool;
+struct s_Pool;
+typedef struct s_Pool Pool;
 
 /* identifier for string values */
 typedef int Id;                /* must be signed!, since negative Id is used in solver rules to denote negation */
index 2b5cefd..df751c4 100644 (file)
@@ -247,23 +247,8 @@ solver_autouninstall(Solver *solv, int start)
       if (v >= solv->updaterules && v < solv->updaterules_end)
        {
          Rule *r;
-         Id p = solv->installed->start + (v - solv->updaterules);
          if (m && !MAPTST(m, v - solv->updaterules))
            continue;
-         if (pool->considered && !MAPTST(pool->considered, p))
-           continue;   /* do not uninstalled disabled packages */
-         if (solv->bestrules_pkg && solv->bestrules_end > solv->bestrules)
-           {
-             int j;
-             for (j = start + 1; j < solv->problems.count - 1; j++)
-               {
-                 Id vv = solv->problems.elements[j];
-                 if (vv >= solv->bestrules && vv < solv->bestrules_end && solv->bestrules_pkg[vv - solv->bestrules] == p)
-                   break;
-               }
-             if (j < solv->problems.count - 1)
-               continue;       /* best rule involved, do not uninstall */
-           }
          /* check if identical to feature rule, we don't like that (except for orphans) */
          r = solv->rules + solv->featurerules + (v - solv->updaterules);
          if (!r->p)
@@ -275,7 +260,7 @@ solver_autouninstall(Solver *solv, int start)
              if (solv->keep_orphans)
                {
                  r = solv->rules + v;
-                 if (!r->d && !r->w2 && r->p == p)
+                 if (!r->d && !r->w2 && r->p == (solv->installed->start + (v - solv->updaterules)))
                    {
                      lastfeature = v;
                      lastupdate = 0;
index 63319d6..37021e1 100644 (file)
@@ -20,7 +20,7 @@ extern "C" {
 #endif
 
 
-struct _Solver;
+struct s_Solver;
 
 #define SOLVER_SOLUTION_JOB             (0)
 #define SOLVER_SOLUTION_DISTUPGRADE     (-1)
@@ -28,31 +28,31 @@ struct _Solver;
 #define SOLVER_SOLUTION_BEST            (-3)
 #define SOLVER_SOLUTION_POOLJOB         (-4)
 
-void solver_recordproblem(struct _Solver *solv, Id rid);
-void solver_fixproblem(struct _Solver *solv, Id rid);
-Id solver_autouninstall(struct _Solver *solv, int start);
-void solver_disableproblemset(struct _Solver *solv, int start);
+void solver_recordproblem(struct s_Solver *solv, Id rid);
+void solver_fixproblem(struct s_Solver *solv, Id rid);
+Id solver_autouninstall(struct s_Solver *solv, int start);
+void solver_disableproblemset(struct s_Solver *solv, int start);
 
-int solver_prepare_solutions(struct _Solver *solv);
+int solver_prepare_solutions(struct s_Solver *solv);
 
-unsigned int solver_problem_count(struct _Solver *solv);
-Id solver_next_problem(struct _Solver *solv, Id problem);
-unsigned int solver_solution_count(struct _Solver *solv, Id problem);
-Id solver_next_solution(struct _Solver *solv, Id problem, Id solution);
-unsigned int solver_solutionelement_count(struct _Solver *solv, Id problem, Id solution);
-Id solver_solutionelement_internalid(struct _Solver *solv, Id problem, Id solution);
-Id solver_solutionelement_extrajobflags(struct _Solver *solv, Id problem, Id solution);
-Id solver_next_solutionelement(struct _Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp);
+unsigned int solver_problem_count(struct s_Solver *solv);
+Id solver_next_problem(struct s_Solver *solv, Id problem);
+unsigned int solver_solution_count(struct s_Solver *solv, Id problem);
+Id solver_next_solution(struct s_Solver *solv, Id problem, Id solution);
+unsigned int solver_solutionelement_count(struct s_Solver *solv, Id problem, Id solution);
+Id solver_solutionelement_internalid(struct s_Solver *solv, Id problem, Id solution);
+Id solver_solutionelement_extrajobflags(struct s_Solver *solv, Id problem, Id solution);
+Id solver_next_solutionelement(struct s_Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp);
 
-void solver_take_solutionelement(struct _Solver *solv, Id p, Id rp, Id extrajobflags, Queue *job);
-void solver_take_solution(struct _Solver *solv, Id problem, Id solution, Queue *job);
+void solver_take_solutionelement(struct s_Solver *solv, Id p, Id rp, Id extrajobflags, Queue *job);
+void solver_take_solution(struct s_Solver *solv, Id problem, Id solution, Queue *job);
 
-Id solver_findproblemrule(struct _Solver *solv, Id problem);
-void solver_findallproblemrules(struct _Solver *solv, Id problem, Queue *rules);
+Id solver_findproblemrule(struct s_Solver *solv, Id problem);
+void solver_findallproblemrules(struct s_Solver *solv, Id problem, Queue *rules);
 
-extern const char *solver_problemruleinfo2str(struct _Solver *solv, SolverRuleinfo type, Id source, Id target, Id dep);
-extern const char *solver_problem2str(struct _Solver *solv, Id problem);
-extern const char *solver_solutionelement2str(struct _Solver *solv, Id p, Id rp);
+extern const char *solver_problemruleinfo2str(struct s_Solver *solv, SolverRuleinfo type, Id source, Id target, Id dep);
+extern const char *solver_problem2str(struct s_Solver *solv, Id problem);
+extern const char *solver_solutionelement2str(struct s_Solver *solv, Id p, Id rp);
 
 #ifdef __cplusplus
 }
index 7e56035..8b1ef08 100644 (file)
@@ -19,7 +19,7 @@
 extern "C" {
 #endif
 
-typedef struct _Queue {
+typedef struct s_Queue {
   Id *elements;                /* pointer to elements */
   int count;           /* current number of elements in queue */
   Id *alloc;           /* this is whats actually allocated, elements > alloc if shifted */
index 9e59fe2..d163f13 100644 (file)
@@ -672,11 +672,12 @@ struct matchdata
   int flags;
   Datamatcher matcher;
   int stop;
+  Id *keyskip;
   int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv);
   void *callback_data;
 };
 
-int
+static int
 repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
 {
   struct matchdata *md = cbdata;
@@ -692,6 +693,12 @@ repo_matchvalue(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValu
       if (!datamatcher_match(&md->matcher, str))
        return 0;
     }
+  else
+    {
+      /* stringify filelist if requested */
+      if (key->name == SOLVABLE_FILELIST && key->type == REPOKEY_TYPE_DIRSTRARRAY && (md->matcher.flags & SEARCH_FILES) != 0)
+        repodata_stringify(md->pool, data, key, kv, md->flags);
+    }
   md->stop = md->callback(md->callback_data, s, data, key, kv);
   return md->stop;
 }
@@ -736,8 +743,9 @@ repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
   KeyValue kv;
   Pool *pool = repo->pool;
   Repodata *data;
-  int i, j, flags;
+  int i, flags;
   Solvable *s;
+  Id *keyskip;
 
   kv.parent = 0;
   md->stop = 0;
@@ -752,12 +760,10 @@ repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
        }
       return;
     }
-  else if (p < 0)
-    /* The callback only supports solvables, so we can't iterate over the
-       extra things.  */
-    return;
+  if (p < 0 && p != SOLVID_META)
+    return;            /* SOLVID_POS not supported yet */
   flags = md->flags;
-  if (!(flags & SEARCH_NO_STORAGE_SOLVABLE))
+  if (p > 0 && !(flags & SEARCH_NO_STORAGE_SOLVABLE))
     {
       s = pool->solvables + p;
       switch(keyname)
@@ -850,42 +856,23 @@ repo_search_md(Repo *repo, Id p, Id keyname, struct matchdata *md)
        }
     }
 
+  if (keyname)
+    {
+      if (keyname == SOLVABLE_FILELIST)
+       data = repo_lookup_filelist_repodata(repo, p, &md->matcher);
+      else
+        data = repo_lookup_repodata_opt(repo, p, keyname);
+      if (data)
+        repodata_search(data, p, keyname, md->flags, repo_matchvalue, md);
+      return;
+    }
+
+  keyskip = repo_create_keyskip(repo, p, &md->keyskip);
   FOR_REPODATAS(repo, i, data)
     {
-      if (p < data->start || p >= data->end)
-       continue;
-      if (keyname && !repodata_precheck_keyname(data, keyname))
+      if (p != SOLVID_META && (p < data->start || p >= data->end))
        continue;
-      if (keyname == SOLVABLE_FILELIST && !(md->flags & SEARCH_COMPLETE_FILELIST))
-       {
-         /* do not search filelist extensions */
-         if (data->state != REPODATA_AVAILABLE)
-           continue;
-         for (j = 1; j < data->nkeys; j++)
-           if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-             break;
-         if (j == data->nkeys)
-           continue;
-       }
-      if (data->state == REPODATA_STUB)
-       {
-         if (keyname)
-           {
-             for (j = 1; j < data->nkeys; j++)
-               if (keyname == data->keys[j].name)
-                 break;
-             if (j == data->nkeys)
-               continue;
-           }
-         /* load it */
-         if (data->loadcallback)
-           data->loadcallback(data);
-         else
-            data->state = REPODATA_ERROR;
-       }
-      if (data->state == REPODATA_ERROR)
-       continue;
-      repodata_search(data, p, keyname, md->flags, repo_matchvalue, md);
+      repodata_search_keyskip(data, p, keyname, md->flags, keyskip, repo_matchvalue, md);
       if (md->stop > SEARCH_NEXT_KEY)
        break;
     }
@@ -908,18 +895,181 @@ repo_search(Repo *repo, Id p, Id keyname, const char *match, int flags, int (*ca
   repo_search_md(repo, p, keyname, &md);
   if (match)
     datamatcher_free(&md.matcher);
+  solv_free(md.keyskip);
+}
+
+Repodata *
+repo_lookup_repodata(Repo *repo, Id entry, Id keyname)
+{
+  Repodata *data;
+  int rdid;
+  Id type;
+
+  if (entry == SOLVID_POS)
+    {
+      Pool *pool = repo->pool;
+      return pool->pos.repo == repo && pool->pos.repodataid ? pool->pos.repo->repodata + pool->pos.repodataid : 0;
+    }
+  for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
+    {
+      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
+       continue;
+      if (!repodata_precheck_keyname(data, keyname))
+       continue;
+      if ((type = repodata_lookup_type(data, entry, keyname)) != 0)
+        return type == REPOKEY_TYPE_DELETED ? 0 : data;
+    }
+  return 0;
+}
+
+/* like repo_lookup_repodata, but may return a repodata that contains no match instead of NULL */
+Repodata *
+repo_lookup_repodata_opt(Repo *repo, Id entry, Id keyname)
+{
+  Repodata *data, *found = 0;
+  int rdid;
+  Id type;
+
+  if (entry == SOLVID_POS)
+    {
+      Pool *pool = repo->pool;
+      return pool->pos.repo == repo && pool->pos.repodataid ? pool->pos.repo->repodata + pool->pos.repodataid : 0;
+    }
+  for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
+    {
+      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
+       continue;
+      if (!repodata_precheck_keyname(data, keyname))
+       continue;
+      if (found && (type = repodata_lookup_type(found, entry, keyname)) != 0)
+       return type == REPOKEY_TYPE_DELETED ? 0 : found;
+      found = data;
+    }
+  return found;
+}
+
+Repodata *
+repo_lookup_filelist_repodata(Repo *repo, Id entry, Datamatcher *matcher)
+{
+  Repodata *data;
+  int haveextension;
+  int rdid;
+  Id type;
+
+  if (entry <= 0 || !matcher || !matcher->match || ((matcher->flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
+      && (matcher->flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB))
+    return repo_lookup_repodata_opt(repo, entry, SOLVABLE_FILELIST);   /* cannot use filtered filelist */
+
+  haveextension = 0;
+  for (rdid = repo->nrepodata - 1, data = repo->repodata + rdid; rdid > 0; rdid--, data--)
+    {    
+      if (entry < data->start || entry >= data->end)
+       continue;
+      if (data->filelisttype == REPODATA_FILELIST_FILTERED)
+       {
+         if (data->state != REPODATA_AVAILABLE)
+           {
+             if (data->state != REPODATA_STUB)
+               continue;
+             repodata_load(data);
+             if (data->state != REPODATA_AVAILABLE || entry < data->start || entry >= data->end)
+               continue;
+           }
+         /* does this contain any data about the solvable we're looking for? */
+         if (!data->incoreoffset[entry - data->start])
+           continue;   /* no, ignore */
+         if (haveextension && repodata_filelistfilter_matches(data, matcher->match))
+           return data;
+         break;        /* fall back to normal code */
+       }
+      if (!repodata_has_keyname(data, SOLVABLE_FILELIST))
+       continue;
+      if (data->filelisttype == REPODATA_FILELIST_EXTENSION)
+       {
+         haveextension++;
+         continue;
+       }
+      if ((type = repodata_lookup_type(data, entry, SOLVABLE_FILELIST)) != 0)
+       {
+         if (haveextension)
+           break;              /* need to look in extension */
+         return type == REPOKEY_TYPE_DELETED ? 0 : data;
+       }
+    }
+  /* cannot use filtered filelist */
+  return repo_lookup_repodata_opt(repo, entry, SOLVABLE_FILELIST);
+}
+
+
+/* the keyskip array has the following format:
+ * 0: keyname area size
+ * 1: repoid base
+ * 2: repoid end
+ * 3: entry for keyname 0
+ * 4: entry for keyname 1
+ * ...
+ */
+Id *
+repo_create_keyskip(Repo *repo, Id entry, Id **oldkeyskip)
+{
+  Repodata *data, *last = 0;
+  Id *keyskip;
+  int rdid, cnt = 0;
+
+  if (repo->nrepodata <= 2)
+    return 0;  /* just one repodata, nothing to filter */
+  keyskip = oldkeyskip ? *oldkeyskip : 0;
+  if (keyskip)
+    {
+      if (keyskip[1] >= 0x10000000)
+       keyskip = solv_free(keyskip);
+      else
+        keyskip[1] = keyskip[2];
+    }
+  FOR_REPODATAS(repo, rdid, data)
+    {
+      if (entry != SOLVID_META)
+       {
+         if (data->state != REPODATA_AVAILABLE && data->state != REPODATA_LOADING)
+           {
+             if (data->state != REPODATA_STUB)
+               continue;
+             repodata_load(data);
+             if (data->state != REPODATA_AVAILABLE)
+               continue;
+           }
+         if ((entry < data->start || entry >= data->end))
+           continue;
+         if (!data->incoreoffset[entry - data->start])
+            continue;
+       }
+      if (last)
+        keyskip = repodata_fill_keyskip(last, entry, keyskip);
+      last = data;
+      cnt++;
+    }
+  if (cnt <= 1)
+    {
+      if (oldkeyskip)
+       *oldkeyskip = keyskip;
+      return 0;
+    }
+  keyskip = repodata_fill_keyskip(last, entry, keyskip);
+  if (keyskip)
+    keyskip[2] = keyskip[1] + repo->nrepodata;
+  if (oldkeyskip)
+    *oldkeyskip = keyskip;
+  return keyskip;
 }
 
 const char *
 repo_lookup_str(Repo *repo, Id entry, Id keyname)
 {
-  Pool *pool = repo->pool;
   Repodata *data;
-  int i;
-  const char *str;
 
   if (entry >= 0)
     {
+      Pool *pool = repo->pool;
       switch (keyname)
        {
        case SOLVABLE_NAME:
@@ -932,31 +1082,15 @@ repo_lookup_str(Repo *repo, Id entry, Id keyname)
          return pool_id2str(pool, pool->solvables[entry].vendor);
        }
     }
-  else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_str(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      str = repodata_lookup_str(data, entry, keyname);
-      if (str)
-       return str;
-      if (repodata_lookup_type(data, entry, keyname))
-       return 0;
-    }
-  return 0;
+  data = repo_lookup_repodata_opt(repo, entry, keyname);
+  return data ? repodata_lookup_str(data, entry, keyname) : 0;
 }
 
 
 unsigned long long
 repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned long long notfound)
 {
-  Pool *pool = repo->pool;
   Repodata *data;
-  int i;
-  unsigned long long value;
 
   if (entry >= 0)
     {
@@ -967,28 +1101,14 @@ repo_lookup_num(Repo *repo, Id entry, Id keyname, unsigned long long notfound)
          return notfound;
        }
     }
-  else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_num(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname, &value) ? value : notfound;
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      if (repodata_lookup_num(data, entry, keyname, &value))
-       return value;
-      if (repodata_lookup_type(data, entry, keyname))
-       return notfound;
-    }
-  return notfound;
+  data = repo_lookup_repodata_opt(repo, entry, keyname);
+  return data ? repodata_lookup_num(data, entry, keyname, notfound) : notfound;
 }
 
 Id
 repo_lookup_id(Repo *repo, Id entry, Id keyname)
 {
-  Pool *pool = repo->pool;
   Repodata *data;
-  int i;
   Id id;
 
   if (entry >= 0)
@@ -1005,24 +1125,9 @@ repo_lookup_id(Repo *repo, Id entry, Id keyname)
          return repo->pool->solvables[entry].vendor;
        }
     }
-  else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    {
-      Repodata *data = pool->pos.repo->repodata + pool->pos.repodataid;
-      Id id = repodata_lookup_id(data, entry, keyname);
-      return data->localpool ? repodata_globalize_id(data, id, 1) : id;
-    }
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      id = repodata_lookup_id(data, entry, keyname);
-      if (id)
-       return data->localpool ? repodata_globalize_id(data, id, 1) : id;
-      if (repodata_lookup_type(data, entry, keyname))
-       return 0;
-    }
+  data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && (id = repodata_lookup_id(data, entry, keyname)) != 0)
+    return data->localpool ? repodata_globalize_id(data, id, 1) : id;
   return 0;
 }
 
@@ -1041,7 +1146,6 @@ lookup_idarray_solvable(Repo *repo, Offset off, Queue *q)
 int
 repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q)
 {
-  Pool *pool = repo->pool;
   Repodata *data;
   int i;
   if (entry >= 0)
@@ -1066,36 +1170,15 @@ repo_lookup_idarray(Repo *repo, Id entry, Id keyname, Queue *q)
          return lookup_idarray_solvable(repo, repo->pool->solvables[entry].enhances, q);
         }
     }
-  else if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    {
-      Repodata *data = pool->pos.repo->repodata + pool->pos.repodataid;
-      if (repodata_lookup_idarray(data, entry, keyname, q))
-       {
-         if (data->localpool)
-           {
-             for (i = 0; i < q->count; i++)
-               q->elements[i] = repodata_globalize_id(data, q->elements[i], 1);
-           }
-         return 1;
-       }
-    }
-  FOR_REPODATAS(repo, i, data)
+  data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && repodata_lookup_idarray(data, entry, keyname, q))
     {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      if (repodata_lookup_idarray(data, entry, keyname, q))
+      if (data->localpool)
        {
-         if (data->localpool)
-           {
-             for (i = 0; i < q->count; i++)
-               q->elements[i] = repodata_globalize_id(data, q->elements[i], 1);
-           }
-         return 1;
+         for (i = 0; i < q->count; i++)
+           q->elements[i] = repodata_globalize_id(data, q->elements[i], 1);
        }
-      if (repodata_lookup_type(data, entry, keyname))
-       break;
+      return 1;
     }
   queue_empty(q);
   return 0;
@@ -1139,25 +1222,10 @@ repo_lookup_deparray(Repo *repo, Id entry, Id keyname, Queue *q, Id marker)
 const unsigned char *
 repo_lookup_bin_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
 {
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
   const unsigned char *chk;
-
-  if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname, typep);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      chk = repodata_lookup_bin_checksum(data, entry, keyname, typep);
-      if (chk)
-       return chk;
-      if (repodata_lookup_type(data, entry, keyname))
-       return 0;
-    }
+  Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && (chk = repodata_lookup_bin_checksum(data, entry, keyname, typep)) != 0)
+    return chk;
   *typep = 0;
   return 0;
 }
@@ -1172,69 +1240,29 @@ repo_lookup_checksum(Repo *repo, Id entry, Id keyname, Id *typep)
 int
 repo_lookup_void(Repo *repo, Id entry, Id keyname)
 {
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
-  Id type;
-
-  if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_void(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      type = repodata_lookup_type(data, entry, keyname);
-      if (type)
-       return type == REPOKEY_TYPE_VOID;
-    }
+  Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data)
+    return repodata_lookup_void(data, entry, keyname);
   return 0;
 }
 
 Id
 repo_lookup_type(Repo *repo, Id entry, Id keyname)
 {
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
   Id type;
-
-  if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_type(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      type = repodata_lookup_type(data, entry, keyname);
-      if (type)
-       return type == REPOKEY_TYPE_DELETED ? 0 : type;
-    }
+  Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && (type = repodata_lookup_type(data, entry, keyname)) != 0 && type != REPOKEY_TYPE_DELETED)
+    return type;
   return 0;
 }
 
 const void *
 repo_lookup_binary(Repo *repo, Id entry, Id keyname, int *lenp)
 {
-  Pool *pool = repo->pool;
-  Repodata *data;
-  int i;
   const void *bin;
-
-  if (entry == SOLVID_POS && pool->pos.repo == repo && pool->pos.repodataid)
-    return repodata_lookup_binary(pool->pos.repo->repodata + pool->pos.repodataid, entry, keyname, lenp);
-  FOR_REPODATAS(repo, i, data)
-    {
-      if (entry != SOLVID_META && (entry < data->start || entry >= data->end))
-       continue;
-      if (!repodata_precheck_keyname(data, keyname))
-       continue;
-      bin = repodata_lookup_binary(data, entry, keyname, lenp);
-      if (bin)
-       return bin;
-    }
+  Repodata *data = repo_lookup_repodata_opt(repo, entry, keyname);
+  if (data && (bin = repodata_lookup_binary(data, entry, keyname, lenp)) != 0)
+    return bin;
   *lenp = 0;
   return 0;
 }
index bd9c58c..4abfb0f 100644 (file)
@@ -24,7 +24,7 @@
 extern "C" {
 #endif
 
-typedef struct _Repo {
+typedef struct s_Repo {
   const char *name;            /* name pointer */
   Id repoid;                   /* our id */
   void *appdata;               /* application private pointer */
@@ -146,6 +146,11 @@ Repodata *repo_last_repodata(Repo *repo);
 
 void repo_search(Repo *repo, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata);
 
+/* returns the last repodata that contains the key */
+Repodata *repo_lookup_repodata(Repo *repo, Id entry, Id keyname);
+Repodata *repo_lookup_repodata_opt(Repo *repo, Id entry, Id keyname);
+Repodata *repo_lookup_filelist_repodata(Repo *repo, Id entry, Datamatcher *matcher);
+
 /* returns the string value of the attribute, or NULL if not found */
 Id repo_lookup_type(Repo *repo, Id entry, Id keyname);
 const char *repo_lookup_str(Repo *repo, Id entry, Id keyname);
@@ -173,6 +178,8 @@ void repo_unset(Repo *repo, Id p, Id keyname);
 
 void repo_internalize(Repo *repo);
 void repo_disable_paging(Repo *repo);
+Id *repo_create_keyskip(Repo *repo, Id entry, Id **oldkeyskip);
+
 
 /* iterator macros */
 #define FOR_REPO_SOLVABLES(r, p, s)                                            \
index 5858d4f..be33967 100644 (file)
@@ -478,7 +478,7 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
   int oldnstrings = pool->ss.nstrings;
   int oldnrels = pool->nrels;
 
-  struct _Stringpool *spool;
+  struct s_Stringpool *spool;
 
   Repodata *parent = 0;
   Repodata data;
@@ -859,7 +859,7 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
        type = idmap[type];
       else if ((flags & REPO_LOCALPOOL) != 0)
         type = pool_str2id(pool, stringpool_id2str(spool, type), 1);
-      if (type < REPOKEY_TYPE_VOID || type > REPOKEY_TYPE_FLEXARRAY)
+      if (type < REPOKEY_TYPE_VOID || type > REPOKEY_TYPE_DELETED)
        {
          data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "unsupported data type '%s'", pool_id2str(pool, type));
          type = REPOKEY_TYPE_VOID;
@@ -879,6 +879,8 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
            data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "main solvable data must use incore storage %d", keys[i].storage);
          keys[i].storage = KEY_STORAGE_SOLVABLE;
        }
+      if ((type == REPOKEY_TYPE_FIXARRAY || type == REPOKEY_TYPE_FLEXARRAY) && keys[i].storage != KEY_STORAGE_INCORE)
+       data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "flex/fixarrays must use incore storage\n");
       /* cannot handle rel idarrays in incore/vertical */
       if (type == REPOKEY_TYPE_REL_IDARRAY && keys[i].storage != KEY_STORAGE_SOLVABLE)
        data.error = pool_error(pool, SOLV_ERROR_UNSUPPORTED, "type REL_IDARRAY is only supported for STORAGE_SOLVABLE");
@@ -1216,12 +1218,9 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
            }
          /* FALLTHROUGH */
        default:
-         if (id == RPM_RPMDBID && s && (keys[key].type == REPOKEY_TYPE_U32 || keys[key].type == REPOKEY_TYPE_NUM))
+         if (id == RPM_RPMDBID && s && keys[key].type == REPOKEY_TYPE_NUM)
            {
-             if (keys[key].type == REPOKEY_TYPE_U32)
-               dp = data_read_u32(dp, (unsigned int *)&id);
-             else
-               dp = data_read_id_max(dp, &id, 0, 0, &data);
+             dp = data_read_id_max(dp, &id, 0, 0, &data);
              if (!repo->rpmdbid)
                repo->rpmdbid = repo_sidedata_create(repo, sizeof(Id));
              repo->rpmdbid[(s - pool->solvables) - repo->start] = id;
@@ -1270,7 +1269,7 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
       keys[i].type = REPOKEY_TYPE_IDARRAY;
 
   for (i = 1; i < numkeys; i++)
-    if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
+    if (keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET && keys[i].size)
       break;
   if (i < numkeys && !data.error)
     {
@@ -1310,6 +1309,7 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
       /* overwrite stub repodata */
       repodata_freedata(parent);
       data.repodataid = parent->repodataid;
+      data.loadcallback = parent->loadcallback;
       *parent = data;
     }
   else
@@ -1326,6 +1326,17 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
       repo->repodata[repo->nrepodata++] = data;
     }
 
+  if ((flags & REPO_EXTEND_SOLVABLES) != 0)
+    {
+      if (repodata_has_keyname(&data, SOLVABLE_FILELIST))
+       repodata_set_filelisttype(repo->repodata + data.repodataid, REPODATA_FILELIST_EXTENSION);
+    }
+  else
+    {
+      if (repodata_lookup_type(&data, SOLVID_META, REPOSITORY_FILTEREDFILELIST))
+        repodata_set_filelisttype(repo->repodata + data.repodataid, REPODATA_FILELIST_FILTERED);
+    }
+
   /* create stub repodata entries for all external */
   if (!(flags & SOLV_ADD_NO_STUBS) && !parent)
     {
@@ -1333,7 +1344,7 @@ printf("=> %s %s %p\n", pool_id2str(pool, keys[key].name), pool_id2str(pool, key
        if (data.keys[key].name == REPOSITORY_EXTERNAL && data.keys[key].type == REPOKEY_TYPE_FLEXARRAY)
          break;
       if (key < data.nkeys)
-       repodata_create_stubs(repo->repodata + (repo->nrepodata - 1));
+       repodata_create_stubs(repo->repodata + data.repodataid);
     }
 
   POOL_DEBUG(SOLV_DEBUG_STATS, "repo_add_solv took %d ms\n", solv_timems(now));
index 7e78af5..a975cec 100644 (file)
@@ -38,7 +38,7 @@ typedef struct needid {
 } NeedId;
 
 
-#define RELOFF(id) (needid[0].map + GETRELID(id))
+#define NEEDIDOFF(id) (ISRELDEP(id) ? (needid[0].map + GETRELID(id)) : id)
 
 /*
  * increment need Id
@@ -49,44 +49,22 @@ typedef struct needid {
  *
  */
 
-static void
-incneedid(Pool *pool, Id id, NeedId *needid)
+static inline void
+incneedid(Id id, NeedId *needid)
 {
-  while (ISRELDEP(id))
-    {
-      Reldep *rd = GETRELDEP(pool, id);
-      needid[RELOFF(id)].need++;
-      if (ISRELDEP(rd->evr))
-       incneedid(pool, rd->evr, needid);
-      else
-       needid[rd->evr].need++;
-      id = rd->name;
-    }
-  needid[id].need++;
+  needid[NEEDIDOFF(id)].need++;
 }
 
 static int
-incneedidarray(Pool *pool, Id *idarray, NeedId *needid)
+incneedidarray(Id *idarray, NeedId *needid)
 {
   Id id;
   int n = 0;
 
-  if (!idarray)
-    return 0;
   while ((id = *idarray++) != 0)
     {
       n++;
-      while (ISRELDEP(id))
-       {
-         Reldep *rd = GETRELDEP(pool, id);
-         needid[RELOFF(id)].need++;
-         if (ISRELDEP(rd->evr))
-           incneedid(pool, rd->evr, needid);
-         else
-           needid[rd->evr].need++;
-         id = rd->name;
-       }
-      needid[id].need++;
+      needid[NEEDIDOFF(id)].need++;
     }
   return n + 1;
 }
@@ -248,7 +226,7 @@ write_idarray(Repodata *data, Pool *pool, NeedId *needid, Id *ids)
     {
       id = *ids++;
       if (needid)
-        id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
+        id = needid[NEEDIDOFF(id)].need;
       if (id >= 64)
        id = (id & 63) | ((id & ~63) << 1);
       if (!*ids)
@@ -266,23 +244,21 @@ struct extdata {
 };
 
 struct cbdata {
+  Pool *pool;
   Repo *repo;
   Repodata *target;
 
   Stringpool *ownspool;
   Dirpool *owndirpool;
+  int clonepool;       /* are the pool ids cloned into ownspool? */
 
-  Id *keymap;
-  int nkeymap;
-  Id *keymapstart;
+  Id *keymap;          /* keymap for this repodata */
 
   NeedId *needid;
 
   Id *schema;          /* schema construction space */
   Id *sp;              /* pointer in above */
-  Id *oldschema, *oldsp;
 
-  Id *solvschemata;
   Id *subschemata;
   int nsubschemata;
   int current_sub;
@@ -291,18 +267,20 @@ struct cbdata {
 
   Id *dirused;
 
-  Id vstart;
+  Id vstart;           /* offset of key in vertical data */
 
   Id maxdata;
   Id lastlen;
 
   int doingsolvables;  /* working on solvables data */
   int filelistmode;
+
+  Id lastdirid;                /* last dir id seen in this repodata */
+  Id lastdirid_own;    /* last dir id put in own pool */
 };
 
-#define NEEDED_BLOCK 1023
+#define NEEDID_BLOCK 1023
 #define SCHEMATA_BLOCK 31
-#define SCHEMATADATA_BLOCK 255
 #define EXTDATA_BLOCK 4095
 
 static inline void
@@ -411,7 +389,7 @@ data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marke
     {
       Id id = ids[len];
       if (needid)
-        id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
+        id = needid[NEEDIDOFF(id)].need;
       lids[len] = id;
     }
   if (ids[len])
@@ -424,7 +402,7 @@ data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marke
        {
          Id id = ids[len];
          if (needid)
-            id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
+            id = needid[NEEDIDOFF(id)].need;
          sids[len] = id;
        }
     }
@@ -493,7 +471,7 @@ data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marke
   while ((id = *ids++) != 0)
     {
       if (needid)
-        id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
+        id = needid[NEEDIDOFF(id)].need;
       data_addideof(xd, id, *ids ? 0 : 1);
     }
 }
@@ -508,73 +486,53 @@ data_addblob(struct extdata *xd, unsigned char *blob, int len)
   xd->len += len;
 }
 
-static inline void
-data_addu32(struct extdata *xd, unsigned int num)
+/* grow needid array so that it contains the specified id */
+static void
+grow_needid(struct cbdata *cbdata, Id id)
 {
-  unsigned char d[4];
-  d[0] = num >> 24;
-  d[1] = num >> 16;
-  d[2] = num >> 8;
-  d[3] = num;
-  data_addblob(xd, d, 4);
+  int oldoff = cbdata->needid[0].map;
+  int newoff = (id + 1 + NEEDID_BLOCK) & ~NEEDID_BLOCK;
+  int nrels = cbdata->pool->nrels;
+  cbdata->needid = solv_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId));
+  if (nrels)
+    memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId));
+  memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId));
+  cbdata->needid[0].map = newoff;
 }
 
 static Id
-putinownpool(struct cbdata *cbdata, Stringpool *ss, Id id)
+putinownpool(struct cbdata *cbdata, Repodata *data, Id id)
 {
+  Stringpool *ss = data->localpool ? &data->spool : &cbdata->pool->ss;
   const char *str = stringpool_id2str(ss, id);
   id = stringpool_str2id(cbdata->ownspool, str, 1);
   if (id >= cbdata->needid[0].map)
-    {
-      int oldoff = cbdata->needid[0].map;
-      int newoff = (id + 1 + NEEDED_BLOCK) & ~NEEDED_BLOCK;
-      int nrels = cbdata->repo->pool->nrels;
-      cbdata->needid = solv_realloc2(cbdata->needid, newoff + nrels, sizeof(NeedId));
-      if (nrels)
-       memmove(cbdata->needid + newoff, cbdata->needid + oldoff, nrels * sizeof(NeedId));
-      memset(cbdata->needid + oldoff, 0, (newoff - oldoff) * sizeof(NeedId));
-      cbdata->needid[0].map = newoff;
-    }
+    grow_needid(cbdata, id);
   return id;
 }
 
 static Id
-putinowndirpool(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir)
+putinowndirpool_slow(struct cbdata *cbdata, Repodata *data, Dirpool *dp, Id dir)
 {
   Id compid, parent;
 
   parent = dirpool_parent(dp, dir);
   if (parent)
-    parent = putinowndirpool(cbdata, data, dp, parent);
-  compid = dp->dirs[dir];
-  if (cbdata->ownspool && compid > 1)
-    compid = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, compid);
+    parent = putinowndirpool_slow(cbdata, data, dp, parent);
+  compid = dirpool_compid(dp, dir);
+  if (cbdata->ownspool && compid > 1 && (!cbdata->clonepool || data->localpool))
+    compid = putinownpool(cbdata, data, compid);
   return dirpool_add_dir(cbdata->owndirpool, parent, compid, 1);
 }
 
-/*
- * collect usage information about the dirs
- * 1: dir used, no child of dir used
- * 2: dir used as parent of another used dir
- */
-static inline void
-setdirused(struct cbdata *cbdata, Dirpool *dp, Id dir)
+static inline Id
+putinowndirpool(struct cbdata *cbdata, Repodata *data, Id dir)
 {
-  if (cbdata->dirused[dir])
-    return;
-  cbdata->dirused[dir] = 1;
-  while ((dir = dirpool_parent(dp, dir)) != 0)
-    {
-      if (cbdata->dirused[dir] == 2)
-       return;
-      if (cbdata->dirused[dir])
-        {
-         cbdata->dirused[dir] = 2;
-         return;
-        }
-      cbdata->dirused[dir] = 2;
-    }
-  cbdata->dirused[0] = 2;
+  if (dir && dir == cbdata->lastdirid)
+    return cbdata->lastdirid_own;
+  cbdata->lastdirid = dir;
+  cbdata->lastdirid_own = putinowndirpool_slow(cbdata, data, &data->dirpool, dir);
+  return cbdata->lastdirid_own;
 }
 
 /*
@@ -582,26 +540,24 @@ setdirused(struct cbdata *cbdata, Dirpool *dp, Id dir)
  * collect key/id/dirid usage information, create needed schemas
  */
 static int
-repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Repokey *key, KeyValue *kv)
+collect_needed_cb(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
 {
+  struct cbdata *cbdata = vcbdata;
   Id id;
   int rm;
 
+#if 0
+    fprintf(stderr, "solvable %d (%s): key (%d)%s %d\n", s ? (int)(s - cbdata->pool->solvables) : 0, s ? pool_id2str(cbdata->pool, s->name) : "", key->name, pool_id2str(cbdata->pool, key->name), key->type);
+#endif
   if (key->name == REPOSITORY_SOLVABLES)
     return SEARCH_NEXT_KEY;    /* we do not want this one */
 
-  /* hack: ignore some keys, see BUGS */
-  if (data->repodataid != data->repo->nrepodata - 1)
-    if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION)
-      return SEARCH_NEXT_KEY;
-
-  rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)];
+  rm = cbdata->keymap[key - data->keys];
   if (!rm)
     return SEARCH_NEXT_KEY;    /* we do not want this one */
 
   /* record key in schema */
-  if ((key->type != REPOKEY_TYPE_FIXARRAY || kv->eof == 0)
-      && (cbdata->sp == cbdata->schema || cbdata->sp[-1] != rm))
+  if (cbdata->sp[-1] != rm)
     *cbdata->sp++ = rm;
 
   switch(key->type)
@@ -609,51 +565,20 @@ repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Rep
       case REPOKEY_TYPE_ID:
       case REPOKEY_TYPE_IDARRAY:
        id = kv->id;
-       if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
-         id = putinownpool(cbdata, data->localpool ? &data->spool : &repo->pool->ss, id);
-       incneedid(repo->pool, id, cbdata->needid);
+       if (!ISRELDEP(id) && cbdata->ownspool && id > 1 && (!cbdata->clonepool || data->localpool))
+         id = putinownpool(cbdata, data, id);
+       incneedid(id, cbdata->needid);
        break;
       case REPOKEY_TYPE_DIR:
       case REPOKEY_TYPE_DIRNUMNUMARRAY:
       case REPOKEY_TYPE_DIRSTRARRAY:
        id = kv->id;
        if (cbdata->owndirpool)
-         putinowndirpool(cbdata, data, &data->dirpool, id);
+         putinowndirpool(cbdata, data, id);
        else
-         setdirused(cbdata, &data->dirpool, id);
+         cbdata->dirused[id] = 1;
        break;
       case REPOKEY_TYPE_FIXARRAY:
-       if (kv->eof == 0)
-         {
-           if (cbdata->oldschema)
-             {
-               cbdata->target->error = pool_error(cbdata->repo->pool, -1, "nested fixarray structs not yet implemented");
-               return SEARCH_NEXT_KEY;
-             }
-           cbdata->oldschema = cbdata->schema;
-           cbdata->oldsp = cbdata->sp;
-           cbdata->schema = solv_calloc(cbdata->target->nkeys, sizeof(Id));
-           cbdata->sp = cbdata->schema;
-         }
-       else if (kv->eof == 1)
-         {
-           cbdata->current_sub++;
-           *cbdata->sp = 0;
-           cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
-           cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, cbdata->schema, 1);
-#if 0
-           fprintf(stderr, "Have schema %d\n", cbdata->subschemata[cbdata->nsubschemata-1]);
-#endif
-           cbdata->sp = cbdata->schema;
-         }
-       else
-         {
-           solv_free(cbdata->schema);
-           cbdata->schema = cbdata->oldschema;
-           cbdata->sp = cbdata->oldsp;
-           cbdata->oldsp = cbdata->oldschema = 0;
-         }
-       break;
       case REPOKEY_TYPE_FLEXARRAY:
        if (kv->entry == 0)
          {
@@ -662,13 +587,16 @@ repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Rep
          }
        else
          {
-           /* just finished a schema, rewind */
+           /* just finished a schema, rewind to start */
            Id *sp = cbdata->sp - 1;
            *sp = 0;
            while (sp[-1])
              sp--;
-           cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
-           cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, sp, 1);
+           if (kv->entry == 1 || key->type == REPOKEY_TYPE_FLEXARRAY)
+             {
+               cbdata->subschemata = solv_extend(cbdata->subschemata, cbdata->nsubschemata, 1, sizeof(Id), SCHEMATA_BLOCK);
+               cbdata->subschemata[cbdata->nsubschemata++] = repodata_schema2id(cbdata->target, sp, 1);
+             }
            cbdata->sp = kv->eof == 2 ? sp - 1: sp;
          }
        break;
@@ -678,17 +606,82 @@ repo_write_collect_needed(struct cbdata *cbdata, Repo *repo, Repodata *data, Rep
   return 0;
 }
 
-static int
-repo_write_cb_needed(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
+static void
+collect_needed_solvable(struct cbdata *cbdata, Solvable *s, Id *keymap)
 {
-  struct cbdata *cbdata = vcbdata;
-  Repo *repo = data->repo;
-
-#if 0
-  if (s)
-    fprintf(stderr, "solvable %d (%s): key (%d)%s %d\n", s ? s - repo->pool->solvables : 0, s ? pool_id2str(repo->pool, s->name) : "", key->name, pool_id2str(repo->pool, key->name), key->type);
-#endif
-  return repo_write_collect_needed(cbdata, repo, data, key, kv);
+  /* set schema info, keep in sync with collect_data_solvable */
+  Repo *repo = s->repo;
+  Id *sp = cbdata->sp;
+  NeedId *needid = cbdata->needid;
+  Repodata *target = cbdata->target;
+  Id *idarraydata = repo->idarraydata;
+
+  if (keymap[SOLVABLE_NAME])
+    {
+      *sp++ = keymap[SOLVABLE_NAME];
+      needid[s->name].need++;
+    }
+  if (keymap[SOLVABLE_ARCH])
+    {
+      *sp++ = keymap[SOLVABLE_ARCH];
+      needid[s->arch].need++;
+    }
+  if (keymap[SOLVABLE_EVR])
+    {
+      *sp++ = keymap[SOLVABLE_EVR];
+      needid[s->evr].need++;
+    }
+  if (s->vendor && keymap[SOLVABLE_VENDOR])
+    {
+      *sp++ = keymap[SOLVABLE_VENDOR];
+      needid[s->vendor].need++;
+    }
+  if (s->provides && keymap[SOLVABLE_PROVIDES])
+    {
+      *sp++ = keymap[SOLVABLE_PROVIDES];
+      target->keys[keymap[SOLVABLE_PROVIDES]].size += incneedidarray(idarraydata + s->provides, needid);
+    }
+  if (s->obsoletes && keymap[SOLVABLE_OBSOLETES])
+    {
+      *sp++ = keymap[SOLVABLE_OBSOLETES];
+      target->keys[keymap[SOLVABLE_OBSOLETES]].size += incneedidarray(idarraydata + s->obsoletes, needid);
+    }
+  if (s->conflicts && keymap[SOLVABLE_CONFLICTS])
+    {
+      *sp++ = keymap[SOLVABLE_CONFLICTS];
+      target->keys[keymap[SOLVABLE_CONFLICTS]].size += incneedidarray(idarraydata + s->conflicts, needid);
+    }
+  if (s->requires && keymap[SOLVABLE_REQUIRES])
+    {
+      *sp++ = keymap[SOLVABLE_REQUIRES];
+      target->keys[keymap[SOLVABLE_REQUIRES]].size += incneedidarray(idarraydata + s->requires, needid);
+    }
+  if (s->recommends && keymap[SOLVABLE_RECOMMENDS])
+    {
+      *sp++ = keymap[SOLVABLE_RECOMMENDS];
+      target->keys[keymap[SOLVABLE_RECOMMENDS]].size += incneedidarray(idarraydata + s->recommends, needid);
+    }
+  if (s->suggests && keymap[SOLVABLE_SUGGESTS])
+    {
+      *sp++ = keymap[SOLVABLE_SUGGESTS];
+      target->keys[keymap[SOLVABLE_SUGGESTS]].size += incneedidarray(idarraydata + s->suggests, needid);
+    }
+  if (s->supplements && keymap[SOLVABLE_SUPPLEMENTS])
+    {
+      *sp++ = keymap[SOLVABLE_SUPPLEMENTS];
+      target->keys[keymap[SOLVABLE_SUPPLEMENTS]].size += incneedidarray(idarraydata + s->supplements, needid);
+    }
+  if (s->enhances && keymap[SOLVABLE_ENHANCES])
+    {
+      *sp++ = keymap[SOLVABLE_ENHANCES];
+      target->keys[keymap[SOLVABLE_ENHANCES]].size += incneedidarray(idarraydata + s->enhances, needid);
+    }
+  if (repo->rpmdbid && keymap[RPM_RPMDBID])
+    {
+      *sp++ = keymap[RPM_RPMDBID];
+      target->keys[keymap[RPM_RPMDBID]].size++;
+    }
+  cbdata->sp = sp;
 }
 
 
@@ -696,57 +689,51 @@ repo_write_cb_needed(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, K
  * pass 2 callback:
  * encode all of the data into the correct buffers
  */
-
 static int
-repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue *kv)
+collect_data_cb(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
 {
+  struct cbdata *cbdata = vcbdata;
   int rm;
-  Id id;
-  unsigned int u32;
-  unsigned char v[4];
+  Id id, storage;
   struct extdata *xd;
   NeedId *needid;
 
   if (key->name == REPOSITORY_SOLVABLES)
     return SEARCH_NEXT_KEY;
 
-  /* hack: ignore some keys, see BUGS */
-  if (data->repodataid != data->repo->nrepodata - 1)
-    if (key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_LOCATION || key->name == REPOSITORY_KEYS || key->name == REPOSITORY_TOOLVERSION)
-      return SEARCH_NEXT_KEY;
-
-  rm = cbdata->keymap[cbdata->keymapstart[data->repodataid] + (key - data->keys)];
+  rm = cbdata->keymap[key - data->keys];
   if (!rm)
     return SEARCH_NEXT_KEY;    /* we do not want this one */
+  storage = cbdata->target->keys[rm].storage;
 
-  if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET)
+  xd = cbdata->extdata + 0;            /* incore buffer */
+  if (storage == KEY_STORAGE_VERTICAL_OFFSET)
     {
-      xd = cbdata->extdata + rm;       /* vertical buffer */
+      xd += rm;                /* vertical buffer */
       if (cbdata->vstart == -1)
         cbdata->vstart = xd->len;
     }
-  else
-    xd = cbdata->extdata + 0;          /* incore buffer */
   switch(key->type)
     {
+      case REPOKEY_TYPE_DELETED:
       case REPOKEY_TYPE_VOID:
       case REPOKEY_TYPE_CONSTANT:
       case REPOKEY_TYPE_CONSTANTID:
        break;
       case REPOKEY_TYPE_ID:
        id = kv->id;
-       if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
-         id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
-       needid = cbdata->needid;
-       id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
+       if (!ISRELDEP(id) && cbdata->ownspool && id > 1 && (!cbdata->clonepool || data->localpool))
+         id = putinownpool(cbdata, data, id);
+        needid = cbdata->needid;
+       id = needid[NEEDIDOFF(id)].need;
        data_addid(xd, id);
        break;
       case REPOKEY_TYPE_IDARRAY:
        id = kv->id;
-       if (!ISRELDEP(id) && cbdata->ownspool && id > 1)
-         id = putinownpool(cbdata, data->localpool ? &data->spool : &data->repo->pool->ss, id);
-       needid = cbdata->needid;
-       id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
+       if (!ISRELDEP(id) && cbdata->ownspool && id > 1 && (!cbdata->clonepool || data->localpool))
+         id = putinownpool(cbdata, data, id);
+        needid = cbdata->needid;
+       id = needid[NEEDIDOFF(id)].need;
        data_addideof(xd, id, kv->eof);
        break;
       case REPOKEY_TYPE_STR:
@@ -770,13 +757,6 @@ repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue
       case REPOKEY_TYPE_SHA512:
        data_addblob(xd, (unsigned char *)kv->str, SIZEOF_SHA512);
        break;
-      case REPOKEY_TYPE_U32:
-       u32 = kv->num;
-       v[0] = u32 >> 24;
-       v[1] = u32 >> 16;
-       v[2] = u32 >> 8;
-       v[3] = u32;
-       data_addblob(xd, v, 4);
        break;
       case REPOKEY_TYPE_NUM:
        data_addid64(xd, kv->num, kv->num2);
@@ -784,7 +764,7 @@ repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue
       case REPOKEY_TYPE_DIR:
        id = kv->id;
        if (cbdata->owndirpool)
-         id = putinowndirpool(cbdata, data, &data->dirpool, id);
+         id = putinowndirpool(cbdata, data, id);
        id = cbdata->dirused[id];
        data_addid(xd, id);
        break;
@@ -796,7 +776,7 @@ repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue
       case REPOKEY_TYPE_DIRNUMNUMARRAY:
        id = kv->id;
        if (cbdata->owndirpool)
-         id = putinowndirpool(cbdata, data, &data->dirpool, id);
+         id = putinowndirpool(cbdata, data, id);
        id = cbdata->dirused[id];
        data_addid(xd, id);
        data_addid(xd, kv->num);
@@ -805,39 +785,22 @@ repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue
       case REPOKEY_TYPE_DIRSTRARRAY:
        id = kv->id;
        if (cbdata->owndirpool)
-         id = putinowndirpool(cbdata, data, &data->dirpool, id);
+         id = putinowndirpool(cbdata, data, id);
        id = cbdata->dirused[id];
-       if (cbdata->filelistmode > 0)
+       if (rm == cbdata->filelistmode)
          {
+           /* postpone adding to xd, just update len to get the correct offsets into the incore data*/
            xd->len += data_addideof_len(id) + strlen(kv->str) + 1;
            break;
          }
        data_addideof(xd, id, kv->eof);
        data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
-       if (cbdata->filelistmode < 0)
-         return 0;
        break;
       case REPOKEY_TYPE_FIXARRAY:
-       if (kv->eof == 0)
-         {
-           if (kv->num)
-             {
-               data_addid(xd, kv->num);
-               data_addid(xd, cbdata->subschemata[cbdata->current_sub]);
-#if 0
-               fprintf(stderr, "writing %d %d\n", kv->num, cbdata->subschemata[cbdata->current_sub]);
-#endif
-             }
-         }
-       else if (kv->eof == 1)
-         {
-           cbdata->current_sub++;
-         }
-       break;
       case REPOKEY_TYPE_FLEXARRAY:
        if (!kv->entry)
          data_addid(xd, kv->num);
-       if (kv->eof != 2)
+       if (kv->eof != 2 && (!kv->entry || key->type == REPOKEY_TYPE_FLEXARRAY))
          data_addid(xd, cbdata->subschemata[cbdata->current_sub++]);
        if (xd == cbdata->extdata + 0 && !kv->parent && !cbdata->doingsolvables)
          {
@@ -847,10 +810,10 @@ repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue
          }
        break;
       default:
-       cbdata->target->error = pool_error(cbdata->repo->pool, -1, "unknown type for %d: %d\n", key->name, key->type);
+       cbdata->target->error = pool_error(cbdata->pool, -1, "unknown type for %d: %d\n", key->name, key->type);
        break;
     }
-  if (cbdata->target->keys[rm].storage == KEY_STORAGE_VERTICAL_OFFSET && kv->eof)
+  if (storage == KEY_STORAGE_VERTICAL_OFFSET && kv->eof)
     {
       /* we can re-use old data in the blob here! */
       data_addid(cbdata->extdata + 0, cbdata->vstart);                 /* add offset into incore data */
@@ -860,11 +823,63 @@ repo_write_adddata(struct cbdata *cbdata, Repodata *data, Repokey *key, KeyValue
   return 0;
 }
 
+/* special version of collect_data_cb that collects just one single REPOKEY_TYPE_DIRSTRARRAY vertical data */
 static int
-repo_write_cb_adddata(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
+collect_filelist_cb(void *vcbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv)
 {
   struct cbdata *cbdata = vcbdata;
-  return repo_write_adddata(cbdata, data, key, kv);
+  int rm;
+  Id id;
+  struct extdata *xd;
+
+  rm = cbdata->keymap[key - data->keys];
+  if (rm != cbdata->filelistmode)
+    return SEARCH_NEXT_KEY;    /* we do not want this one */
+  id = kv->id;
+  if (cbdata->owndirpool)
+    id = putinowndirpool(cbdata, data, id);
+  id = cbdata->dirused[id];
+  xd = cbdata->extdata + rm;   /* vertical buffer */
+  data_addideof(xd, id, kv->eof);
+  data_addblob(xd, (unsigned char *)kv->str, strlen(kv->str) + 1);
+  return 0;
+}
+
+static void
+collect_data_solvable(struct cbdata *cbdata, Solvable *s, Id *keymap)
+{
+  Repo *repo = s->repo;
+  Pool *pool = repo->pool;
+  struct extdata *xd = cbdata->extdata;
+  NeedId *needid = cbdata->needid;
+  Id *idarraydata = repo->idarraydata;
+
+  if (keymap[SOLVABLE_NAME])
+    data_addid(xd, needid[s->name].need);
+  if (keymap[SOLVABLE_ARCH])
+    data_addid(xd, needid[s->arch].need);
+  if (keymap[SOLVABLE_EVR])
+    data_addid(xd, needid[s->evr].need);
+  if (s->vendor && keymap[SOLVABLE_VENDOR])
+    data_addid(xd, needid[s->vendor].need);
+  if (s->provides && keymap[SOLVABLE_PROVIDES])
+    data_adddepids(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
+  if (s->obsoletes && keymap[SOLVABLE_OBSOLETES])
+    data_adddepids(xd, pool, needid, idarraydata + s->obsoletes, 0);
+  if (s->conflicts && keymap[SOLVABLE_CONFLICTS])
+    data_adddepids(xd, pool, needid, idarraydata + s->conflicts, 0);
+  if (s->requires && keymap[SOLVABLE_REQUIRES])
+    data_adddepids(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
+  if (s->recommends && keymap[SOLVABLE_RECOMMENDS])
+    data_adddepids(xd, pool, needid, idarraydata + s->recommends, 0);
+  if (s->suggests && keymap[SOLVABLE_SUGGESTS])
+    data_adddepids(xd, pool, needid, idarraydata + s->suggests, 0);
+  if (s->supplements && keymap[SOLVABLE_SUPPLEMENTS])
+    data_adddepids(xd, pool, needid, idarraydata + s->supplements, 0);
+  if (s->enhances && keymap[SOLVABLE_ENHANCES])
+    data_adddepids(xd, pool, needid, idarraydata + s->enhances, 0);
+  if (repo->rpmdbid && keymap[RPM_RPMDBID])
+    data_addid(xd, repo->rpmdbid[(s - pool->solvables) - repo->start]);
 }
 
 /* traverse through directory with first child "dir" */
@@ -972,24 +987,6 @@ repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata)
   return KEY_STORAGE_INCORE;
 }
 
-/*
- * return true if the repodata contains the filelist (and just
- * the filelist). The same code is used in the dataiterator. The way
- * it is used is completely wrong, of course, as having the filelist
- * key does not mean it is used for a specific solvable. Nevertheless
- * it is better to have it than to write broken solv files.
- */
-static inline int
-is_filelist_extension(Repodata *data)
-{
-  int j;
-  for (j = 1; j < data->nkeys; j++)
-    if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-      return 0;
-  return 1;
-}
-
-
 static int
 write_compressed_extdata(Repodata *target, struct extdata *xd, unsigned char *vpage, int lpage)
 {
@@ -1013,10 +1010,109 @@ write_compressed_extdata(Repodata *target, struct extdata *xd, unsigned char *vp
   return lpage;
 }
 
+
+static Id *
+create_keyskip(Repo *repo, Id entry, unsigned char *repodataused, Id **oldkeyskip)
+{
+  Repodata *data, *last = 0;
+  Id *keyskip;
+  int rdid, cnt = 0;
+
+  if (repo->nrepodata <= 2)
+    return 0;
+  keyskip = *oldkeyskip;
+  if (keyskip)
+    {
+      if (keyskip[1] >= 0x10000000)
+       keyskip = solv_free(keyskip);
+      else
+        keyskip[1] = keyskip[2];
+    }
+  FOR_REPODATAS(repo, rdid, data)
+    {
+      if (!repodataused[rdid])
+        continue;
+      if (entry != SOLVID_META)
+       {
+         if (entry < data->start || entry >= data->end)
+           continue;
+         /* if repodataused is set we know that the state is AVAILABLE */
+         if (!data->incoreoffset[entry - data->start])
+           continue;
+       }
+      if (last)
+        keyskip = repodata_fill_keyskip(last, entry, keyskip);
+      last = data;
+      cnt++;
+    }
+  if (cnt <= 1)                /* just one repodata means we don't need a keyskip */
+    {
+      *oldkeyskip = keyskip;
+      return 0;
+    }
+  keyskip = repodata_fill_keyskip(last, entry, keyskip);
+  if (keyskip)
+    keyskip[2] = keyskip[1] + repo->nrepodata;
+  *oldkeyskip = keyskip;
+  return keyskip;
+}
+
 /*
  * Repo
  */
 
+Repowriter *
+repowriter_create(Repo *repo)
+{
+  Repowriter *writer = solv_calloc(1, sizeof(*writer));
+  writer->repo = repo;
+  writer->keyfilter = repo_write_stdkeyfilter;
+  writer->repodatastart = 1;
+  writer->repodataend = repo->nrepodata;
+  writer->solvablestart = repo->start;
+  writer->solvableend = repo->end;
+  return writer;
+}
+
+Repowriter *
+repowriter_free(Repowriter *writer)
+{
+  return solv_free(writer);
+}
+
+void
+repowriter_set_flags(Repowriter *writer, int flags)
+{
+  writer->flags = flags;
+}
+
+void
+repowriter_set_keyfilter(Repowriter *writer, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata)
+{
+  writer->keyfilter = keyfilter;
+  writer->kfdata = kfdata;
+}
+
+void
+repowriter_set_keyqueue(Repowriter *writer, Queue *keyq)
+{
+  writer->keyq = keyq;
+}
+
+void
+repowriter_set_repodatarange(Repowriter *writer, int repodatastart, int repodataend)
+{
+  writer->repodatastart = repodatastart;
+  writer->repodataend = repodataend;
+}
+
+void
+repowriter_set_solvablerange(Repowriter *writer, int solvablestart, int solvableend)
+{
+  writer->solvablestart = solvablestart;
+  writer->solvableend = solvableend;
+}
+
 /*
  * the code works the following way:
  *
@@ -1029,31 +1125,43 @@ write_compressed_extdata(Repodata *target, struct extdata *xd, unsigned char *vp
  * 5) write everything to disk
  */
 int
-repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
+repowriter_write(Repowriter *writer, FILE *fp)
 {
+  Repo *repo = writer->repo;
   Pool *pool = repo->pool;
-  int i, j, n, lastfilelistn;
+  int i, j, n;
   Solvable *s;
-  NeedId *needid;
+  NeedId *needid, *needidp;
   int nstrings, nrels;
   unsigned int sizeid;
   unsigned int solv_flags;
-  Reldep *ran;
-  Id *idarraydata;
+  Id *oldkeyskip = 0;
+  Id *keyskip = 0;
+  int searchflags = 0;
 
   Id id, *sp;
 
+  Id *keymap;  /* maps repo key to my key, 0 -> not used */
+  int nkeymap;
+  int *keymapstart;    /* maps repo number to keymap offset */
+
   Id *dirmap;
   int ndirmap;
   Id *keyused;
+
   unsigned char *repodataused;
   int anyrepodataused = 0;
+
+  int solvablestart, solvableend;
+  Id *solvschemata;
   int anysolvableused = 0;
+  int nsolvables;
 
   struct cbdata cbdata;
+
   int clonepool;
   Repokey *key;
-  int poolusage, dirpoolusage, idused, dirused;
+  int poolusage, dirpoolusage;
   int reloff;
 
   Repodata *data, *dirpooldata;
@@ -1063,14 +1171,15 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *
   Stringpool *spool;
   Dirpool *dirpool;
 
-  Id mainschema;
+  Id mainschema, *mainschemakeys;
 
   struct extdata *xd;
 
-  Id type_constantid = REPOKEY_TYPE_CONSTANTID;
+  Id type_constantid = 0;
 
 
   memset(&cbdata, 0, sizeof(cbdata));
+  cbdata.pool = pool;
   cbdata.repo = repo;
   cbdata.target = &target;
 
@@ -1078,48 +1187,50 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *
 
   /* go through all repodata and find the keys we need */
   /* also unify keys */
-  /*          keymapstart - maps repo number to keymap offset */
-  /*          keymap      - maps repo key to my key, 0 -> not used */
 
   /* start with all KEY_STORAGE_SOLVABLE ids */
 
   n = ID_NUM_INTERNAL;
   FOR_REPODATAS(repo, i, data)
     n += data->nkeys;
-  cbdata.keymap = solv_calloc(n, sizeof(Id));
-  cbdata.keymapstart = solv_calloc(repo->nrepodata, sizeof(Id));
+  nkeymap = n;
+  keymap = solv_calloc(nkeymap, sizeof(Id));
+  keymapstart = solv_calloc(repo->nrepodata, sizeof(Id));
   repodataused = solv_calloc(repo->nrepodata, 1);
 
   clonepool = 0;
   poolusage = 0;
 
-  /* add keys for STORAGE_SOLVABLE */
-  for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
+  if (!(writer->flags & REPOWRITER_NO_STORAGE_SOLVABLE))
     {
-      Repokey keyd;
-      keyd.name = i;
-      if (i < SOLVABLE_PROVIDES)
-        keyd.type = REPOKEY_TYPE_ID;
-      else if (i < RPM_RPMDBID)
+      /* add keys for STORAGE_SOLVABLE */
+      for (i = SOLVABLE_NAME; i <= RPM_RPMDBID; i++)
+       {
+         Repokey keyd;
+         keyd.name = i;
+         if (i < SOLVABLE_PROVIDES)
+           keyd.type = REPOKEY_TYPE_ID;
+         else if (i < RPM_RPMDBID)
 #ifdef USE_REL_IDARRAY
-        keyd.type = REPOKEY_TYPE_REL_IDARRAY;
+           keyd.type = REPOKEY_TYPE_REL_IDARRAY;
 #else
-        keyd.type = REPOKEY_TYPE_IDARRAY;
+           keyd.type = REPOKEY_TYPE_IDARRAY;
 #endif
-      else
-        keyd.type = REPOKEY_TYPE_NUM;
-      keyd.size = 0;
-      keyd.storage = KEY_STORAGE_SOLVABLE;
-      if (keyfilter)
-       {
-         keyd.storage = keyfilter(repo, &keyd, kfdata);
-         if (keyd.storage == KEY_STORAGE_DROPPED)
-           continue;
+         else
+           keyd.type = REPOKEY_TYPE_NUM;
+         keyd.size = 0;
          keyd.storage = KEY_STORAGE_SOLVABLE;
+         if (writer->keyfilter)
+           {
+             keyd.storage = writer->keyfilter(repo, &keyd, writer->kfdata);
+             if (keyd.storage == KEY_STORAGE_DROPPED)
+               continue;
+             keyd.storage = KEY_STORAGE_SOLVABLE;
+           }
+         poolusage = 1;
+         clonepool = 1;
+         keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
        }
-      poolusage = 1;
-      clonepool = 1;
-      cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
     }
 
   if (repo->nsolvables)
@@ -1129,7 +1240,7 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *
       keyd.type = REPOKEY_TYPE_FLEXARRAY;
       keyd.size = 0;
       keyd.storage = KEY_STORAGE_INCORE;
-      cbdata.keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
+      keymap[keyd.name] = repodata_key2id(&target, &keyd, 1);
     }
 
   dirpoolusage = 0;
@@ -1138,35 +1249,37 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *
   dirpool = 0;
   dirpooldata = 0;
   n = ID_NUM_INTERNAL;
-  lastfilelistn = 0;
   FOR_REPODATAS(repo, i, data)
     {
-      cbdata.keymapstart[i] = n;
-      cbdata.keymap[n++] = 0;  /* key 0 */
-      idused = 0;
-      dirused = 0;
-      if (keyfilter)
+      int idused, dirused;
+      if (i < writer->repodatastart || i >= writer->repodataend)
+       continue;
+      if (writer->keyfilter && (writer->flags & REPOWRITER_LEGACY) != 0)
        {
+         /* ask keyfilter if we want this repodata */
          Repokey keyd;
          /* check if we want this repodata */
          memset(&keyd, 0, sizeof(keyd));
          keyd.name = 1;
          keyd.type = 1;
          keyd.size = i;
-         if (keyfilter(repo, &keyd, kfdata) == -1)
+         if (writer->keyfilter(repo, &keyd, writer->kfdata) == -1)
            continue;
        }
+      keymapstart[i] = n;
+      keymap[n++] = 0; /* key 0 */
+      idused = dirused = 0;
       for (j = 1; j < data->nkeys; j++, n++)
        {
          key = data->keys + j;
          if (key->name == REPOSITORY_SOLVABLES && key->type == REPOKEY_TYPE_FLEXARRAY)
            {
-             cbdata.keymap[n] = cbdata.keymap[key->name];
+             keymap[n] = keymap[key->name];
              continue;
            }
-         if (key->type == REPOKEY_TYPE_DELETED)
+         if (key->type == REPOKEY_TYPE_DELETED && (writer->flags & REPOWRITER_KEEP_TYPE_DELETED) == 0)
            {
-             cbdata.keymap[n] = 0;
+             keymap[n] = 0;
              continue;
            }
          if (key->type == REPOKEY_TYPE_CONSTANTID && data->localpool)
@@ -1179,43 +1292,48 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *
            id = repodata_key2id(&target, key, 0);
          if (!id)
            {
+             /* a new key. ask keyfilter if we want it before creating it */
              Repokey keyd = *key;
              keyd.storage = KEY_STORAGE_INCORE;
              if (keyd.type == REPOKEY_TYPE_CONSTANTID)
                keyd.size = repodata_globalize_id(data, key->size, 1);
              else if (keyd.type != REPOKEY_TYPE_CONSTANT)
                keyd.size = 0;
-             if (keyfilter)
+             if (writer->keyfilter)
                {
-                 keyd.storage = keyfilter(repo, &keyd, kfdata);
+                 keyd.storage = writer->keyfilter(repo, &keyd, writer->kfdata);
                  if (keyd.storage == KEY_STORAGE_DROPPED)
                    {
-                     cbdata.keymap[n] = 0;
+                     keymap[n] = 0;
                      continue;
                    }
                }
-             id = repodata_key2id(&target, &keyd, 1);
+             if (data->state != REPODATA_STUB)
+               id = repodata_key2id(&target, &keyd, 1);
            }
-         cbdata.keymap[n] = id;
+         keymap[n] = id;
          /* load repodata if not already loaded */
          if (data->state == REPODATA_STUB)
            {
-             if (data->loadcallback)
-               data->loadcallback(data);
-             else
-               data->state = REPODATA_ERROR;
-             if (data->state != REPODATA_ERROR)
+             int oldnkeys = data->nkeys;
+             repodata_load(data);
+             if (oldnkeys != data->nkeys)
+               {
+                 nkeymap += data->nkeys - oldnkeys;            /* grow/shrink keymap */
+                 keymap = solv_realloc2(keymap, nkeymap, sizeof(Id));
+               }
+             if (data->state == REPODATA_AVAILABLE)
                {
                  /* redo this repodata! */
                  j = 0;
-                 n = cbdata.keymapstart[i];
+                 n = keymapstart[i];
                  continue;
                }
            }
-         if (data->state == REPODATA_ERROR)
+         if (data->state != REPODATA_AVAILABLE && data->state != REPODATA_LOADING)
            {
              /* too bad! */
-             cbdata.keymap[n] = 0;
+             keymap[n] = 0;
              continue;
            }
 
@@ -1229,20 +1347,6 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *
              idused = 1;       /* dirs also use ids */
              dirused = 1;
            }
-         if (key->type == REPOKEY_TYPE_DIRSTRARRAY && key->name == SOLVABLE_FILELIST)
-           {
-             /* is this a file list extension */
-             if (is_filelist_extension(data))
-               {
-                 /* hmm, we have a file list extension. Kill filelist of other repodata.
-                  * XXX: this is wrong, as the extension does not need to cover all
-                  * solvables of the other repodata */
-                 if (lastfilelistn)
-                   cbdata.keymap[lastfilelistn] = 0;
-               }
-             else
-               lastfilelistn = n;
-           }
        }
       if (idused)
        {
@@ -1276,20 +1380,24 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *
            }
        }
     }
-  cbdata.nkeymap = n;
+  nkeymap = n;         /* update */
 
   /* 0: no pool needed at all */
   /* 1: use global pool */
   /* 2: use repodata local pool */
   /* 3: need own pool */
+  if (poolusage != 3)
+    clonepool = 0;
   if (poolusage == 3)
     {
       spool = &target.spool;
+      target.localpool = 1;    /* so we can use repodata_translate */
       /* hack: reuse global pool data so we don't have to map pool ids */
       if (clonepool)
        {
          stringpool_free(spool);
          stringpool_clone(spool, &pool->ss);
+         cbdata.clonepool = 1;
        }
       cbdata.ownspool = spool;
     }
@@ -1301,6 +1409,10 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *
 
   if (dirpoolusage == 3)
     {
+      /* dirpoolusage == 3 means that at least two repodata
+       * areas have dir keys. This means that two areas have
+       * idused set to 1, which results in poolusage being
+       * either 1 (global pool) or 3 (own pool) */
       dirpool = &target.dirpool;
       dirpooldata = 0;
       cbdata.owndirpool = dirpool;
@@ -1313,196 +1425,110 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *
 #if 0
 fprintf(stderr, "poolusage: %d\n", poolusage);
 fprintf(stderr, "dirpoolusage: %d\n", dirpoolusage);
+fprintf(stderr, "clonepool: %d\n", clonepool);
 fprintf(stderr, "nkeys: %d\n", target.nkeys);
 for (i = 1; i < target.nkeys; i++)
   fprintf(stderr, "  %2d: %s[%d] %d %d %d\n", i, pool_id2str(pool, target.keys[i].name), target.keys[i].name, target.keys[i].type, target.keys[i].size, target.keys[i].storage);
 #endif
 
-  /* copy keys if requested */
-  if (keyq)
-    {
-      queue_empty(keyq);
-      for (i = 1; i < target.nkeys; i++)
-       queue_push2(keyq, target.keys[i].name, target.keys[i].type);
-    }
-
-  if (poolusage > 1)
-    {
-      /* put all the keys we need in our string pool */
-      /* put mapped ids right into target.keys */
-      for (i = 1, key = target.keys + i; i < target.nkeys; i++, key++)
-       {
-         key->name = stringpool_str2id(spool, pool_id2str(pool, key->name), 1);
-         if (key->type == REPOKEY_TYPE_CONSTANTID)
-           {
-             key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1);
-             type_constantid = key->type;
-             key->size = stringpool_str2id(spool, pool_id2str(pool, key->size), 1);
-           }
-         else
-           key->type = stringpool_str2id(spool, pool_id2str(pool, key->type), 1);
-       }
-      if (poolusage == 2)
-       stringpool_freehash(spool);     /* free some mem */
-    }
-
-
 /********************************************************************/
 
+  searchflags = SEARCH_SUB|SEARCH_ARRAYSENTINEL;
+  if ((writer->flags & REPOWRITER_KEEP_TYPE_DELETED) != 0)
+    searchflags |= SEARCH_KEEP_TYPE_DELETED;
+
   /* set needed count of all strings and rels,
    * find which keys are used in the solvables
    * put all strings in own spool
    */
 
   reloff = spool->nstrings;
-  if (poolusage == 3)
-    reloff = (reloff + NEEDED_BLOCK) & ~NEEDED_BLOCK;
+  if (cbdata.ownspool)
+    reloff = (reloff + NEEDID_BLOCK) & ~NEEDID_BLOCK;
+  else if (poolusage == 2)
+    {
+      /* we'll need to put the key data into the spool,
+       * so leave some room. 3 * nkeys is an upper bound */
+      reloff += 3 * target.nkeys;
+    }
 
   needid = calloc(reloff + pool->nrels, sizeof(*needid));
-  needid[0].map = reloff;
+  needid[0].map = reloff;      /* remember size in case we need to grow */
 
   cbdata.needid = needid;
-  cbdata.schema = solv_calloc(target.nkeys, sizeof(Id));
-  cbdata.sp = cbdata.schema;
-  cbdata.solvschemata = solv_calloc(repo->nsolvables, sizeof(Id));
+  cbdata.schema = solv_calloc(target.nkeys + 2, sizeof(Id));
 
   /* create main schema */
-  cbdata.sp = cbdata.schema;
-  /* collect all other data from all repodatas */
+  cbdata.sp = cbdata.schema + 1;
+
+  /* collect meta data from all repodatas */
   /* XXX: merge arrays of equal keys? */
+  keyskip = create_keyskip(repo, SOLVID_META, repodataused, &oldkeyskip);
   FOR_REPODATAS(repo, j, data)
     {
       if (!repodataused[j])
        continue;
-      repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
+      cbdata.keymap = keymap + keymapstart[j];
+      cbdata.lastdirid = 0;            /* clear dir mapping cache */
+      repodata_search_keyskip(data, SOLVID_META, 0, searchflags, keyskip, collect_needed_cb, &cbdata);
     }
+  needid = cbdata.needid;              /* maybe relocated */
   sp = cbdata.sp;
   /* add solvables if needed (may revert later) */
   if (repo->nsolvables)
     {
-      *sp++ = cbdata.keymap[REPOSITORY_SOLVABLES];
-      target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size++;
+      *sp++ = keymap[REPOSITORY_SOLVABLES];
+      target.keys[keymap[REPOSITORY_SOLVABLES]].size++;
     }
   *sp = 0;
-  mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1);
-
-  idarraydata = repo->idarraydata;
+  /* stash away main schema (including terminating zero) */
+  mainschemakeys = solv_memdup2(cbdata.schema + 1, sp - cbdata.schema, sizeof(Id));
 
+  /* collect data for all solvables */
+  solvschemata = solv_calloc(repo->nsolvables, sizeof(Id));    /* allocate upper bound */
+  solvablestart = writer->solvablestart < repo->start ? repo->start : writer->solvablestart;
+  solvableend = writer->solvableend > repo->end ? repo->end : writer->solvableend;
   anysolvableused = 0;
+  nsolvables = 0;              /* solvables we are going to write, will be <= repo->nsolvables */
   cbdata.doingsolvables = 1;
-  for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
+  for (i = solvablestart, s = pool->solvables + i; i < solvableend; i++, s++)
     {
       if (s->repo != repo)
        continue;
 
-      /* set schema info, keep in sync with further down */
-      sp = cbdata.schema;
-      if (cbdata.keymap[SOLVABLE_NAME])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_NAME];
-         needid[s->name].need++;
-       }
-      if (cbdata.keymap[SOLVABLE_ARCH])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_ARCH];
-         needid[s->arch].need++;
-       }
-      if (cbdata.keymap[SOLVABLE_EVR])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_EVR];
-         needid[s->evr].need++;
-       }
-      if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_VENDOR];
-         needid[s->vendor].need++;
-       }
-      if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
-        {
-          *sp++ = cbdata.keymap[SOLVABLE_PROVIDES];
-         target.keys[cbdata.keymap[SOLVABLE_PROVIDES]].size += incneedidarray(pool, idarraydata + s->provides, needid);
-       }
-      if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_OBSOLETES];
-         target.keys[cbdata.keymap[SOLVABLE_OBSOLETES]].size += incneedidarray(pool, idarraydata + s->obsoletes, needid);
-       }
-      if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_CONFLICTS];
-         target.keys[cbdata.keymap[SOLVABLE_CONFLICTS]].size += incneedidarray(pool, idarraydata + s->conflicts, needid);
-       }
-      if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_REQUIRES];
-         target.keys[cbdata.keymap[SOLVABLE_REQUIRES]].size += incneedidarray(pool, idarraydata + s->requires, needid);
-       }
-      if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_RECOMMENDS];
-         target.keys[cbdata.keymap[SOLVABLE_RECOMMENDS]].size += incneedidarray(pool, idarraydata + s->recommends, needid);
-       }
-      if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_SUGGESTS];
-         target.keys[cbdata.keymap[SOLVABLE_SUGGESTS]].size += incneedidarray(pool, idarraydata + s->suggests, needid);
-       }
-      if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_SUPPLEMENTS];
-         target.keys[cbdata.keymap[SOLVABLE_SUPPLEMENTS]].size += incneedidarray(pool, idarraydata + s->supplements, needid);
-       }
-      if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
-       {
-          *sp++ = cbdata.keymap[SOLVABLE_ENHANCES];
-         target.keys[cbdata.keymap[SOLVABLE_ENHANCES]].size += incneedidarray(pool, idarraydata + s->enhances, needid);
-       }
-      if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
-       {
-          *sp++ = cbdata.keymap[RPM_RPMDBID];
-         target.keys[cbdata.keymap[RPM_RPMDBID]].size++;
-       }
-      cbdata.sp = sp;
+      cbdata.sp = cbdata.schema + 1;
+      collect_needed_solvable(&cbdata, s, keymap);
 
       if (anyrepodataused)
        {
+         keyskip = create_keyskip(repo, i, repodataused, &oldkeyskip);
          FOR_REPODATAS(repo, j, data)
            {
-             if (!repodataused[j])
-               continue;
-             if (i < data->start || i >= data->end)
+             if (!repodataused[j] || i < data->start || i >= data->end)
                continue;
-             repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_needed, &cbdata);
-             needid = cbdata.needid;
+             cbdata.keymap = keymap + keymapstart[j];
+             cbdata.lastdirid = 0;
+             repodata_search_keyskip(data, i, 0, searchflags, keyskip, collect_needed_cb, &cbdata);
            }
+         needid = cbdata.needid;               /* maybe relocated */
        }
       *cbdata.sp = 0;
-      cbdata.solvschemata[n] = repodata_schema2id(cbdata.target, cbdata.schema, 1);
-      if (cbdata.solvschemata[n])
+      solvschemata[nsolvables] = repodata_schema2id(cbdata.target, cbdata.schema + 1, 1);
+      if (solvschemata[nsolvables])
        anysolvableused = 1;
-      n++;
+      nsolvables++;
     }
   cbdata.doingsolvables = 0;
-  assert(n == repo->nsolvables);
 
   if (repo->nsolvables && !anysolvableused)
     {
-      /* strip off solvable from the main schema */
-      target.keys[cbdata.keymap[REPOSITORY_SOLVABLES]].size = 0;
-      sp = cbdata.schema;
-      for (i = 0; target.schemadata[target.schemata[mainschema] + i]; i++)
-       {
-         *sp = target.schemadata[target.schemata[mainschema] + i];
-         if (*sp != cbdata.keymap[REPOSITORY_SOLVABLES])
-           sp++;
-       }
-      assert(target.schemadatalen == target.schemata[mainschema] + i + 1);
-      *sp = 0;
-      target.schemadatalen = target.schemata[mainschema];
-      target.nschemata--;
-      repodata_free_schemahash(&target);
-      mainschema = repodata_schema2id(cbdata.target, cbdata.schema, 1);
+      /* strip off REPOSITORY_SOLVABLES from the main schema */
+      for (sp = mainschemakeys; *sp; sp++)
+       ;
+      sp[-1] = 0;      /* strip last entry */
     }
+  mainschema = repodata_schema2id(cbdata.target, mainschemakeys, 1);
+  mainschemakeys = solv_free(mainschemakeys);
 
 /********************************************************************/
 
@@ -1515,32 +1541,78 @@ for (i = 1; i < target.nkeys; i++)
     {
       if (!keyused[i])
        continue;
-      keyused[i] = n;
       if (i != n)
-       {
-         target.keys[n] = target.keys[i];
-         if (keyq)
-           {
-             keyq->elements[2 * n - 2] = keyq->elements[2 * i - 2];
-             keyq->elements[2 * n - 1] = keyq->elements[2 * i - 1];
-           }
-       }
-      n++;
+       target.keys[n] = target.keys[i];
+      keyused[i] = n++;
     }
   target.nkeys = n;
-  if (keyq)
-    queue_truncate(keyq, 2 * n - 2);
 
   /* update schema data to the new key ids */
   for (i = 1; i < (int)target.schemadatalen; i++)
     target.schemadata[i] = keyused[target.schemadata[i]];
   /* update keymap to the new key ids */
-  for (i = 0; i < cbdata.nkeymap; i++)
-    cbdata.keymap[i] = keyused[cbdata.keymap[i]];
+  for (i = 0; i < nkeymap; i++)
+    keymap[i] = keyused[keymap[i]];
   keyused = solv_free(keyused);
 
-  /* increment needid of the used keys, they are already mapped to
-   * the correct string pool  */
+  /* copy keys if requested */
+  if (writer->keyq)
+    {
+      queue_empty(writer->keyq);
+      for (i = 1; i < target.nkeys; i++)
+       queue_push2(writer->keyq, target.keys[i].name, target.keys[i].type);
+    }
+
+/********************************************************************/
+
+  /* check if we can do the special filelist memory optimization
+   * we do the check before the keys are mapped.
+   * The optimization is done if there is just one vertical key and
+   * it is of type REPOKEY_TYPE_DIRSTRARRAY */
+  if (anysolvableused && anyrepodataused)
+    {
+      for (i = 1; i < target.nkeys; i++)
+       {
+         if (target.keys[i].storage != KEY_STORAGE_VERTICAL_OFFSET)
+           continue;
+         if (target.keys[i].type != REPOKEY_TYPE_DIRSTRARRAY || cbdata.filelistmode != 0)
+           {
+             cbdata.filelistmode = 0;
+             break;
+           }
+         cbdata.filelistmode = i;
+       }
+    }
+
+/********************************************************************/
+
+  if (poolusage > 1)
+    {
+      /* put all the keys in our string pool */
+      /* put mapped ids right into target.keys */
+      for (i = 1, key = target.keys + i; i < target.nkeys; i++, key++)
+       {
+         key->name = stringpool_str2id(spool, pool_id2str(pool, key->name), 1);
+         id = stringpool_str2id(spool, pool_id2str(pool, key->type), 1);
+         if (key->type == REPOKEY_TYPE_CONSTANTID)
+           {
+             type_constantid = id;
+             key->size = stringpool_str2id(spool, pool_id2str(pool, key->size), 1);
+           }
+         key->type = id;
+       }
+      if (poolusage == 2)
+       stringpool_freehash(spool);     /* free some mem */
+      if (cbdata.ownspool && spool->nstrings > needid[0].map)
+       {
+         grow_needid(&cbdata, spool->nstrings - 1);
+         needid = cbdata.needid;               /* we relocated */
+       }
+    }
+  else
+    type_constantid = REPOKEY_TYPE_CONSTANTID;
+
+  /* increment needid of the keys */
   for (i = 1; i < target.nkeys; i++)
     {
       if (target.keys[i].type == type_constantid)
@@ -1551,41 +1623,116 @@ for (i = 1; i < target.nkeys; i++)
 
 /********************************************************************/
 
-  if (dirpool && cbdata.dirused && !cbdata.dirused[0])
+  /* increment need id of all relations
+   * if we refer to another relation, make sure that the
+   * need value is it is bigger than our value so that
+   * ordering works.
+   */
+  reloff = needid[0].map;
+  for (i = pool->nrels - 1, needidp = needid + (reloff + i); i > 0; i--, needidp--)
+    if (needidp->need)
+      break;
+  if (i)
     {
-      /* no dirs used at all */
-      cbdata.dirused = solv_free(cbdata.dirused);
-      dirpool = 0;
-    }
+      /* we have some relations with a non-zero need */
+      Reldep *rd;
+
+      for (rd = pool->rels + i; i > 1; i--, rd--)
+       {
+         int need = needid[reloff + i].need;
+         if (!need)
+           continue;
+         id = rd->name;
+         if (ISRELDEP(id))
+           {
+             id = GETRELID(id);
+             if (needid[reloff + id].need < need + 1)
+               needid[reloff + id].need = need + 1;
+           }
+         else
+           {
+             if (cbdata.ownspool && id > 1 && !cbdata.clonepool)
+               {
+                 id = stringpool_str2id(cbdata.ownspool, pool_id2str(pool, id), 1);
+                 if (id >= cbdata.needid[0].map)
+                   {
+                     grow_needid(&cbdata, id);
+                     needid = cbdata.needid;           /* we relocated */
+                     reloff = needid[0].map;           /* we have a new offset */
+                   }
+               }
+             needid[id].need++;
+           }
+
+         id = rd->evr;
+         if (ISRELDEP(id))
+           {
+             id = GETRELID(id);
+             if (needid[reloff + id].need < need + 1)
+               needid[reloff + id].need = need + 1;
+           }
+         else
+           {
+             if (cbdata.ownspool && id > 1 && !cbdata.clonepool)
+               {
+                 id = stringpool_str2id(cbdata.ownspool, pool_id2str(pool, id), 1);
+                 if (id >= cbdata.needid[0].map)
+                   {
+                     grow_needid(&cbdata, id);
+                     needid = cbdata.needid;           /* we relocated */
+                     reloff = needid[0].map;           /* we have a new offset */
+                   }
+               }
+             needid[id].need++;
+           }
+       }
+  }
+
+/********************************************************************/
 
   /* increment need id for used dir components */
-  if (dirpool)
+  if (cbdata.owndirpool)
     {
       /* if we have own dirpool, all entries in it are used.
         also, all comp ids are already mapped by putinowndirpool(),
         so we can simply increment needid.
         (owndirpool != 0, dirused == 0, dirpooldata == 0) */
+      for (i = 1; i < dirpool->ndirs; i++)
+       {
+         id = dirpool->dirs[i];
+         if (id <= 0)
+           continue;
+         needid[id].need++;
+       }
+    }
+  else if (dirpool)
+    {
+      Id parent;
       /* else we re-use a dirpool of repodata "dirpooldata".
         dirused tells us which of the ids are used.
         we need to map comp ids if we generate a new pool.
         (owndirpool == 0, dirused != 0, dirpooldata != 0) */
-      for (i = 1; i < dirpool->ndirs; i++)
+      for (i = dirpool->ndirs - 1; i > 0; i--)
        {
-#if 0
-fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
-#endif
-         if (cbdata.dirused && !cbdata.dirused[i])
+         if (!cbdata.dirused[i])
            continue;
+         parent = dirpool_parent(dirpool, i);  /* always < i */
+         cbdata.dirused[parent] = 2;           /* 2: used as parent */
          id = dirpool->dirs[i];
          if (id <= 0)
            continue;
-         if (dirpooldata && cbdata.ownspool && id > 1)
+         if (cbdata.ownspool && id > 1 && (!cbdata.clonepool || dirpooldata->localpool))
            {
-             id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
+             id = putinownpool(&cbdata, dirpooldata, id);
              needid = cbdata.needid;
            }
          needid[id].need++;
        }
+      if (!cbdata.dirused[0])
+       {
+          cbdata.dirused = solv_free(cbdata.dirused);
+          dirpool = 0;
+       }
     }
 
 
@@ -1606,13 +1753,9 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
   for (i = 1; i < reloff + pool->nrels; i++)
     needid[i].map = i;
 
-#if 0
-  solv_sort(needid + 1, spool->nstrings - 1, sizeof(*needid), needid_cmp_need_s, spool);
-#else
   /* make first entry '' */
   needid[1].need = 1;
   solv_sort(needid + 2, spool->nstrings - 2, sizeof(*needid), needid_cmp_need_s, spool);
-#endif
   solv_sort(needid + reloff, pool->nrels, sizeof(*needid), needid_cmp_need, 0);
   /* now needid is in new order, needid[newid].map -> oldid */
 
@@ -1652,7 +1795,7 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
 
   ndirmap = 0;
   dirmap = 0;
-  if (dirpool)
+  if (dirpool && dirpool->ndirs)
     {
       /* create our new target directory structure by traversing through all
        * used dirs. This will concatenate blocks with the same parent
@@ -1661,7 +1804,10 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
        * we will change this in the second step below */
       /* (dirpooldata and dirused are 0 if we have our own dirpool) */
       if (cbdata.dirused && !cbdata.dirused[1])
-       cbdata.dirused[1] = 1;  /* always want / entry */
+       {
+         cbdata.dirused[1] = 1;        /* always want / entry */
+         cbdata.dirused[0] = 2;        /* always want / entry */
+       }
       dirmap = solv_calloc(dirpool->ndirs, sizeof(Id));
       dirmap[0] = 0;
       ndirmap = traverse_dirs(dirpool, dirmap, 1, dirpool_child(dirpool, 0), cbdata.dirused);
@@ -1678,7 +1824,7 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
          cbdata.dirused[dirmap[i]] = i;
          id = dirpool->dirs[dirmap[i]];
          if (dirpooldata && cbdata.ownspool && id > 1)
-           id = putinownpool(&cbdata, dirpooldata->localpool ? &dirpooldata->spool : &pool->ss, id);
+           id = putinownpool(&cbdata, dirpooldata, id);
          dirmap[i] = needid[id].need;
        }
       /* now the new target directory structure is complete (dirmap), and we have
@@ -1689,6 +1835,8 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
 
   /* collect all data
    * we use extdata[0] for incore data and extdata[keyid] for vertical data
+   *
+   * this must match the code above that creates the schema data!
    */
 
   cbdata.extdata = solv_calloc(target.nkeys, sizeof(struct extdata));
@@ -1699,77 +1847,41 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
   cbdata.lastlen = 0;
   data_addid(xd, mainschema);
 
-#if 1
+  keyskip = create_keyskip(repo, SOLVID_META, repodataused, &oldkeyskip);
   FOR_REPODATAS(repo, j, data)
     {
       if (!repodataused[j])
        continue;
-      repodata_search(data, SOLVID_META, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
+      cbdata.keymap = keymap + keymapstart[j];
+      cbdata.lastdirid = 0;
+      repodata_search_keyskip(data, SOLVID_META, 0, searchflags, keyskip, collect_data_cb, &cbdata);
     }
-#endif
-
   if (xd->len - cbdata.lastlen > cbdata.maxdata)
     cbdata.maxdata = xd->len - cbdata.lastlen;
   cbdata.lastlen = xd->len;
 
   if (anysolvableused)
     {
-      data_addid(xd, repo->nsolvables);        /* FLEXARRAY nentries */
+      data_addid(xd, nsolvables);      /* FLEXARRAY nentries */
       cbdata.doingsolvables = 1;
 
-      /* check if we can do the special filelist memory optimization */
-      if (anyrepodataused)
-       {
-         for (i = 1; i < target.nkeys; i++)
-           if (target.keys[i].storage == KEY_STORAGE_VERTICAL_OFFSET)
-             cbdata.filelistmode |= cbdata.filelistmode == 0 && target.keys[i].type == REPOKEY_TYPE_DIRSTRARRAY ? 1 : 2;
-           else if (target.keys[i].type == REPOKEY_TYPE_DIRSTRARRAY)
-             cbdata.filelistmode = 2;
-         if (cbdata.filelistmode != 1)
-           cbdata.filelistmode = 0;
-       }
-
-      for (i = repo->start, s = pool->solvables + i, n = 0; i < repo->end; i++, s++)
+      for (i = solvablestart, s = pool->solvables + i, n = 0; i < solvableend; i++, s++)
        {
          if (s->repo != repo)
            continue;
-         data_addid(xd, cbdata.solvschemata[n]);
-         if (cbdata.keymap[SOLVABLE_NAME])
-           data_addid(xd, needid[s->name].need);
-         if (cbdata.keymap[SOLVABLE_ARCH])
-           data_addid(xd, needid[s->arch].need);
-         if (cbdata.keymap[SOLVABLE_EVR])
-           data_addid(xd, needid[s->evr].need);
-         if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
-           data_addid(xd, needid[s->vendor].need);
-         if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
-           data_adddepids(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
-         if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
-           data_adddepids(xd, pool, needid, idarraydata + s->obsoletes, 0);
-         if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
-           data_adddepids(xd, pool, needid, idarraydata + s->conflicts, 0);
-         if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
-           data_adddepids(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
-         if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
-           data_adddepids(xd, pool, needid, idarraydata + s->recommends, 0);
-         if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
-           data_adddepids(xd, pool, needid, idarraydata + s->suggests, 0);
-         if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
-           data_adddepids(xd, pool, needid, idarraydata + s->supplements, 0);
-         if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
-           data_adddepids(xd, pool, needid, idarraydata + s->enhances, 0);
-         if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
-           data_addid(xd, repo->rpmdbid[i - repo->start]);
+         data_addid(xd, solvschemata[n]);
+          collect_data_solvable(&cbdata, s, keymap);
          if (anyrepodataused)
            {
+             keyskip = create_keyskip(repo, i, repodataused, &oldkeyskip);
              cbdata.vstart = -1;
              FOR_REPODATAS(repo, j, data)
                {
-                 if (!repodataused[j])
-                   continue;
-                 if (i < data->start || i >= data->end)
+                 if (!repodataused[j] || i < data->start || i >= data->end)
                    continue;
-                 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
+                 cbdata.keymap = keymap + keymapstart[j];
+                 cbdata.lastdirid = 0;
+                 repodata_search_keyskip(data, i, 0, searchflags, keyskip, collect_data_cb, &cbdata);
                }
            }
          if (xd->len - cbdata.lastlen > cbdata.maxdata)
@@ -1781,11 +1893,8 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
     }
 
   assert(cbdata.current_sub == cbdata.nsubschemata);
-  if (cbdata.subschemata)
-    {
-      cbdata.subschemata = solv_free(cbdata.subschemata);
-      cbdata.nsubschemata = 0;
-    }
+  cbdata.subschemata = solv_free(cbdata.subschemata);
+  cbdata.nsubschemata = 0;
 
 /********************************************************************/
 
@@ -1802,7 +1911,7 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
   write_u32(&target, nstrings);
   write_u32(&target, nrels);
   write_u32(&target, ndirmap);
-  write_u32(&target, anysolvableused ? repo->nsolvables : 0);
+  write_u32(&target, anysolvableused ? nsolvables : 0);
   write_u32(&target, target.nkeys);
   write_u32(&target, target.nschemata);
   solv_flags = 0;
@@ -1857,9 +1966,9 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
    */
   for (i = 0; i < nrels; i++)
     {
-      ran = pool->rels + (needid[reloff + i].map - reloff);
-      write_id(&target, needid[ISRELDEP(ran->name) ? RELOFF(ran->name) : ran->name].need);
-      write_id(&target, needid[ISRELDEP(ran->evr) ? RELOFF(ran->evr) : ran->evr].need);
+      Reldep *ran = pool->rels + (needid[reloff + i].map - reloff);
+      write_id(&target, needid[NEEDIDOFF(ran->name)].need);
+      write_id(&target, needid[NEEDIDOFF(ran->evr)].need);
       write_u8(&target, ran->flags);
     }
 
@@ -1901,52 +2010,60 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
   for (i = 1; i < target.nschemata; i++)
     write_idarray(&target, pool, 0, repodata_id2schema(&target, i));
 
-/********************************************************************/
-
+  /*
+   * write incore data
+   */
   write_id(&target, cbdata.maxdata);
   write_id(&target, cbdata.extdata[0].len);
   if (cbdata.extdata[0].len)
     write_blob(&target, cbdata.extdata[0].buf, cbdata.extdata[0].len);
   solv_free(cbdata.extdata[0].buf);
 
-  /* do we have vertical data? */
+  /*
+   * write vertical data if we have any
+   */
   for (i = 1; i < target.nkeys; i++)
     if (cbdata.extdata[i].len)
       break;
   if (i < target.nkeys)
     {
-      /* yes, write it in pages */
+      /* have vertical data, write it in pages */
       unsigned char vpage[REPOPAGE_BLOBSIZE];
       int lpage = 0;
 
       write_u32(&target, REPOPAGE_BLOBSIZE);
-      for (i = 1; i < target.nkeys; i++)
-       if (cbdata.extdata[i].len)
-         {
-           if (cbdata.filelistmode)
-             break;
-           lpage = write_compressed_extdata(&target, cbdata.extdata + i, vpage, lpage);
-         }
-      if (cbdata.filelistmode && i < target.nkeys)
+      if (!cbdata.filelistmode)
        {
-         /* ok, just this single extdata, which is a filelist */
+         for (i = 1; i < target.nkeys; i++)
+           if (cbdata.extdata[i].len)
+             lpage = write_compressed_extdata(&target, cbdata.extdata + i, vpage, lpage);
+       }
+      else
+       {
+         /* ok, just one single extdata which is of type REPOKEY_TYPE_DIRSTRARRAY */
          xd = cbdata.extdata + i;
          xd->len = 0;
-         cbdata.filelistmode = -1;
-         for (j = 0; j < cbdata.nkeymap; j++)
-           if (cbdata.keymap[j] != i)
-             cbdata.keymap[j] = 0;
-         for (i = repo->start, s = pool->solvables + i; i < repo->end; i++, s++)
+         keyskip = create_keyskip(repo, SOLVID_META, repodataused, &oldkeyskip);
+         FOR_REPODATAS(repo, j, data)
+           {
+             if (!repodataused[j])
+               continue;
+             cbdata.keymap = keymap + keymapstart[j];
+             cbdata.lastdirid = 0;
+             repodata_search_keyskip(data, SOLVID_META, 0, searchflags, keyskip, collect_filelist_cb, &cbdata);
+           }
+         for (i = solvablestart, s = pool->solvables + i; i < solvableend; i++, s++)
            {
              if (s->repo != repo)
                continue;
+             keyskip = create_keyskip(repo, i, repodataused, &oldkeyskip);
              FOR_REPODATAS(repo, j, data)
                {
-                 if (!repodataused[j])
+                 if (!repodataused[j] || i < data->start || i >= data->end)
                    continue;
-                 if (i < data->start || i >= data->end)
-                   continue;
-                 repodata_search(data, i, 0, SEARCH_SUB|SEARCH_ARRAYSENTINEL, repo_write_cb_adddata, &cbdata);
+                 cbdata.keymap = keymap + keymapstart[j];
+                 cbdata.lastdirid = 0;
+                 repodata_search_keyskip(data, i, 0, searchflags, keyskip, collect_filelist_cb, &cbdata);
                }
              if (xd->len > 1024 * 1024)
                {
@@ -1969,56 +2086,64 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
   repodata_freedata(&target);
 
   solv_free(needid);
-  solv_free(cbdata.solvschemata);
+  solv_free(solvschemata);
   solv_free(cbdata.schema);
 
-  solv_free(cbdata.keymap);
-  solv_free(cbdata.keymapstart);
+  solv_free(keymap);
+  solv_free(keymapstart);
   solv_free(cbdata.dirused);
   solv_free(repodataused);
+  solv_free(oldkeyskip);
   return target.error;
 }
 
-struct repodata_write_data {
-  int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata);
-  void *kfdata;
-  int repodataid;
-};
-
-static int
-repodata_write_keyfilter(Repo *repo, Repokey *key, void *kfdata)
+int
+repo_write(Repo *repo, FILE *fp)
 {
-  struct repodata_write_data *wd = kfdata;
-
-  /* XXX: special repodata selection hack */
-  if (key->name == 1 && key->size != wd->repodataid)
-    return -1;
-  if (key->storage == KEY_STORAGE_SOLVABLE)
-    return KEY_STORAGE_DROPPED;        /* not part of this repodata */
-  if (wd->keyfilter)
-    return (*wd->keyfilter)(repo, key, wd->kfdata);
-  return key->storage;
+  int res;
+  Repowriter *writer = repowriter_create(repo);
+  res = repowriter_write(writer, fp);
+  repowriter_free(writer);
+  return res;
 }
 
 int
-repodata_write_filtered(Repodata *data, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
+repodata_write(Repodata *data, FILE *fp)
 {
-  struct repodata_write_data wd;
-
-  wd.keyfilter = keyfilter;
-  wd.kfdata = kfdata;
-  wd.repodataid = data->repodataid;
-  return repo_write_filtered(data->repo, fp, repodata_write_keyfilter, &wd, keyq);
+  int res;
+  Repowriter *writer = repowriter_create(data->repo);
+  repowriter_set_repodatarange(writer, data->repodataid, data->repodataid + 1);
+  repowriter_set_flags(writer, REPOWRITER_NO_STORAGE_SOLVABLE);
+  res = repowriter_write(writer, fp);
+  repowriter_free(writer);
+  return res;
 }
 
+/* deprecated functions, do not use in new code! */
 int
-repodata_write(Repodata *data, FILE *fp)
+repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
 {
-  return repodata_write_filtered(data, fp, repo_write_stdkeyfilter, 0, 0);
+  int res;
+  Repowriter *writer = repowriter_create(repo);
+  repowriter_set_flags(writer, REPOWRITER_LEGACY);
+  repowriter_set_keyfilter(writer, keyfilter, kfdata);
+  repowriter_set_keyqueue(writer, keyq);
+  res = repowriter_write(writer, fp);
+  repowriter_free(writer);
+  return res;
 }
 
 int
-repo_write(Repo *repo, FILE *fp)
+repodata_write_filtered(Repodata *data, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq)
 {
-  return repo_write_filtered(repo, fp, repo_write_stdkeyfilter, 0, 0);
+  int res;
+  Repowriter *writer = repowriter_create(data->repo);
+  repowriter_set_repodatarange(writer, data->repodataid, data->repodataid + 1);
+  repowriter_set_flags(writer, REPOWRITER_NO_STORAGE_SOLVABLE | REPOWRITER_LEGACY);
+  repowriter_set_keyfilter(writer, keyfilter, kfdata);
+  repowriter_set_keyqueue(writer, keyq);
+  res = repowriter_write(writer, fp);
+  repowriter_free(writer);
+  return res;
 }
+
index 763147e..3471670 100644 (file)
 extern "C" {
 #endif
 
-extern int repo_write(Repo *repo, FILE *fp);
-extern int repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq);
+typedef struct s_Repowriter {
+  Repo *repo;
+  int flags;
+  int repodatastart;
+  int repodataend;
+  int solvablestart;
+  int solvableend;
+  int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata);
+  void *kfdata;
+  Queue *keyq;
+} Repowriter;
+
+/* repowriter flags */
+#define REPOWRITER_NO_STORAGE_SOLVABLE (1 << 0)
+#define REPOWRITER_KEEP_TYPE_DELETED   (1 << 1)
+#define REPOWRITER_LEGACY              (1 << 30)
 
+Repowriter *repowriter_create(Repo *repo);
+Repowriter *repowriter_free(Repowriter *writer);
+void repowriter_set_flags(Repowriter *writer, int flags);
+void repowriter_set_keyfilter(Repowriter *writer, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata);
+void repowriter_set_keyqueue(Repowriter *writer, Queue *keyq);
+void repowriter_set_repodatarange(Repowriter *writer, int repodatastart, int repodataend);
+void repowriter_set_solvablerange(Repowriter *writer, int solvablestart, int solvableend);
+int repowriter_write(Repowriter *writer, FILE *fp);
+
+/* convenience functions */
+extern int repo_write(Repo *repo, FILE *fp);
 extern int repodata_write(Repodata *data , FILE *fp);
-extern int repodata_write_filtered(Repodata *data , FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq);
 
 extern int repo_write_stdkeyfilter(Repo *repo, Repokey *key, void *kfdata);
 
+/* deprecated functions, do not use in new code! */
+extern int repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq);
+extern int repodata_write_filtered(Repodata *data , FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Queue *keyq);
+
 #ifdef __cplusplus
 }
 #endif
index 4ab5d18..71e8175 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, Novell Inc.
+ * Copyright (c) 2018, SUSE LLC.
  *
  * This program is licensed under the BSD license, read LICENSE.BSD
  * for further information
@@ -94,6 +94,8 @@ repodata_freedata(Repodata *data)
   solv_free(data->attrnum64data);
 
   solv_free(data->dircache);
+
+  repodata_free_filelistfilter(data);
 }
 
 void
@@ -518,17 +520,36 @@ get_data(Repodata *data, Repokey *key, unsigned char **dpp, int advance)
   return 0;
 }
 
-static int
-load_repodata(Repodata *data)
+void
+repodata_load(Repodata *data)
 {
+  if (data->state != REPODATA_STUB)
+    return;
   if (data->loadcallback)
+    data->loadcallback(data);
+  else
+    data->state = REPODATA_ERROR;
+}
+
+static int
+maybe_load_repodata_stub(Repodata *data, Id keyname)
+{
+  if (data->state != REPODATA_STUB)
     {
-      data->loadcallback(data);
-      if (data->state == REPODATA_AVAILABLE)
-       return 1;
+      data->state = REPODATA_ERROR;
+      return 0;
     }
-  data->state = REPODATA_ERROR;
-  return 0;
+  if (keyname)
+    {
+      int i;
+      for (i = 1; i < data->nkeys; i++)
+       if (keyname == data->keys[i].name)
+         break;
+      if (i == data->nkeys)
+       return 0;
+    }
+  repodata_load(data);
+  return data->state == REPODATA_AVAILABLE ? 1 : 0;
 }
 
 static inline int
@@ -536,28 +557,11 @@ maybe_load_repodata(Repodata *data, Id keyname)
 {
   if (keyname && !repodata_precheck_keyname(data, keyname))
     return 0;  /* do not bother... */
-  switch(data->state)
-    {
-    case REPODATA_STUB:
-      if (keyname)
-       {
-         int i;
-         for (i = 1; i < data->nkeys; i++)
-           if (keyname == data->keys[i].name)
-             break;
-         if (i == data->nkeys)
-           return 0;
-       }
-      return load_repodata(data);
-    case REPODATA_ERROR:
-      return 0;
-    case REPODATA_AVAILABLE:
-    case REPODATA_LOADING:
-      return 1;
-    default:
-      data->state = REPODATA_ERROR;
-      return 0;
-    }
+  if (data->state == REPODATA_AVAILABLE || data->state == REPODATA_LOADING)
+    return 1;
+  if (data->state == REPODATA_ERROR)
+    return 0;
+  return maybe_load_repodata_stub(data, keyname);
 }
 
 static inline unsigned char *
@@ -626,6 +630,53 @@ find_key_data(Repodata *data, Id solvid, Id keyname, Repokey **keypp)
   return get_data(data, key, &dp, 0);
 }
 
+static const Id *
+repodata_lookup_schemakeys(Repodata *data, Id solvid)
+{
+  Id schema;
+  if (!maybe_load_repodata(data, 0))
+    return 0;
+  if (!solvid2data(data, solvid, &schema))
+    return 0;
+  return data->schemadata + data->schemata[schema];
+}
+
+static Id *
+alloc_keyskip()
+{
+  Id *keyskip = solv_calloc(3 + 256, sizeof(Id));
+  keyskip[0] = 256; 
+  keyskip[1] = keyskip[2] = 1; 
+  return keyskip;
+}
+
+Id *
+repodata_fill_keyskip(Repodata *data, Id solvid, Id *keyskip)
+{
+  const Id *keyp;
+  Id maxkeyname, value;
+  keyp = repodata_lookup_schemakeys(data, solvid);
+  if (!keyp)
+    return keyskip;    /* no keys for this solvid */
+  if (!keyskip)
+    keyskip = alloc_keyskip();
+  maxkeyname = keyskip[0];
+  value = keyskip[1] + data->repodataid;
+  for (; *keyp; keyp++)
+    {
+      Id keyname = data->keys[*keyp].name;
+      if (keyname >= maxkeyname)
+       {
+         int newmax = (keyname | 255) + 1; 
+         keyskip = solv_realloc2(keyskip, 3 + newmax, sizeof(Id));
+         memset(keyskip + (3 + maxkeyname), 0, (newmax - maxkeyname) * sizeof(Id));
+         keyskip[0] = maxkeyname = newmax;
+       }
+      keyskip[3 + keyname] = value;
+    }
+  return keyskip;
+}
+
 Id
 repodata_lookup_type(Repodata *data, Id solvid, Id keyname)
 {
@@ -682,52 +733,32 @@ repodata_lookup_str(Repodata *data, Id solvid, Id keyname)
   return pool_id2str(data->repo->pool, id);
 }
 
-int
-repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value)
+unsigned long long
+repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long notfound)
 {
   unsigned char *dp;
   Repokey *key;
   unsigned int high, low;
 
-  *value = 0;
   dp = find_key_data(data, solvid, keyname, &key);
   if (!dp)
-    return 0;
+    return notfound;
   switch (key->type)
     {
     case REPOKEY_TYPE_NUM:
       data_read_num64(dp, &low, &high);
-      *value = (unsigned long long)high << 32 | low;
-      return 1;
-    case REPOKEY_TYPE_U32:
-      data_read_u32(dp, &low);
-      *value = low;
-      return 1;
+      return (unsigned long long)high << 32 | low;
     case REPOKEY_TYPE_CONSTANT:
-      *value = key->size;
-      return 1;
+      return key->size;
     default:
-      return 0;
+      return notfound;
     }
 }
 
 int
 repodata_lookup_void(Repodata *data, Id solvid, Id keyname)
 {
-  Id schema;
-  Id *keyp;
-  unsigned char *dp;
-
-  if (!maybe_load_repodata(data, keyname))
-    return 0;
-  dp = solvid2data(data, solvid, &schema);
-  if (!dp)
-    return 0;
-  /* can't use find_key_data as we need to test the type */
-  for (keyp = data->schemadata + data->schemata[schema]; *keyp; keyp++)
-    if (data->keys[*keyp].name == keyname && data->keys[*keyp].type == REPOKEY_TYPE_VOID)
-      return 1;
-  return 0;
+  return repodata_lookup_type(data, solvid, keyname) == REPOKEY_TYPE_VOID ? 1 : 0;
 }
 
 const unsigned char *
@@ -760,9 +791,7 @@ repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q)
 
   queue_empty(q);
   dp = find_key_data(data, solvid, keyname, &key);
-  if (!dp)
-    return 0;
-  if (key->type != REPOKEY_TYPE_IDARRAY)
+  if (!dp || key->type != REPOKEY_TYPE_IDARRAY)
     return 0;
   for (;;)
     {
@@ -792,6 +821,48 @@ repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp)
   return dp;
 }
 
+/* highly specialized function to speed up fileprovides adding.
+ * - repodata must be available
+ * - solvid must be >= data->start and < data->end
+ * - returns NULL is not found, a "" entry if wrong type
+ * - also returns wrong type for REPOKEY_TYPE_DELETED
+ */
+const unsigned char *
+repodata_lookup_packed_dirstrarray(Repodata *data, Id solvid, Id keyname)
+{
+  static unsigned char wrongtype[2] = { 0x00 /* dir id 0 */, 0 /* "" */ };
+  unsigned char *dp;
+  Id schema, *keyp, *kp;
+  Repokey *key;
+
+  if (!data->incoredata || !data->incoreoffset[solvid - data->start])
+    return 0;
+  dp = data->incoredata + data->incoreoffset[solvid - data->start];
+  dp = data_read_id(dp, &schema);
+  keyp = data->schemadata + data->schemata[schema];
+  for (kp = keyp; *kp; kp++)
+    if (data->keys[*kp].name == keyname)
+      break;
+  if (!*kp)
+    return 0;
+  key = data->keys + *kp;
+  if (key->type != REPOKEY_TYPE_DIRSTRARRAY)
+    return wrongtype;
+  dp = forward_to_key(data, *kp, keyp, dp);
+  if (key->storage == KEY_STORAGE_INCORE)
+    return dp;
+  if (key->storage == KEY_STORAGE_VERTICAL_OFFSET && dp)
+    {
+      Id off, len;
+      dp = data_read_id(dp, &off);
+      data_read_id(dp, &len);
+      return get_vertical_data(data, key, off, len);
+    }
+  return 0;
+}
+
+/* id translation functions */
+
 Id
 repodata_globalize_id(Repodata *data, Id id, int create)
 {
@@ -811,97 +882,172 @@ repodata_localize_id(Repodata *data, Id id, int create)
 Id
 repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create)
 {
+  const char *s;
   if (!id || !data || !fromdata)
     return id;
-  if (!data->localpool || !fromdata->localpool)
-    {
-      if (fromdata->localpool)
-       id = repodata_globalize_id(fromdata, id, create);
-      if (data->localpool)
-       id = repodata_localize_id(data, id, create);
-      return id;
-    }
-  /* localpool is set in both data and fromdata */
-  return stringpool_str2id(&data->spool, stringpool_id2str(&fromdata->spool, id), create);
+  if (data == fromdata || (!data->localpool && !fromdata->localpool))
+    return id;
+  if (fromdata->localpool)
+    s = stringpool_id2str(&fromdata->spool, id);
+  else
+    s = pool_id2str(data->repo->pool, id);
+  if (data->localpool)
+    return stringpool_str2id(&data->spool, s, create);
+  else
+    return pool_str2id(data->repo->pool, s, create);
 }
 
 Id
-repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid)
+repodata_translate_dir_slow(Repodata *data, Repodata *fromdata, Id dir, int create, Id *cache)
 {
-  Id *ap;
-  if (!data->attrs)
-    return 0;
-  ap = data->attrs[solvid - data->start];
-  if (!ap)
-    return 0;
-  for (; *ap; ap += 2)
+  Id parent, compid;
+  if (!dir)
     {
-      if (data->keys[*ap].name != keyname)
-       continue;
-      if (data->keys[*ap].type == REPOKEY_TYPE_VOID)
-       return voidid;
-      if (data->keys[*ap].type == REPOKEY_TYPE_ID)
-       return ap[1];
+      /* make sure that the dirpool has an entry */
+      if (create && !data->dirpool.ndirs)
+        dirpool_add_dir(&data->dirpool, 0, 0, create);
       return 0;
     }
-  return 0;
+  parent = dirpool_parent(&fromdata->dirpool, dir);
+  if (parent)
+    {
+      if (!(parent = repodata_translate_dir(data, fromdata, parent, create, cache)))
+       return 0;
+    }
+  compid = dirpool_compid(&fromdata->dirpool, dir);
+  if (compid > 1 && (data->localpool || fromdata->localpool))
+    {
+      if (!(compid = repodata_translate_id(data, fromdata, compid, create)))
+       return 0;
+    }
+  if (!(compid = dirpool_add_dir(&data->dirpool, parent, compid, create)))
+    return 0;
+  if (cache)
+    {
+      cache[(dir & 255) * 2] = dir;
+      cache[(dir & 255) * 2 + 1] = compid;
+    }
+  return compid;
 }
 
-const char *
-repodata_lookup_dirstrarray_uninternalized(Repodata *data, Id solvid, Id keyname, Id *didp, Id *iterp)
+/************************************************************************
+ * uninternalized lookup / search
+ */
+
+static void
+data_fetch_uninternalized(Repodata *data, Repokey *key, Id value, KeyValue *kv)
 {
-  Id *ap, did;
-  Id iter = *iterp;
-  if (iter == 0)       /* find key data */
+  Id *array;
+  kv->eof = 1;
+  switch (key->type)
     {
-      if (!data->attrs)
-       return 0;
-      ap = data->attrs[solvid - data->start];
-      if (!ap)
-       return 0;
-      for (; *ap; ap += 2)
-       if (data->keys[*ap].name == keyname && data->keys[*ap].type == REPOKEY_TYPE_DIRSTRARRAY)
-         break;
-      if (!*ap)
-       return 0;
-      iter = ap[1];
+    case REPOKEY_TYPE_STR:
+      kv->str = (const char *)data->attrdata + value;
+      return;
+    case REPOKEY_TYPE_CONSTANT:
+      kv->num2 = 0;
+      kv->num = key->size;
+      return;
+    case REPOKEY_TYPE_CONSTANTID:
+      kv->id = key->size;
+      return;
+    case REPOKEY_TYPE_NUM:
+      kv->num2 = 0;
+      kv->num = value;
+      if (value & 0x80000000)
+       {
+         kv->num = (unsigned int)data->attrnum64data[value ^ 0x80000000];
+         kv->num2 = (unsigned int)(data->attrnum64data[value ^ 0x80000000] >> 32);
+       }
+      return;
+    case_CHKSUM_TYPES:
+      kv->num = 0;     /* not stringified */
+      kv->str = (const char *)data->attrdata + value;
+      return;
+    case REPOKEY_TYPE_BINARY:
+      kv->str = (const char *)data_read_id(data->attrdata + value, (Id *)&kv->num);
+      return;
+    case REPOKEY_TYPE_IDARRAY:
+      array = data->attriddata + (value + kv->entry);
+      kv->id = array[0];
+      kv->eof = array[1] ? 0 : 1;
+      return;
+    case REPOKEY_TYPE_DIRSTRARRAY:
+      kv->num = 0;     /* not stringified */
+      array = data->attriddata + (value + kv->entry * 2);
+      kv->id = array[0];
+      kv->str = (const char *)data->attrdata + array[1];
+      kv->eof = array[2] ? 0 : 1;
+      return;
+    case REPOKEY_TYPE_DIRNUMNUMARRAY:
+      array = data->attriddata + (value + kv->entry * 3);
+      kv->id = array[0];
+      kv->num = array[1];
+      kv->num2 = array[2];
+      kv->eof = array[3] ? 0 : 1;
+      return;
+    case REPOKEY_TYPE_FIXARRAY:
+    case REPOKEY_TYPE_FLEXARRAY:
+      array = data->attriddata + (value + kv->entry);
+      kv->id = array[0];               /* the handle */
+      kv->eof = array[1] ? 0 : 1;
+      return;
+    default:
+      kv->id = value;
+      return;
     }
-  did = *didp;
-  for (ap = data->attriddata + iter; *ap; ap += 2)
+}
+
+Repokey *
+repodata_lookup_kv_uninternalized(Repodata *data, Id solvid, Id keyname, KeyValue *kv)
+{
+  Id *ap;
+  if (!data->attrs || solvid < data->start || solvid >= data->end)
+    return 0;
+  ap = data->attrs[solvid - data->start];
+  if (!ap)
+    return 0;
+  for (; *ap; ap += 2)
     {
-      if (did && ap[0] != did)
+      Repokey *key = data->keys + *ap;
+      if (key->name != keyname)
        continue;
-      *didp = ap[0];
-      *iterp = ap - data->attriddata + 2;
-      return (const char *)data->attrdata + ap[1];
+      data_fetch_uninternalized(data, key, ap[1], kv);
+      return key;
     }
-  *iterp = 0;
   return 0;
 }
 
-const unsigned char *
-repodata_lookup_bin_checksum_uninternalized(Repodata *data, Id solvid, Id keyname, Id *typep)
+void
+repodata_search_uninternalized(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
 {
   Id *ap;
-  if (!data->attrs)
-    return 0;
+  int stop;
+  Solvable *s;
+  KeyValue kv;
+
+  if (!data->attrs || solvid < data->start || solvid >= data->end)
+    return;
   ap = data->attrs[solvid - data->start];
   if (!ap)
-    return 0;
+    return;
   for (; *ap; ap += 2)
     {
-      if (data->keys[*ap].name != keyname)
+      Repokey *key = data->keys + *ap;
+      if (keyname && key->name != keyname)
        continue;
-      switch (data->keys[*ap].type)
+      s = solvid > 0 ? data->repo->pool->solvables + solvid : 0;
+      kv.entry = 0;
+      do
        {
-         case_CHKSUM_TYPES:
-           *typep = data->keys[*ap].type;
-           return (const unsigned char *)data->attrdata + ap[1];
-         default:
-           break;
+         data_fetch_uninternalized(data, key, ap[1], &kv);
+         stop = callback(cbdata, s, data, key, &kv);
+         kv.entry++;
        }
+      while (!kv.eof && !stop);
+      if (keyname || stop > SEARCH_NEXT_KEY)
+       return;
     }
-  return 0;
 }
 
 /************************************************************************
@@ -921,7 +1067,7 @@ repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int f
        kv->str = stringpool_id2str(&data->spool, kv->id);
       else
        kv->str = pool_id2str(pool, kv->id);
-      if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE)
+      if ((flags & SEARCH_SKIP_KIND) != 0 && key->storage == KEY_STORAGE_SOLVABLE && (key->name == SOLVABLE_NAME || key->type == REPOKEY_TYPE_IDARRAY))
        {
          const char *s;
          for (s = kv->str; *s >= 'a' && *s <= 'z'; s++)
@@ -955,15 +1101,59 @@ repodata_stringify(Pool *pool, Repodata *data, Repokey *key, KeyValue *kv, int f
 }
 
 
+/* this is an internal hack to pass the parent kv to repodata_search_keyskip */
 struct subschema_data {
-  Solvable *s;
   void *cbdata;
+  Id solvid;
   KeyValue *parent;
 };
 
+void
+repodata_search_arrayelement(Repodata *data, Id solvid, Id keyname, int flags, KeyValue *kv, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
+{
+  repodata_search_keyskip(data, solvid, keyname, flags | SEARCH_SUBSCHEMA, (Id *)kv, callback, cbdata);
+}
+
+static int
+repodata_search_array(Repodata *data, Id solvid, Id keyname, int flags, Repokey *key, KeyValue *kv, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
+{
+  Solvable *s = solvid > 0 ? data->repo->pool->solvables + solvid : 0;
+  unsigned char *dp = (unsigned char *)kv->str;
+  int stop;
+  Id schema = 0;
+
+  if (!dp || kv->entry != -1)
+    return 0;
+  while (++kv->entry < kv->num)
+    {
+      if (kv->entry)
+       dp = data_skip_schema(data, dp, schema);
+      if (kv->entry == 0 || key->type == REPOKEY_TYPE_FLEXARRAY)
+       dp = data_read_id(dp, &schema);
+      kv->id = schema;
+      kv->str = (const char *)dp;
+      kv->eof = kv->entry == kv->num - 1 ? 1 : 0;
+      stop = callback(cbdata, s, data, key, kv);
+      if (stop && stop != SEARCH_ENTERSUB)
+       return stop;
+      if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
+        repodata_search_keyskip(data, solvid, keyname, flags | SEARCH_SUBSCHEMA, (Id *)kv, callback, cbdata);
+    }
+  if ((flags & SEARCH_ARRAYSENTINEL) != 0)
+    {
+      if (kv->entry)
+       dp = data_skip_schema(data, dp, schema);
+      kv->id = 0;
+      kv->str = (const char *)dp;
+      kv->eof = 2;
+      return callback(cbdata, s, data, key, kv);
+    }
+  return 0;
+}
+
 /* search a specific repodata */
 void
-repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
+repodata_search_keyskip(Repodata *data, Id solvid, Id keyname, int flags, Id *keyskip, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
 {
   Id schema;
   Repokey *key;
@@ -976,14 +1166,13 @@ repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback
 
   if (!maybe_load_repodata(data, keyname))
     return;
-  if (solvid == SOLVID_SUBSCHEMA)
+  if ((flags & SEARCH_SUBSCHEMA) != 0)
     {
-      struct subschema_data *subd = cbdata;
-      cbdata = subd->cbdata;
-      s = subd->s;
-      schema = subd->parent->id;
-      dp = (unsigned char *)subd->parent->str;
-      kv.parent = subd->parent;
+      flags ^= SEARCH_SUBSCHEMA;
+      kv.parent = (KeyValue *)keyskip;
+      keyskip = 0;
+      schema = kv.parent->id;
+      dp = (unsigned char *)kv.parent->str;
     }
   else
     {
@@ -991,9 +1180,9 @@ repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback
       dp = solvid2data(data, solvid, &schema);
       if (!dp)
        return;
-      s = data->repo->pool->solvables + solvid;
       kv.parent = 0;
     }
+  s = solvid > 0 ? data->repo->pool->solvables + solvid : 0;
   keyp = data->schemadata + data->schemata[schema];
   if (keyname)
     {
@@ -1013,58 +1202,30 @@ repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback
     {
       stop = 0;
       key = data->keys + keyid;
-      ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
+      ddp = get_data(data, key, &dp, *keyp && !onekey ? 1 : 0);
 
-      if (key->type == REPOKEY_TYPE_DELETED)
+      if (keyskip && (key->name >= keyskip[0] || keyskip[3 + key->name] != keyskip[1] + data->repodataid))
        {
          if (onekey)
            return;
          continue;
        }
-      if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
+      if (key->type == REPOKEY_TYPE_DELETED && !(flags & SEARCH_KEEP_TYPE_DELETED))
        {
-         struct subschema_data subd;
-         int nentries;
-         Id schema = 0;
-
-         subd.cbdata = cbdata;
-         subd.s = s;
-         subd.parent = &kv;
-         ddp = data_read_id(ddp, &nentries);
-         kv.num = nentries;
-         kv.entry = 0;
-         kv.eof = 0;
-          while (ddp && nentries > 0)
-           {
-             if (!--nentries)
-               kv.eof = 1;
-             if (key->type == REPOKEY_TYPE_FLEXARRAY || !kv.entry)
-               ddp = data_read_id(ddp, &schema);
-             kv.id = schema;
-             kv.str = (char *)ddp;
-             stop = callback(cbdata, s, data, key, &kv);
-             if (stop > SEARCH_NEXT_KEY)
-               return;
-             if (stop && stop != SEARCH_ENTERSUB)
-               break;
-             if ((flags & SEARCH_SUB) != 0 || stop == SEARCH_ENTERSUB)
-               repodata_search(data, SOLVID_SUBSCHEMA, 0, flags, callback, &subd);
-             ddp = data_skip_schema(data, ddp, schema);
-             kv.entry++;
-           }
-         if (!nentries && (flags & SEARCH_ARRAYSENTINEL) != 0)
-           {
-             /* sentinel */
-             kv.eof = 2;
-             kv.str = (char *)ddp;
-             stop = callback(cbdata, s, data, key, &kv);
-             if (stop > SEARCH_NEXT_KEY)
-               return;
-           }
          if (onekey)
            return;
          continue;
        }
+      if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
+       {
+         kv.entry = -1;
+         ddp = data_read_id(ddp, (Id *)&kv.num);
+         kv.str = (const char *)ddp;
+         stop = repodata_search_array(data, solvid, 0, flags, key, &kv, callback, cbdata);
+         if (onekey || stop > SEARCH_NEXT_KEY)
+           return;
+         continue;
+       }
       kv.entry = 0;
       do
        {
@@ -1081,6 +1242,12 @@ repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback
 }
 
 void
+repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *kv), void *cbdata)
+{
+  repodata_search_keyskip(data, solvid, keyname, flags, 0, callback, cbdata);
+}
+
+void
 repodata_setpos_kv(Repodata *data, KeyValue *kv)
 {
   Pool *pool = data->repo->pool;
@@ -1271,21 +1438,6 @@ datamatcher_checkbasename(Datamatcher *ma, const char *basename)
     return !strcmp(match, basename);
 }
 
-int
-repodata_filelistfilter_matches(Repodata *data, const char *str)
-{
-  /* '.*bin\/.*', '^\/etc\/.*', '^\/usr\/lib\/sendmail$' */
-  /* for now hardcoded */
-  if (strstr(str, "bin/"))
-    return 1;
-  if (!strncmp(str, "/etc/", 5))
-    return 1;
-  if (!strcmp(str, "/usr/lib/sendmail"))
-    return 1;
-  return 0;
-}
-
-
 enum {
   di_bye,
 
@@ -1364,6 +1516,10 @@ dataiterator_init_clone(Dataiterator *di, Dataiterator *from)
        di->parents[i].kv.parent = &di->parents[i - 1].kv;
       di->kv.parent = &di->parents[di->nparents - 1].kv;
     }
+  if (di->oldkeyskip)
+    di->oldkeyskip = solv_memdup2(di->oldkeyskip, 3 + di->oldkeyskip[0], sizeof(Id));
+  if (di->keyskip)
+    di->keyskip = di->oldkeyskip;
 }
 
 int
@@ -1439,6 +1595,8 @@ dataiterator_free(Dataiterator *di)
     datamatcher_free(&di->matcher);
   if (di->dupstr)
     solv_free(di->dupstr);
+  if (di->oldkeyskip)
+    solv_free(di->oldkeyskip);
 }
 
 static unsigned char *
@@ -1465,88 +1623,21 @@ dataiterator_find_keyname(Dataiterator *di, Id keyname)
   return dp;
 }
 
-static inline int
-is_filelist_extension(Repodata *data)
-{
-  int j;
-  if (!repodata_precheck_keyname(data, SOLVABLE_FILELIST))
-    return 0;
-  for (j = 1; j < data->nkeys; j++)
-    if (data->keys[j].name == SOLVABLE_FILELIST)
-      break;
-  if (j == data->nkeys)
-    return 0;
-  if (data->state != REPODATA_AVAILABLE)
-    return 1;
-  for (j = 1; j < data->nkeys; j++)
-    if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-      return 0;
-  return 1;
-}
-
-static int
-dataiterator_filelistcheck(Dataiterator *di)
-{
-  int j;
-  int needcomplete = 0;
-  Repodata *data = di->data;
-
-  if ((di->flags & SEARCH_COMPLETE_FILELIST) != 0)
-    if (!di->matcher.match
-       || ((di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_STRING
-           && (di->matcher.flags & (SEARCH_STRINGMASK|SEARCH_NOCASE)) != SEARCH_GLOB)
-       || !repodata_filelistfilter_matches(data, di->matcher.match))
-      needcomplete = 1;
-  if (data->state != REPODATA_AVAILABLE)
-    return needcomplete ? 1 : 0;
-  if (!needcomplete)
-    {
-      /* we don't need the complete filelist, so ignore all stubs */
-      if (data->repo->nrepodata == 2)
-       return 1;
-      for (j = 1; j < data->nkeys; j++)
-       if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-         return 1;
-      return 0;
-    }
-  else
-    {
-      /* we need the complete filelist. check if we habe a filtered filelist and there's
-       * a extension with the complete filelist later on */
-      for (j = 1; j < data->nkeys; j++)
-       if (data->keys[j].name == SOLVABLE_FILELIST)
-         break;
-      if (j == data->nkeys)
-       return 0;       /* does not have filelist */
-      for (j = 1; j < data->nkeys; j++)
-       if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST)
-         break;
-      if (j == data->nkeys)
-       return 1;       /* this is the externsion */
-      while (data - data->repo->repodata + 1 < data->repo->nrepodata)
-       {
-         data++;
-         if (is_filelist_extension(data))
-           return 0;
-       }
-      return 1;
-    }
-}
-
 int
 dataiterator_step(Dataiterator *di)
 {
   Id schema;
 
-  if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate) {
-    unsigned int ddpoff = di->ddp - di->vert_ddp;
-    di->vert_off += ddpoff;
-    di->vert_len -= ddpoff;
-    di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
-    di->vert_storestate = di->data->storestate;
-    if (!di->ddp)
-      di->state = di_nextkey;
-  }
+  if (di->state == di_nextattr && di->key->storage == KEY_STORAGE_VERTICAL_OFFSET && di->vert_ddp && di->vert_storestate != di->data->storestate)
+    {
+      unsigned int ddpoff = di->ddp - di->vert_ddp;
+      di->vert_off += ddpoff;
+      di->vert_len -= ddpoff;
+      di->ddp = di->vert_ddp = get_vertical_data(di->data, di->key, di->vert_off, di->vert_len);
+      di->vert_storestate = di->data->storestate;
+      if (!di->ddp)
+       di->state = di_nextkey;
+    }
   for (;;)
     {
       switch (di->state)
@@ -1562,18 +1653,28 @@ dataiterator_step(Dataiterator *di)
          /* FALLTHROUGH */
 
        case di_entersolvable: di_entersolvable:
-         if (di->repodataid)
+         if (!di->repodataid)
+           goto di_enterrepodata;      /* POS case, repodata is set */
+         if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames)
            {
-             di->repodataid = 1;       /* reset repodata iterator */
-             if (di->solvid > 0 && !(di->flags & SEARCH_NO_STORAGE_SOLVABLE) && (!di->keyname || (di->keyname >= SOLVABLE_NAME && di->keyname <= RPM_RPMDBID)) && di->nparents - di->rootlevel == di->nkeynames)
-               {
-                 extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
+             extern Repokey repo_solvablekeys[RPM_RPMDBID - SOLVABLE_NAME + 1];
+             di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
+             di->data = 0;
+             goto di_entersolvablekey;
+           }
 
-                 di->key = repo_solvablekeys + (di->keyname ? di->keyname - SOLVABLE_NAME : 0);
-                 di->data = 0;
-                 goto di_entersolvablekey;
-               }
+         if (di->keyname)
+           {
+             di->data = di->keyname == SOLVABLE_FILELIST ? repo_lookup_filelist_repodata(di->repo, di->solvid, &di->matcher) : repo_lookup_repodata_opt(di->repo, di->solvid, di->keyname);
+             if (!di->data)
+               goto di_nextsolvable;
+             di->repodataid = di->data - di->repo->repodata;
+             di->keyskip = 0;
+             goto di_enterrepodata;
            }
+       di_leavesolvablekey:
+         di->repodataid = 1;   /* reset repodata iterator */
+         di->keyskip = repo_create_keyskip(di->repo, di->solvid, &di->oldkeyskip);
          /* FALLTHROUGH */
 
        case di_enterrepodata: di_enterrepodata:
@@ -1583,8 +1684,6 @@ dataiterator_step(Dataiterator *di)
                goto di_nextsolvable;
              di->data = di->repo->repodata + di->repodataid;
            }
-         if (di->repodataid && di->keyname == SOLVABLE_FILELIST && !dataiterator_filelistcheck(di))
-           goto di_nextrepodata;
          if (!maybe_load_repodata(di->data, di->keyname))
            goto di_nextrepodata;
          di->dp = solvid2data(di->data, di->solvid, &schema);
@@ -1625,15 +1724,17 @@ dataiterator_step(Dataiterator *di)
            }
          else if (di->key->storage == KEY_STORAGE_INCORE)
            {
-             di->ddp = di->dp;
+             di->ddp = di->dp;         /* start of data */
              if (di->keyp[1] && (!di->keyname || (di->flags & SEARCH_SUB) != 0))
-               di->dp = data_skip_key(di->data, di->dp, di->key);
+               di->dp = data_skip_key(di->data, di->dp, di->key);      /* advance to next key */
            }
          else
            di->ddp = 0;
          if (!di->ddp)
            goto di_nextkey;
-          if (di->key->type == REPOKEY_TYPE_DELETED)
+         if (di->keyskip && (di->key->name >= di->keyskip[0] || di->keyskip[3 + di->key->name] != di->keyskip[1] + di->data->repodataid))
+           goto di_nextkey;
+          if (di->key->type == REPOKEY_TYPE_DELETED && !(di->flags & SEARCH_KEEP_TYPE_DELETED))
            goto di_nextkey;
          if (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY)
            goto di_enterarray;
@@ -1644,10 +1745,7 @@ dataiterator_step(Dataiterator *di)
        case di_nextattr:
           di->kv.entry++;
          di->ddp = data_fetch(di->ddp, &di->kv, di->key);
-         if (di->kv.eof)
-           di->state = di_nextkey;
-         else
-           di->state = di_nextattr;
+         di->state = di->kv.eof ? di_nextkey : di_nextattr;
          break;
 
        case di_nextkey: di_nextkey:
@@ -1658,7 +1756,7 @@ dataiterator_step(Dataiterator *di)
          /* FALLTHROUGH */
 
        case di_nextrepodata: di_nextrepodata:
-         if (di->repodataid && ++di->repodataid < di->repo->nrepodata)
+         if (!di->keyname && di->repodataid && ++di->repodataid < di->repo->nrepodata)
              goto di_enterrepodata;
          /* FALLTHROUGH */
 
@@ -1759,8 +1857,10 @@ dataiterator_step(Dataiterator *di)
         /* special solvable attr handling follows */
 
        case di_nextsolvablekey: di_nextsolvablekey:
-         if (di->keyname || di->key->name == RPM_RPMDBID)
-           goto di_enterrepodata;
+         if (di->keyname)
+           goto di_nextsolvable;
+         if (di->key->name == RPM_RPMDBID)     /* reached end of list? */
+           goto di_leavesolvablekey;
          di->key++;
          /* FALLTHROUGH */
 
@@ -1794,6 +1894,7 @@ dataiterator_step(Dataiterator *di)
 
        }
 
+      /* we have a potential match */
       if (di->matcher.match)
        {
          const char *str;
@@ -1801,6 +1902,7 @@ dataiterator_step(Dataiterator *di)
          if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->matcher.flags & SEARCH_FILES) != 0)
            if (!datamatcher_checkbasename(&di->matcher, di->kv.str))
              continue;
+         /* now stringify so that we can do the matching */
          if (!(str = repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags)))
            {
              if (di->keyname && (di->key->type == REPOKEY_TYPE_FIXARRAY || di->key->type == REPOKEY_TYPE_FLEXARRAY))
@@ -1812,6 +1914,7 @@ dataiterator_step(Dataiterator *di)
        }
       else
        {
+         /* stringify filelist if requested */
          if (di->keyname == SOLVABLE_FILELIST && di->key->type == REPOKEY_TYPE_DIRSTRARRAY && (di->flags & SEARCH_FILES) != 0)
            repodata_stringify(di->pool, di->data, di->key, &di->kv, di->flags);
        }
@@ -2792,18 +2895,18 @@ repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname,
 }
 
 void
-repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
+repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id handle)
 {
   repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FIXARRAY, 1);
-  data->attriddata[data->attriddatalen++] = ghandle;
+  data->attriddata[data->attriddatalen++] = handle;
   data->attriddata[data->attriddatalen++] = 0;
 }
 
 void
-repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
+repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id handle)
 {
   repodata_add_array(data, solvid, keyname, REPOKEY_TYPE_FLEXARRAY, 1);
-  data->attriddata[data->attriddatalen++] = ghandle;
+  data->attriddata[data->attriddatalen++] = handle;
   data->attriddata[data->attriddatalen++] = 0;
 }
 
@@ -2873,7 +2976,6 @@ repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
   *pp = 0;
 }
 
-/* XXX: does not work correctly, needs fix in iterators! */
 void
 repodata_unset(Repodata *data, Id solvid, Id keyname)
 {
@@ -3583,13 +3685,14 @@ repodata_disable_paging(Repodata *data)
     }
 }
 
+/* call the pool's loadcallback to load a stub repodata */
 static void
-repodata_load_stub(Repodata *data)
+repodata_stub_loader(Repodata *data)
 {
   Repo *repo = data->repo;
   Pool *pool = repo->pool;
   int r, i;
-  struct _Pool_tmpspace oldtmpspace;
+  struct s_Pool_tmpspace oldtmpspace;
   Datapos oldpos;
 
   if (!pool->loadcallback)
@@ -3640,7 +3743,7 @@ repodata_add_stub(Repodata **datap)
   if (data->end > data->start)
     repodata_extend_block(sdata, data->start, data->end - data->start);
   sdata->state = REPODATA_STUB;
-  sdata->loadcallback = repodata_load_stub;
+  sdata->loadcallback = repodata_stub_loader;
   *datap = data;
   return sdata;
 }
@@ -3694,6 +3797,8 @@ repodata_create_stubs(Repodata *data)
          else
            {
              repodata_add_stubkey(sdata, xkeyname, di.kv.id);
+             if (xkeyname == SOLVABLE_FILELIST)
+               repodata_set_filelisttype(sdata, REPODATA_FILELIST_EXTENSION);
              xkeyname = 0;
            }
        }
@@ -3705,6 +3810,12 @@ repodata_create_stubs(Repodata *data)
   return data;
 }
 
+void
+repodata_set_filelisttype(Repodata *data, int type)
+{
+  data->filelisttype = type;
+}
+
 unsigned int
 repodata_memused(Repodata *data)
 {
index 7208e95..f204e34 100644 (file)
@@ -34,10 +34,10 @@ extern "C" {
 #define SIZEOF_SHA384  48
 #define SIZEOF_SHA512  64
 
-struct _Repo;
-struct _KeyValue;
+struct s_Repo;
+struct s_KeyValue;
 
-typedef struct _Repokey {
+typedef struct s_Repokey {
   Id name;
   Id type;                     /* REPOKEY_TYPE_xxx */
   unsigned int size;
@@ -53,19 +53,26 @@ typedef struct _Repokey {
 struct dircache;
 #endif
 
-typedef struct _Repodata {
-  Id repodataid;               /* our id */
-  struct _Repo *repo;          /* back pointer to repo */
-
+/* repodata states */
 #define REPODATA_AVAILABLE     0
 #define REPODATA_STUB          1
 #define REPODATA_ERROR         2
 #define REPODATA_STORE         3
 #define REPODATA_LOADING       4
 
+/* repodata filelist types */
+/* note that FILELIST_FILTERED means that the data contains a filtered
+ * filelist *AND* that it is authoritative for all included solvables. */
+#define REPODATA_FILELIST_FILTERED     1
+#define REPODATA_FILELIST_EXTENSION    2
+
+typedef struct s_Repodata {
+  Id repodataid;               /* our id */
+  struct s_Repo *repo;         /* back pointer to repo */
+
   int state;                   /* available, stub or error */
 
-  void (*loadcallback)(struct _Repodata *);
+  void (*loadcallback)(struct s_Repodata *);
 
   int start;                   /* start of solvables this repodata is valid for */
   int end;                     /* last solvable + 1 of this repodata */
@@ -87,6 +94,10 @@ typedef struct _Repodata {
   FILE *fp;                    /* file pointer of solv file */
   int error;                   /* corrupt solv file */
 
+  int filelisttype;            /* type of filelist */
+  Id *filelistfilter;          /* filelist filter used */
+  char *filelistfilterdata;    /* filelist filter string space */
+
   unsigned int schemadatalen;   /* schema storage size */
   Id *schematahash;            /* unification helper */
 
@@ -132,18 +143,18 @@ typedef struct _Repodata {
 
 #define SOLVID_META            -1
 #define SOLVID_POS             -2
-#define SOLVID_SUBSCHEMA       -3              /* internal! */
 
 
 /*-----
  * management functions
  */
-void repodata_initdata(Repodata *data, struct _Repo *repo, int localpool);
+void repodata_initdata(Repodata *data, struct s_Repo *repo, int localpool);
 void repodata_freedata(Repodata *data);
 
 void repodata_free(Repodata *data);
 void repodata_empty(Repodata *data, int localpool);
 
+void repodata_load(Repodata *data);
 
 /*
  * key management functions
@@ -196,25 +207,34 @@ repodata_has_keyname(Repodata *data, Id keyname)
 
 /* search key <keyname> (all keys, if keyname == 0) for Id <solvid>
  * Call <callback> for each match */
-void repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct _KeyValue *kv), void *cbdata);
+void repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct s_KeyValue *kv), void *cbdata);
+void repodata_search_keyskip(Repodata *data, Id solvid, Id keyname, int flags, Id *keyskip, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct s_KeyValue *kv), void *cbdata);
+void repodata_search_arrayelement(Repodata *data, Id solvid, Id keyname, int flags, struct s_KeyValue *kv, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct s_KeyValue *kv), void *cbdata);
 
 /* Make sure the found KeyValue has the "str" field set. Return "str"
  * if valid, NULL if not possible */
-const char *repodata_stringify(Pool *pool, Repodata *data, Repokey *key, struct _KeyValue *kv, int flags);
+const char *repodata_stringify(Pool *pool, Repodata *data, Repokey *key, struct s_KeyValue *kv, int flags);
 
+/* filelist filter support */
+void repodata_set_filelisttype(Repodata *data, int filelisttype);
 int repodata_filelistfilter_matches(Repodata *data, const char *str);
-
+void repodata_free_filelistfilter(Repodata *data);
 
 /* lookup functions */
 Id repodata_lookup_type(Repodata *data, Id solvid, Id keyname);
 Id repodata_lookup_id(Repodata *data, Id solvid, Id keyname);
 const char *repodata_lookup_str(Repodata *data, Id solvid, Id keyname);
-int repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long *value);
+unsigned long long repodata_lookup_num(Repodata *data, Id solvid, Id keyname, unsigned long long notfound);
 int repodata_lookup_void(Repodata *data, Id solvid, Id keyname);
 const unsigned char *repodata_lookup_bin_checksum(Repodata *data, Id solvid, Id keyname, Id *typep);
 int repodata_lookup_idarray(Repodata *data, Id solvid, Id keyname, Queue *q);
 const void *repodata_lookup_binary(Repodata *data, Id solvid, Id keyname, int *lenp);
 
+/* internal, used in fileprovides code */
+const unsigned char *repodata_lookup_packed_dirstrarray(Repodata *data, Id solvid, Id keyname);
+
+/* internal, fill keyskip array with data */
+Id *repodata_fill_keyskip(Repodata *data, Id solvid, Id *keyskip);
 
 /*-----
  * data assignment functions
@@ -264,14 +284,14 @@ void repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const ch
 void repodata_free_dircache(Repodata *data);
 
 
-/* Arrays */
+/* arrays */
 void repodata_add_idarray(Repodata *data, Id solvid, Id keyname, Id id);
 void repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname, const char *str);
 void repodata_add_fixarray(Repodata *data, Id solvid, Id keyname, Id ghandle);
 void repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle);
 
 /* generic */
-void repodata_set_kv(Repodata *data, Id solvid, Id keyname, Id keytype, struct _KeyValue *kv);
+void repodata_set_kv(Repodata *data, Id solvid, Id keyname, Id keytype, struct s_KeyValue *kv);
 void repodata_unset(Repodata *data, Id solvid, Id keyname);
 void repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname);
 
@@ -294,6 +314,7 @@ void repodata_disable_paging(Repodata *data);
 Id repodata_globalize_id(Repodata *data, Id id, int create);
 Id repodata_localize_id(Repodata *data, Id id, int create);
 Id repodata_translate_id(Repodata *data, Repodata *fromdata, Id id, int create);
+Id repodata_translate_dir_slow(Repodata *data, Repodata *fromdata, Id dir, int create, Id *cache);
 
 Id repodata_str2dir(Repodata *data, const char *dir, int create);
 const char *repodata_dir2str(Repodata *data, Id did, const char *suf);
@@ -302,14 +323,34 @@ void repodata_set_location(Repodata *data, Id solvid, int medianr, const char *d
 void repodata_set_deltalocation(Repodata *data, Id handle, int medianr, const char *dir, const char *file);
 void repodata_set_sourcepkg(Repodata *data, Id solvid, const char *sourcepkg);
 
-/* uninternalized data lookup */
-Id repodata_lookup_id_uninternalized(Repodata *data, Id solvid, Id keyname, Id voidid);
-const char *repodata_lookup_dirstrarray_uninternalized(Repodata *data, Id solvid, Id keyname, Id *didp, Id *iterp);
-const unsigned char *repodata_lookup_bin_checksum_uninternalized(Repodata *data, Id solvid, Id keyname, Id *typep);
+/* uninternalized data lookup / search */
+Repokey *repodata_lookup_kv_uninternalized(Repodata *data, Id solvid, Id keyname, struct s_KeyValue *kv);
+void repodata_search_uninternalized(Repodata *data, Id solvid, Id keyname, int flags, int (*callback)(void *cbdata, Solvable *s, Repodata *data, Repokey *key, struct s_KeyValue *kv), void *cbdata);
 
 /* stats */
 unsigned int repodata_memused(Repodata *data);
 
+static inline Id
+repodata_translate_dir(Repodata *data, Repodata *fromdata, Id dir, int create, Id *cache)
+{
+  if (cache && dir && cache[(dir & 255) * 2] == dir)
+    return cache[(dir & 255) * 2 + 1];
+  return repodata_translate_dir_slow(data, fromdata, dir, create, cache);
+}
+
+static inline Id *
+repodata_create_dirtranscache(Repodata *data)
+{
+  return (Id *)solv_calloc(256, sizeof(Id) * 2);
+}
+
+static inline Id *
+repodata_free_dirtranscache(Id *cache)
+{
+  return (Id *)solv_free(cache);
+}
+
+
 #ifdef __cplusplus
 }
 #endif
index 3079239..e63366d 100644 (file)
@@ -129,13 +129,6 @@ data_read_ideof(unsigned char *dp, Id *idp, int *eof)
 }
 
 static inline unsigned char *
-data_read_u32(unsigned char *dp, unsigned int *nump)
-{
-  *nump = (dp[0] << 24) | (dp[1] << 16) | (dp[2] << 8) | dp[3];
-  return dp + 4;
-}
-
-static inline unsigned char *
 data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key)
 {
   kv->eof = 1;
@@ -144,6 +137,7 @@ data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key)
   switch (key->type)
     {
     case REPOKEY_TYPE_VOID:
+    case REPOKEY_TYPE_DELETED:
       return dp;
     case REPOKEY_TYPE_CONSTANT:
       kv->num2 = 0;
@@ -160,9 +154,6 @@ data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key)
       return data_read_id(dp, &kv->id);
     case REPOKEY_TYPE_NUM:
       return data_read_num64(dp, &kv->num, &kv->num2);
-    case REPOKEY_TYPE_U32:
-      kv->num2 = 0;
-      return data_read_u32(dp, &kv->num);
     case REPOKEY_TYPE_MD5:
       kv->num = 0;     /* not stringified yet */
       kv->str = (const char *)dp;
@@ -203,10 +194,17 @@ data_fetch(unsigned char *dp, KeyValue *kv, Repokey *key)
       dp = data_read_id(dp, (Id *)&kv->num);
       return data_read_ideof(dp, (Id *)&kv->num2, &kv->eof);
     case REPOKEY_TYPE_FIXARRAY:
-      dp = data_read_id(dp, (Id *)&kv->num);
-      return data_read_id(dp, &kv->id);
     case REPOKEY_TYPE_FLEXARRAY:
-      return data_read_id(dp, (Id *)&kv->num);
+      if (!kv->entry)
+       {
+          dp = data_read_id(dp, (Id *)&kv->num);       /* number of elements */
+         if (!kv->num)
+           return 0;           /* illegal */
+       }
+      if (!kv->entry || key->type == REPOKEY_TYPE_FLEXARRAY)
+        dp = data_read_id(dp, &kv->id);        /* schema */
+      kv->str = (const char *)dp;
+      return dp;
     default:
       return 0;
     }
@@ -229,8 +227,6 @@ data_skip(unsigned char *dp, int type)
       while ((*dp & 0x80) != 0)
         dp++;
       return dp + 1;
-    case REPOKEY_TYPE_U32:
-      return dp + 4;
     case REPOKEY_TYPE_MD5:
       return dp + SIZEOF_MD5;
     case REPOKEY_TYPE_SHA1:
@@ -290,96 +286,4 @@ data_skip(unsigned char *dp, int type)
     }
 }
 
-static inline unsigned char *
-data_skip_verify(unsigned char *dp, int type, int maxid, int maxdir)
-{
-  Id id;
-  int eof;
-
-  switch (type)
-    {
-    case REPOKEY_TYPE_VOID:
-    case REPOKEY_TYPE_CONSTANT:
-    case REPOKEY_TYPE_CONSTANTID:
-    case REPOKEY_TYPE_DELETED:
-      return dp;
-    case REPOKEY_TYPE_NUM:
-      while ((*dp & 0x80) != 0)
-        dp++;
-      return dp + 1;
-    case REPOKEY_TYPE_U32:
-      return dp + 4;
-    case REPOKEY_TYPE_MD5:
-      return dp + SIZEOF_MD5;
-    case REPOKEY_TYPE_SHA1:
-      return dp + SIZEOF_SHA1;
-    case REPOKEY_TYPE_SHA224:
-      return dp + SIZEOF_SHA224;
-    case REPOKEY_TYPE_SHA256:
-      return dp + SIZEOF_SHA256;
-    case REPOKEY_TYPE_SHA384:
-      return dp + SIZEOF_SHA384;
-    case REPOKEY_TYPE_SHA512:
-      return dp + SIZEOF_SHA512;
-    case REPOKEY_TYPE_ID:
-      dp = data_read_id(dp, &id);
-      if (id >= maxid)
-       return 0;
-      return dp;
-    case REPOKEY_TYPE_DIR:
-      dp = data_read_id(dp, &id);
-      if (id >= maxdir)
-       return 0;
-      return dp;
-    case REPOKEY_TYPE_IDARRAY:
-      for (;;)
-       {
-         dp = data_read_ideof(dp, &id, &eof);
-         if (id >= maxid)
-           return 0;
-         if (eof)
-           return dp;
-       }
-    case REPOKEY_TYPE_STR:
-      while ((*dp) != 0)
-        dp++;
-      return dp + 1;
-    case REPOKEY_TYPE_BINARY:
-      {
-       unsigned int len;
-       dp = data_read_id(dp, (Id *)&len);
-       return dp + len;
-      }
-    case REPOKEY_TYPE_DIRSTRARRAY:
-      for (;;)
-        {
-         dp = data_read_ideof(dp, &id, &eof);
-         if (id >= maxdir)
-           return 0;
-          while ((*dp) != 0)
-            dp++;
-          dp++;
-          if (eof)
-            return dp;
-        }
-    case REPOKEY_TYPE_DIRNUMNUMARRAY:
-      for (;;)
-        {
-         dp = data_read_id(dp, &id);
-         if (id >= maxdir)
-           return 0;
-          while ((*dp & 0x80) != 0)
-            dp++;
-          dp++;
-          while ((*dp & 0x80) != 0)
-            dp++;
-          if (!(*dp & 0x40))
-            return dp + 1;
-          dp++;
-        }
-    default:
-      return 0;
-    }
-}
-
 #endif /* LIBSOLV_REPOPACK */
index 739345e..b5f2eee 100644 (file)
@@ -11,7 +11,7 @@
 #define REPOPAGE_BLOBBITS 15
 #define REPOPAGE_BLOBSIZE (1 << REPOPAGE_BLOBBITS)
 
-typedef struct _Attrblobpage
+typedef struct s_Attrblobpage
 {
   /* page_size == 0 means the page is not backed by some file storage.
      Otherwise it is L*2+(compressed ? 1 : 0), with L being the data
@@ -20,7 +20,7 @@ typedef struct _Attrblobpage
   unsigned int page_size;
 } Attrblobpage;
 
-typedef struct _Repopagestore {
+typedef struct s_Repopagestore {
   int pagefd;          /* file descriptor we're paging from */
   long file_offset;    /* pages in file start here */
 
index 5901145..df32341 100644 (file)
@@ -1328,31 +1328,6 @@ solver_addfeaturerule(Solver *solv, Solvable *s)
     }
 }
 
-/* check if multiversion solvable s2 has an obsoletes for installed solvable s */
-static int
-is_multiversion_obsoleteed(Pool *pool, Solvable *s, Solvable *s2)
-{
-  Id *wp, obs, *obsp;
-
-  if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
-    return 0;
-  obsp = s2->repo->idarraydata + s2->obsoletes;
-  if (!pool->obsoleteusesprovides)
-    {
-      while ((obs = *obsp++) != 0)
-        if (pool_match_nevr(pool, s, obs))
-         return 1;
-    }
-  else
-    {
-      while ((obs = *obsp++) != 0)
-        for (wp = pool_whatprovides_ptr(pool, obs); *wp; wp++)
-         if (pool->solvables + *wp == s)
-           return 1;
-    }
-  return 0;
-}
-
 /*-------------------------------------------------------------------
  *
  * add rule for update
@@ -1414,8 +1389,9 @@ solver_addupdaterule(Solver *solv, Solvable *s)
              if (MAPTST(&solv->multiversion, qs.elements[i]))
                {
                  Solvable *ps = pool->solvables + qs.elements[i];
-                 /* check if there is an explicit obsoletes */
-                 if (solv->keepexplicitobsoletes && ps->obsoletes && is_multiversion_obsoleteed(pool, s, ps))
+                 /* if keepexplicitobsoletes is set and the name is different,
+                  * we assume that there is an obsoletes. XXX: not 100% correct */
+                 if (solv->keepexplicitobsoletes && ps->name != s->name)
                    {
                      qs.elements[j++] = qs.elements[i];
                      continue;
@@ -2199,7 +2175,7 @@ jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
          if (pool->solvables[p].repo == installed)
            return;
          if (solv->multiversion.size && MAPTST(&solv->multiversion, p) && !solv->keepexplicitobsoletes)
-           return;             /* will not obsolete anything, so just return */
+           return;
        }
       omap.size = 0;
       qstart = q->count;
index db52199..a3c0135 100644 (file)
@@ -35,7 +35,7 @@ extern "C" {
  * possible. Do not add new members unless there is no other way.
  */
 
-typedef struct _Rule {
+typedef struct s_Rule {
   Id p;                /* first literal in rule */
   Id d;                /* Id offset into 'list of providers terminated by 0' as used by whatprovides; pool->whatprovides + d */
                /* in case of binary rules, d == 0, w1 == p, w2 == other literal */
@@ -76,14 +76,14 @@ typedef enum {
 
 #define SOLVER_RULE_TYPEMASK    0xff00
 
-struct _Solver;
+struct s_Solver;
 
 /*-------------------------------------------------------------------
  * disable rule
  */
 
 static inline void
-solver_disablerule(struct _Solver *solv, Rule *r)
+solver_disablerule(struct s_Solver *solv, Rule *r)
 {
   if (r->d >= 0)
     r->d = -r->d - 1;
@@ -94,64 +94,64 @@ solver_disablerule(struct _Solver *solv, Rule *r)
  */
 
 static inline void
-solver_enablerule(struct _Solver *solv, Rule *r)
+solver_enablerule(struct s_Solver *solv, Rule *r)
 {
   if (r->d < 0)
     r->d = -r->d - 1;
 }
 
-extern Rule *solver_addrule(struct _Solver *solv, Id p, Id p2, Id d);
-extern void solver_unifyrules(struct _Solver *solv);
-extern int solver_rulecmp(struct _Solver *solv, Rule *r1, Rule *r2);
-extern void solver_shrinkrules(struct _Solver *solv, int nrules);
+extern Rule *solver_addrule(struct s_Solver *solv, Id p, Id p2, Id d);
+extern void solver_unifyrules(struct s_Solver *solv);
+extern int solver_rulecmp(struct s_Solver *solv, Rule *r1, Rule *r2);
+extern void solver_shrinkrules(struct s_Solver *solv, int nrules);
 
 /* pkg rules */
-extern void solver_addpkgrulesforsolvable(struct _Solver *solv, Solvable *s, Map *m);
-extern void solver_addpkgrulesforweak(struct _Solver *solv, Map *m);
-extern void solver_addpkgrulesforlinked(struct _Solver *solv, Map *m);
-extern void solver_addpkgrulesforupdaters(struct _Solver *solv, Solvable *s, Map *m, int allow_all);
+extern void solver_addpkgrulesforsolvable(struct s_Solver *solv, Solvable *s, Map *m);
+extern void solver_addpkgrulesforweak(struct s_Solver *solv, Map *m);
+extern void solver_addpkgrulesforlinked(struct s_Solver *solv, Map *m);
+extern void solver_addpkgrulesforupdaters(struct s_Solver *solv, Solvable *s, Map *m, int allow_all);
 
 /* update/feature rules */
-extern void solver_addfeaturerule(struct _Solver *solv, Solvable *s);
-extern void solver_addupdaterule(struct _Solver *solv, Solvable *s);
+extern void solver_addfeaturerule(struct s_Solver *solv, Solvable *s);
+extern void solver_addupdaterule(struct s_Solver *solv, Solvable *s);
 
 /* infarch rules */
-extern void solver_addinfarchrules(struct _Solver *solv, Map *addedmap);
+extern void solver_addinfarchrules(struct s_Solver *solv, Map *addedmap);
 
 /* dup rules */
-extern void solver_createdupmaps(struct _Solver *solv);
-extern void solver_freedupmaps(struct _Solver *solv);
-extern void solver_addduprules(struct _Solver *solv, Map *addedmap);
+extern void solver_createdupmaps(struct s_Solver *solv);
+extern void solver_freedupmaps(struct s_Solver *solv);
+extern void solver_addduprules(struct s_Solver *solv, Map *addedmap);
 
 /* choice rules */
-extern void solver_addchoicerules(struct _Solver *solv);
-extern void solver_disablechoicerules(struct _Solver *solv, Rule *r);
+extern void solver_addchoicerules(struct s_Solver *solv);
+extern void solver_disablechoicerules(struct s_Solver *solv, Rule *r);
 
 /* best rules */
-extern void solver_addbestrules(struct _Solver *solv, int havebestinstalljobs);
+extern void solver_addbestrules(struct s_Solver *solv, int havebestinstalljobs);
 
 /* yumobs rules */
-extern void solver_addyumobsrules(struct _Solver *solv);
+extern void solver_addyumobsrules(struct s_Solver *solv);
 
 /* policy rule disabling/reenabling */
-extern void solver_disablepolicyrules(struct _Solver *solv);
-extern void solver_reenablepolicyrules(struct _Solver *solv, int jobidx);
-extern void solver_reenablepolicyrules_cleandeps(struct _Solver *solv, Id pkg);
+extern void solver_disablepolicyrules(struct s_Solver *solv);
+extern void solver_reenablepolicyrules(struct s_Solver *solv, int jobidx);
+extern void solver_reenablepolicyrules_cleandeps(struct s_Solver *solv, Id pkg);
 
 /* rule info */
-extern int solver_allruleinfos(struct _Solver *solv, Id rid, Queue *rq);
-extern SolverRuleinfo solver_ruleinfo(struct _Solver *solv, Id rid, Id *fromp, Id *top, Id *depp);
-extern SolverRuleinfo solver_ruleclass(struct _Solver *solv, Id rid);
-extern void solver_ruleliterals(struct _Solver *solv, Id rid, Queue *q);
-extern int  solver_rule2jobidx(struct _Solver *solv, Id rid);
-extern Id   solver_rule2job(struct _Solver *solv, Id rid, Id *whatp);
-extern Id   solver_rule2solvable(struct _Solver *solv, Id rid);
-extern void solver_rule2rules(struct _Solver *solv, Id rid, Queue *q, int recursive);
-extern Id   solver_rule2pkgrule(struct _Solver *solv, Id rid);
+extern int solver_allruleinfos(struct s_Solver *solv, Id rid, Queue *rq);
+extern SolverRuleinfo solver_ruleinfo(struct s_Solver *solv, Id rid, Id *fromp, Id *top, Id *depp);
+extern SolverRuleinfo solver_ruleclass(struct s_Solver *solv, Id rid);
+extern void solver_ruleliterals(struct s_Solver *solv, Id rid, Queue *q);
+extern int  solver_rule2jobidx(struct s_Solver *solv, Id rid);
+extern Id   solver_rule2job(struct s_Solver *solv, Id rid, Id *whatp);
+extern Id   solver_rule2solvable(struct s_Solver *solv, Id rid);
+extern void solver_rule2rules(struct s_Solver *solv, Id rid, Queue *q, int recursive);
+extern Id   solver_rule2pkgrule(struct s_Solver *solv, Id rid);
 
 /* orphan handling */
-extern void solver_breakorphans(struct _Solver *solv);
-extern void solver_check_brokenorphanrules(struct _Solver *solv, Queue *dq);
+extern void solver_breakorphans(struct s_Solver *solv);
+extern void solver_check_brokenorphanrules(struct s_Solver *solv, Queue *dq);
 
 
 /* legacy */
index 0b36ea8..a160122 100644 (file)
@@ -89,6 +89,7 @@ selection_solvables(Pool *pool, Queue *selection, Queue *pkgs)
   for (i = 0; i < selection->count; i += 2)
     {
       Id select = selection->elements[i] & SOLVER_SELECTMASK;
+      Id id = selection->elements[i + 1];
       if (select == SOLVER_SOLVABLE_ALL)
        {
          FOR_POOL_SOLVABLES(p)
@@ -97,16 +98,18 @@ selection_solvables(Pool *pool, Queue *selection, Queue *pkgs)
       if (select == SOLVER_SOLVABLE_REPO)
        {
          Solvable *s;
-         Repo *repo = pool_id2repo(pool, selection->elements[i + 1]);
+         Repo *repo = pool_id2repo(pool, id);
          if (repo)
            {
              FOR_REPO_SOLVABLES(repo, p, s)
                queue_push(pkgs, p);
            }
        }
+      else if (select == SOLVER_SOLVABLE)
+       queue_push(pkgs, id);
       else
        {
-         FOR_JOB_SELECT(p, pp, select, selection->elements[i + 1])
+         FOR_JOB_SELECT(p, pp, select, id)
            queue_push(pkgs, p);
        }
     }
@@ -260,7 +263,7 @@ selection_filter_rel(Pool *pool, Queue *selection, Id relflags, Id relevr)
 /* limit a selection to to repository */
 /* prunes empty jobs */
 static void
-selection_filter_repo(Pool *pool, Queue *selection, Repo *repo)
+selection_filter_repo(Pool *pool, Queue *selection, Repo *repo, int setflags)
 {
   Queue q;
   int i, j;
@@ -285,7 +288,12 @@ selection_filter_repo(Pool *pool, Queue *selection, Repo *repo)
       else if (select == SOLVER_SOLVABLE_REPO)
        {
          if (id != repo->repoid)
-           select = 0;
+           continue;
+       }
+      else if (select == SOLVER_SOLVABLE)
+       {
+         if (pool->solvables[id].repo != repo)
+           continue;
        }
       else
        {
@@ -299,11 +307,11 @@ selection_filter_repo(Pool *pool, Queue *selection, Repo *repo)
              else
                queue_push(&q, p);
            }
-         if (bad || !q.count)
+         if (!q.count)
+           continue;
+         if (bad)
            {
-             if (!q.count)
-               select = 0;             /* prune empty jobs */
-             else if (q.count == 1)
+             if (q.count == 1)
                {
                  select = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
                  id = q.elements[0];
@@ -315,8 +323,6 @@ selection_filter_repo(Pool *pool, Queue *selection, Repo *repo)
                }
            }
        }
-      if (!select)
-       continue;       /* job is now empty */
       if (select == SOLVER_SOLVABLE_REPO)
        {
          Id p;
@@ -326,7 +332,7 @@ selection_filter_repo(Pool *pool, Queue *selection, Repo *repo)
          if (!p)
            continue;   /* repo is empty */
        }
-      selection->elements[j++] = select | (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SETREPO;
+      selection->elements[j++] = select | (selection->elements[i] & ~SOLVER_SELECTMASK) | setflags;
       selection->elements[j++] = id;
     }
   queue_truncate(selection, j);
@@ -538,8 +544,8 @@ selection_addextra_provides(Pool *pool, Queue *selection, const char *name, int
 }
 
 /* this is the fast path of selection_provides: the id for the name
- * is known and thus we can quickly check the existance of a
- * package with that provides */
+ * is known and thus we can use the whatprovides data to quickly
+ * check the existance of a package with that provides */
 static int
 selection_provides_id(Pool *pool, Queue *selection, Id id, int flags)
 {
@@ -550,20 +556,18 @@ selection_provides_id(Pool *pool, Queue *selection, Id id, int flags)
       Solvable *s = pool->solvables + p;
       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
        continue;
-      break;
-    }
-  if (p)
-    {
       queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
       return SELECTION_PROVIDES;
     }
 
   if ((flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
     {
+      /* misuse selection_addextra to test if there is an extra package
+       * that provides the id */
       queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
       selection_addextra(pool, selection, flags);
       if (selection->elements[0] == SOLVER_SOLVABLE_PROVIDES)
-       queue_empty(selection);
+       queue_empty(selection);         /* no extra package found */
       else
        {
           selection->elements[0] = SOLVER_SOLVABLE_PROVIDES;
@@ -575,7 +579,6 @@ selection_provides_id(Pool *pool, Queue *selection, Id id, int flags)
   return 0;
 }
 
-/* add missing provides matchers to the selection */
 /* match the provides of a package */
 /* note that we only return raw SOLVER_SOLVABLE_PROVIDES jobs
  * so that the selection can be modified later. */
@@ -619,7 +622,7 @@ selection_provides(Pool *pool, Queue *selection, const char *name, int flags)
   for (id = 1; id < pool->ss.nstrings; id++)
     {
       /* do we habe packages providing this id? */
-      if (!pool->whatprovides[id] || pool->whatprovides[id] == 1)
+      if ((!pool->whatprovides[id] && pool->addedfileprovides == 2) || pool->whatprovides[id] == 1)
        continue;
       n = pool_id2str(pool, id);
       if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
@@ -632,6 +635,13 @@ selection_provides(Pool *pool, Queue *selection, const char *name, int flags)
              if (!p)
                continue;
            }
+         else if (!pool->whatprovides[id])
+           {
+             FOR_PROVIDES(p, pp, id)
+               break;
+             if (!p)
+               continue;
+           }
          queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
          match = 1;
        }
@@ -704,6 +714,34 @@ selection_name_id(Pool *pool, Queue *selection, Id id, int flags)
   return 0;
 }
 
+/* does not check SELECTION_INSTALLED_ONLY, as it is normally done
+ * by other means */
+static inline int
+solvable_matches_selection_flags(Pool *pool, Solvable *s, int flags)
+{
+  if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+    {
+      if (!(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
+       return 0;
+      /* source package are never installed and never have a bad arch */
+      if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+       return 0;
+    }
+  else
+    {
+      if ((flags & SELECTION_SOURCE_ONLY) != 0)
+       return 0;
+      if (s->repo != pool->installed)
+       {
+         if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+           return 0;
+         if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
+           return 0;
+       }
+    }
+  return 1;
+}
+
 /* match the name of a package */
 /* note that for SELECTION_INSTALLED_ONLY the result is not trimmed */
 static int
@@ -743,20 +781,8 @@ selection_name(Pool *pool, Queue *selection, const char *name, int flags)
       Solvable *s = pool->solvables + p;
       if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
        continue;
-      if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
-       {
-         if (!(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
-           continue;
-         if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
-           continue;
-       }
-      else if (s->repo != pool->installed)
-       {
-         if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
-           continue;
-         if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
-           continue;
-       }
+      if (!solvable_matches_selection_flags(pool, s, flags))
+       continue;
       id = s->name;
       n = pool_id2str(pool, id);
       if (flags & SELECTION_SKIP_KIND)
@@ -940,31 +966,14 @@ selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
   if ((flags & SELECTION_NOCASE) != 0)
     type |= SEARCH_NOCASE;
   queue_init(&q);
-  dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
+  dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES);
   while (dataiterator_step(&di))
     {
       Solvable *s = pool->solvables + di.solvid;
       if (!s->repo)
        continue;
-      if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
-       {
-         if (!(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
-           continue;
-         if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
-           continue;
-       }
-      else
-       {
-         if ((flags & SELECTION_SOURCE_ONLY) != 0)
-           continue;
-         if (s->repo != pool->installed)
-           {
-             if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
-               continue;
-             if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
-               continue;
-           }
-       }
+      if (!solvable_matches_selection_flags(pool, s, flags))
+       continue;
       if ((flags & SELECTION_FLAT) != 0)
        {
          /* don't bother with the complex stuff */
@@ -1291,46 +1300,57 @@ selection_extrabits(Pool *pool, Queue *selection, int flags)
   return needflags;
 }
 
+static int
+selection_combine(Pool *pool, Queue *sel1, Queue *sel2, int flags, int ret)
+{
+  if ((flags & SELECTION_MODEBITS) == SELECTION_ADD)
+    selection_add(pool, sel1, sel2);
+  else if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT)
+    selection_subtract(pool, sel1, sel2);
+  else if ((flags & SELECTION_MODEBITS) == SELECTION_FILTER)
+    {
+      if (ret || !(flags & SELECTION_FILTER_KEEP_IFEMPTY))
+       {
+         if ((flags & SELECTION_FILTER_SWAPPED) != 0)
+           {
+             selection_filter(pool, sel2, sel1);
+             queue_free(sel1);
+             queue_init_clone(sel1, sel2);
+           }
+         else
+           selection_filter(pool, sel1, sel2);
+       }
+    }
+  else /* SELECTION_REPLACE */
+    {
+      queue_free(sel1);
+      queue_init_clone(sel1, sel2);
+    }
+  queue_free(sel2);
+  return ret;
+}
+
 int
 selection_make(Pool *pool, Queue *selection, const char *name, int flags)
 {
   int ret = 0;
-  if ((flags & SELECTION_MODEBITS) != 0)
+  if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
     {
       Queue q;
 
-      queue_init(&q);
       if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT || (flags & SELECTION_MODEBITS) == SELECTION_FILTER)
        {
          if (!selection->count)
-           {
-             queue_free(&q);
-             return 0;
-           }
+           return 0;
          if ((flags & (SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) != 0)
            {
              /* try to drop expensive extra bits */
              flags = (flags & ~(SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) | selection_extrabits(pool, selection, flags);
            }
        }
+      queue_init(&q);
       ret = selection_make(pool, &q, name, flags & ~SELECTION_MODEBITS);
-      if ((flags & SELECTION_MODEBITS) == SELECTION_ADD)
-       selection_add(pool, selection, &q);
-      else if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT)
-       selection_subtract(pool, selection, &q);
-      else if (ret || !(flags & SELECTION_FILTER_KEEP_IFEMPTY))
-       {
-         if ((flags & SELECTION_FILTER_SWAPPED) != 0)
-           {
-             selection_filter(pool, &q, selection);
-             queue_free(selection);
-             queue_init_clone(selection, &q);
-           }
-         else
-           selection_filter(pool, selection, &q);
-       }
-      queue_free(&q);
-      return ret;
+      return selection_combine(pool, selection, &q, flags, ret);
     }
   queue_empty(selection);
   if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
@@ -1348,7 +1368,7 @@ selection_make(Pool *pool, Queue *selection, const char *name, int flags)
 
   /* now do result filtering */
   if (ret && (flags & SELECTION_INSTALLED_ONLY) != 0)
-    selection_filter_repo(pool, selection, pool->installed);
+    selection_filter_repo(pool, selection, pool->installed, SOLVER_SETREPO);
 
   /* flatten if requested */
   if (ret && (flags & SELECTION_FLAT) != 0)
@@ -1356,30 +1376,6 @@ selection_make(Pool *pool, Queue *selection, const char *name, int flags)
   return selection->count ? ret : 0;
 }
 
-struct limiter {
-  int start;   /* either 2 or repofilter->start */
-  int end;     /* either nsolvables or repofilter->end */
-  Id *mapper;
-  Repo *repofilter;
-};
-
-/* add matching src packages to simple SOLVABLE_NAME selections */
-static void
-setup_limiter(Pool *pool, int flags, struct limiter *limiter)
-{
-  limiter->start = 2;
-  limiter->end = pool->nsolvables;
-  limiter->mapper = 0;
-  limiter->repofilter = 0;
-  if ((flags & SELECTION_INSTALLED_ONLY) != 0)
-    {
-      Repo *repo = pool->installed;
-      limiter->repofilter = repo;
-      limiter->start = repo ? repo->start : 0;
-      limiter->end = repo ? repo->end : 0;
-    }
-}
-
 static int
 matchdep_str(const char *pattern, const char *string, int flags)
 {
@@ -1430,8 +1426,88 @@ matchdep(Pool *pool, Id id, char *rname, int rflags, Id revr, int flags)
   return matchdep_str(rname, pool_id2str(pool, id), flags);
 }
 
+struct limiter {
+  int start;   /* either 2 or repofilter->start */
+  int end;     /* either nsolvables or repofilter->end */
+  Repo *repofilter;
+  Id *mapper;
+  Queue qlimit;
+};
+
+
+static int
+selection_make_matchsolvable_common(Pool *pool, Queue *selection, Queue *solvidq, Id solvid, int flags, int keyname, int marker, struct limiter *limiter)
+{
+  Map m, missc;
+  int reloff;
+  int li, i, j;
+  Id p;
+  Queue q;
+
+  if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
+    {
+      int ret;
+      Queue q;
+      queue_init(&q);
+      ret = selection_make_matchsolvable_common(pool, &q, solvidq, solvid, flags & ~SELECTION_MODEBITS, keyname, marker, limiter);
+      return selection_combine(pool, selection, &q, flags, ret);
+    }
+
+  queue_empty(selection);
+  if (!limiter->end)
+    return 0;
+  if (!solvidq && !solvid)
+    return 0;
+  if (solvidq && solvid)
+    return 0;
+
+  if (solvidq)
+    {
+      map_init(&m, pool->nsolvables);
+      for (i = 0; i < solvidq->count; i++)
+       MAPSET(&m, solvidq->elements[i]);
+    }
+  queue_init(&q);
+  reloff = pool->ss.nstrings;
+  map_init(&missc, reloff + pool->nrels);
+  for (li = limiter->start; li < limiter->end; li++)
+    {
+      Solvable *s;
+      p = limiter->mapper ? limiter->mapper[li] : li;
+      if (solvidq && MAPTST(&m, p))
+       continue;
+      if (!solvidq && p == solvid)
+       continue;
+      s = pool->solvables + p;
+      if (!s->repo || (limiter->repofilter && s->repo != limiter->repofilter))
+       continue;
+      if (!solvable_matches_selection_flags(pool, s, flags))
+       continue;
+      if (solvable_matchessolvable_int(s, keyname, marker, solvid, solvidq ? &m : 0, &q, &missc, reloff))
+        queue_push(selection, p);
+    }
+  queue_free(&q);
+  map_free(&missc);
+  if (solvidq)
+    map_free(&m);
+
+  /* convert package list to selection */
+  if (!selection->count)
+    return 0;
+  j = selection->count;
+  queue_insertn(selection, 0, selection->count, 0);
+  for (i = 0; i < selection->count; i += 2)
+    {
+      selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+      selection->elements[i + 1] = selection->elements[j++];
+    }
+  if ((flags & SELECTION_FLAT) != 0)
+    selection_flatten(pool, selection);
+  return SELECTION_PROVIDES;
+}
+
 static int
-selection_make_matchdeps_common_limited(Pool *pool, Queue *selection, const char *name, Id dep, int flags, int keyname, int marker, struct limiter *limiter)
+selection_make_matchdeps_common(Pool *pool, Queue *selection, const char *name, Id dep, int flags, int keyname, int marker, struct limiter *limiter)
 {
   int li, i, j;
   int ret = 0;
@@ -1441,6 +1517,14 @@ selection_make_matchdeps_common_limited(Pool *pool, Queue *selection, const char
   Id p;
   Queue q;
 
+  if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
+    {
+      Queue q;
+      queue_init(&q);
+      ret = selection_make_matchdeps_common(pool, &q, name, dep, flags & ~SELECTION_MODEBITS, keyname, marker, limiter);
+      return selection_combine(pool, selection, &q, flags, ret);
+    }
+
   queue_empty(selection);
   if (!limiter->end)
     return 0;
@@ -1468,7 +1552,7 @@ selection_make_matchdeps_common_limited(Pool *pool, Queue *selection, const char
          revr = pool_str2id(pool, r, 1);
          ret |= SELECTION_REL;
        }
-      if ((flags & SELECTION_GLOB) != 0 && strpbrk(rname, "[*?") == 0)
+      if ((flags & SELECTION_GLOB) != 0 && !strpbrk(rname, "[*?") != 0)
        flags &= ~SELECTION_GLOB;
 
       if ((flags & SELECTION_GLOB) == 0 && (flags & SELECTION_NOCASE) == 0 && (flags & SELECTION_MATCH_DEPSTR) == 0)
@@ -1505,25 +1589,8 @@ selection_make_matchdeps_common_limited(Pool *pool, Queue *selection, const char
       s = pool->solvables + p;
       if (!s->repo || (limiter->repofilter && s->repo != limiter->repofilter))
        continue;
-      if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
-       {
-         if (!(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
-           continue;
-         if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
-           continue;
-       }
-      else
-        {
-         if ((flags & SELECTION_SOURCE_ONLY) != 0)
-           continue;
-         if (s->repo != pool->installed)
-           {
-             if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
-               continue;
-             if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
-               continue;
-           }
-       }
+      if (!solvable_matches_selection_flags(pool, s, flags))
+       continue;
       if (keyname == SOLVABLE_NAME)                    /* nevr match hack */
        {
          if (dep)
@@ -1558,7 +1625,8 @@ selection_make_matchdeps_common_limited(Pool *pool, Queue *selection, const char
          queue_push(selection, p);
          continue;
        }
-      queue_empty(&q);
+      if (q.count)
+        queue_empty(&q);
       repo_lookup_deparray(s->repo, p, keyname, &q, marker);
       if (!q.count)
        continue;
@@ -1597,16 +1665,16 @@ selection_make_matchdeps_common_limited(Pool *pool, Queue *selection, const char
     }
   queue_free(&q);
   solv_free(rname);
-  if (!selection->count)
-    return 0;
 
   /* convert package list to selection */
+  if (!selection->count)
+    return 0;
   j = selection->count;
   queue_insertn(selection, 0, selection->count, 0);
-  for (i = 0; i < selection->count; )
+  for (i = 0; i < selection->count; i += 2)
     {
-      selection->elements[i++] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
-      selection->elements[i++] = selection->elements[j++];
+      selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+      selection->elements[i + 1] = selection->elements[j++];
     }
 
   if ((flags & SELECTION_FLAT) != 0)
@@ -1614,75 +1682,56 @@ selection_make_matchdeps_common_limited(Pool *pool, Queue *selection, const char
   return ret | (keyname == SOLVABLE_NAME ? SELECTION_NAME : SELECTION_PROVIDES);
 }
 
-static int
-selection_make_matchdeps_common(Pool *pool, Queue *selection, const char *name, Id dep, int flags, int keyname, int marker)
+static void
+setup_limiter(Pool *pool, Queue *selection, int flags, struct limiter *limiter)
 {
-  struct limiter limiter;
-
-  setup_limiter(pool, flags, &limiter);
-  if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
+  limiter->start = 2;
+  limiter->end = pool->nsolvables;
+  limiter->mapper = 0;
+  limiter->repofilter = 0;
+  if ((flags & SELECTION_INSTALLED_ONLY) != 0)
     {
-      int ret;
-      Queue q, qlimit;
-      queue_init(&q);
-      queue_init(&qlimit);
-      /* deal with special filter cases */
-      if ((flags & SELECTION_MODEBITS) == SELECTION_FILTER && selection->count == 2 && limiter.end)
-       {
-         if ((selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
-           flags = (flags & ~SELECTION_MODEBITS) | SELECTION_REPLACE;
-         else if ((selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO)
-           {
-             Repo *repo = pool_id2repo(pool, selection->elements[1]);
-             if (limiter.repofilter && repo != limiter.repofilter)
-               repo = 0;
-             limiter.repofilter = repo;
-             limiter.start = repo ? repo->start : 0;
-             limiter.end = repo ? repo->end : 0;
-             flags = (flags & ~SELECTION_MODEBITS) | SELECTION_REPLACE;
-           }
-       }
-      if (limiter.end && ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT || (flags & SELECTION_MODEBITS) == SELECTION_FILTER))
-       {
-         selection_solvables(pool, selection, &qlimit);
-         limiter.start = 0;
-         limiter.end = qlimit.count;
-         limiter.mapper = qlimit.elements;
-       }
-      ret = selection_make_matchdeps_common_limited(pool, &q, name, dep, flags & ~SELECTION_MODEBITS, keyname, marker, &limiter);
-      queue_free(&qlimit);
-      if ((flags & SELECTION_MODEBITS) == SELECTION_ADD)
-       selection_add(pool, selection, &q);
-      else if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT)
-       selection_subtract(pool, selection, &q);
-      else if ((flags & SELECTION_MODEBITS) == SELECTION_FILTER)
-       {
-          if (ret || !(flags & SELECTION_FILTER_KEEP_IFEMPTY))
-           {
-             if ((flags & SELECTION_FILTER_SWAPPED) != 0)
-               {
-                 selection_filter(pool, &q, selection);
-                 queue_free(selection);
-                 queue_init_clone(selection, &q);
-               }
-             else
-               selection_filter(pool, selection, &q);
-           }
-       }
-      else if (ret || !(flags & SELECTION_FILTER_KEEP_IFEMPTY))
-       {
-         /* special filter case from above */
-         int i;
-         Id f = selection->elements[0] & ~(SOLVER_SELECTMASK|SOLVER_NOAUTOSET);        /* job, jobflags, setflags */
-         queue_free(selection);
-         queue_init_clone(selection, &q);
-         for (i = 0; i < selection->count; i += 2)
-           selection->elements[i] = (selection->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | f;
-       }
-      queue_free(&q);
-      return ret;
+      Repo *repo = pool->installed;
+      limiter->repofilter = repo;
+      limiter->start = repo ? repo->start : 0;
+      limiter->end = repo ? repo->end : 0;
+    }
+  if ((flags & SELECTION_MODEBITS) != SELECTION_SUBTRACT && (flags & SELECTION_MODEBITS) != SELECTION_FILTER)
+    return;
+  /* the result will be limited to the first selection */
+  if (!selection->count)
+    limiter->start = limiter->end = 0;
+  if (!limiter->end)
+    return;
+  /* check for special cases where we do not need to call selection_solvables() */
+  if (selection->count == 2 && (selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
+    return;
+  if (selection->count == 2 && (selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO)
+    {
+      Repo *repo = pool_id2repo(pool, selection->elements[1]);
+      if (limiter->repofilter && repo != limiter->repofilter)
+       repo = 0;
+      limiter->repofilter = repo;
+      limiter->start = repo ? repo->start : 0;
+      limiter->end = repo ? repo->end : 0;
+      return;
     }
-  return selection_make_matchdeps_common_limited(pool, selection, name, dep, flags, keyname, marker, &limiter);
+  /* convert selection into a package list and use it in the limiter */
+  queue_init(&limiter->qlimit);
+  selection_solvables(pool, selection, &limiter->qlimit);
+  limiter->start = 0;
+  limiter->end = limiter->qlimit.count;
+  if (!limiter->qlimit.count)
+    queue_free(&limiter->qlimit);
+  else
+    limiter->mapper = limiter->qlimit.elements;
+}
+
+static void
+free_limiter(struct limiter *limiter)
+{
+  if (limiter->mapper)
+    queue_free(&limiter->qlimit);
 }
 
 /*
@@ -1696,7 +1745,12 @@ selection_make_matchdeps_common(Pool *pool, Queue *selection, const char *name,
 int
 selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker)
 {
-  return selection_make_matchdeps_common(pool, selection, name, 0, flags, keyname, marker);
+  struct limiter limiter;
+  int ret;
+  setup_limiter(pool, selection, flags, &limiter);
+  ret = selection_make_matchdeps_common(pool, selection, name, 0, flags, keyname, marker, &limiter);
+  free_limiter(&limiter);
+  return ret;
 }
 
 /*
@@ -1705,7 +1759,34 @@ selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int fla
 int
 selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker)
 {
-  return selection_make_matchdeps_common(pool, selection, 0, dep, flags, keyname, marker);
+  struct limiter limiter;
+  int ret;
+  setup_limiter(pool, selection, flags, &limiter);
+  ret = selection_make_matchdeps_common(pool, selection, 0, dep, flags, keyname, marker, &limiter);
+  free_limiter(&limiter);
+  return ret;
+}
+
+int
+selection_make_matchsolvable(Pool *pool, Queue *selection, Id solvid, int flags, int keyname, int marker)
+{
+  struct limiter limiter;
+  int ret;
+  setup_limiter(pool, selection, flags, &limiter);
+  ret = selection_make_matchsolvable_common(pool, selection, 0, solvid, flags, keyname, marker, &limiter);
+  free_limiter(&limiter);
+  return ret;
+}
+
+int
+selection_make_matchsolvablelist(Pool *pool, Queue *selection, Queue *solvidq, int flags, int keyname, int marker)
+{
+  struct limiter limiter;
+  int ret;
+  setup_limiter(pool, selection, flags, &limiter);
+  ret = selection_make_matchsolvable_common(pool, selection, solvidq, 0, flags, keyname, marker, &limiter);
+  free_limiter(&limiter);
+  return ret;
 }
 
 static inline int
@@ -1742,7 +1823,9 @@ selection_filter_map(Pool *pool, Queue *sel, Map *m, int setflags)
   for (i = j = 0; i < sel->count; i += 2)
     {
       Id select = sel->elements[i] & SOLVER_SELECTMASK;
-      queue_empty(&q);
+      Id id = sel->elements[i + 1];
+      if (q.count)
+        queue_empty(&q);
       miss = 0;
       if (select == SOLVER_SOLVABLE_ALL)
        {
@@ -1757,7 +1840,7 @@ selection_filter_map(Pool *pool, Queue *sel, Map *m, int setflags)
       else if (select == SOLVER_SOLVABLE_REPO)
        {
          Solvable *s;
-         Repo *repo = pool_id2repo(pool, sel->elements[i + 1]);
+         Repo *repo = pool_id2repo(pool, id);
          if (repo)
            {
              FOR_REPO_SOLVABLES(repo, p, s)
@@ -1769,9 +1852,18 @@ selection_filter_map(Pool *pool, Queue *sel, Map *m, int setflags)
                }
            }
        }
+      else if (select == SOLVER_SOLVABLE)
+       {
+         if (!map_tst(m, id))
+           continue;
+         sel->elements[j] = sel->elements[i] | setflags;
+         sel->elements[j + 1] = id;
+          j += 2;
+         continue;
+       }
       else
        {
-         FOR_JOB_SELECT(p, pp, select, sel->elements[i + 1])
+         FOR_JOB_SELECT(p, pp, select, id)
            {
              if (map_tst(m, p))
                queue_pushunique(&q, p);
@@ -1784,7 +1876,7 @@ selection_filter_map(Pool *pool, Queue *sel, Map *m, int setflags)
       if (!miss)
        {
          sel->elements[j] = sel->elements[i] | setflags;
-         sel->elements[j + 1] = sel->elements[i + 1];
+         sel->elements[j + 1] = id;
        }
       else if (q.count > 1)
        {
@@ -1811,6 +1903,7 @@ selection_filter_int(Pool *pool, Queue *sel1, Queue *sel2, int invert)
   Map m2;
   Id setflags = 0;
 
+  /* handle special cases */
   if (!sel1->count || !sel2->count)
     {
       if (invert && !sel2->count)
@@ -1821,11 +1914,35 @@ selection_filter_int(Pool *pool, Queue *sel1, Queue *sel2, int invert)
   if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL && !invert)
     {
       /* XXX: not 100% correct, but very useful */
-      p = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_SETMASK);   /* job & jobflags */
+      setflags = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_SETMASK);    /* job & jobflags */
       queue_free(sel1);
       queue_init_clone(sel1, sel2);
       for (i = 0; i < sel1->count; i += 2)
-        sel1->elements[i] = (sel1->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | p ;
+        sel1->elements[i] = (sel1->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | setflags;
+      return;
+    }
+  if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO && !invert)
+    {
+      Repo *repo = pool_id2repo(pool, sel1->elements[1]);
+      setflags = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_NOAUTOSET);  /* job, jobflags, setflags */
+      queue_free(sel1);
+      queue_init_clone(sel1, sel2);
+      for (i = 0; i < sel1->count; i += 2)
+        sel1->elements[i] &= SOLVER_SELECTMASK | SOLVER_SETMASK;       /* remove job and jobflags */
+      selection_filter_repo(pool, sel1, repo, setflags);
+      return;
+    }
+  if (sel2->count == 2 && (sel2->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
+    {
+      if (invert)
+       queue_empty(sel1);
+      return;
+    }
+  if (sel2->count == 2 && (sel2->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO && !invert)
+    {
+      Repo *repo = pool_id2repo(pool, sel2->elements[1]);
+      setflags = sel2->elements[0] & (SOLVER_SETMASK & ~SOLVER_NOAUTOSET);
+      selection_filter_repo(pool, sel1, repo, setflags);
       return;
     }
 
@@ -1897,7 +2014,7 @@ selection_filter_int(Pool *pool, Queue *sel1, Queue *sel2, int invert)
   if (invert)
     map_invertall(&m2);
   if (sel2->count == 2)
-    setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET;
+    setflags = sel2->elements[0] & (SOLVER_SETMASK & ~SOLVER_NOAUTOSET);
   selection_filter_map(pool, sel1, &m2, setflags);
   map_free(&m2);
 }
index 9938c2f..8e60a27 100644 (file)
@@ -52,16 +52,19 @@ extern "C" {
 #define SELECTION_SUBTRACT             (2 << 28)
 #define SELECTION_FILTER               (3 << 28)
 
-#define SELECTION_MODEBITS             (3 << 28)       /* internal */
 
 /* extra SELECTION_FILTER bits */
 #define SELECTION_FILTER_KEEP_IFEMPTY  (1 << 30)
 #define SELECTION_FILTER_SWAPPED       (1 << 31)
 
+/* internal */
+#define SELECTION_MODEBITS             (3 << 28)
 
 extern int  selection_make(Pool *pool, Queue *selection, const char *name, int flags);
 extern int  selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker);
 extern int  selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker);
+extern int selection_make_matchsolvable(Pool *pool, Queue *selection, Id solvid, int flags, int keyname, int marker);
+extern int selection_make_matchsolvablelist(Pool *pool, Queue *selection, Queue *solvidq, int flags, int keyname, int marker);
 
 extern void selection_filter(Pool *pool, Queue *sel1, Queue *sel2);
 extern void selection_add(Pool *pool, Queue *sel1, Queue *sel2);
index 220af32..5377360 100644 (file)
  * uintXX_t (from inttypes.h), you may need to define things by hand
  * for your system:
  */
-typedef struct _SHA256_CTX {
+typedef struct s_SHA256_CTX {
        uint32_t        state[8];
        uint64_t        bitcount;
        uint32_t        buffer[SHA256_BLOCK_LENGTH/4];
 } SHA256_CTX;
-typedef struct _SHA512_CTX {
+typedef struct s_SHA512_CTX {
        uint64_t        state[8];
        uint64_t        bitcount[2];
        uint64_t        buffer[SHA512_BLOCK_LENGTH/8];
index 6f6ba1d..331f290 100644 (file)
@@ -257,14 +257,14 @@ solvable_lookup_num(Solvable *s, Id keyname, unsigned long long notfound)
   return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound);
 }
 
-unsigned int
-solvable_lookup_sizek(Solvable *s, Id keyname, unsigned int notfound)
+unsigned long long
+solvable_lookup_sizek(Solvable *s, Id keyname, unsigned long long notfound)
 {
   unsigned long long size;
   if (!s->repo)
     return notfound;
-  size = solvable_lookup_num(s, keyname, (unsigned long long)notfound << 10);
-  return (unsigned int)((size + 1023) >> 10);
+  size = solvable_lookup_num(s, keyname, (unsigned long long)-1);
+  return size == (unsigned long long)-1 ? notfound : ((size + 1023) >> 10);
 }
 
 int
@@ -613,3 +613,67 @@ solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker)
   queue_free(&q);
   return i;
 }
+
+int
+solvable_matchessolvable_int(Solvable *s, Id keyname, int marker, Id solvid, Map *solvidmap, Queue *depq, Map *missc, int reloff)
+{
+  Pool *pool = s->repo->pool;
+  int i, boff;
+  Id *wp;
+
+  if (depq->count)
+    queue_empty(depq);
+  solvable_lookup_deparray(s, keyname, depq, marker);
+  for (i = 0; i < depq->count; i++)
+    {
+      Id dep = depq->elements[i];
+      boff = ISRELDEP(dep) ? reloff + GETRELID(dep) : dep;
+      if (MAPTST(missc, boff))
+       continue;
+      if (ISRELDEP(dep))
+       {
+         Reldep *rd = GETRELDEP(pool, dep);
+         if (!ISRELDEP(rd->name) && rd->flags < 8)
+           {
+             /* do pre-filtering on the base */
+             if (MAPTST(missc, rd->name))
+               continue;
+             wp = pool_whatprovides_ptr(pool, rd->name);
+             if (solvidmap)
+               {
+                 for (; *wp; wp++)
+                   if (MAPTST(solvidmap, *wp))
+                     break;
+               }
+             else
+               {
+                 for (; *wp; wp++)
+                   if (*wp == solvid)
+                     break;
+               }
+             if (!*wp)
+               {
+                 /* the base does not include solvid, no need to check the complete dep */
+                 MAPSET(missc, rd->name);
+                 MAPSET(missc, boff);
+                 continue;
+               }
+           }
+       }
+      wp = pool_whatprovides_ptr(pool, dep);
+      if (solvidmap)
+       {
+         for (; *wp; wp++)
+           if (MAPTST(solvidmap, *wp))
+             return 1;
+       }
+      else
+       {
+         for (; *wp; wp++)
+           if (*wp == solvid)
+             return 1;
+       }
+      MAPSET(missc, boff);
+    }
+  return 0;
+}
index 090b758..bf92a00 100644 (file)
 extern "C" {
 #endif
 
-struct _Repo;
+struct s_Repo;
 
-typedef struct _Solvable {
+typedef struct s_Solvable {
   Id name;
   Id arch;
   Id evr;                      /* epoch:version-release */
   Id vendor;
 
-  struct _Repo *repo;          /* repo we belong to */
+  struct s_Repo *repo;         /* repo we belong to */
 
   /* dependencies are offsets into repo->idarraydata */
   Offset provides;             /* terminated with Id 0 */
@@ -51,7 +51,7 @@ typedef struct _Solvable {
 Id solvable_lookup_type(Solvable *s, Id keyname);
 Id solvable_lookup_id(Solvable *s, Id keyname);
 unsigned long long solvable_lookup_num(Solvable *s, Id keyname, unsigned long long notfound);
-unsigned int solvable_lookup_sizek(Solvable *s, Id keyname, unsigned int notfound);
+unsigned long long solvable_lookup_sizek(Solvable *s, Id keyname, unsigned long long notfound);
 const char *solvable_lookup_str(Solvable *s, Id keyname);
 const char *solvable_lookup_str_poollang(Solvable *s, Id keyname);
 const char *solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase);
@@ -79,13 +79,18 @@ void solvable_unset(Solvable *s, Id keyname);
 
 int solvable_identical(Solvable *s1, Solvable *s2);
 Id solvable_selfprovidedep(Solvable *s);
+
 int solvable_matchesdep(Solvable *s, Id keyname, Id dep, int marker);
 
+/* internal */
+int solvable_matchessolvable_int(Solvable *s, Id keyname, int marker, Id solvid, Map *solvidmap, Queue *depq, Map *missc, int reloff);
+
+
 /* weird suse stuff */
 int solvable_is_irrelevant_patch(Solvable *s, Map *installedmap);
 int solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap, Map *multiversionmap);
 int solvable_trivial_installable_queue(Solvable *s, Queue *installed, Map *multiversionmap);
-int solvable_trivial_installable_repo(Solvable *s, struct _Repo *installed, Map *multiversionmap);
+int solvable_trivial_installable_repo(Solvable *s, struct s_Repo *installed, Map *multiversionmap);
 
 #ifdef __cplusplus
 }
index 102d814..a4e0c4b 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 level %d -----\n", level);
+  POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n");
 
   /* 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 decision %d:", -pkg);
+         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
          solver_printruleelement(solv, SOLV_DEBUG_PROPAGATE, 0, -pkg);
         }
 
@@ -462,10 +462,10 @@ propagate(Solver *solv, int level)
              continue;
            }
 
-         IF_POOLDEBUG (SOLV_DEBUG_WATCHES)
+         IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
            {
-             POOL_DEBUG(SOLV_DEBUG_WATCHES, "  watch triggered ");
-             solver_printrule(solv, SOLV_DEBUG_WATCHES, r);
+             POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"  watch triggered ");
+             solver_printrule(solv, SOLV_DEBUG_PROPAGATE, 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_WATCHES)
+                 IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
                    {
                      if (p > 0)
-                       POOL_DEBUG(SOLV_DEBUG_WATCHES, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
+                       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
                      else
-                       POOL_DEBUG(SOLV_DEBUG_WATCHES, "    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
+                       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> 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 */
 }
@@ -1790,69 +1790,6 @@ 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)
 {
@@ -1880,8 +1817,6 @@ resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
        }
       if (i == solv->nrules)
        i = 1;
-      if (solv->focus_best && solv->do_extra_reordering && i >= solv->featurerules)
-       continue;
       r = solv->rules + i;
       if (r->d < 0)            /* ignore disabled rules */
        continue;
@@ -1950,25 +1885,15 @@ 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))
-             {
-               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;
-             }
+             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)
@@ -3032,7 +2957,9 @@ add_update_target(Solver *solv, Id p, Id how)
   Pool *pool = solv->pool;
   Solvable *s = pool->solvables + p;
   Repo *installed = solv->installed;
-  Id pi, pip;
+  Id pi, pip, identicalp;
+  int startcnt, endcnt;
+
   if (!solv->update_targets)
     {
       solv->update_targets = solv_calloc(1, sizeof(Queue));
@@ -3043,6 +2970,8 @@ add_update_target(Solver *solv, Id p, Id how)
       queue_push2(solv->update_targets, p, p);
       return;
     }
+  identicalp = 0;
+  startcnt = solv->update_targets->count;
   FOR_PROVIDES(pi, pip, s->name)
     {
       Solvable *si = pool->solvables + pi;
@@ -3057,9 +2986,9 @@ add_update_target(Solver *solv, Id p, Id how)
       if (how & SOLVER_CLEANDEPS)
        add_cleandeps_updatepkg(solv, pi);
       queue_push2(solv->update_targets, pi, p);
-      /* check if it's ok to keep the installed package */
+      /* remember an installed package that is identical to p */
       if (s->evr == si->evr && solvable_identical(s, si))
-        queue_push2(solv->update_targets, pi, pi);
+       identicalp = pi;
     }
   if (s->obsoletes)
     {
@@ -3089,6 +3018,12 @@ add_update_target(Solver *solv, Id p, Id how)
            }
        }
     }
+  /* also allow upgrading to an identical installed package */
+  if (identicalp)
+    {
+      for (endcnt = solv->update_targets->count; startcnt < endcnt; startcnt += 2)
+       queue_push2(solv->update_targets, solv->update_targets->elements[startcnt], identicalp);
+    }
 }
 
 static int
@@ -3308,7 +3243,6 @@ solver_solve(Solver *solv, Queue *job)
   POOL_DEBUG(SOLV_DEBUG_STATS, "solver started\n");
   POOL_DEBUG(SOLV_DEBUG_STATS, "dosplitprovides=%d, noupdateprovide=%d, noinfarchcheck=%d\n", solv->dosplitprovides, solv->noupdateprovide, solv->noinfarchcheck);
   POOL_DEBUG(SOLV_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allownamechange=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allownamechange, solv->allowarchchange, solv->allowvendorchange);
-  POOL_DEBUG(SOLV_DEBUG_STATS, "dupallowdowngrade=%d, dupallownamechange=%d, dupallowarchchange=%d, dupallowvendorchange=%d\n", solv->dup_allowdowngrade, solv->dup_allownamechange, solv->dup_allowarchchange, solv->dup_allowvendorchange);
   POOL_DEBUG(SOLV_DEBUG_STATS, "promoteepoch=%d, forbidselfconflicts=%d\n", pool->promoteepoch, pool->forbidselfconflicts);
   POOL_DEBUG(SOLV_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d, obsoleteusescolors=%d, implicitobsoleteusescolors=%d\n", pool->obsoleteusesprovides, pool->implicitobsoleteusesprovides, pool->obsoleteusescolors, pool->implicitobsoleteusescolors);
   POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended);
@@ -3812,10 +3746,6 @@ solver_solve(Solver *solv, Queue *job)
                  name_s = s;
                }
              solver_addjobrule(solv, -p, 0, 0, i, weak);
-#ifdef ENABLE_LINKED_PKGS
-             if (solv->instbuddy && installed && s->repo == installed && solv->instbuddy[p - installed->start] > 1)
-               solver_addjobrule(solv, -solv->instbuddy[p - installed->start], 0, 0, i, weak);
-#endif
            }
          /* special case for "erase a specific solvable": we also
           * erase all other solvables with that name, so that they
@@ -3883,14 +3813,7 @@ solver_solve(Solver *solv, Queue *job)
                }
            }
          FOR_JOB_SELECT(p, pp, select, what)
-           {
-             s = pool->solvables + p;
-             solver_addjobrule(solv, installed && s->repo == installed ? p : -p, 0, 0, i, weak);
-#ifdef ENABLE_LINKED_PKGS
-             if (solv->instbuddy && installed && s->repo == installed && solv->instbuddy[p - installed->start] > 1)
-               solver_addjobrule(solv, solv->instbuddy[p - installed->start], 0, 0, i, weak);
-#endif
-           }
+           solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, 0, i, weak);
          break;
        case SOLVER_DISTUPGRADE:
          POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
index ebb2232..4c85b4d 100644 (file)
 extern "C" {
 #endif
 
-struct _Solver {
+struct s_Solver {
   Pool *pool;                          /* back pointer to pool */
   Queue job;                           /* copy of the job we're solving */
 
-  int (*solution_callback)(struct _Solver *solv, void *data);
+  int (*solution_callback)(struct s_Solver *solv, void *data);
   void *solution_callback_data;
 
   int pooljobcnt;                      /* number of pooljob entries in job queue */
@@ -211,7 +211,7 @@ struct _Solver {
 #endif /* LIBSOLV_INTERNAL */
 };
 
-typedef struct _Solver Solver;
+typedef struct s_Solver Solver;
 
 /*
  * queue commands
index f96c5c1..fd13bdb 100644 (file)
@@ -17,7 +17,7 @@ extern "C" {
 #define STRID_NULL  0
 #define STRID_EMPTY 1
 
-struct _Stringpool
+struct s_Stringpool
 {
   Offset *strings;            /* table of offsets into stringspace, indexed by Id: Id -> Offset */
   int nstrings;               /* number of ids in strings table */
index 9a32966..4a4189e 100644 (file)
@@ -828,11 +828,11 @@ transaction_make_installedmap(Transaction *trans, Map *installedmap)
     }
 }
 
-int
+long long
 transaction_calc_installsizechange(Transaction *trans)
 {
   Map installedmap;
-  int change;
+  long long change;
 
   transaction_make_installedmap(trans, &installedmap);
   change = pool_calc_installsizechange(trans->pool, &installedmap);
index c840838..5b01354 100644 (file)
 extern "C" {
 #endif
 
-struct _Pool;
-struct _DUChanges;
-struct _TransactionOrderdata;
+struct s_Pool;
+struct s_DUChanges;
+struct s_TransactionOrderdata;
 
-typedef struct _Transaction {
-  struct _Pool *pool;          /* back pointer to pool */
+typedef struct s_Transaction {
+  struct s_Pool *pool;         /* back pointer to pool */
 
   Queue steps;                 /* the transaction steps */
 
@@ -36,7 +36,7 @@ typedef struct _Transaction {
   Map transactsmap;
   Map multiversionmap;
 
-  struct _TransactionOrderdata *orderdata;
+  struct s_TransactionOrderdata *orderdata;
 #endif
 
 } Transaction;
@@ -92,8 +92,8 @@ typedef struct _Transaction {
 #define SOLVER_ORDERCYCLE_NORMAL               1
 #define SOLVER_ORDERCYCLE_CRITICAL             2
 
-extern Transaction *transaction_create(struct _Pool *pool);
-extern Transaction *transaction_create_decisionq(struct _Pool *pool, Queue *decisionq, Map *multiversionmap);
+extern Transaction *transaction_create(struct s_Pool *pool);
+extern Transaction *transaction_create_decisionq(struct s_Pool *pool, Queue *decisionq, Map *multiversionmap);
 extern Transaction *transaction_create_clone(Transaction *srctrans);
 extern void transaction_free(Transaction *trans);
 
@@ -115,8 +115,8 @@ extern void transaction_classify_pkgs(Transaction *trans, int mode, Id type, Id
    packages is returned */
 extern int transaction_installedresult(Transaction *trans, Queue *installedq);
 
-int transaction_calc_installsizechange(Transaction *trans);
-void transaction_calc_duchanges(Transaction *trans, struct _DUChanges *mps, int nmps);
+long long transaction_calc_installsizechange(Transaction *trans);
+void transaction_calc_duchanges(Transaction *trans, struct s_DUChanges *mps, int nmps);
 
 
 
diff --git a/test/testcases/allowuninstall/conflict.t b/test/testcases/allowuninstall/conflict.t
deleted file mode 100644 (file)
index a66d322..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: a 1 1 noarch
-#>=Con: b
-repo available 0 testtags <inline>
-#>=Pkg: b 1 1 noarch
-
-system x86_64 rpm system
-solverflags allowuninstall
-disable pkg a-1-1.noarch@system
-job install name b
-result transaction,problems <inline>
-#>problem a658cbaf info package a-1-1.noarch conflicts with b provided by b-1-1.noarch
-#>problem a658cbaf solution 567aa15d erase a-1-1.noarch@system
-#>problem a658cbaf solution e98e1a37 deljob install name b
diff --git a/test/testcases/allowuninstall/forcebest.t b/test/testcases/allowuninstall/forcebest.t
deleted file mode 100644 (file)
index 38ade6f..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-repo system 0 testtags <inline>
-#>=Pkg: a 1 1 noarch
-#>=Req: b = 1-1
-#>=Pkg: b 1 1 noarch
-repo available 0 testtags <inline>
-#>=Pkg: a 2 1 noarch
-#>=Req: b = 2-1
-#>=Pkg: b 2 1 noarch
-
-system x86_64 rpm system
-disable pkg b-1-1.noarch@system
-disable pkg b-2-1.noarch@available
-job allowuninstall pkg a-1-1.noarch@system
-job allowuninstall pkg b-1-1.noarch@system
-job update name a [forcebest]
-result transaction,problems <inline>
-#>problem e6d3911d info nothing provides b = 2-1 needed by a-2-1.noarch
-#>problem e6d3911d solution 0011b04f allow a-1-1.noarch@system
-#>problem e6d3911d solution 44d189a0 erase a-1-1.noarch@system
diff --git a/test/testcases/cleandeps/cleandeps_up3.t b/test/testcases/cleandeps/cleandeps_up3.t
deleted file mode 100644 (file)
index 7a4bfbc..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-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
diff --git a/test/testcases/selection/selection_matchsolvable.t b/test/testcases/selection/selection_matchsolvable.t
new file mode 100644 (file)
index 0000000..545abc4
--- /dev/null
@@ -0,0 +1,27 @@
+repo available 0 testtags <inline>
+#>=Pkg: A1 1 1 noarch
+#>=Req: B > 1 + B < 3
+#>=Pkg: A2 1 1 noarch
+#>=Req: B > 1 & B < 3
+#>=Pkg: X 1 1 noarch
+#>=Prv: B = 4
+#>=Pkg: Y 1 1 noarch
+#>=Prv: B = 2
+#>=Pkg: A1 2 1 noarch
+system i686 rpm
+
+job noop selection_matchsolvable solvable:requires X-1-1.noarch@available flat
+result jobs <inline>
+#>job noop pkg A2-1-1.noarch@available [noautoset]
+
+nextjob
+job noop selection_matchsolvable solvable:requires Y-1-1.noarch@available flat
+result jobs <inline>
+#>job noop oneof A1-1-1.noarch@available A2-1-1.noarch@available
+
+nextjob
+job noop selection A1 name
+job noop selection_matchsolvable solvable:requires Y-1-1.noarch@available flat,filter
+result jobs <inline>
+#>job noop pkg A1-1-1.noarch@available [noautoset]
+
index ce6c98c..e5a42cf 100644 (file)
@@ -70,7 +70,7 @@ main(int argc, char **argv)
          exit(1);
        }
     }
-  tool_write(repo, 0, 0);
+  tool_write(repo, stdout);
   pool_free(pool);
   exit(0);
 }
index 4ce95a4..14c3ba4 100644 (file)
@@ -57,16 +57,12 @@ main(int argc, char **argv)
   Repo *repo;
   FILE *fp;
   char buf[4096], *p;
-  const char *basefile = 0;
   int flags = 0;
 
-  while ((c = getopt(argc, argv, "0b:m:i")) >= 0)
+  while ((c = getopt(argc, argv, "0:m:i")) >= 0)
     {
       switch(c)
        {
-       case 'b':
-         basefile = optarg;
-         break;
        case 'm':
          manifest = optarg;
          break;
@@ -124,7 +120,7 @@ main(int argc, char **argv)
        res = 1;
       }
   repo_internalize(repo);
-  tool_write(repo, basefile, 0);
+  tool_write(repo, stdout);
   pool_free(pool);
   for (c = 0; c < npkgs; c++)
     solv_free((char *)pkgs[c]);
index 5f8eade..e60960f 100644 (file)
@@ -73,7 +73,7 @@ main(int argc, char **argv)
       fprintf(stderr, "archrepo2solv: %s\n", pool_errstr(pool));
       exit(1);
     }
-  tool_write(repo, 0, 0);
+  tool_write(repo, stdout);
   pool_free(pool);
   exit(0);
 }
index 577b1ab..36f8dd8 100644 (file)
  * 1.1: changed PRODUCT_ENDOFLIFE parsing
 */
 
-static Id verticals[] = {
-  SOLVABLE_AUTHORS,
-  SOLVABLE_DESCRIPTION,
-  SOLVABLE_MESSAGEDEL,
-  SOLVABLE_MESSAGEINS,
-  SOLVABLE_EULA,
-  SOLVABLE_DISKUSAGE,
-  SOLVABLE_FILELIST,
-  SOLVABLE_CHANGELOG_AUTHOR,
-  SOLVABLE_CHANGELOG_TEXT,
-  0
-};
-
-static char *languagetags[] = {
-  "solvable:summary:",
-  "solvable:description:",
-  "solvable:messageins:",
-  "solvable:messagedel:",
-  "solvable:eula:",
-  0
-};
-
-static int test_separate = 0;
-
-struct keyfilter_data {
-  char **languages;
-  int nlanguages;
-  int haveaddedfileprovides;
-  int haveexternal;
-};
-
 static int
-keyfilter_solv(Repo *data, Repokey *key, void *kfdata)
+keyfilter_solv(Repo *repo, Repokey *key, void *kfdata)
 {
-  struct keyfilter_data *kd = kfdata;
-  int i;
-  const char *keyname;
-
-  if (test_separate && key->storage != KEY_STORAGE_SOLVABLE)
-    return KEY_STORAGE_DROPPED;
-  if (!kd->haveaddedfileprovides && key->name == REPOSITORY_ADDEDFILEPROVIDES)
-    return KEY_STORAGE_DROPPED;
-  if (!kd->haveexternal && key->name == REPOSITORY_EXTERNAL)
-    return KEY_STORAGE_DROPPED;
   if (key->name == SUSETAGS_SHARE_NAME || key->name == SUSETAGS_SHARE_EVR || key->name == SUSETAGS_SHARE_ARCH)
     return KEY_STORAGE_DROPPED;
-  for (i = 0; verticals[i]; i++)
-    if (key->name == verticals[i])
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  keyname = pool_id2str(data->pool, key->name);
-  for (i = 0; languagetags[i] != 0; i++)
-    if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  return KEY_STORAGE_INCORE;
-}
-
-static int
-keyfilter_attr(Repo *data, Repokey *key, void *kfdata)
-{
-  int i;
-  const char *keyname;
-  if (key->storage == KEY_STORAGE_SOLVABLE)
-    return KEY_STORAGE_DROPPED;
-  /* those must only be in the main solv file */
-  if (key->name == REPOSITORY_EXTERNAL || key->name == REPOSITORY_ADDEDFILEPROVIDES || key->name == REPOSITORY_TOOLVERSION)
-    return KEY_STORAGE_DROPPED;
-  for (i = 0; verticals[i]; i++)
-    if (key->name == verticals[i])
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  keyname = pool_id2str(data->pool, key->name);
-  for (i = 0; languagetags[i] != 0; i++)
-    if (!strncmp(keyname, languagetags[i], strlen(languagetags[i])))
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  return KEY_STORAGE_INCORE;
-}
-
-static int
-keyfilter_language(Repo *repo, Repokey *key, void *kfdata)
-{
-  Pool *pool = repo->pool;
-  const char *name, *p;
-  char *lang = kfdata;
-  int i;
-
-  name = pool_id2str(repo->pool, key->name);
-  p = strrchr(name, ':');
-  if (!p || strcmp(p + 1, lang) != 0)
-    return KEY_STORAGE_DROPPED;
-  for (i = 0; verticals[i]; i++)
-    {
-      const char *vname = pool_id2str(pool, verticals[i]);
-      if (!strncmp(name, vname, p - name) && vname[p - name] == 0)
-       return KEY_STORAGE_VERTICAL_OFFSET;
-    }
-  return KEY_STORAGE_INCORE;
-}
-
-static int
-keyfilter_DU(Repo *repo, Repokey *key, void *kfdata)
-{
-  int i;
-  if (key->name != SOLVABLE_DISKUSAGE)
-    return KEY_STORAGE_DROPPED;
-  for (i = 0; verticals[i]; i++)
-    if (key->name == verticals[i])
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  return KEY_STORAGE_INCORE;
-}
-
-static int
-keyfilter_FL(Repo *repo, Repokey *key, void *kfdata)
-{
-  int i;
-  if (key->name != SOLVABLE_FILELIST)
-    return KEY_STORAGE_DROPPED;
-  for (i = 0; verticals[i]; i++)
-    if (key->name == verticals[i])
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  return KEY_STORAGE_INCORE;
-}
-
-static int
-keyfilter_other(Repo *repo, Repokey *key, void *kfdata)
-{
-  const char *name, *p;
-  struct keyfilter_data *kd = kfdata;
-  int i;
-
-  if (!kd->haveaddedfileprovides && key->name == REPOSITORY_ADDEDFILEPROVIDES)
-    return KEY_STORAGE_DROPPED;
-  if (!kd->haveexternal && key->name == REPOSITORY_EXTERNAL)
-    return KEY_STORAGE_DROPPED;
-
-  if (key->name == SOLVABLE_FILELIST || key->name == SOLVABLE_DISKUSAGE)
-    return KEY_STORAGE_DROPPED;
-
-  name = pool_id2str(repo->pool, key->name);
-  p = strrchr(name, ':');
-  if (p)
-    {
-      for (i = 0; i < kd->nlanguages; i++)
-       if (!strcmp(p + 1, kd->languages[i]))
-         return KEY_STORAGE_DROPPED;
-    }
-  for (i = 0; verticals[i]; i++)
-    if (key->name == verticals[i])
-      return KEY_STORAGE_VERTICAL_OFFSET;
-  return KEY_STORAGE_INCORE;
+  return repo_write_stdkeyfilter(repo, key, kfdata);
 }
 
 /*
- * Write <repo> to stdout
- * If <attrname> is given, write attributes to <attrname>
- * If <basename> is given, split attributes
+ * Write <repo> to fp
  */
-
-#define REPODATAFILE_BLOCK 15
-
-static void
-write_info(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *key, void *kfdata), void *kfdata, Repodata *info, const char *location)
-{
-  Id h;
-  Queue keyq;
-
-  queue_init(&keyq);
-  if (repo_write_filtered(repo, fp, keyfilter, kfdata, &keyq) != 0)
-    {
-      fprintf(stderr, "repo_write failed\n");
-      exit(1);
-    }
-  h = repodata_new_handle(info);
-  if (keyq.count)
-    repodata_set_idarray(info, h, REPOSITORY_KEYS, &keyq);
-  queue_free(&keyq);
-  repodata_set_str(info, h, REPOSITORY_LOCATION, location);
-  repodata_add_flexarray(info, SOLVID_META, REPOSITORY_EXTERNAL, h);
-}
-
 void
-tool_write(Repo *repo, const char *basename, const char *attrname)
+tool_write(Repo *repo, FILE *fp)
 {
-  Repodata *data;
-  Repodata *info = 0;
-  Repokey *key;
-  char **languages = 0;
-  int nlanguages = 0;
-  int i, j, k, l;
-  struct keyfilter_data kd;
+  Repodata *info;
   Queue addedfileprovides;
+  Repowriter *writer;
 
-  memset(&kd, 0, sizeof(kd));
-  info = repo_add_repodata(repo, 0);
+  info = repo_add_repodata(repo, 0);   /* add new repodata for our meta info */
   repodata_set_str(info, SOLVID_META, REPOSITORY_TOOLVERSION, LIBSOLV_TOOLVERSION);
+  repodata_unset(info, SOLVID_META, REPOSITORY_EXTERNAL);      /* do not propagate this */
+
   queue_init(&addedfileprovides);
   pool_addfileprovides_queue(repo->pool, &addedfileprovides, 0);
   if (addedfileprovides.count)
-    {
-      kd.haveaddedfileprovides = 1;
-      repodata_set_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &addedfileprovides);
-    }
+    repodata_set_idarray(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &addedfileprovides);
+  else
+    repodata_unset(info, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES);
   queue_free(&addedfileprovides);
 
   pool_freeidhashes(repo->pool);       /* free some mem */
 
-  if (basename)
-    {
-      char fn[4096];
-      FILE *fp;
-      int has_DU = 0;
-      int has_FL = 0;
-
-      /* find languages and other info */
-      FOR_REPODATAS(repo, i, data)
-       {
-         for (j = 1, key = data->keys + j; j < data->nkeys; j++, key++)
-           {
-             const char *keyname = pool_id2str(repo->pool, key->name);
-             if (key->name == SOLVABLE_DISKUSAGE)
-               has_DU = 1;
-             if (key->name == SOLVABLE_FILELIST)
-               has_FL = 1;
-             for (k = 0; languagetags[k] != 0; k++)
-               if (!strncmp(keyname, languagetags[k], strlen(languagetags[k])))
-                 break;
-             if (!languagetags[k])
-               continue;
-             l = strlen(languagetags[k]);
-             if (strlen(keyname + l) > 5)
-               continue;
-             for (k = 0; k < nlanguages; k++)
-               if (!strcmp(languages[k], keyname + l))
-                 break;
-             if (k < nlanguages)
-               continue;
-             languages = solv_realloc2(languages, nlanguages + 1, sizeof(char *));
-             languages[nlanguages++] = strdup(keyname + l);
-           }
-       }
-      /* write language subfiles */
-      for (i = 0; i < nlanguages; i++)
-        {
-         sprintf(fn, "%s.%s.solv", basename, languages[i]);
-         if (!(fp = fopen(fn, "w")))
-           {
-             perror(fn);
-             exit(1);
-           }
-         write_info(repo, fp, keyfilter_language, languages[i], info, fn);
-         fclose(fp);
-         kd.haveexternal = 1;
-        }
-      /* write DU subfile */
-      if (has_DU)
-       {
-         sprintf(fn, "%s.DU.solv", basename);
-         if (!(fp = fopen(fn, "w")))
-           {
-             perror(fn);
-             exit(1);
-           }
-         write_info(repo, fp, keyfilter_DU, 0, info, fn);
-         fclose(fp);
-         kd.haveexternal = 1;
-       }
-      /* write filelist */
-      if (has_FL)
-       {
-         sprintf(fn, "%s.FL.solv", basename);
-         if (!(fp = fopen(fn, "w")))
-           {
-             perror(fn);
-             exit(1);
-           }
-         write_info(repo, fp, keyfilter_FL, 0, info, fn);
-         fclose(fp);
-         kd.haveexternal = 1;
-       }
-      /* write everything else */
-      sprintf(fn, "%s.solv", basename);
-      if (!(fp = fopen(fn, "w")))
-       {
-         perror(fn);
-         exit(1);
-       }
-      kd.languages = languages;
-      kd.nlanguages = nlanguages;
-      repodata_internalize(info);
-      if (repo_write_filtered(repo, fp, keyfilter_other, &kd, 0) != 0)
-       {
-         fprintf(stderr, "repo_write failed\n");
-         exit(1);
-       }
-      if (fclose(fp) != 0)
-       {
-         perror("fclose");
-         exit(1);
-       }
-      for (i = 0; i < nlanguages; i++)
-       free(languages[i]);
-      solv_free(languages);
-      repodata_free(info);
-    }
-  if (attrname)
+  repodata_internalize(info);
+  writer = repowriter_create(repo);
+  repowriter_set_keyfilter(writer, keyfilter_solv, 0);
+  if (repowriter_write(writer, fp) != 0)
     {
-      FILE *fp;
-      test_separate = 1;
-      fp = fopen(attrname, "w");
-      write_info(repo, fp, keyfilter_attr, 0, info, attrname);
-      fclose(fp);
-      kd.haveexternal = 1;
+      fprintf(stderr, "repo write failed: %s\n", pool_errstr(repo->pool));
+      exit(1);
     }
-  repodata_internalize(info);
-  if (repo_write_filtered(repo, stdout, keyfilter_solv, &kd, 0) != 0)
+  if (fflush(fp))
     {
-      fprintf(stderr, "repo_write failed\n");
+      perror("fflush");
       exit(1);
     }
-  repodata_free(info);
+  repowriter_free(writer);
+  repodata_free(info);         /* delete meta info repodata again */
 }
index 7630edd..fda1fd5 100644 (file)
@@ -10,6 +10,6 @@
 
 #include "repo.h"
 
-void tool_write(Repo *repo, const char *basename, const char *attrname);
+void tool_write(Repo *repo, FILE *fp);
 
 #endif
index cdbcf74..ebb39b5 100644 (file)
@@ -34,7 +34,7 @@ main(int argc, char **argv)
       fprintf(stderr, "comps2solv: %s\n", pool_errstr(pool));
       exit(1);
     }
-  tool_write(repo, 0, 0);
+  tool_write(repo, stdout);
   pool_free(pool);
   exit(0);
 }
index 63b6839..ad27541 100644 (file)
@@ -60,13 +60,10 @@ main(int argc, char **argv)
   const char *basefile = 0;
   int is_repo = 0;
 
-  while ((c = getopt(argc, argv, "0b:m:r")) >= 0)
+  while ((c = getopt(argc, argv, "0:m:r")) >= 0)
     {
       switch(c)
        {
-       case 'b':
-         basefile = optarg;
-         break;
        case 'm':
          manifest = optarg;
          break;
@@ -150,7 +147,7 @@ main(int argc, char **argv)
        }
     }
   repo_internalize(repo);
-  tool_write(repo, basefile, 0);
+  tool_write(repo, stdout);
   pool_free(pool);
   for (c = 0; c < ndebs; c++)
     free((char *)debs[c]);
index 7d6348f..906b3ad 100644 (file)
@@ -20,10 +20,9 @@ static void
 usage(int status)
 {
   fprintf(stderr, "\nUsage:\n"
-          "deltainfoxml2solv [-a][-h][-n <attrname>]\n"
+          "deltainfoxml2solv [-h]\n"
          "  reads a 'deltainfo.xml' file from <stdin> and writes a .solv file to <stdout>\n"
          "  -h : print help & exit\n"
-         "  -n <name>: save attributes as <name>.attr\n"
         );
   exit(status);
 }
@@ -32,21 +31,17 @@ int
 main(int argc, char **argv)
 {
   int c, flags = 0;
-  char *attrname = 0;
   
   Pool *pool = pool_create();
   Repo *repo = repo_create(pool, "<stdin>");
 
-  while ((c = getopt(argc, argv, "hn:")) >= 0)
+  while ((c = getopt(argc, argv, "h")) >= 0)
     {   
       switch(c)
        {
        case 'h':
          usage(0);
          break;
-       case 'n':
-         attrname = optarg;
-         break;
        default:
          usage(1);
          break;
@@ -57,7 +52,7 @@ main(int argc, char **argv)
       fprintf(stderr, "deltainfoxml2solv: %s\n", pool_errstr(pool));
       exit(1);
     }
-  tool_write(repo, 0, attrname);
+  tool_write(repo, stdout);
   pool_free(pool);
   exit(0);
 }
index 59ac79a..850b02c 100644 (file)
@@ -22,10 +22,9 @@ static void
 usage(int status)
 {
   fprintf(stderr, "\nUsage:\n"
-          "diskusagexml2solv [-a][-h][-n <attrname>]\n"
+          "diskusagexml2solv [-h]\n"
          "  reads a 'diskusage.xml' file from <stdin> and writes a .solv file to <stdout>\n"
          "  -h : print help & exit\n"
-         "  -n <name>: save attributes as <name>.attr\n"
         );
   exit(status);
 }
@@ -34,21 +33,17 @@ int
 main(int argc, char **argv)
 {
   int c, flags = 0;
-  char *attrname = 0;
   
   Pool *pool = pool_create();
   Repo *repo = repo_create(pool, "<stdin>");
 
-  while ((c = getopt(argc, argv, "hn:")) >= 0)
+  while ((c = getopt(argc, argv, "h")) >= 0)
     {   
       switch(c)
        {
        case 'h':
          usage(0);
          break;
-       case 'n':
-         attrname = optarg;
-         break;
        default:
          usage(1);
          break;
@@ -59,7 +54,7 @@ main(int argc, char **argv)
       fprintf(stderr, "diskusagexml2solv: %s\n", pool_errstr(pool));
       exit(1);
     }
-  tool_write(repo, 0, attrname);
+  tool_write(repo, stdout);
   pool_free(pool);
   exit(0);
 }
index 1aaee16..bdd521e 100644 (file)
@@ -54,7 +54,6 @@ dump_attr(Repo *repo, Repodata *data, Repokey *key, KeyValue *kv)
     case REPOKEY_TYPE_VOID:
       printf("%s: (void)\n", keyname);
       break;
-    case REPOKEY_TYPE_U32:
     case REPOKEY_TYPE_CONSTANT:
       printf("%s: %u\n", keyname, kv->num);
       break;
@@ -225,7 +224,6 @@ dump_attr_json(Repo *repo, Repodata *data, Repokey *key, KeyValue *kv, struct cb
     case REPOKEY_TYPE_VOID:
       printf("null");
       break;
-    case REPOKEY_TYPE_U32:
     case REPOKEY_TYPE_CONSTANT:
       printf("%u", kv->num);
       break;
index 04c6b48..8ab531e 100644 (file)
@@ -33,7 +33,7 @@ main(int argc, char **argv)
       fprintf(stderr, "helix2solv: %s\n", pool_errstr(pool));
       exit(1);
     }
-  tool_write(repo, 0, 0);
+  tool_write(repo, stdout);
   pool_free(pool);
   exit(0);
 }
index bd77fb7..3a6cf94 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Novell Inc.
+ * Copyright (c) 2012, Novell Inc.);
  *
  * This program is licensed under the BSD license, read LICENSE.BSD
  * for further information
@@ -104,7 +104,7 @@ main(int argc, char **argv)
       fclose(fp);
     }
   repo_internalize(repo);
-  tool_write(repo, 0, 0);
+  tool_write(repo, stdout);
   pool_free(pool);
   exit(0);
 }
index ae6e163..8746ac6 100644 (file)
@@ -60,7 +60,6 @@ main(int argc, char **argv)
 {
   Pool *pool;
   Repo *repo;
-  const char *basefile = 0;
   int with_attr = 0;
 #ifdef SUSE
   int add_auto = 0;
@@ -70,7 +69,7 @@ main(int argc, char **argv)
   pool = pool_create();
   repo = repo_create(pool, "<mergesolv>");
   
-  while ((c = getopt(argc, argv, "ahb:X")) >= 0)
+  while ((c = getopt(argc, argv, "ahX")) >= 0)
     {
       switch (c)
       {
@@ -80,9 +79,6 @@ main(int argc, char **argv)
        case 'a':
          with_attr = 1;
          break;
-       case 'b':
-         basefile = optarg;
-         break;
        case 'X':
 #ifdef SUSE
          add_auto = 1;
@@ -115,7 +111,7 @@ main(int argc, char **argv)
   if (add_auto)
     repo_add_autopattern(repo, 0);
 #endif
-  tool_write(repo, basefile, 0);
+  tool_write(repo, stdout);
   pool_free(pool);
   return 0;
 }
index ece4225..d5b3328 100644 (file)
@@ -169,9 +169,9 @@ read_plaindir_repo(Repo *repo, const char *dir)
          close(fds[1]);
        }
       if (recursive)
-       execl("/usr/bin/find", "/usr/bin/find", ".", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0);
+       execl("/usr/bin/find", ".", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0);
       else
-       execl("/usr/bin/find", "/usr/bin/find", ".", "-maxdepth", "1", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0);
+       execl("/usr/bin/find", ".", "-maxdepth", "1", "-name", ".", "-o", "-name", ".*", "-prune", "-o", "-name", "*.delta.rpm", "-o", "-name", "*.patch.rpm", "-o", "-name", "*.rpm", "-a", "-type", "f", "-print0", (char *)0);
       perror("/usr/bin/find");
       _exit(1);
     }
@@ -208,7 +208,6 @@ read_plaindir_repo(Repo *repo, const char *dir)
        repodata_set_location(data, p, 0, 0, bp[0] == '.' && bp[1] == '/' ? bp + 2 : bp);
       solv_free(rpm);
     }
-  solv_free(buf);
   fclose(fp);
   while (waitpid(pid, &wstatus, 0) == -1)
     {
@@ -828,12 +827,7 @@ main(int argc, char **argv)
   if (add_auto)
     repo_add_autopattern(repo, 0);
 #endif
-  tool_write(repo, 0, 0);
-  if (fflush(stdout))
-    {
-      perror("fflush");
-      exit(1);
-    }
+  tool_write(repo, stdout);
   pool_free(pool);
   solv_free(dir);
   exit(res);
index e3159de..fdf7666 100644 (file)
@@ -115,7 +115,7 @@ main(int argc, char **argv)
   if (query)
     doquery(pool, repo, query);
   else
-    tool_write(repo, 0, 0);
+    tool_write(repo, stdout);
   pool_free(pool);
   exit(0);
 }
index 9fa8580..58ef567 100644 (file)
@@ -41,14 +41,11 @@ static void
 usage(int status)
 {
   fprintf(stderr, "\nUsage:\n"
-         "rpmdb2solv [-P] [-C] [-n] [-b <basefile>] [-p <productsdir>] [-r <root>]\n"
+         "rpmdb2solv [-n] [-b <basefile>] [-p <productsdir>] [-r <root>]\n"
          " -n : No packages, do not read rpmdb, useful to only parse products\n"
-         " -b <basefile> : Write .solv to <basefile>.solv instead of stdout\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);
 }
@@ -65,7 +62,6 @@ main(int argc, char **argv)
   int nopacks = 0;
   int add_changelog = 0;
   const char *root = 0;
-  const char *basefile = 0;
   const char *refname = 0;
 #ifdef ENABLE_SUSEREPO
   char *proddir = 0;
@@ -85,7 +81,7 @@ main(int argc, char **argv)
    * parse arguments
    */
   
-  while ((c = getopt(argc, argv, "ACPhnkxXb:r:p:o:")) >= 0)
+  while ((c = getopt(argc, argv, "ACPhnkxXr:p:o:")) >= 0)
     switch (c)
       {
       case 'h':
@@ -94,9 +90,6 @@ main(int argc, char **argv)
       case 'r':
         root = optarg;
         break;
-      case 'b':
-        basefile = optarg;
-        break;
       case 'n':
        nopacks = 1;
        break;
@@ -231,7 +224,7 @@ main(int argc, char **argv)
     repo_add_autopattern(repo, ADD_NO_AUTOPRODUCTS);
 #endif
 
-  tool_write(repo, basefile, 0);
+  tool_write(repo, stdout);
   pool_free(pool);
   exit(0);
 }
index 437c83d..ad75025 100644 (file)
@@ -27,11 +27,9 @@ static void
 usage(int status)
 {
   fprintf(stderr, "\nUsage:\n"
-          "rpmmd2solv [-a][-h][-n <attrname>][-l <locale>]\n"
+          "rpmmd2solv [-h]\n"
          "  reads 'primary' from a 'rpmmd' repository from <stdin> and writes a .solv file to <stdout>\n"
          "  -h : print help & exit\n"
-         "  -n <name>: save attributes as <name>.attr\n"
-         "  -l <locale>: parse localization data for <locale>\n"
         );
    exit(status);
 }
@@ -39,11 +37,7 @@ usage(int status)
 int
 main(int argc, char **argv)
 {
-  int c, flags = 0;
-  const char *attrname = 0;
-  const char *basefile = 0;
-  const char *dir = 0;
-  const char *locale = 0;
+  int c;
 #ifdef SUSE
   int add_auto = 0;
 #endif
@@ -51,25 +45,13 @@ main(int argc, char **argv)
   Pool *pool = pool_create();
   Repo *repo = repo_create(pool, "<stdin>");
 
-  while ((c = getopt (argc, argv, "hn:b:d:l:X")) >= 0)
+  while ((c = getopt (argc, argv, "hX")) >= 0)
     {
-      switch(c)
+      switch (c)
        {
         case 'h':
           usage(0);
           break;
-        case 'n':
-          attrname = optarg;
-          break;
-        case 'b':
-          basefile = optarg;
-          break;
-        case 'd':
-          dir = optarg;
-          break;
-       case 'l':
-         locale = optarg;
-         break;
        case 'X':
 #ifdef SUSE
          add_auto = 1;
@@ -80,81 +62,16 @@ main(int argc, char **argv)
           break;
        }
     }
-  if (dir)
-    {
-      FILE *fp;
-      int l;
-      char *fnp;
-      l = strlen(dir) + 128;
-      fnp = solv_malloc(l+1);
-      snprintf(fnp, l, "%s/primary.xml.gz", dir);
-      if (!(fp = solv_xfopen(fnp, 0)))
-       {
-         perror(fnp);
-         exit(1);
-       }
-      if (repo_add_rpmmd(repo, fp, 0, flags))
-       {
-         fprintf(stderr, "rpmmd2solv: %s: %s\n", fnp, pool_errstr(pool));
-         exit(1);
-       }
-      fclose(fp);
-      snprintf(fnp, l, "%s/diskusagedata.xml.gz", dir);
-      if ((fp = solv_xfopen(fnp, 0)))
-       {
-         if (repo_add_rpmmd(repo, fp, 0, flags))
-           {
-             fprintf(stderr, "rpmmd2solv: %s: %s\n", fnp, pool_errstr(pool));
-             exit(1);
-           }
-         fclose(fp);
-       }
-      if (locale)
-       {
-         if (snprintf(fnp, l, "%s/translation-%s.xml.gz", dir, locale) >= l)
-           {
-             fprintf(stderr, "-l parameter too long\n");
-             exit(1);
-           }
-         while (!(fp = solv_xfopen(fnp, 0)))
-           {
-             fprintf(stderr, "not opened %s\n", fnp);
-             if (strlen(locale) > 2)
-               {
-                 if (snprintf(fnp, l, "%s/translation-%.2s.xml.gz", dir, locale) >= l)
-                   {
-                     fprintf(stderr, "-l parameter too long\n");
-                     exit(1);
-                   }
-                 if ((fp = solv_xfopen(fnp, 0)))
-                   break;
-               }
-             perror(fnp);
-             exit(1);
-           }
-         fprintf(stderr, "opened %s\n", fnp);
-         if (repo_add_rpmmd(repo, fp, 0, flags))
-           {
-             fprintf(stderr, "rpmmd2solv: %s: %s\n", fnp, pool_errstr(pool));
-             exit(1);
-           }
-         fclose(fp);
-       }
-      solv_free(fnp);
-    }
-  else
+  if (repo_add_rpmmd(repo, stdin, 0, 0))
     {
-      if (repo_add_rpmmd(repo, stdin, 0, flags))
-       {
-         fprintf(stderr, "rpmmd2solv: %s\n", pool_errstr(pool));
-         exit(1);
-       }
+      fprintf(stderr, "rpmmd2solv: %s\n", pool_errstr(pool));
+      exit(1);
     }
 #ifdef SUSE
   if (add_auto)
     repo_add_autopattern(repo, 0);
 #endif
-  tool_write(repo, basefile, attrname);
+  tool_write(repo, stdout);
   pool_free(pool);
   exit(0);
 }
index 7852b08..c012b46 100644 (file)
@@ -64,7 +64,6 @@ main(int argc, char **argv)
   Repo *repo;
   FILE *fp;
   char buf[4096], *p;
-  const char *basefile = 0;
 #ifdef ENABLE_PUBKEY
   int pubkeys = 0;
 #endif
@@ -73,13 +72,10 @@ main(int argc, char **argv)
 #endif
   int filtered_filelist = 0;
 
-  while ((c = getopt(argc, argv, "0XkKb:m:F")) >= 0)
+  while ((c = getopt(argc, argv, "0XkKm:F")) >= 0)
     {
       switch(c)
        {
-       case 'b':
-         basefile = optarg;
-         break;
        case 'm':
          manifest = optarg;
          break;
@@ -184,7 +180,7 @@ main(int argc, char **argv)
   if (add_auto)
     repo_add_autopattern(repo, 0);
 #endif
-  tool_write(repo, basefile, 0);
+  tool_write(repo, stdout);
   pool_free(pool);
   for (c = 0; c < nrpms; c++)
     free((char *)rpms[c]);
index ced614b..f7544dc 100644 (file)
@@ -29,13 +29,11 @@ static void
 usage(int status)
 {
   fprintf(stderr, "\nUsage:\n"
-          "susetags2solv [-b <base>][-c <content>][-d <descrdir>][-h][-n <name>]\n"
+          "susetags2solv [-c <content>][-d <descrdir>][-h][-n <name>]\n"
          "  reads a 'susetags' repository from <stdin> and writes a .solv file to <stdout>\n"
-         "  -b <base>: save as multiple files starting with <base>\n"
          "  -c <contentfile> : parse given contentfile (for product information)\n"
           "  -d <descrdir> : do not read from stdin, but use data in descrdir\n"
          "  -h : print help & exit\n"
-         "  -n <name>: save attributes as <name>.attr\n"
         );
    exit(status);
 }
@@ -61,9 +59,7 @@ int
 main(int argc, char **argv)
 {
   const char *contentfile = 0;
-  const char *attrname = 0;
   const char *descrdir = 0;
-  const char *basefile = 0;
   const char *query = 0;
   const char *mergefile = 0;
   Id defvendor = 0;
@@ -75,25 +71,19 @@ main(int argc, char **argv)
   Pool *pool;
   Repo *repo;
 
-  while ((c = getopt(argc, argv, "hn:c:d:b:q:M:X")) >= 0)
+  while ((c = getopt(argc, argv, "hc:d:q:M:X")) >= 0)
     {
       switch (c)
        {
        case 'h':
          usage(0);
          break;
-       case 'n':
-         attrname = optarg;
-         break;
        case 'c':
          contentfile = optarg;
          break;
        case 'd':
          descrdir = optarg;
          break;
-       case 'b':
-         basefile = optarg;
-         break;
        case 'q':
          query = optarg;
          break;
@@ -132,20 +122,6 @@ main(int argc, char **argv)
       fclose(fp);
     }
 
-  if (attrname)
-    {
-      /* ensure '.attr' suffix */
-      const char *dot = strrchr(attrname, '.');
-      if (!dot || strcmp(dot, ".attr"))
-      {
-       int len = strlen (attrname);
-       char *newname = (char *)malloc(len + 6); /* alloc for <attrname>+'.attr'+'\0' */
-       strcpy (newname, attrname);
-       strcpy (newname+len, ".attr");
-       attrname = newname;
-      }
-    }
-
   /*
    * descrdir path given, open files and read from there
    */
@@ -311,7 +287,7 @@ main(int argc, char **argv)
   if (query)
     doquery(pool, repo, query);
   else
-    tool_write(repo, basefile, attrname);
+    tool_write(repo, stdout);
   pool_free(pool);
   exit(0);
 }
index 6a97b0d..9bc038e 100644 (file)
@@ -20,10 +20,9 @@ static void
 usage(int status)
 {
   fprintf(stderr, "\nUsage:\n"
-          "updateinfoxml2solv [-h][-n <attrname>]\n"
+          "updateinfoxml2solv [-h]\n"
          "  reads a 'updateinfo.xml' file from <stdin> and writes a .solv file to <stdout>\n"
          "  -h : print help & exit\n"
-         "  -n <name>: save attributes as <name>.attr\n"
         );
   exit(status);
 }
@@ -32,21 +31,17 @@ int
 main(int argc, char **argv)
 {
   int c, flags = 0;
-  char *attrname = 0;
   
   Pool *pool = pool_create();
   Repo *repo = repo_create(pool, "<stdin>");
 
-  while ((c = getopt(argc, argv, "hn:")) >= 0)
+  while ((c = getopt(argc, argv, "h")) >= 0)
     {
       switch(c)
        {
        case 'h':
          usage(0);
          break;
-       case 'n':
-         attrname = optarg;
-         break;
        default:
          usage(1);
          break;
@@ -57,7 +52,7 @@ main(int argc, char **argv)
       fprintf(stderr, "updateinfoxml2solv: %s\n", pool_errstr(pool));
       exit(1);
     }
-  tool_write(repo, 0, attrname);
+  tool_write(repo, stdout);
   pool_free(pool);
   exit(0);
 }