From e679b515eddb3dd340fb25620de0160211f40fdc Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Tue, 4 Dec 2018 14:04:28 +0900 Subject: [PATCH] Imported Upstream version 0.6.35 Change-Id: Ib7359aa10c08c1469105fbd6a82ea922f46f8b51 Signed-off-by: DongHun Kwak --- CMakeLists.txt | 24 +- NEWS | 11 + VERSION.cmake | 2 +- bindings/solv.i | 14 +- doc/CMakeLists.txt | 2 +- doc/Makefile.gen | 2 +- doc/gen/libsolv-bindings.3 | 51 ++- doc/gen/libsolv-pool.3 | 18 +- doc/gen/repo2solv.1 | 79 ++++ doc/gen/solv.1 | 102 +++++ doc/libsolv-bindings.txt | 22 +- doc/libsolv-pool.txt | 4 + doc/repo2solv.txt | 60 +++ doc/solv.txt | 73 ++++ {tools => examples}/repo2solv.sh | 3 + examples/solv/checksig.c | 12 +- examples/solv/solv.c | 4 + ext/CMakeLists.txt | 5 + ext/repo_deb.c | 5 +- ext/repo_rpmdb.c | 93 ++--- ext/repo_rpmdb.h | 1 + ext/repo_rpmdb_bdb.h | 4 +- ext/repo_rpmdb_librpm.h | 24 +- ext/solv_xfopen.c | 261 ++++++++++++ ext/solv_zchunk.c | 408 +++++++++++++++++++ ext/solv_zchunk.h | 13 + package/libsolv.changes | 23 ++ package/libsolv.spec.in | 164 ++++---- src/bitmap.c | 20 +- src/bitmap.h | 8 +- src/cleandeps.c | 13 +- src/libsolv.ver | 4 + src/policy.c | 20 +- src/pool.c | 2 +- src/pool.h | 6 +- src/poolarch.c | 7 +- src/poolarch.h | 6 +- src/poolid.c | 67 +++- src/poolid.h | 1 + src/problems.c | 2 +- src/queue.c | 22 +- src/queue.h | 4 +- src/repo.h | 5 +- src/repo_solv.c | 69 +--- src/repo_write.c | 154 +++---- src/repodata.c | 93 +++-- src/repodata.h | 3 +- src/rules.c | 54 ++- src/selection.c | 6 +- src/solvversion.h.in | 1 + src/strpool.c | 50 ++- src/strpool.h | 1 + tools/CMakeLists.txt | 11 +- tools/common_write.c | 2 + tools/patchcheck.c | 641 ------------------------------ tools/repo2solv.c | 839 +++++++++++++++++++++++++++++++++++++++ 56 files changed, 2453 insertions(+), 1142 deletions(-) create mode 100644 doc/gen/repo2solv.1 create mode 100644 doc/gen/solv.1 create mode 100644 doc/repo2solv.txt create mode 100644 doc/solv.txt rename {tools => examples}/repo2solv.sh (98%) create mode 100644 ext/solv_zchunk.c create mode 100644 ext/solv_zchunk.h delete mode 100644 tools/patchcheck.c create mode 100644 tools/repo2solv.c 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 -.\" Date: 02/28/2018 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" 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 -.\" Date: 01/18/2018 +.\" Generator: DocBook XSL Stylesheets vsnapshot +.\" 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 +.\" 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 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 +.\" 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 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 + +//// +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 + +//// +vim: syntax=asciidoc +//// diff --git a/tools/repo2solv.sh b/examples/repo2solv.sh similarity index 98% rename from tools/repo2solv.sh rename to 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 + +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 +#include +#include +#include +#include + +#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 -#include -#include -#include - -#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: [--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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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 ] \n" + " Convert a repository in to a solv file\n" + " -h : print help & exit\n" + " -o : 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, ""); + + 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); +} -- 2.7.4