summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2018-12-04 14:04:28 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2018-12-04 14:04:32 +0900
commite679b515eddb3dd340fb25620de0160211f40fdc (patch)
tree93271e0bbd40dba805f8270cfc78a3ac10ab2c8f
parentd98199487aa414cb7f965a058c4395235343e20a (diff)
downloadlibsolv-e679b515eddb3dd340fb25620de0160211f40fdc.tar.gz
libsolv-e679b515eddb3dd340fb25620de0160211f40fdc.tar.bz2
libsolv-e679b515eddb3dd340fb25620de0160211f40fdc.zip
Imported Upstream version 0.6.35upstream/0.6.35
Change-Id: Ib7359aa10c08c1469105fbd6a82ea922f46f8b51 Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
-rw-r--r--CMakeLists.txt24
-rw-r--r--NEWS11
-rw-r--r--VERSION.cmake2
-rw-r--r--bindings/solv.i14
-rw-r--r--doc/CMakeLists.txt2
-rw-r--r--doc/Makefile.gen2
-rw-r--r--doc/gen/libsolv-bindings.351
-rw-r--r--doc/gen/libsolv-pool.318
-rw-r--r--doc/gen/repo2solv.179
-rw-r--r--doc/gen/solv.1102
-rw-r--r--doc/libsolv-bindings.txt22
-rw-r--r--doc/libsolv-pool.txt4
-rw-r--r--doc/repo2solv.txt60
-rw-r--r--doc/solv.txt73
-rwxr-xr-xexamples/repo2solv.sh (renamed from tools/repo2solv.sh)3
-rw-r--r--examples/solv/checksig.c12
-rw-r--r--examples/solv/solv.c4
-rw-r--r--ext/CMakeLists.txt5
-rw-r--r--ext/repo_deb.c5
-rw-r--r--ext/repo_rpmdb.c93
-rw-r--r--ext/repo_rpmdb.h1
-rw-r--r--ext/repo_rpmdb_bdb.h4
-rw-r--r--ext/repo_rpmdb_librpm.h24
-rw-r--r--ext/solv_xfopen.c261
-rw-r--r--ext/solv_zchunk.c408
-rw-r--r--ext/solv_zchunk.h13
-rw-r--r--package/libsolv.changes23
-rw-r--r--package/libsolv.spec.in164
-rw-r--r--src/bitmap.c20
-rw-r--r--src/bitmap.h8
-rw-r--r--src/cleandeps.c13
-rw-r--r--src/libsolv.ver4
-rw-r--r--src/policy.c20
-rw-r--r--src/pool.c2
-rw-r--r--src/pool.h6
-rw-r--r--src/poolarch.c7
-rw-r--r--src/poolarch.h6
-rw-r--r--src/poolid.c67
-rw-r--r--src/poolid.h1
-rw-r--r--src/problems.c2
-rw-r--r--src/queue.c22
-rw-r--r--src/queue.h4
-rw-r--r--src/repo.h5
-rw-r--r--src/repo_solv.c69
-rw-r--r--src/repo_write.c154
-rw-r--r--src/repodata.c93
-rw-r--r--src/repodata.h3
-rw-r--r--src/rules.c54
-rw-r--r--src/selection.c6
-rw-r--r--src/solvversion.h.in1
-rw-r--r--src/strpool.c50
-rw-r--r--src/strpool.h1
-rw-r--r--tools/CMakeLists.txt11
-rw-r--r--tools/common_write.c2
-rw-r--r--tools/patchcheck.c641
-rw-r--r--tools/repo2solv.c839
56 files changed, 2453 insertions, 1142 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2557f0a..8c6a1be 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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
--- 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
diff --git a/VERSION.cmake b/VERSION.cmake
index 1d14e17..991c920 100644
--- a/VERSION.cmake
+++ b/VERSION.cmake
@@ -49,5 +49,5 @@ SET(LIBSOLVEXT_SOVERSION "0")
SET(LIBSOLV_MAJOR "0")
SET(LIBSOLV_MINOR "6")
-SET(LIBSOLV_PATCH "34")
+SET(LIBSOLV_PATCH "35")
diff --git a/bindings/solv.i b/bindings/solv.i
index acd01ac..8fb469f 100644
--- a/bindings/solv.i
+++ b/bindings/solv.i
@@ -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;
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index b18596d..66011b4 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -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)
diff --git a/doc/Makefile.gen b/doc/Makefile.gen
index 2e8c4a1..e9f1b69 100644
--- a/doc/Makefile.gen
+++ b/doc/Makefile.gen
@@ -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
diff --git a/doc/gen/libsolv-bindings.3 b/doc/gen/libsolv-bindings.3
index a6534aa..7ca0bb5 100644
--- a/doc/gen/libsolv-bindings.3
+++ b/doc/gen/libsolv-bindings.3
@@ -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
diff --git a/doc/gen/libsolv-pool.3 b/doc/gen/libsolv-pool.3
index ffb8e56..c64eeb1 100644
--- a/doc/gen/libsolv-pool.3
+++ b/doc/gen/libsolv-pool.3
@@ -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
index 0000000..5f21465
--- /dev/null
+++ b/doc/gen/repo2solv.1
@@ -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
index 0000000..b61538d
--- /dev/null
+++ b/doc/gen/solv.1
@@ -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>
diff --git a/doc/libsolv-bindings.txt b/doc/libsolv-bindings.txt
index 1f6422f..5db1116 100644
--- a/doc/libsolv-bindings.txt
+++ b/doc/libsolv-bindings.txt
@@ -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)
diff --git a/doc/libsolv-pool.txt b/doc/libsolv-pool.txt
index 6014720..0b9bc41 100644
--- a/doc/libsolv-pool.txt
+++ b/doc/libsolv-pool.txt
@@ -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
index 0000000..3b2145f
--- /dev/null
+++ b/doc/repo2solv.txt
@@ -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
index 0000000..936ae78
--- /dev/null
+++ b/doc/solv.txt
@@ -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
+////
diff --git a/tools/repo2solv.sh b/examples/repo2solv.sh
index 49b623a..450b7fa 100755
--- a/tools/repo2solv.sh
+++ b/examples/repo2solv.sh
@@ -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
diff --git a/examples/solv/checksig.c b/examples/solv/checksig.c
index ff60c66..44603d3 100644
--- a/examples/solv/checksig.c
+++ b/examples/solv/checksig.c
@@ -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);
diff --git a/examples/solv/solv.c b/examples/solv/solv.c
index 627c248..42ab751 100644
--- a/examples/solv/solv.c
+++ b/examples/solv/solv.c
@@ -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);
diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt
index b8917a2..edc2b9f 100644
--- a/ext/CMakeLists.txt
+++ b/ext/CMakeLists.txt
@@ -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")
diff --git a/ext/repo_deb.c b/ext/repo_deb.c
index 277e65a..6af7f10 100644
--- a/ext/repo_deb.c
+++ b/ext/repo_deb.c
@@ -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);
diff --git a/ext/repo_rpmdb.c b/ext/repo_rpmdb.c
index cd14a9b..75bb678 100644
--- a/ext/repo_rpmdb.c
+++ b/ext/repo_rpmdb.c
@@ -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);
diff --git a/ext/repo_rpmdb.h b/ext/repo_rpmdb.h
index 9e3bd0d..554d48a 100644
--- a/ext/repo_rpmdb.h
+++ b/ext/repo_rpmdb.h
@@ -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 */
diff --git a/ext/repo_rpmdb_bdb.h b/ext/repo_rpmdb_bdb.h
index c34ff70..ed82a69 100644
--- a/ext/repo_rpmdb_bdb.h
+++ b/ext/repo_rpmdb_bdb.h
@@ -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;
diff --git a/ext/repo_rpmdb_librpm.h b/ext/repo_rpmdb_librpm.h
index 802c5d1..79983d3 100644
--- a/ext/repo_rpmdb_librpm.h
+++ b/ext/repo_rpmdb_librpm.h
@@ -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)
{
diff --git a/ext/solv_xfopen.c b/ext/solv_xfopen.c
index 2c64bb6..a74762f 100644
--- a/ext/solv_xfopen.c
+++ b/ext/solv_xfopen.c
@@ -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
index 0000000..0833445
--- /dev/null
+++ b/ext/solv_zchunk.c
@@ -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
index 0000000..9d73486
--- /dev/null
+++ b/ext/solv_zchunk.h
@@ -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);
+
diff --git a/package/libsolv.changes b/package/libsolv.changes
index ee3a9f0..430e479 100644
--- a/package/libsolv.changes
+++ b/package/libsolv.changes
@@ -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
diff --git a/package/libsolv.spec.in b/package/libsolv.spec.in
index 6276f3c..ca649e8 100644
--- a/package/libsolv.spec.in
+++ b/package/libsolv.spec.in
@@ -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
@@ -15,55 +15,61 @@
# 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*
diff --git a/src/bitmap.c b/src/bitmap.c
index e004bf2..4e8adbd 100644
--- a/src/bitmap.c
+++ b/src/bitmap.c
@@ -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;
diff --git a/src/bitmap.h b/src/bitmap.h
index 0050a6a..1e89590 100644
--- a/src/bitmap.h
+++ b/src/bitmap.h
@@ -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)
diff --git a/src/cleandeps.c b/src/cleandeps.c
index cbe2020..1da28f6 100644
--- a/src/cleandeps.c
+++ b/src/cleandeps.c
@@ -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
diff --git a/src/libsolv.ver b/src/libsolv.ver
index 9adf60d..a3fa19a 100644
--- a/src/libsolv.ver
+++ b/src/libsolv.ver
@@ -431,3 +431,7 @@ SOLV_1.2 {
pool_set_whatprovides;
selection_subtract;
} SOLV_1.1;
+
+SOLV_1.3 {
+ repodata_set_kv;
+} SOLV_1.2;
diff --git a/src/policy.c b/src/policy.c
index 6f06101..a38dea0 100644
--- a/src/policy.c
+++ b/src/policy.c
@@ -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;
diff --git a/src/pool.c b/src/pool.c
index ba5e799..60cc0f4 100644
--- a/src/pool.c
+++ b/src/pool.c
@@ -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);
diff --git a/src/pool.h b/src/pool.h
index f6573af..e6d1700 100644
--- a/src/pool.h
+++ b/src/pool.h
@@ -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)
diff --git a/src/poolarch.c b/src/poolarch.c
index 8da16c1..4a1fa50 100644
--- a/src/poolarch.c
+++ b/src/poolarch.c
@@ -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);
diff --git a/src/poolarch.h b/src/poolarch.h
index 3fe5f02..787883b 100644
--- a/src/poolarch.h
+++ b/src/poolarch.h
@@ -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
diff --git a/src/poolid.c b/src/poolid.c
index bb8d4f6..3b55f76 100644
--- a/src/poolid.c
+++ b/src/poolid.c
@@ -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 */
diff --git a/src/poolid.h b/src/poolid.h
index 2363595..79a3ccd 100644
--- a/src/poolid.h
+++ b/src/poolid.h
@@ -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
}
diff --git a/src/problems.c b/src/problems.c
index 5bd2bf5..df751c4 100644
--- a/src/problems.c
+++ b/src/problems.c
@@ -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:
diff --git a/src/queue.c b/src/queue.c
index ceb1062..6d5e531 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -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;
diff --git a/src/queue.h b/src/queue.h
index 4785e67..7e56035 100644
--- a/src/queue.h
+++ b/src/queue.h
@@ -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);
diff --git a/src/repo.h b/src/repo.h
index 9dcbcca..bd9c58c 100644
--- a/src/repo.h
+++ b/src/repo.h
@@ -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)
{
diff --git a/src/repo_solv.c b/src/repo_solv.c
index 2460e30..5858d4f 100644
--- a/src/repo_solv.c
+++ b/src/repo_solv.c
@@ -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 */
}
diff --git a/src/repo_write.c b/src/repo_write.c
index 396cd42..7e78af5 100644
--- a/src/repo_write.c
+++ b/src/repo_write.c
@@ -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)
diff --git a/src/repodata.c b/src/repodata.c
index 06b2ea3..4ab5d18 100644
--- a/src/repodata.c
+++ b/src/repodata.c
@@ -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);
diff --git a/src/repodata.h b/src/repodata.h
index d72c60f..7208e95 100644
--- a/src/repodata.h
+++ b/src/repodata.h
@@ -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);
diff --git a/src/rules.c b/src/rules.c
index cf368e4..df32341 100644
--- a/src/rules.c
+++ b/src/rules.c
@@ -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)
diff --git a/src/selection.c b/src/selection.c
index 6ca72e5..d44c482 100644
--- a/src/selection.c
+++ b/src/selection.c
@@ -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;
diff --git a/src/solvversion.h.in b/src/solvversion.h.in
index 7d107f9..4caba47 100644
--- a/src/solvversion.h.in
+++ b/src/solvversion.h.in
@@ -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"
diff --git a/src/strpool.c b/src/strpool.c
index af43e01..5e87918 100644
--- a/src/strpool.c
+++ b/src/strpool.c
@@ -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;
diff --git a/src/strpool.h b/src/strpool.h
index c97b873..f96c5c1 100644
--- a/src/strpool.h
+++ b/src/strpool.h
@@ -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);
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 6b592f7..802dc50 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -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})
diff --git a/tools/common_write.c b/tools/common_write.c
index e20f64f..577b1ab 100644
--- a/tools/common_write.c
+++ b/tools/common_write.c
@@ -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
index 4025f92..0000000
--- a/tools/patchcheck.c
+++ /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
index 0000000..e055e40
--- /dev/null
+++ b/tools/repo2solv.c
@@ -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);
+}