Imported Upstream version 0.6.35 89/194389/1 upstream/0.6.35
authorDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 4 Dec 2018 05:04:28 +0000 (14:04 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Tue, 4 Dec 2018 05:04:32 +0000 (14:04 +0900)
Change-Id: Ib7359aa10c08c1469105fbd6a82ea922f46f8b51
Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
56 files changed:
CMakeLists.txt
NEWS
VERSION.cmake
bindings/solv.i
doc/CMakeLists.txt
doc/Makefile.gen
doc/gen/libsolv-bindings.3
doc/gen/libsolv-pool.3
doc/gen/repo2solv.1 [new file with mode: 0644]
doc/gen/solv.1 [new file with mode: 0644]
doc/libsolv-bindings.txt
doc/libsolv-pool.txt
doc/repo2solv.txt [new file with mode: 0644]
doc/solv.txt [new file with mode: 0644]
examples/repo2solv.sh [moved from tools/repo2solv.sh with 98% similarity]
examples/solv/checksig.c
examples/solv/solv.c
ext/CMakeLists.txt
ext/repo_deb.c
ext/repo_rpmdb.c
ext/repo_rpmdb.h
ext/repo_rpmdb_bdb.h
ext/repo_rpmdb_librpm.h
ext/solv_xfopen.c
ext/solv_zchunk.c [new file with mode: 0644]
ext/solv_zchunk.h [new file with mode: 0644]
package/libsolv.changes
package/libsolv.spec.in
src/bitmap.c
src/bitmap.h
src/cleandeps.c
src/libsolv.ver
src/policy.c
src/pool.c
src/pool.h
src/poolarch.c
src/poolarch.h
src/poolid.c
src/poolid.h
src/problems.c
src/queue.c
src/queue.h
src/repo.h
src/repo_solv.c
src/repo_write.c
src/repodata.c
src/repodata.h
src/rules.c
src/selection.c
src/solvversion.h.in
src/strpool.c
src/strpool.h
tools/CMakeLists.txt
tools/common_write.c
tools/patchcheck.c [deleted file]
tools/repo2solv.c [new file with mode: 0644]

index 2557f0a..8c6a1be 100644 (file)
@@ -33,17 +33,11 @@ OPTION (MULTI_SEMANTICS "Build with support for multiple distribution types?" OF
 
 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_LIBXML2  "Build with libxml2 instead of libexpat?" OFF)
 
-#IF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERISION} GREATER 2.4)
-#ENDIF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERISION} GREATER 2.4)
-
-IF (COMMAND cmake_policy)
-  # escape preprocessor, see -DVERSION below
-  CMAKE_POLICY (SET CMP0005 OLD)
-ENDIF (COMMAND cmake_policy)
-
 # Library
 IF (DEFINED LIB)
   SET (LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${LIB}")
@@ -162,6 +156,10 @@ IF (ENABLE_ARCHREPO OR ENABLE_DEBIAN)
 SET (ENABLE_LZMA_COMPRESSION ON)
 ENDIF (ENABLE_ARCHREPO OR ENABLE_DEBIAN)
 
+IF (ENABLE_ZCHUNK_COMPRESSION)
+SET (ENABLE_ZSTD_COMPRESSION ON)
+ENDIF (ENABLE_ZCHUNK_COMPRESSION)
+
 IF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
 IF (WITH_LIBXML2 )
 FIND_PACKAGE (LibXml2 REQUIRED)
@@ -184,6 +182,10 @@ IF (ENABLE_BZIP2_COMPRESSION)
 FIND_PACKAGE (BZip2 REQUIRED)
 ENDIF (ENABLE_BZIP2_COMPRESSION)
 
+IF (ENABLE_ZSTD_COMPRESSION)
+FIND_LIBRARY (ZSTD_LIBRARY NAMES zstd)
+ENDIF (ENABLE_ZSTD_COMPRESSION)
+
 IF (RPM5)
 MESSAGE (STATUS "Enabling RPM 5 support")
 ADD_DEFINITIONS (-DRPM5)
@@ -292,7 +294,7 @@ 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_PGPVRFY ENABLE_APPDATA)
+  ENABLE_ZSTD_COMPRESSION ENABLE_ZCHUNK_COMPRESSION ENABLE_PGPVRFY ENABLE_APPDATA)
   IF(${VAR})
     ADD_DEFINITIONS (-D${VAR}=1)
     SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR})
@@ -305,7 +307,6 @@ SET (PACKAGE "libsolv")
 SET (VERSION "${LIBSOLV_MAJOR}.${LIBSOLV_MINOR}.${LIBSOLV_PATCH}")
 
 ADD_DEFINITIONS (-D_FILE_OFFSET_BITS=64)
-ADD_DEFINITIONS (-DVERSION=\\\"${VERSION}\\\")
 CONFIGURE_FILE (src/solvversion.h.in src/solvversion.h)
 
 SET (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Package dependency solver library")
@@ -395,6 +396,9 @@ ENDIF (ENABLE_LZMA_COMPRESSION)
 IF (ENABLE_BZIP2_COMPRESSION)
 SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${BZIP2_LIBRARIES})
 ENDIF (ENABLE_BZIP2_COMPRESSION)
+IF (ENABLE_ZSTD_COMPRESSION)
+SET (SYSTEM_LIBRARIES ${SYSTEM_LIBRARIES} ${ZSTD_LIBRARY})
+ENDIF (ENABLE_ZSTD_COMPRESSION)
 IF (ENABLE_RPMDB)
 SET (SYSTEM_LIBRARIES ${RPMDB_LIBRARY} ${SYSTEM_LIBRARIES})
 ENDIF (ENABLE_RPMDB)
diff --git a/NEWS b/NEWS
index 2ed1bf4..abb211f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,17 @@
 This file contains the major changes between
 libsolv versions:
 
+Version 0.6.35
+- new configuration options:
+  * ENABLE_ZSTD_COMPRESSION: support zstd compression
+  * ENABLE_ZCHUNK_COMPRESSION: support zchunk compression
+- new features:
+  * new repodata_set_kv() function
+  * new pool_solvable2id() inline function
+  * bindings: new str2dir, dir2str, add_dirstr repodata methods
+- other changes
+  * new repo2solv tool replacing the old shell script
+
 Version 0.6.34
 - new features:
   * also look at suggests for package ordering
index 1d14e17..991c920 100644 (file)
@@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "0")
 
 SET(LIBSOLV_MAJOR "0")
 SET(LIBSOLV_MINOR "6")
-SET(LIBSOLV_PATCH "34")
+SET(LIBSOLV_PATCH "35")
 
index acd01ac..8fb469f 100644 (file)
@@ -1924,7 +1924,7 @@ typedef struct {
       return 0;
     if (id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
       return 1;
-    if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id]))
+    if (pool->id2arch && pool_arch2score(pool, id) == 0)
       return 0;
     return 1;
   }
@@ -3916,6 +3916,18 @@ rb_eval_string(
   bool write(FILE *fp) {
     return repodata_write(repo_id2repodata($self->repo, $self->id), fp) == 0;
   }
+  Id str2dir(const char *dir, bool create=1) {
+    Repodata *data = repo_id2repodata($self->repo, $self->id);
+    return repodata_str2dir(data, dir, create);
+  }
+  const char *dir2str(Id did, const char *suf = 0) {
+    Repodata *data = repo_id2repodata($self->repo, $self->id);
+    return repodata_dir2str(data, did, suf);
+  }
+  void add_dirstr(Id solvid, Id keyname, Id dir, const char *str) {
+    Repodata *data = repo_id2repodata($self->repo, $self->id);
+    repodata_add_dirstr(data, solvid, keyname, dir, str);
+  }
   bool add_solv(FILE *fp, int flags = 0) {
     Repodata *data = repo_id2repodata($self->repo, $self->id);
     int r, oldstate = data->state;
index b18596d..66011b4 100644 (file)
@@ -4,7 +4,7 @@ SET (libsolv_MANPAGES3
     libsolv-pool.3)
 
 SET (libsolv_MANPAGES1
-    mergesolv.1 dumpsolv.1 installcheck.1 testsolv.1)
+    mergesolv.1 dumpsolv.1 installcheck.1 testsolv.1 repo2solv.1 solv.1)
 
 IF (ENABLE_RPMDB)
 SET (libsolv_MANPAGES1 ${libsolv_MANPAGES1} rpmdb2solv.1 rpms2solv.1)
index 2e8c4a1..e9f1b69 100644 (file)
@@ -8,7 +8,7 @@ man3:   libsolv.3 libsolv-bindings.3 libsolv-constantids.3 libsolv-history.3 libso
 man1:  mergesolv.1 dumpsolv.1 installcheck.1 testsolv.1 rpmdb2solv.1 rpms2solv.1 \
        rpmmd2solv.1 repomdxml2solv.1 updateinfoxml2solv.1 deltainfoxml2solv.1 \
        helix2solv.1 susetags2solv.1 comps2solv.1 deb2solv.1 mdk2solv.1 \
-       archpkgs2solv.1 archrepo2solv.1 appdata2solv.1
+       archpkgs2solv.1 archrepo2solv.1 appdata2solv.1 repo2solv.1 solv.1
 
 html: libsolv.html libsolv-bindings.html libsolv-constantids.html libsolv-history.html libsolv-pool.html
 
index a6534aa..7ca0bb5 100644 (file)
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: Libsolv-Bindings
 .\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 02/28/2018
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 06/15/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "LIBSOLV\-BINDINGS" "3" "02/28/2018" "libsolv" "LIBSOLV"
+.TH "LIBSOLV\-BINDINGS" "3" "06/15/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -2763,7 +2763,7 @@ Do a sub\-search in the array stored in keyname\&.
 .\}
 .nf
 \fBvoid skip_solvable()\fR;
-\fI$di\fR\fB\->kip_solvable()\fR;
+\fI$di\fR\fB\->skip_solvable()\fR;
 \fIdi\fR\fB\&.skip_solvable()\fR
 \fIdi\fR\fB\&.skip_solvable()\fR
 .fi
@@ -5622,6 +5622,49 @@ Write the contents of the repodata area as solv file\&.
 .RS 4
 .\}
 .nf
+\fBId str2dir(const char *\fR\fIdir\fR\fB, bool\fR \fIcreate\fR \fB= 1)\fR
+my \fI$did\fR \fB=\fR \fIdata\fR\fB\->str2dir(\fR\fI$dir\fR\fB)\fR;
+\fIdid\fR \fB=\fR \fIdata\fR\fB\&.str2dir(\fR\fIdir\fR\fB)\fR
+\fIdid\fR \fB=\fR \fIdata\fR\fB\&.str2dir(\fR\fIdir\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBconst char *dir2str(Id\fR \fIdid\fR\fB, const char *\fR\fIsuffix\fR \fB= 0)\fR
+\fI$dir\fR \fB=\fR \fIpool\fR\fB\->dir2str(\fR\fI$did\fR\fB)\fR;
+\fIdir\fR \fB=\fR \fIpool\fR\fB\&.dir2str(\fR\fIdid\fR\fB)\fR
+\fIdir\fR \fB=\fR \fIpool\fR\fB\&.dir2str(\fR\fIdid\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert a string (directory) into an Id and back\&. If the string is currently not in the pool and \fIcreate\fR is false, zero is returned\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid add_dirstr(Id\fR \fIsolvid\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fIdir\fR\fB, const char *\fR\fIstr\fR\fB)\fR
+\fI$data\fR\fB\->add_dirstr(\fR\fI$solvid\fR\fB,\fR \fI$keyname\fR\fB,\fR \fI$dir\fR\fB,\fR \fI$string\fR\fB)\fR
+\fIdata\fR\fB\&.add_dirstr(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIdir\fR\fB,\fR \fIstring\fR\fB)\fR
+\fIdata\fR\fB\&.add_dirstr(\fR\fIsolvid\fR\fB,\fR \fIkeyname\fR\fB,\fR \fIdir\fR\fB,\fR \fIstring\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Add a file path consisting of a dirname Id and a basename string\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
 \fBbool add_solv(FILE *\fR\fIfp\fR\fB, int\fR \fIflags\fR \fB= 0)\fR;
 \fI$data\fR\fB\->add_solv(\fR\fI$fp\fR\fB)\fR;
 \fIdata\fR\fB\&.add_solv(\fR\fIfp\fR\fB)\fR
index ffb8e56..c64eeb1 100644 (file)
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: Libsolv-Pool
 .\"    Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 01/18/2018
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 07/16/2018
 .\"    Manual: LIBSOLV
 .\"    Source: libsolv
 .\"  Language: English
 .\"
-.TH "LIBSOLV\-POOL" "3" "01/18/2018" "libsolv" "LIBSOLV"
+.TH "LIBSOLV\-POOL" "3" "07/16/2018" "libsolv" "LIBSOLV"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -764,6 +764,18 @@ Convert a solvable Id into a pointer to the solvable data\&. Note that the point
 .RS 4
 .\}
 .nf
+\fBId pool_solvable2id(const Pool *\fR\fIpool\fR\fB, Solvable *\fR\fIs\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Convert a pointer to the solvable data into a solvable Id\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
 \fBconst char *pool_solvid2str(Pool *\fR\fIpool\fR\fB, Id\fR \fIp\fR\fB)\fR;
 .fi
 .if n \{\
diff --git a/doc/gen/repo2solv.1 b/doc/gen/repo2solv.1
new file mode 100644 (file)
index 0000000..5f21465
--- /dev/null
@@ -0,0 +1,79 @@
+'\" t
+.\"     Title: repo2solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 07/16/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "REPO2SOLV" "1" "07/16/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+repo2solv \- convert repository metadata into a solv file
+.SH "SYNOPSIS"
+.sp
+\fBrepo2solv\fR [\fIOPTIONS\fR] \fIDIR\fR
+.SH "DESCRIPTION"
+.sp
+The repo2solv tool converts repository metadata in the directory \fIDIR\fR into a solv file written to standard output\&.
+.sp
+Note that repo2solv does not verify signatures or checksum, it is expected that this is done by the tool that downloads the metadata\&.
+.sp
+If no metadata is detected, repo2solv assumes the "plaindir" format and generates the solv file from all rpm files it finds\&.
+.PP
+\fB\-o\fR \fIOUTFILE\fR
+.RS 4
+Write the solv file to
+\fIOUTFILE\fR
+instead of stdout\&.
+.RE
+.PP
+\fB\-R\fR
+.RS 4
+Also recurse into subdirectories in "plaindir" mode\&.
+.RE
+.PP
+\fB\-F\fR
+.RS 4
+Put the complete filelist in the output\&. The default is to just include the "importent" parts of the file list, except for "plaindir" mode, which always includes all files\&.
+.RE
+.PP
+\fB\-C\fR
+.RS 4
+Add changelog entires to the output\&.
+.RE
+.PP
+\fB\-A\fR
+.RS 4
+Add appdata pseudo packages to the output\&. This is an experimental feature\&.
+.RE
+.PP
+\fB\-X\fR
+.RS 4
+Autoexpand SUSE pattern and product provides into packages\&.
+.RE
+.SH "SEE ALSO"
+.sp
+dumpsolv(1)
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
diff --git a/doc/gen/solv.1 b/doc/gen/solv.1
new file mode 100644 (file)
index 0000000..b61538d
--- /dev/null
@@ -0,0 +1,102 @@
+'\" t
+.\"     Title: solv
+.\"    Author: [see the "Author" section]
+.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
+.\"      Date: 07/19/2018
+.\"    Manual: LIBSOLV
+.\"    Source: libsolv
+.\"  Language: English
+.\"
+.TH "SOLV" "1" "07/19/2018" "libsolv" "LIBSOLV"
+.\" -----------------------------------------------------------------
+.\" * Define some portability stuff
+.\" -----------------------------------------------------------------
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.\" http://bugs.debian.org/507673
+.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
+.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\" -----------------------------------------------------------------
+.\" * set default formatting
+.\" -----------------------------------------------------------------
+.\" disable hyphenation
+.nh
+.\" disable justification (adjust text to left margin only)
+.ad l
+.\" -----------------------------------------------------------------
+.\" * MAIN CONTENT STARTS HERE *
+.\" -----------------------------------------------------------------
+.SH "NAME"
+solv \- example package manager based on libsolv
+.SH "SYNOPSIS"
+.sp
+\fBsolv\fR install [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR erase [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR list [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR info [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR search [OPTIONS] STRING\&...
+.sp
+\fBsolv\fR verify [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR update [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR dist\-upgrade [OPTIONS] PKG\&...
+.sp
+\fBsolv\fR repolist [OPTIONS]
+.SH "DESCRIPTION"
+.sp
+The solv tool demos some features of the libsolv library\&. It is not meant to replace a real package manager, for example it does not cache downloaded packages\&.
+.PP
+\fB\-\-root\fR \fIROOTDIR\fR
+.RS 4
+Install packages using
+\fIROOTDIR\fR
+as root of the filesystem\&. This also means that the package database of
+\fIROOTDIR\fR
+will be used\&.
+.RE
+.PP
+\fB\-\-clean\fR
+.RS 4
+Also get rid of no longer needed packages when erasing, like libraries that have been used by the erased packages\&.
+.RE
+.PP
+\fB\-\-best\fR
+.RS 4
+Force usage of the best package (normally the one with the highest version) for install and update operations\&.
+.RE
+.PP
+\fB\-\-testcase\fR
+.RS 4
+Write a testcase after dependency solving\&.
+.RE
+.sp
+The following options can be used to filter the packages\&. If the same option is used multiple times, the result is ORed together\&.
+.PP
+\fB\-i\fR
+.RS 4
+Limit the packages to installed ones\&.
+.RE
+.PP
+\fB\-r\fR \fIREPO\fR
+.RS 4
+Limit the packages to the specified repository\&.
+.RE
+.PP
+\fB\-\-arch\fR \fIARCHITECTURE\fR
+.RS 4
+Limit the packages to the specified package architecture\&.
+.RE
+.PP
+\fB\-\-type\fR \fITYPE\fR
+.RS 4
+Limit the packages to the specified package type\&.
+.RE
+.SH "AUTHOR"
+.sp
+Michael Schroeder <mls@suse\&.de>
index 1f6422f..5db1116 100644 (file)
@@ -1543,7 +1543,7 @@ Allow the matching of checksum entries.
 Do a sub-search in the array stored in keyname.
 
        void skip_solvable();
-       $di->kip_solvable();
+       $di->skip_solvable();
        di.skip_solvable()
        di.skip_solvable()
 
@@ -3457,6 +3457,26 @@ after it has been internalized.
 
 Write the contents of the repodata area as solv file.
 
+       Id str2dir(const char *dir, bool create = 1)
+       my $did = data->str2dir($dir);
+       did = data.str2dir(dir)
+       did = data.str2dir(dir)
+
+       const char *dir2str(Id did, const char *suffix = 0)
+       $dir = pool->dir2str($did);
+       dir = pool.dir2str(did)
+       dir = pool.dir2str(did)
+
+Convert a string (directory) into an Id and back. If the string is currently not in the
+pool and _create_ is false, zero is returned.
+
+       void add_dirstr(Id solvid, Id keyname, Id dir, const char *str)
+       $data->add_dirstr($solvid, $keyname, $dir, $string)
+       data.add_dirstr(solvid, keyname, dir, string)
+       data.add_dirstr(solvid, keyname, dir, string)
+
+Add a file path consisting of a dirname Id and a basename string.
+
        bool add_solv(FILE *fp, int flags = 0);
        $data->add_solv($fp);
        data.add_solv(fp)
index 6014720..0b9bc41 100644 (file)
@@ -499,6 +499,10 @@ Convert a solvable Id into a pointer to the solvable data. Note that the
 pointer may become invalid if new solvables are created or old solvables
 deleted, because the array storing all solvables may get reallocated.
 
+       Id pool_solvable2id(const Pool *pool, Solvable *s);
+
+Convert a pointer to the solvable data into a solvable Id.
+
        const char *pool_solvid2str(Pool *pool, Id p);
 
 Return a string representing the solvable with the Id _p_. The string will
diff --git a/doc/repo2solv.txt b/doc/repo2solv.txt
new file mode 100644 (file)
index 0000000..3b2145f
--- /dev/null
@@ -0,0 +1,60 @@
+repo2solv(1)
+============
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+repo2solv - convert repository metadata into a solv file
+
+Synopsis
+--------
+*repo2solv* ['OPTIONS'] 'DIR'
+
+Description
+-----------
+The repo2solv tool converts repository metadata in the directory
+'DIR' into a solv file written to standard output.
+
+Note that repo2solv does not verify signatures or checksum, it
+is expected that this is done by the tool that downloads the
+metadata.
+
+If no metadata is detected, repo2solv assumes the "plaindir"
+format and generates the solv file from all rpm files it
+finds.
+
+*-o* 'OUTFILE'::
+Write the solv file to 'OUTFILE' instead of stdout.
+
+*-R*::
+Also recurse into subdirectories in "plaindir" mode.
+
+*-F*::
+Put the complete filelist in the output. The default is
+to just include the "importent" parts of the file list,
+except for "plaindir" mode, which always includes all
+files.
+
+*-C*::
+Add changelog entires to the output.
+
+*-A*::
+Add appdata pseudo packages to the output. This is an
+experimental feature.
+
+*-X*::
+Autoexpand SUSE pattern and product provides into packages.
+
+See Also
+--------
+dumpsolv(1)
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
diff --git a/doc/solv.txt b/doc/solv.txt
new file mode 100644 (file)
index 0000000..936ae78
--- /dev/null
@@ -0,0 +1,73 @@
+solv(1)
+=======
+:man manual: LIBSOLV
+:man source: libsolv
+
+
+Name
+----
+solv - example package manager based on libsolv
+
+Synopsis
+--------
+*solv* install [OPTIONS] PKG...
+
+*solv* erase [OPTIONS] PKG...
+
+*solv* list [OPTIONS] PKG...
+
+*solv* info [OPTIONS] PKG...
+
+*solv* search [OPTIONS] STRING...
+
+*solv* verify [OPTIONS] PKG...
+
+*solv* update [OPTIONS] PKG...
+
+*solv* dist-upgrade [OPTIONS] PKG...
+
+*solv* repolist [OPTIONS]
+
+Description
+-----------
+The solv tool demos some features of the libsolv library. It is not
+meant to replace a real package manager, for example it does not cache
+downloaded packages.
+
+*--root* 'ROOTDIR'::
+Install packages using 'ROOTDIR' as root of the filesystem. This also
+means that the package database of 'ROOTDIR' will be used.
+
+*--clean*::
+Also get rid of no longer needed packages when erasing, like libraries
+that have been used by the erased packages.
+
+*--best*::
+Force usage of the best package (normally the one with the highest
+version) for install and update operations.
+
+*--testcase*::
+Write a testcase after dependency solving.
+
+The following options can be used to filter the packages. If the
+same option is used multiple times, the result is ORed together.
+
+*-i*::
+Limit the packages to installed ones.
+
+*-r* 'REPO'::
+Limit the packages to the specified repository.
+
+*--arch* 'ARCHITECTURE'::
+Limit the packages to the specified package architecture.
+
+*--type* 'TYPE'::
+Limit the packages to the specified package type.
+
+Author
+------
+Michael Schroeder <mls@suse.de>
+
+////
+vim: syntax=asciidoc
+////
similarity index 98%
rename from tools/repo2solv.sh
rename to examples/repo2solv.sh
index 49b623a..450b7fa 100755 (executable)
@@ -1,6 +1,9 @@
 #! /bin/sh
 # repo2solv
 #
+# this is a shell implementation of repo2solv that makes use of
+# the different parser utilities
+#
 # give it a directory of a local mirror of a repo and this
 # tries to detect the repo type and generate one SOLV file on stdout
 
index ff60c66..44603d3 100644 (file)
@@ -27,6 +27,12 @@ cleanupgpg(char *gpgdir)
   unlink(cmd);
   snprintf(cmd, sizeof(cmd), "%s/keys", gpgdir);
   unlink(cmd);
+  snprintf(cmd, sizeof(cmd), "%s/pubring.kbx", gpgdir);
+  unlink(cmd);
+  snprintf(cmd, sizeof(cmd), "%s/pubring.kbx~", gpgdir);
+  unlink(cmd);
+  snprintf(cmd, sizeof(cmd), "%s/private-keys-v1.d", gpgdir);
+  rmdir(cmd);
   rmdir(gpgdir);
 }
 
@@ -35,7 +41,7 @@ checksig(Pool *sigpool, FILE *fp, FILE *sigfp)
 {
   char *gpgdir;
   char *keysfile;
-  const char *pubkey;
+  const char *pubkey, *pubring;
   char cmd[256];
   FILE *kfp;
   Solvable *s;
@@ -83,7 +89,9 @@ checksig(Pool *sigpool, FILE *fp, FILE *sigfp)
   lseek(fileno(fp), 0, SEEK_SET);
   possigfp = lseek(fileno(sigfp), 0, SEEK_CUR);
   lseek(fileno(sigfp), 0, SEEK_SET);
-  snprintf(cmd, sizeof(cmd), "gpgv -q --homedir %s --keyring %s/pubring.gpg /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", gpgdir, gpgdir, fileno(sigfp), fileno(fp));
+  snprintf(cmd, sizeof(cmd), "%s/pubring.kbx", gpgdir);
+  pubring = access(cmd, R_OK) == 0 ? "pubring.kbx" : "pubring.gpg";
+  snprintf(cmd, sizeof(cmd), "gpgv -q --homedir %s --keyring %s/%s /dev/fd/%d /dev/fd/%d >/dev/null 2>&1", gpgdir, gpgdir, pubring, fileno(sigfp), fileno(fp));
   fcntl(fileno(fp), F_SETFD, 0);       /* clear CLOEXEC */
   fcntl(fileno(sigfp), F_SETFD, 0);    /* clear CLOEXEC */
   r = system(cmd);
index 627c248..42ab751 100644 (file)
@@ -459,6 +459,10 @@ main(int argc, char **argv)
       dataiterator_free(&di);
       if (repofilter.count)
        selection_filter(pool, &sel, &repofilter);
+      if (archfilter.count)
+       selection_filter(pool, &sel, &archfilter);
+      if (kindfilter.count)
+       selection_filter(pool, &sel, &kindfilter);
        
       queue_init(&q);
       selection_solvables(pool, &sel, &q);
index b8917a2..edc2b9f 100644 (file)
@@ -126,6 +126,11 @@ IF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_
        solv_xmlparser.c)
 ENDIF (ENABLE_RPMMD OR ENABLE_SUSEREPO OR ENABLE_APPDATA OR ENABLE_COMPS OR ENABLE_HELIXREPO OR ENABLE_MDKREPO)
 
+IF (ENABLE_ZCHUNK_COMPRESSION)
+    SET (libsolvext_SRCS ${libsolvext_SRCS}
+       solv_zchunk.c)
+ENDIF (ENABLE_ZCHUNK_COMPRESSION)
+
 SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
 IF (HAVE_LINKER_VERSION_SCRIPT)
 SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/ext/libsolvext.ver")
index 277e65a..6af7f10 100644 (file)
@@ -599,8 +599,11 @@ repo_add_deb(Repo *repo, const char *deb, int flags)
       fclose(fp);
       return 0;
     }
+  /* dpkg has no actual maximum size for the control.tar member, so this
+   * just keeps from allocating arbitrarily large amounts of memory.
+   */
   clen = atoi((char *)buf + 8 + 60 + vlen + 48);
-  if (clen <= 0 || clen >= 0x100000)
+  if (clen <= 0 || clen >= 0x1000000)
     {
       pool_error(pool, -1, "%s: control.tar has illegal size", deb);
       fclose(fp);
index cd14a9b..75bb678 100644 (file)
@@ -457,7 +457,13 @@ headbinary(RpmHead *h, int tag, unsigned int *sizep)
 static int
 headissourceheuristic(RpmHead *h)
 {
-  return headerIsSource(h);
+  struct rpmtd_s td;
+  int issource;
+  if (!headerGet(h, TAG_DIRNAMES, &td, HEADERGET_MINMEM))
+    return 0;
+  issource = td.count == 1 && td.data && ((char **)td.data)[0] && !((char **)td.data)[0][0];
+  rpmtdFreeData(&td);
+  return issource;
 }
 
 static inline void
@@ -480,10 +486,7 @@ static char *headtoevr(RpmHead *h)
   release  = headstring(h, TAG_RELEASE);
   epoch = headint32(h, TAG_EPOCH);
   if (!version || !release)
-    {
-      fprintf(stderr, "headtoevr: bad rpm header\n");
-      return 0;
-    }
+    return 0;
   for (v = version; *v >= '0' && *v <= '9'; v++)
     ;
   if (epoch || (v != version && *v == ':'))
@@ -1089,7 +1092,7 @@ rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhe
       pool_error(pool, 0, "package has no name");
       return 0;
     }
-  if (!strcmp(name, "gpg-pubkey"))
+  if (!(flags & RPMDB_KEEP_GPG_PUBKEY) && !strcmp(name, "gpg-pubkey"))
     return 0;
   s->name = pool_str2id(pool, name, 1);
   sourcerpm = headstring(rpmhead, TAG_SOURCERPM);
@@ -1106,6 +1109,7 @@ rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhe
     s->arch = ARCH_NOARCH;
   evr = headtoevr(rpmhead);
   s->evr = pool_str2id(pool, evr, 1);
+  solv_free(evr);
   s->vendor = pool_str2id(pool, headstring(rpmhead, TAG_VENDOR), 1);
 
   queue_init_buffer(&ignq, ignqbuf, sizeof(ignqbuf)/sizeof(*ignqbuf));
@@ -1203,7 +1207,6 @@ rpmhead2solv(Pool *pool, Repo *repo, Repodata *data, Solvable *s, RpmHead *rpmhe
       if ((flags & RPM_ADD_WITH_CHANGELOG) != 0)
        addchangelog(data, handle, rpmhead);
     }
-  solv_free(evr);
   return 1;
 }
 
@@ -1257,10 +1260,7 @@ headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *
     }
   rpmhead = state->rpmhead;
   if (fread(rpmhead->data, len, 1, fp) != 1)
-    {
-      fclose(fp);
-      return pool_error(state->pool, 0, "%s: unexpected EOF", name);
-    }
+    return pool_error(state->pool, 0, "%s: unexpected EOF", name);
   if (chk1)
     solv_chksum_add(chk1, rpmhead->data, len);
   if (chk2)
@@ -1387,18 +1387,18 @@ copydeps(Pool *pool, Repo *repo, Offset fromoff, Repo *fromrepo)
 
 #define COPYDIR_DIRCACHE_SIZE 512
 
-static Id copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache);
+static Id copydir_complex(Repodata *data, Repodata *fromdata, Id did, Id *cache);
 
 static inline Id
-copydir(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache)
+copydir(Repodata *data, Repodata *fromdata, Id did, Id *cache)
 {
   if (cache && did && cache[did & 255] == did)
     return cache[(did & 255) + 256];
-  return copydir_complex(pool, data, fromdata, did, cache);
+  return copydir_complex(data, fromdata, did, cache);
 }
 
 static Id
-copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cache)
+copydir_complex(Repodata *data, Repodata *fromdata, Id did, Id *cache)
 {
   Id parent, compid;
   if (!did)
@@ -1411,7 +1411,7 @@ copydir_complex(Pool *pool, Repodata *data, Repodata *fromdata, Id did, Id *cach
   parent = dirpool_parent(&fromdata->dirpool, did);
   compid = dirpool_compid(&fromdata->dirpool, did);
   if (parent)
-    parent = copydir(pool, data, fromdata, parent, cache);
+    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);
@@ -1434,50 +1434,20 @@ static int
 solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, KeyValue *kv)
 {
   struct solvable_copy_cbdata *cbdata = vcbdata;
-  Id id, keyname;
   Repodata *data = cbdata->data;
   Id handle = cbdata->handle;
-  Pool *pool = data->repo->pool;
 
-  keyname = key->name;
-  switch(key->type)
+  switch (key->type)
     {
     case REPOKEY_TYPE_ID:
     case REPOKEY_TYPE_CONSTANTID:
     case REPOKEY_TYPE_IDARRAY: /* used for triggers */
-      id = kv->id;
       if (data->localpool || fromdata->localpool)
-       id = repodata_translate_id(data, fromdata, id, 1);
-      if (key->type == REPOKEY_TYPE_ID)
-        repodata_set_id(data, handle, keyname, id);
-      else if (key->type == REPOKEY_TYPE_CONSTANTID)
-        repodata_set_constantid(data, handle, keyname, id);
-      else
-        repodata_add_idarray(data, handle, keyname, id);
-      break;
-    case REPOKEY_TYPE_STR:
-      repodata_set_str(data, handle, keyname, kv->str);
-      break;
-    case REPOKEY_TYPE_VOID:
-      repodata_set_void(data, handle, keyname);
-      break;
-    case REPOKEY_TYPE_NUM:
-      repodata_set_num(data, handle, keyname, SOLV_KV_NUM64(kv));
-      break;
-    case REPOKEY_TYPE_CONSTANT:
-      repodata_set_constant(data, handle, keyname, kv->num);
+       kv->id = repodata_translate_id(data, fromdata, kv->id, 1);
       break;
     case REPOKEY_TYPE_DIRNUMNUMARRAY:
-      id = kv->id;
-      id = copydir(pool, data, fromdata, id, cbdata->dircache);
-      if (id)
-        repodata_add_dirnumnum(data, handle, keyname, id, kv->num, kv->num2);
-      break;
     case REPOKEY_TYPE_DIRSTRARRAY:
-      id = kv->id;
-      id = copydir(pool, data, fromdata, id, cbdata->dircache);
-      if (id)
-        repodata_add_dirstr(data, handle, keyname, id, kv->str);
+      kv->id = copydir(data, fromdata, kv->id, cbdata->dircache);
       break;
     case REPOKEY_TYPE_FLEXARRAY:
       if (kv->eof == 2)
@@ -1493,16 +1463,12 @@ solvable_copy_cb(void *vcbdata, Solvable *r, Repodata *fromdata, Repokey *key, K
          cbdata->subhandle = cbdata->handle;
        }
       cbdata->handle = repodata_new_handle(data);
-      repodata_add_flexarray(data, cbdata->subhandle, keyname, cbdata->handle);
-      break;
+      repodata_add_flexarray(data, cbdata->subhandle, key->name, cbdata->handle);
+      return 0;
     default:
-      if (solv_chksum_len(key->type))
-       {
-         repodata_set_bin_checksum(data, handle, keyname, key->type, (const unsigned char *)kv->str);
-         break;
-       }
       break;
     }
+  repodata_set_kv(data, handle, key->name, key->type, kv);
   return 0;
 }
 
@@ -1530,13 +1496,20 @@ solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache)
   s->enhances  = copydeps(pool, repo, r->enhances, fromrepo);
 
   /* copy all attributes */
-  if (!data)
+  if (!data || fromrepo->nrepodata < 2)
     return;
   cbdata.data = data;
   cbdata.handle = s - pool->solvables;
   cbdata.subhandle = 0;
   cbdata.dircache = dircache;
   p = r - fromrepo->pool->solvables;
+  if (fromrepo->nrepodata == 2)
+    {
+      Repodata *fromdata = repo_id2repodata(fromrepo, 1);
+      if (p >= fromdata->start && p < fromdata->end)
+        repodata_search(fromdata, p, 0, SEARCH_SUB | SEARCH_ARRAYSENTINEL, 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
@@ -1769,7 +1742,7 @@ repo_add_rpmdb(Repo *repo, Repo *ref, int flags)
       memset(dircache, 0, sizeof(dircache));
 
       /* get ids of installed rpms */
-      entries = getinstalledrpmdbids(&state, "Name", 0, &nentries, &namedata);
+      entries = getinstalledrpmdbids(&state, "Name", 0, &nentries, &namedata, flags & RPMDB_KEEP_GPG_PUBKEY);
       if (!entries)
        {
          freestate(&state);
@@ -2359,7 +2332,7 @@ rpm_query(void *rpmhandle, Id what)
   r = 0;
   switch (what)
     {
-    case 0:
+    case 0:    /* return canonical name of rpm */
       name = headstring(rpmhead, TAG_NAME);
       if (!name)
        name = "";
@@ -2423,7 +2396,7 @@ rpm_installedrpmdbids(void *rpmstate, const char *index, const char *match, Queu
   struct rpmdbentry *entries;
   int nentries, i;
 
-  entries = getinstalledrpmdbids(rpmstate, index ? index : "Name", match, &nentries, 0);
+  entries = getinstalledrpmdbids(rpmstate, index ? index : "Name", match, &nentries, 0, 0);
   if (rpmdbidq)
     {
       queue_empty(rpmdbidq);
index 9e3bd0d..554d48a 100644 (file)
@@ -25,6 +25,7 @@ extern Id repo_add_rpm(Repo *repo, const char *rpm, int flags);
 #define RPM_ADD_WITH_LEADSIGID (1 << 16)
 #define RPM_ADD_WITH_CHANGELOG (1 << 17)
 #define RPM_ADD_FILTERED_FILELIST (1 << 18)
+#define RPMDB_KEEP_GPG_PUBKEY   (1 << 19)
 
 #define RPMDB_EMPTY_REFREPO    (1 << 30)       /* internal */
 
index c34ff70..ed82a69 100644 (file)
@@ -265,7 +265,7 @@ closepkgdb(struct rpmdbstate *state)
 /* get the rpmdbids of all installed packages from the Name index database.
  * This is much faster then querying the big Packages database */
 static struct rpmdbentry *
-getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap)
+getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap, int keep_gpg_pubkey)
 {
   DB_ENV *dbenv = 0;
   DB *db = 0;
@@ -321,7 +321,7 @@ getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *ma
     }
   while (dbc->c_get(dbc, &dbkey, &dbdata, match ? DB_SET : DB_NEXT) == 0)
     {
-      if (!match && dbkey.size == 10 && !memcmp(dbkey.data, "gpg-pubkey", 10))
+      if (!match && !keep_gpg_pubkey && dbkey.size == 10 && !memcmp(dbkey.data, "gpg-pubkey", 10))
        continue;
       dl = dbdata.size;
       dp = dbdata.data;
index 802c5d1..79983d3 100644 (file)
@@ -111,10 +111,10 @@ closepkgdb(struct rpmdbstate *state)
 /* get the rpmdbids of all installed packages from the Name index database.
  * This is much faster then querying the big Packages database */
 static struct rpmdbentry *
-getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap)
+getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *match, int *nentriesp, char **namedatap, int keep_gpg_pubkey)
 {
   const void * key;
-  size_t keylen;
+  size_t keylen, matchl = 0;
   Id nameoff;
 
   char *namedata = 0;
@@ -125,20 +125,26 @@ getinstalledrpmdbids(struct rpmdbstate *state, const char *index, const char *ma
   rpmdbIndexIterator ii;
   int i;
 
+  *nentriesp = 0;
+  if (namedatap)
+    *namedatap = 0;
+
   if (state->dbenvopened != 1 && !opendbenv(state))
     return 0;
 
+  if (match)
+    matchl = strlen(match);
   ii = rpmdbIndexIteratorInit(rpmtsGetRdb(state->ts), RPMDBI_NAME);
 
-  *nentriesp = 0;
-  if (namedatap)
-    *namedatap = 0;
-
   while (rpmdbIndexIteratorNext(ii, &key, &keylen) == 0)
     {
-
-      if (keylen == 10 && !memcmp(key, "gpg-pubkey", 10))
-       continue;
+      if (match)
+       {
+         if (keylen != matchl || memcmp(key, match, keylen) != 0)
+           continue;
+       }
+      else if (!keep_gpg_pubkey && keylen == 10 && !memcmp(key, "gpg-pubkey", 10))
+        continue;
       nameoff = namedatal;
       if (namedatap)
        {
index 2c64bb6..a74762f 100644 (file)
@@ -316,6 +316,227 @@ static inline FILE *mylzfdopen(int fd, const char *mode)
 
 #endif /* ENABLE_LZMA_COMPRESSION */
 
+#ifdef ENABLE_ZSTD_COMPRESSION
+
+#include <zstd.h>
+
+typedef struct zstdfile {
+  ZSTD_CStream *cstream;
+  ZSTD_DStream *dstream;
+  FILE *file;
+  int encoding;
+  int eof;
+  ZSTD_inBuffer in;
+  ZSTD_outBuffer out;
+  unsigned char buf[1 << 15];
+} ZSTDFILE;
+
+static ZSTDFILE *zstdopen(const char *path, const char *mode, int fd)
+{
+  int level = 7;
+  int encoding = 0;
+  FILE *fp;
+  ZSTDFILE *zstdfile;
+
+  if (!path && fd < 0)
+    return 0;
+  for (; *mode; mode++)
+    {
+      if (*mode == 'w')
+       encoding = 1;
+      else if (*mode == 'r')
+       encoding = 0;
+      else if (*mode >= '1' && *mode <= '9')
+       level = *mode - '0';
+    }
+  if (fd != -1)
+    fp = fdopen(fd, encoding ? "w" : "r");
+  else
+    fp = fopen(path, encoding ? "w" : "r");
+  if (!fp)
+    return 0;
+  zstdfile = solv_calloc(1, sizeof(*zstdfile));
+  zstdfile->encoding = encoding;
+  if (encoding)
+    {
+      zstdfile->cstream = ZSTD_createCStream();
+      zstdfile->encoding = 1;
+      if (!zstdfile->cstream)
+       {
+         solv_free(zstdfile);
+         fclose(fp);
+         return 0;
+       }
+      if (ZSTD_isError(ZSTD_initCStream(zstdfile->cstream, level)))
+       {
+         ZSTD_freeCStream(zstdfile->cstream);
+         solv_free(zstdfile);
+         fclose(fp);
+         return 0;
+       }
+      zstdfile->out.dst = zstdfile->buf;
+      zstdfile->out.pos = 0;
+      zstdfile->out.size = sizeof(zstdfile->buf);
+    }
+  else
+    {
+      zstdfile->dstream = ZSTD_createDStream();
+      if (ZSTD_isError(ZSTD_initDStream(zstdfile->dstream)))
+       {
+         ZSTD_freeDStream(zstdfile->dstream);
+         solv_free(zstdfile);
+         fclose(fp);
+         return 0;
+       }
+      zstdfile->in.src = zstdfile->buf;
+      zstdfile->in.pos = 0;
+      zstdfile->in.size = 0;
+    }
+  zstdfile->file = fp;
+  return zstdfile;
+}
+
+static int zstdclose(void *cookie)
+{
+  ZSTDFILE *zstdfile = cookie;
+  int rc;
+
+  if (!zstdfile)
+    return -1;
+  if (zstdfile->encoding)
+    {
+      for (;;)
+       {
+         size_t ret;
+         zstdfile->out.pos = 0;
+         ret = ZSTD_endStream(zstdfile->cstream, &zstdfile->out);
+         if (ZSTD_isError(ret))
+           return -1;
+         if (zstdfile->out.pos && fwrite(zstdfile->buf, 1, zstdfile->out.pos, zstdfile->file) != zstdfile->out.pos)
+           return -1;
+         if (ret == 0)
+           break;
+       }
+      ZSTD_freeCStream(zstdfile->cstream);
+    }
+  else
+    {
+      ZSTD_freeDStream(zstdfile->dstream);
+    }
+  rc = fclose(zstdfile->file);
+  free(zstdfile);
+  return rc;
+}
+
+static ssize_t zstdread(void *cookie, char *buf, size_t len)
+{
+  ZSTDFILE *zstdfile = cookie;
+  int eof = 0;
+  size_t ret = 0;
+  if (!zstdfile || zstdfile->encoding)
+    return -1;
+  if (zstdfile->eof)
+    return 0;
+  zstdfile->out.dst = buf;
+  zstdfile->out.pos = 0;
+  zstdfile->out.size = len;
+  for (;;)
+    {
+      if (!eof && zstdfile->in.pos == zstdfile->in.size)
+       {
+         zstdfile->in.pos = 0;
+         zstdfile->in.size = fread(zstdfile->buf, 1, sizeof(zstdfile->buf), zstdfile->file);
+         if (!zstdfile->in.size)
+           eof = 1;
+       }
+      if (ret || !eof)
+        ret = ZSTD_decompressStream(zstdfile->dstream, &zstdfile->out, &zstdfile->in);
+      if (ret == 0 && eof)
+       {
+         zstdfile->eof = 1;
+         return zstdfile->out.pos;
+       }
+      if (ZSTD_isError(ret))
+       return -1;
+      if (zstdfile->out.pos == len)
+       return len;
+    }
+}
+
+static ssize_t zstdwrite(void *cookie, const char *buf, size_t len)
+{
+  ZSTDFILE *zstdfile = cookie;
+  if (!zstdfile || !zstdfile->encoding)
+    return -1;
+  if (!len)
+    return 0;
+  zstdfile->in.src = buf;
+  zstdfile->in.pos = 0;
+  zstdfile->in.size = len;
+
+  for (;;)
+    {
+      size_t ret;
+      zstdfile->out.pos = 0;
+      ret = ZSTD_compressStream(zstdfile->cstream, &zstdfile->out, &zstdfile->in);
+      if (ZSTD_isError(ret))
+        return -1;
+      if (zstdfile->out.pos && fwrite(zstdfile->buf, 1, zstdfile->out.pos, zstdfile->file) != zstdfile->out.pos)
+        return -1;
+      if (zstdfile->in.pos == len)
+        return len;
+    }
+}
+
+static inline FILE *myzstdfopen(const char *fn, const char *mode)
+{
+  ZSTDFILE *zstdfile = zstdopen(fn, mode, -1);
+  return cookieopen(zstdfile, mode, zstdread, zstdwrite, zstdclose);
+}
+
+static inline FILE *myzstdfdopen(int fd, const char *mode)
+{
+  ZSTDFILE *zstdfile = zstdopen(0, mode, fd);
+  return cookieopen(zstdfile, mode, zstdread, zstdwrite, zstdclose);
+}
+
+#endif
+
+#ifdef ENABLE_ZCHUNK_COMPRESSION
+
+#include "solv_zchunk.h"
+
+static void *zchunkopen(const char *path, const char *mode, int fd)
+{
+  FILE *fp;
+  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;
+  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);
+}
+
+static inline FILE *myzchunkfopen(const char *fn, const char *mode)
+{
+  return zchunkopen(fn, mode, -1);
+}
+
+static inline FILE *myzchunkfdopen(int fd, const char *mode)
+{
+  return zchunkopen(0, mode, fd);
+}
+
+#endif
 
 FILE *
 solv_xfopen(const char *fn, const char *mode)
@@ -352,6 +573,20 @@ solv_xfopen(const char *fn, const char *mode)
   if (suf && !strcmp(suf, ".bz2"))
     return 0;
 #endif
+#ifdef ENABLE_ZSTD_COMPRESSION
+  if (suf && !strcmp(suf, ".zst"))
+    return myzstdfopen(fn, mode);
+#else
+  if (suf && !strcmp(suf, ".zst"))
+    return 0;
+#endif
+#ifdef ENABLE_ZCHUNK_COMPRESSION
+  if (suf && !strcmp(suf, ".zck"))
+    return myzchunkfopen(fn, mode);
+#else
+  if (suf && !strcmp(suf, ".zst"))
+    return 0;
+#endif
   return fopen(fn, mode);
 }
 
@@ -403,6 +638,20 @@ solv_xfopen_fd(const char *fn, int fd, const char *mode)
   if (suf && !strcmp(suf, ".bz2"))
     return 0;
 #endif
+#ifdef ENABLE_ZSTD_COMPRESSION
+  if (suf && !strcmp(suf, ".zst"))
+    return myzstdfdopen(fd, simplemode);
+#else
+  if (suf && !strcmp(suf, ".zst"))
+    return 0;
+#endif
+#ifdef ENABLE_ZCHUNK_COMPRESSION
+  if (suf && !strcmp(suf, ".zck"))
+    return myzchunkfdopen(fd, simplemode);
+#else
+  if (suf && !strcmp(suf, ".zst"))
+    return 0;
+#endif
   return fdopen(fd, mode);
 }
 
@@ -430,6 +679,18 @@ solv_xfopen_iscompressed(const char *fn)
 #else
     return -1;
 #endif
+  if (!strcmp(suf, ".zst"))
+#ifdef ENABLE_ZSTD_COMPRESSION
+    return 1;
+#else
+    return -1;
+#endif
+  if (!strcmp(suf, ".zck"))
+#ifdef ENABLE_ZCHUNK_COMPRESSION
+    return 1;
+#else
+    return -1;
+#endif
   return 0;
 }
 
diff --git a/ext/solv_zchunk.c b/ext/solv_zchunk.c
new file mode 100644 (file)
index 0000000..0833445
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2018, SUSE LLC.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <zstd.h>
+
+#include "chksum.h"
+#include "util.h"
+#include "solv_zchunk.h"
+
+#define MAX_HDR_SIZE  0xffffff00
+#define MAX_CHUNK_CNT 0x0fffffff
+
+#undef VERIFY_DATA_CHKSUM
+
+struct solv_zchunk {
+  FILE *fp;
+  unsigned char *hdr;
+  unsigned char *hdr_end;
+
+  unsigned int flags;  /* header flags */
+  unsigned int comp;   /* compression type */
+
+  unsigned int hdr_chk_type;   /* header + data checksum */
+  unsigned int hdr_chk_len;
+  Id hdr_chk_id;
+
+  unsigned int chunk_chk_type; /* chunk checksum */
+  unsigned int chunk_chk_len;
+  Id chunk_chk_id;
+
+  Chksum *data_chk;    /* for data checksum verification */
+  unsigned char *data_chk_ptr;
+
+  unsigned int streamid;       /* stream we are reading */
+  unsigned int nchunks;                /* chunks left */
+  unsigned char *chunks;
+
+  ZSTD_DCtx *dctx;
+  ZSTD_DDict *ddict;
+
+  int eof;
+  unsigned char *buf;
+  unsigned int buf_used;
+  unsigned int buf_avail;
+};
+
+/* return 32bit compressed integer. returns NULL on overflow. */
+static unsigned char *
+getuint(unsigned char *p, unsigned char *endp, unsigned int *dp)
+{
+  if (!p || p >= endp)
+    return 0;
+  if (p < endp && (*p & 0x80) != 0)
+    {
+      *dp = p[0] ^ 0x80;
+      return p + 1;
+    }
+  if (++p < endp && (*p & 0x80) != 0)
+    {
+      *dp = p[-1] ^ ((p[0] ^ 0x80) << 7);
+      return p + 1;
+    }
+  if (++p < endp && (*p & 0x80) != 0)
+    {
+      *dp = p[-2] ^ (p[-1] << 7) ^ ((p[0] ^ 0x80) << 14);
+      return p + 1;
+    }
+  if (++p < endp && (*p & 0x80) != 0)
+    {
+      *dp = p[-3] ^ (p[-2] << 7) ^ (p[1] << 14) ^ ((p[0] ^ 0x80) << 21);
+      return p + 1;
+    }
+  if (++p < endp && (*p & 0xf0) == 0x80)
+    {
+      *dp = p[-4] ^ (p[-3] << 7) ^ (p[2] << 14) ^ (p[1] << 21) ^ ((p[0] ^ 0x80) << 28);
+      return p + 1;
+    }
+  return 0;
+}
+
+static unsigned char *
+getchksum(unsigned char *p, unsigned char *endp, unsigned int *typep, unsigned int *lenp, Id *idp)
+{
+  if ((p = getuint(p, endp, typep)) == 0)
+    return 0;
+  switch (*typep)
+    {
+    case 0:
+      *lenp = 20;
+      *idp = REPOKEY_TYPE_SHA1;
+      return p;
+    case 1:
+      *lenp = 32;
+      *idp = REPOKEY_TYPE_SHA256;
+      return p;
+    case 2:
+      *lenp = 64;
+      *idp = REPOKEY_TYPE_SHA512;
+      return p;
+    case 3:
+      *lenp = 16;
+      *idp = REPOKEY_TYPE_SHA512;
+      return p;
+    default:
+      break;
+    }
+  return 0;
+}
+
+static int
+skip_bytes(FILE *fp, size_t skip, Chksum *chk)
+{
+  unsigned char buf[4096];
+  while (skip)
+    {
+      size_t bite = skip > sizeof(buf) ? sizeof(buf) : skip;
+      if (fread(buf, bite, 1, fp) != 1)
+       return 0;
+      if (chk)
+       solv_chksum_add(chk, buf, bite);
+      skip -= bite;
+    }
+  return 1;
+}
+
+static int
+nextchunk(struct solv_zchunk *zck, unsigned int streamid)
+{
+  unsigned char *p = zck->chunks;
+  unsigned char *chunk_chk_ptr;
+  unsigned int sid, chunk_len, uncompressed_len;
+  unsigned char *cbuf;
+
+  /* free old buffer */
+  zck->buf = solv_free(zck->buf);
+  zck->buf_avail = 0;
+  zck->buf_used = 0;
+
+  for (;;)
+    {
+      if (zck->nchunks == 0)
+       {
+         zck->chunks = p;
+         return 1;             /* EOF reached */
+       }
+      if (p >= zck->hdr_end)
+       return 0;
+      sid = streamid ? 1 : 0;
+      /* check if this is the correct stream */
+      if ((zck->flags & 1) != 0 && (p = getuint(p, zck->hdr_end, &sid)) == 0)
+       return 0;
+      chunk_chk_ptr = p;       /* remember for verification */
+      p += zck->chunk_chk_len;
+      if (p >= zck->hdr_end)
+       return 0;
+      if ((p = getuint(p, zck->hdr_end, &chunk_len)) == 0)
+       return 0;
+      if ((p = getuint(p, zck->hdr_end, &uncompressed_len)) == 0)
+       return 0;
+      zck->nchunks--;
+      if (sid == streamid)
+       break;
+      /* skip the chunk, but the dict chunk must come first */
+      if (streamid == 0 || skip_bytes(zck->fp, chunk_len, zck->data_chk) == 0)
+       return 0;
+    }
+  zck->chunks = p;
+
+  /* ok, read the compressed chunk */
+  if (!chunk_len)
+    return uncompressed_len ? 0 : 1;
+  cbuf = solv_malloc(chunk_len);
+  if (fread(cbuf, chunk_len, 1, zck->fp) != 1)
+    {
+      solv_free(cbuf);
+      return 0;
+    }
+  if (zck->data_chk)
+    solv_chksum_add(zck->data_chk, cbuf, chunk_len);
+
+  /* verify the chunk checksum */
+  if (zck->chunk_chk_id)
+    {
+      Chksum *chk = solv_chksum_create(zck->chunk_chk_id);
+      if (!chk)
+       {
+         solv_free(cbuf);
+         return 0;
+       }
+      solv_chksum_add(chk, cbuf, chunk_len);
+      if (memcmp(solv_chksum_get(chk, 0), chunk_chk_ptr, zck->chunk_chk_len) != 0)
+       {
+         solv_chksum_free(chk, 0);
+         solv_free(cbuf);
+         return 0;
+       }
+      solv_chksum_free(chk, 0);
+    }
+
+  /* uncompress */
+  if (zck->comp == 0)
+    {
+      /* not compressed */
+      if (chunk_len != uncompressed_len)
+       {
+         solv_free(cbuf);
+         return 0;
+       }
+      zck->buf = cbuf;
+      zck->buf_avail = uncompressed_len;
+      return 1;
+    }
+  if (zck->comp == 2)
+    {
+      /* zstd compressed */
+      size_t r;
+      zck->buf = solv_malloc(uncompressed_len + 1);    /* +1 so we can detect too large frames */
+      if (zck->ddict)
+       r = ZSTD_decompress_usingDDict(zck->dctx, zck->buf, uncompressed_len + 1, cbuf, chunk_len, zck->ddict);
+      else
+       r = ZSTD_decompressDCtx(zck->dctx, zck->buf, uncompressed_len + 1, cbuf, chunk_len);
+      solv_free(cbuf);
+      if (r != uncompressed_len)
+       return 0;
+      zck->buf_avail = uncompressed_len;
+      return 1;
+    }
+  solv_free(cbuf);
+  return 0;
+}
+
+static inline struct solv_zchunk *
+open_error(struct solv_zchunk *zck)
+{
+  solv_zchunk_close(zck);
+  return 0;
+}
+
+struct solv_zchunk *
+solv_zchunk_open(FILE *fp, unsigned int streamid)
+{
+  struct solv_zchunk *zck;
+  unsigned char *p;
+  unsigned int hdr_size;       /* preface + index + signatures */
+  unsigned int lead_size;
+  unsigned int preface_size;
+  unsigned int index_size;
+
+  zck = solv_calloc(1, sizeof(*zck));
+
+  /* read and parse the lead, read the complete header */
+  zck->hdr = solv_calloc(15, 1);
+  zck->hdr_end = zck->hdr + 15;
+  if (fread(zck->hdr, 15, 1, fp) != 1 || memcmp(zck->hdr, "\000ZCK1", 5) != 0)
+    return open_error(zck);
+  p = zck->hdr + 5;
+  if ((p = getchksum(p, zck->hdr_end, &zck->hdr_chk_type, &zck->hdr_chk_len, &zck->hdr_chk_id)) == 0)
+    return open_error(zck);
+  if ((p = getuint(p, zck->hdr_end, &hdr_size)) == 0 || hdr_size > MAX_HDR_SIZE)
+    return open_error(zck);
+  lead_size = p - zck->hdr + zck->hdr_chk_len;
+  zck->hdr = solv_realloc(zck->hdr, lead_size + hdr_size);
+  zck->hdr_end = zck->hdr + lead_size + hdr_size;
+  if (fread(zck->hdr + 15, lead_size + hdr_size - 15, 1, fp) != 1)
+    return open_error(zck);
+
+  /* verify header checksum to guard against corrupt files */
+  if (zck->hdr_chk_id)
+    {
+      Chksum *chk = solv_chksum_create(zck->hdr_chk_id);
+      if (!chk)
+       return open_error(zck);
+      solv_chksum_add(chk, zck->hdr, lead_size - zck->hdr_chk_len);
+      solv_chksum_add(chk, zck->hdr + lead_size, hdr_size);
+      if (memcmp(solv_chksum_get(chk, 0), zck->hdr + (lead_size - zck->hdr_chk_len), zck->hdr_chk_len) != 0)
+       {
+         solv_chksum_free(chk, 0);
+         return open_error(zck);
+       }
+      solv_chksum_free(chk, 0);
+    }
+
+  /* parse preface: data chksum, flags, compression */
+  p = zck->hdr + lead_size;
+  if (p + zck->hdr_chk_len > zck->hdr_end)
+    return open_error(zck);
+  zck->data_chk_ptr = p;
+  p += zck->hdr_chk_len;
+#ifdef VERIFY_DATA_CHKSUM
+  if (zck->hdr_chk_id && (zck->data_chk = solv_chksum_create(zck->hdr_chk_id)) == 0)
+    return open_error(zck);
+#endif
+  if ((p = getuint(p, zck->hdr_end, &zck->flags)) == 0)
+    return open_error(zck);
+  if ((zck->flags & ~(1)) != 0)
+    return open_error(zck);
+  if ((p = getuint(p, zck->hdr_end, &zck->comp)) == 0 || (zck->comp != 0 && zck->comp != 2))
+    return open_error(zck);    /* only uncompressed + zstd supported */
+  preface_size = p - (zck->hdr + lead_size);
+
+  /* parse index: index size, index chksum type, num chunks, chunk data  */
+  if ((p = getuint(p, zck->hdr_end, &index_size)) == 0)
+    return open_error(zck);
+  if (hdr_size < preface_size + index_size)
+    return open_error(zck);
+  if ((p = getchksum(p, zck->hdr_end, &zck->chunk_chk_type, &zck->chunk_chk_len, &zck->chunk_chk_id)) == 0)
+    return open_error(zck);
+  if ((p = getuint(p, zck->hdr_end, &zck->nchunks)) == 0 || zck->nchunks > MAX_CHUNK_CNT)
+    return open_error(zck);
+
+  /* setup decompressor */
+  if (zck->comp == 2)
+    {
+      if ((zck->dctx = ZSTD_createDCtx()) == 0)
+       return open_error(zck);
+    }
+
+  zck->fp = fp;
+  zck->chunks = p;
+  zck->streamid = streamid;
+  if (streamid == 0)
+    {
+      zck->nchunks = zck->nchunks ? 1 : 0;     /* limit to dict chunk */
+      return zck;      
+    }
+
+  /* setup dictionary */
+  if (!nextchunk(zck, 0))
+    {
+      zck->fp = 0;
+      return open_error(zck);
+    }
+  if (zck->comp == 2 && zck->buf_avail)
+    {
+      if ((zck->ddict = ZSTD_createDDict(zck->buf, zck->buf_avail)) == 0)
+       {
+         zck->fp = 0;
+         return open_error(zck);
+       }
+    }
+  zck->buf = solv_free(zck->buf);
+  zck->buf_used = 0;
+  zck->buf_avail = 0;
+
+  /* ready to read the rest of the chunks */
+  return zck;
+}
+
+ssize_t
+solv_zchunk_read(struct solv_zchunk *zck, char *buf, size_t len)
+{
+  size_t n = 0;
+  if (!zck || zck->eof == 2)
+    return -1;
+  while (n < len && !zck->eof)
+    {
+      unsigned int bite;
+      while (!zck->buf_avail)
+       {
+         if (!zck->nchunks)
+           {
+             /* verify data checksum if requested */
+             if (zck->streamid != 0 && zck->data_chk && memcmp(solv_chksum_get(zck->data_chk, 0), zck->data_chk_ptr, zck->hdr_chk_len) != 0) {
+               zck->eof = 2;
+               return -1;
+             }
+             zck->eof = 1;
+             return n;
+           }
+         if (!nextchunk(zck, zck->streamid))
+           {
+             zck->eof = 2;
+             return -1;
+           }
+       }
+      bite = len - n > zck->buf_avail ? zck->buf_avail : len - n;
+      memcpy(buf + n, zck->buf + zck->buf_used, bite);
+      n += bite;
+      zck->buf_used += bite;
+      zck->buf_avail -= bite;
+    }
+  return n;
+}
+
+int
+solv_zchunk_close(struct solv_zchunk *zck)
+{
+  if (zck->data_chk)
+    solv_chksum_free(zck->data_chk, 0);
+  if (zck->ddict)
+    ZSTD_freeDDict(zck->ddict);
+  if (zck->dctx)
+    ZSTD_freeDCtx(zck->dctx);
+  solv_free(zck->hdr);
+  solv_free(zck->buf);
+  if (zck->fp)
+    fclose(zck->fp);
+  solv_free(zck);
+  return 0;
+}
diff --git a/ext/solv_zchunk.h b/ext/solv_zchunk.h
new file mode 100644 (file)
index 0000000..9d73486
--- /dev/null
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2018, SUSE LLC.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+struct solv_zchunk;
+
+extern struct solv_zchunk *solv_zchunk_open(FILE *fp, unsigned int streamid);
+extern ssize_t solv_zchunk_read(struct solv_zchunk *zck, char *buf, size_t len);
+extern int solv_zchunk_close(struct solv_zchunk *zck);
+
index ee3a9f0..430e479 100644 (file)
@@ -1,4 +1,27 @@
 -------------------------------------------------------------------
+Thu Aug  9 17:09:41 CEST 2018 - mls@suse.de
+
+- refactor arch handling
+- add support for zstd and zchunk compression
+- convert repo2solv.sh script into a binary tool
+- bump version to 0.6.35
+
+------------------------------------------------------------------
+Wed Jul 18 14:11:51 UTC 2018 - ngompa13@gmail.com
+
+- Fix compatibility with Mageia and RH/Fedora
+
+------------------------------------------------------------------
+Wed Jul 18 11:02:29 UTC 2018 - tchvatal@suse.com
+
+- Sort a bit with spec-cleaner
+- Use python/ruby/etc condition names to match what other packages
+  do in order to make sure we are enabling/disabling stuff within
+  prjcfg
+- Silence the source unpacking
+- Make sure to execute tests
+
+-------------------------------------------------------------------
 Fri Mar 23 12:02:08 CET 2018 - mls@suse.de
 
 - make sure product files come from /etc/products.d in fallback
index 6276f3c..ca649e8 100644 (file)
@@ -1,7 +1,7 @@
 #
 # spec file for package libsolv
 #
-# Copyright (c) 2017 SUSE LINUX Products GmbH, Nuernberg, Germany.
+# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
 # Please submit bugfixes or comments via http://bugs.opensuse.org/
 #
 
-Name:           libsolv
-Version:        @VERSION@
-Release:        0
-Url:            https://github.com/openSUSE/libsolv
-Source:         libsolv-%{version}.tar.bz2
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
+%define libname libsolv@LIBSOLV_SOVERSION@
 
-%bcond_without enable_static
-%bcond_without disable_shared
-%bcond_without perl_binding
-%bcond_without python_binding
-%bcond_without python3_binding
-%bcond_without ruby_binding
-%bcond_with zypp
-
-%if 0%{?leap_version} >= 420300 || 0%{?sle_version} >= 120300 || 0%{?suse_version} >= 1330 || !0%{?suse_version}
+%if 0%{?sle_version} >= 120300 || 0%{?suse_version} >= 1330 || !0%{?suse_version}
 %bcond_without bz2
 %bcond_without xz
 %else
 %bcond_with bz2
 %bcond_with xz
 %endif
-
+%if 0%{?sle_version} >= 150000 || 0%{?suse_version} >= 1500
+%bcond_without zstd
+%else
+%bcond_with zstd
+%endif
 %if 0%{?fedora} || 0%{?rhel} >= 7 || 0%{?mageia} >= 6 || 0%{?suse_version} >= 1330
 %bcond_without richdeps
 %else
 %bcond_with richdeps
 %endif
-
-%if 0%{?mandriva_version}
-# force this version on mandriva
-BuildRequires:  libneon0.26-devel
-%endif
-%if 0%{?fedora} || 0%{?rhel} >= 6 || 0%{?mageia}
-BuildRequires:  db-devel
-%endif
-BuildRequires:  libxml2-devel
-%if 0%{?suse_version} && 0%{?suse_version} < 1100
-BuildRequires:  graphviz
-%endif
-%if 0%{?suse_version} > 1020 || 0%{?fedora} || 0%{?mageia}
-BuildRequires:  fdupes
+# we need at least swig 1.3.40 for the bindings ($typemap support)
+%if 0%{?suse_version} != 1110
+%bcond_without python3
+%bcond_without python
+%bcond_without ruby
+%bcond_without perl
+%else
+%bcond_with python3
+%bcond_with python
+%bcond_with ruby
+%bcond_with perl
 %endif
+%bcond_without static
+%bcond_with shared
+%bcond_with zypp
+
+Name:           libsolv
+Version:        @VERSION@
+Release:        0
+Summary:        Package dependency solver using a satisfiability algorithm
+License:        BSD-3-Clause
+Group:          Development/Libraries/C and C++
+Url:            https://github.com/openSUSE/libsolv
+Source:         libsolv-%{version}.tar.bz2
 BuildRequires:  cmake
 BuildRequires:  gcc-c++
+BuildRequires:  libxml2-devel
 BuildRequires:  rpm-devel
 BuildRequires:  zlib-devel
+BuildRoot:      %{_tmppath}/%{name}-%{version}-build
+
+%if 0%{?fedora} || 0%{?rhel} >= 6 || 0%{?mageia}
+BuildRequires:  db-devel
+%endif
 
-%if %{with perl_binding}
+%if %{with perl}
 BuildRequires:  perl
 %if 0%{?fedora} || 0%{?rhel} >= 6 || 0%{?mageia}
 BuildRequires:  perl-devel
@@ -71,22 +77,23 @@ BuildRequires:  perl-devel
 BuildRequires:  swig
 %endif
 
-%if %{with ruby_binding}
+%if %{with ruby}
 %global ruby_vendorarch %(ruby  -r rbconfig -e "puts RbConfig::CONFIG['vendorarchdir'].nil? ? RbConfig::CONFIG['sitearchdir'] : RbConfig::CONFIG['vendorarchdir']")
 BuildRequires:  ruby
 BuildRequires:  ruby-devel
 BuildRequires:  swig
 %endif
 
-%if %{with python_binding}
+%if %{with python}
 %global python_sitearch %(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))")
 BuildRequires:  python-devel
 BuildRequires:  swig
 %endif
 
-%if %{with python3_binding}
+%if %{with python3}
 %global python3_sitearch %(python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))")
 BuildRequires:  python3-devel
+BuildRequires:  swig
 %endif
 
 %if %{with bz2}
@@ -101,21 +108,21 @@ BuildRequires:  bzip2-devel
 BuildRequires:  xz-devel
 %endif
 
+%if %{with zstd}
+BuildRequires:  libzstd-devel
+%endif
 
-Summary:        Package dependency solver using a satisfiability algorithm
-License:        BSD-3-Clause
-Group:          Development/Libraries/C and C++
 
 %description
 libsolv is a library for solving packages and reading repositories.
 The solver uses a satisfiability algorithm.
 
-%if !%{with disable_shared}
-%package -n libsolv@LIBSOLV_SOVERSION@
+%if %{with shared}
+%package -n %{libname}
 Summary:        Package dependency solver using a satisfiability algorithm
 Group:          System/Libraries
 
-%description -n libsolv@LIBSOLV_SOVERSION@
+%description -n %{libname}
 libsolv is a library for solving packages and reading repositories.
 It consists of two central blocks: Using a dictionary approach to
 store and retrieve package and dependency information, and, using a
@@ -126,8 +133,8 @@ dependencies.
 %package devel
 Summary:        Development files for libsolv, a package solver
 Group:          Development/Libraries/C and C++
-%if !%{with disable_shared}
-Requires:       libsolv@LIBSOLV_SOVERSION@ = %version
+%if %{with shared}
+Requires:       %{libname} = %version
 %endif
 Requires:       rpm-devel
 Conflicts:      libsatsolver-devel
@@ -139,10 +146,9 @@ reading repositories.
 %package tools
 Summary:        Utilities to work with .solv files
 Group:          System/Management
+Conflicts:      satsolver-tools-obsolete
 Obsoletes:      satsolver-tools < 0.18
 Provides:       satsolver-tools = 0.18
-Conflicts:      satsolver-tools-obsolete
-Requires:       gzip bzip2 coreutils findutils
 
 %description tools
 libsolv is a library for solving packages and reading repositories.
@@ -154,13 +160,13 @@ files used by libsolv.
 Summary:        Applications demoing the libsolv library
 Group:          System/Management
 Requires:       curl
+Conflicts:      libsatsolver-demo
 %if 0%{?fedora} || 0%{?rhel} >= 6 || 0%{?mageia}
 Requires:       gnupg2
 %endif
 %if 0%{?suse_version}
 Requires:       gpg2
 %endif
-Conflicts:      libsatsolver-demo
 
 %description demo
 Applications demoing the libsolv library.
@@ -173,7 +179,7 @@ Group:          Development/Languages/Ruby
 Ruby bindings for libsolv.
 
 %package -n python-solv
-%if 0%{?py_requires:1} && %{with python_binding}
+%if 0%{?py_requires:1} && %{with python}
 %py_requires
 %endif
 Summary:        Python bindings for the libsolv library
@@ -190,15 +196,15 @@ Group:          Development/Languages/Python
 Python3 bindings for libsolv.
 
 %package -n perl-solv
-Requires:       perl = %{perl_version}
 Summary:        Perl bindings for the libsolv library
 Group:          Development/Languages/Perl
+Requires:       perl = %{perl_version}
 
 %description -n perl-solv
 Perl bindings for libsolv.
 
 %prep
-%setup -n libsolv-%{version}
+%setup -q
 
 %build
 export CFLAGS="%{optflags}"
@@ -206,13 +212,13 @@ export CXXFLAGS="$CFLAGS"
 
 CMAKE_FLAGS=
 %if 0%{?fedora} || 0%{?rhel} >= 6
-CMAKE_FLAGS="-DFEDORA=1 -DENABLE_APPDATA=1 -DENABLE_COMPS=1"
+CMAKE_FLAGS="-DFEDORA=1"
 %endif
 %if 0%{?mageia}
-CMAKE_FLAGS="-DMAGEIA=1 -DENABLE_APPDATA=1 -DENABLE_COMPS=1"
+CMAKE_FLAGS="-DMAGEIA=1"
 %endif
 %if 0%{?suse_version}
-CMAKE_FLAGS="-DSUSE=1 -DENABLE_APPDATA=1 -DENABLE_COMPS=1"
+CMAKE_FLAGS="-DSUSE=1"
 %endif
 
 cmake  $CMAKE_FLAGS \
@@ -221,14 +227,18 @@ cmake     $CMAKE_FLAGS \
        -DCMAKE_VERBOSE_MAKEFILE=TRUE \
        -DCMAKE_BUILD_TYPE=RelWithDebInfo \
        -DWITH_LIBXML2=1 \
-       %{?with_enable_static:-DENABLE_STATIC=1} \
-       %{?with_disable_shared:-DDISABLE_SHARED=1} \
-       %{?with_perl_binding:-DENABLE_PERL=1} \
-       %{?with_python_binding:-DENABLE_PYTHON=1} \
-       %{?with_python3_binding:-DENABLE_PYTHON3=1} \
-       %{?with_ruby_binding:-DENABLE_RUBY=1} \
+       -DENABLE_APPDATA=1 \
+       -DENABLE_COMPS=1 \
+       %{?with_static:-DENABLE_STATIC=1} \
+       %{!?with_shared:-DDISABLE_SHARED=1} \
+       %{?with_perl:-DENABLE_PERL=1} \
+       %{?with_python:-DENABLE_PYTHON=1} \
+       %{?with_python3:-DENABLE_PYTHON3=1} \
+       %{?with_ruby:-DENABLE_RUBY=1} \
        %{?with_bz2:-DENABLE_BZIP2_COMPRESSION=1} \
        %{?with_xz:-DENABLE_LZMA_COMPRESSION=1} \
+       %{?with_zstd:-DENABLE_ZSTD_COMPRESSION=1} \
+       %{?with_zstd:-DENABLE_ZCHUNK_COMPRESSION=1} \
        %{?with_richdeps:-DENABLE_COMPLEX_DEPS=1} \
        %{?with_zypp:-DENABLE_SUSEREPO=1 -DENABLE_HELIXREPO=1} \
        -DUSE_VENDORDIRS=1 \
@@ -237,28 +247,30 @@ make %{?_smp_mflags}
 
 %install
 make DESTDIR=%{buildroot} install
+ln -s repo2solv %{buildroot}/%{_bindir}/repo2solv.sh
+
 %if 0%{?suse_version}
-%if %{with python_binding}
-pushd %{buildroot}/%{python_sitearch}
-python %py_libdir/py_compile.py *.py
-python -O %py_libdir/py_compile.py *.py
-popd
+%if %{with python}
+%py_compile -O %{buildroot}/%{python_sitearch}
 %endif
-%if %{with python3_binding}
+%if %{with python3}
 %py3_compile %{buildroot}/%{python3_sitearch}
 %endif
 %endif
-%if %{with disable_shared}
+%if %{with static}
 # we want to leave the .a file untouched
 export NO_BRP_STRIP_DEBUG=true
 %endif
 
-%if !%{with disable_shared}
-%post -n libsolv@LIBSOLV_SOVERSION@ -p /sbin/ldconfig
+%check
+make ARGS=--output-on-failure test
+
+%if %{with shared}
+%post -n %{libname} -p /sbin/ldconfig
 
-%postun -n libsolv@LIBSOLV_SOVERSION@ -p /sbin/ldconfig
+%postun -n %{libname} -p /sbin/ldconfig
 
-%files -n libsolv@LIBSOLV_SOVERSION@
+%files -n %{libname}
 %defattr(-,root,root)
 %license LICENSE*
 %{_libdir}/libsolv.so.*
@@ -271,17 +283,18 @@ export NO_BRP_STRIP_DEBUG=true
 %exclude %{_bindir}/helix2solv
 %exclude %{_mandir}/man1/helix2solv*
 %endif
+%exclude %{_mandir}/man1/solv.1*
 %exclude %{_bindir}/solv
 %{_bindir}/*
 %{_mandir}/man1/*
 
 %files devel
 %defattr(-,root,root)
-%if %{with enable_static}
+%if %{with static}
 %{_libdir}/libsolv.a
 %{_libdir}/libsolvext.a
 %endif
-%if !%{with disable_shared}
+%if %{with shared}
 %{_libdir}/libsolv.so
 %{_libdir}/libsolvext.so
 %endif
@@ -297,26 +310,27 @@ export NO_BRP_STRIP_DEBUG=true
 %files demo
 %defattr(-,root,root)
 %{_bindir}/solv
+%{_mandir}/man1/solv.1*
 
-%if %{with perl_binding}
+%if %{with perl}
 %files -n perl-solv
 %defattr(-,root,root)
 %{perl_vendorarch}/*
 %endif
 
-%if %{with ruby_binding}
+%if %{with ruby}
 %files -n ruby-solv
 %defattr(-,root,root)
 %{ruby_vendorarch}/*
 %endif
 
-%if %{with python_binding}
+%if %{with python}
 %files -n python-solv
 %defattr(-,root,root)
 %{python_sitearch}/*
 %endif
 
-%if %{with python3_binding}
+%if %{with python3}
 %files -n python3-solv
 %defattr(-,root,root)
 %{python3_sitearch}/*solv*
index e004bf2..4e8adbd 100644 (file)
@@ -32,18 +32,18 @@ map_free(Map *m)
   m->size = 0;
 }
 
-/* copy constructor t <- s */
+/* copy constructor target <- source */
 void
-map_init_clone(Map *t, Map *s)
+map_init_clone(Map *target, const Map *source)
 {
-  t->size = s->size;
-  if (s->size)
+  target->size = source->size;
+  if (source->size)
     {
-      t->map = solv_malloc(s->size);
-      memcpy(t->map, s->map, s->size);
+      target->map = solv_malloc(source->size);
+      memcpy(target->map, source->map, source->size);
     }
   else
-    t->map = 0;
+    target->map = 0;
 }
 
 /* grow a map */
@@ -61,7 +61,7 @@ map_grow(Map *m, int n)
 
 /* bitwise-ands maps t and s, stores the result in t. */
 void
-map_and(Map *t, Map *s)
+map_and(Map *t, const Map *s)
 {
   unsigned char *ti, *si, *end;
   ti = t->map;
@@ -73,7 +73,7 @@ map_and(Map *t, Map *s)
 
 /* bitwise-ors maps t and s, stores the result in t. */
 void
-map_or(Map *t, Map *s)
+map_or(Map *t, const Map *s)
 {
   unsigned char *ti, *si, *end;
   if (t->size < s->size)
@@ -87,7 +87,7 @@ map_or(Map *t, Map *s)
 
 /* remove all set bits in s from t. */
 void
-map_subtract(Map *t, Map *s)
+map_subtract(Map *t, const Map *s)
 {
   unsigned char *ti, *si, *end;
   ti = t->map;
index 0050a6a..1e89590 100644 (file)
@@ -37,12 +37,12 @@ typedef struct _Map {
 #define MAPCLR_AT(m, n) ((m)->map[(n) >> 3] = 0)
 
 extern void map_init(Map *m, int n);
-extern void map_init_clone(Map *t, Map *s);
+extern void map_init_clone(Map *target, const Map *source);
 extern void map_grow(Map *m, int n);
 extern void map_free(Map *m);
-extern void map_and(Map *t, Map *s);
-extern void map_or(Map *t, Map *s);
-extern void map_subtract(Map *t, Map *s);
+extern void map_and(Map *t, const Map *s);
+extern void map_or(Map *t, const Map *s);
+extern void map_subtract(Map *t, const Map *s);
 extern void map_invertall(Map *m);
 
 static inline void map_empty(Map *m)
index cbe2020..1da28f6 100644 (file)
@@ -1122,23 +1122,22 @@ solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded)
 #endif
       if (s->repo == installed && pool->implicitobsoleteusescolors)
        {
-         Id a, bestarch = 0;
+         unsigned int a, bestscore = 0;
          FOR_PROVIDES(p, pp, s->name)
            {
              Solvable *ps = pool->solvables + p;
              if (ps->name != s->name || ps->repo == installed)
                continue;
-             a = ps->arch;
-             a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
-             if (a && a != 1 && (!bestarch || a < bestarch))
-               bestarch = a;
+             a = pool_arch2score(pool, ps->arch);
+             if (a && a != 1 && (!bestscore || a < bestscore))
+               bestscore = a;
            }
-         if (bestarch && (s->arch > pool->lastarch || pool->id2arch[s->arch] != bestarch))
+         if (bestscore && pool_arch2score(pool, s->arch) != bestscore)
            {
              FOR_PROVIDES(p, pp, s->name)
                {
                  Solvable *ps = pool->solvables + p;
-                 if (ps->repo == installed && ps->name == s->name && ps->evr == s->evr && ps->arch != s->arch && ps->arch < pool->lastarch && pool->id2arch[ps->arch] == bestarch)
+                 if (ps->repo == installed && ps->name == s->name && ps->evr == s->evr && ps->arch != s->arch && pool_arch2score(pool, ps->arch) == bestscore)
                    if (!MAPTST(&im, p))
                      {
 #ifdef CLEANDEPSDEBUG
index 9adf60d..a3fa19a 100644 (file)
@@ -431,3 +431,7 @@ SOLV_1.2 {
                pool_set_whatprovides;
                selection_subtract;
 } SOLV_1.1;
+
+SOLV_1.3 {
+               repodata_set_kv;
+} SOLV_1.2;
index 6f06101..a38dea0 100644 (file)
@@ -56,11 +56,11 @@ prune_to_best_version_sortcmp(const void *ap, const void *bp, void *dp)
     }
   if (sa->arch != sb->arch)
     {
-      int aa, ab;
-      aa = (sa->arch <= pool->lastarch) ? pool->id2arch[sa->arch] : 0;
-      ab = (sb->arch <= pool->lastarch) ? pool->id2arch[sb->arch] : 0;
+      unsigned int aa, ab;
+      aa = pool_arch2score(pool, sa->arch);
+      ab = pool_arch2score(pool, sb->arch);
       if (aa != ab && aa > 1 && ab > 1)
-       return aa - ab;         /* lowest score first */
+       return aa < ab ? -1 : 1;        /* lowest score first */
     }
 
   /* the same name, bring installed solvables to the front */
@@ -646,8 +646,7 @@ prune_to_best_arch(const Pool *pool, Queue *plist)
   for (i = 0; i < plist->count; i++)
     {
       s = pool->solvables + plist->elements[i];
-      a = s->arch;
-      a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
+      a = pool_arch2score(pool, s->arch);
       if (a && a != 1 && (!bestscore || a < bestscore))
        bestscore = a;
     }
@@ -656,10 +655,9 @@ prune_to_best_arch(const Pool *pool, Queue *plist)
   for (i = j = 0; i < plist->count; i++)
     {
       s = pool->solvables + plist->elements[i];
-      a = s->arch;
-      if (a > pool->lastarch)
+      a = pool_arch2score(pool, s->arch);
+      if (!a)
        continue;
-      a = pool->id2arch[a];
       /* a == 1 -> noarch */
       if (a != 1 && ((a ^ bestscore) & 0xffff0000) != 0)
        continue;
@@ -1383,8 +1381,8 @@ policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2)
     return 0;
   if (!pool->id2arch)
     return 0;
-  a1 = a1 <= pool->lastarch ? pool->id2arch[a1] : 0;
-  a2 = a2 <= pool->lastarch ? pool->id2arch[a2] : 0;
+  a1 = pool_arch2score(pool, a1);
+  a2 = pool_arch2score(pool, a2);
   if (((a1 ^ a2) & 0xffff0000) != 0)
     return 1;
   return 0;
index ba5e799..60cc0f4 100644 (file)
@@ -44,7 +44,7 @@ pool_create(void)
 
   pool = (Pool *)solv_calloc(1, sizeof(*pool));
 
-  stringpool_init (&pool->ss, initpool_data);
+  stringpool_init(&pool->ss, initpool_data);
 
   /* alloc space for RelDep 0 */
   pool->rels = solv_extend_resize(0, 1, sizeof(Reldep), REL_BLOCK);
index f6573af..e6d1700 100644 (file)
@@ -88,7 +88,7 @@ struct _Pool {
 
   Id *id2arch;                 /* map arch ids to scores */
   unsigned char *id2color;     /* map arch ids to colors */
-  Id lastarch;                 /* last valid entry in id2arch/id2color */
+  Id lastarch;                 /* size of the id2arch/id2color arrays */
 
   Queue vendormap;             /* map vendor to vendorclasses mask */
   const char **vendorclasses;  /* vendor equivalence classes */
@@ -282,6 +282,10 @@ static inline Solvable *pool_id2solvable(const Pool *pool, Id p)
 {
   return pool->solvables + p;
 }
+static inline Id pool_solvable2id(const Pool *pool, Solvable *s)
+{
+  return s - pool->solvables;
+}
 
 extern const char *pool_solvable2str(Pool *pool, Solvable *s);
 static inline const char *pool_solvid2str(Pool *pool, Id p)
index 8da16c1..4a1fa50 100644 (file)
@@ -104,6 +104,9 @@ pool_setarchpolicy(Pool *pool, const char *arch)
     }
   id = pool->noarchid;
   lastarch = id + 255;
+  /* note that we overallocate one element to be compatible with
+   * old versions that accessed id2arch[lastarch].
+   * id2arch[lastarch] will always be zero */
   id2arch = solv_calloc(lastarch + 1, sizeof(Id));
   id2arch[id] = 1;     /* the "noarch" class */
 
@@ -114,7 +117,7 @@ pool_setarchpolicy(Pool *pool, const char *arch)
       if (l)
        {
          id = pool_strn2id(pool, arch, l, 1);
-         if (id > lastarch)
+         if (id >= lastarch)
            {
              id2arch = solv_realloc2(id2arch, (id + 255 + 1), sizeof(Id));
              memset(id2arch + lastarch + 1, 0, (id + 255 - lastarch) * sizeof(Id));
@@ -143,7 +146,7 @@ pool_arch2color_slow(Pool *pool, Id arch)
   const char *s;
   unsigned char color;
 
-  if (arch > pool->lastarch)
+  if ((unsigned int)arch >= (unsigned int)pool->lastarch)
     return ARCHCOLOR_ALL;
   if (!pool->id2color)
     pool->id2color = solv_calloc(pool->lastarch + 1, 1);
index 3fe5f02..787883b 100644 (file)
@@ -24,7 +24,7 @@ extern unsigned char pool_arch2color_slow(Pool *pool, Id arch);
 
 static inline unsigned char pool_arch2color(Pool *pool, Id arch)
 {
-  if (arch > pool->lastarch)
+  if ((unsigned int)arch >= (unsigned int)pool->lastarch)
     return ARCHCOLOR_ALL;
   if (pool->id2color && pool->id2color[arch])
     return pool->id2color[arch];
@@ -40,6 +40,10 @@ static inline int pool_colormatch(Pool *pool, Solvable *s1, Solvable *s2)
   return 0;
 }
 
+static inline unsigned int pool_arch2score(const Pool *pool, Id arch) {
+  return (unsigned int)arch < (unsigned int)pool->lastarch ? (unsigned int)pool->id2arch[arch] : 0;
+}
+
 #ifdef __cplusplus
 }
 #endif
index bb8d4f6..3b55f76 100644 (file)
@@ -51,39 +51,58 @@ pool_strn2id(Pool *pool, const char *str, unsigned int len, int create)
   return id;
 }
 
+void
+pool_resize_rels_hash(Pool *pool, int numnew)
+{
+  Hashval h, hh, hashmask;
+  Hashtable hashtbl;
+  int i;
+  Reldep *rd;
+
+  if (numnew <= 0)
+    return;
+  hashmask = mkmask(pool->nrels + numnew);
+  if (hashmask <= pool->relhashmask)
+    return;    /* same as before */
+
+  /* realloc hash table */
+  pool->relhashmask = hashmask;
+  solv_free(pool->relhashtbl);
+  pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id));
+
+  /* rehash all rels into new hashtable */
+  for (i = 1, rd = pool->rels + i; i < pool->nrels; i++, rd++)
+    {
+      h = relhash(rd->name, rd->evr, rd->flags) & hashmask;
+      hh = HASHCHAIN_START;
+      while (hashtbl[h])
+       h = HASHCHAIN_NEXT(h, hh, hashmask);
+      hashtbl[h] = i;
+    }
+}
+
 Id
 pool_rel2id(Pool *pool, Id name, Id evr, int flags, int create)
 {
   Hashval h, hh, hashmask;
-  int i;
   Id id;
   Hashtable hashtbl;
   Reldep *ran;
 
-  hashmask = pool->relhashmask;
-  hashtbl = pool->relhashtbl;
-  ran = pool->rels;
 
   /* extend hashtable if needed */
+  hashmask = pool->relhashmask;
   if ((Hashval)pool->nrels * 2 > hashmask)
     {
-      solv_free(pool->relhashtbl);
-      pool->relhashmask = hashmask = mkmask(pool->nrels + REL_BLOCK);
-      pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id));
-      /* rehash all rels into new hashtable */
-      for (i = 1; i < pool->nrels; i++)
-       {
-         h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
-         hh = HASHCHAIN_START;
-         while (hashtbl[h])
-           h = HASHCHAIN_NEXT(h, hh, hashmask);
-         hashtbl[h] = i;
-       }
+      pool_resize_rels_hash(pool, REL_BLOCK);
+      hashmask = pool->relhashmask;
     }
+  hashtbl = pool->relhashtbl;
 
   /* compute hash and check for match */
   h = relhash(name, evr, flags) & hashmask;
   hh = HASHCHAIN_START;
+  ran = pool->rels;
   while ((id = hashtbl[h]) != 0)
     {
       if (ran[id].name == name && ran[id].evr == evr && ran[id].flags == flags)
@@ -297,15 +316,28 @@ pool_dep2str(Pool *pool, Id id)
   return p;
 }
 
+static void
+pool_free_rels_hash(Pool *pool)
+{
+  pool->relhashtbl = solv_free(pool->relhashtbl);
+  pool->relhashmask = 0;
+}
+
 void
 pool_shrink_strings(Pool *pool)
 {
+  /* free excessive big hashes */
+  if (pool->ss.stringhashmask && pool->ss.stringhashmask > mkmask(pool->ss.nstrings + 8192))
+    stringpool_freehash(&pool->ss);
   stringpool_shrink(&pool->ss);
 }
 
 void
 pool_shrink_rels(Pool *pool)
 {
+  /* free excessive big hashes */
+  if (pool->relhashmask && pool->relhashmask > mkmask(pool->nrels + 4096))
+    pool_free_rels_hash(pool);
   pool->rels = solv_extend_resize(pool->rels, pool->nrels, sizeof(Reldep), REL_BLOCK);
 }
 
@@ -314,8 +346,7 @@ void
 pool_freeidhashes(Pool *pool)
 {
   stringpool_freehash(&pool->ss);
-  pool->relhashtbl = solv_free(pool->relhashtbl);
-  pool->relhashmask = 0;
+  pool_free_rels_hash(pool);
 }
 
 /* EOF */
index 2363595..79a3ccd 100644 (file)
@@ -41,6 +41,7 @@ extern const char *pool_dep2str(Pool *pool, Id); /* might alloc tmpspace */
 extern void pool_shrink_strings(Pool *pool);
 extern void pool_shrink_rels(Pool *pool);
 extern void pool_freeidhashes(Pool *pool);
+extern void pool_resize_rels_hash(Pool *pool, int numnew);
 
 #ifdef __cplusplus
 }
index 5bd2bf5..df751c4 100644 (file)
@@ -1281,7 +1281,7 @@ solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id targ
       if (pool_disabled_solvable(pool, ss))
         return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " is disabled");
       if (ss->arch && ss->arch != ARCH_SRC && ss->arch != ARCH_NOSRC &&
-          pool->id2arch && (ss->arch > pool->lastarch || !pool->id2arch[ss->arch]))
+          pool->id2arch && pool_arch2score(pool, ss->arch) == 0)
         return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " does not have a compatible architecture");
       return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " is not installable");
     case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP:
index ceb1062..6d5e531 100644 (file)
@@ -36,21 +36,21 @@ queue_init(Queue *q)
 }
 
 void
-queue_init_clone(Queue *t, Queue *s)
+queue_init_clone(Queue *target, const Queue *source)
 {
   int extra_space;
-  if (!s->elements)
+  if (!source->elements)
     {
-      t->alloc = t->elements = 0;
-      t->count = t->left = 0;
+      target->alloc = target->elements = 0;
+      target->count = target->left = 0;
       return;
     }
-  extra_space = queue_extra_space(s->count);
-  t->alloc = t->elements = solv_malloc2(s->count + extra_space, sizeof(Id));
-  if (s->count)
-    memcpy(t->alloc, s->elements, s->count * sizeof(Id));
-  t->count = s->count;
-  t->left = extra_space;
+  extra_space = queue_extra_space(source->count);
+  target->alloc = target->elements = solv_malloc2(source->count + extra_space, sizeof(Id));
+  if (source->count)
+    memcpy(target->alloc, source->elements, source->count * sizeof(Id));
+  target->count = source->count;
+  target->left = extra_space;
 }
 
 void
@@ -168,7 +168,7 @@ queue_delete2(Queue *q, int pos)
 }
 
 void
-queue_insertn(Queue *q, int pos, int n, Id *elements)
+queue_insertn(Queue *q, int pos, int n, const Id *elements)
 {
   if (n <= 0)
     return;
index 4785e67..7e56035 100644 (file)
@@ -109,12 +109,12 @@ queue_truncate(Queue *q, int n)
 
 extern void queue_init(Queue *q);
 extern void queue_init_buffer(Queue *q, Id *buf, int size);
-extern void queue_init_clone(Queue *t, Queue *s);
+extern void queue_init_clone(Queue *target, const Queue *source);
 extern void queue_free(Queue *q);
 
 extern void queue_insert(Queue *q, int pos, Id id);
 extern void queue_insert2(Queue *q, int pos, Id id1, Id id2);
-extern void queue_insertn(Queue *q, int pos, int n, Id *elements);
+extern void queue_insertn(Queue *q, int pos, int n, const Id *elements);
 extern void queue_delete(Queue *q, int pos);
 extern void queue_delete2(Queue *q, int pos);
 extern void queue_deleten(Queue *q, int pos, int n);
index 9dcbcca..bd9c58c 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "pooltypes.h"
 #include "pool.h"
+#include "poolarch.h"
 #include "repodata.h"
 #include "dataiterator.h"
 #include "hash.h"
@@ -102,7 +103,7 @@ static inline int pool_badarch_solvable(const Pool *pool, Solvable *s)
 {
   if (!s->arch)
     return 1;
-  if (pool->id2arch && (s->arch > pool->lastarch || !pool->id2arch[s->arch]))
+  if (pool->id2arch && pool_arch2score(pool, s->arch) == 0)
     return 1;
   return 0;
 }
@@ -113,7 +114,7 @@ static inline int pool_installable(const Pool *pool, Solvable *s)
     return 0;
   if (s->repo && s->repo->disabled)
     return 0;
-  if (pool->id2arch && (s->arch > pool->lastarch || !pool->id2arch[s->arch]))
+  if (pool->id2arch && pool_arch2score(pool, s->arch) == 0)
     return 0;
   if (pool->considered)
     {
index 2460e30..5858d4f 100644 (file)
@@ -223,7 +223,7 @@ data_read_idarray(unsigned char *dp, Id **storep, Id *map, int max, Repodata *da
          data->error = SOLV_ERROR_ID_RANGE;
          break;
        }
-      *store++ = x;
+      *store++ = map ? map[x] : x;
       if ((c & 64) == 0)
         break;
       x = 0;
@@ -612,7 +612,7 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
       unsigned int pfsize = read_u32(&data);
       char *prefix = solv_malloc(pfsize);
       char *pp = prefix;
-      char *old_str = 0;
+      char *old_str = strsp;
       char *dest = strsp;
       int freesp = sizeid;
 
@@ -682,35 +682,16 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
       /* alloc id map for name and rel Ids. this maps ids in the solv files
        * to the ids in our pool */
       idmap = solv_calloc(numid + numrel, sizeof(Id));
-
-      /* grow hash if needed, otherwise reuse */
-      hashmask = mkmask(spool->nstrings + numid);
+      stringpool_resize_hash(spool, numid);
+      hashtbl = spool->stringhashtbl;
+      hashmask = spool->stringhashmask;
 #if 0
       POOL_DEBUG(SOLV_DEBUG_STATS, "read %d strings\n", numid);
-      POOL_DEBUG(SOLV_DEBUG_STATS, "string hash buckets: %d, old %d\n", hashmask + 1, spool->stringhashmask + 1);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "string hash buckets: %d\n", hashmask + 1);
 #endif
-      if (hashmask > spool->stringhashmask)
-       {
-         spool->stringhashtbl = solv_free(spool->stringhashtbl);
-         spool->stringhashmask = hashmask;
-          spool->stringhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id));
-         for (i = 1; i < spool->nstrings; i++)
-           {
-             h = strhash(spool->stringspace + spool->strings[i]) & hashmask;
-             hh = HASHCHAIN_START;
-             while (hashtbl[h])
-               h = HASHCHAIN_NEXT(h, hh, hashmask);
-             hashtbl[h] = i;
-           }
-       }
-      else
-       {
-         hashtbl = spool->stringhashtbl;
-         hashmask = spool->stringhashmask;
-       }
-
       /*
        * run over strings and merge with pool.
+       * we could use stringpool_str2id, but this is faster.
        * also populate id map (maps solv Id -> pool Id)
        */
       for (i = 1; i < numid; i++)
@@ -758,11 +739,6 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
          idmap[i] = id;       /* repo relative -> pool relative */
          sp += l;             /* next string */
        }
-      if (hashmask > mkmask(spool->nstrings + 8192))
-       {
-         spool->stringhashtbl = solv_free(spool->stringhashtbl);
-         spool->stringhashmask = 0;
-       }
       stringpool_shrink(spool);                /* vacuum */
     }
 
@@ -780,31 +756,13 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
       pool->rels = solv_realloc2(pool->rels, pool->nrels + numrel, sizeof(Reldep));
       ran = pool->rels;
 
-      /* grow hash if needed, otherwise reuse */
-      hashmask = mkmask(pool->nrels + numrel);
+      pool_resize_rels_hash(pool, numrel);
+      hashtbl = pool->relhashtbl;
+      hashmask = pool->relhashmask;
 #if 0
       POOL_DEBUG(SOLV_DEBUG_STATS, "read %d rels\n", numrel);
-      POOL_DEBUG(SOLV_DEBUG_STATS, "rel hash buckets: %d, old %d\n", hashmask + 1, pool->relhashmask + 1);
+      POOL_DEBUG(SOLV_DEBUG_STATS, "rel hash buckets: %d\n", hashmask + 1);
 #endif
-      if (hashmask > pool->relhashmask)
-       {
-         pool->relhashtbl = solv_free(pool->relhashtbl);
-         pool->relhashmask = hashmask;
-          pool->relhashtbl = hashtbl = solv_calloc(hashmask + 1, sizeof(Id));
-         for (i = 1; i < pool->nrels; i++)
-           {
-             h = relhash(ran[i].name, ran[i].evr, ran[i].flags) & hashmask;
-             hh = HASHCHAIN_START;
-             while (hashtbl[h])
-               h = HASHCHAIN_NEXT(h, hh, hashmask);
-             hashtbl[h] = i;
-           }
-       }
-      else
-       {
-         hashtbl = pool->relhashtbl;
-         hashmask = pool->relhashmask;
-       }
 
       /*
        * read RelDeps from repo
@@ -837,11 +795,6 @@ repo_add_solv(Repo *repo, FILE *fp, int flags)
            }
          idmap[i + numid] = MAKERELDEP(id);   /* fill Id map */
        }
-      if (hashmask > mkmask(pool->nrels + 4096))
-       {
-         pool->relhashtbl = solv_free(pool->relhashtbl);
-         pool->relhashmask = 0;
-       }
       pool_shrink_rels(pool);          /* vacuum */
     }
 
index 396cd42..7e78af5 100644 (file)
@@ -260,106 +260,6 @@ write_idarray(Repodata *data, Pool *pool, NeedId *needid, Id *ids)
     }
 }
 
-static int
-cmp_ids(const void *pa, const void *pb, void *dp)
-{
-  Id a = *(Id *)pa;
-  Id b = *(Id *)pb;
-  return a - b;
-}
-
-#if 0
-static void
-write_idarray_sort(Repodata *data, Pool *pool, NeedId *needid, Id *ids, Id marker)
-{
-  int len, i;
-  Id lids[64], *sids;
-
-  if (!ids)
-    return;
-  if (!*ids)
-    {
-      write_u8(data, 0);
-      return;
-    }
-  for (len = 0; len < 64 && ids[len]; len++)
-    {
-      Id id = ids[len];
-      if (needid)
-        id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
-      lids[len] = id;
-    }
-  if (ids[len])
-    {
-      for (i = len + 1; ids[i]; i++)
-       ;
-      sids = solv_malloc2(i, sizeof(Id));
-      memcpy(sids, lids, 64 * sizeof(Id));
-      for (; ids[len]; len++)
-       {
-         Id id = ids[len];
-         if (needid)
-            id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
-         sids[len] = id;
-       }
-    }
-  else
-    sids = lids;
-
-  /* That bloody solvable:prereqmarker needs to stay in position :-(  */
-  if (needid)
-    marker = needid[marker].need;
-  for (i = 0; i < len; i++)
-    if (sids[i] == marker)
-      break;
-  if (i > 1)
-    solv_sort(sids, i, sizeof(Id), cmp_ids, 0);
-  if ((len - i) > 2)
-    solv_sort(sids + i + 1, len - i - 1, sizeof(Id), cmp_ids, 0);
-
-  Id id, old = 0;
-
-  /* The differencing above produces many runs of ones and twos.  I tried
-     fairly elaborate schemes to RLE those, but they give only very mediocre
-     improvements in compression, as coding the escapes costs quite some
-     space.  Even if they are coded only as bits in IDs.  The best improvement
-     was about 2.7% for the whole .solv file.  It's probably better to
-     invest some complexity into sharing idarrays, than RLEing.  */
-  for (i = 0; i < len - 1; i++)
-    {
-      id = sids[i];
-    /* Ugly PREREQ handling.  A "difference" of 0 is the prereq marker,
-       hence all real differences are offsetted by 1.  Otherwise we would
-       have to handle negative differences, which would cost code space for
-       the encoding of the sign.  We loose the exact mapping of prereq here,
-       but we know the result, so we can recover from that in the reader.  */
-      if (id == marker)
-       id = old = 0;
-      else
-       {
-          id = id - old + 1;
-         old = sids[i];
-       }
-      /* XXX If difference is zero we have multiple equal elements,
-        we might want to skip writing them out.  */
-      if (id >= 64)
-       id = (id & 63) | ((id & ~63) << 1);
-      write_id(data, id | 64);
-    }
-  id = sids[i];
-  if (id == marker)
-    id = 0;
-  else
-    id = id - old + 1;
-  if (id >= 64)
-    id = (id & 63) | ((id & ~63) << 1);
-  write_id(data, id);
-  if (sids != lids)
-    solv_free(sids);
-}
-#endif
-
-
 struct extdata {
   unsigned char *buf;
   int len;
@@ -482,8 +382,19 @@ data_addid64(struct extdata *xd, unsigned int x, unsigned int hx)
     data_addid(xd, (Id)x);
 }
 
+#define USE_REL_IDARRAY
+#ifdef USE_REL_IDARRAY
+
+static int
+cmp_ids(const void *pa, const void *pb, void *dp)
+{
+  Id a = *(Id *)pa;
+  Id b = *(Id *)pb;
+  return a - b;
+}
+
 static void
-data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
+data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
 {
   int len, i;
   Id lids[64], *sids;
@@ -568,6 +479,27 @@ data_addidarray_sort(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id
     solv_free(sids);
 }
 
+#else
+
+static void
+data_adddepids(struct extdata *xd, Pool *pool, NeedId *needid, Id *ids, Id marker)
+{
+  Id id;
+  if (!ids || !*ids)
+    {
+      data_addid(xd, 0);
+      return;
+    }
+  while ((id = *ids++) != 0)
+    {
+      if (needid)
+        id = needid[ISRELDEP(id) ? RELOFF(id) : id].need;
+      data_addideof(xd, id, *ids ? 0 : 1);
+    }
+}
+
+#endif
+
 static inline void
 data_addblob(struct extdata *xd, unsigned char *blob, int len)
 {
@@ -1169,7 +1101,11 @@ repo_write_filtered(Repo *repo, FILE *fp, int (*keyfilter)(Repo *repo, Repokey *
       if (i < SOLVABLE_PROVIDES)
         keyd.type = REPOKEY_TYPE_ID;
       else if (i < RPM_RPMDBID)
+#ifdef USE_REL_IDARRAY
         keyd.type = REPOKEY_TYPE_REL_IDARRAY;
+#else
+        keyd.type = REPOKEY_TYPE_IDARRAY;
+#endif
       else
         keyd.type = REPOKEY_TYPE_NUM;
       keyd.size = 0;
@@ -1807,21 +1743,21 @@ fprintf(stderr, "dir %d used %d\n", i, cbdata.dirused ? cbdata.dirused[i] : 1);
          if (s->vendor && cbdata.keymap[SOLVABLE_VENDOR])
            data_addid(xd, needid[s->vendor].need);
          if (s->provides && cbdata.keymap[SOLVABLE_PROVIDES])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
+           data_adddepids(xd, pool, needid, idarraydata + s->provides, SOLVABLE_FILEMARKER);
          if (s->obsoletes && cbdata.keymap[SOLVABLE_OBSOLETES])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->obsoletes, 0);
+           data_adddepids(xd, pool, needid, idarraydata + s->obsoletes, 0);
          if (s->conflicts && cbdata.keymap[SOLVABLE_CONFLICTS])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->conflicts, 0);
+           data_adddepids(xd, pool, needid, idarraydata + s->conflicts, 0);
          if (s->requires && cbdata.keymap[SOLVABLE_REQUIRES])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
+           data_adddepids(xd, pool, needid, idarraydata + s->requires, SOLVABLE_PREREQMARKER);
          if (s->recommends && cbdata.keymap[SOLVABLE_RECOMMENDS])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->recommends, 0);
+           data_adddepids(xd, pool, needid, idarraydata + s->recommends, 0);
          if (s->suggests && cbdata.keymap[SOLVABLE_SUGGESTS])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->suggests, 0);
+           data_adddepids(xd, pool, needid, idarraydata + s->suggests, 0);
          if (s->supplements && cbdata.keymap[SOLVABLE_SUPPLEMENTS])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->supplements, 0);
+           data_adddepids(xd, pool, needid, idarraydata + s->supplements, 0);
          if (s->enhances && cbdata.keymap[SOLVABLE_ENHANCES])
-           data_addidarray_sort(xd, pool, needid, idarraydata + s->enhances, 0);
+           data_adddepids(xd, pool, needid, idarraydata + s->enhances, 0);
          if (repo->rpmdbid && cbdata.keymap[RPM_RPMDBID])
            data_addid(xd, repo->rpmdbid[i - repo->start]);
          if (anyrepodataused)
index 06b2ea3..4ab5d18 100644 (file)
@@ -1016,7 +1016,11 @@ repodata_search(Repodata *data, Id solvid, Id keyname, int flags, int (*callback
       ddp = get_data(data, key, &dp, *keyp ? 1 : 0);
 
       if (key->type == REPOKEY_TYPE_DELETED)
-       continue;
+       {
+         if (onekey)
+           return;
+         continue;
+       }
       if (key->type == REPOKEY_TYPE_FLEXARRAY || key->type == REPOKEY_TYPE_FIXARRAY)
        {
          struct subschema_data subd;
@@ -2804,6 +2808,47 @@ repodata_add_flexarray(Repodata *data, Id solvid, Id keyname, Id ghandle)
 }
 
 void
+repodata_set_kv(Repodata *data, Id solvid, Id keyname, Id keytype, KeyValue *kv)
+{
+  switch (keytype)
+    {
+    case REPOKEY_TYPE_ID:
+      repodata_set_id(data, solvid, keyname, kv->id);
+      break;
+    case REPOKEY_TYPE_CONSTANTID:
+      repodata_set_constantid(data, solvid, keyname, kv->id);
+      break;
+    case REPOKEY_TYPE_IDARRAY:
+      repodata_add_idarray(data, solvid, keyname, kv->id);
+      break;
+    case REPOKEY_TYPE_STR:
+      repodata_set_str(data, solvid, keyname, kv->str);
+      break;
+    case REPOKEY_TYPE_VOID:
+      repodata_set_void(data, solvid, keyname);
+      break;
+    case REPOKEY_TYPE_NUM:
+      repodata_set_num(data, solvid, keyname, SOLV_KV_NUM64(kv));
+      break;
+    case REPOKEY_TYPE_CONSTANT:
+      repodata_set_constant(data, solvid, keyname, kv->num);
+      break;
+    case REPOKEY_TYPE_DIRNUMNUMARRAY:
+      if (kv->id)
+        repodata_add_dirnumnum(data, solvid, keyname, kv->id, kv->num, kv->num2);
+      break;
+    case REPOKEY_TYPE_DIRSTRARRAY:
+      repodata_add_dirstr(data, solvid, keyname, kv->id, kv->str);
+      break;
+    case_CHKSUM_TYPES:
+      repodata_set_bin_checksum(data, solvid, keyname, keytype, (const unsigned char *)kv->str);
+      break;
+    default:
+      break;
+    }
+}
+
+void
 repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname)
 {
   Id *pp, *ap, **app;
@@ -3512,7 +3557,6 @@ entrydone:
   data->incoredatalen = newincore.len;
   data->incoredatafree = 0;
 
-  solv_free(data->vincore);
   data->vincore = newvincore.buf;
   data->vincorelen = newvincore.len;
 
@@ -3639,44 +3683,19 @@ repodata_create_stubs(Repodata *data)
          xkeyname = 0;
          continue;
        }
-      switch (di.key->type)
+      repodata_set_kv(sdata, SOLVID_META, di.key->name, di.key->type, &di.kv);
+      if (di.key->name == REPOSITORY_KEYS && di.key->type == REPOKEY_TYPE_IDARRAY)
        {
-        case REPOKEY_TYPE_ID:
-         repodata_set_id(sdata, SOLVID_META, di.key->name, di.kv.id);
-         break;
-       case REPOKEY_TYPE_CONSTANTID:
-         repodata_set_constantid(sdata, SOLVID_META, di.key->name, di.kv.id);
-         break;
-       case REPOKEY_TYPE_STR:
-         repodata_set_str(sdata, SOLVID_META, di.key->name, di.kv.str);
-         break;
-       case REPOKEY_TYPE_VOID:
-         repodata_set_void(sdata, SOLVID_META, di.key->name);
-         break;
-       case REPOKEY_TYPE_NUM:
-         repodata_set_num(sdata, SOLVID_META, di.key->name, SOLV_KV_NUM64(&di.kv));
-         break;
-       case_CHKSUM_TYPES:
-         repodata_set_bin_checksum(sdata, SOLVID_META, di.key->name, di.key->type, (const unsigned char *)di.kv.str);
-         break;
-       case REPOKEY_TYPE_IDARRAY:
-         repodata_add_idarray(sdata, SOLVID_META, di.key->name, di.kv.id);
-         if (di.key->name == REPOSITORY_KEYS)
+         if (!xkeyname)
            {
-             if (!xkeyname)
-               {
-                 if (!di.kv.eof)
-                   xkeyname = di.kv.id;
-               }
-             else
-               {
-                 repodata_add_stubkey(sdata, xkeyname, di.kv.id);
-                 xkeyname = 0;
-               }
+             if (!di.kv.eof)
+               xkeyname = di.kv.id;
+           }
+         else
+           {
+             repodata_add_stubkey(sdata, xkeyname, di.kv.id);
+             xkeyname = 0;
            }
-         break;
-       default:
-         break;
        }
     }
   dataiterator_free(&di);
index d72c60f..7208e95 100644 (file)
@@ -258,7 +258,6 @@ void repodata_set_checksum(Repodata *data, Id solvid, Id keyname, Id type,
                           const char *str);
 void repodata_set_idarray(Repodata *data, Id solvid, Id keyname, Queue *q);
 
-
 /* directory (for package file list) */
 void repodata_add_dirnumnum(Repodata *data, Id solvid, Id keyname, Id dir, Id num, Id num2);
 void repodata_add_dirstr(Repodata *data, Id solvid, Id keyname, Id dir, const char *str);
@@ -271,6 +270,8 @@ void repodata_add_poolstr_array(Repodata *data, Id solvid, Id keyname, const cha
 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_unset(Repodata *data, Id solvid, Id keyname);
 void repodata_unset_uninternalized(Repodata *data, Id solvid, Id keyname);
 
index cf368e4..df32341 100644 (file)
@@ -1031,16 +1031,17 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
            }
        }
 
-      if (m && pool->implicitobsoleteusescolors && (s->arch > pool->lastarch || pool->id2arch[s->arch] != 1))
+      if (m && pool->implicitobsoleteusescolors && pool_arch2score(pool, s->arch) > 1)
        {
-         int a = pool->id2arch[s->arch];
+         unsigned int pa, a = pool_arch2score(pool, s->arch);
          /* check lock-step candidates */
          FOR_PROVIDES(p, pp, s->name)
            {
              Solvable *ps = pool->solvables + p;
              if (s->name != ps->name || s->evr != ps->evr || MAPTST(m, p))
                continue;
-             if (ps->arch > pool->lastarch || pool->id2arch[ps->arch] == 1 || pool->id2arch[ps->arch] >= a)
+             pa = pool_arch2score(pool, ps->arch);
+             if (!pa || pa == 1 || pa >= a)
                continue;
              queue_push(&workq, p);
            }
@@ -1058,7 +1059,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
              if (pool_is_complex_dep(pool, rec))
                {
                  pool_add_pos_literals_complex_dep(pool, rec, &workq, m, 0);
-                   continue;
+                 continue;
                }
 #endif
              FOR_PROVIDES(p, pp, rec)
@@ -1075,7 +1076,7 @@ solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
              if (pool_is_complex_dep(pool, sug))
                {
                  pool_add_pos_literals_complex_dep(pool, sug, &workq, m, 0);
-                   continue;
+                 continue;
                }
 #endif
              FOR_PROVIDES(p, pp, sug)
@@ -1531,7 +1532,8 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
   Pool *pool = solv->pool;
   Repo *installed = pool->installed;
   int first, i, j;
-  Id p, pp, a, aa, bestarch;
+  Id p, pp, aa;
+  unsigned int a, bestscore;
   Solvable *s, *ps, *bests;
   Queue badq, allowedarchs;
   Queue lsq;
@@ -1546,7 +1548,7 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
        continue;
       s = pool->solvables + i;
       first = i;
-      bestarch = 0;
+      bestscore = 0;
       bests = 0;
       queue_empty(&allowedarchs);
       FOR_PROVIDES(p, pp, s->name)
@@ -1558,8 +1560,7 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
            first = 0;
          if (first)
            break;
-         a = ps->arch;
-         a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
+         a = pool_arch2score(pool, ps->arch);
          if (a != 1 && installed && ps->repo == installed)
            {
              if (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
@@ -1567,9 +1568,9 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
              queue_pushunique(&allowedarchs, ps->arch);        /* also ok to keep this architecture */
              continue;         /* but ignore installed solvables when calculating the best arch */
            }
-         if (a && a != 1 && (!bestarch || a < bestarch))
+         if (a && a != 1 && (!bestscore || a < bestscore))
            {
-             bestarch = a;
+             bestscore = a;
              bests = ps;
            }
        }
@@ -1580,7 +1581,7 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
       if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch)
        allowedarchs.count--;   /* installed arch is best */
 
-      if (allowedarchs.count && pool->implicitobsoleteusescolors && installed && bestarch)
+      if (allowedarchs.count && pool->implicitobsoleteusescolors && installed && bestscore)
        {
          /* need an extra pass for lockstep checking: we only allow to keep an inferior arch
           * if the corresponding installed package is not lock-stepped */
@@ -1593,25 +1594,23 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
                continue;
              if (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
                continue;
-             a = ps->arch;
-             a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
+             a = pool_arch2score(pool, ps->arch);
              if (!a)
                {
                  queue_pushunique(&allowedarchs, ps->arch);    /* strange arch, allow */
                  continue;
                }
-             if (a == 1 || ((a ^ bestarch) & 0xffff0000) == 0)
+             if (a == 1 || ((a ^ bestscore) & 0xffff0000) == 0)
                continue;
              /* have installed package with inferior arch, check if lock-stepped */
              FOR_PROVIDES(p2, pp2, s->name)
                {
                  Solvable *s2 = pool->solvables + p2;
-                 Id a2;
+                 unsigned int a2;
                  if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch)
                    continue;
-                 a2 = s2->arch;
-                 a2 = (a2 <= pool->lastarch) ? pool->id2arch[a2] : 0;
-                 if (a2 && (a2 == 1 || ((a2 ^ bestarch) & 0xffff0000) == 0))
+                 a2 = pool_arch2score(pool, s2->arch);
+                 if (a2 && (a2 == 1 || ((a2 ^ bestscore) & 0xffff0000) == 0))
                    break;
                }
              if (!p2)
@@ -1626,9 +1625,8 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
          ps = pool->solvables + p;
          if (ps->name != s->name || !MAPTST(addedmap, p))
            continue;
-         a = ps->arch;
-         a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
-         if (a != 1 && bestarch && ((a ^ bestarch) & 0xffff0000) != 0)
+         a = pool_arch2score(pool, ps->arch);
+         if (a != 1 && bestscore && ((a ^ bestscore) & 0xffff0000) != 0)
            {
              if (installed && ps->repo == installed)
                {
@@ -1638,11 +1636,12 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
                }
              for (j = 0; j < allowedarchs.count; j++)
                {
+                 unsigned int aas;
                  aa = allowedarchs.elements[j];
                  if (ps->arch == aa)
                    break;
-                 aa = (aa <= pool->lastarch) ? pool->id2arch[aa] : 0;
-                 if (aa && ((a ^ aa) & 0xffff0000) == 0)
+                 aas = pool_arch2score(pool, aa);
+                 if (aas && ((a ^ aas) & 0xffff0000) == 0)
                    break;      /* compatible */
                }
              if (j == allowedarchs.count)
@@ -1654,7 +1653,7 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
       for (j = 0; j < badq.count; j++)
        {
          p = badq.elements[j];
-         /* lock-step */
+         /* special lock-step handling */
          if (pool->implicitobsoleteusescolors)
            {
              Id p2;
@@ -1665,9 +1664,8 @@ solver_addinfarchrules(Solver *solv, Map *addedmap)
                  Solvable *s2 = pool->solvables + p2;
                  if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch)
                    continue;
-                 a = s2->arch;
-                 a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
-                 if (a && (a == 1 || ((a ^ bestarch) & 0xffff000) == 0))
+                 a = pool_arch2score(pool, s2->arch);
+                 if (a && (a == 1 || ((a ^ bestscore) & 0xffff000) == 0))
                    {
                      queue_push(&lsq, p2);
                      if (installed && s2->repo == installed)
index 6ca72e5..d44c482 100644 (file)
@@ -32,7 +32,7 @@ str2archid(Pool *pool, const char *arch)
   id = pool_str2id(pool, arch, 0);
   if (!id || id == ARCH_SRC || id == ARCH_NOSRC || id == ARCH_NOARCH)
     return id;
-  if (pool->id2arch && (id > pool->lastarch || !pool->id2arch[id]))
+  if (pool->id2arch && pool_arch2score(pool, id) == 0)
     return 0;
   return id;
 }
@@ -1383,6 +1383,8 @@ setup_limiter(Pool *pool, int flags, struct limiter *limiter)
 static int
 matchdep_str(const char *pattern, const char *string, int flags)
 {
+  if (!pattern || !string)
+    return 0;
   if (flags & SELECTION_GLOB)
     {
       int globflags = (flags & SELECTION_NOCASE) != 0 ? FNM_CASEFOLD : 0;
@@ -1444,6 +1446,8 @@ selection_make_matchdeps_common_limited(Pool *pool, Queue *selection, const char
     return 0;
   if (!name && !dep)
     return 0;
+  if (name && dep)
+    return 0;
 
   if ((flags & SELECTION_MATCH_DEPSTR) != 0)
     flags &= ~SELECTION_REL;
index 7d107f9..4caba47 100644 (file)
@@ -43,6 +43,7 @@ extern int solv_version_patch;
 #cmakedefine LIBSOLVEXT_FEATURE_ZLIB_COMPRESSION
 #cmakedefine LIBSOLVEXT_FEATURE_LZMA_COMPRESSION
 #cmakedefine LIBSOLVEXT_FEATURE_BZIP2_COMPRESSION
+#cmakedefine LIBSOLVEXT_FEATURE_ZSTD_COMPRESSION
 
 /* see tools/common_write.c for toolversion history */
 #define LIBSOLV_TOOLVERSION "1.1"
index af43e01..5e87918 100644 (file)
@@ -76,11 +76,39 @@ stringpool_clone(Stringpool *ss, Stringpool *from)
   ss->sstrings = from->sstrings;
 }
 
+void
+stringpool_resize_hash(Stringpool *ss, int numnew)
+{
+  Hashval h, hh, hashmask;
+  Hashtable hashtbl;
+  int i;
+
+  if (numnew <= 0)
+    return;
+  hashmask = mkmask(ss->nstrings + numnew);
+  if (hashmask <= ss->stringhashmask)
+    return;    /* same as before */
+
+  /* realloc hash table */
+  ss->stringhashmask = hashmask;
+  solv_free(ss->stringhashtbl);
+  ss->stringhashtbl = hashtbl = (Hashtable)solv_calloc(hashmask + 1, sizeof(Id));
+  
+  /* rehash all strings into new hashtable */
+  for (i = 1; i < ss->nstrings; i++)
+    {
+      h = strhash(ss->stringspace + ss->strings[i]) & hashmask;
+      hh = HASHCHAIN_START;
+      while (hashtbl[h] != 0)
+       h = HASHCHAIN_NEXT(h, hh, hashmask);
+      hashtbl[h] = i;
+    }
+}
+
 Id
 stringpool_strn2id(Stringpool *ss, const char *str, unsigned int len, int create)
 {
   Hashval h, hh, hashmask, oldhashmask;
-  int i;
   Id id;
   Hashtable hashtbl;
 
@@ -90,27 +118,13 @@ stringpool_strn2id(Stringpool *ss, const char *str, unsigned int len, int create
     return STRID_EMPTY;
 
   hashmask = oldhashmask = ss->stringhashmask;
-  hashtbl = ss->stringhashtbl;
-
   /* expand hashtable if needed */
   if ((Hashval)ss->nstrings * 2 > hashmask)
     {
-      solv_free(hashtbl);
-
-      /* realloc hash table */
-      ss->stringhashmask = hashmask = mkmask(ss->nstrings + STRING_BLOCK);
-      ss->stringhashtbl = hashtbl = (Hashtable)solv_calloc(hashmask + 1, sizeof(Id));
-
-      /* rehash all strings into new hashtable */
-      for (i = 1; i < ss->nstrings; i++)
-       {
-         h = strhash(ss->stringspace + ss->strings[i]) & hashmask;
-         hh = HASHCHAIN_START;
-         while (hashtbl[h] != 0)
-           h = HASHCHAIN_NEXT(h, hh, hashmask);
-         hashtbl[h] = i;
-       }
+      stringpool_resize_hash(ss, STRING_BLOCK);
+      hashmask = ss->stringhashmask;
     }
+  hashtbl = ss->stringhashtbl;
 
   /* compute hash and check for match */
   h = strnhash(str, len) & hashmask;
index c97b873..f96c5c1 100644 (file)
@@ -33,6 +33,7 @@ void stringpool_init_empty(Stringpool *ss);
 void stringpool_clone(Stringpool *ss, Stringpool *from);
 void stringpool_free(Stringpool *ss);
 void stringpool_freehash(Stringpool *ss);
+void stringpool_resize_hash(Stringpool *ss, int numnew);
 
 Id stringpool_str2id(Stringpool *ss, const char *str, int create);
 Id stringpool_strn2id(Stringpool *ss, const char *str, unsigned int len, int create);
index 6b592f7..802dc50 100644 (file)
@@ -4,7 +4,7 @@
 
 ADD_LIBRARY (toolstuff STATIC common_write.c)
 
-SET (tools_list mergesolv dumpsolv installcheck testsolv)
+SET (tools_list mergesolv dumpsolv installcheck testsolv repo2solv)
 
 IF (ENABLE_RPMDB)
 ADD_EXECUTABLE (rpmdb2solv rpmdb2solv.c)
@@ -91,11 +91,6 @@ ENDIF (ENABLE_CUDFREPO)
 ADD_EXECUTABLE (installcheck installcheck.c)
 TARGET_LINK_LIBRARIES (installcheck libsolvext libsolv ${SYSTEM_LIBRARIES})
 
-IF (SUSE)
-ADD_EXECUTABLE (patchcheck patchcheck.c)
-TARGET_LINK_LIBRARIES (patchcheck libsolvext libsolv ${SYSTEM_LIBRARIES})
-ENDIF (SUSE)
-
 IF (ENABLE_APPDATA)
 ADD_EXECUTABLE (appdata2solv appdata2solv.c)
 TARGET_LINK_LIBRARIES (appdata2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
@@ -112,6 +107,8 @@ TARGET_LINK_LIBRARIES (mergesolv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES
 ADD_EXECUTABLE (testsolv testsolv.c)
 TARGET_LINK_LIBRARIES (testsolv libsolvext libsolv ${SYSTEM_LIBRARIES})
 
+ADD_EXECUTABLE (repo2solv repo2solv.c )
+TARGET_LINK_LIBRARIES (repo2solv toolstuff libsolvext libsolv ${SYSTEM_LIBRARIES})
+
 INSTALL (TARGETS ${tools_list} DESTINATION ${BIN_INSTALL_DIR})
 
-INSTALL (PROGRAMS repo2solv.sh DESTINATION ${BIN_INSTALL_DIR})
index e20f64f..577b1ab 100644 (file)
@@ -65,6 +65,8 @@ keyfilter_solv(Repo *data, Repokey *key, void *kfdata)
     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;
diff --git a/tools/patchcheck.c b/tools/patchcheck.c
deleted file mode 100644 (file)
index 4025f92..0000000
+++ /dev/null
@@ -1,641 +0,0 @@
-/* vim: sw=2 et
- */
-
-/*
- * Copyright (c) 2009, Novell Inc.
- *
- * This program is licensed under the BSD license, read LICENSE.BSD
- * for further information
- */
-
-#define _GNU_SOURCE
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "pool.h"
-#include "evr.h"
-#include "poolarch.h"
-#include "repo_solv.h"
-#ifdef ENABLE_SUSEREPO
-#include "repo_susetags.h"
-#endif
-#ifdef ENABLE_RPMMD
-#include "repo_updateinfoxml.h"
-#include "repo_rpmmd.h"
-#endif
-#include "solver.h"
-#include "solverdebug.h"
-
-#include "solv_xfopen.h"
-
-void
-showproblems(Solver *solv, Solvable *s, Queue *cand, Queue *badguys)
-{
-  Pool *pool = solv->pool;
-  Queue rids, rinfo;
-  Id problem = 0;
-  int jj;
-  int rerun = 0;
-
-  queue_init(&rids);
-  queue_init(&rinfo);
-  printf("can't install %s:\n", pool_solvable2str(pool, s));
-  while ((problem = solver_next_problem(solv, problem)) != 0)
-    {
-      solver_findallproblemrules(solv, problem, &rids);
-      for (jj = 0; jj < rids.count; jj++)
-       {
-         Id probr = rids.elements[jj];
-         int k, l;
-
-         queue_empty(&rinfo);
-         solver_allruleinfos(solv, probr, &rinfo);
-         for (k = 0; k < rinfo.count; k += 4)
-           {
-             Id dep, source, target;
-             source = rinfo.elements[k + 1];
-             target = rinfo.elements[k + 2];
-             dep = rinfo.elements[k + 3];
-             switch (rinfo.elements[k])
-               {
-               case SOLVER_RULE_DISTUPGRADE:
-                 break;
-               case SOLVER_RULE_INFARCH:
-                 printf("  %s has inferior architecture\n", pool_solvid2str(pool, source));
-                 break;
-               case SOLVER_RULE_UPDATE:
-                 printf("  update rule for %s\n", pool_solvid2str(pool, source));
-                 if (badguys)
-                   queue_pushunique(badguys, source);
-                 if (!cand)
-                   break;
-                 /* only drop update problem packages from cand so that we see all problems of this patch */
-                 for (l = 0; l < cand->count; l++)
-                   if (cand->elements[l] == source || cand->elements[l] == -source)
-                     break;
-                 if (l == cand->count)
-                   break;
-                 if (!rerun)
-                   {
-                     for (l = 0; l < cand->count; l++)
-                       if (cand->elements[l] < 0)
-                         cand->elements[l] = -cand->elements[l];
-                     rerun = 1;
-                   }
-                 for (l = 0; l < cand->count; l++)
-                   if (cand->elements[l] == source)
-                     {
-                       cand->elements[l] = -source;
-                     }
-                 break;
-               case SOLVER_RULE_JOB:
-               case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
-               case SOLVER_RULE_JOB_UNKNOWN_PACKAGE:
-               case SOLVER_RULE_JOB_UNSUPPORTED:
-                 break;
-               case SOLVER_RULE_RPM:
-                 printf("  some dependency problem\n");
-                 break;
-               case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
-                 printf("  nothing provides requested %s\n", pool_dep2str(pool, dep));
-                 break;
-               case SOLVER_RULE_RPM_NOT_INSTALLABLE:
-                 printf("  package %s is not installable\n", pool_solvid2str(pool, source));
-                 break;
-               case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP:
-                 printf("  nothing provides %s needed by %s\n", pool_dep2str(pool, dep), pool_solvid2str(pool, source));
-                 if (ISRELDEP(dep))
-                   {
-                     Reldep *rd = GETRELDEP(pool, dep);
-                     if (!ISRELDEP(rd->name))
-                       {
-                         Id rp, rpp;
-                         FOR_PROVIDES(rp, rpp, rd->name)
-                           printf("    (we have %s)\n", pool_solvid2str(pool, rp));
-                       }
-                   }
-                 break;
-               case SOLVER_RULE_RPM_SAME_NAME:
-                 printf("  cannot install both %s and %s\n", pool_solvid2str(pool, source), pool_solvid2str(pool, target));
-                 break;
-               case SOLVER_RULE_RPM_PACKAGE_CONFLICT:
-                 printf("  package %s conflicts with %s provided by %s\n", pool_solvid2str(pool, source), pool_dep2str(pool, dep), pool_solvid2str(pool, target));
-                 break;
-               case SOLVER_RULE_RPM_PACKAGE_OBSOLETES:
-                 printf("  package %s obsoletes %s provided by %s\n", pool_solvid2str(pool, source), pool_dep2str(pool, dep), pool_solvid2str(pool, target));
-                 break;
-               case SOLVER_RULE_RPM_PACKAGE_REQUIRES:
-                 printf("  package %s requires %s, but none of the providers can be installed\n", pool_solvid2str(pool, source), pool_dep2str(pool, dep));
-                 break;
-               case SOLVER_RULE_RPM_SELF_CONFLICT:
-                 printf("  package %s conflicts with %s provided by itself\n", pool_solvid2str(pool, source), pool_dep2str(pool, dep));
-                 break;
-               }
-           }
-       }
-    }
-  queue_free(&rids);
-  queue_free(&rinfo);
-}
-
-void
-toinst(Solver *solv, Repo *repo, Repo *instrepo)
-{
-  Pool *pool = solv->pool;
-  Queue q;
-  int k;
-  Id p;
-
-  queue_init(&q);
-  solver_get_decisionqueue(solv, &q);
-  for (k = 0; k < q.count; k++)
-    {
-      p = q.elements[k];
-      if (p < 0 || p == SYSTEMSOLVABLE)
-       continue;
-
-     /* printf(" toinstall %s\n", pool_solvid2str(pool, p));*/
-      /* oh my! */
-      pool->solvables[p].repo = instrepo;
-    }
-  queue_free(&q);
-}
-
-void
-dump_instrepo(Repo *instrepo, Pool *pool)
-{
-  Solvable *s;
-  Id p;
-
-  printf("instrepo..\n");
-  FOR_REPO_SOLVABLES(instrepo, p, s)
-    printf("  %s\n", pool_solvable2str(pool, s));
-  printf("done.\n");
-}
-
-void
-frominst(Solver *solv, Repo *repo, Repo *instrepo)
-{
-  Pool *pool = solv->pool;
-  int k;
-
-  for (k = 1; k < pool->nsolvables; k++)
-    if (pool->solvables[k].repo == instrepo)
-      pool->solvables[k].repo = repo;
-}
-
-void
-usage(char** argv)
-{
-
-  printf("%s: <arch> <patchnameprefix>  [--install-available] [repos] [--updaterepos] [repos]...\n"
-      "\t --install-available: installation repository is available during update\n"
-      "\t repos: repository ending in\n"
-      "\t\tpackages, packages.gz, primary.xml.gz, updateinfo.xml.gz or .solv\n",
-      argv[0]);
-
-  exit(1);
-}
-
-typedef struct {
-  int updatestart;
-  int shown;
-  int status;
-  int install_available;
-  Repo *repo;
-  Repo *instrepo;
-} context_t;
-
-#define SHOW_PATCH(c) if (!(c)->shown++) printf("%s:\n", pool_solvable2str(pool, s));
-#define PERF_DEBUGGING 0
-static Pool *pool;
-
-void
-test_all_old_patches_included(context_t *c, Id pid)
-{
-  Id p, pp;
-  Id con, *conp;
-  Solvable *s = pool->solvables + pid;
-  /* Test 1: are all old patches included */
-  FOR_PROVIDES(p, pp, s->name)
-    {
-      Solvable *s2 = pool->solvables + p;
-      Id con2, *conp2;
-
-      if (!s2->conflicts)
-        continue;
-      if (pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) <= 0)
-        continue;
-      conp2 = s2->repo->idarraydata + s2->conflicts;
-      while ((con2 = *conp2++) != 0)
-        {
-          Reldep *rd2, *rd;
-          if (!ISRELDEP(con2))
-            continue;
-          rd2 = GETRELDEP(pool, con2);
-          conp = s->repo->idarraydata + s->conflicts;
-          while ((con = *conp++) != 0)
-            {
-              if (!ISRELDEP(con))
-                continue;
-              rd = GETRELDEP(pool, con);
-              if (rd->name == rd2->name)
-                break;
-            }
-          if (!con)
-            {
-              SHOW_PATCH(c);
-              printf("  %s contained %s\n", pool_solvable2str(pool, s2), pool_dep2str(pool, rd2->name));
-            }
-          else
-           {
-             if (pool_evrcmp(pool, rd->evr, rd2->evr, EVRCMP_COMPARE) < 0)
-               {
-                 SHOW_PATCH(c);
-                 printf("  %s required newer version %s-%s of %s-%s\n",
-                     pool_solvable2str(pool, s2), pool_dep2str(pool, rd2->name), pool_dep2str(pool, rd2->evr),
-                     pool_dep2str(pool, rd->name), pool_dep2str(pool, rd->evr));
-               }
-           }
-
-        }
-    }
-}
-
-void
-test_all_packages_installable(context_t *c, Id pid)
-{
-  Solver *solv;
-  Queue job;
-  Id p, pp;
-  Id con, *conp;
-  unsigned int now, solver_runs;
-  int i;
-  Solvable *s = pool->solvables + pid;
-
-  queue_init(&job);
-
-  now = solv_timems(0);
-  solver_runs = 0;
-
-  conp = s->repo->idarraydata + s->conflicts;
-  while ((con = *conp++) != 0)
-    {
-      FOR_PROVIDES(p, pp, con)
-        {
-          queue_empty(&job);
-          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
-          queue_push(&job, p);
-
-          /* also set up some minimal system */
-          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
-          queue_push(&job, pool_str2id(pool, "rpm", 1));
-          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
-          queue_push(&job, pool_str2id(pool, "aaa_base", 1));
-
-          solv = solver_create(pool);
-          /* solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); */
-          ++solver_runs;
-          if (solver_solve(solv, &job))
-            {
-              c->status = 1;
-              printf("error installing original package\n");
-              showproblems(solv, s, 0, 0);
-            }
-          toinst(solv, c->repo, c->instrepo);
-          solver_free(solv);
-
-#if 0
-          dump_instrepo(instrepo, pool);
-
-#endif
-          if (!c->install_available)
-            {
-              queue_empty(&job);
-              for (i = 1; i < c->updatestart; i++)
-                {
-                  if (pool->solvables[i].repo != c->repo || i == pid)
-                    continue;
-                  queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
-                  queue_push(&job, i);
-                }
-            }
-          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE);
-          queue_push(&job, pid);
-          solv = solver_create(pool);
-          /* solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1); */
-          ++solver_runs;
-          if (solver_solve(solv, &job))
-            {
-              c->status = 1;
-              showproblems(solv, s, 0, 0);
-            }
-          frominst(solv, c->repo, c->instrepo);
-          solver_free(solv);
-        }
-    }
-
-  if (PERF_DEBUGGING)
-    printf("  test_all_packages_installable took %d ms in %d runs\n", solv_timems(now), solver_runs);
-}
-
-void
-test_can_upgrade_all_packages(context_t *c, Id pid)
-{
-  Solver *solv;
-  Id p;
-  Id con, *conp;
-  Queue job;
-  Queue cand;
-  Queue badguys;
-  int i, j;
-  unsigned int now, solver_runs;
-  Solvable *s = pool->solvables + pid;
-
-  queue_init(&job);
-  queue_init(&cand);
-  queue_init(&badguys);
-
-  now = solv_timems(0);
-  solver_runs = 0;
-
-  /* Test 3: can we upgrade all packages? */
-  for (p = 1; p < pool->nsolvables; p++)
-    {
-      Solvable *s = pool->solvables + p;
-      if (!s->repo)
-        continue;
-      if (strchr(pool_id2str(pool, s->name), ':'))
-        continue;      /* only packages, please */
-      if (!pool_installable(pool, s))
-        continue;
-      queue_push(&cand, p);
-    }
-  while (cand.count)
-    {
-      solv = solver_create(pool);
-      queue_empty(&job);
-      for (i = 0; i < badguys.count; i++)
-        {
-          queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE|SOLVER_WEAK);
-          queue_push(&job, badguys.elements[i]);
-        }
-      conp = s->repo->idarraydata + s->conflicts;
-      while ((con = *conp++) != 0)
-        {
-          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES|SOLVER_WEAK);
-          queue_push(&job, con);
-        }
-      for (i = 0; i < cand.count; i++)
-        {
-          p = cand.elements[i];
-          queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_WEAK);
-          queue_push(&job, p);
-        }
-      ++solver_runs;
-      solver_solve(solv, &job);
-#if 0
-      solver_printdecisions(solv);
-#endif
-      /* put packages into installed repo and prune them from cand */
-      toinst(solv, c->repo, c->instrepo);
-      for (i = 0; i < cand.count; i++)
-        {
-          p = cand.elements[i];
-          if (p > 0 && solver_get_decisionlevel(solv, p) > 0)
-            cand.elements[i] = -p;     /* drop candidate */
-        }
-      solver_free(solv);
-
-      /* now the interesting part: test patch */
-      queue_empty(&job);
-      if (!c->install_available)
-        {
-          for (i = 1; i < c->updatestart; i++)
-            {
-              if (pool->solvables[i].repo != c->repo || i == pid)
-                continue;
-              queue_push(&job, SOLVER_ERASE|SOLVER_SOLVABLE);
-              queue_push(&job, i);
-            }
-        }
-      queue_push(&job, SOLVER_INSTALL|SOLVER_SOLVABLE);
-      queue_push(&job, pid);
-      solv = solver_create(pool);
-      solver_set_flag(solv, SOLVER_FLAG_IGNORE_RECOMMENDED, 1);
-      ++solver_runs;
-      if (solver_solve(solv, &job))
-        {
-          c->status = 1;
-          showproblems(solv, s, &cand, &badguys);
-        }
-      frominst(solv, c->repo, c->instrepo);
-      solver_free(solv);
-      /* now drop all negative elements from cand */
-      for (i = j = 0; i < cand.count; i++)
-        {
-          if (cand.elements[i] < 0)
-            continue;
-          cand.elements[j++] = cand.elements[i];
-        }
-      if (i == j)
-        break; /* no progress */
-      cand.count = j;
-    }
-  if (PERF_DEBUGGING)
-    printf("  test_can_upgrade_all_packages took %d ms in %d runs\n", solv_timems(now), solver_runs);
-}
-
-void
-test_no_ga_package_fulfills_dependency(context_t *c, Id pid)
-{
-  Id con, *conp;
-  Solvable *s = pool->solvables + pid;
-
-  /* Test 4: no GA package fulfills patch dependency */
-  conp = s->repo->idarraydata + s->conflicts;
-  while ((con = *conp++) != 0)
-    {
-      Reldep *rd;
-      Id rp, rpp;
-
-      if (!ISRELDEP(con))
-        continue;
-      rd = GETRELDEP(pool, con);
-      FOR_PROVIDES(rp, rpp, rd->name)
-        {
-          Solvable *s2 = pool_id2solvable(pool, rp);
-          if (rp < c->updatestart
-              && pool_evrcmp(pool, rd->evr, s2->evr, EVRCMP_COMPARE) < 0
-              && pool_match_nevr_rel(pool, s2, rd->name)
-             )
-            {
-              SHOW_PATCH(c);
-              printf("  conflict %s < %s satisfied by non-updated package %s\n",
-                  pool_dep2str(pool, rd->name), pool_dep2str(pool, rd->evr), pool_solvable2str(pool, s2));
-              break;
-            }
-        }
-    }
-}
-
-int
-main(int argc, char **argv)
-{
-  char *arch, *mypatch;
-  const char *pname;
-  int l, r;
-  FILE *fp;
-  int i;
-  Id pid, p, pp;
-  int tests = 0;
-  context_t c;
-  static const char* langs[] = {"en"};
-
-  c.install_available = 0;
-  c.updatestart = 0;
-  c.status = 0;
-
-  if (argc <= 3)
-    usage(argv);
-
-  arch = argv[1];
-  pool = pool_create();
-  pool_setarch(pool, arch);
-  pool_set_languages(pool, langs, 1);
-
-#if 0
-  pool_setdebuglevel(pool, 2);
-#endif
-
-  mypatch = argv[2];
-
-  c.repo = repo_create(pool, 0);
-  c.instrepo = repo_create(pool, 0);
-  for (i = 3; i < argc; i++)
-    {
-      if (!strcmp(argv[i], "--updaterepos"))
-       {
-         c.updatestart = pool->nsolvables;
-         continue;
-       }
-
-      if (!strcmp(argv[i], "--install-available"))
-       {
-         c.install_available = 1;
-         continue;
-       }
-      l = strlen(argv[i]);
-      if (!strcmp(argv[i], "-"))
-        fp = stdin;
-      else if ((fp = solv_xfopen(argv[i], 0)) == 0)
-        {
-          perror(argv[i]);
-          exit(1);
-        }
-      r = 0;
-      if (0)
-       {
-       }
-#ifdef ENABLE_SUSEREPO
-      else if (l >= 8 && !strcmp(argv[i] + l - 8, "packages"))
-        {
-          r = repo_add_susetags(c.repo, fp, 0, 0, 0);
-        }
-      else if (l >= 11 && !strcmp(argv[i] + l - 11, "packages.gz"))
-        {
-          r = repo_add_susetags(c.repo, fp, 0, 0, 0);
-        }
-#endif
-#ifdef ENABLE_RPMMD
-      else if (l >= 14 && !strcmp(argv[i] + l - 14, "primary.xml.gz"))
-        {
-          r = repo_add_rpmmd(c.repo, fp, 0, 0);
-        }
-      else if (l >= 17 && !strcmp(argv[i] + l - 17, "updateinfo.xml.gz"))
-       {
-          r = repo_add_updateinfoxml(c.repo, fp, 0);
-       }
-#endif
-      else
-       r = repo_add_solv(c.repo, fp, 0);
-      if (r)
-        {
-          fprintf(stderr, "could not add repo %s: %s\n", argv[i], pool_errstr(pool));
-          exit(1);
-        }
-      if (fp != stdin)
-        fclose(fp);
-    }
-
-  pool_addfileprovides(pool);
-
-  /* bad hack ahead: clone repo */
-  c.instrepo->idarraydata = c.repo->idarraydata;
-  c.instrepo->idarraysize = c.repo->idarraysize;
-  c.instrepo->start = c.repo->start;
-  c.instrepo->end = c.repo->end;
-  c.instrepo->nsolvables = c.repo->nsolvables; /* sic! */
-  pool_set_installed(pool, c.instrepo);
-  pool_createwhatprovides(pool);
-
-  for (pid = 1; pid < pool->nsolvables; pid++)
-    {
-      Solvable *s;
-      c.shown = 0;
-      s = pool->solvables + pid;
-      if (!s->repo)
-        continue;
-      if (!pool_installable(pool, s))
-        continue;
-      pname = pool_id2str(pool, s->name);
-      if (strncmp(pname, "patch:", 6) != 0)
-       continue;
-
-      if (*mypatch)
-       {
-         if (strncmp(mypatch, pname + 6, strlen(pname + 6)) != 0)
-           continue;
-         if (strcmp(mypatch, pname + 6) != 0)
-           {
-             l = strlen(pname + 6);
-             if (mypatch[l] != '-')
-               continue;
-             if (strcmp(mypatch + l + 1, pool_id2str(pool, s->evr)) != 0)
-               continue;
-           }
-       }
-      else
-       {
-         FOR_PROVIDES(p, pp, s->name)
-           {
-             Solvable *s2 = pool->solvables + p;
-             if (pool_evrcmp(pool, s->evr, s2->evr, EVRCMP_COMPARE) < 0)
-               break;
-           }
-         if (p) {
-            /* printf("found a newer one for %s\n", pname+6); */
-           continue;   /* found a newer one */
-          }
-       }
-      tests++;
-      if (!s->conflicts)
-       continue;
-
-#if 0
-      printf("testing patch %s-%s\n", pname + 6, pool_id2str(pool, s->evr));
-#endif
-
-      test_all_old_patches_included(&c, pid);
-      test_all_packages_installable(&c, pid);
-      test_can_upgrade_all_packages(&c, pid);
-      test_no_ga_package_fulfills_dependency(&c, pid);
-    }
-
-  exit(c.status);
-}
diff --git a/tools/repo2solv.c b/tools/repo2solv.c
new file mode 100644 (file)
index 0000000..e055e40
--- /dev/null
@@ -0,0 +1,839 @@
+/*
+ * Copyright (c) 2018, SUSE LLC.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <errno.h>
+
+#include "pool.h"
+#include "repo.h"
+
+#ifdef ENABLE_RPMPKG
+#include "repo_rpmdb.h"
+#endif
+
+#ifdef ENABLE_RPMMD
+#include "repo_repomdxml.h"
+#include "repo_rpmmd.h"
+#include "repo_updateinfoxml.h"
+#include "repo_deltainfoxml.h"
+#endif
+
+#ifdef ENABLE_SUSEREPO
+#include "repo_content.h"
+#include "repo_susetags.h"
+#endif
+
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
+#ifdef ENABLE_APPDATA
+#include "repo_appdata.h"
+#endif
+#include "common_write.h"
+#include "solv_xfopen.h"
+
+
+#ifdef SUSE
+int add_auto = 0;
+#endif
+#ifdef ENABLE_APPDATA
+int add_appdata = 0;
+#endif
+int recursive = 0;
+int add_filelist = 0;
+int add_changelog = 0;
+int filtered_filelist = 0;
+
+
+#define REPO_PLAINDIR          1
+#define REPO_RPMMD             2
+#define REPO_RPMMD_REPODATA    3
+#define REPO_SUSETAGS          4
+
+int
+autodetect_repotype(Pool *pool, const char *dir)
+{
+  struct stat stb;
+  char *tmp;
+  FILE *fp;
+
+  tmp = pool_tmpjoin(pool, dir, "/repomd.xml", 0);
+  if (stat(tmp, &stb) == 0)
+    return REPO_RPMMD;
+  tmp = pool_tmpjoin(pool, dir, "/repodata/repomd.xml", 0);
+  if (stat(tmp, &stb) == 0)
+    return REPO_RPMMD_REPODATA;
+  tmp = pool_tmpjoin(pool, dir, "/content", 0);
+  if ((fp = fopen(tmp, "r")) != 0)
+    {
+      char buf[512], *descrdir = 0;
+      while (fgets(buf, sizeof(buf), fp))
+       {
+         int l = strlen(buf);
+         char *bp = buf;
+         if (buf[l - 1] != '\n')
+           {
+             int c;
+             while ((c = getc(fp)) != EOF && c != '\n')
+               ;
+             continue;
+           }
+         while (l && (buf[l - 1] == '\n' || buf[l - 1] == ' ' || buf[l - 1] == '\t'))
+           l--;
+         buf[l] = 0;
+         while (*bp == ' ' || *bp == '\t')
+           bp++;
+         if (strncmp(bp, "DESCRDIR", 8) != 0 || (bp[8] != ' ' && bp[8] != '\t'))
+           continue;
+         bp += 9;
+         while (*bp == ' ' || *bp == '\t')
+           bp++;
+         descrdir = bp;
+         break;
+       }
+      fclose(fp);
+      if (descrdir)
+       {
+         tmp = pool_tmpjoin(pool, dir, "/", descrdir);
+         if (stat(tmp, &stb) == 0 && S_ISDIR(stb.st_mode))
+           return REPO_SUSETAGS;
+       }
+    }
+  tmp = pool_tmpjoin(pool, dir, "/suse/setup/descr", 0);
+  if (stat(tmp, &stb) == 0 && S_ISDIR(stb.st_mode))
+    return REPO_SUSETAGS;
+  return REPO_PLAINDIR;
+}
+
+
+#ifdef ENABLE_RPMPKG
+
+int
+read_plaindir_repo(Repo *repo, const char *dir)
+{
+  Pool *pool = repo->pool;
+  Repodata *data;
+  int c;
+  FILE *fp;
+  int wstatus;
+  int fds[2];
+  pid_t pid;
+  char *buf = 0;
+  char *buf_end = 0;
+  char *bp = 0;
+  char *rpm;
+  int res = 0;
+  Id p;
+
+  /* run find command */
+  if (pipe(fds))
+    {
+      perror("pipe");
+      exit(1);
+    }
+  while ((pid = fork()) == (pid_t)-1)
+    {
+      if (errno != EAGAIN)
+       {
+         perror("fork");
+         exit(1);
+       }
+      sleep(3);
+    }
+  if (pid == 0)
+    {
+      if (chdir(dir))
+       {
+         perror(dir);
+         _exit(1);
+       }
+      close(fds[0]);
+      if (fds[1] != 1)
+       {
+         if (dup2(fds[1], 1) == -1)
+           {
+             perror("dup2");
+             _exit(1);
+           }
+         close(fds[1]);
+       }
+      if (recursive)
+       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", ".", "-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);
+    }
+  close(fds[1]);
+  if ((fp = fdopen(fds[0], "r")) == 0)
+    {
+      perror("fdopen");
+      exit(1);
+    }
+  data = repo_add_repodata(repo, 0);
+  bp = buf;
+  while ((c = getc(fp)) != EOF)
+    {
+      if (bp == buf_end)
+       {
+         size_t len = bp - buf;
+         buf = solv_realloc(buf, len + 4096);
+         bp = buf + len;
+         buf_end = bp + 4096;
+       }
+      *bp++ = c;
+      if (c)
+       continue;
+      bp = buf;
+      rpm = solv_dupjoin(dir, "/", bp[0] == '.' && bp[1] == '/' ? bp + 2 : bp);
+      if ((p = repo_add_rpm(repo, rpm, REPO_REUSE_REPODATA|REPO_NO_INTERNALIZE|REPO_NO_LOCATION|(filtered_filelist ? RPM_ADD_FILTERED_FILELIST : 0))) == 0)
+       {
+         fprintf(stderr, "%s: %s\n", rpm, pool_errstr(pool));
+#if 0
+         res = 1;
+#endif
+       }
+      else
+       repodata_set_location(data, p, 0, 0, bp[0] == '.' && bp[1] == '/' ? bp + 2 : bp);
+      solv_free(rpm);
+    }
+  fclose(fp);
+  while (waitpid(pid, &wstatus, 0) == -1)
+    {
+      if (errno == EINTR)
+       continue;
+      perror("waitpid");
+      exit(1);
+    }
+  if (wstatus)
+    {
+      fprintf(stderr, "find: exit status %d\n", (wstatus >> 8) | (wstatus & 255) << 8);
+#if 0
+      res = 1;
+#endif
+    }
+  repo_internalize(repo);
+  return res;
+}
+
+#else
+
+int
+read_plaindir_repo(Repo *repo, const char *dir)
+{
+  fprintf(stderr, "plaindir repo type is not supported\n");
+  exit(1);
+}
+
+#endif
+
+#ifdef ENABLE_SUSEREPO
+
+static const char *
+susetags_find(char **files, int nfiles, const char *what)
+{
+  int i;
+  size_t l = strlen(what);
+  for (i = 0; i < nfiles; i++)
+    {
+      char *fn = files[i];
+      if (strncmp(fn, what, l) != 0)
+       continue;
+      if (fn[l] == 0)
+       return fn;
+      if (fn[l] != '.')
+       continue;
+      if (strchr(fn + l + 1, '.') != 0)
+       continue;
+      if (solv_xfopen_iscompressed(fn) <= 0)
+       continue;
+      return fn;
+    }
+  return 0;
+}
+
+static FILE *
+susetags_open(const char *dir, const char *filename, char **tmpp, int missingok)
+{
+  FILE *fp;
+  if (!filename)
+    {
+      *tmpp = 0;
+      return 0;
+    }
+  *tmpp = solv_dupjoin(dir, "/", filename);
+  if ((fp = solv_xfopen(*tmpp, "r")) == 0)
+    {
+      if (!missingok)
+       {
+         perror(*tmpp);
+         exit(1);
+       }
+      *tmpp = solv_free(*tmpp);
+      return 0;
+    }
+  return fp;
+}
+
+static void
+susetags_extend(Repo *repo, const char *dir, char **files, int nfiles, char *what, Id defvendor, char *language, int missingok)
+{
+  const char *filename;
+  FILE *fp;
+  char *tmp;
+
+  filename = susetags_find(files, nfiles, what);
+  if (!filename)
+    return;
+  if ((fp = susetags_open(dir, filename, &tmp, missingok)) != 0)
+    {
+      if (repo_add_susetags(repo, fp, defvendor, language, REPO_EXTEND_SOLVABLES))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool));
+         exit(1);
+       }
+      fclose(fp);
+      solv_free(tmp);
+    }
+}
+
+static void
+susetags_extend_languages(Repo *repo, const char *dir, char **files, int nfiles, Id defvendor, int missingok)
+{
+  int i;
+  for (i = 0; i < nfiles; i++)
+    {
+      char *fn = files[i];
+      char lang[64], *p;
+      if (strncmp(fn, "packages.", 9) != 0)
+       continue;
+      if (strlen(fn + 9) + 1 >= sizeof(lang))
+       continue;
+      strncpy(lang, fn + 9, sizeof(lang) - 1);
+      lang[sizeof(lang) - 1] = 0;
+      p = strrchr(lang, '.');
+      if (p)
+       {
+          if (solv_xfopen_iscompressed(lang) <= 0)
+           continue;
+         *p = 0;
+       }
+      if (strchr(lang, '.'))
+       continue;
+      if (!strcmp(lang, "en"))
+       continue;       /* already did that one */
+      if (!strcmp(lang, "DU"))
+       continue;       /* disk usage */
+      if (!strcmp(lang, "FL"))
+       continue;       /* file list */
+      if (!strcmp(lang, "DL"))
+       continue;       /* deltas */
+      susetags_extend(repo, dir, files, nfiles, fn, defvendor, lang, missingok);
+    }
+}
+
+static int
+susetags_dircmp(const void *ap, const void *bp, void *dp)
+{
+  return strcmp(*(const char **)ap, *(const char **)bp);
+}
+
+int
+read_susetags_repo(Repo *repo, const char *dir)
+{
+  Pool *pool = repo->pool;
+  const char *filename;
+  char *ddir;
+  char *tmp;
+  FILE *fp;
+  Id defvendor = 0;
+  const char *descrdir = 0;
+  char **files = 0;
+  int nfiles = 0;
+  DIR *dp;
+  struct dirent *de;
+
+  /* read content file */
+  repo_add_repodata(repo, 0);
+  tmp = solv_dupjoin(dir, "/content", 0);
+  if ((fp = fopen(tmp, "r")) != 0)
+    {
+      if (repo_add_content(repo, fp, REPO_REUSE_REPODATA))
+        {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+        }
+      fclose(fp);
+      descrdir = repo_lookup_str(repo, SOLVID_META, SUSETAGS_DESCRDIR);
+      defvendor = repo_lookup_id(repo, SOLVID_META, SUSETAGS_DEFAULTVENDOR);
+    }
+  if (!descrdir)
+    descrdir = "suse/setup/descr";
+  tmp = solv_free(tmp);
+
+  /* get content of descrdir directory */
+  ddir = solv_dupjoin(dir, "/", descrdir);
+  if ((dp = opendir(ddir)) == 0)
+    {
+      perror(ddir);
+      exit(1);
+    }
+  while ((de = readdir(dp)) != 0)
+    {
+      if (de->d_name[0] == 0 || de->d_name[0] == '.')
+       continue;
+      files = solv_extend(files, nfiles, 1, sizeof(char *), 63);
+      files[nfiles++] = solv_strdup(de->d_name);
+    }
+  closedir(dp);
+  if (nfiles > 1)
+    solv_sort(files, nfiles, sizeof(char *), susetags_dircmp, 0);
+  
+  /* add packages */
+  filename = susetags_find(files, nfiles, "packages");
+  if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0)
+    {
+      if (repo_add_susetags(repo, fp, defvendor, 0, REPO_NO_INTERNALIZE|SUSETAGS_RECORD_SHARES))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+
+      /* now extend the packages */
+      susetags_extend(repo, ddir, files, nfiles, "packages.DU", defvendor, 0, 1);
+      susetags_extend(repo, ddir, files, nfiles, "packages.en", defvendor, 0, 1);
+      susetags_extend_languages(repo, ddir, files, nfiles, defvendor, 1);
+      if (add_filelist)
+        susetags_extend(repo, ddir, files, nfiles, "packages.FL", defvendor, 0, 1);
+    }
+
+  /* add deltas */
+  filename = susetags_find(files, nfiles, "packages.DL");
+  if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0)
+    {
+      if (repo_add_susetags(repo, fp, defvendor, 0, 0))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+    }
+
+  /* add legacy patterns */
+  tmp = solv_dupjoin(ddir, "/patterns", 0);
+  if ((fp = fopen(tmp, "r")) != 0)
+    {
+      char pbuf[4096];
+
+      repo_add_repodata(repo, 0);
+      while (fgets(pbuf, sizeof(pbuf), fp))
+       {
+         char *p;
+         FILE *pfp;
+         if (strchr(pbuf, '/') != 0)
+           continue;
+         if ((p = strchr(pbuf, '\n')) != 0)
+           *p = 0;
+         if (*pbuf == 0)
+           continue;
+         solv_free(tmp);
+         tmp = solv_dupjoin(ddir, "/", pbuf);
+         if ((pfp = solv_xfopen(tmp, "r")) != 0)
+           {
+             if (repo_add_susetags(repo, pfp, defvendor, 0, REPO_NO_INTERNALIZE|REPO_REUSE_REPODATA))
+               {
+                 fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+                 exit(1);
+               }
+             fclose(pfp);
+           }
+       }
+      fclose(fp);
+    }
+  tmp = solv_free(tmp);
+#ifdef ENABLE_APPDATA
+  /* appdata */
+  filename = add_appdata ? susetags_find(files, nfiles, "appdata.xml") : 0;
+  if (filename && (fp = susetags_open(ddir, filename, &tmp, 1)) != 0)
+    {
+      if (repo_add_appdata(repo, fp, 0))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+    }
+#endif
+
+  while (nfiles > 0)
+    solv_free(files[--nfiles]);
+  solv_free(files);
+  solv_free(ddir);
+  repo_internalize(repo);
+  return 0;
+}
+
+#else
+
+int
+read_susetags_repo(Repo *repo, const char *dir)
+{
+  fprintf(stderr, "susetags repo type is not supported\n");
+  exit(1);
+}
+
+#endif
+
+
+#ifdef ENABLE_RPMMD
+
+static const char *
+repomd_find(Repo *repo, const char *what)
+{
+  Pool *pool = repo->pool;
+  Dataiterator di;
+  const char *filename;
+
+  filename = 0;
+  dataiterator_init(&di, pool, repo, SOLVID_META, REPOSITORY_REPOMD_TYPE, what, SEARCH_STRING);
+  dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD);
+  if (dataiterator_step(&di))
+    {
+      dataiterator_setpos_parent(&di);
+      filename = pool_lookup_str(pool, SOLVID_POS, REPOSITORY_REPOMD_LOCATION);
+    }
+  dataiterator_free(&di);
+  if (filename && strncmp(filename, "repodata/", 9) == 0)
+    filename += 9;
+  return filename;
+}
+
+static FILE *
+repomd_open(const char *dir, const char *filename, char **tmpp, int missingok)
+{
+  FILE *fp;
+  if (!filename)
+    {
+      *tmpp = 0;
+      return 0;
+    }
+  *tmpp = solv_dupjoin(dir, "/", filename);
+  if ((fp = solv_xfopen(*tmpp, "r")) == 0)
+    {
+      if (!missingok)
+       {
+         perror(*tmpp);
+         exit(1);
+       }
+      *tmpp = solv_free(*tmpp);
+      return 0;
+    }
+  return fp;
+}
+
+static void
+repomd_extend(Repo *repo, const char *dir, const char *what, const char *language, int missingok)
+{
+  const char *filename;
+  FILE *fp;
+  char *tmp;
+
+  filename = repomd_find(repo, what);
+  if (!filename)
+    return;
+  fp = repomd_open(dir, filename, &tmp, missingok);
+  if (fp)
+    {
+      if (repo_add_rpmmd(repo, fp, language, REPO_EXTEND_SOLVABLES))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool));
+         exit(1);
+       }
+      fclose(fp);
+    }
+  solv_free(tmp);
+}
+
+static void
+repomd_extend_languages(Repo *repo, const char *dir, int missingok)
+{
+  char **susedatas = 0;
+  int nsusedatas = 0, i;
+  Dataiterator di;
+  dataiterator_init(&di, repo->pool, repo, SOLVID_META, REPOSITORY_REPOMD_TYPE, "susedata.", SEARCH_STRINGSTART);
+  dataiterator_prepend_keyname(&di, REPOSITORY_REPOMD);
+  while (dataiterator_step(&di))
+    {
+      susedatas = solv_extend(susedatas, nsusedatas, 1, sizeof(char *), 15);
+      susedatas[nsusedatas++] = solv_strdup(di.kv.str);
+    }
+  dataiterator_free(&di);
+  for (i = 0; i < nsusedatas; i++)
+    {
+      repomd_extend(repo, dir, susedatas[i], susedatas[i] + 9, missingok);
+      susedatas[i] = solv_free(susedatas[i]);
+    }
+  solv_free(susedatas);
+}
+
+static void
+add_rpmmd_file(Repo *repo, const char *dir, const char *filename, int missingok)
+{
+  FILE *fp;
+  char *tmp;
+
+  fp = repomd_open(dir, filename, &tmp, missingok);
+  if (!fp)
+    return;
+  if (repo_add_rpmmd(repo, fp, 0, 0))
+    {
+      fprintf(stderr, "%s: %s\n", tmp, pool_errstr(repo->pool));
+      exit(1);
+    }
+  fclose(fp);
+  solv_free(tmp);
+}
+
+int
+read_rpmmd_repo(Repo *repo, const char *dir)
+{
+  Pool *pool = repo->pool;
+  FILE *fp;
+  char *tmp = 0;
+  const char *filename;
+
+  /* add repomd.xml and suseinfo.xml */
+  fp = repomd_open(dir, "repomd.xml", &tmp, 0);
+  if (repo_add_repomdxml(repo, fp, 0))
+    {
+      fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+      exit(1);
+    }
+  fclose(fp);
+  tmp = solv_free(tmp);
+  filename = repomd_find(repo, "suseinfo");
+  if (filename && (fp = repomd_open(dir, filename, &tmp, 0)) != 0)
+    {
+      if (repo_add_repomdxml(repo, fp, REPO_REUSE_REPODATA))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+    }
+  
+  /* first all primary packages */
+  filename = repomd_find(repo, "primary");
+  if (filename)
+    {
+      add_rpmmd_file(repo, dir, filename, 0);
+      repomd_extend(repo, dir, "susedata", 0, 1);
+      repomd_extend_languages(repo, dir, 1);
+      if (add_filelist)
+        repomd_extend(repo, dir, "filelists", 0, 1);
+      if (add_changelog)
+        repomd_extend(repo, dir, "other", 0, 1);
+    }
+
+  /* some legacy stuff */
+  filename = repomd_find(repo, "products");
+  if (!filename)
+    filename = repomd_find(repo, "product");
+  if (filename)
+    add_rpmmd_file(repo, dir, filename, 1);
+  filename = repomd_find(repo, "patterns");
+    add_rpmmd_file(repo, dir, filename, 1);
+  
+  /* updateinfo */
+  filename = repomd_find(repo, "updateinfo");
+  if (filename && (fp = repomd_open(dir, filename, &tmp, 0)) != 0)
+    {
+      if (repo_add_updateinfoxml(repo, fp, 0))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+    }
+
+  /* deltainfo */
+  filename = repomd_find(repo, "deltainfo");
+  if (!filename)
+    filename = repomd_find(repo, "prestodelta");
+  if (filename && (fp = repomd_open(dir, filename, &tmp, 1)) != 0)
+    {
+      if (repo_add_deltainfoxml(repo, fp, 0))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+    }
+
+#ifdef ENABLE_APPDATA
+  /* appdata */
+  filename = add_appdata ? repomd_find(repo, "appdata") : 0;
+  if (filename && (fp = repomd_open(dir, filename, &tmp, 1)) != 0)
+    {
+      if (repo_add_appdata(repo, fp, 0))
+       {
+         fprintf(stderr, "%s: %s\n", tmp, pool_errstr(pool));
+         exit(1);
+       }
+      fclose(fp);
+      tmp = solv_free(tmp);
+    }
+#endif
+
+  repo_internalize(repo);
+  return 0;
+}
+
+#else
+
+int
+read_rpmmd_repo(Repo *repo, const char *dir)
+{
+  fprintf(stderr, "rpmmd repo type is not supported\n");
+  exit(1);
+}
+
+#endif
+
+static void
+usage(int status)
+{
+  fprintf(stderr, "\nUsage:\n"
+          "repo2solv [-R] [-X] [-A] [-o <out.solv>] <dir>\n"
+         "  Convert a repository in <dir> to a solv file\n"
+         "  -h : print help & exit\n"
+         "  -o <out.solv>: write to this file instead of stdout\n"
+         "  -F : add filelist\n"
+         "  -R : also search subdirectories for rpms\n"
+         "  -X : generate pattern/product pseudo packages\n"
+         "  -A : add appdata packages\n"
+        );
+   exit(status);
+}
+
+int
+main(int argc, char **argv)
+{
+  int c, res;
+  int repotype = 0;
+  char *outfile = 0;
+  char *dir;
+  struct stat stb;
+  
+  Pool *pool = pool_create();
+  Repo *repo = repo_create(pool, "<repo>");
+
+  while ((c = getopt(argc, argv, "hAXRFCo:")) >= 0)
+    {
+      switch(c)
+       {
+        case 'h':
+          usage(0);
+          break;
+       case 'X':
+#ifdef SUSE
+         add_auto = 1;
+#endif
+         break;
+       case 'A':
+#ifdef ENABLE_APPDATA
+         add_appdata = 1;
+#endif
+         break;
+       case 'R':
+         repotype = REPO_PLAINDIR;
+         recursive = 1;
+         break;
+       case 'F':
+         add_filelist = 1;
+         break;
+       case 'C':
+         add_changelog = 1;
+         break;
+       case 'o':
+         outfile = optarg;
+         break;
+        default:
+          usage(1);
+          break;
+       }
+    }
+  if (optind + 1 != argc)
+    usage(1);
+  dir = argv[optind];
+  if (stat(dir, &stb))
+    {
+      perror(dir);
+      exit(1);
+    }
+  if (!S_ISDIR(stb.st_mode))
+    {
+      fprintf(stderr, "%s: not a directory\n", dir);
+      exit(1);
+    }
+  dir = solv_strdup(dir);
+  if (repotype == 0)
+    repotype = autodetect_repotype(pool, dir);
+
+  switch (repotype)
+    {
+    case REPO_RPMMD:
+      res = read_rpmmd_repo(repo, dir);
+      break;
+    case REPO_RPMMD_REPODATA:
+      dir = solv_dupappend(dir, "/repodata", 0);
+      res = read_rpmmd_repo(repo, dir);
+      break;
+    case REPO_SUSETAGS:
+      res = read_susetags_repo(repo, dir);
+      break;
+    case REPO_PLAINDIR:
+      res = read_plaindir_repo(repo, dir);
+      break;
+    default:
+      fprintf(stderr, "unknown repotype %d\n", repotype);
+      exit(1);
+    }
+  if (outfile && freopen(outfile, "w", stdout) == 0)
+    {
+      perror(outfile);
+      exit(1);
+    }
+#ifdef SUSE
+  if (add_auto)
+    repo_add_autopattern(repo, 0);
+#endif
+  tool_write(repo, 0, 0);
+  if (fflush(stdout))
+    {
+      perror("fflush");
+      exit(1);
+    }
+  pool_free(pool);
+  solv_free(dir);
+  exit(res);
+}