OPTION (ENABLE_RPMPKG "Build with rpm package support?" OFF)
OPTION (ENABLE_PUBKEY "Build with pubkey support?" OFF)
OPTION (ENABLE_RPMDB_BYRPMHEADER "Build with rpmdb Header support?" OFF)
+OPTION (ENABLE_RPMDB_LIBRPM "Use librpm to access the rpm database?" OFF)
+OPTION (ENABLE_RPMPKG_LIBRPM "Use librpm to access rpm header information?" OFF)
OPTION (ENABLE_RPMMD "Build with rpmmd repository support?" OFF)
OPTION (ENABLE_SUSEREPO "Build with suse repository support?" OFF)
OPTION (ENABLE_COMPS "Build with fedora comps support?" OFF)
ENDIF (ENABLE_RPMDB)
INCLUDE (CheckIncludeFile)
-IF (ENABLE_RPMDB)
+IF (ENABLE_RPMDB OR ENABLE_RPMPKG_LIBRPM)
FIND_LIBRARY (RPMDB_LIBRARY NAMES rpmdb)
IF (NOT RPMDB_LIBRARY)
# check if rpm contains a bundled berkeley db
CHECK_INCLUDE_FILE(rpm/db.h HAVE_RPM_DB_H)
- IF (NOT HAVE_RPM_DB_H)
- FIND_LIBRARY (DB_LIBRARY NAMES db)
- IF (DB_LIBRARY)
- SET (RPMDB_LIBRARY ${DB_LIBRARY} ${RPMDB_LIBRARY})
- ENDIF (DB_LIBRARY)
- IF (DB_INCLUDE_DIR)
- INCLUDE_DIRECTORIES (${DB_INCLUDE_DIR})
- ENDIF (DB_INCLUDE_DIR)
- ENDIF (NOT HAVE_RPM_DB_H)
+ IF (NOT ENABLE_RPMDB_LIBRPM)
+ IF (NOT HAVE_RPM_DB_H)
+ FIND_LIBRARY (DB_LIBRARY NAMES db)
+ IF (DB_LIBRARY)
+ SET (RPMDB_LIBRARY ${DB_LIBRARY} ${RPMDB_LIBRARY})
+ ENDIF (DB_LIBRARY)
+ IF (DB_INCLUDE_DIR)
+ INCLUDE_DIRECTORIES (${DB_INCLUDE_DIR})
+ ENDIF (DB_INCLUDE_DIR)
+ ENDIF (NOT HAVE_RPM_DB_H)
+ ENDIF (NOT ENABLE_RPMDB_LIBRPM)
INCLUDE (CheckLibraryExists)
CHECK_LIBRARY_EXISTS(rpmio pgpDigGetParams "" HAVE_PGPDIGGETPARAMS)
-ENDIF (ENABLE_RPMDB)
+ENDIF (ENABLE_RPMDB OR ENABLE_RPMPKG_LIBRPM)
IF (ENABLE_PUBKEY)
SET (ENABLE_PGPVRFY ON)
ENDFOREACH (VAR)
FOREACH (VAR
- ENABLE_RPMDB ENABLE_RPMPKG ENABLE_PUBKEY ENABLE_RPMMD ENABLE_RPMDB_BYRPMHEADER
+ ENABLE_RPMDB ENABLE_RPMPKG ENABLE_PUBKEY ENABLE_RPMMD
+ ENABLE_RPMPKG_LIBRPM ENABLE_RPMDB_LIBRPM ENABLE_RPMDB_BYRPMHEADER
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
This file contains the major changes between
libsolv versions:
+Version 0.6.31
+- new configuration options:
+ * ENABLE_RPMDB_LIBRPM: use librpm to read the package
+ database
+ * ENABLE_RPMPKG_LIBRPM: use librpm to access information
+ from package headers
+- new features:
+ * new pool_set_whatprovides function to manually change
+ the whatprovides data
+ * new selection_subtract function to remove packages of
+ one selection from another selection
+ * new selection flags SELECTION_FILTER,
+ SELECTION_WITH_DISABLED and SELECTION_WITH_BADARCH
+ * new map_invertall function to invert a bitmap
+ * new map_clr_at function to clear some bits
+
Version 0.6.30
- new features:
* many fixes and extenstions for cleandeps, e.g.
- deal with DIRSTR entries having dirid 0 (for source rpms)
-- test rich dep rule creation
-
-- clean up rich dep rule code (see perl-BSSolv)
-
- drop patchcheck
- rename repo2solv.sh to repo2solv (maybe rewrite in C?)
- write more manpages
-- bindings: selections.flags() should be a attribute and not a method
+- bindings: selection.flags() should be a attribute and not a method
- rename repodata_lookup_id_uninternalized to repodata_lookup_id_voidid_uninternalized
and add a notfound argument
SET(LIBSOLV_MAJOR "0")
SET(LIBSOLV_MINOR "6")
-SET(LIBSOLV_PATCH "30")
+SET(LIBSOLV_PATCH "31")
static const Id SELECTION_GLOB = SELECTION_GLOB;
static const Id SELECTION_FLAT = SELECTION_FLAT;
static const Id SELECTION_NOCASE = SELECTION_NOCASE;
+ static const Id SELECTION_SKIP_KIND = SELECTION_SKIP_KIND;
+ static const Id SELECTION_MATCH_DEPSTR = SELECTION_MATCH_DEPSTR;
static const Id SELECTION_SOURCE_ONLY = SELECTION_SOURCE_ONLY;
static const Id SELECTION_WITH_SOURCE = SELECTION_WITH_SOURCE;
+ static const Id SELECTION_WITH_DISABLED = SELECTION_WITH_DISABLED;
+ static const Id SELECTION_WITH_BADARCH = SELECTION_WITH_BADARCH;
+ static const Id SELECTION_WITH_ALL = SELECTION_WITH_ALL;
+ static const Id SELECTION_ADD = SELECTION_ADD;
+ static const Id SELECTION_SUBTRACT = SELECTION_SUBTRACT;
+ static const Id SELECTION_FILTER = SELECTION_FILTER;
+ static const Id SELECTION_FILTER_KEEP_IFEMPTY = SELECTION_FILTER_KEEP_IFEMPTY;
+ static const Id SELECTION_FILTER_SWAPPED = SELECTION_FILTER_SWAPPED;
Selection(Pool *pool) {
Selection *s;
bool isempty() {
return $self->q.count == 0;
}
+ %newobject clone;
+ Selection *clone(Selection *from, int flags = 0) {
+ Selection *s;
+ s = solv_calloc(1, sizeof(*s));
+ s->pool = from->pool;
+ s->flags = from->flags;
+ queue_init_clone(&s->q, &from->q);
+ return s;
+ }
void filter(Selection *lsel) {
if ($self->pool != lsel->pool)
queue_empty(&$self->q);
void add_raw(Id how, Id what) {
queue_push2(&$self->q, how, what);
}
+ void subtract(Selection *lsel) {
+ if ($self->pool == lsel->pool)
+ selection_subtract($self->pool, &$self->q, &lsel->q);
+ }
+
+ void select(const char *name, int flags) {
+ if ((flags & SELECTION_MODEBITS) == 0)
+ flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
+ $self->flags = selection_make($self->pool, &$self->q, name, flags);
+ }
+ void matchdeps(const char *name, int flags, Id keyname, Id marker = -1) {
+ if ((flags & SELECTION_MODEBITS) == 0)
+ flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
+ $self->flags = selection_make_matchdeps($self->pool, &$self->q, name, flags, keyname, marker);
+ }
+ void matchdepid(DepId dep, int flags, Id keyname, Id marker = -1) {
+ if ((flags & SELECTION_MODEBITS) == 0)
+ flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
+ $self->flags = selection_make_matchdepid($self->pool, &$self->q, dep, flags, keyname, marker);
+ }
+
%typemap(out) Queue jobs Queue2Array(Job *, 2, new_Job(arg1->pool, id, idp[1]));
%newobject jobs;
Queue jobs(int flags) {
return pool_queuetowhatprovides($self, &q);
}
+ void set_namespaceproviders(DepId ns, DepId evr, bool value=1) {
+ Id dep = pool_rel2id($self, ns, evr, REL_NAMESPACE, 1);
+ pool_set_whatprovides($self, dep, value ? 2 : 1);
+ }
+
+ void flush_namespaceproviders(DepId ns, DepId evr) {
+ pool_flush_namespaceproviders($self, ns, evr);
+ }
+
+
%typemap(out) Queue whatmatchesdep Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id));
%newobject whatmatchesdep;
Queue whatmatchesdep(Id keyname, DepId dep, Id marker = -1) {
return sel;
}
+ %newobject matchdeps;
+ Selection *matchdeps(const char *name, int flags, Id keyname, Id marker = -1) {
+ Selection *sel = new_Selection($self);
+ sel->flags = selection_make_matchdeps($self, &sel->q, name, flags, keyname, marker);
+ return sel;
+ }
+
+ %newobject matchdepid;
+ Selection *matchdepid(DepId dep, int flags, Id keyname, Id marker = -1) {
+ Selection *sel = new_Selection($self);
+ sel->flags = selection_make_matchdepid($self, &sel->q, dep, flags, keyname, marker);
+ return sel;
+ }
+
void setpooljobs_helper(Queue jobs) {
queue_free(&$self->pooljobs);
queue_init_clone(&$self->pooljobs, &jobs);
.\" Title: Libsolv-Bindings
.\" Author: [see the "Author" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 09/07/2017
+.\" Date: 01/18/2018
.\" Manual: LIBSOLV
.\" Source: libsolv
.\" Language: English
.\"
-.TH "LIBSOLV\-BINDINGS" "3" "09/07/2017" "libsolv" "LIBSOLV"
+.TH "LIBSOLV\-BINDINGS" "3" "01/18/2018" "libsolv" "LIBSOLV"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.RS 4
.\}
.nf
+\fBvoid set_namespaceproviders(DepId\fR \fIns\fR\fB, DepId\fR \fIevr\fR\fB, bool\fR \fIvalue\fR \fB= 1)\fR
+\fI$pool\fR\fB\->set_namespaceproviders(\fR\fI$ns\fR\fB,\fR \fI$evr\fR\fB, 1)\fR;
+\fIpool\fR\fB\&.set_namespaceproviders(\fR\fIns\fR\fB,\fR \fIevr\fR\fB,\fR \fITrue\fR\fB)\fR
+\fIpool\fR\fB\&.set_namespaceproviders(\fR\fIns\fR\fB,\fR \fIevr\fR\fB,\fR \fItrue\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Manually set an namespace provides entry in the whatprovides index\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid flush_namespaceproviders(DepId\fR \fIns\fR\fB, DepId\fR \fIevr\fR\fB)\fR
+\fI$pool\fR\fB\->flush_namespaceproviders(\fR\fI$ns\fR\fB,\fR \fI$evr\fR\fB)\fR;
+\fI$pool\fR\fB\&.flush_namespaceproviders(\fR\fIns\fR\fB,\fR \fIevr\fR\fB)\fR
+\fI$pool\fR\fB\&.flush_namespaceproviders(\fR\fIns\fR\fB,\fR \fIevr\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Flush the cache of all namespacprovudes matching the specified namespace dependency\&. You can use zero as a wildcard argument\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
\fBbool isknownarch(DepId\fR \fIid\fR\fB)\fR
my \fI$bool\fR \fB=\fR \fI$pool\fR\fB\->isknownarch(\fR\fI$id\fR\fB)\fR;
\fIbool\fR \fB=\fR \fIpool\fR\fB\&.isknownarch(\fR\fIid\fR\fB)\fR
.RS 4
.\}
.nf
+\fBSelection matchdeps(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->matchdeps(\fR\fI$name\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdeps(\fR\fIname\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdeps(\fR\fIname\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a selection by matching package dependencies against the specified string\&. This can be used if you want to match other dependency types than "provides"\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSelection matchdepid(DepId\fR \fIdep\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->matchdepid(\fR\fIdep\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Create a selection by matching package dependencies against the specified dependency\&. This may be faster than matchdeps and also works with complex dependencies\&. The downside is that you cannot use globs or case insensitive matching\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
\fBvoid setpooljobs(Jobs *\fR\fIjobs\fR\fB)\fR
\fI$pool\fR\fB\->setpooljobs(\e\fR\fI@jobs\fR\fB)\fR;
\fIpool\fR\fB\&.setpooljobs(\fR\fIjobs\fR\fB)\fR
.PP
\fBSELECTION_DOTARCH\fR
.RS 4
-Allow an \(lq\&.<architecture>\(rq suffix when matching names or provides\&.
+Allow an "\&.<architecture>" suffix when matching names or provides\&.
.RE
.PP
\fBSELECTION_REL\fR
.RS 4
-Allow the specification of a relation when matching names or provides, e\&.g\&. "name >= 1\&.2"\&.
+Allow the specification of a relation when matching names or dependencies, e\&.g\&. "name >= 1\&.2"\&.
+.RE
+.PP
+\fBSELECTION_GLOB\fR
+.RS 4
+Allow glob matching for package names, package provides, and file names\&.
+.RE
+.PP
+\fBSELECTION_NOCASE\fR
+.RS 4
+Ignore case when matching package names, package provides, and file names\&.
+.RE
+.PP
+\fBSELECTION_FLAT\fR
+.RS 4
+Return only one selection element describing the selected packages\&. The default is to create multiple elements for all globbed packages\&. Multiple elements are useful if you want to turn the selection into an install job, in that case you want an install job for every globbed package\&.
+.RE
+.PP
+\fBSELECTION_SKIP_KIND\fR
+.RS 4
+Remove a "packagekind:" prefix from the package names\&.
+.RE
+.PP
+\fBSELECTION_MATCH_DEPSTR\fR
+.RS 4
+When matching dependencies, do a string match on the result of dep2str instead of using the normal dependency intersect algorithm\&.
.RE
.PP
\fBSELECTION_INSTALLED_ONLY\fR
Extend the package search to also match source packages\&. The default is only to match binary packages\&.
.RE
.PP
-\fBSELECTION_GLOB\fR
+\fBSELECTION_WITH_DISABLED\fR
.RS 4
-Allow glob matching for package names, package provides, and file names\&.
+Extend the package search to also include disabled packages\&.
.RE
.PP
-\fBSELECTION_NOCASE\fR
+\fBSELECTION_WITH_BADARCH\fR
.RS 4
-Ignore case when matching package names, package provides, and file names\&.
+Extend the package search to also include packages that are not installable on the configured architecture\&.
.RE
.PP
-\fBSELECTION_FLAT\fR
+\fBSELECTION_WITH_ALL\fR
.RS 4
-Return only one selection element describing the selected packages\&. The default is to create multiple elements for all globbed packages\&. Multiple elements are useful if you want to turn the selection into an install job, in that case you want an install job for every globbed package\&.
+Shortcut for selecting the three modifiers above\&.
+.RE
+.PP
+\fBSELECTION_ADD\fR
+.RS 4
+Add the result of the match to the current selection instead of replacing it\&.
+.RE
+.PP
+\fBSELECTION_SUBTRACT\fR
+.RS 4
+Remove the result of the match to the current selection instead of replacing it\&.
+.RE
+.PP
+\fBSELECTION_FILTER\fR
+.RS 4
+Intersect the result of the match to the current selection instead of replacing it\&.
.RE
.SS "ATTRIBUTES"
.sp
.RS 4
.\}
.nf
+\fBvoid subtract(Selection *\fR\fIother\fR\fB)\fR
+\fI$sel\fR\fB\->subtract(\fR\fI$other\fR\fB)\fR;
+\fIsel\fR\fB\&.subtract(\fR\fIother\fR\fB)\fR
+\fIsel\fR\fB\&.subtract(\fR\fIother\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Remove the packages of the other selection from the packages of the selection object\&. Does an in\-place modification\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
\fBvoid add_raw(Id\fR \fIhow\fR\fB, Id\fR \fIwhat\fR\fB)\fR
\fI$sel\fR\fB\->add_raw(\fR\fI$how\fR\fB,\fR \fI$what\fR\fB)\fR;
\fIsel\fR\fB\&.add_raw(\fR\fIhow\fR\fB,\fR \fIwhat\fR\fB)\fR
.RE
.\}
.sp
-Add a raw element to the selection\&. Check the Job class for information about the how and what parameters\&.
+Add a raw element to the selection\&. Check the Job class for information about the how and what parameters\&. Note that the selection flags are no longer meaningful after the add_raw operation\&.
.sp
.if n \{\
.RS 4
.RS 4
.\}
.nf
+\fBvoid select(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR\fB)\fR
+\fI$sel\fR\fB\->select(\fR\fI$name\fR\fB,\fR \fI$flags\fR\fB)\fR;
+\fIsel\fR\fB\&.select(\fR\fIname\fR\fB,\fR \fIflags\fR\fB)\fR
+\fIsel\fR\fB\&.select(\fR\fIname\fR\fB,\fR \fIflags\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Do a select operation and combine the result with the current selection\&. You can choose the desired combination method by using either the SELECTION_ADD, SELECTION_SUBTRACT, or SELECTION_FILTER flag\&. If none of the flags are used, SELECTION_FILTER|SELECTION_WITH_ALL is assumed\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid matchdeps(const char *\fR\fIname\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+\fI$sel\fR\fB\->matchdeps(\fR\fI$name\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIsel\fR\fB\&.matchdeps(\fR\fIname\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIsel\fR\fB\&.matchdeps(\fR\fIname\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Do a matchdeps operation and combine the result with the current selection\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBvoid matchdepid(DepId\fR \fIdep\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+\fI$sel\fR\fB\->matchdepid(\fR\fI$dep\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIsel\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIsel\fR\fB\&.matchdepid(\fR\fIdep\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Do a matchdepid operation and combine the result with the current selection\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
\fB<stringification>\fR
my \fI$str\fR \fB=\fR \fI$sel\fR\fB\->str\fR;
\fIstr\fR \fB= str(\fR\fIsel\fR\fB)\fR
'\" t
.\" Title: Libsolv-Pool
.\" Author: [see the "Author" section]
-.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 09/04/2017
+.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
+.\" Date: 01/18/2018
.\" Manual: LIBSOLV
.\" Source: libsolv
.\" Language: English
.\"
-.TH "LIBSOLV\-POOL" "3" "09/04/2017" "libsolv" "LIBSOLV"
+.TH "LIBSOLV\-POOL" "3" "01/18/2018" "libsolv" "LIBSOLV"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.RS 4
.\}
.nf
+\fBvoid pool_set_whatprovides(\fR\fIpool\fR\fB, Id\fR \fIid\fR\fB, Id\fR \fIoffset\fR\fB)\fR;
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Manually set an entry in the whatprovides index\&. You\(cqll never do this for package dependencies, as those entries are created by calling the pool_createwhatprovides() function\&. But this function is useful for namespace provides if you do not want to use a namespace callback to lazily set the provides\&. The offset argument is a offset in the whatprovides array, thus you can use \(lq1\(rq as a false value and \(lq2\(rq as true value\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
\fBvoid pool_flush_namespaceproviders(Pool *\fR\fIpool\fR\fB, Id\fR \fIns\fR\fB, Id\fR \fIevr\fR\fB)\fR;
.fi
.if n \{\
create solver jobs working on a specific set of packages. See the Solver class
for more information.
+ void set_namespaceproviders(DepId ns, DepId evr, bool value = 1)
+ $pool->set_namespaceproviders($ns, $evr, 1);
+ pool.set_namespaceproviders(ns, evr, True)
+ pool.set_namespaceproviders(ns, evr, true)
+
+Manually set an namespace provides entry in the whatprovides index.
+
+ void flush_namespaceproviders(DepId ns, DepId evr)
+ $pool->flush_namespaceproviders($ns, $evr);
+ $pool.flush_namespaceproviders(ns, evr)
+ $pool.flush_namespaceproviders(ns, evr)
+
+Flush the cache of all namespacprovudes matching the specified namespace
+dependency. You can use zero as a wildcard argument.
+
bool isknownarch(DepId id)
my $bool = $pool->isknownarch($id);
bool = pool.isknownarch(id)
Selection class for a list of flags and how to create solver jobs from a
selection.
+ Selection matchdeps(const char *name, int flags, Id keyname, Id marker = -1)
+ my $sel = $pool->matchdeps($name, $flags, $keyname);
+ sel = pool.matchdeps(name, flags, keyname)
+ sel = pool.matchdeps(name, flags, keyname)
+
+Create a selection by matching package dependencies against the specified string.
+This can be used if you want to match other dependency types than "provides".
+
+ Selection matchdepid(DepId dep, int flags, Id keyname, Id marker = -1)
+ my $sel = $pool->matchdepid(dep, $flags, $keyname);
+ sel = pool.matchdepid(dep, flags, keyname)
+ sel = pool.matchdepid(dep, flags, keyname)
+
+Create a selection by matching package dependencies against the specified
+dependency. This may be faster than matchdeps and also works with complex
+dependencies. The downside is that you cannot use globs or case insensitive
+matching.
+
void setpooljobs(Jobs *jobs)
$pool->setpooljobs(\@jobs);
pool.setpooljobs(jobs)
the version, and the architecture of a package.
*SELECTION_DOTARCH*::
-Allow an ``.<architecture>'' suffix when matching names or
+Allow an ".<architecture>" suffix when matching names or
provides.
*SELECTION_REL*::
Allow the specification of a relation when matching names
-or provides, e.g. "name >= 1.2".
-
-*SELECTION_INSTALLED_ONLY*::
-Limit the package search to installed packages.
-
-*SELECTION_SOURCE_ONLY*::
-Limit the package search to source packages only.
-
-*SELECTION_WITH_SOURCE*::
-Extend the package search to also match source packages. The default is
-only to match binary packages.
+or dependencies, e.g. "name >= 1.2".
*SELECTION_GLOB*::
Allow glob matching for package names, package provides, and file names.
an install job, in that case you want an install job for every
globbed package.
+*SELECTION_SKIP_KIND*::
+Remove a "packagekind:" prefix from the package names.
+
+*SELECTION_MATCH_DEPSTR*::
+When matching dependencies, do a string match on the result of dep2str
+instead of using the normal dependency intersect algorithm.
+
+*SELECTION_INSTALLED_ONLY*::
+Limit the package search to installed packages.
+
+*SELECTION_SOURCE_ONLY*::
+Limit the package search to source packages only.
+
+*SELECTION_WITH_SOURCE*::
+Extend the package search to also match source packages. The default is
+only to match binary packages.
+
+*SELECTION_WITH_DISABLED*::
+Extend the package search to also include disabled packages.
+
+*SELECTION_WITH_BADARCH*::
+Extend the package search to also include packages that are not installable
+on the configured architecture.
+
+*SELECTION_WITH_ALL*::
+Shortcut for selecting the three modifiers above.
+
+*SELECTION_ADD*::
+Add the result of the match to the current selection instead of replacing it.
+
+*SELECTION_SUBTRACT*::
+Remove the result of the match to the current selection instead of replacing it.
+
+*SELECTION_FILTER*::
+Intersect the result of the match to the current selection instead of replacing it.
+
=== ATTRIBUTES ===
Pool *pool; /* read only */
modification. Note that the selection flags are no longer meaningful after the
add operation.
+ void subtract(Selection *other)
+ $sel->subtract($other);
+ sel.subtract(other)
+ sel.subtract(other)
+
+Remove the packages of the other selection from the packages of the selection
+object. Does an in-place modification.
+
void add_raw(Id how, Id what)
$sel->add_raw($how, $what);
sel.add_raw(how, what)
sel.add_raw(how, what)
Add a raw element to the selection. Check the Job class for information about
-the how and what parameters.
+the how and what parameters. Note that the selection flags are no longer meaningful
+after the add_raw operation.
Job *jobs(int action)
my @jobs = $sel->jobs($action);
Convert a selection into an array of Solvable objects.
+ void select(const char *name, int flags)
+ $sel->select($name, $flags);
+ sel.select(name, flags)
+ sel.select(name, flags)
+
+Do a select operation and combine the result with the current selection. You
+can choose the desired combination method by using either the SELECTION_ADD,
+SELECTION_SUBTRACT, or SELECTION_FILTER flag. If none of the flags are
+used, SELECTION_FILTER|SELECTION_WITH_ALL is assumed.
+
+ void matchdeps(const char *name, int flags, Id keyname, Id marker = -1)
+ $sel->matchdeps($name, $flags, $keyname);
+ sel.matchdeps(name, flags, keyname)
+ sel.matchdeps(name, flags, keyname)
+
+Do a matchdeps operation and combine the result with the current selection.
+
+ void matchdepid(DepId dep, int flags, Id keyname, Id marker = -1)
+ $sel->matchdepid($dep, $flags, $keyname);
+ sel.matchdepid(dep, flags, keyname)
+ sel.matchdepid(dep, flags, keyname)
+
+Do a matchdepid operation and combine the result with the current selection.
+
<stringification>
my $str = $sel->str;
str = str(sel)
the meta section of the repositories to speed up the next time the
repository is loaded and addfileprovides is called
+ void pool_set_whatprovides(pool, Id id, Id offset);
+
+Manually set an entry in the whatprovides index. You'll never do this for
+package dependencies, as those entries are created by calling the
+pool_createwhatprovides() function. But this function is useful for
+namespace provides if you do not want to use a namespace callback to
+lazily set the provides. The offset argument is a offset in the
+whatprovides array, thus you can use ``1'' as a false value and ``2''
+as true value.
+
void pool_flush_namespaceproviders(Pool *pool, Id ns, Id evr);
Clear the cache of the providers for namespace dependencies matching
$pool->addfileprovides();
$pool->createwhatprovides();
+$pool->set_namespaceproviders($solv::NAMESPACE_LANGUAGE, $pool->Dep('de'), 1);
my @jobs;
for my $arg (@ARGV) {
#ifdef ENABLE_APPDATA
#include "repo_appdata.h"
#endif
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
#include "repoinfo.h"
#include "repoinfo_cache.h"
fclose(fp);
}
#endif
+#ifdef SUSE
+ repo_add_autopattern(repo, 0);
+#endif
data = repo_add_repodata(repo, 0);
repodata_extend_block(data, repo->start, repo->end - repo->start);
repomd_add_ext(repo, data, "deltainfo", "DL");
#ifdef ENABLE_APPDATA
#include "repo_appdata.h"
#endif
+#ifdef SUSE
+#include "repo_autopattern.h"
+#endif
#include "repoinfo.h"
#include "repoinfo_cache.h"
}
#endif
repo_internalize(repo);
+#ifdef SUSE
+ repo_add_autopattern(repo, 0);
+#endif
data = repo_add_repodata(repo, 0);
repodata_extend_block(data, repo->start, repo->end - repo->start);
susetags_add_ext(repo, data);
flags |= SELECTION_WITH_SOURCE;
if (argv[i][0] == '/')
flags |= SELECTION_FILELIST | (mode == MODE_ERASE ? SELECTION_INSTALLED_ONLY : 0);
+ if (keyname && keyname_depstr)
+ flags |= SELECTION_MATCH_DEPSTR;
if (!keyname)
rflags = selection_make(pool, &job2, argv[i], flags);
else
- {
- if (keyname_depstr)
- flags |= SELECTION_MATCH_DEPSTR;
- rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
- }
+ rflags = selection_make_matchdeps(pool, &job2, argv[i], flags, pool_str2id(pool, keyname, 1), 0);
if (repofilter.count)
selection_filter(pool, &job2, &repofilter);
if (archfilter.count)
/*
- * Copyright (c) 2007-2012, Novell Inc.
+ * Copyright (c) 2007-2018, SUSE Inc.
*
* This program is licensed under the BSD license, read LICENSE.BSD
* for further information
#endif
#include <rpm/rpmdb.h>
-#ifndef DB_CREATE
-# if defined(SUSE) || defined(HAVE_RPM_DB_H)
-# include <rpm/db.h>
-# else
-# include <db.h>
-# endif
-#endif
-
#endif
#include "pool.h"
#define TAG_SIGBASE 256
#define TAG_SIGMD5 (TAG_SIGBASE + 5)
#define TAG_SHA1HEADER (TAG_SIGBASE + 13)
+#define TAG_SHA256HEADER (TAG_SIGBASE + 17)
#define SIGTAG_SIZE 1000
#define SIGTAG_PGP 1002 /* RSA signature */
#define DEP_PRE_IN ((1 << 6) | (1 << 9) | (1 << 10))
#define DEP_PRE_UN ((1 << 6) | (1 << 11) | (1 << 12))
-#define FILEFLAG_GHOST (1 << 6)
+#define FILEFLAG_GHOST (1 << 6)
-#ifdef RPM5
-# define RPM_INDEX_SIZE 4 /* just the rpmdbid */
-#else
-# define RPM_INDEX_SIZE 8 /* rpmdbid + array index */
-#endif
-
/* some limits to guard against corrupt rpms */
/* dsize limits taken from rpm's lib/header.c */
#define MAX_SIG_CNT 0x10000
#define MAX_HDR_CNT 0x10000
#define MAX_HDR_DSIZE 0x10000000
+
+#ifndef ENABLE_RPMPKG_LIBRPM
+
typedef struct rpmhead {
int cnt;
unsigned int dcnt;
return headfindtag(h, tag) ? 1 : 0;
}
-static unsigned int *
+static uint32_t *
headint32array(RpmHead *h, int tag, int *cnt)
{
- unsigned int i, o, *r;
+ uint32_t *r;
+ unsigned int i, o;
unsigned char *d = headfindtag(h, tag);
if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 4)
if (o > h->dcnt || i > h->dcnt || o + 4 * i > h->dcnt)
return 0;
d = h->dp + o;
- r = solv_calloc(i ? i : 1, sizeof(unsigned int));
+ r = solv_calloc(i ? i : 1, sizeof(uint32_t));
if (cnt)
*cnt = i;
for (o = 0; o < i; o++, d += 4)
}
/* returns the first entry of an integer array */
-static unsigned int
+static uint32_t
headint32(RpmHead *h, int tag)
{
unsigned int i, o;
return d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
}
-static unsigned long long *
+static uint64_t *
headint64array(RpmHead *h, int tag, int *cnt)
{
+ uint64_t *r;
unsigned int i, o;
- unsigned long long *r;
unsigned char *d = headfindtag(h, tag);
if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 5)
if (o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt)
return 0;
d = h->dp + o;
- r = solv_calloc(i ? i : 1, sizeof(unsigned long long));
+ r = solv_calloc(i ? i : 1, sizeof(uint64_t));
if (cnt)
*cnt = i;
for (o = 0; o < i; o++, d += 8)
{
- unsigned int x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
- r[o] = (unsigned long long)x << 32 | (unsigned int)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
+ uint32_t x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
+ r[o] = (uint64_t)x << 32 | (uint32_t)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
}
return r;
}
/* returns the first entry of an 64bit integer array */
-static unsigned long long
+static uint64_t
headint64(RpmHead *h, int tag)
{
+ uint32_t x;
unsigned int i, o;
unsigned char *d = headfindtag(h, tag);
+
if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 5)
return 0;
o = d[8] << 24 | d[9] << 16 | d[10] << 8 | d[11];
if (i == 0 || o > h->dcnt || i > h->dcnt || o + 8 * i > h->dcnt)
return 0;
d = h->dp + o;
- i = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
- return (unsigned long long)i << 32 | (unsigned int)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
+ x = d[0] << 24 | d[1] << 16 | d[2] << 8 | d[3];
+ return (uint64_t)x << 32 | (uint32_t)(d[4] << 24 | d[5] << 16 | d[6] << 8 | d[7]);
}
-static unsigned int *
+static uint16_t *
headint16array(RpmHead *h, int tag, int *cnt)
{
- unsigned int i, o, *r;
+ uint16_t *r;
+ unsigned int i, o;
unsigned char *d = headfindtag(h, tag);
if (!d || d[4] != 0 || d[5] != 0 || d[6] != 0 || d[7] != 3)
if (o > h->dcnt || i > h->dcnt || o + 2 * i > h->dcnt)
return 0;
d = h->dp + o;
- r = solv_calloc(i ? i : 1, sizeof(unsigned int));
+ r = solv_calloc(i ? i : 1, sizeof(uint16_t));
if (cnt)
*cnt = i;
for (o = 0; o < i; o++, d += 2)
return i == 1 && o < h->dcnt && !h->dp[o] ? 1 : 0;
}
+static inline void
+headfree(RpmHead *h)
+{
+ solv_free(h);
+}
+
+#else
+
+typedef struct headerToken_s RpmHead;
+
+static int
+headexists(RpmHead *h, int tag)
+{
+ return headerIsEntry(h, tag);
+}
+
+static void *headget(RpmHead *h, int tag, int *cnt, int alloc)
+{
+ struct rpmtd_s td;
+ if (!headerGet(h, tag, &td, alloc ? HEADERGET_ALLOC : HEADERGET_MINMEM))
+ return 0;
+ if (cnt)
+ *cnt = td.count;
+ return td.data;
+}
+
+static uint32_t *
+headint32array(RpmHead *h, int tag, int *cnt)
+{
+ return headget(h, tag, cnt, 1);
+}
+
+static uint32_t
+headint32(RpmHead *h, int tag)
+{
+ uint32_t *arr = headget(h, tag, 0, 0);
+ return arr ? arr[0] : 0;
+}
+
+static uint64_t *
+headint64array(RpmHead *h, int tag, int *cnt)
+{
+ return headget(h, tag, cnt, 1);
+}
+
+/* returns the first entry of an 64bit integer array */
+static uint64_t
+headint64(RpmHead *h, int tag)
+{
+ uint64_t *arr = headget(h, tag, 0, 0);
+ return arr ? arr[0] : 0;
+}
+
+static uint16_t *
+headint16array(RpmHead *h, int tag, int *cnt)
+{
+ return headget(h, tag, cnt, 1);
+}
+
+static char *
+headstring(RpmHead *h, int tag)
+{
+ return headget(h, tag, 0, 0);
+}
+
+static char **
+headstringarray(RpmHead *h, int tag, int *cnt)
+{
+ return headget(h, tag, cnt, 1);
+}
+
+static unsigned char *
+headbinary(RpmHead *h, int tag, unsigned int *sizep)
+{
+ return headget(h, tag, (int *)sizep, 0);
+}
+
+static int
+headissourceheuristic(RpmHead *h)
+{
+ return headerIsSource(h);
+}
+
+static inline void
+headfree(RpmHead *h)
+{
+ headerFree(h);
+}
+
+#endif
+
static char *headtoevr(RpmHead *h)
{
unsigned int epoch;
makedeps(Pool *pool, Repo *repo, RpmHead *rpmhead, int tagn, int tagv, int tagf, int flags, Queue *ignq)
{
char **n, **v;
- unsigned int *f;
+ uint32_t *f;
int i, cc, nc, vc, fc;
int haspre, premask, has_ign;
unsigned int olddeps;
}
static void
-adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, unsigned int *di, int fc, int dc)
+adddudata(Repodata *data, Id handle, RpmHead *rpmhead, char **dn, uint32_t *di, int fc, int dc)
{
Id did;
int i, fszc;
- unsigned int *fkb, *fn, *fsz, *fm, *fino;
- unsigned long long *fsz64;
+ unsigned int *fkb, *fn;
+ uint64_t *fsz64;
+ uint32_t *fsz, *fino;
+ uint16_t *fm;
unsigned int inotest[256], inotestok;
if (!fc)
{
char **bn;
char **dn;
- unsigned int *di;
+ uint32_t *di;
int bnc, dnc, dic;
int i;
Id did;
- unsigned int lastdii = -1;
+ uint32_t lastdii = -1;
int lastfiltered = 0;
if (!data)
{
char **cn;
char **cx;
- unsigned int *ct;
+ uint32_t *ct;
int i, cnc, cxc, ctc;
Queue hq;
return dp[0] << 24 | dp[1] << 16 | dp[2] << 8 | dp[3];
}
-
-/******************************************************************/
-/* Rpm Database stuff
- */
-
-struct rpmdbstate {
- Pool *pool;
- char *rootdir;
-
- RpmHead *rpmhead; /* header storage space */
- int rpmheadsize;
-
-#ifdef ENABLE_RPMDB
- int dbopened;
- DB_ENV *dbenv; /* database environment */
- DB *db; /* packages database */
- int byteswapped; /* endianess of packages database */
- int is_ostree; /* read-only db that lives in /usr/share/rpm */
-#endif
-};
-
#ifdef ENABLE_RPMDB
struct rpmdbentry {
#define ENTRIES_BLOCK 255
#define NAMEDATA_BLOCK 1023
-
-static inline Id
-db2rpmdbid(unsigned char *db, int byteswapped)
-{
-#ifdef RPM5
- return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3];
-#else
-# if defined(WORDS_BIGENDIAN)
- if (!byteswapped)
+# ifdef ENABLE_RPMDB_LIBRPM
+# include "repo_rpmdb_librpm.h"
# else
- if (byteswapped)
+# include "repo_rpmdb_bdb.h"
# endif
- return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3];
- else
- return db[3] << 24 | db[2] << 16 | db[1] << 8 | db[0];
-#endif
-}
-static inline void
-rpmdbid2db(unsigned char *db, Id id, int byteswapped)
-{
-#ifdef RPM5
- db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id;
#else
-# if defined(WORDS_BIGENDIAN)
- if (!byteswapped)
-# else
- if (byteswapped)
-# endif
- db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id;
- else
- db[3] = id >> 24, db[2] = id >> 16, db[1] = id >> 8, db[0] = id;
-#endif
-}
-#if defined(FEDORA) || defined(MAGEIA)
-int
-serialize_dbenv_ops(struct rpmdbstate *state)
-{
- char *lpath;
- mode_t oldmask;
- int fd;
- struct flock fl;
-
- lpath = solv_dupjoin(state->rootdir, "/var/lib/rpm/.dbenv.lock", 0);
- oldmask = umask(022);
- fd = open(lpath, (O_RDWR|O_CREAT), 0644);
- free(lpath);
- umask(oldmask);
- if (fd < 0)
- return -1;
- memset(&fl, 0, sizeof(fl));
- fl.l_type = F_WRLCK;
- fl.l_whence = SEEK_SET;
- for (;;)
- {
- if (fcntl(fd, F_SETLKW, &fl) != -1)
- return fd;
- if (errno != EINTR)
- break;
- }
- close(fd);
- return -1;
-}
+/* dummy state just to store pool/rootdir and header data */
+struct rpmdbstate {
+ Pool *pool;
+ char *rootdir;
+
+ RpmHead *rpmhead; /* header storage space */
+ int rpmheadsize;
+};
+
#endif
-/* should look in /usr/lib/rpm/macros instead, but we want speed... */
+
+#ifndef ENABLE_RPMPKG_LIBRPM
+
static int
-opendbenv(struct rpmdbstate *state)
+headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *lead, unsigned int cnt, unsigned int dsize, unsigned int pad, Chksum *chk1, Chksum *chk2)
{
- const char *rootdir = state->rootdir;
- char *dbpath;
- DB_ENV *dbenv = 0;
- int r;
-
- if (db_env_create(&dbenv, 0))
- return pool_error(state->pool, 0, "db_env_create: %s", strerror(errno));
-#if (defined(FEDORA) || defined(MAGEIA)) && (DB_VERSION_MAJOR >= 5 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5))
- dbenv->set_thread_count(dbenv, 8);
-#endif
- dbpath = solv_dupjoin(rootdir, "/var/lib/rpm", 0);
- if (access(dbpath, W_OK) == -1)
- {
- free(dbpath);
- dbpath = solv_dupjoin(rootdir, "/usr/share/rpm/Packages", 0);
- if (access(dbpath, R_OK) == 0)
- state->is_ostree = 1;
- free(dbpath);
- dbpath = solv_dupjoin(rootdir, state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm", 0);
- r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0);
- }
- else
+ RpmHead *rpmhead;
+ unsigned int len = 16 * cnt + dsize + pad;
+ if (len + 1 > state->rpmheadsize)
{
-#if defined(FEDORA) || defined(MAGEIA)
- int serialize_fd = serialize_dbenv_ops(state);
- r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL, 0644);
- if (serialize_fd >= 0)
- close(serialize_fd);
-#else
- r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0);
-#endif
+ state->rpmheadsize = len + 128;
+ state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
}
- if (r)
+ rpmhead = state->rpmhead;
+ if (fread(rpmhead->data, len, 1, fp) != 1)
{
- pool_error(state->pool, 0, "dbenv->open: %s", strerror(errno));
- free(dbpath);
- dbenv->close(dbenv, 0);
- return 0;
+ fclose(fp);
+ return pool_error(state->pool, 0, "%s: unexpected EOF", name);
}
- free(dbpath);
- state->dbenv = dbenv;
+ if (chk1)
+ solv_chksum_add(chk1, rpmhead->data, len);
+ if (chk2)
+ solv_chksum_add(chk2, rpmhead->data, len);
+ rpmhead->data[len] = 0;
+ rpmhead->cnt = cnt;
+ rpmhead->dcnt = dsize;
+ rpmhead->dp = rpmhead->data + cnt * 16;
return 1;
}
+#if defined(ENABLE_RPMDB_BYRPMHEADER)
static void
-closedbenv(struct rpmdbstate *state)
+headfromblob(struct rpmdbstate *state, const unsigned char *blob, unsigned int cnt, unsigned int dsize)
{
-#if defined(FEDORA) || defined(MAGEIA)
- uint32_t eflags = 0;
-#endif
-
- if (!state->dbenv)
- return;
-#if defined(FEDORA) || defined(MAGEIA)
- (void)state->dbenv->get_open_flags(state->dbenv, &eflags);
- if (!(eflags & DB_PRIVATE))
+ RpmHead *rpmhead;
+ unsigned int len = 16 * cnt + dsize;
+ if (len + 1 > state->rpmheadsize)
{
- int serialize_fd = serialize_dbenv_ops(state);
- state->dbenv->close(state->dbenv, 0);
- if (serialize_fd >= 0)
- close(serialize_fd);
+ state->rpmheadsize = len + 128;
+ state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
}
- else
- state->dbenv->close(state->dbenv, 0);
-#else
- state->dbenv->close(state->dbenv, 0);
-#endif
- state->dbenv = 0;
+ rpmhead = state->rpmhead;
+ memcpy(rpmhead->data, blob, len);
+ rpmhead->data[len] = 0;
+ rpmhead->cnt = cnt;
+ rpmhead->dcnt = dsize;
+ rpmhead->dp = rpmhead->data + cnt * 16;
}
+#endif
+
+#else
static int
-stat_database(struct rpmdbstate *state, char *dbname, struct stat *statbuf, int seterror)
+headfromfp(struct rpmdbstate *state, const char *name, FILE *fp, unsigned char *lead, unsigned int cnt, unsigned int dsize, unsigned int pad, Chksum *chk1, Chksum *chk2)
{
- char *dbpath;
- dbpath = solv_dupjoin(state->rootdir, state->is_ostree ? "/usr/share/rpm/" : "/var/lib/rpm/", dbname);
- if (stat(dbpath, statbuf))
- {
- if (seterror)
- pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno));
- free(dbpath);
- return -1;
- }
- free(dbpath);
- return 0;
+ unsigned int len = 16 * cnt + dsize + pad;
+ char *buf = solv_malloc(8 + len);
+ Header h;
+ memcpy(buf, lead + 8, 8);
+ if (fread(buf + 8, len, 1, fp) != 1)
+ {
+ solv_free(buf);
+ return pool_error(state->pool, 0, "%s: unexpected EOF", name);
+ }
+ if (chk1)
+ solv_chksum_add(chk1, buf + 8, len);
+ if (chk2)
+ solv_chksum_add(chk2, buf + 8, len);
+ h = headerImport(buf, 8 + len - pad, HEADERIMPORT_FAST);
+ if (!h)
+ {
+ solv_free(buf);
+ return pool_error(state->pool, 0, "%s: headerImport error", name);
+ }
+ if (state->rpmhead)
+ headfree(state->rpmhead);
+ state->rpmhead = h;
+ return 1;
}
#endif
freestate(struct rpmdbstate *state)
{
/* close down */
- if (!state)
- return;
#ifdef ENABLE_RPMDB
- if (state->db)
- state->db->close(state->db, 0);
- if (state->dbenv)
+ if (state->pkgdbopened)
+ closepkgdb(state);
+ if (state->dbenvopened)
closedbenv(state);
#endif
if (state->rootdir)
solv_free(state->rootdir);
- solv_free(state->rpmhead);
+ headfree(state->rpmhead);
}
void *
void *
rpm_state_free(void *state)
{
- freestate(state);
+ if (state)
+ freestate(state);
return solv_free(state);
}
#ifdef ENABLE_RPMDB
-static int
-openpkgdb(struct rpmdbstate *state)
-{
- if (state->dbopened)
- return state->dbopened > 0 ? 1 : 0;
- state->dbopened = -1;
- if (!state->dbenv && !opendbenv(state))
- return 0;
- if (db_create(&state->db, state->dbenv, 0))
- {
- pool_error(state->pool, 0, "db_create: %s", strerror(errno));
- state->db = 0;
- closedbenv(state);
- return 0;
- }
- if (state->db->open(state->db, 0, "Packages", 0, DB_UNKNOWN, DB_RDONLY, 0664))
- {
- pool_error(state->pool, 0, "db->open Packages: %s", strerror(errno));
- state->db->close(state->db, 0);
- state->db = 0;
- closedbenv(state);
- return 0;
- }
- if (state->db->get_byteswapped(state->db, &state->byteswapped))
- {
- pool_error(state->pool, 0, "db->get_byteswapped: %s", strerror(errno));
- state->db->close(state->db, 0);
- state->db = 0;
- closedbenv(state);
- return 0;
- }
- state->dbopened = 1;
- return 1;
-}
-
-/* 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)
-{
- DB_ENV *dbenv = 0;
- DB *db = 0;
- DBC *dbc = 0;
- int byteswapped;
- DBT dbkey;
- DBT dbdata;
- unsigned char *dp;
- int dl;
- Id nameoff;
-
- char *namedata = 0;
- int namedatal = 0;
- struct rpmdbentry *entries = 0;
- int nentries = 0;
-
- *nentriesp = 0;
- if (namedatap)
- *namedatap = 0;
-
- if (!state->dbenv && !opendbenv(state))
- return 0;
- dbenv = state->dbenv;
- if (db_create(&db, dbenv, 0))
- {
- pool_error(state->pool, 0, "db_create: %s", strerror(errno));
- return 0;
- }
- if (db->open(db, 0, index, 0, DB_UNKNOWN, DB_RDONLY, 0664))
- {
- pool_error(state->pool, 0, "db->open %s: %s", index, strerror(errno));
- db->close(db, 0);
- return 0;
- }
- if (db->get_byteswapped(db, &byteswapped))
- {
- pool_error(state->pool, 0, "db->get_byteswapped: %s", strerror(errno));
- db->close(db, 0);
- return 0;
- }
- if (db->cursor(db, NULL, &dbc, 0))
- {
- pool_error(state->pool, 0, "db->cursor: %s", strerror(errno));
- db->close(db, 0);
- return 0;
- }
- memset(&dbkey, 0, sizeof(dbkey));
- memset(&dbdata, 0, sizeof(dbdata));
- if (match)
- {
- dbkey.data = (void *)match;
- dbkey.size = strlen(match);
- }
- while (dbc->c_get(dbc, &dbkey, &dbdata, match ? DB_SET : DB_NEXT) == 0)
- {
- if (!match && dbkey.size == 10 && !memcmp(dbkey.data, "gpg-pubkey", 10))
- continue;
- dl = dbdata.size;
- dp = dbdata.data;
- nameoff = namedatal;
- if (namedatap)
- {
- namedata = solv_extend(namedata, namedatal, dbkey.size + 1, 1, NAMEDATA_BLOCK);
- memcpy(namedata + namedatal, dbkey.data, dbkey.size);
- namedata[namedatal + dbkey.size] = 0;
- namedatal += dbkey.size + 1;
- }
- while(dl >= RPM_INDEX_SIZE)
- {
- entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK);
- entries[nentries].rpmdbid = db2rpmdbid(dp, byteswapped);
- entries[nentries].nameoff = nameoff;
- nentries++;
- dp += RPM_INDEX_SIZE;
- dl -= RPM_INDEX_SIZE;
- }
- if (match)
- break;
- }
- dbc->c_close(dbc);
- db->close(db, 0);
- /* make sure that enteries is != 0 if there was no error */
- if (!entries)
- entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK);
- *nentriesp = nentries;
- if (namedatap)
- *namedatap = namedata;
- return entries;
-}
-
-/* common code, return dbid on success, -1 on error */
-static int
-getrpm_dbdata(struct rpmdbstate *state, DBT *dbdata, int dbid)
-{
- unsigned int dsize, cnt, l;
- RpmHead *rpmhead;
-
- if (dbdata->size < 8)
- return pool_error(state->pool, -1, "corrupt rpm database (size)");
- cnt = getu32((const unsigned char *)dbdata->data);
- dsize = getu32((const unsigned char *)dbdata->data + 4);
- if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE)
- return pool_error(state->pool, -1, "corrupt rpm database (cnt/dcnt)");
- l = cnt * 16 + dsize;
- if (8 + l > dbdata->size)
- return pool_error(state->pool, -1, "corrupt rpm database (data size)");
- if (l + 1 > state->rpmheadsize)
- {
- state->rpmheadsize = l + 128;
- state->rpmhead = solv_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize);
- }
- rpmhead = state->rpmhead;
- rpmhead->cnt = cnt;
- rpmhead->dcnt = dsize;
- memcpy(rpmhead->data, (unsigned char *)dbdata->data + 8, l);
- rpmhead->data[l] = 0;
- rpmhead->dp = rpmhead->data + cnt * 16;
- return dbid;
-}
-
-/* retrive header by rpmdbid, returns 0 if not found, -1 on error */
-static int
-getrpm_dbid(struct rpmdbstate *state, Id dbid)
-{
- unsigned char buf[4];
- DBT dbkey;
- DBT dbdata;
-
- if (dbid <= 0)
- return pool_error(state->pool, -1, "illegal rpmdbid %d", dbid);
- if (state->dbopened != 1 && !openpkgdb(state))
- return -1;
- rpmdbid2db(buf, dbid, state->byteswapped);
- memset(&dbkey, 0, sizeof(dbkey));
- memset(&dbdata, 0, sizeof(dbdata));
- dbkey.data = buf;
- dbkey.size = 4;
- dbdata.data = 0;
- dbdata.size = 0;
- if (state->db->get(state->db, NULL, &dbkey, &dbdata, 0))
- return 0;
- return getrpm_dbdata(state, &dbdata, dbid);
-}
-
-/* retrive header by berkeleydb cursor, returns 0 on EOF, -1 on error */
-static Id
-getrpm_cursor(struct rpmdbstate *state, DBC *dbc)
-{
- DBT dbkey;
- DBT dbdata;
- Id dbid;
-
- memset(&dbkey, 0, sizeof(dbkey));
- memset(&dbdata, 0, sizeof(dbdata));
- while (dbc->c_get(dbc, &dbkey, &dbdata, DB_NEXT) == 0)
- {
- if (dbkey.size != 4)
- return pool_error(state->pool, -1, "corrupt Packages database (key size)");
- dbid = db2rpmdbid(dbkey.data, state->byteswapped);
- if (dbid) /* ignore join key */
- return getrpm_dbdata(state, &dbdata, dbid);
- }
- return 0;
-}
-
-static int
-count_headers(struct rpmdbstate *state)
-{
- Pool *pool = state->pool;
- struct stat statbuf;
- DB *db = 0;
- DBC *dbc = 0;
- int count = 0;
- DBT dbkey;
- DBT dbdata;
-
- if (stat_database(state, "Name", &statbuf, 0))
- return 0;
- memset(&dbkey, 0, sizeof(dbkey));
- memset(&dbdata, 0, sizeof(dbdata));
- if (db_create(&db, state->dbenv, 0))
- {
- pool_error(pool, 0, "db_create: %s", strerror(errno));
- return 0;
- }
- if (db->open(db, 0, "Name", 0, DB_UNKNOWN, DB_RDONLY, 0664))
- {
- pool_error(pool, 0, "db->open Name: %s", strerror(errno));
- db->close(db, 0);
- return 0;
- }
- if (db->cursor(db, NULL, &dbc, 0))
- {
- db->close(db, 0);
- pool_error(pool, 0, "db->cursor: %s", strerror(errno));
- return 0;
- }
- while (dbc->c_get(dbc, &dbkey, &dbdata, DB_NEXT) == 0)
- count += dbdata.size / RPM_INDEX_SIZE;
- dbc->c_close(dbc);
- db->close(db, 0);
- return count;
-}
/******************************************************************/
{
int solvstart = 0, solvend = 0;
Id dbid;
- DBC *dbc = 0;
if (ref && (flags & RPMDB_EMPTY_REFREPO) != 0)
repo_empty(ref, 1); /* get it out of the way */
freestate(&state);
return -1;
}
- if (state.db->cursor(state.db, NULL, &dbc, 0))
+ if (pkgdb_cursor_open(&state))
{
freestate(&state);
- return pool_error(pool, -1, "db->cursor failed");
+ return -1;
}
i = 0;
s = 0;
- while ((dbid = getrpm_cursor(&state, dbc)) != 0)
+ while ((dbid = pkgdb_cursor_getrpm(&state)) != 0)
{
if (dbid == -1)
{
- dbc->c_close(dbc);
+ pkgdb_cursor_close(&state);
freestate(&state);
return -1;
}
pool_debug(pool, SOLV_ERROR, "%%%% %d\n", done * 100 / count);
}
}
- dbc->c_close(dbc);
+ pkgdb_cursor_close(&state);
if (s)
{
/* oops, could not reuse. free it instead */
return res;
}
-#endif
+#endif /* ENABLE_RPMDB */
Id
repo_add_rpm(Repo *repo, const char *rpm, int flags)
{
- unsigned int sigdsize, sigcnt, l;
+ unsigned int sigdsize, sigcnt, sigpad, l;
Pool *pool = repo->pool;
Solvable *s;
- RpmHead *rpmhead = 0;
- int rpmheadsize = 0;
+ struct rpmdbstate state;
char *payloadformat;
FILE *fp;
unsigned char lead[4096];
else if ((flags & RPM_ADD_WITH_SHA1SUM) != 0)
chksumtype = REPOKEY_TYPE_SHA1;
+ /* open rpm */
if ((fp = fopen(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, rpm) : rpm, "r")) == 0)
{
pool_error(pool, -1, "%s: %s", rpm, strerror(errno));
fclose(fp);
return 0;
}
+
+ /* setup state */
+ memset(&state, 0, sizeof(state));
+ state.pool = pool;
+
+ /* process lead */
if (chksumtype)
chksumh = solv_chksum_create(chksumtype);
if ((flags & RPM_ADD_WITH_LEADSIGID) != 0)
solv_chksum_add(chksumh, lead, 96 + 16);
if (leadsigchksumh)
solv_chksum_add(leadsigchksumh, lead, 96 + 16);
+
+ /* process signature header */
if (lead[78] != 0 || lead[79] != 5)
{
pool_error(pool, -1, "%s: not a rpm v5 header", rpm);
fclose(fp);
return 0;
}
- sigdsize += sigcnt * 16;
- sigdsize = (sigdsize + 7) & ~7;
- headerstart = 96 + 16 + sigdsize;
+ sigpad = sigdsize & 7 ? 8 - (sigdsize & 7) : 0;
+ headerstart = 96 + 16 + sigcnt * 16 + sigdsize + sigpad;
pkgidtype = leadsigidtype = hdridtype = 0;
if ((flags & (RPM_ADD_WITH_PKGID | RPM_ADD_WITH_HDRID)) != 0)
{
- /* extract pkgid or hdrid from the signature header */
- if (sigdsize + 1 > rpmheadsize)
+ if (!headfromfp(&state, rpm, fp, lead + 96, sigcnt, sigdsize, sigpad, chksumh, leadsigchksumh))
{
- rpmheadsize = sigdsize + 128;
- rpmhead = solv_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize);
- }
- if (fread(rpmhead->data, sigdsize, 1, fp) != 1)
- {
- pool_error(pool, -1, "%s: unexpected EOF", rpm);
fclose(fp);
return 0;
}
- rpmhead->data[sigdsize] = 0;
- if (chksumh)
- solv_chksum_add(chksumh, rpmhead->data, sigdsize);
- if (leadsigchksumh)
- solv_chksum_add(leadsigchksumh, rpmhead->data, sigdsize);
- rpmhead->cnt = sigcnt;
- rpmhead->dcnt = sigdsize - sigcnt * 16;
- rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
if ((flags & RPM_ADD_WITH_PKGID) != 0)
{
unsigned char *chksum;
unsigned int chksumsize;
- chksum = headbinary(rpmhead, SIGTAG_MD5, &chksumsize);
+ chksum = headbinary(state.rpmhead, SIGTAG_MD5, &chksumsize);
if (chksum && chksumsize == 16)
{
pkgidtype = REPOKEY_TYPE_MD5;
}
if ((flags & RPM_ADD_WITH_HDRID) != 0)
{
- const char *str = headstring(rpmhead, TAG_SHA1HEADER);
+ const char *str = headstring(state.rpmhead, TAG_SHA1HEADER);
if (str && strlen(str) == 40)
{
if (solv_hex2bin(&str, hdrid, 20) == 20)
else
{
/* just skip the signature header */
- while (sigdsize)
+ unsigned int len = sigcnt * 16 + sigdsize + sigpad;
+ while (len)
{
- l = sigdsize > 4096 ? 4096 : sigdsize;
+ l = len > 4096 ? 4096 : len;
if (fread(lead, l, 1, fp) != 1)
{
pool_error(pool, -1, "%s: unexpected EOF", rpm);
solv_chksum_add(chksumh, lead, l);
if (leadsigchksumh)
solv_chksum_add(leadsigchksumh, lead, l);
- sigdsize -= l;
+ len -= l;
}
}
if (leadsigchksumh)
leadsigchksumh = solv_chksum_free(leadsigchksumh, leadsigid);
leadsigidtype = REPOKEY_TYPE_MD5;
}
+
+ /* process main header */
if (fread(lead, 16, 1, fp) != 1)
{
pool_error(pool, -1, "%s: unexpected EOF", rpm);
fclose(fp);
return 0;
}
- l = sigdsize + sigcnt * 16;
- headerend = headerstart + 16 + l;
- if (l + 1 > rpmheadsize)
- {
- rpmheadsize = l + 128;
- rpmhead = solv_realloc(rpmhead, sizeof(*rpmhead) + rpmheadsize);
- }
- if (fread(rpmhead->data, l, 1, fp) != 1)
+ headerend = headerstart + 16 + sigdsize + sigcnt * 16;
+
+ if (!headfromfp(&state, rpm, fp, lead, sigcnt, sigdsize, 0, chksumh, 0))
{
- pool_error(pool, -1, "%s: unexpected EOF", rpm);
fclose(fp);
return 0;
}
- rpmhead->data[l] = 0;
- if (chksumh)
- solv_chksum_add(chksumh, rpmhead->data, l);
- rpmhead->cnt = sigcnt;
- rpmhead->dcnt = sigdsize;
- rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
- if (headexists(rpmhead, TAG_PATCHESNAME))
+ if (headexists(state.rpmhead, TAG_PATCHESNAME))
{
/* this is a patch rpm, ignore */
pool_error(pool, -1, "%s: is patch rpm", rpm);
fclose(fp);
solv_chksum_free(chksumh, 0);
- solv_free(rpmhead);
+ headfree(state.rpmhead);
return 0;
}
- payloadformat = headstring(rpmhead, TAG_PAYLOADFORMAT);
+ payloadformat = headstring(state.rpmhead, TAG_PAYLOADFORMAT);
if (payloadformat && !strcmp(payloadformat, "drpm"))
{
/* this is a delta rpm */
pool_error(pool, -1, "%s: is delta rpm", rpm);
fclose(fp);
solv_chksum_free(chksumh, 0);
- solv_free(rpmhead);
+ headfree(state.rpmhead);
return 0;
}
if (chksumh)
solv_chksum_add(chksumh, lead, l);
fclose(fp);
s = pool_id2solvable(pool, repo_add_solvable(repo));
- if (!rpmhead2solv(pool, repo, data, s, rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID)))
+ if (!rpmhead2solv(pool, repo, data, s, state.rpmhead, flags & ~(RPM_ADD_WITH_HDRID | RPM_ADD_WITH_PKGID)))
{
repo_free_solvable(repo, s - pool->solvables, 1);
solv_chksum_free(chksumh, 0);
- solv_free(rpmhead);
+ headfree(state.rpmhead);
return 0;
}
if (!(flags & REPO_NO_LOCATION))
repodata_set_bin_checksum(data, s - pool->solvables, SOLVABLE_CHECKSUM, chksumtype, solv_chksum_get(chksumh, 0));
chksumh = solv_chksum_free(chksumh, 0);
}
- solv_free(rpmhead);
+ headfree(state.rpmhead);
if (!(flags & REPO_NO_INTERNALIZE))
repodata_internalize(data);
return s - pool->solvables;
char **dn;
char **md = 0;
char **lt = 0;
- unsigned int *di, diidx;
- unsigned int *co = 0;
- unsigned int *ff = 0;
+ uint32_t *di, diidx;
+ uint32_t *co = 0;
+ uint32_t *ff = 0;
+ uint16_t *fm;
unsigned int lastdir;
int lastdirl;
- unsigned int *fm;
int cnt, dcnt, cnt2;
int i, l1, l;
char *space = 0;
return r <= 0 ? 0 : state->rpmhead;
}
-#endif
+#endif /* ENABLE_RPMDB */
void *
rpm_byfp(void *rpmstate, FILE *fp, const char *name)
{
struct rpmdbstate *state = rpmstate;
- /* int headerstart, headerend; */
- RpmHead *rpmhead;
unsigned int sigdsize, sigcnt, l;
unsigned char lead[4096];
pool_error(state->pool, 0, "%s: not a V5 header", name);
return 0;
}
+
+ /* skip signature header */
if (getu32(lead + 96) != 0x8eade801)
{
pool_error(state->pool, 0, "%s: bad signature header", name);
}
sigdsize += sigcnt * 16;
sigdsize = (sigdsize + 7) & ~7;
- /* headerstart = 96 + 16 + sigdsize; */
while (sigdsize)
{
l = sigdsize > 4096 ? 4096 : sigdsize;
}
sigdsize -= l;
}
+
if (fread(lead, 16, 1, fp) != 1)
{
pool_error(state->pool, 0, "%s: unexpected EOF", name);
pool_error(state->pool, 0, "%s: bad header", name);
return 0;
}
- l = sigdsize + sigcnt * 16;
- /* headerend = headerstart + 16 + l; */
- if (l + 1 > state->rpmheadsize)
- {
- state->rpmheadsize = l + 128;
- state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
- }
- rpmhead = state->rpmhead;
- if (fread(rpmhead->data, l, 1, fp) != 1)
- {
- pool_error(state->pool, 0, "%s: unexpected EOF", name);
- return 0;
- }
- rpmhead->data[l] = 0;
- rpmhead->cnt = sigcnt;
- rpmhead->dcnt = sigdsize;
- rpmhead->dp = rpmhead->data + rpmhead->cnt * 16;
- return rpmhead;
+ if (!headfromfp(state, name, fp, lead, sigcnt, sigdsize, 0, 0, 0))
+ return 0;
+ return state->rpmhead;
}
-#ifdef ENABLE_RPMDB_BYRPMHEADER
+#if defined(ENABLE_RPMDB_BYRPMHEADER) || defined(ENABLE_RPMDB_LIBRPM)
void *
rpm_byrpmh(void *rpmstate, Header h)
{
struct rpmdbstate *state = rpmstate;
+#ifndef ENABLE_RPMPKG_LIBRPM
const unsigned char *uh;
- unsigned int sigdsize, sigcnt, l;
- RpmHead *rpmhead;
+ unsigned int dsize, cnt;
+ if (!h)
+ return 0;
#ifndef RPM5
uh = headerUnload(h);
#else
#endif
if (!uh)
return 0;
- sigcnt = getu32(uh);
- sigdsize = getu32(uh + 4);
- if (sigcnt >= MAX_HDR_CNT || sigdsize >= MAX_HDR_DSIZE)
- return 0;
- l = sigdsize + sigcnt * 16;
- if (l + 1 > state->rpmheadsize)
+ cnt = getu32(uh);
+ dsize = getu32(uh + 4);
+ if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE)
{
- state->rpmheadsize = l + 128;
- state->rpmhead = solv_realloc(state->rpmhead, sizeof(*state->rpmhead) + state->rpmheadsize);
+ free((void *)uh);
+ return 0;
}
- rpmhead = state->rpmhead;
- memcpy(rpmhead->data, uh + 8, l);
- rpmhead->data[l] = 0;
+ headfromblob(state, uh + 8, cnt, dsize);
free((void *)uh);
- rpmhead->cnt = sigcnt;
- rpmhead->dcnt = sigdsize;
- rpmhead->dp = rpmhead->data + sigcnt * 16;
- return rpmhead;
+#else
+ if (!h)
+ return 0;
+ if (state->rpmhead)
+ headfree(state->rpmhead);
+ state->rpmhead = headerLink(h);
+#endif
+ return state->rpmhead;
}
-#endif
+#endif /* defined(ENABLE_RPMDB_BYRPMHEADER) || defined(ENABLE_RPMDB_LIBRPM) */
--- /dev/null
+/*
+ * Copyright (c) 2018 SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo_rpmdb_bdb.h
+ *
+ * Use BerkeleyDB to access the rpm database
+ *
+ */
+
+
+#if !defined(DB_CREATE) && !defined(ENABLE_RPMDB_LIBRPM)
+# if defined(SUSE) || defined(HAVE_RPM_DB_H)
+# include <rpm/db.h>
+# else
+# include <db.h>
+# endif
+#endif
+
+#ifdef RPM5
+# define RPM_INDEX_SIZE 4 /* just the rpmdbid */
+#else
+# define RPM_INDEX_SIZE 8 /* rpmdbid + array index */
+#endif
+
+
+/******************************************************************/
+/* Rpm Database stuff
+ */
+
+struct rpmdbstate {
+ Pool *pool;
+ char *rootdir;
+
+ RpmHead *rpmhead; /* header storage space */
+ int rpmheadsize;
+
+ int dbenvopened; /* database environment opened */
+ int pkgdbopened; /* package database openend */
+ int is_ostree; /* read-only db that lives in /usr/share/rpm */
+
+ DB_ENV *dbenv; /* database environment */
+ DB *db; /* packages database */
+ int byteswapped; /* endianess of packages database */
+ DBC *dbc; /* iterator over packages database */
+};
+
+
+static int
+stat_database(struct rpmdbstate *state, char *dbname, struct stat *statbuf, int seterror)
+{
+ char *dbpath;
+ dbpath = solv_dupjoin(state->rootdir, state->is_ostree ? "/usr/share/rpm/" : "/var/lib/rpm/", dbname);
+ if (stat(dbpath, statbuf))
+ {
+ if (seterror)
+ pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno));
+ free(dbpath);
+ return -1;
+ }
+ free(dbpath);
+ return 0;
+}
+
+
+static inline Id
+db2rpmdbid(unsigned char *db, int byteswapped)
+{
+#ifdef RPM5
+ return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3];
+#else
+# if defined(WORDS_BIGENDIAN)
+ if (!byteswapped)
+# else
+ if (byteswapped)
+# endif
+ return db[0] << 24 | db[1] << 16 | db[2] << 8 | db[3];
+ else
+ return db[3] << 24 | db[2] << 16 | db[1] << 8 | db[0];
+#endif
+}
+
+static inline void
+rpmdbid2db(unsigned char *db, Id id, int byteswapped)
+{
+#ifdef RPM5
+ db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id;
+#else
+# if defined(WORDS_BIGENDIAN)
+ if (!byteswapped)
+# else
+ if (byteswapped)
+# endif
+ db[0] = id >> 24, db[1] = id >> 16, db[2] = id >> 8, db[3] = id;
+ else
+ db[3] = id >> 24, db[2] = id >> 16, db[1] = id >> 8, db[0] = id;
+#endif
+}
+
+#if defined(FEDORA) || defined(MAGEIA)
+static int
+serialize_dbenv_ops(struct rpmdbstate *state)
+{
+ char *lpath;
+ mode_t oldmask;
+ int fd;
+ struct flock fl;
+
+ lpath = solv_dupjoin(state->rootdir, "/var/lib/rpm/.dbenv.lock", 0);
+ oldmask = umask(022);
+ fd = open(lpath, (O_RDWR|O_CREAT), 0644);
+ free(lpath);
+ umask(oldmask);
+ if (fd < 0)
+ return -1;
+ memset(&fl, 0, sizeof(fl));
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ for (;;)
+ {
+ if (fcntl(fd, F_SETLKW, &fl) != -1)
+ return fd;
+ if (errno != EINTR)
+ break;
+ }
+ close(fd);
+ return -1;
+}
+
+#endif
+
+/* should look in /usr/lib/rpm/macros instead, but we want speed... */
+static int
+opendbenv(struct rpmdbstate *state)
+{
+ const char *rootdir = state->rootdir;
+ char *dbpath;
+ DB_ENV *dbenv = 0;
+ int r;
+
+ if (db_env_create(&dbenv, 0))
+ return pool_error(state->pool, 0, "db_env_create: %s", strerror(errno));
+#if (defined(FEDORA) || defined(MAGEIA)) && (DB_VERSION_MAJOR >= 5 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5))
+ dbenv->set_thread_count(dbenv, 8);
+#endif
+ dbpath = solv_dupjoin(rootdir, "/var/lib/rpm", 0);
+ if (access(dbpath, W_OK) == -1)
+ {
+ free(dbpath);
+ dbpath = solv_dupjoin(rootdir, "/usr/share/rpm/Packages", 0);
+ if (access(dbpath, R_OK) == 0)
+ state->is_ostree = 1;
+ free(dbpath);
+ dbpath = solv_dupjoin(rootdir, state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm", 0);
+ r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0);
+ }
+ else
+ {
+#if defined(FEDORA) || defined(MAGEIA)
+ int serialize_fd = serialize_dbenv_ops(state);
+ int eflags = DB_CREATE|DB_INIT_CDB|DB_INIT_MPOOL;
+ r = dbenv->open(dbenv, dbpath, eflags, 0644);
+ /* see rpm commit 2822ccbcdf3e898b960fafb23c4d571e26cef0a4 */
+ if (r == DB_VERSION_MISMATCH)
+ {
+ eflags |= DB_PRIVATE;
+ dbenv->errx(dbenv, "warning: DB_VERSION_MISMATCH, retrying with DB_PRIVATE");
+ r = dbenv->open(dbenv, dbpath, eflags, 0644);
+ }
+ if (serialize_fd >= 0)
+ close(serialize_fd);
+#else
+ r = dbenv->open(dbenv, dbpath, DB_CREATE|DB_PRIVATE|DB_INIT_MPOOL, 0);
+#endif
+ }
+ if (r)
+ {
+ pool_error(state->pool, 0, "dbenv->open: %s", strerror(errno));
+ free(dbpath);
+ dbenv->close(dbenv, 0);
+ return 0;
+ }
+ free(dbpath);
+ state->dbenv = dbenv;
+ state->dbenvopened = 1;
+ return 1;
+}
+
+static void
+closedbenv(struct rpmdbstate *state)
+{
+#if defined(FEDORA) || defined(MAGEIA)
+ uint32_t eflags = 0;
+#endif
+
+ if (!state->dbenv)
+ return;
+#if defined(FEDORA) || defined(MAGEIA)
+ (void)state->dbenv->get_open_flags(state->dbenv, &eflags);
+ if (!(eflags & DB_PRIVATE))
+ {
+ int serialize_fd = serialize_dbenv_ops(state);
+ state->dbenv->close(state->dbenv, 0);
+ if (serialize_fd >= 0)
+ close(serialize_fd);
+ }
+ else
+ state->dbenv->close(state->dbenv, 0);
+#else
+ state->dbenv->close(state->dbenv, 0);
+#endif
+ state->dbenv = 0;
+ state->dbenvopened = 0;
+}
+
+static int
+openpkgdb(struct rpmdbstate *state)
+{
+ if (state->pkgdbopened)
+ return state->pkgdbopened > 0 ? 1 : 0;
+ state->pkgdbopened = -1;
+ if (state->dbenvopened != 1 && !opendbenv(state))
+ return 0;
+ if (db_create(&state->db, state->dbenv, 0))
+ {
+ pool_error(state->pool, 0, "db_create: %s", strerror(errno));
+ state->db = 0;
+ closedbenv(state);
+ return 0;
+ }
+ if (state->db->open(state->db, 0, "Packages", 0, DB_UNKNOWN, DB_RDONLY, 0664))
+ {
+ pool_error(state->pool, 0, "db->open Packages: %s", strerror(errno));
+ state->db->close(state->db, 0);
+ state->db = 0;
+ closedbenv(state);
+ return 0;
+ }
+ if (state->db->get_byteswapped(state->db, &state->byteswapped))
+ {
+ pool_error(state->pool, 0, "db->get_byteswapped: %s", strerror(errno));
+ state->db->close(state->db, 0);
+ state->db = 0;
+ closedbenv(state);
+ return 0;
+ }
+ state->pkgdbopened = 1;
+ return 1;
+}
+
+static void
+closepkgdb(struct rpmdbstate *state)
+{
+ if (!state->db)
+ return;
+ state->db->close(state->db, 0);
+ state->db = 0;
+ state->pkgdbopened = 0;
+}
+
+/* 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)
+{
+ DB_ENV *dbenv = 0;
+ DB *db = 0;
+ DBC *dbc = 0;
+ int byteswapped;
+ DBT dbkey;
+ DBT dbdata;
+ unsigned char *dp;
+ int dl;
+ Id nameoff;
+
+ char *namedata = 0;
+ int namedatal = 0;
+ struct rpmdbentry *entries = 0;
+ int nentries = 0;
+
+ *nentriesp = 0;
+ if (namedatap)
+ *namedatap = 0;
+
+ if (state->dbenvopened != 1 && !opendbenv(state))
+ return 0;
+ dbenv = state->dbenv;
+ if (db_create(&db, dbenv, 0))
+ {
+ pool_error(state->pool, 0, "db_create: %s", strerror(errno));
+ return 0;
+ }
+ if (db->open(db, 0, index, 0, DB_UNKNOWN, DB_RDONLY, 0664))
+ {
+ pool_error(state->pool, 0, "db->open %s: %s", index, strerror(errno));
+ db->close(db, 0);
+ return 0;
+ }
+ if (db->get_byteswapped(db, &byteswapped))
+ {
+ pool_error(state->pool, 0, "db->get_byteswapped: %s", strerror(errno));
+ db->close(db, 0);
+ return 0;
+ }
+ if (db->cursor(db, NULL, &dbc, 0))
+ {
+ pool_error(state->pool, 0, "db->cursor: %s", strerror(errno));
+ db->close(db, 0);
+ return 0;
+ }
+ memset(&dbkey, 0, sizeof(dbkey));
+ memset(&dbdata, 0, sizeof(dbdata));
+ if (match)
+ {
+ dbkey.data = (void *)match;
+ dbkey.size = strlen(match);
+ }
+ while (dbc->c_get(dbc, &dbkey, &dbdata, match ? DB_SET : DB_NEXT) == 0)
+ {
+ if (!match && dbkey.size == 10 && !memcmp(dbkey.data, "gpg-pubkey", 10))
+ continue;
+ dl = dbdata.size;
+ dp = dbdata.data;
+ nameoff = namedatal;
+ if (namedatap)
+ {
+ namedata = solv_extend(namedata, namedatal, dbkey.size + 1, 1, NAMEDATA_BLOCK);
+ memcpy(namedata + namedatal, dbkey.data, dbkey.size);
+ namedata[namedatal + dbkey.size] = 0;
+ namedatal += dbkey.size + 1;
+ }
+ while(dl >= RPM_INDEX_SIZE)
+ {
+ entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK);
+ entries[nentries].rpmdbid = db2rpmdbid(dp, byteswapped);
+ entries[nentries].nameoff = nameoff;
+ nentries++;
+ dp += RPM_INDEX_SIZE;
+ dl -= RPM_INDEX_SIZE;
+ }
+ if (match)
+ break;
+ }
+ dbc->c_close(dbc);
+ db->close(db, 0);
+ /* make sure that enteries is != 0 if there was no error */
+ if (!entries)
+ entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK);
+ *nentriesp = nentries;
+ if (namedatap)
+ *namedatap = namedata;
+ return entries;
+}
+
+/* common code, return dbid on success, -1 on error */
+static int
+getrpm_dbdata(struct rpmdbstate *state, DBT *dbdata, int dbid)
+{
+ unsigned int dsize, cnt, l;
+ RpmHead *rpmhead;
+
+ if (dbdata->size < 8)
+ return pool_error(state->pool, -1, "corrupt rpm database (size)");
+ cnt = getu32((const unsigned char *)dbdata->data);
+ dsize = getu32((const unsigned char *)dbdata->data + 4);
+ if (cnt >= MAX_HDR_CNT || dsize >= MAX_HDR_DSIZE)
+ return pool_error(state->pool, -1, "corrupt rpm database (cnt/dcnt)");
+ l = cnt * 16 + dsize;
+ if (8 + l > dbdata->size)
+ return pool_error(state->pool, -1, "corrupt rpm database (data size)");
+ if (l + 1 > state->rpmheadsize)
+ {
+ state->rpmheadsize = l + 128;
+ state->rpmhead = solv_realloc(state->rpmhead, sizeof(*rpmhead) + state->rpmheadsize);
+ }
+ rpmhead = state->rpmhead;
+ rpmhead->cnt = cnt;
+ rpmhead->dcnt = dsize;
+ memcpy(rpmhead->data, (unsigned char *)dbdata->data + 8, l);
+ rpmhead->data[l] = 0;
+ rpmhead->dp = rpmhead->data + cnt * 16;
+ return dbid;
+}
+
+/* retrive header by rpmdbid, returns 0 if not found, -1 on error */
+static int
+getrpm_dbid(struct rpmdbstate *state, Id dbid)
+{
+ unsigned char buf[4];
+ DBT dbkey;
+ DBT dbdata;
+
+ if (dbid <= 0)
+ return pool_error(state->pool, -1, "illegal rpmdbid %d", dbid);
+ if (state->pkgdbopened != 1 && !openpkgdb(state))
+ return -1;
+ rpmdbid2db(buf, dbid, state->byteswapped);
+ memset(&dbkey, 0, sizeof(dbkey));
+ memset(&dbdata, 0, sizeof(dbdata));
+ dbkey.data = buf;
+ dbkey.size = 4;
+ dbdata.data = 0;
+ dbdata.size = 0;
+ if (state->db->get(state->db, NULL, &dbkey, &dbdata, 0))
+ return 0;
+ return getrpm_dbdata(state, &dbdata, dbid);
+}
+
+static int
+count_headers(struct rpmdbstate *state)
+{
+ Pool *pool = state->pool;
+ struct stat statbuf;
+ DB *db = 0;
+ DBC *dbc = 0;
+ int count = 0;
+ DBT dbkey;
+ DBT dbdata;
+
+ if (stat_database(state, "Name", &statbuf, 0))
+ return 0;
+ memset(&dbkey, 0, sizeof(dbkey));
+ memset(&dbdata, 0, sizeof(dbdata));
+ if (db_create(&db, state->dbenv, 0))
+ {
+ pool_error(pool, 0, "db_create: %s", strerror(errno));
+ return 0;
+ }
+ if (db->open(db, 0, "Name", 0, DB_UNKNOWN, DB_RDONLY, 0664))
+ {
+ pool_error(pool, 0, "db->open Name: %s", strerror(errno));
+ db->close(db, 0);
+ return 0;
+ }
+ if (db->cursor(db, NULL, &dbc, 0))
+ {
+ db->close(db, 0);
+ pool_error(pool, 0, "db->cursor: %s", strerror(errno));
+ return 0;
+ }
+ while (dbc->c_get(dbc, &dbkey, &dbdata, DB_NEXT) == 0)
+ count += dbdata.size / RPM_INDEX_SIZE;
+ dbc->c_close(dbc);
+ db->close(db, 0);
+ return count;
+}
+
+static int
+pkgdb_cursor_open(struct rpmdbstate *state)
+{
+ if (state->db->cursor(state->db, NULL, &state->dbc, 0))
+ return pool_error(state->pool, -1, "db->cursor failed");
+ return 0;
+}
+
+static void
+pkgdb_cursor_close(struct rpmdbstate *state)
+{
+ state->dbc->c_close(state->dbc);
+ state->dbc = 0;
+}
+
+/* retrive header by berkeleydb cursor, returns 0 on EOF, -1 on error */
+static Id
+pkgdb_cursor_getrpm(struct rpmdbstate *state)
+{
+ DBT dbkey;
+ DBT dbdata;
+ Id dbid;
+
+ memset(&dbkey, 0, sizeof(dbkey));
+ memset(&dbdata, 0, sizeof(dbdata));
+ while (state->dbc->c_get(state->dbc, &dbkey, &dbdata, DB_NEXT) == 0)
+ {
+ if (dbkey.size != 4)
+ return pool_error(state->pool, -1, "corrupt Packages database (key size)");
+ dbid = db2rpmdbid(dbkey.data, state->byteswapped);
+ if (dbid) /* ignore join key */
+ return getrpm_dbdata(state, &dbdata, dbid);
+ }
+ return 0; /* no more entries */
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2018, SUSE Inc.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * repo_rpmdb_librpm.h
+ *
+ * Use librpm to access the rpm database
+ *
+ */
+
+#include <rpm/rpmts.h>
+#include <rpm/rpmmacro.h>
+
+struct rpmdbstate {
+ Pool *pool;
+ char *rootdir;
+
+ RpmHead *rpmhead; /* header storage space */
+ int rpmheadsize;
+
+ int dbenvopened; /* database environment opened */
+ int pkgdbopened; /* package database openend */
+ int is_ostree; /* read-only db that lives in /usr/share/rpm */
+
+ rpmts ts;
+ rpmdbMatchIterator mi; /* iterator over packages database */
+};
+
+static int
+stat_database(struct rpmdbstate *state, char *dbname, struct stat *statbuf, int seterror)
+{
+ char *dbpath;
+ dbpath = solv_dupjoin(state->rootdir, state->is_ostree ? "/usr/share/rpm/" : "/var/lib/rpm/", dbname);
+ if (stat(dbpath, statbuf))
+ {
+ if (seterror)
+ pool_error(state->pool, -1, "%s: %s", dbpath, strerror(errno));
+ free(dbpath);
+ return -1;
+ }
+ free(dbpath);
+ return 0;
+}
+
+static int
+opendbenv(struct rpmdbstate *state)
+{
+ const char *rootdir = state->rootdir;
+ rpmts ts;
+ char *dbpath;
+ dbpath = solv_dupjoin("_dbpath ", rootdir, "/var/lib/rpm");
+ if (access(dbpath + 8, W_OK) == -1)
+ {
+ free(dbpath);
+ dbpath = solv_dupjoin(rootdir, "/usr/share/rpm/Packages", 0);
+ if (access(dbpath, R_OK) == 0)
+ state->is_ostree = 1;
+ free(dbpath);
+ dbpath = solv_dupjoin("_dbpath ", rootdir, state->is_ostree ? "/usr/share/rpm" : "/var/lib/rpm");
+ }
+ rpmDefineMacro(NULL, dbpath, 0);
+ solv_free(dbpath);
+ ts = rpmtsCreate();
+ if (!ts)
+ {
+ pool_error(state->pool, 0, "rpmtsCreate failed");
+ delMacro(NULL, "_dbpath");
+ return 0;
+ }
+ if (rpmtsOpenDB(ts, O_RDONLY))
+ {
+ pool_error(state->pool, 0, "rpmtsOpenDB failed: %s", strerror(errno));
+ rpmtsFree(ts);
+ delMacro(NULL, "_dbpath");
+ return 0;
+ }
+ delMacro(NULL, "_dbpath");
+ rpmtsSetVSFlags(ts, _RPMVSF_NODIGESTS | _RPMVSF_NOSIGNATURES | _RPMVSF_NOHEADER);
+ state->ts = ts;
+ state->dbenvopened = 1;
+ state->pkgdbopened = 1;
+ return 1;
+}
+
+static void
+closedbenv(struct rpmdbstate *state)
+{
+ if (state->ts)
+ rpmtsFree(state->ts);
+ state->ts = 0;
+ state->pkgdbopened = 0;
+ state->dbenvopened = 0;
+}
+
+static int
+openpkgdb(struct rpmdbstate *state)
+{
+ /* already done in opendbenv */
+ return 1;
+}
+
+static void
+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)
+{
+ const void * key;
+ size_t keylen;
+ Id nameoff;
+
+ char *namedata = 0;
+ int namedatal = 0;
+ struct rpmdbentry *entries = 0;
+ int nentries = 0;
+
+ rpmdbIndexIterator ii;
+ int i;
+
+ if (state->dbenvopened != 1 && !opendbenv(state))
+ return 0;
+
+ 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;
+ nameoff = namedatal;
+ if (namedatap)
+ {
+ namedata = solv_extend(namedata, namedatal, keylen + 1, 1, NAMEDATA_BLOCK);
+ memcpy(namedata + namedatal, key, keylen);
+ namedata[namedatal + keylen] = 0;
+ namedatal += keylen + 1;
+ }
+ for (i = 0; i < rpmdbIndexIteratorNumPkgs(ii); i++)
+ {
+ entries = solv_extend(entries, nentries, 1, sizeof(*entries), ENTRIES_BLOCK);
+ entries[nentries].rpmdbid = rpmdbIndexIteratorPkgOffset(ii, i);
+ entries[nentries].nameoff = nameoff;
+ nentries++;
+ }
+ }
+ rpmdbIndexIteratorFree(ii);
+ /* make sure that enteries is != 0 if there was no error */
+ if (!entries)
+ entries = solv_extend(entries, 1, 1, sizeof(*entries), ENTRIES_BLOCK);
+ *nentriesp = nentries;
+ if (namedatap)
+ *namedatap = namedata;
+ return entries;
+}
+
+/* retrive header by rpmdbid, returns 0 if not found, -1 on error */
+static int
+getrpm_dbid(struct rpmdbstate *state, Id rpmdbid)
+{
+ Header h;
+ rpmdbMatchIterator mi;
+ unsigned int offset = rpmdbid;
+
+ if (state->dbenvopened != 1 && !opendbenv(state))
+ return -1;
+ mi = rpmtsInitIterator(state->ts, RPMDBI_PACKAGES, &offset, sizeof(offset));
+ h = rpmdbNextIterator(mi);
+ if (!h)
+ {
+ rpmdbFreeIterator(mi);
+ return 0;
+ }
+ if (!rpm_byrpmh(state, h))
+ {
+ rpmdbFreeIterator(mi);
+ return -1;
+ }
+ mi = rpmdbFreeIterator(mi);
+ return 1;
+}
+
+static int
+count_headers(struct rpmdbstate *state)
+{
+ int count;
+ rpmdbMatchIterator mi;
+
+ if (state->dbenvopened != 1 && !opendbenv(state))
+ return 0;
+ mi = rpmtsInitIterator(state->ts, RPMDBI_NAME, NULL, 0);
+ count = rpmdbGetIteratorCount(mi);
+ rpmdbFreeIterator(mi);
+ return count;
+}
+
+static int
+pkgdb_cursor_open(struct rpmdbstate *state)
+{
+ state->mi = rpmtsInitIterator(state->ts, RPMDBI_PACKAGES, NULL, 0);
+ return 0;
+}
+
+static void
+pkgdb_cursor_close(struct rpmdbstate *state)
+{
+ rpmdbFreeIterator(state->mi);
+ state->mi = 0;
+}
+
+static Id
+pkgdb_cursor_getrpm(struct rpmdbstate *state)
+{
+ Header h;
+ while ((h = rpmdbNextIterator(state->mi)))
+ {
+ Id dbid = rpmdbGetIteratorOffset(state->mi);
+ if (!rpm_byrpmh(state, h))
+ continue;
+ return dbid;
+ }
+ return 0;
+}
+
if (suf && !strcmp(suf, ".gz"))
return mygzfdopen(fd, simplemode);
#else
- return 0;
if (suf && !strcmp(suf, ".gz"))
+ return 0;
#endif
#ifdef ENABLE_LZMA_COMPRESSION
if (suf && !strcmp(suf, ".xz"))
{ TESTCASE_RESULT_GENID, "genid" },
{ TESTCASE_RESULT_REASON, "reason" },
{ TESTCASE_RESULT_CLEANDEPS, "cleandeps" },
+ { TESTCASE_RESULT_JOBS, "jobs" },
{ 0, 0 }
};
{ SELECTION_NOCASE, "nocase" },
{ SELECTION_SOURCE_ONLY, "sourceonly" },
{ SELECTION_WITH_SOURCE, "withsource" },
+ { SELECTION_SKIP_KIND, "skipkind" },
+ { SELECTION_MATCH_DEPSTR, "depstr" },
+ { SELECTION_WITH_DISABLED, "withdisabled" },
+ { SELECTION_WITH_BADARCH, "withbadarch" },
{ 0, 0 }
};
}
static int
-addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue)
+addselectionjob(Pool *pool, char **pieces, int npieces, Queue *jobqueue, int keyname)
{
Id job;
int i, r;
int selflags;
Queue sel;
+ char *sp;
for (i = 0; job2str[i].str; i++)
if (!strcmp(pieces[0], job2str[i].str))
}
if (npieces < 4)
return pool_error(pool, -1, "selstr2job: no selection flags");
- selflags = str2selflags(pool, pieces[3]);
+ selflags = str2selflags(pool, pieces[npieces - 1]);
+ /* re-join pieces */
+ for (sp = pieces[2]; sp < pieces[npieces - 2]; sp++)
+ if (*sp == 0)
+ *sp = ' ';
queue_init(&sel);
- r = selection_make(pool, &sel, pieces[2], selflags);
+ if (keyname > 0)
+ r = selection_make_matchdeps(pool, &sel, pieces[2], selflags, keyname, 0);
+ else if (keyname < 0)
+ r = selection_make_matchdepid(pool, &sel, testcase_str2dep(pool, pieces[2]), selflags, -keyname, 0);
+ else
+ r = selection_make(pool, &sel, pieces[2], selflags);
for (i = 0; i < sel.count; i += 2)
queue_push2(jobqueue, job | sel.elements[i], sel.elements[i + 1]);
queue_free(&sel);
if (*line != '=' || !line[1] || !line[2] || !line[3] || line[4] != ':')
continue;
tag = line[1] << 16 | line[2] << 8 | line[3];
+ /* tags that do not need a solvable */
switch(tag)
- {
+ {
case 'V' << 16 | 'e' << 8 | 'r':
tagsversion = atoi(line + 6);
addselfprovides = tagsversion < 3 || strstr(line + 6, "addselfprovides") != 0;
- break;
+ continue;
case 'P' << 16 | 'k' << 8 | 'g':
if (s)
{
sp[2][-1] = '-';
s->evr = makeevr(pool, sp[1]);
s->arch = pool_str2id(pool, sp[3], 1);
+ continue;
+ default:
break;
+ }
+ if (!s)
+ continue;
+ /* tags that need a solvable */
+ switch(tag)
+ {
case 'S' << 16 | 'u' << 8 | 'm':
repodata_set_str(data, s - pool->solvables, SOLVABLE_SUMMARY, line + 6);
break;
}
queue_free(&q);
}
+ if ((resultflags & TESTCASE_RESULT_JOBS) != 0)
+ {
+ for (i = 0; i < solv->job.count; i += 2)
+ {
+ s = (char *)testcase_job2str(pool, solv->job.elements[i], solv->job.elements[i + 1]);
+ s = pool_tmpjoin(pool, "job ", s, 0);
+ strqueue_push(&sq, s);
+ }
+ }
strqueue_sort(&sq);
result = strqueue_join(&sq);
strqueue_free(&sq);
}
if (npieces >= 3 && !strcmp(pieces[2], "selection"))
{
- addselectionjob(pool, pieces + 1, npieces - 1, job);
+ addselectionjob(pool, pieces + 1, npieces - 1, job, 0);
+ continue;
+ }
+ if (npieces >= 4 && !strcmp(pieces[2], "selection_matchdeps"))
+ {
+ pieces[2] = pieces[1];
+ addselectionjob(pool, pieces + 2, npieces - 2, job, pool_str2id(pool, pieces[3], 1));
+ continue;
+ }
+ if (npieces >= 4 && !strcmp(pieces[2], "selection_matchdepid"))
+ {
+ pieces[2] = pieces[1];
+ addselectionjob(pool, pieces + 2, npieces - 2, job, -pool_str2id(pool, pieces[3], 1));
continue;
}
/* rejoin */
#define TESTCASE_RESULT_GENID (1 << 7)
#define TESTCASE_RESULT_REASON (1 << 8)
#define TESTCASE_RESULT_CLEANDEPS (1 << 9)
+#define TESTCASE_RESULT_JOBS (1 << 10)
/* reuse solver hack, testsolv use only */
#define TESTCASE_RESULT_REUSE_SOLVER (1 << 31)
-------------------------------------------------------------------
+Wed Jan 31 11:41:51 CET 2018 - mls@suse.de
+
+- new ENABLE_RPMDB_LIBRPM/ENABLE_RPMPKG_LIBRPM config options
+- new pool_set_whatprovides function to change the whatprovides
+ data
+- much improved selection code
+- bump version to 0.6.31
+
+-------------------------------------------------------------------
+Tue Oct 24 12:09:32 UTC 2017 - jengelh@inai.de
+
+- Update package descriptions and groups.
+ Replace old $RPM_* variables by macros.
+
+-------------------------------------------------------------------
Mon Oct 23 11:40:22 CEST 2017 - mls@suse.de
- many fixes and improvements for cleandeps
- support debian packages with xz compressed control.tar
- always create dup rules for "distupgrade" jobs
- use recommends also for ordering packages
+- Fix splitprovides handling with addalreadyrecommended turned off
+ [bnc#1059065]
- bump version to 0.6.30
-------------------------------------------------------------------
#
# spec file for package libsolv
#
-# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany.
+# Copyright (c) 2017 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
%endif
-Summary: A new approach to package dependency solving
+Summary: Package dependency solver using a satisfiability algorithm
License: BSD-3-Clause
Group: Development/Libraries/C and C++
%description
-A new approach to package dependency solving
+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@
-Summary: A new approach to package dependency solving
-Group: Development/Libraries/C and C++
+Summary: Package dependency solver using a satisfiability algorithm
+Group: System/Libraries
%description -n libsolv@LIBSOLV_SOVERSION@
-A new approach to package dependency solving
+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
+so-called satisfiability algorithm for resolving package
+dependencies.
%endif
%package devel
-Summary: A new approach to package dependency solving
+Summary: Development files for libsolv, a package solver
Group: Development/Libraries/C and C++
%if !%{with disable_shared}
Requires: libsolv@LIBSOLV_SOVERSION@ = %version
Conflicts: libsatsolver-devel
%description devel
-Development files for libsolv, a new approach to package dependency solving
+Development files for libsolv, a library for solving packages and
+reading repositories.
%package tools
-Summary: A new approach to package dependency solving
-Group: Development/Libraries/C and C++
+Summary: Utilities to work with .solv files
+Group: System/Management
Obsoletes: satsolver-tools < 0.18
Provides: satsolver-tools = 0.18
Conflicts: satsolver-tools-obsolete
Requires: gzip bzip2 coreutils findutils
%description tools
-A new approach to package dependency solving.
+libsolv is a library for solving packages and reading repositories.
+
+This subpackage contains utilities to create and work with the .solv
+files used by libsolv.
%package demo
Summary: Applications demoing the libsolv library
Group: Development/Languages/Ruby
%description -n ruby-solv
-Ruby bindings for sat solver.
+Ruby bindings for libsolv.
%package -n python-solv
%if 0%{?py_requires:1} && %{with python_binding}
Group: Development/Languages/Python
%description -n python-solv
-Python bindings for sat solver.
+Python bindings for libsolv.
%package -n python3-solv
Summary: Python3 bindings for the libsolv library
Group: Development/Languages/Python
%description -n python3-solv
-Python3 bindings for sat solver.
+Python3 bindings for libsolv.
%package -n perl-solv
Requires: perl = %{perl_version}
Group: Development/Languages/Perl
%description -n perl-solv
-Perl bindings for sat solver.
+Perl bindings for libsolv.
%prep
%setup -n libsolv-%{version}
%build
-export CFLAGS="$RPM_OPT_FLAGS"
+export CFLAGS="%{optflags}"
export CXXFLAGS="$CFLAGS"
CMAKE_FLAGS=
make %{?_smp_mflags}
%install
-make DESTDIR=$RPM_BUILD_ROOT install
+make DESTDIR=%{buildroot} install
%if 0%{?suse_version}
%if %{with python_binding}
-pushd $RPM_BUILD_ROOT/%{python_sitearch}
+pushd %{buildroot}/%{python_sitearch}
python %py_libdir/py_compile.py *.py
python -O %py_libdir/py_compile.py *.py
popd
%endif
%if %{with python3_binding}
-%py3_compile $RPM_BUILD_ROOT/%{python3_sitearch}
+%py3_compile %{buildroot}/%{python3_sitearch}
%endif
%endif
%if %{with disable_shared}
export NO_BRP_STRIP_DEBUG=true
%endif
-%clean
-rm -rf "$RPM_BUILD_ROOT"
-
%if !%{with disable_shared}
%post -n libsolv@LIBSOLV_SOVERSION@ -p /sbin/ldconfig
queue.c repo.c repodata.c repopage.c util.c policy.c solvable.c
transaction.c order.c rules.c problems.c linkedpkg.c cplxdeps.c
chksum.c md5.c sha1.c sha2.c solvversion.c selection.c
- fileprovides.c diskusage.c suse.c solver_util.c cleandeps.c)
+ fileprovides.c diskusage.c suse.c solver_util.c cleandeps.c
+ userinstalled.c)
SET (libsolv_HEADERS
bitmap.h evr.h hash.h policy.h poolarch.h poolvendor.h pool.h
void
map_and(Map *t, Map *s)
{
- unsigned char *ti, *si, *end;
- ti = t->map;
- si = s->map;
- end = ti + (t->size < s->size ? t->size : s->size);
- while (ti < end)
- *ti++ &= *si++;
+ unsigned char *ti, *si, *end;
+ ti = t->map;
+ si = s->map;
+ end = ti + (t->size < s->size ? t->size : s->size);
+ while (ti < end)
+ *ti++ &= *si++;
}
/* bitwise-ors maps t and s, stores the result in t. */
void
map_or(Map *t, Map *s)
{
- unsigned char *ti, *si, *end;
- if (t->size < s->size)
- map_grow(t, s->size << 3);
- ti = t->map;
- si = s->map;
- end = ti + (t->size < s->size ? t->size : s->size);
- while (ti < end)
- *ti++ |= *si++;
+ unsigned char *ti, *si, *end;
+ if (t->size < s->size)
+ map_grow(t, s->size << 3);
+ ti = t->map;
+ si = s->map;
+ end = ti + (t->size < s->size ? t->size : s->size);
+ while (ti < end)
+ *ti++ |= *si++;
}
/* remove all set bits in s from t. */
void
map_subtract(Map *t, Map *s)
{
- unsigned char *ti, *si, *end;
- ti = t->map;
- si = s->map;
- end = ti + (t->size < s->size ? t->size : s->size);
- while (ti < end)
- *ti++ &= ~*si++;
+ unsigned char *ti, *si, *end;
+ ti = t->map;
+ si = s->map;
+ end = ti + (t->size < s->size ? t->size : s->size);
+ while (ti < end)
+ *ti++ &= ~*si++;
+}
+
+void
+map_invertall(Map *m)
+{
+ unsigned char *ti, *end;
+ ti = m->map;
+ end = ti + m->size;
+ while (ti < end)
+ *ti++ ^= 0xff;
}
/* EOF */
#define MAPCLR(m, n) ((m)->map[(n) >> 3] &= ~(1 << ((n) & 7)))
/* test bit */
#define MAPTST(m, n) ((m)->map[(n) >> 3] & (1 << ((n) & 7)))
+/* clear some bits at a position */
+#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_and(Map *t, Map *s);
extern void map_or(Map *t, Map *s);
extern void map_subtract(Map *t, Map *s);
+extern void map_invertall(Map *m);
static inline void map_empty(Map *m)
{
{
return MAPTST(m, n);
}
+static inline void map_clr_at(Map *m, int n)
+{
+ MAPCLR_AT(m, n);
+}
#ifdef __cplusplus
}
pool_best_solvables;
solver_get_cleandeps;
} SOLV_1.0;
+
+SOLV_1.2 {
+ map_invertall;
+ pool_set_whatprovides;
+ selection_subtract;
+} SOLV_1.1;
if (!ISRELDEP(d1))
{
if (!ISRELDEP(d2))
- return 0;
+ return 0; /* cannot match as d1 != d2 */
rd2 = GETRELDEP(pool, d2);
return pool_match_dep(pool, d1, rd2->name);
}
continue;
if (evr && rd->evr != evr)
continue;
- pool->whatprovides_rel[d] = 0;
+ if (pool->whatprovides_rel[d])
+ pool_set_whatprovides(pool, MAKERELDEP(d), 0);
}
}
{
va_list args;
int l;
+
+ if (!pool)
+ return ret;
va_start(args, format);
if (!pool->errstr)
{
return loc;
}
+void
+pool_set_whatprovides(Pool *pool, Id id, Id providers)
+{
+ int d, nrels = pool->nrels;
+ Reldep *rd;
+ Map m;
+
+ /* set new entry */
+ if (ISRELDEP(id))
+ {
+ d = GETRELID(id);
+ pool->whatprovides_rel[d] = providers;
+ d++;
+ }
+ else
+ {
+ pool->whatprovides[id] = providers;
+ if (id < pool->whatprovidesauxoff)
+ pool->whatprovidesaux[id] = 0; /* sorry */
+ d = 1;
+ }
+ if (!pool->whatprovides_rel)
+ return;
+ /* clear cache of all rels that use it */
+ map_init(&m, 0);
+ for (rd = pool->rels + d; d < nrels; d++, rd++)
+ {
+ if (rd->name == id || rd->evr == id ||
+ (m.size && ISRELDEP(rd->name) && MAPTST(&m, GETRELID(rd->name))) ||
+ (m.size && ISRELDEP(rd->evr) && MAPTST(&m, GETRELID(rd->evr))))
+ {
+ pool->whatprovides_rel[d] = 0; /* clear cache */
+ if (!m.size)
+ map_init(&m, nrels);
+ MAPSET(&m, d);
+ }
+ }
+ map_free(&m);
+}
+
static void
add_new_provider(Pool *pool, Id id, Id p)
{
Queue q;
Id *pp;
+ /* find whatprovides entry */
while (ISRELDEP(id))
{
Reldep *rd = GETRELDEP(pool, id);
id = rd->name;
}
+ /* add new provider to existing list keeping it sorted */
queue_init(&q);
for (pp = pool->whatprovidesdata + pool->whatprovides[id]; *pp; pp++)
{
if (*pp == p)
{
- queue_free(&q);
+ queue_free(&q); /* already have it */
return;
}
if (*pp > p)
}
if (p)
queue_push(&q, p);
- pool->whatprovides[id] = pool_queuetowhatprovides(pool, &q);
- if (id < pool->whatprovidesauxoff)
- pool->whatprovidesaux[id] = 0; /* sorry */
+ pool_set_whatprovides(pool, id, pool_queuetowhatprovides(pool, &q));
queue_free(&q);
}
continue;
s->provides = repo_addid_dep(s->repo, s->provides, id, SOLVABLE_FILEMARKER);
if (pool->whatprovides)
- add_new_provider(pool, fn, p);
- if (pool->whatprovides_rel)
- pool->whatprovides_rel[GETRELID(id)] = 0; /* clear cache */
+ add_new_provider(pool, id, p);
s = pool->solvables + q;
if (!s->repo)
continue;
void pool_whatmatchesdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker);
void pool_whatcontainsdep(Pool *pool, Id keyname, Id dep, Queue *q, int marker);
+void pool_set_whatprovides(Pool *pool, Id id, Id providers);
+
/* search the pool. the following filters are available:
* p - search just this solvable
#include "evr.h"
#include "solverdebug.h"
-
/**********************************************************************************/
/* a problem is an item on the solver's problem list. It can either be >0, in that
* consisting of multiple job rules.
*/
-void
+static void
solver_disableproblem(Solver *solv, Id v)
{
- Rule *r;
int i;
Id *jp;
return;
}
solver_disablerule(solv, solv->rules + v);
-#if 0
- /* XXX: doesn't work */
- if (v >= solv->updaterules && v < solv->updaterules_end)
- {
- /* enable feature rule if we disabled the update rule */
- r = solv->rules + (v - solv->updaterules + solv->featurerules);
- if (r->p)
- solver_enablerule(solv, r);
- }
-#endif
return;
}
v = -(v + 1);
jp = solv->ruletojob.elements;
- for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
+ if (solv->bestrules_pkg)
+ {
+ int ni = solv->bestrules_up - solv->bestrules;
+ for (i = 0; i < ni; i++)
+ {
+ int j = solv->bestrules_pkg[i];
+ if (j < 0 && jp[-j - solv->jobrules] == v)
+ solver_disablerule(solv, solv->rules + solv->bestrules + i);
+ }
+ }
+ for (i = solv->jobrules; i < solv->jobrules_end; i++, jp++)
if (*jp == v)
- solver_disablerule(solv, r);
+ solver_disablerule(solv, solv->rules + i);
}
/*-------------------------------------------------------------------
* enableproblem
*/
-void
+static void
solver_enableproblem(Solver *solv, Id v)
{
Rule *r;
}
v = -(v + 1);
jp = solv->ruletojob.elements;
- for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++, jp++)
+ if (solv->bestrules_pkg)
+ {
+ int ni = solv->bestrules_up - solv->bestrules;
+ for (i = 0; i < ni; i++)
+ {
+ int j = solv->bestrules_pkg[i];
+ if (j < 0 && jp[-j - solv->jobrules] == v)
+ solver_enablerule(solv, solv->rules + solv->bestrules + i);
+ }
+ }
+ for (i = solv->jobrules; i < solv->jobrules_end; i++, jp++)
if (*jp == v)
- solver_enablerule(solv, r);
+ solver_enablerule(solv, solv->rules + i);
+}
+
+
+/*-------------------------------------------------------------------
+ * turn a problem rule into a problem id by normalizing it
+ */
+static Id
+solver_ruletoproblem(Solver *solv, Id rid)
+{
+ if (rid >= solv->jobrules && rid < solv->jobrules_end)
+ rid = -(solv->ruletojob.elements[rid - solv->jobrules] + 1);
+ else if (rid >= solv->bestrules && rid < solv->bestrules_up && solv->bestrules_pkg[rid - solv->bestrules] < 0)
+ rid = -(solv->ruletojob.elements[-solv->bestrules_pkg[rid - solv->bestrules] - solv->jobrules] + 1);
+ else if (rid > solv->infarchrules && rid < solv->infarchrules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[rid].p].name;
+ while (rid > solv->infarchrules && pool->solvables[-solv->rules[rid - 1].p].name == name)
+ rid--;
+ }
+ else if (rid > solv->duprules && rid < solv->duprules_end)
+ {
+ Pool *pool = solv->pool;
+ Id name = pool->solvables[-solv->rules[rid].p].name;
+ while (rid > solv->duprules && pool->solvables[-solv->rules[rid - 1].p].name == name)
+ rid--;
+ }
+ return rid;
+}
+
+/*-------------------------------------------------------------------
+ * when the solver runs into a problem, it needs to disable all
+ * involved non-pkg rules and record the rules for solution
+ * generation.
+ */
+void
+solver_recordproblem(Solver *solv, Id rid)
+{
+ Id v = solver_ruletoproblem(solv, rid);
+ /* return if problem already countains our rule */
+ if (solv->problems.count)
+ {
+ int i;
+ for (i = solv->problems.count - 1; i >= 0; i--)
+ if (solv->problems.elements[i] == 0) /* end of last problem reached? */
+ break;
+ else if (solv->problems.elements[i] == v)
+ return;
+ }
+ queue_push(&solv->problems, v);
+}
+
+/*-------------------------------------------------------------------
+ * this is called when a problem is solved by disabling a rule.
+ * It calls disableproblem and then re-enables policy rules
+ */
+void
+solver_fixproblem(Solver *solv, Id rid)
+{
+ Id v = solver_ruletoproblem(solv, rid);
+ solver_disableproblem(solv, v);
+ if (v < 0)
+ solver_reenablepolicyrules(solv, -v);
+}
+
+/*-------------------------------------------------------------------
+ * disable a set of problems
+ */
+void
+solver_disableproblemset(Solver *solv, int start)
+{
+ int i;
+ for (i = start + 1; i < solv->problems.count - 1; i++)
+ solver_disableproblem(solv, solv->problems.elements[i]);
+}
+
+/*-------------------------------------------------------------------
+ * try to fix a problem by auto-uninstalling packages
+ */
+Id
+solver_autouninstall(Solver *solv, int start)
+{
+ Pool *pool = solv->pool;
+ int i;
+ int lastfeature = 0, lastupdate = 0;
+ Id v;
+ Id extraflags = -1;
+ Map *m = 0;
+
+ if (!solv->allowuninstall && !solv->allowuninstall_all)
+ {
+ if (!solv->allowuninstallmap.size)
+ return 0; /* why did we get called? */
+ m = &solv->allowuninstallmap;
+ }
+ for (i = start + 1; i < solv->problems.count - 1; i++)
+ {
+ v = solv->problems.elements[i];
+ if (v < 0)
+ extraflags &= solv->job.elements[-v - 1];
+ if (v >= solv->updaterules && v < solv->updaterules_end)
+ {
+ Rule *r;
+ if (m && !MAPTST(m, v - solv->updaterules))
+ continue;
+ /* check if identical to feature rule, we don't like that (except for orphans) */
+ r = solv->rules + solv->featurerules + (v - solv->updaterules);
+ if (!r->p)
+ {
+ /* update rule == feature rule */
+ if (v > lastfeature)
+ lastfeature = v;
+ /* prefer orphaned packages in dup mode */
+ if (solv->keep_orphans)
+ {
+ r = solv->rules + v;
+ if (!r->d && !r->w2 && r->p == (solv->installed->start + (v - solv->updaterules)))
+ {
+ lastfeature = v;
+ lastupdate = 0;
+ break;
+ }
+ }
+ continue;
+ }
+ if (v > lastupdate)
+ lastupdate = v;
+ }
+ }
+ if (!lastupdate && !lastfeature)
+ return 0;
+ v = lastupdate ? lastupdate : lastfeature;
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling ");
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v);
+ /* should really be solver_fixproblem, but we know v is an update/feature rule */
+ solver_disableproblem(solv, v);
+ if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size)
+ {
+ /* add the package to the updatepkgs list, this will automatically turn
+ * on cleandeps mode */
+ Id p = solv->rules[v].p;
+ if (!solv->cleandeps_updatepkgs)
+ {
+ solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
+ queue_init(solv->cleandeps_updatepkgs);
+ }
+ if (p > 0)
+ {
+ int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count;
+ queue_pushunique(solv->cleandeps_updatepkgs, p);
+ if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt)
+ solver_disablepolicyrules(solv);
+ }
+ }
+ return v;
}
queue_empty(refined);
if (!essentialok && sug < 0 && (solv->job.elements[-sug - 1] & SOLVER_ESSENTIAL) != 0)
return;
- queue_init(&disabled);
queue_push(refined, sug);
/* re-enable all problem rules with the exception of "sug"(gestion) */
for (i = 0; problem[i]; i++)
if (problem[i] != sug)
solver_enableproblem(solv, problem[i]);
-
if (sug < 0)
solver_reenablepolicyrules(solv, -sug);
- else if (sug >= solv->updaterules && sug < solv->updaterules_end)
+
+ /* here is where the feature rules come into play: if we disabled an
+ * update rule, we enable the corresponding feature rule if there is
+ * one. We do this to make the solver downgrade packages instead of
+ * deinstalling them */
+ if (sug >= solv->updaterules && sug < solv->updaterules_end)
{
/* enable feature rule */
Rule *r = solv->rules + solv->featurerules + (sug - solv->updaterules);
enableweakrules(solv);
+ /* disabled contains all of the rules we disabled in the refinement process */
+ queue_init(&disabled);
for (;;)
{
- int njob, nfeature, nupdate, pass;
+ int nother, nfeature, nupdate, pass;
queue_empty(&solv->problems);
solver_reset(solv);
+ /* we set disablerules to zero because we are only interested in
+ * the first problem and we don't want the solver to disable the problems */
solver_run_sat(solv, 0, 0);
if (!solv->problems.count)
break; /* great, no more problems */
}
disabledcnt = disabled.count;
- /* start with 1 to skip over proof index */
- njob = nfeature = nupdate = 0;
+ nother = nfeature = nupdate = 0;
for (pass = 0; pass < 2; pass++)
{
+ /* start with 1 to skip over proof index */
for (i = 1; i < solv->problems.count - 1; i++)
{
/* ignore solutions in refined */
v = solv->problems.elements[i];
if (v == 0)
break; /* end of problem reached */
+ if (!essentialok && v < 0 && (solv->job.elements[-v - 1] & SOLVER_ESSENTIAL) != 0)
+ continue; /* not that one! */
if (sug != v)
{
/* check if v is in the given problems list
}
if (v >= solv->featurerules && v < solv->featurerules_end)
nfeature++;
- else if (v > 0)
+ else if (v > solv->updaterules && v < solv->updaterules_end)
nupdate++;
else
- {
- if (!essentialok && (solv->job.elements[-v - 1] & SOLVER_ESSENTIAL) != 0)
- continue; /* not that one! */
- njob++;
- }
+ nother++;
queue_push(&disabled, v);
}
if (disabled.count != disabledcnt)
refined->count = 0;
break;
}
- if (!njob && nupdate && nfeature)
+ if (!nother && nupdate && nfeature)
{
/* got only update rules, filter out feature rules */
POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "throwing away feature rules\n");
if (!nfeature && v != sug)
queue_push(refined, v); /* do not record feature rules */
solver_disableproblem(solv, v);
+ if (v < 0)
+ solver_reenablepolicyrules(solv, -v);
if (v >= solv->updaterules && v < solv->updaterules_end)
{
Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
if (r->p)
solver_enablerule(solv, r); /* enable corresponding feature rule */
}
- if (v < 0)
- solver_reenablepolicyrules(solv, -v);
}
else
{
for (i = 0; i < disabled.count; i++)
solver_enableproblem(solv, disabled.elements[i]);
queue_free(&disabled);
+
/* reset policy rules */
for (i = 0; problem[i]; i++)
solver_enableproblem(solv, problem[i]);
#define SOLVER_SOLUTION_BEST (-3)
#define SOLVER_SOLUTION_POOLJOB (-4)
-void solver_disableproblem(struct _Solver *solv, Id v);
-void solver_enableproblem(struct _Solver *solv, Id v);
+void solver_recordproblem(struct _Solver *solv, Id rid);
+void solver_fixproblem(struct _Solver *solv, Id rid);
+Id solver_autouninstall(struct _Solver *solv, int start);
+void solver_disableproblemset(struct _Solver *solv, int start);
+
int solver_prepare_solutions(struct _Solver *solv);
unsigned int solver_problem_count(struct _Solver *solv);
return 0;
}
+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]))
+ return 1;
+ return 0;
+}
+
static inline int pool_installable(const Pool *pool, Solvable *s)
{
if (!s->arch || s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
{
int i, ni;
ni = solv->bestrules_end - solv->bestrules;
- for (i = 0; i < ni; i++)
+ for (i = solv->bestrules_up - solv->bestrules; i < ni; i++)
if (solv->bestrules_pkg[i] == p)
solver_disablerule(solv, solv->rules + solv->bestrules + i);
}
{
int i, ni;
ni = solv->bestrules_end - solv->bestrules;
- for (i = 0; i < ni; i++)
+ for (i = solv->bestrules_up - solv->bestrules; i < ni; i++)
if (solv->bestrules_pkg[i] == p)
solver_enablerule(solv, solv->rules + solv->bestrules + i);
}
}
if (solv->dupinvolvedmap.size)
MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE);
+ /* set update for all involved installed packages. We need to do
+ * this before creating the update rules */
+ if (solv->dupinvolvedmap_all)
+ solv->updatemap_all = 1;
+ else if (installed && !solv->updatemap_all && solv->dupinvolvedmap.size)
+ {
+ FOR_REPO_SOLVABLES(installed, p, s)
+ {
+ if (!MAPTST(&solv->dupinvolvedmap, p))
+ continue;
+ if (!solv->updatemap.size)
+ map_grow(&solv->updatemap, installed->end - installed->start);
+ MAPSET(&solv->updatemap, p - installed->start);
+ }
+ }
}
void
Rule *r;
solv->duprules = solv->nrules;
- if (solv->dupinvolvedmap_all)
- solv->updatemap_all = 1;
for (i = 1; i < pool->nsolvables; i++)
{
if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
continue;
if (installed && ps->repo == installed)
{
- if (!solv->updatemap_all)
- {
- if (!solv->updatemap.size)
- map_grow(&solv->updatemap, installed->end - installed->start);
- MAPSET(&solv->updatemap, p - installed->start);
- }
if (!MAPTST(&solv->dupmap, p))
{
Id ip, ipp;
{
for (i = 0; i < solv->job.count; i += 2)
{
- if ((solv->job.elements[i] & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST))
+ Id how = solv->job.elements[i];
+ if ((how & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST))
{
int j;
Id p2, pp2;
for (j = 0; j < solv->ruletojob.count; j++)
- if (solv->ruletojob.elements[j] == i)
- break;
- if (j == solv->ruletojob.count)
- continue;
- r = solv->rules + solv->jobrules + j;
- queue_empty(&q);
- FOR_RULELITERALS(p2, pp2, r)
- if (p2 > 0)
- queue_push(&q, p2);
- if (!q.count)
- continue; /* orphaned */
- /* select best packages, just look at prio and version */
- oldcnt = q.count;
- policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
- if (q.count == oldcnt)
- continue; /* nothing filtered */
- p2 = queue_shift(&q);
- if (q.count < 2)
- solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0);
- else
- solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q));
- queue_push(&r2pkg, -(solv->jobrules + j));
+ {
+ if (solv->ruletojob.elements[j] != i)
+ continue;
+ r = solv->rules + solv->jobrules + j;
+ queue_empty(&q);
+ queue_empty(&q2);
+ FOR_RULELITERALS(p2, pp2, r)
+ {
+ if (p2 > 0)
+ queue_push(&q, p2);
+ else if (p2 < 0)
+ queue_push(&q2, p2);
+ }
+ if (!q.count)
+ continue; /* orphaned */
+ /* select best packages, just look at prio and version */
+ oldcnt = q.count;
+ policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
+ if (q.count == oldcnt)
+ continue; /* nothing filtered */
+ if (q2.count)
+ queue_insertn(&q, 0, q2.count, q2.elements);
+ p2 = queue_shift(&q);
+ if (q.count < 2)
+ solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0);
+ else
+ solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q));
+ if ((how & SOLVER_WEAK) != 0)
+ queue_push(&solv->weakruleq, solv->nrules - 1);
+ queue_push(&r2pkg, -(solv->jobrules + j));
+ }
}
}
}
+ solv->bestrules_up = solv->nrules;
if (installed && (solv->bestupdatemap_all || solv->bestupdatemap.size))
{
/* yumobs rule handling */
+/* note that we use pool->obsoleteusescolors || pool->implicitobsoleteusescolors
+ * like in policy_findupdatepackages */
static void
find_obsolete_group(Solver *solv, Id obs, Queue *q)
Id obs2, *obsp2;
if (!os->obsoletes)
continue;
- if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os))
+ if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os))
continue;
obsp2 = os->repo->idarraydata + os->obsoletes;
while ((obs2 = *obsp2++) != 0)
continue;
if (!os->obsoletes)
continue;
- if (pool->obsoleteusescolors && !pool_colormatch(pool, s2, os))
+ if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os))
continue;
obsp2 = os->repo->idarraydata + os->obsoletes;
while ((obs2 = *obsp2++) != 0)
continue;
if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
continue;
- if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
+ if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s, s2))
continue;
queue_pushunique(&qo, obs);
break;
return id;
}
+/* remove empty jobs from the selection */
static void
selection_prune(Pool *pool, Queue *selection)
{
}
}
+/* only supports simple rels plus REL_ARCH */
+static int
+match_nevr_rel(Pool *pool, Solvable *s, Id rflags, Id revr)
+{
+ if (rflags == REL_ARCH)
+ {
+ if (s->arch != revr)
+ {
+ if (revr != ARCH_SRC || s->arch != ARCH_NOSRC)
+ return 0;
+ }
+ return 1;
+ }
+ if (rflags > 7)
+ return 0;
+ return pool_intersect_evrs(pool, REL_EQ, s->evr, rflags, revr);
+}
+
+/* only supports simple rels plus REL_ARCH */
static void
-selection_filter_rel(Pool *pool, Queue *selection, Id relflags, Id relevr)
+selection_filter_rel_noprune(Pool *pool, Queue *selection, Id relflags, Id relevr)
{
int i;
+ if (!selection->count)
+ return;
+
for (i = 0; i < selection->count; i += 2)
{
Id select = selection->elements[i] & SOLVER_SELECTMASK;
Id id = selection->elements[i + 1];
if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_ONE_OF)
{
- /* done by selection_addsrc, currently implies SELECTION_NAME */
+ /* done by selection_addextra, currently implies SELECTION_NAME */
Queue q;
Id p, pp;
- Id rel = 0, relname = 0;
int miss = 0;
queue_init(&q);
FOR_JOB_SELECT(p, pp, select, id)
{
Solvable *s = pool->solvables + p;
- if (!rel || s->name != relname)
- {
- relname = s->name;
- rel = pool_rel2id(pool, relname, relevr, relflags, 1);
- }
- if (pool_match_nevr(pool, s, rel))
+ if (match_nevr_rel(pool, s, relflags, relevr))
queue_push(&q, p);
else
miss = 1;
selection->elements[i + 1] = pool_rel2id(pool, id, relevr, relflags, 1);
}
else
- continue; /* actually internal error */
+ continue; /* actually cannot happen */
+
+ /* now add the setflags we gained */
if (relflags == REL_ARCH)
- selection->elements[i] |= SOLVER_SETARCH;
+ selection->elements[i] |= SOLVER_SETARCH;
if (relflags == REL_EQ && select != SOLVER_SOLVABLE_PROVIDES)
- {
+ {
if (pool->disttype == DISTTYPE_DEB)
- selection->elements[i] |= SOLVER_SETEVR; /* debian can't match version only like rpm */
+ selection->elements[i] |= SOLVER_SETEVR; /* debian can't match version only like rpm */
else
{
const char *rel = strrchr(pool_id2str(pool, relevr), '-');
selection->elements[i] |= rel ? SOLVER_SETEVR : SOLVER_SETEV;
}
- }
+ }
}
+}
+
+/* only supports simple rels plus REL_ARCH */
+/* prunes empty jobs */
+static void
+selection_filter_rel(Pool *pool, Queue *selection, Id relflags, Id relevr)
+{
+ selection_filter_rel_noprune(pool, selection, relflags, relevr);
selection_prune(pool, selection);
}
+/* limit a selection to to repository */
+/* prunes empty jobs */
static void
-selection_filter_installed(Pool *pool, Queue *selection)
+selection_filter_repo(Pool *pool, Queue *selection, Repo *repo)
{
Queue q;
int i, j;
- if (!pool->installed)
- queue_empty(selection);
+ if (!selection->count)
+ return;
+ if (!repo)
+ {
+ queue_empty(selection);
+ return;
+ }
queue_init(&q);
for (i = j = 0; i < selection->count; i += 2)
{
if (select == SOLVER_SOLVABLE_ALL)
{
select = SOLVER_SOLVABLE_REPO;
- id = pool->installed->repoid;
+ id = repo->repoid;
}
else if (select == SOLVER_SOLVABLE_REPO)
{
- if (id != pool->installed->repoid)
+ if (id != repo->repoid)
select = 0;
}
else
queue_empty(&q);
FOR_JOB_SELECT(p, pp, select, id)
{
- if (pool->solvables[p].repo != pool->installed)
+ if (pool->solvables[p].repo != repo)
bad = 1;
else
queue_push(&q, p);
if (bad || !q.count)
{
if (!q.count)
- select = 0;
+ select = 0; /* prune empty jobs */
else if (q.count == 1)
{
select = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
}
}
}
- if (select)
+ if (!select)
+ continue; /* job is now empty */
+ if (select == SOLVER_SOLVABLE_REPO)
{
- selection->elements[j++] = select | (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SETREPO;
- selection->elements[j++] = id;
+ Id p;
+ Solvable *s;
+ FOR_REPO_SOLVABLES(repo, p, s)
+ break;
+ if (!p)
+ continue; /* repo is empty */
}
+ selection->elements[j++] = select | (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SETREPO;
+ selection->elements[j++] = id;
}
queue_truncate(selection, j);
queue_free(&q);
}
+
+static int
+matchprovides(Pool *pool, Solvable *s, Id dep)
+{
+ Id id, *idp;
+ idp = s->repo->idarraydata + s->provides;
+ while ((id = *idp++) != 0)
+ if (pool_match_dep(pool, id, dep))
+ return 1;
+ return 0;
+}
+
+/* change a SOLVER_SOLVABLE_NAME/PROVIDES selection to something that also includes
+ * extra packages.
+ * extra packages are: src, badarch, disabled
+ */
static void
-selection_addsrc(Pool *pool, Queue *selection, int flags)
+selection_addextra(Pool *pool, Queue *selection, int flags)
{
Queue q;
- Id p, name;
- int i, havesrc;
+ Id p, pp, dep;
+ int i, isextra, haveextra, doprovides;
if ((flags & SELECTION_INSTALLED_ONLY) != 0)
- return; /* sources can't be installed */
+ flags &= ~SELECTION_WITH_SOURCE;
+
+ if (!(flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH)))
+ return; /* nothing to add */
+
queue_init(&q);
for (i = 0; i < selection->count; i += 2)
{
- if (selection->elements[i] != SOLVER_SOLVABLE_NAME)
+ if (selection->elements[i] == SOLVER_SOLVABLE_NAME)
+ doprovides = 0;
+ else if (selection->elements[i] == SOLVER_SOLVABLE_PROVIDES)
+ doprovides = 1;
+ else
continue;
- name = selection->elements[i + 1];
- havesrc = 0;
+ dep = selection->elements[i + 1];
+ haveextra = 0;
queue_empty(&q);
+ if (doprovides)
+ {
+ /* first put all non-extra packages on the queue */
+ FOR_PROVIDES(p, pp, dep)
+ {
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && pool->solvables[p].repo != pool->installed)
+ continue;
+ queue_push(&q, p);
+ }
+ }
FOR_POOL_SOLVABLES(p)
{
Solvable *s = pool->solvables + p;
- if (s->name != name)
+ if (!doprovides && !pool_match_nevr(pool, s, dep))
continue;
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ continue;
+ isextra = 0;
if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
{
+ if (!(flags & SELECTION_WITH_SOURCE) && !(flags & SELECTION_SOURCE_ONLY))
+ continue;
+ if (!(flags & SELECTION_SOURCE_ONLY))
+ isextra = 1;
if (pool_disabled_solvable(pool, s))
+ {
+ if (!(flags & SELECTION_WITH_DISABLED))
+ continue;
+ isextra = 1;
+ }
+ }
+ else
+ {
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
+ continue;
+ if (s->repo != pool->installed)
+ {
+ if (pool_disabled_solvable(pool, s))
+ {
+ if (!(flags & SELECTION_WITH_DISABLED))
+ continue;
+ isextra = 1;
+ }
+ if (pool_badarch_solvable(pool, s))
+ {
+ if (!(flags & SELECTION_WITH_BADARCH))
+ continue;
+ isextra = 1;
+ }
+ }
+ }
+ if (doprovides)
+ {
+ if (!isextra)
+ continue; /* already done above in FOR_PROVIDES */
+ if (!s->provides || !matchprovides(pool, s, dep))
continue;
- havesrc = 1;
}
- else if (s->repo != pool->installed && !pool_installable(pool, s))
- continue;
+ haveextra |= isextra;
queue_push(&q, p);
}
- if (!havesrc || !q.count)
+ if (!haveextra || !q.count)
continue;
if (q.count == 1)
{
- selection->elements[i] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+ selection->elements[i] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
selection->elements[i + 1] = q.elements[0];
}
else
{
- selection->elements[i] = SOLVER_SOLVABLE_ONE_OF;
+ if (doprovides)
+ solv_sort(q.elements, q.count, sizeof(Id), selection_solvables_sortcmp, NULL);
+ selection->elements[i] = (selection->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF;
selection->elements[i + 1] = pool_queuetowhatprovides(pool, &q);
}
}
queue_push2(q, id1, id2);
}
+
+/***** provides matching *****/
+
static int
-selection_depglob_id(Pool *pool, Queue *selection, Id id, int flags)
+selection_addextra_provides(Pool *pool, Queue *selection, const char *name, int flags)
{
- Id p, pp;
+ Id p, id, *idp;
int match = 0;
+ int doglob, nocase, globflags;
- FOR_PROVIDES(p, pp, id)
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0)
+ return 0; /* neither disabled nor badarch nor src */
+
+ nocase = flags & SELECTION_NOCASE;
+ doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0;
+ globflags = doglob && nocase ? FNM_CASEFOLD : 0;
+
+ FOR_POOL_SOLVABLES(p)
{
+ const char *n;
Solvable *s = pool->solvables + p;
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ if (!s->provides)
+ continue;
+ if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) /* no provides */
+ continue;
+ if (s->repo == pool->installed)
continue;
- match = 1;
- if (s->name == id && (flags & SELECTION_NAME) != 0)
+ if (pool_disabled_solvable(pool, s))
{
- if ((flags & SELECTION_SOURCE_ONLY) != 0)
- id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
- queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
- if ((flags & SELECTION_WITH_SOURCE) != 0)
- selection_addsrc(pool, selection, flags);
- return SELECTION_NAME;
+ if (!(flags & SELECTION_WITH_DISABLED))
+ continue;
+ if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
+ continue;
}
- }
- if ((flags & (SELECTION_SOURCE_ONLY | SELECTION_WITH_SOURCE)) != 0 && (flags & SELECTION_NAME) != 0)
- {
- /* src rpms don't have provides, so we must check every solvable */
- FOR_POOL_SOLVABLES(p) /* slow path */
+ else if (pool_badarch_solvable(pool, s))
{
- Solvable *s = pool->solvables + p;
- if (s->name == id && (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC))
+ if (!(flags & SELECTION_WITH_BADARCH))
+ continue;
+ }
+ else
+ continue;
+ /* here is an extra solvable we need to consider */
+ idp = s->repo->idarraydata + s->provides;
+ while ((id = *idp++) != 0)
+ {
+ while (ISRELDEP(id))
{
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
- continue; /* just in case... src rpms can't be installed */
- if (pool_disabled_solvable(pool, s))
- continue;
- if ((flags & SELECTION_SOURCE_ONLY) != 0)
- id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
- queue_push2(selection, SOLVER_SOLVABLE_NAME, id);
- if ((flags & SELECTION_WITH_SOURCE) != 0)
- selection_addsrc(pool, selection, flags);
- return SELECTION_NAME;
+ Reldep *rd = GETRELDEP(pool, id);
+ id = rd->name;
+ }
+ if (pool->whatprovides[id] > 1)
+ continue; /* we already did that one in the normal code path */
+ n = pool_id2str(pool, id);
+ if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
+ {
+ queue_pushunique2(selection, SOLVER_SOLVABLE_PROVIDES, id);
+ match = 1;
}
}
}
- if (match && (flags & SELECTION_PROVIDES) != 0)
+ return match;
+}
+
+/* this is the fast path of selection_provides: the id for the name
+ * is known and thus we can quickly check the existance of a
+ * package with that provides */
+static int
+selection_provides_id(Pool *pool, Queue *selection, Id id, int flags)
+{
+ Id p, pp;
+
+ FOR_PROVIDES(p, pp, id)
+ {
+ Solvable *s = pool->solvables + p;
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ continue;
+ break;
+ }
+ if (p)
{
queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
return SELECTION_PROVIDES;
}
+
+ if ((flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
+ {
+ queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
+ selection_addextra(pool, selection, flags);
+ if (selection->elements[0] == SOLVER_SOLVABLE_PROVIDES)
+ queue_empty(selection);
+ else
+ {
+ selection->elements[0] = SOLVER_SOLVABLE_PROVIDES;
+ selection->elements[1] = id;
+ }
+ return selection->count ? SELECTION_PROVIDES : 0;
+ }
+
return 0;
}
+/* add missing provides matchers to the selection */
+/* match the provides of a package */
+/* note that we only return raw SOLVER_SOLVABLE_PROVIDES jobs
+ * so that the selection can be modified later. */
static int
-selection_depglob(Pool *pool, Queue *selection, const char *name, int flags)
+selection_provides(Pool *pool, Queue *selection, const char *name, int flags)
{
Id id, p, pp;
- int match = 0;
- int doglob = 0;
- int nocase = 0;
- int globflags = 0;
+ int match;
+ int doglob;
+ int nocase;
+ int globflags;
+ const char *n;
if ((flags & SELECTION_SOURCE_ONLY) != 0)
- {
- flags &= ~SELECTION_PROVIDES; /* sources don't provide anything */
- flags &= ~SELECTION_WITH_SOURCE;
- }
-
- if (!(flags & (SELECTION_NAME|SELECTION_PROVIDES)))
- return 0;
-
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
- return 0;
+ return 0; /* sources do not have provides */
nocase = flags & SELECTION_NOCASE;
- if (!nocase && !(flags & SELECTION_SKIP_KIND))
+ if (!nocase)
{
+ /* try the fast path first */
id = pool_str2id(pool, name, 0);
if (id)
{
- /* the id is know, do the fast id matching using the whatprovides lookup */
- int ret = selection_depglob_id(pool, selection, id, flags);
+ /* the id is known, do the fast id matching */
+ int ret = selection_provides_id(pool, selection, id, flags);
if (ret)
return ret;
}
}
- if ((flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0)
- doglob = 1;
-
- if (!nocase && !(flags & SELECTION_SKIP_KIND) && !doglob)
- return 0; /* all done above in depglob_id */
-
- if (doglob && nocase)
- globflags = FNM_CASEFOLD;
+ doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0;
+ if (!nocase && !doglob)
+ {
+ /* all done above in selection_provides_id */
+ return 0;
+ }
- if ((flags & SELECTION_NAME) != 0)
+ /* looks like a glob or nocase match. really hard work. */
+ match = 0;
+ globflags = doglob && nocase ? FNM_CASEFOLD : 0;
+ for (id = 1; id < pool->ss.nstrings; id++)
{
- /* looks like a name glob. hard work. */
- FOR_POOL_SOLVABLES(p)
+ /* do we habe packages providing this id? */
+ if (!pool->whatprovides[id] || pool->whatprovides[id] == 1)
+ continue;
+ n = pool_id2str(pool, id);
+ if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
{
- Solvable *s = pool->solvables + p;
- const char *n;
- if (s->repo != pool->installed && !pool_installable(pool, s))
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0)
{
- if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
- continue;
- if (pool_disabled_solvable(pool, s))
+ FOR_PROVIDES(p, pp, id)
+ if (pool->solvables[p].repo == pool->installed)
+ break;
+ if (!p)
continue;
}
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
+ match = 1;
+ }
+ }
+
+ if (flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED))
+ match |= selection_addextra_provides(pool, selection, name, flags);
+
+ return match ? SELECTION_PROVIDES : 0;
+}
+
+/***** name matching *****/
+
+/* this is the fast path of selection_name: the id for the name
+ * is known and thus we can quickly check the existance of a
+ * package with that name */
+static int
+selection_name_id(Pool *pool, Queue *selection, Id id, int flags)
+{
+ Id p, pp, matchid;
+
+ matchid = id;
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
+ {
+ /* sources cannot be installed */
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0)
+ return 0;
+ /* add ARCH_SRC to match only sources */
+ matchid = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
+ flags &= ~SELECTION_WITH_SOURCE;
+ }
+
+ FOR_PROVIDES(p, pp, matchid)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->name != id)
+ continue;
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ continue;
+ /* one match is all we need */
+ queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid);
+ /* add the requested extra packages */
+ if ((flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
+ selection_addextra(pool, selection, flags);
+ return SELECTION_NAME;
+ }
+
+ if ((flags & (SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
+ {
+ queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid);
+ selection_addextra(pool, selection, flags);
+ if (selection->elements[0] == SOLVER_SOLVABLE_NAME)
+ queue_empty(selection);
+ return selection->count ? SELECTION_NAME : 0;
+ }
+
+ if ((flags & SELECTION_WITH_SOURCE) != 0 && (flags & SELECTION_INSTALLED_ONLY) == 0)
+ {
+ /* WITH_SOURCE case, but we had no match. try SOURCE_ONLY instead */
+ matchid = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
+ FOR_PROVIDES(p, pp, matchid)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->name != id)
continue;
- id = s->name;
- n = pool_id2str(pool, id);
- if (flags & SELECTION_SKIP_KIND)
- n = skipkind(n);
- if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
- {
- if ((flags & SELECTION_SOURCE_ONLY) != 0)
- id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
- queue_pushunique2(selection, SOLVER_SOLVABLE_NAME, id);
- match = 1;
- }
+ queue_push2(selection, SOLVER_SOLVABLE_NAME, matchid);
+ return SELECTION_NAME;
}
- if (match)
+ }
+ return 0;
+}
+
+/* match the name of a package */
+/* note that for SELECTION_INSTALLED_ONLY the result is not trimmed */
+static int
+selection_name(Pool *pool, Queue *selection, const char *name, int flags)
+{
+ Id id, p;
+ int match;
+ int doglob, nocase;
+ int globflags;
+ const char *n;
+
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
+ flags &= ~SELECTION_WITH_SOURCE;
+
+ nocase = flags & SELECTION_NOCASE;
+ if (!nocase && !(flags & SELECTION_SKIP_KIND))
+ {
+ /* try the fast path first */
+ id = pool_str2id(pool, name, 0);
+ if (id)
{
- if ((flags & SELECTION_WITH_SOURCE) != 0)
- selection_addsrc(pool, selection, flags);
- return SELECTION_NAME;
+ int ret = selection_name_id(pool, selection, id, flags);
+ if (ret)
+ return ret;
}
}
- if ((flags & SELECTION_PROVIDES))
+ doglob = (flags & SELECTION_GLOB) != 0 && strpbrk(name, "[*?") != 0;
+ if (!nocase && !(flags & SELECTION_SKIP_KIND) && !doglob)
+ return 0; /* all done above in selection_name_id */
+
+ /* do a name match over all packages. hard work. */
+ match = 0;
+ globflags = doglob && nocase ? FNM_CASEFOLD : 0;
+ FOR_POOL_SOLVABLES(p)
{
- /* looks like a dep glob. really hard work. */
- for (id = 1; id < pool->ss.nstrings; id++)
+ Solvable *s = pool->solvables + p;
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ continue;
+ if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
{
- const char *n;
- if (!pool->whatprovides[id] || pool->whatprovides[id] == 1)
+ if (!(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
continue;
- n = pool_id2str(pool, id);
- if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
+ if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+ continue;
+ }
+ else if (s->repo != pool->installed)
+ {
+ if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+ continue;
+ if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
+ continue;
+ }
+ id = s->name;
+ n = pool_id2str(pool, id);
+ if (flags & SELECTION_SKIP_KIND)
+ n = skipkind(n);
+ if ((doglob ? fnmatch(name, n, globflags) : nocase ? strcasecmp(name, n) : strcmp(name, n)) == 0)
+ {
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
{
- if ((flags & SELECTION_INSTALLED_ONLY) != 0)
- {
- FOR_PROVIDES(p, pp, id)
- if (pool->solvables[p].repo == pool->installed)
- break;
- if (!p)
- continue;
- }
- queue_push2(selection, SOLVER_SOLVABLE_PROVIDES, id);
- match = 1;
+ if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC)
+ continue;
+ id = pool_rel2id(pool, id, ARCH_SRC, REL_ARCH, 1);
}
+ queue_pushunique2(selection, SOLVER_SOLVABLE_NAME, id);
+ match = 1;
}
- if (match)
- return SELECTION_PROVIDES;
+ }
+ if (match)
+ {
+ /* if there was a match widen the selector to include all extra packages */
+ if ((flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_BADARCH | SELECTION_WITH_DISABLED)) != 0)
+ selection_addextra(pool, selection, flags);
+ return SELECTION_NAME;
}
return 0;
}
+
+/***** SELECTION_DOTARCH and SELECTION_REL handling *****/
+
+/* like selection_name, but check for a .arch suffix if the match did
+ not work and SELECTION_DOTARCH is used */
static int
-selection_depglob_arch(Pool *pool, Queue *selection, const char *name, int flags)
+selection_name_arch(Pool *pool, Queue *selection, const char *name, int flags, int doprovides, int noprune)
{
int ret;
const char *r;
Id archid;
- if ((ret = selection_depglob(pool, selection, name, flags)) != 0)
+ if (doprovides)
+ ret = selection_provides(pool, selection, name, flags);
+ else
+ ret = selection_name(pool, selection, name, flags);
+ if (ret)
return ret;
if (!(flags & SELECTION_DOTARCH))
return 0;
rname[r - name] = 0;
if (archid == ARCH_SRC || archid == ARCH_NOSRC)
flags |= SELECTION_SOURCE_ONLY;
- if ((ret = selection_depglob(pool, selection, rname, flags)) != 0)
+ if (doprovides)
+ ret = selection_provides(pool, selection, rname, flags);
+ else
+ ret = selection_name(pool, selection, rname, flags);
+ if (ret)
{
- selection_filter_rel(pool, selection, REL_ARCH, archid);
- solv_free(rname);
- return ret | SELECTION_DOTARCH;
+ selection_filter_rel_noprune(pool, selection, REL_ARCH, archid);
+ if (!noprune)
+ selection_prune(pool, selection);
}
solv_free(rname);
+ return ret && selection->count ? ret | SELECTION_DOTARCH : 0;
}
return 0;
}
-static int
-selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
+static char *
+splitrel(char *rname, char *r, int *rflagsp)
{
- Dataiterator di;
- Queue q;
- int type;
-
- /* all files in the file list start with a '/' */
- if (*name != '/')
+ int nend = r - rname;
+ int rflags = 0;
+ if (nend && *r == '=' && r[-1] == '!')
{
- if (!(flags & SELECTION_GLOB))
- return 0;
- if (*name != '*' && *name != '[' && *name != '?')
- return 0;
+ nend--;
+ r++;
+ rflags = REL_LT|REL_GT;
}
- type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
- if ((flags & SELECTION_NOCASE) != 0)
- type |= SEARCH_NOCASE;
- queue_init(&q);
- dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
- while (dataiterator_step(&di))
- {
- Solvable *s = pool->solvables + di.solvid;
- if (!s->repo)
- continue;
- if (s->repo != pool->installed && !pool_installable(pool, s))
- {
- if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
- continue;
- if (pool_disabled_solvable(pool, s))
- continue;
- }
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
- continue;
- queue_push(&q, di.solvid);
- dataiterator_skip_solvable(&di);
- }
- dataiterator_free(&di);
- if (!q.count)
- return 0;
- if (q.count > 1)
- queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_queuetowhatprovides(pool, &q));
- else
- queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
- queue_free(&q);
- return SELECTION_FILELIST;
-}
-
-static char *
-splitrel(char *rname, char *r, int *rflagsp)
-{
- int nend = r - rname;
- int rflags = 0;
- if (nend && *r == '=' && r[-1] == '!')
- {
- nend--;
- r++;
- rflags = REL_LT|REL_GT;
- }
- for (; *r; r++)
+ for (; *r; r++)
{
if (*r == '<')
rflags |= REL_LT;
r++;
while (nend && (rname[nend - 1] == ' ' || rname[nend - 1] == '\t'))
nend--;
- if (!*rname || !*r)
+ if (nend <= 0 || !*r || !rflags)
return 0;
*rflagsp = rflags;
rname[nend] = 0;
return r;
}
+/* match name/provides, support DOTARCH and REL modifiers
+ */
static int
-selection_rel(Pool *pool, Queue *selection, const char *name, int flags)
+selection_name_arch_rel(Pool *pool, Queue *selection, const char *name, int flags, int doprovides)
{
- int ret, rflags = 0;
- char *r, *rname;
+ int ret, rflags = 0, noprune;
+ char *r = 0, *rname = 0;
- /* relation case, support:
- * depglob rel
- * depglob.arch rel
- */
- rname = solv_strdup(name);
- if ((r = strpbrk(rname, "<=>")) != 0)
+ /* try to split off an relation part */
+ if ((flags & SELECTION_REL) != 0)
{
- if ((r = splitrel(rname, r, &rflags)) == 0)
+ if ((r = strpbrk(name, "<=>")) != 0)
{
- solv_free(rname);
- return 0;
+ rname = solv_strdup(name);
+ r = rname + (r - name);
+ if ((r = splitrel(rname, r, &rflags)) == 0)
+ rname = solv_free(rname);
}
}
- if ((ret = selection_depglob_arch(pool, selection, rname, flags)) != 0)
+
+ /* check if we need to call selection_addextra */
+ noprune = doprovides && (flags & (SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH));
+
+ if (!r)
{
- if (rflags)
- selection_filter_rel(pool, selection, rflags, pool_str2id(pool, r, 1));
- solv_free(rname);
- return ret | SELECTION_REL;
+ /* could not split off relation */
+ ret = selection_name_arch(pool, selection, name, flags, doprovides, noprune);
+ if (ret && noprune)
+ {
+ selection_addextra(pool, selection, flags);
+ selection_prune(pool, selection);
+ }
+ return ret && selection->count ? ret : 0;
+ }
+
+ /* we could split of a relation. prune name and then filter rel */
+ ret = selection_name_arch(pool, selection, rname, flags, doprovides, noprune);
+ if (ret)
+ {
+ selection_filter_rel_noprune(pool, selection, rflags, pool_str2id(pool, r, 1));
+ if (noprune)
+ selection_addextra(pool, selection, flags);
+ selection_prune(pool, selection);
}
solv_free(rname);
- return 0;
+ return ret && selection->count ? ret | SELECTION_REL : 0;
}
+/***** filelist matching *****/
+
+static int
+selection_filelist_sortcmp(const void *ap, const void *bp, void *dp)
+{
+ Pool *pool = dp;
+ const Id *a = ap, *b = bp;
+ if (a[0] != b[0])
+ return strcmp(pool_id2str(pool, a[0]), pool_id2str(pool, b[0]));
+ return a[1] - b[1];
+}
+
+static int
+selection_filelist(Pool *pool, Queue *selection, const char *name, int flags)
+{
+ Dataiterator di;
+ Queue q;
+ Id id;
+ int type;
+ int i, j, lastid;
+
+ /* all files in the file list start with a '/' */
+ if (*name != '/')
+ {
+ if (!(flags & SELECTION_GLOB))
+ return 0;
+ if (*name != '*' && *name != '[' && *name != '?')
+ return 0;
+ }
+ type = !(flags & SELECTION_GLOB) || strpbrk(name, "[*?") == 0 ? SEARCH_STRING : SEARCH_GLOB;
+ if ((flags & SELECTION_NOCASE) != 0)
+ type |= SEARCH_NOCASE;
+ queue_init(&q);
+ dataiterator_init(&di, pool, flags & SELECTION_INSTALLED_ONLY ? pool->installed : 0, 0, SOLVABLE_FILELIST, name, type|SEARCH_FILES|SEARCH_COMPLETE_FILELIST);
+ while (dataiterator_step(&di))
+ {
+ Solvable *s = pool->solvables + di.solvid;
+ if (!s->repo)
+ continue;
+ if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+ {
+ if (!(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
+ continue;
+ if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+ continue;
+ }
+ else
+ {
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
+ continue;
+ if (s->repo != pool->installed)
+ {
+ if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+ continue;
+ if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
+ continue;
+ }
+ }
+ if ((flags & SELECTION_FLAT) != 0)
+ {
+ /* don't bother with the complex stuff */
+ queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, di.solvid);
+ dataiterator_skip_solvable(&di);
+ continue;
+ }
+ id = pool_str2id(pool, di.kv.str, 1);
+ queue_push2(&q, id, di.solvid);
+ }
+ dataiterator_free(&di);
+ if ((flags & SELECTION_FLAT) != 0)
+ {
+ queue_free(&q);
+ return selection->count ? SELECTION_FILELIST : 0;
+ }
+ if (!q.count)
+ {
+ queue_free(&q);
+ return 0;
+ }
+ solv_sort(q.elements, q.count / 2, 2 * sizeof(Id), selection_filelist_sortcmp, pool);
+ lastid = 0;
+ queue_push2(&q, 0, 0);
+ for (i = j = 0; i < q.count; i += 2)
+ {
+ if (q.elements[i] != lastid)
+ {
+ if (j == 1)
+ queue_pushunique2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, q.elements[0]);
+ else if (j > 1)
+ {
+ int k;
+ Id *idp;
+ /* check if we already have it */
+ for (k = 0; k < selection->count; k += 2)
+ {
+ if (selection->elements[k] != SOLVER_SOLVABLE_ONE_OF)
+ continue;
+ idp = pool->whatprovidesdata + selection->elements[k + 1];
+ if (!memcmp(idp, q.elements, j * sizeof(Id)) && !idp[j])
+ break;
+ }
+ if (k == selection->count)
+ queue_push2(selection, SOLVER_SOLVABLE_ONE_OF, pool_ids2whatprovides(pool, q.elements, j));
+ }
+ lastid = q.elements[i];
+ j = 0;
+ }
+ if (!j || q.elements[j - 1] != q.elements[i])
+ q.elements[j++] = q.elements[i + 1];
+ }
+ queue_free(&q);
+ return SELECTION_FILELIST;
+}
+
+
+/***** canon name matching *****/
+
#if defined(MULTI_SEMANTICS)
# define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE)
#elif defined(DEBIAN)
/* magic epoch promotion code, works only for SELECTION_NAME selections */
static void
-selection_filter_evr(Pool *pool, Queue *selection, char *evr)
+selection_filter_evr(Pool *pool, Queue *selection, const char *evr)
{
int i, j;
Queue q;
Id qbuf[10];
+ const char *sp;
+
+ /* do we already have an epoch? */
+ for (sp = evr; *sp >= '0' && *sp <= '9'; sp++)
+ ;
+ if (*sp == ':' && sp != evr)
+ {
+ /* yes, just add the rel filter */
+ selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, evr, 1));
+ return;
+ }
queue_init(&q);
queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
{
Solvable *s = pool->solvables + p;
const char *sevr = pool_id2str(pool, s->evr);
- const char *sp;
for (sp = sevr; *sp >= '0' && *sp <= '9'; sp++)
;
if (*sp != ':')
rname = solv_strdup(name); /* so we can modify it */
r = rname + (r - name);
*r++ = 0;
- if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
+ if ((ret = selection_name(pool, selection, rname, flags)) == 0)
{
solv_free(rname);
return 0;
}
selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
solv_free(rname);
- return ret | SELECTION_CANON;
+ return selection->count ? ret | SELECTION_CANON : 0;
}
if (pool->disttype == DISTTYPE_HAIKU)
rname = solv_strdup(name); /* so we can modify it */
r = rname + (r - name);
*r++ = 0;
- if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
+ if ((ret = selection_name(pool, selection, rname, flags)) == 0)
{
solv_free(rname);
return 0;
}
selection_filter_rel(pool, selection, REL_EQ, pool_str2id(pool, r, 1));
solv_free(rname);
- return ret | SELECTION_CANON;
+ return selection->count ? ret | SELECTION_CANON : 0;
}
if ((r = strrchr(name, '-')) == 0)
flags |= SELECTION_SOURCE_ONLY;
/* try with just the version */
- if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
+ if ((ret = selection_name(pool, selection, rname, flags)) == 0)
{
/* no luck, try with version-release */
if ((r2 = strrchr(rname, '-')) == 0)
*r = '-';
*r2 = 0;
r = r2;
- if ((ret = selection_depglob(pool, selection, rname, flags)) == 0)
+ if ((ret = selection_name(pool, selection, rname, flags)) == 0)
{
solv_free(rname);
return 0;
selection_filter_rel(pool, selection, REL_ARCH, archid);
selection_filter_evr(pool, selection, r + 1); /* magic epoch promotion */
solv_free(rname);
- return ret | SELECTION_CANON;
+ return selection->count ? ret | SELECTION_CANON : 0;
+}
+
+/* return the needed withbits to match the provided selection */
+static int
+selection_extrabits(Pool *pool, Queue *selection, int flags)
+{
+ int i, needflags, isextra;
+ int allflags;
+ Id p;
+ Solvable *s;
+ Queue qlimit;
+
+ allflags = flags & (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH);
+ if (!selection->count)
+ return allflags;
+ if (selection->count == 2 && selection->elements[0] == SOLVER_SOLVABLE_ALL)
+ return allflags; /* don't bother */
+ queue_init(&qlimit);
+ selection_solvables(pool, selection, &qlimit);
+ needflags = 0;
+ for (i = 0; i < qlimit.count; i++)
+ {
+ p = qlimit.elements[i];
+ s = pool->solvables + p;
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
+ continue;
+ isextra = 0;
+ if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
+ {
+ if (!(flags & SELECTION_WITH_SOURCE))
+ continue;
+ isextra |= SELECTION_WITH_SOURCE;
+ if (pool_disabled_solvable(pool, s))
+ {
+ if (!(flags & SELECTION_WITH_DISABLED))
+ continue;
+ isextra |= SELECTION_WITH_DISABLED;
+ }
+ }
+ else
+ {
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
+ continue;
+ if (s->repo != pool->installed)
+ {
+ if (pool_disabled_solvable(pool, s))
+ {
+ if (!(flags & SELECTION_WITH_DISABLED))
+ continue;
+ isextra |= SELECTION_WITH_DISABLED;
+ }
+ if (pool_badarch_solvable(pool, s))
+ {
+ if (!(flags & SELECTION_WITH_BADARCH))
+ continue;
+ isextra |= SELECTION_WITH_BADARCH;
+ }
+ }
+ }
+ if (isextra)
+ {
+ needflags |= isextra;
+ if (needflags == allflags)
+ break;
+ }
+ }
+ queue_free(&qlimit);
+ return needflags;
}
int
selection_make(Pool *pool, Queue *selection, const char *name, int flags)
{
int ret = 0;
+ if ((flags & SELECTION_MODEBITS) != 0)
+ {
+ Queue q;
+ queue_init(&q);
+ if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT || (flags & SELECTION_MODEBITS) == SELECTION_FILTER)
+ {
+ if (!selection->count)
+ {
+ queue_free(&q);
+ return 0;
+ }
+ if ((flags & (SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) != 0)
+ {
+ /* try to drop expensive extra bits */
+ flags = (flags & ~(SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH | SELECTION_WITH_SOURCE)) | selection_extrabits(pool, selection, flags);
+ }
+ }
+ ret = selection_make(pool, &q, name, flags & ~SELECTION_MODEBITS);
+ if ((flags & SELECTION_MODEBITS) == SELECTION_ADD)
+ selection_add(pool, selection, &q);
+ else if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT)
+ selection_subtract(pool, selection, &q);
+ else if (ret || !(flags & SELECTION_FILTER_KEEP_IFEMPTY))
+ {
+ if ((flags & SELECTION_FILTER_SWAPPED) != 0)
+ {
+ selection_filter(pool, &q, selection);
+ queue_free(selection);
+ queue_init_clone(selection, &q);
+ }
+ else
+ selection_filter(pool, selection, &q);
+ }
+ queue_free(&q);
+ return ret;
+ }
queue_empty(selection);
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0 && !pool->installed)
+ return 0;
+
+ /* here come our four selection modes */
if ((flags & SELECTION_FILELIST) != 0)
ret = selection_filelist(pool, selection, name, flags);
- if (!ret && (flags & SELECTION_REL) != 0 && strpbrk(name, "<=>") != 0)
- ret = selection_rel(pool, selection, name, flags);
- if (!ret)
- ret = selection_depglob_arch(pool, selection, name, flags);
+ if (!ret && (flags & SELECTION_NAME) != 0)
+ ret = selection_name_arch_rel(pool, selection, name, flags, 0);
+ if (!ret && (flags & SELECTION_PROVIDES) != 0)
+ ret = selection_name_arch_rel(pool, selection, name, flags, 1);
if (!ret && (flags & SELECTION_CANON) != 0)
ret = selection_canon(pool, selection, name, flags);
- if (selection->count && (flags & SELECTION_INSTALLED_ONLY) != 0)
- selection_filter_installed(pool, selection);
- if (ret && !selection->count)
- ret = 0; /* no match -> always return zero */
+
+ /* now do result filtering */
+ if (ret && (flags & SELECTION_INSTALLED_ONLY) != 0)
+ selection_filter_repo(pool, selection, pool->installed);
+
+ /* flatten if requested */
if (ret && (flags & SELECTION_FLAT) != 0)
selection_flatten(pool, selection);
- return ret;
+ return selection->count ? ret : 0;
}
-static inline int
+struct limiter {
+ int start; /* either 2 or repofilter->start */
+ int end; /* either nsolvables or repofilter->end */
+ Id *mapper;
+ Repo *repofilter;
+};
+
+/* add matching src packages to simple SOLVABLE_NAME selections */
+static void
+setup_limiter(Pool *pool, int flags, struct limiter *limiter)
+{
+ limiter->start = 2;
+ limiter->end = pool->nsolvables;
+ limiter->mapper = 0;
+ limiter->repofilter = 0;
+ if ((flags & SELECTION_INSTALLED_ONLY) != 0)
+ {
+ Repo *repo = pool->installed;
+ limiter->repofilter = repo;
+ limiter->start = repo ? repo->start : 0;
+ limiter->end = repo ? repo->end : 0;
+ }
+}
+
+static int
matchdep_str(const char *pattern, const char *string, int flags)
{
if (flags & SELECTION_GLOB)
return strcmp(pattern, string) == 0 ? 1 : 0;
}
+/* like pool_match_dep but uses matchdep_str to match the name for glob and nocase matching */
static int
-matchdep(Pool *pool, Id id, char *rname, int rflags, char *revr, int flags)
+matchdep(Pool *pool, Id id, char *rname, int rflags, Id revr, int flags)
{
if (ISRELDEP(id))
{
Reldep *rd = GETRELDEP(pool, id);
- if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH || rd->flags == REL_WITHOUT || rd->flags == REL_COND || rd->flags == REL_UNLESS)
+ if (rd->flags > 7)
{
- if (matchdep(pool, rd->name, rname, rflags, revr, flags))
- return 1;
- if ((rd->flags == REL_COND || rd->flags == REL_UNLESS) && ISRELDEP(rd->evr))
+ if (rd->flags == REL_AND || rd->flags == REL_OR || rd->flags == REL_WITH || rd->flags == REL_WITHOUT || rd->flags == REL_COND || rd->flags == REL_UNLESS)
{
- rd = GETRELDEP(pool, rd->evr);
- if (rd->flags != REL_ELSE)
- return 0;
+ if (matchdep(pool, rd->name, rname, rflags, revr, flags))
+ return 1;
+ if ((rd->flags == REL_COND || rd->flags == REL_UNLESS) && ISRELDEP(rd->evr))
+ {
+ rd = GETRELDEP(pool, rd->evr);
+ if (rd->flags != REL_ELSE)
+ return 0;
+ }
+ if (rd->flags != REL_COND && rd->flags != REL_UNLESS && rd->flags != REL_WITHOUT && matchdep(pool, rd->evr, rname, rflags, revr, flags))
+ return 1;
+ return 0;
}
- if (rd->flags != REL_COND && rd->flags != REL_UNLESS && rd->flags != REL_WITHOUT && matchdep(pool, rd->evr, rname, rflags, revr, flags))
- return 1;
- return 0;
+ if (rd->flags == REL_ARCH)
+ return matchdep(pool, rd->name, rname, rflags, revr, flags);
}
- if (rd->flags == REL_ARCH)
- return matchdep(pool, rd->name, rname, rflags, revr, flags);
if (!matchdep(pool, rd->name, rname, rflags, revr, flags))
return 0;
- if (rflags)
- {
- /* XXX: need pool_match_flags_evr here */
- if (!pool_match_dep(pool, pool_rel2id(pool, rd->name, pool_str2id(pool, revr, 1), rflags, 1), id))
- return 0;
- }
+ if (rflags && !pool_intersect_evrs(pool, rd->flags, rd->evr, rflags, revr))
+ return 0;
return 1;
}
return matchdep_str(rname, pool_id2str(pool, id), flags);
}
-/*
- * select against the dependencies in keyname
- * like SELECTION_REL and SELECTION_PROVIDES, but with the
- * deps in keyname instead of provides.
- */
-int
-selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker)
+static int
+selection_make_matchdeps_common_limited(Pool *pool, Queue *selection, const char *name, Id dep, int flags, int keyname, int marker, struct limiter *limiter)
{
- char *rname, *r = 0;
+ int li, i, j;
+ int ret = 0;
+ char *rname = 0, *r = 0;
int rflags = 0;
+ Id revr = 0;
Id p;
Queue q;
queue_empty(selection);
- rname = solv_strdup(name);
- if (!(flags & SELECTION_MATCH_DEPSTR))
+ if (!limiter->end)
+ return 0;
+ if (!name && !dep)
+ return 0;
+
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0)
+ flags &= ~SELECTION_REL;
+
+ if (name)
{
- if ((r = strpbrk(rname, "<=>")) != 0)
+ rname = solv_strdup(name);
+ if ((flags & SELECTION_REL) != 0)
{
- if ((r = splitrel(rname, r, &rflags)) == 0)
+ if ((r = strpbrk(rname, "<=>")) != 0)
{
- solv_free(rname);
- return 0;
+ if ((r = splitrel(rname, r, &rflags)) == 0)
+ {
+ solv_free(rname);
+ return 0;
+ }
}
+ revr = pool_str2id(pool, r, 1);
+ ret |= SELECTION_REL;
+ }
+ if ((flags & SELECTION_GLOB) != 0 && !strpbrk(rname, "[*?") != 0)
+ flags &= ~SELECTION_GLOB;
+
+ if ((flags & SELECTION_GLOB) == 0 && (flags & SELECTION_NOCASE) == 0 && (flags & SELECTION_MATCH_DEPSTR) == 0)
+ {
+ /* we can use the faster selection_make_matchdepid */
+ dep = pool_str2id(pool, rname, 1);
+ if (rflags)
+ dep = pool_rel2id(pool, dep, revr, rflags, 1);
+ rname = solv_free(rname);
+ name = 0;
+ }
+ }
+ if (dep)
+ {
+ if (keyname == SOLVABLE_NAME && (flags & SELECTION_MATCH_DEPSTR) != 0)
+ {
+ Reldep *rd;
+ if (!ISRELDEP(dep))
+ return 0;
+ rd = GETRELDEP(pool, dep);
+ if (!rd->name || rd->flags != REL_EQ)
+ return 0;
+ dep = rd->name;
+ rflags = rd->flags;
+ revr = rd->evr;
}
}
- if ((flags & SELECTION_GLOB) != 0 && !strpbrk(rname, "[*?") != 0)
- flags &= ~SELECTION_GLOB;
queue_init(&q);
- FOR_POOL_SOLVABLES(p)
+ for (li = limiter->start; li < limiter->end; li++)
{
- Solvable *s = pool->solvables + p;
- int i;
-
- if (s->repo != pool->installed && !pool_installable(pool, s))
+ Solvable *s;
+ p = limiter->mapper ? limiter->mapper[li] : li;
+ s = pool->solvables + p;
+ if (!s->repo || (limiter->repofilter && s->repo != limiter->repofilter))
+ continue;
+ if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
{
- if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
+ if (!(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
continue;
- if (pool_disabled_solvable(pool, s))
+ if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
continue;
}
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
- continue;
- if ((s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) && !(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
- continue;
+ else
+ {
+ if ((flags & SELECTION_SOURCE_ONLY) != 0)
+ continue;
+ if (s->repo != pool->installed)
+ {
+ if (!(flags & SELECTION_WITH_DISABLED) && pool_disabled_solvable(pool, s))
+ continue;
+ if (!(flags & SELECTION_WITH_BADARCH) && pool_badarch_solvable(pool, s))
+ continue;
+ }
+ }
+ if (keyname == SOLVABLE_NAME) /* nevr match hack */
+ {
+ if (dep)
+ {
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0)
+ {
+ if (s->name != dep || s->evr != revr)
+ continue;
+ }
+ else
+ {
+ if (!pool_match_nevr(pool, s, dep))
+ continue;
+ }
+ }
+ else
+ {
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0) /* mis-use */
+ {
+ char *tmp = pool_tmpjoin(pool, pool_id2str(pool, s->name), " = ", pool_id2str(pool, s->evr));
+ if (!matchdep_str(rname, tmp, flags))
+ continue;
+ }
+ else
+ {
+ if (!matchdep(pool, s->name, rname, rflags, revr, flags))
+ continue;
+ if (rflags && !pool_intersect_evrs(pool, rflags, revr, REL_EQ, s->evr))
+ continue;
+ }
+ }
+ queue_push(selection, p);
+ continue;
+ }
queue_empty(&q);
repo_lookup_deparray(s->repo, p, keyname, &q, marker);
- for (i = 0; i < q.count; i++)
+ if (!q.count)
+ continue;
+ if (dep)
+ {
+ if ((flags & SELECTION_MATCH_DEPSTR) != 0) /* mis-use */
+ {
+ for (i = 0; i < q.count; i++)
+ if (q.elements[i] == dep)
+ break;
+ }
+ else
+ {
+ for (i = 0; i < q.count; i++)
+ if (pool_match_dep(pool, q.elements[i], dep))
+ break;
+ }
+ }
+ else
{
- Id id = q.elements[i];
if ((flags & SELECTION_MATCH_DEPSTR) != 0)
{
- if (matchdep_str(rname, pool_dep2str(pool, id), flags))
- break;
- continue;
+ for (i = 0; i < q.count; i++)
+ if (matchdep_str(rname, pool_dep2str(pool, q.elements[i]), flags))
+ break;
+ }
+ else
+ {
+ for (i = 0; i < q.count; i++)
+ if (matchdep(pool, q.elements[i], rname, rflags, revr, flags))
+ break;
}
- if (matchdep(pool, id, rname, rflags, r, flags))
- break;
}
if (i < q.count)
- queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, p);
+ queue_push(selection, p);
}
queue_free(&q);
solv_free(rname);
if (!selection->count)
return 0;
+
+ /* convert package list to selection */
+ j = selection->count;
+ queue_insertn(selection, 0, selection->count, 0);
+ for (i = 0; i < selection->count; )
+ {
+ selection->elements[i++] = SOLVER_SOLVABLE | SOLVER_NOAUTOSET;
+ selection->elements[i++] = selection->elements[j++];
+ }
+
if ((flags & SELECTION_FLAT) != 0)
selection_flatten(pool, selection);
- return SELECTION_PROVIDES;
+ return ret | (keyname == SOLVABLE_NAME ? SELECTION_NAME : SELECTION_PROVIDES);
}
-int
-selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker)
+static int
+selection_make_matchdeps_common(Pool *pool, Queue *selection, const char *name, Id dep, int flags, int keyname, int marker)
{
- Id p;
- Queue q;
+ struct limiter limiter;
- queue_empty(selection);
- if (!dep)
- return 0;
- queue_init(&q);
- FOR_POOL_SOLVABLES(p)
+ setup_limiter(pool, flags, &limiter);
+ if ((flags & SELECTION_MODEBITS) != SELECTION_REPLACE)
{
- Solvable *s = pool->solvables + p;
- int i;
-
- if (s->repo != pool->installed && !pool_installable(pool, s))
+ int ret;
+ Queue q, qlimit;
+ queue_init(&q);
+ queue_init(&qlimit);
+ /* deal with special filter cases */
+ if ((flags & SELECTION_MODEBITS) == SELECTION_FILTER && selection->count == 2 && limiter.end)
{
- if (!(flags & SELECTION_SOURCE_ONLY) || (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC))
- continue;
- if (pool_disabled_solvable(pool, s))
- continue;
+ if ((selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
+ flags = (flags & ~SELECTION_MODEBITS) | SELECTION_REPLACE;
+ else if ((selection->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_REPO)
+ {
+ Repo *repo = pool_id2repo(pool, selection->elements[1]);
+ if (limiter.repofilter && repo != limiter.repofilter)
+ repo = 0;
+ limiter.repofilter = repo;
+ limiter.start = repo ? repo->start : 0;
+ limiter.end = repo ? repo->end : 0;
+ flags = (flags & ~SELECTION_MODEBITS) | SELECTION_REPLACE;
+ }
}
- if ((flags & SELECTION_INSTALLED_ONLY) != 0 && s->repo != pool->installed)
- continue;
- if ((s->arch == ARCH_SRC || s->arch == ARCH_NOSRC) && !(flags & SELECTION_SOURCE_ONLY) && !(flags & SELECTION_WITH_SOURCE))
- continue;
- queue_empty(&q);
- repo_lookup_deparray(s->repo, p, keyname, &q, marker);
- for (i = 0; i < q.count; i++)
+ if (limiter.end && ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT || (flags & SELECTION_MODEBITS) == SELECTION_FILTER))
+ {
+ selection_solvables(pool, selection, &qlimit);
+ limiter.start = 0;
+ limiter.end = qlimit.count;
+ limiter.mapper = qlimit.elements;
+ }
+ ret = selection_make_matchdeps_common_limited(pool, &q, name, dep, flags & ~SELECTION_MODEBITS, keyname, marker, &limiter);
+ queue_free(&qlimit);
+ if ((flags & SELECTION_MODEBITS) == SELECTION_ADD)
+ selection_add(pool, selection, &q);
+ else if ((flags & SELECTION_MODEBITS) == SELECTION_SUBTRACT)
+ selection_subtract(pool, selection, &q);
+ else if ((flags & SELECTION_MODEBITS) == SELECTION_FILTER)
{
- if ((flags & SELECTION_MATCH_DEPSTR) != 0) /* mis-use */
+ if (ret || !(flags & SELECTION_FILTER_KEEP_IFEMPTY))
{
- if (q.elements[i] == dep)
- break;
- continue;
+ if ((flags & SELECTION_FILTER_SWAPPED) != 0)
+ {
+ selection_filter(pool, &q, selection);
+ queue_free(selection);
+ queue_init_clone(selection, &q);
+ }
+ else
+ selection_filter(pool, selection, &q);
}
- if (pool_match_dep(pool, q.elements[i], dep))
- break;
}
- if (i < q.count)
- queue_push2(selection, SOLVER_SOLVABLE | SOLVER_NOAUTOSET, p);
+ else if (ret || !(flags & SELECTION_FILTER_KEEP_IFEMPTY))
+ {
+ /* special filter case from above */
+ int i;
+ Id f = selection->elements[0] & ~(SOLVER_SELECTMASK|SOLVER_NOAUTOSET); /* job, jobflags, setflags */
+ queue_free(selection);
+ queue_init_clone(selection, &q);
+ for (i = 0; i < selection->count; i += 2)
+ selection->elements[i] = (selection->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | f;
+ }
+ queue_free(&q);
+ return ret;
}
- queue_free(&q);
- if (!selection->count)
- return 0;
- if ((flags & SELECTION_FLAT) != 0)
- selection_flatten(pool, selection);
- return SELECTION_PROVIDES;
+ return selection_make_matchdeps_common_limited(pool, selection, name, dep, flags, keyname, marker, &limiter);
+}
+
+/*
+ * select against the dependencies in keyname
+ * like SELECTION_PROVIDES, but with the deps in keyname instead of provides.
+ * supported match modifiers:
+ * SELECTION_REL
+ * SELECTION_GLOB
+ * SELECTION_NOCASE
+ */
+int
+selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker)
+{
+ return selection_make_matchdeps_common(pool, selection, name, 0, flags, keyname, marker);
+}
+
+/*
+ * select against the dependency id in keyname
+ */
+int
+selection_make_matchdepid(Pool *pool, Queue *selection, Id dep, int flags, int keyname, int marker)
+{
+ return selection_make_matchdeps_common(pool, selection, 0, dep, flags, keyname, marker);
}
static inline int
}
}
-void
-selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
+static void
+selection_filter_map(Pool *pool, Queue *sel, Map *m, int setflags)
{
int i, j, miss;
+ Queue q;
+ Id p, pp;
+
+ queue_init(&q);
+ for (i = j = 0; i < sel->count; i += 2)
+ {
+ Id select = sel->elements[i] & SOLVER_SELECTMASK;
+ queue_empty(&q);
+ miss = 0;
+ if (select == SOLVER_SOLVABLE_ALL)
+ {
+ FOR_POOL_SOLVABLES(p)
+ {
+ if (map_tst(m, p))
+ queue_push(&q, p);
+ else
+ miss = 1;
+ }
+ }
+ else if (select == SOLVER_SOLVABLE_REPO)
+ {
+ Solvable *s;
+ Repo *repo = pool_id2repo(pool, sel->elements[i + 1]);
+ if (repo)
+ {
+ FOR_REPO_SOLVABLES(repo, p, s)
+ {
+ if (map_tst(m, p))
+ queue_push(&q, p);
+ else
+ miss = 1;
+ }
+ }
+ }
+ else
+ {
+ FOR_JOB_SELECT(p, pp, select, sel->elements[i + 1])
+ {
+ if (map_tst(m, p))
+ queue_pushunique(&q, p);
+ else
+ miss = 1;
+ }
+ }
+ if (!q.count)
+ continue;
+ if (!miss)
+ {
+ sel->elements[j] = sel->elements[i] | setflags;
+ sel->elements[j + 1] = sel->elements[i + 1];
+ }
+ else if (q.count > 1)
+ {
+ sel->elements[j] = (sel->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
+ sel->elements[j + 1] = pool_queuetowhatprovides(pool, &q);
+ }
+ else
+ {
+ sel->elements[j] = (sel->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
+ sel->elements[j + 1] = q.elements[0];
+ }
+ j += 2;
+ }
+ queue_truncate(sel, j);
+ queue_free(&q);
+}
+
+static void
+selection_filter_int(Pool *pool, Queue *sel1, Queue *sel2, int invert)
+{
+ int i, j;
Id p, pp, q1filled = 0;
Queue q1;
Map m2;
if (!sel1->count || !sel2->count)
{
+ if (invert && !sel2->count)
+ return;
queue_empty(sel1);
return;
}
- if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL)
+ if (sel1->count == 2 && (sel1->elements[0] & SOLVER_SELECTMASK) == SOLVER_SOLVABLE_ALL && !invert)
{
/* XXX: not 100% correct, but very useful */
p = sel1->elements[0] & ~(SOLVER_SELECTMASK | SOLVER_SETMASK); /* job & jobflags */
sel1->elements[i] = (sel1->elements[i] & (SOLVER_SELECTMASK | SOLVER_SETMASK)) | p ;
return;
}
+
+ /* convert sel2 into a map */
queue_init(&q1);
map_init(&m2, pool->nsolvables);
for (i = 0; i < sel2->count; i += 2)
{
queue_free(&q1);
map_free(&m2);
+ if (invert)
+ queue_empty(sel1);
return;
}
if (select == SOLVER_SOLVABLE_REPO)
map_set(&m2, p);
}
}
- if (sel2->count == 2) /* XXX: AND all setmasks instead? */
- setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET;
- for (i = j = 0; i < sel1->count; i += 2)
- {
- Id select = sel1->elements[i] & SOLVER_SELECTMASK;
- queue_empty(&q1);
- miss = 0;
- if (select == SOLVER_SOLVABLE_ALL)
- {
- FOR_POOL_SOLVABLES(p)
- {
- if (map_tst(&m2, p))
- queue_push(&q1, p);
- else
- miss = 1;
- }
- }
- else if (select == SOLVER_SOLVABLE_REPO)
- {
- Solvable *s;
- Repo *repo = pool_id2repo(pool, sel1->elements[i + 1]);
- if (repo)
- {
- FOR_REPO_SOLVABLES(repo, p, s)
- {
- if (map_tst(&m2, p))
- queue_push(&q1, p);
- else
- miss = 1;
- }
- }
- }
- else
- {
- FOR_JOB_SELECT(p, pp, select, sel1->elements[i + 1])
- {
- if (map_tst(&m2, p))
- queue_pushunique(&q1, p);
- else
- miss = 1;
- }
- }
- if (!q1.count)
- continue;
- if (!miss)
- {
- sel1->elements[j] = sel1->elements[i] | setflags;
- sel1->elements[j + 1] = sel1->elements[i + 1];
- }
- else if (q1.count > 1)
- {
- sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE_ONE_OF | setflags;
- sel1->elements[j + 1] = pool_queuetowhatprovides(pool, &q1);
- }
- else
- {
- sel1->elements[j] = (sel1->elements[i] & ~SOLVER_SELECTMASK) | SOLVER_SOLVABLE | SOLVER_NOAUTOSET | setflags;
- sel1->elements[j + 1] = q1.elements[0];
- }
- j += 2;
- }
- queue_truncate(sel1, j);
queue_free(&q1);
+
+ /* now filter sel1 with the map */
+ if (invert)
+ map_invertall(&m2);
+ if (sel2->count == 2)
+ setflags = sel2->elements[0] & SOLVER_SETMASK & ~SOLVER_NOAUTOSET;
+ selection_filter_map(pool, sel1, &m2, setflags);
map_free(&m2);
}
void
+selection_filter(Pool *pool, Queue *sel1, Queue *sel2)
+{
+ selection_filter_int(pool, sel1, sel2, 0);
+}
+
+void
selection_add(Pool *pool, Queue *sel1, Queue *sel2)
{
- int i;
- for (i = 0; i < sel2->count; i++)
- queue_push(sel1, sel2->elements[i]);
+ if (sel2->count)
+ queue_insertn(sel1, sel1->count, sel2->count, sel2->elements);
+}
+
+void
+selection_subtract(Pool *pool, Queue *sel1, Queue *sel2)
+{
+ selection_filter_int(pool, sel1, sel2, 1);
}
const char *
extern "C" {
#endif
+/* what to match */
#define SELECTION_NAME (1 << 0)
#define SELECTION_PROVIDES (1 << 1)
#define SELECTION_FILELIST (1 << 2)
#define SELECTION_CANON (1 << 3)
-#define SELECTION_DOTARCH (1 << 4)
-#define SELECTION_REL (1 << 5)
-#define SELECTION_INSTALLED_ONLY (1 << 8)
+/* match extensions */
+#define SELECTION_DOTARCH (1 << 4) /* allow ".arch" suffix */
+#define SELECTION_REL (1 << 5) /* allow "<=> rel" suffix */
+
+/* string comparison modifiers */
#define SELECTION_GLOB (1 << 9)
-#define SELECTION_FLAT (1 << 10)
#define SELECTION_NOCASE (1 << 11)
+
+/* extra flags */
+#define SELECTION_FLAT (1 << 10) /* flatten the resulting selection */
+#define SELECTION_SKIP_KIND (1 << 14) /* remove kind: name prefix in SELECTION_NAME matches */
+#define SELECTION_MATCH_DEPSTR (1 << 15) /* match dep2str result */
+
+/* package selection */
+#define SELECTION_INSTALLED_ONLY (1 << 8)
#define SELECTION_SOURCE_ONLY (1 << 12)
#define SELECTION_WITH_SOURCE (1 << 13)
-#define SELECTION_SKIP_KIND (1 << 14)
-#define SELECTION_MATCH_DEPSTR (1 << 15)
+#define SELECTION_WITH_DISABLED (1 << 16)
+#define SELECTION_WITH_BADARCH (1 << 17)
+#define SELECTION_WITH_ALL (SELECTION_WITH_SOURCE | SELECTION_WITH_DISABLED | SELECTION_WITH_BADARCH)
+
+/* result operator */
+#define SELECTION_REPLACE (0 << 28)
+#define SELECTION_ADD (1 << 28)
+#define SELECTION_SUBTRACT (2 << 28)
+#define SELECTION_FILTER (3 << 28)
+
+#define SELECTION_MODEBITS (3 << 28) /* internal */
+
+/* extra SELECTION_FILTER bits */
+#define SELECTION_FILTER_KEEP_IFEMPTY (1 << 30)
+#define SELECTION_FILTER_SWAPPED (1 << 31)
+
extern int selection_make(Pool *pool, Queue *selection, const char *name, int flags);
extern int selection_make_matchdeps(Pool *pool, Queue *selection, const char *name, int flags, int keyname, int marker);
extern void selection_filter(Pool *pool, Queue *sel1, Queue *sel2);
extern void selection_add(Pool *pool, Queue *sel1, Queue *sel2);
+extern void selection_subtract(Pool *pool, Queue *sel1, Queue *sel2);
+
extern void selection_solvables(Pool *pool, Queue *selection, Queue *pkgs);
extern const char *pool_selection2str(Pool *pool, Queue *selection, Id flagmask);
#define RULES_BLOCK 63
-static Id
-autouninstall(Solver *solv, Id *problem)
-{
- Pool *pool = solv->pool;
- int i;
- int lastfeature = 0, lastupdate = 0;
- Id v;
- Id extraflags = -1;
- Map *m = 0;
-
- if (!solv->allowuninstall && !solv->allowuninstall_all)
- {
- if (!solv->allowuninstallmap.size)
- return 0; /* why did we get called? */
- m = &solv->allowuninstallmap;
- }
- for (i = 0; (v = problem[i]) != 0; i++)
- {
- if (v < 0)
- extraflags &= solv->job.elements[-v - 1];
- if (v >= solv->updaterules && v < solv->updaterules_end)
- {
- Rule *r;
- if (m && !MAPTST(m, v - solv->updaterules))
- continue;
- /* check if identical to feature rule, we don't like that (except for orphans) */
- r = solv->rules + solv->featurerules + (v - solv->updaterules);
- if (!r->p)
- {
- /* update rule == feature rule */
- if (v > lastfeature)
- lastfeature = v;
- /* prefer orphaned packages in dup mode */
- if (solv->keep_orphans)
- {
- r = solv->rules + v;
- if (!r->d && !r->w2 && r->p == (solv->installed->start + (v - solv->updaterules)))
- {
- lastfeature = v;
- lastupdate = 0;
- break;
- }
- }
- continue;
- }
- if (v > lastupdate)
- lastupdate = v;
- }
- }
- if (!lastupdate && !lastfeature)
- return 0;
- v = lastupdate ? lastupdate : lastfeature;
- POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling ");
- solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v);
- solver_disableproblem(solv, v);
- if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size)
- {
- /* add the package to the updatepkgs list, this will automatically turn
- * on cleandeps mode */
- Id p = solv->rules[v].p;
- if (!solv->cleandeps_updatepkgs)
- {
- solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
- queue_init(solv->cleandeps_updatepkgs);
- }
- if (p > 0)
- {
- int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count;
- queue_pushunique(solv->cleandeps_updatepkgs, p);
- if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt)
- solver_disablepolicyrules(solv);
- }
- }
- return v;
-}
-
/************************************************************************/
/*
* If we find a conflict, disable rules and add them to problem queue.
*/
-static void
-makeruledecisions(Solver *solv)
+static int
+makeruledecisions(Solver *solv, int disablerules)
{
Pool *pool = solv->pool;
- int i, ri, ii;
+ int i, ri, ii, ori;
Rule *r, *rr;
Id v, vv;
int decisionstart;
int record_proof = 1;
int oldproblemcount;
int havedisabled = 0;
+ int doautouninstall;
/* The system solvable is always installed first */
assert(solv->decisionq.count == 0);
if (!solv->decisionmap[vv]) /* if not yet decided */
{
queue_push(&solv->decisionq, v);
- queue_push(&solv->decisionq_why, r - solv->rules);
+ queue_push(&solv->decisionq_why, ri);
solv->decisionmap[vv] = v > 0 ? 1 : -1;
IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
{
/* conflict with a learnt rule */
/* can happen when packages cannot be installed for multiple reasons. */
/* we disable the learnt rule in this case */
- /* (XXX: we should really call analyze_unsolvable_rule here!) */
+ /* (XXX: we should really do something like analyze_unsolvable_rule here!) */
solver_disablerule(solv, r);
continue;
}
POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ASSERTION ----------------------\n");
- IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
- solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ri);
+ assert(ri >= solv->pkgrules_end); /* must not have a conflict in the pkg rules! */
/*
* find the decision which is the "opposite" of the rule
if (solv->decisionq.elements[i] == -v)
break;
assert(i < solv->decisionq.count); /* assert that we found it */
- oldproblemcount = solv->problems.count;
-
- /*
- * conflict with system solvable ?
- */
if (v == -SYSTEMSOLVABLE)
+ ori = 0;
+ else
{
- if (record_proof)
- {
- queue_push(&solv->problems, solv->learnt_pool.count);
- queue_push(&solv->learnt_pool, ri);
- queue_push(&solv->learnt_pool, 0);
- }
- else
- queue_push(&solv->problems, 0);
- POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri);
- if (ri >= solv->jobrules && ri < solv->jobrules_end)
- v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
- else
- v = ri;
- queue_push(&solv->problems, v);
- queue_push(&solv->problems, 0);
- if (v >= solv->featurerules && v < solv->updaterules_end)
- {
- if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
- if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0)
- {
- solv->problems.count = oldproblemcount;
- havedisabled = 1;
- break; /* start over */
- }
- }
- solver_disableproblem(solv, v);
- havedisabled = 1;
- break; /* start over */
+ ori = solv->decisionq_why.elements[i]; /* the conflicting rule */
+ assert(ori > 0);
}
- assert(solv->decisionq_why.elements[i] > 0);
- IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
- solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + solv->decisionq_why.elements[i]);
-
/*
- * conflict with a pkg rule ?
- */
- if (solv->decisionq_why.elements[i] < solv->pkgrules_end)
+ * record the problem
+ */
+ doautouninstall = 0;
+ oldproblemcount = solv->problems.count;
+ queue_push(&solv->problems, 0); /* start problem */
+ if (ori < solv->pkgrules_end)
{
- if (record_proof)
+ /* easy: conflict with system solvable or pkg rule */
+ assert(v > 0 || v == -SYSTEMSOLVABLE);
+ IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
{
- queue_push(&solv->problems, solv->learnt_pool.count);
- queue_push(&solv->learnt_pool, ri);
- queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
- queue_push(&solv->learnt_pool, 0);
+ if (ori)
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with pkg rule, disabling rule #%d\n", ri);
+ else
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri);
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ri);
+ if (ori)
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + ori);
}
- else
- queue_push(&solv->problems, 0);
- assert(v > 0 || v == -SYSTEMSOLVABLE);
- POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with pkg rule, disabling rule #%d\n", ri);
- if (ri >= solv->jobrules && ri < solv->jobrules_end)
- v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
- else
- v = ri;
- queue_push(&solv->problems, v);
- queue_push(&solv->problems, 0);
- if (v >= solv->featurerules && v < solv->updaterules_end)
+ solver_recordproblem(solv, ri);
+ if (ri >= solv->featurerules && ri < solv->updaterules_end)
+ doautouninstall = 1;
+ }
+ else
+ {
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv);
+ /*
+ * push all of our rules (can only be feature or job rules)
+ * asserting this literal on the problem stack
+ */
+ for (i = solv->pkgrules_end, rr = solv->rules + i; i < solv->learntrules; i++, rr++)
{
- if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
- if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0)
- {
- solv->problems.count = oldproblemcount;
- havedisabled = 1;
- break; /* start over */
- }
+ if (rr->d < 0 /* disabled */
+ || rr->w2) /* or no assertion */
+ continue;
+ if (rr->p != vv /* not affecting the literal */
+ && rr->p != -vv)
+ continue;
+ if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */
+ continue;
+
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
+ solver_recordproblem(solv, i);
+ if (i >= solv->featurerules && i < solv->updaterules_end)
+ doautouninstall = 1;
}
- solver_disableproblem(solv, v);
- havedisabled = 1;
- break; /* start over */
}
+ queue_push(&solv->problems, 0); /* finish problem */
- /*
- * conflict with another job or update/feature rule
- */
+ /* try autouninstall if requested */
+ if (doautouninstall)
+ {
+ if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
+ if (solver_autouninstall(solv, oldproblemcount) != 0)
+ {
+ solv->problems.count = oldproblemcount;
+ havedisabled = 1;
+ break; /* start over */
+ }
+ }
- /* record proof */
+ /* record the proof if requested */
if (record_proof)
{
- queue_push(&solv->problems, solv->learnt_pool.count);
+ solv->problems.elements[oldproblemcount] = solv->learnt_pool.count;
queue_push(&solv->learnt_pool, ri);
- queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
+ if (ori)
+ queue_push(&solv->learnt_pool, ori);
queue_push(&solv->learnt_pool, 0);
}
- else
- queue_push(&solv->problems, 0);
- POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv);
-
- /*
- * push all of our rules (can only be feature or job rules)
- * asserting this literal on the problem stack
- */
- for (i = solv->featurerules, rr = solv->rules + i; i < solv->learntrules; i++, rr++)
+ if (!disablerules)
{
- if (rr->d < 0 /* disabled */
- || rr->w2) /* or no assertion */
- continue;
- if (rr->p != vv /* not affecting the literal */
- && rr->p != -vv)
- continue;
- if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, i)) /* weak: silently ignore */
- continue;
-
- POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
- solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
-
- v = i;
- if (i >= solv->jobrules && i < solv->jobrules_end)
- v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
- queue_push(&solv->problems, v);
+ POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
+ return -1;
}
- queue_push(&solv->problems, 0);
-
- if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
- if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0)
- {
- solv->problems.count = oldproblemcount;
- havedisabled = 1;
- break; /* start over */
- }
-
- for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
- solver_disableproblem(solv, solv->problems.elements[i]);
+ /* disable all problem rules */
+ solver_disableproblemset(solv, oldproblemcount);
havedisabled = 1;
break; /* start over */
}
continue;
POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling ");
- solver_printrule(solv, SOLV_DEBUG_UNSOLVABLE, r);
-
- if (ri >= solv->jobrules && ri < solv->jobrules_end)
- v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
- else
- v = ri;
- solver_disableproblem(solv, v);
- if (v < 0)
- solver_reenablepolicyrules(solv, -v);
+ solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r);
+ solver_fixproblem(solv, ri);
havedisabled = 1;
break; /* start over */
}
if (ii == solv->ruleassertions.count)
break; /* finished! */
}
+ return 1; /* the new level */
}
}
if (solv->weakrulemap.size && MAPTST(&solv->weakrulemap, why) && weakq)
queue_push(weakq, why);
- /* do not add pkg rules to problem */
- if (why < solv->pkgrules_end)
- return;
- /* turn rule into problem */
- if (why >= solv->jobrules && why < solv->jobrules_end)
- why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
- /* normalize dup/infarch rules */
- if (why > solv->infarchrules && why < solv->infarchrules_end)
- {
- Id name = pool->solvables[-solv->rules[why].p].name;
- while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
- why--;
- }
- if (why > solv->duprules && why < solv->duprules_end)
- {
- Id name = pool->solvables[-solv->rules[why].p].name;
- while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
- why--;
- }
-
- /* return if problem already countains our rule */
- if (solv->problems.count)
- {
- for (i = solv->problems.count - 1; i >= 0; i--)
- if (solv->problems.elements[i] == 0) /* end of last problem reached? */
- break;
- else if (solv->problems.elements[i] == why)
- return;
- }
- queue_push(&solv->problems, why);
+ /* add non-pkg rules to problem and disable */
+ if (why >= solv->pkgrules_end)
+ solver_recordproblem(solv, why);
}
return 0;
}
queue_free(&weakq);
- if (lastweak >= solv->jobrules && lastweak < solv->jobrules_end)
- v = -(solv->ruletojob.elements[lastweak - solv->jobrules] + 1);
- else
- v = lastweak;
POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak);
if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end)
solver_disablechoicerules(solv, solv->rules + lastweak);
- solver_disableproblem(solv, v);
- if (v < 0)
- solver_reenablepolicyrules(solv, -v);
+ solver_fixproblem(solv, lastweak);
solver_reset(solv);
return 0;
}
queue_free(&weakq);
if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
- if (autouninstall(solv, solv->problems.elements + oldproblemcount + 1) != 0)
+ if (solver_autouninstall(solv, oldproblemcount) != 0)
{
solv->problems.count = oldproblemcount;
solv->learnt_pool.count = oldlearntpoolcount;
/* + 2: index + trailing zero */
if (disablerules && oldproblemcount + 2 < solv->problems.count)
{
- for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
- solver_disableproblem(solv, solv->problems.elements[i]);
+ solver_disableproblemset(solv, oldproblemcount);
/* XXX: might want to enable all weak rules again */
solver_reset(solv);
return 0;
{
if (level < 0)
break;
- makeruledecisions(solv);
- level = 1;
- if (!disablerules && solv->problems.count)
- {
- level = -1;
- break;
- }
+ level = makeruledecisions(solv, disablerules);
+ if (level < 0)
+ break;
POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "initial propagate (propagate_index: %d; size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
if ((r = propagate(solv, level)) != 0)
{
deduceq2addedmap(solv, &addedmap);
if (solv->nrules != initialnrules)
solver_shrinkrules(solv, initialnrules);
- solv->nrules = initialnrules;
solv->lastpkgrule = 0;
solv->pkgrules_end = 0;
}
break;
case SOLVER_DROP_ORPHANED:
- if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
+ if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
solv->droporphanedmap_all = 1;
FOR_JOB_SELECT(p, pp, select, what)
{
/* now create infarch and dup rules */
if (!solv->noinfarchcheck)
- {
- solver_addinfarchrules(solv, &addedmap);
-#if 0
- if (pool->implicitobsoleteusescolors)
- {
- /* currently doesn't work well with infarch rules, so make
- * them weak */
- for (i = solv->infarchrules; i < solv->infarchrules_end; i++)
- queue_push(&solv->weakruleq, i);
- }
-#endif
- }
+ solver_addinfarchrules(solv, &addedmap);
else
solv->infarchrules = solv->infarchrules_end = solv->nrules;
if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob)
solver_addbestrules(solv, hasbestinstalljob);
else
- solv->bestrules = solv->bestrules_end = solv->nrules;
+ solv->bestrules = solv->bestrules_end = solv->bestrules_up = solv->nrules;
if (needduprules)
solver_freedupmaps(solv); /* no longer needed */
map_free(&installcandidatemap);
queue_free(&q);
- POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules);
+ POOL_DEBUG(SOLV_DEBUG_STATS, "%d pkg rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules, %d yumobs rules\n", solv->pkgrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules, solv->yumobsrules_end - solv->yumobsrules);
POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
/* create weak map */
return 1;
}
-static int
-get_userinstalled_cmp(const void *ap, const void *bp, void *dp)
-{
- return *(Id *)ap - *(Id *)bp;
-}
-
-static int
-get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp)
-{
- Pool *pool = dp;
- return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp));
-}
-
-static int
-get_userinstalled_cmp_namearch(const void *ap, const void *bp, void *dp)
-{
- Pool *pool = dp;
- int r;
- r = strcmp(pool_id2str(pool, ((Id *)ap)[0]), pool_id2str(pool, ((Id *)bp)[0]));
- if (r)
- return r;
- return strcmp(pool_id2str(pool, ((Id *)ap)[1]), pool_id2str(pool, ((Id *)bp)[1]));
-}
-
-static void
-get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags)
-{
- Id lastp = -1, lasta = -1;
- int i, j;
- if (q->count < ((flags & GET_USERINSTALLED_NAMEARCH) ? 4 : 2))
- return;
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), get_userinstalled_cmp_namearch, pool);
- else if ((flags & GET_USERINSTALLED_NAMES) != 0)
- solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool);
- else
- solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0);
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- {
- for (i = j = 0; i < q->count; i += 2)
- if (q->elements[i] != lastp || q->elements[i + 1] != lasta)
- {
- q->elements[j++] = lastp = q->elements[i];
- q->elements[j++] = lasta = q->elements[i + 1];
- }
- }
- else
- {
- for (i = j = 0; i < q->count; i++)
- if (q->elements[i] != lastp)
- q->elements[j++] = lastp = q->elements[i];
- }
- queue_truncate(q, j);
-}
-
-static void
-namearch2solvables(Pool *pool, Queue *q, Queue *qout, int job)
-{
- int i;
- if (!pool->installed)
- return;
- for (i = 0; i < q->count; i += 2)
- {
- Id p, pp, name = q->elements[i], arch = q->elements[i + 1];
- FOR_PROVIDES(p, pp, name)
- {
- Solvable *s = pool->solvables + p;
- if (s->repo != pool->installed || s->name != name || (arch && s->arch != arch))
- continue;
- if (job)
- queue_push(qout, job);
- queue_push(qout, p);
- }
- }
-}
-
-void
-solver_get_userinstalled(Solver *solv, Queue *q, int flags)
-{
- Pool *pool = solv->pool;
- Id p, p2, pp;
- Solvable *s;
- Repo *installed = solv->installed;
- int i, j;
- Map userinstalled;
-
- map_init(&userinstalled, 0);
- queue_empty(q);
- /* first process jobs */
- for (i = 0; i < solv->job.count; i += 2)
- {
- Id how = solv->job.elements[i];
- Id what, select;
- if (installed && (how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
- {
- if (!userinstalled.size)
- map_grow(&userinstalled, installed->end - installed->start);
- what = solv->job.elements[i + 1];
- select = how & SOLVER_SELECTMASK;
- if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
- {
- FOR_REPO_SOLVABLES(installed, p, s)
- MAPSET(&userinstalled, p - installed->start);
- }
- FOR_JOB_SELECT(p, pp, select, what)
- if (pool->solvables[p].repo == installed)
- MAPSET(&userinstalled, p - installed->start);
- continue;
- }
- if ((how & SOLVER_JOBMASK) != SOLVER_INSTALL)
- continue;
- if ((how & SOLVER_NOTBYUSER) != 0)
- continue;
- what = solv->job.elements[i + 1];
- select = how & SOLVER_SELECTMASK;
- FOR_JOB_SELECT(p, pp, select, what)
- if (solv->decisionmap[p] > 0)
- {
- queue_push(q, p);
-#ifdef ENABLE_LINKED_PKGS
- if (has_package_link(pool, pool->solvables + p))
- {
- int j;
- Queue lq;
- queue_init(&lq);
- find_package_link(pool, pool->solvables + p, 0, &lq, 0, 0);
- for (j = 0; j < lq.count; j++)
- if (solv->decisionmap[lq.elements[j]] > 0)
- queue_push(q, lq.elements[j]);
- }
-#endif
- }
- }
- /* now process updates of userinstalled packages */
- if (installed && userinstalled.size)
- {
- for (i = 1; i < solv->decisionq.count; i++)
- {
- p = solv->decisionq.elements[i];
- if (p <= 0)
- continue;
- s = pool->solvables + p;
- if (!s->repo)
- continue;
- if (s->repo == installed)
- {
- if (MAPTST(&userinstalled, p - installed->start))
- queue_push(q, p);
- continue;
- }
- /* new package, check if we replace a userinstalled one */
- FOR_PROVIDES(p2, pp, s->name)
- {
- Solvable *ps = pool->solvables + p2;
- if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
- continue;
- if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
- continue;
- if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
- continue;
- queue_push(q, p);
- break;
- }
- if (!p2 && s->repo != installed && s->obsoletes)
- {
- Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
- while ((obs = *obsp++) != 0)
- {
- FOR_PROVIDES(p2, pp, obs)
- {
- Solvable *ps = pool->solvables + p2;
- if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
- continue;
- if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
- continue;
- if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
- continue;
- queue_push(q, p);
- break;
- }
- if (p2)
- break;
- }
- }
- }
- }
- map_free(&userinstalled);
-
- /* convert to desired output format */
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- {
- int qcount = q->count;
- queue_insertn(q, 0, qcount, 0);
- for (i = j = 0; i < qcount; i++)
- {
- s = pool->solvables + q->elements[i + qcount];
- q->elements[j++] = s->name;
- q->elements[j++] = s->arch;
- }
- }
- else if ((flags & GET_USERINSTALLED_NAMES) != 0)
- {
- for (i = 0; i < q->count; i++)
- {
- s = pool->solvables + q->elements[i];
- q->elements[i] = s->name;
- }
- }
- /* sort and unify */
- get_userinstalled_sort_uniq(pool, q, flags);
-
- /* invert if asked for */
- if ((flags & GET_USERINSTALLED_INVERTED) != 0)
- {
- /* first generate queue with all installed packages */
- Queue invq;
- queue_init(&invq);
- for (i = 1; i < solv->decisionq.count; i++)
- {
- p = solv->decisionq.elements[i];
- if (p <= 0)
- continue;
- s = pool->solvables + p;
- if (!s->repo)
- continue;
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- queue_push2(&invq, s->name, s->arch);
- else if ((flags & GET_USERINSTALLED_NAMES) != 0)
- queue_push(&invq, s->name);
- else
- queue_push(&invq, p);
- }
- /* push q on invq, just in case... */
- queue_insertn(&invq, invq.count, q->count, q->elements);
- get_userinstalled_sort_uniq(pool, &invq, flags);
- /* subtract queues (easy as they are sorted and invq is a superset of q) */
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- {
- if (q->count)
- {
- for (i = j = 0; i < invq.count; i += 2)
- if (invq.elements[i] == q->elements[j] && invq.elements[i + 1] == q->elements[j + 1])
- {
- invq.elements[i] = invq.elements[i + 1] = 0;
- j += 2;
- if (j >= q->count)
- break;
- }
- queue_empty(q);
- }
- for (i = 0; i < invq.count; i += 2)
- if (invq.elements[i])
- queue_push2(q, invq.elements[i], invq.elements[i + 1]);
- }
- else
- {
- if (q->count)
- {
- for (i = j = 0; i < invq.count; i++)
- if (invq.elements[i] == q->elements[j])
- {
- invq.elements[i] = 0;
- if (++j >= q->count)
- break;
- }
- queue_empty(q);
- }
- for (i = 0; i < invq.count; i++)
- if (invq.elements[i])
- queue_push(q, invq.elements[i]);
- }
- queue_free(&invq);
- }
-}
-
-void
-pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags)
-{
- int i;
-
- if ((flags & GET_USERINSTALLED_INVERTED) != 0)
- {
- Queue invq;
- Id p, lastid;
- Solvable *s;
- int bad;
- if (!pool->installed)
- return;
- queue_init(&invq);
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- flags &= ~GET_USERINSTALLED_NAMES; /* just in case */
- FOR_REPO_SOLVABLES(pool->installed, p, s)
- queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p);
- if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
- {
- /* for namearch we convert to packages */
- namearch2solvables(pool, q, &invq, 0);
- get_userinstalled_sort_uniq(pool, &invq, flags);
- namearch2solvables(pool, q, &invq, 0);
- flags = 0;
- }
- else
- {
- queue_insertn(&invq, invq.count, q->count, q->elements);
- get_userinstalled_sort_uniq(pool, &invq, flags);
- /* now the fun part, add q again, sort, and remove all dups */
- queue_insertn(&invq, invq.count, q->count, q->elements);
- }
- if (invq.count > 1)
- {
- if ((flags & GET_USERINSTALLED_NAMES) != 0)
- solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp_names, pool);
- else
- solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp, 0);
- }
- lastid = -1;
- bad = 1;
- for (i = 0; i < invq.count; i++)
- {
- if (invq.elements[i] == lastid)
- {
- bad = 1;
- continue;
- }
- if (!bad)
- queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
- bad = 0;
- lastid = invq.elements[i];
- }
- if (!bad)
- queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
- queue_free(&invq);
- }
- else
- {
- if (flags & GET_USERINSTALLED_NAMEARCH)
- namearch2solvables(pool, q, job, SOLVER_USERINSTALLED | SOLVER_SOLVABLE);
- else
- {
- for (i = 0; i < q->count; i++)
- queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]);
- }
- }
-}
-
int
solver_alternatives_count(Solver *solv)
{
Id duprules_end;
Id bestrules; /* rules from SOLVER_FORCEBEST */
+ Id bestrules_up; /* update rule part starts here*/
Id bestrules_end;
Id *bestrules_pkg;
--- /dev/null
+/*
+ * Copyright (c) 2017, SUSE LLC.
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/* Functions that help getting/setting userinstalled packages. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "solver.h"
+#include "solver_private.h"
+#include "bitmap.h"
+#include "pool.h"
+#include "util.h"
+#include "poolarch.h"
+#include "linkedpkg.h"
+
+static int
+get_userinstalled_cmp(const void *ap, const void *bp, void *dp)
+{
+ return *(Id *)ap - *(Id *)bp;
+}
+
+static int
+get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp)
+{
+ Pool *pool = dp;
+ return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp));
+}
+
+static int
+get_userinstalled_cmp_namearch(const void *ap, const void *bp, void *dp)
+{
+ Pool *pool = dp;
+ int r;
+ r = strcmp(pool_id2str(pool, ((Id *)ap)[0]), pool_id2str(pool, ((Id *)bp)[0]));
+ if (r)
+ return r;
+ return strcmp(pool_id2str(pool, ((Id *)ap)[1]), pool_id2str(pool, ((Id *)bp)[1]));
+}
+
+static void
+get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags)
+{
+ Id lastp = -1, lasta = -1;
+ int i, j;
+ if (q->count < ((flags & GET_USERINSTALLED_NAMEARCH) ? 4 : 2))
+ return;
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ solv_sort(q->elements, q->count / 2, 2 * sizeof(Id), get_userinstalled_cmp_namearch, pool);
+ else if ((flags & GET_USERINSTALLED_NAMES) != 0)
+ solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool);
+ else
+ solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0);
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ {
+ for (i = j = 0; i < q->count; i += 2)
+ if (q->elements[i] != lastp || q->elements[i + 1] != lasta)
+ {
+ q->elements[j++] = lastp = q->elements[i];
+ q->elements[j++] = lasta = q->elements[i + 1];
+ }
+ }
+ else
+ {
+ for (i = j = 0; i < q->count; i++)
+ if (q->elements[i] != lastp)
+ q->elements[j++] = lastp = q->elements[i];
+ }
+ queue_truncate(q, j);
+}
+
+static void
+namearch2solvables(Pool *pool, Queue *q, Queue *qout, int job)
+{
+ int i;
+ if (!pool->installed)
+ return;
+ for (i = 0; i < q->count; i += 2)
+ {
+ Id p, pp, name = q->elements[i], arch = q->elements[i + 1];
+ FOR_PROVIDES(p, pp, name)
+ {
+ Solvable *s = pool->solvables + p;
+ if (s->repo != pool->installed || s->name != name || (arch && s->arch != arch))
+ continue;
+ if (job)
+ queue_push(qout, job);
+ queue_push(qout, p);
+ }
+ }
+}
+
+void
+solver_get_userinstalled(Solver *solv, Queue *q, int flags)
+{
+ Pool *pool = solv->pool;
+ Id p, p2, pp;
+ Solvable *s;
+ Repo *installed = solv->installed;
+ int i, j;
+ Map userinstalled;
+
+ map_init(&userinstalled, 0);
+ queue_empty(q);
+ /* first process jobs */
+ for (i = 0; i < solv->job.count; i += 2)
+ {
+ Id how = solv->job.elements[i];
+ Id what, select;
+ if (installed && (how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
+ {
+ if (!userinstalled.size)
+ map_grow(&userinstalled, installed->end - installed->start);
+ what = solv->job.elements[i + 1];
+ select = how & SOLVER_SELECTMASK;
+ if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
+ {
+ FOR_REPO_SOLVABLES(installed, p, s)
+ MAPSET(&userinstalled, p - installed->start);
+ }
+ FOR_JOB_SELECT(p, pp, select, what)
+ if (pool->solvables[p].repo == installed)
+ MAPSET(&userinstalled, p - installed->start);
+ continue;
+ }
+ if ((how & SOLVER_JOBMASK) != SOLVER_INSTALL)
+ continue;
+ if ((how & SOLVER_NOTBYUSER) != 0)
+ continue;
+ what = solv->job.elements[i + 1];
+ select = how & SOLVER_SELECTMASK;
+ FOR_JOB_SELECT(p, pp, select, what)
+ if (solv->decisionmap[p] > 0)
+ {
+ queue_push(q, p);
+#ifdef ENABLE_LINKED_PKGS
+ if (has_package_link(pool, pool->solvables + p))
+ {
+ int j;
+ Queue lq;
+ queue_init(&lq);
+ find_package_link(pool, pool->solvables + p, 0, &lq, 0, 0);
+ for (j = 0; j < lq.count; j++)
+ if (solv->decisionmap[lq.elements[j]] > 0)
+ queue_push(q, lq.elements[j]);
+ }
+#endif
+ }
+ }
+ /* now process updates of userinstalled packages */
+ if (installed && userinstalled.size)
+ {
+ for (i = 1; i < solv->decisionq.count; i++)
+ {
+ p = solv->decisionq.elements[i];
+ if (p <= 0)
+ continue;
+ s = pool->solvables + p;
+ if (!s->repo)
+ continue;
+ if (s->repo == installed)
+ {
+ if (MAPTST(&userinstalled, p - installed->start))
+ queue_push(q, p);
+ continue;
+ }
+ /* new package, check if we replace a userinstalled one */
+ FOR_PROVIDES(p2, pp, s->name)
+ {
+ Solvable *ps = pool->solvables + p2;
+ if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
+ continue;
+ if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
+ continue;
+ if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
+ continue;
+ queue_push(q, p);
+ break;
+ }
+ if (!p2 && s->repo != installed && s->obsoletes)
+ {
+ Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
+ while ((obs = *obsp++) != 0)
+ {
+ FOR_PROVIDES(p2, pp, obs)
+ {
+ Solvable *ps = pool->solvables + p2;
+ if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
+ continue;
+ if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
+ continue;
+ if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
+ continue;
+ queue_push(q, p);
+ break;
+ }
+ if (p2)
+ break;
+ }
+ }
+ }
+ }
+ map_free(&userinstalled);
+
+ /* convert to desired output format */
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ {
+ int qcount = q->count;
+ queue_insertn(q, 0, qcount, 0);
+ for (i = j = 0; i < qcount; i++)
+ {
+ s = pool->solvables + q->elements[i + qcount];
+ q->elements[j++] = s->name;
+ q->elements[j++] = s->arch;
+ }
+ }
+ else if ((flags & GET_USERINSTALLED_NAMES) != 0)
+ {
+ for (i = 0; i < q->count; i++)
+ {
+ s = pool->solvables + q->elements[i];
+ q->elements[i] = s->name;
+ }
+ }
+ /* sort and unify */
+ get_userinstalled_sort_uniq(pool, q, flags);
+
+ /* invert if asked for */
+ if ((flags & GET_USERINSTALLED_INVERTED) != 0)
+ {
+ /* first generate queue with all installed packages */
+ Queue invq;
+ queue_init(&invq);
+ for (i = 1; i < solv->decisionq.count; i++)
+ {
+ p = solv->decisionq.elements[i];
+ if (p <= 0)
+ continue;
+ s = pool->solvables + p;
+ if (!s->repo)
+ continue;
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ queue_push2(&invq, s->name, s->arch);
+ else if ((flags & GET_USERINSTALLED_NAMES) != 0)
+ queue_push(&invq, s->name);
+ else
+ queue_push(&invq, p);
+ }
+ /* push q on invq, just in case... */
+ queue_insertn(&invq, invq.count, q->count, q->elements);
+ get_userinstalled_sort_uniq(pool, &invq, flags);
+ /* subtract queues (easy as they are sorted and invq is a superset of q) */
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ {
+ if (q->count)
+ {
+ for (i = j = 0; i < invq.count; i += 2)
+ if (invq.elements[i] == q->elements[j] && invq.elements[i + 1] == q->elements[j + 1])
+ {
+ invq.elements[i] = invq.elements[i + 1] = 0;
+ j += 2;
+ if (j >= q->count)
+ break;
+ }
+ queue_empty(q);
+ }
+ for (i = 0; i < invq.count; i += 2)
+ if (invq.elements[i])
+ queue_push2(q, invq.elements[i], invq.elements[i + 1]);
+ }
+ else
+ {
+ if (q->count)
+ {
+ for (i = j = 0; i < invq.count; i++)
+ if (invq.elements[i] == q->elements[j])
+ {
+ invq.elements[i] = 0;
+ if (++j >= q->count)
+ break;
+ }
+ queue_empty(q);
+ }
+ for (i = 0; i < invq.count; i++)
+ if (invq.elements[i])
+ queue_push(q, invq.elements[i]);
+ }
+ queue_free(&invq);
+ }
+}
+
+void
+pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags)
+{
+ int i;
+
+ if ((flags & GET_USERINSTALLED_INVERTED) != 0)
+ {
+ Queue invq;
+ Id p, lastid;
+ Solvable *s;
+ int bad;
+ if (!pool->installed)
+ return;
+ queue_init(&invq);
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ flags &= ~GET_USERINSTALLED_NAMES; /* just in case */
+ FOR_REPO_SOLVABLES(pool->installed, p, s)
+ queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p);
+ if ((flags & GET_USERINSTALLED_NAMEARCH) != 0)
+ {
+ /* for namearch we convert to packages */
+ namearch2solvables(pool, q, &invq, 0);
+ get_userinstalled_sort_uniq(pool, &invq, flags);
+ namearch2solvables(pool, q, &invq, 0);
+ flags = 0;
+ }
+ else
+ {
+ queue_insertn(&invq, invq.count, q->count, q->elements);
+ get_userinstalled_sort_uniq(pool, &invq, flags);
+ /* now the fun part, add q again, sort, and remove all dups */
+ queue_insertn(&invq, invq.count, q->count, q->elements);
+ }
+ if (invq.count > 1)
+ {
+ if ((flags & GET_USERINSTALLED_NAMES) != 0)
+ solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp_names, pool);
+ else
+ solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp, 0);
+ }
+ lastid = -1;
+ bad = 1;
+ for (i = 0; i < invq.count; i++)
+ {
+ if (invq.elements[i] == lastid)
+ {
+ bad = 1;
+ continue;
+ }
+ if (!bad)
+ queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
+ bad = 0;
+ lastid = invq.elements[i];
+ }
+ if (!bad)
+ queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
+ queue_free(&invq);
+ }
+ else
+ {
+ if (flags & GET_USERINSTALLED_NAMEARCH)
+ namearch2solvables(pool, q, job, SOLVER_USERINSTALLED | SOLVER_SOLVABLE);
+ else
+ {
+ for (i = 0; i < q->count; i++)
+ queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]);
+ }
+ }
+}
+
job install name A [forcebest]
result transaction,problems <inline>
-#>erase D-1-1.noarch@system
-#>install A-3-1.noarch@available
#>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch
#>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system
-#>problem 1210fdfb solution d85f7c4e deljob install name A [forcebest]
+#>problem 1210fdfb solution ee74e60f deljob install name A [forcebest]
# currently bestobeypolicy is a noop for install jobs
nextjob
solverflags bestobeypolicy
job install name A [forcebest]
result transaction,problems <inline>
-#>erase D-1-1.noarch@system
-#>install A-3-1.noarch@available
#>problem 1210fdfb info package D-1-1.noarch conflicts with A = 3-1 provided by A-3-1.noarch
#>problem 1210fdfb solution 0d75a914 erase D-1-1.noarch@system
-#>problem 1210fdfb solution d85f7c4e deljob install name A [forcebest]
+#>problem 1210fdfb solution ee74e60f deljob install name A [forcebest]
--- /dev/null
+repo available 0 testtags <inline>
+#>=Pkg: A 1 1 noarch
+#>=Pkg: A 2 1 noarch
+#>=Prv: A = 3.1
+#>=Pkg: A 2 2 i686
+#>=Pkg: A 1:1 1 i686
+#>=Pkg: A 2 2 badarch
+#>=Pkg: A 1:3 1 i686
+system i686 rpm
+
+disable pkg E-1-1.src@available
+disable pkg F-1-1.src@available
+
+job noop selection A-2 canon
+result jobs <inline>
+#>job noop name A = 2 [setev]
+
+nextjob
+job noop selection A-2-1 canon
+result jobs <inline>
+#>job noop name A = 2-1 [setevr]
+
+nextjob
+job noop selection A-3 canon
+result jobs <inline>
+#>job noop name A = 1:3 [setev]
+
+nextjob
+job noop selection A-3-1 canon
+result jobs <inline>
+#>job noop name A = 1:3-1 [setevr]
+
+nextjob
+job noop selection A-1 canon
+result jobs <inline>
+#>job noop oneof A-1-1.noarch@available A-1:1-1.i686@available
+
+nextjob
+job noop selection A-1-1 canon
+result jobs <inline>
+#>job noop oneof A-1-1.noarch@available A-1:1-1.i686@available
+
+
+nextjob
+job noop selection A-0:1-1 canon
+result jobs <inline>
+#>job noop name A = 0:1-1 [setevr]
+
+nextjob
+job noop selection A-1:1-1 canon
+result jobs <inline>
+#>job noop name A = 1:1-1 [setevr]
+
--- /dev/null
+repo available 0 testtags <inline>
+#>=Pkg: bash 1 1 noarch
+#>=Fls: /usr/bin/bash
+#>=Fls: /usr/bin/bashbug
+#>=Pkg: bash 2 1 noarch
+#>=Fls: /usr/bin/bash
+#>=Fls: /usr/bin/bashbug
+#>=Pkg: coreutils 1 1 noarch
+#>=Fls: /usr/bin/basename
+system i686 rpm
+
+job noop selection /usr/bin/ba* filelist,glob
+result jobs <inline>
+#>job noop oneof bash-1-1.noarch@available bash-2-1.noarch@available
+#>job noop pkg coreutils-1-1.noarch@available [noautoset]
+
+nextjob
+job noop selection /usr/bin/ba* filelist,glob,flat
+result jobs <inline>
+#>job noop oneof bash-1-1.noarch@available bash-2-1.noarch@available coreutils-1-1.noarch@available
--- /dev/null
+repo available 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Pkg: AP 3 1 noarch
+#>=Prv: A = 3.1
+#>=Pkg: A 2 2 i686
+#>=Req: BBB > 5
+#>=Pkg: B 1 1 src
+#>=Pkg: A 2 2 badarch
+system i686 rpm
+
+job noop selection_matchdeps solvable:name a = 2 rel,flat,nocase
+result jobs <inline>
+#>job noop oneof A-2-1.noarch@available A-2-2.i686@available
+
+nextjob
+job noop selection_matchdeps solvable:name a = 2-* flat,glob,nocase,depstr
+result jobs <inline>
+#>job noop oneof A-2-1.noarch@available A-2-2.i686@available
+
+nextjob
+job noop selection_matchdepid solvable:name A = 2-1 flat
+result jobs <inline>
+#>job noop pkg A-2-1.noarch@available [noautoset]
+
+nextjob
+job noop selection_matchdepid solvable:name A = 2-2 flat,depstr
+result jobs <inline>
+#>job noop pkg A-2-2.i686@available [noautoset]
+
+nextjob
+job noop selection_matchdepid solvable:name A = 2-2 flat,depstr,withbadarch
+result jobs <inline>
+#>job noop oneof A-2-2.i686@available A-2-2.badarch@available
+
+nextjob
+job noop selection_matchdeps solvable:requires bbb < 10 rel,flat,nocase
+result jobs <inline>
+#>job noop pkg A-2-2.i686@available [noautoset]
+
+nextjob
+job noop selection_matchdeps solvable:requires bbb >* depstr,glob,flat,nocase
+result jobs <inline>
+#>job noop pkg A-2-2.i686@available [noautoset]
+
+nextjob
+job noop selection_matchdepid solvable:requires BBB < 10 flat
+result jobs <inline>
+#>job noop pkg A-2-2.i686@available [noautoset]
+
+nextjob
+job noop selection_matchdepid solvable:requires BBB > 5 flat,depstr
+result jobs <inline>
+#>job noop pkg A-2-2.i686@available [noautoset]
+
--- /dev/null
+repo available 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Pkg: AP 3 1 noarch
+#>=Prv: A = 3.1
+#>=Pkg: A 2 2 i686
+#>=Req: BBB > 5
+#>=Pkg: B 1 1 src
+#>=Pkg: A 2 2 badarch
+#>=Pkg: C 2 2 badarch
+#>=Pkg: D 2 2 noarch
+#>=Pkg: D 2 2 badarch
+#>=Pkg: E 1 1 src
+#>=Pkg: F 1 1 src
+#>=Pkg: F 1 2 src
+#>=Pkg: G 1 1 src
+#>=Pkg: G 1 2 src
+system i686 rpm
+
+disable pkg E-1-1.src@available
+disable pkg F-1-1.src@available
+
+job noop selection A name
+result jobs <inline>
+#>job noop name A
+
+nextjob
+job noop selection A.i686 name,dotarch
+result jobs <inline>
+#>job noop name A . i686 [setarch]
+
+nextjob
+job noop selection A.i686>1 name,dotarch,rel
+result jobs <inline>
+#>job noop name (A . i686) > 1 [setarch]
+
+nextjob
+job noop selection B* glob,name,withsource
+result jobs <inline>
+#>job noop pkg B-1-1.src@available [noautoset]
+
+nextjob
+job noop selection A=2-2 name,dotarch,rel,withbadarch
+result jobs <inline>
+#>job noop oneof A-2-2.i686@available A-2-2.badarch@available [setevr]
+
+nextjob
+job noop selection C name,withbadarch
+result jobs <inline>
+#>job noop pkg C-2-2.badarch@available [noautoset]
+
+nextjob
+job noop selection D name,withbadarch
+result jobs <inline>
+#>job noop oneof D-2-2.noarch@available D-2-2.badarch@available
+
+nextjob
+job noop selection E name,sourceonly,withdisabled
+result jobs <inline>
+#>job noop pkg E-1-1.src@available [noautoset]
+
+nextjob
+job noop selection E name,withsource,withdisabled
+result jobs <inline>
+#>job noop pkg E-1-1.src@available [noautoset]
+
+nextjob
+job noop selection F name,sourceonly,withdisabled
+result jobs <inline>
+#>job noop oneof F-1-1.src@available F-1-2.src@available
+
+nextjob
+job noop selection F name,withsource,withdisabled
+result jobs <inline>
+#>job noop oneof F-1-1.src@available F-1-2.src@available
+
+nextjob
+job noop selection G name,sourceonly,withdisabled
+result jobs <inline>
+#>job noop name G . src
+
+nextjob
+job noop selection G name,withsource,withdisabled
+result jobs <inline>
+#>job noop oneof G-1-1.src@available G-1-2.src@available
+
--- /dev/null
+repo available 0 testtags <inline>
+#>=Pkg: A 2 1 noarch
+#>=Pkg: AP 3 1 noarch
+#>=Prv: A = 3.1
+#>=Pkg: A 2 2 i686
+#>=Req: BBB > 5
+#>=Pkg: B 1 1 src
+#>=Pkg: A 2 2 badarch
+#>=Pkg: C 2 2 badarch
+#>=Pkg: D 2 2 badarch
+#>=Pkg: D 2 2 noarch
+system i686 rpm
+
+job noop selection A provides
+result jobs <inline>
+#>job noop provides A
+
+nextjob
+job noop selection A.i686 provides,dotarch
+result jobs <inline>
+#>job noop provides A . i686 [setarch]
+
+nextjob
+job noop selection A.i686>1 provides,dotarch,rel
+result jobs <inline>
+#>job noop provides (A . i686) > 1 [setarch]
+
+nextjob
+job noop selection A* glob,provides,withbadarch
+result jobs <inline>
+#>job noop oneof A-2-1.noarch@available AP-3-1.noarch@available A-2-2.i686@available A-2-2.badarch@available
+#>job noop provides AP
+
+nextjob
+job noop selection A*>=2 glob,provides,dotarch,rel,withbadarch
+result jobs <inline>
+#>job noop oneof A-2-1.noarch@available AP-3-1.noarch@available A-2-2.i686@available A-2-2.badarch@available
+#>job noop provides AP >= 2
+
+nextjob
+job noop selection C provides,withbadarch
+result jobs <inline>
+#>job noop pkg C-2-2.badarch@available [noautoset]
+
+
+nextjob
+job noop selection D provides,withbadarch
+result jobs <inline>
+#>job noop oneof D-2-2.badarch@available D-2-2.noarch@available
{ TESTCASE_RESULT_ALTERNATIVES, "alternatives" },
{ TESTCASE_RESULT_RULES, "rules" },
{ TESTCASE_RESULT_GENID, "genid" },
+ { TESTCASE_RESULT_REASON, "reason" },
+ { TESTCASE_RESULT_CLEANDEPS, "cleandeps" },
+ { TESTCASE_RESULT_JOBS, "jobs" },
{ 0, 0 }
};