OPTION (ENABLE_ARCHREPO "Build with archlinux repository support?" OFF)
OPTION (ENABLE_CUDFREPO "Build with cudf repository support?" OFF)
OPTION (ENABLE_HAIKU "Build with Haiku package support?" OFF)
+OPTION (ENABLE_CONDA "Build with conda dependency support?" OFF)
OPTION (ENABLE_APPDATA "Build with AppStream appdata support?" OFF)
OPTION (MULTI_SEMANTICS "Build with support for multiple distribution types?" OFF)
IF (ENABLE_ZLIB_COMPRESSION)
FIND_PACKAGE (ZLIB REQUIRED)
+INCLUDE_DIRECTORIES (${ZLIB_INCLUDE_DIRS})
ENDIF (ENABLE_ZLIB_COMPRESSION)
IF (ENABLE_LZMA_COMPRESSION)
FIND_PACKAGE (LZMA REQUIRED)
+INCLUDE_DIRECTORIES (${LZMA_INCLUDE_DIR})
ENDIF (ENABLE_LZMA_COMPRESSION)
IF (ENABLE_BZIP2_COMPRESSION)
FIND_PACKAGE (BZip2 REQUIRED)
+INCLUDE_DIRECTORIES (${BZIP2_INCLUDE_DIRS})
ENDIF (ENABLE_BZIP2_COMPRESSION)
IF (ENABLE_ZSTD_COMPRESSION)
FIND_LIBRARY (ZSTD_LIBRARY NAMES zstd)
+FIND_PATH (ZSTD_INCLUDE_DIRS zstd.h)
+INCLUDE_DIRECTORIES (${ZSTD_INCLUDE_DIRS})
ENDIF (ENABLE_ZSTD_COMPRESSION)
IF (RPM5)
INCLUDE_DIRECTORIES (${RPM_INCLUDE_DIRS})
ENDIF (RPM5)
+IF (ENABLE_CONDA)
+SET (MULTI_SEMANTICS ON)
+ENDIF (ENABLE_CONDA)
+
IF (MULTI_SEMANTICS)
MESSAGE (STATUS "Enabling multi dist support")
ENDIF (MULTI_SEMANTICS)
ENDFOREACH (VAR)
FOREACH (VAR
- ENABLE_LINKED_PKGS ENABLE_COMPLEX_DEPS MULTI_SEMANTICS)
+ ENABLE_LINKED_PKGS ENABLE_COMPLEX_DEPS MULTI_SEMANTICS ENABLE_CONDA)
IF(${VAR})
ADD_DEFINITIONS (-D${VAR}=1)
SET (SWIG_FLAGS ${SWIG_FLAGS} -D${VAR})
This file contains the major changes between
libsolv versions:
+Version 0.7.4
+- selected bug fixes:
+ * repo_add_rpmdb: do not copy bad solvables from the old solv file
+ * fix cleandeps updates not updating all packages
+- new features:
+ * bindings: support pool.matchsolvable(), pool.whatmatchessolvable()
+ pool.best_solvables() and selection.matchsolvable()
+ * experimental DISTTYPE_CONDA and REL_CONDA support
+
Version 0.7.3
- selected bug fixes:
* fixed a couple of null pointer derefs and potential memory
SET(LIBSOLV_MAJOR "0")
SET(LIBSOLV_MINOR "7")
-SET(LIBSOLV_PATCH "3")
+SET(LIBSOLV_PATCH "4")
%typemap(in) Queue Array2Queue(SWIG_AsVal_int, "integers")
%typemap(in) Queue solvejobs ObjArray2Queue(Job *, queue_push2(&$1, obj->how, obj->what))
+%typemap(in) Queue solvables ObjArray2Queue(XSolvable *, queue_push(&$1, obj->id))
%constant int REL_ERROR;
%constant int REL_WITHOUT;
%constant int REL_UNLESS;
+%constant int REL_CONDA;
typedef struct {
Pool* const pool;
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;
flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
$self->flags = selection_make_matchdepid($self->pool, &$self->q, dep, flags, keyname, marker);
}
+ void matchsolvable(XSolvable *solvable, int flags, Id keyname, Id marker = -1) {
+ if ((flags & SELECTION_MODEBITS) == 0)
+ flags |= SELECTION_FILTER | SELECTION_WITH_ALL;
+ $self->flags = selection_make_matchsolvable($self->pool, &$self->q, solvable->id, flags, keyname, marker);
+ }
%typemap(out) Queue jobs Queue2Array(Job *, 2, new_Job(arg1->pool, id, idp[1]));
%newobject jobs;
int result, ecode = 0, vresult = 0;
Tcl_Obj *objvx[2];
objvx[0] = callback_var->obj;
- objvx[1] = SWIG_NewInstanceObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, 0);
+ objvx[1] = SWIG_NewInstanceObj(SWIG_as_voidptr(xd), SWIGTYPE_p_XRepodata, 0);
Tcl_IncrRefCount(objvx[1]);
result = Tcl_EvalObjv(interp, sizeof(objvx)/sizeof(*objvx), objvx, TCL_EVAL_GLOBAL);
Tcl_DecrRefCount(objvx[1]);
queue_push(&q, p);
return q;
}
+ %typemap(out) Queue best_solvables Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id));
+ %newobject best_solvables;
+ Queue best_solvables(Queue solvables, int flags=0) {
+ Queue q;
+ queue_init_clone(&q, &solvables);
+ pool_best_solvables($self, &q, flags);
+ return q;
+ }
Id towhatprovides(Queue q) {
return pool_queuetowhatprovides($self, &q);
return q;
}
+ %typemap(out) Queue whatmatchessolvable Queue2Array(XSolvable *, 1, new_XSolvable(arg1, id));
+ %newobject whatmatchessolvable;
+ Queue whatmatchessolvable(Id keyname, XSolvable *pool_solvable, Id marker = -1) {
+ Queue q;
+ queue_init(&q);
+ pool_whatmatchessolvable($self, keyname, pool_solvable->id, &q, marker);
+ return q;
+ }
+
#ifdef SWIGRUBY
%rename("isknownarch?") isknownarch;
#endif
return sel;
}
+ %newobject matchsolvable;
+ Selection *matchsolvable(XSolvable *solvable, int flags, Id keyname, Id marker = -1) {
+ Selection *sel = new_Selection($self);
+ sel->flags = selection_make_matchsolvable($self, &sel->q, solvable->id, flags, keyname, marker);
+ return sel;
+ }
+
Queue get_considered_list() {
Queue q;
queue_init(&q);
.\" Title: Libsolv-Bindings
.\" Author: [see the "Author" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
-.\" Date: 12/06/2018
+.\" Date: 03/16/2019
.\" Manual: LIBSOLV
.\" Source: libsolv
.\" Language: English
.\"
-.TH "LIBSOLV\-BINDINGS" "3" "12/06/2018" "libsolv" "LIBSOLV"
+.TH "LIBSOLV\-BINDINGS" "3" "03/16/2019" "libsolv" "LIBSOLV"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.RS 4
.\}
.nf
+\fBSolvable *best_solvables(Solvable *\fR\fIsolvables\fR\fB, int\fR \fIflags\fR \fB= 0)\fR
+my \fI@solvables\fR \fB=\fR \fI$pool\fR\fB\->best_solvables(\fR\fI$solvables\fR\fB)\fR;
+\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.best_solvables(\fR\fIsolvables\fR\fB)\fR
+\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.best_solvables(\fR\fIsolvables\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Filter list of solvables by repo priority, architecture and version\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
+\fBSolvable *whatmatchessolvable(Id\fR \fIkeyname\fR\fB, Solvable\fR \fIsolvable\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+my \fI@solvables\fR \fB=\fR \fI$pool\fR\fB\->whatmatchessolvable(\fR\fI$keyname\fR\fB,\fR \fI$solvable\fR\fB)\fR
+\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatmatchessolvable(\fR\fIkeyname\fR\fB,\fR \fIsolvable\fR\fB)\fR
+\fIsolvables\fR \fB=\fR \fIpool\fR\fB\&.whatmatchessolvable(\fR\fIkeyname\fR\fB,\fR \fIsolvable\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Return all solvables that match package dependencies against solvable\(cqs provides\&.
+.sp
+.if n \{\
+.RS 4
+.\}
+.nf
\fBId *matchprovidingids(const char *\fR\fImatch\fR\fB, int\fR \fIflags\fR\fB)\fR
my \fI@ids\fR \fB=\fR \fI$pool\fR\fB\->matchprovidingids(\fR\fI$match\fR\fB,\fR \fI$flags\fR\fB)\fR;
\fIids\fR \fB=\fR \fIpool\fR\fB\&.matchprovidingids(\fR\fImatch\fR\fB,\fR \fIflags\fR\fB)\fR
.\}
.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;
+my \fI$sel\fR \fB=\fR \fI$pool\fR\fB\->matchdepid(\fR\fI$dep\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
.RS 4
.\}
.nf
+\fBSelection matchsolvable(Solvable\fR \fIsolvable\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\->matchsolvable(\fR\fI$solvable\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchsolvable(\fR\fIsolvable\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIsel\fR \fB=\fR \fIpool\fR\fB\&.matchsolvable(\fR\fIsolvable\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 solvable\(cqs provides\&.
+.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
.RS 4
.\}
.nf
+\fBvoid matchsolvable(Solvable\fR \fIsolvable\fR\fB, int\fR \fIflags\fR\fB, Id\fR \fIkeyname\fR\fB, Id\fR \fImarker\fR \fB= \-1)\fR
+\fI$sel\fR\fB\->matchsolvable(\fR\fI$solvable\fR\fB,\fR \fI$flags\fR\fB,\fR \fI$keyname\fR\fB)\fR;
+\fIsel\fR\fB\&.matchsolvable(\fR\fIsolvable\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+\fIsel\fR\fB\&.matchsolvable(\fR\fIsolvable\fR\fB,\fR \fIflags\fR\fB,\fR \fIkeyname\fR\fB)\fR
+.fi
+.if n \{\
+.RE
+.\}
+.sp
+Do a matchsolvable 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
constant. Also do not forget to prepend the namespace of the constant:
$pool->set_flag($solv::Pool::POOL_FLAG_OBSOLETEUSESCOLORS, 1);
-
+
Python Specifics
----------------
TCL $pool set_flag $solv::Pool_POOL_FLAG_OBSOLETEUSESCOLORS 1
TCL puts [$solvable lookup_str $solv::SOLVABLE_SUMMARY]
-
+
The Solv Class
--------------
pool = Solv::Pool.new()
Create a new pool instance. In most cases you just need one pool.
-Note that the returned object "owns" the pool, i.e. if the object is
+Note that the returned object "owns" the pool, i.e. if the object is
freed, the pool is also freed. You can use the disown method to
break this ownership relation.
Return all solvables that provide the specified dependency. You can use either
a Dep object or a simple Id as argument.
+ Solvable *best_solvables(Solvable *solvables, int flags = 0)
+ my @solvables = $pool->best_solvables($solvables);
+ solvables = pool.best_solvables(solvables)
+ solvables = pool.best_solvables(solvables)
+
+Filter list of solvables by repo priority, architecture and version.
+
+ Solvable *whatmatchessolvable(Id keyname, Solvable solvable, Id marker = -1)
+ my @solvables = $pool->whatmatchessolvable($keyname, $solvable)
+ solvables = pool.whatmatchessolvable(keyname, solvable)
+ solvables = pool.whatmatchessolvable(keyname, solvable)
+
+Return all solvables that match package dependencies against solvable's
+provides.
+
Id *matchprovidingids(const char *match, int flags)
my @ids = $pool->matchprovidingids($match, $flags);
ids = pool.matchprovidingids(match, flags)
my $sel = $pool->Selection_all();
sel = pool.Selection_all()
sel = pool.Selection_all()
-
+
Create a selection containing all packages. Useful as starting point for
intersecting other selections or for update/distupgrade jobs.
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);
+ my $sel = $pool->matchdepid($dep, $flags, $keyname);
sel = pool.matchdepid(dep, flags, keyname)
sel = pool.matchdepid(dep, flags, keyname)
dependencies. The downside is that you cannot use globs or case insensitive
matching.
+ Selection matchsolvable(Solvable solvable, int flags, Id keyname, Id marker = -1)
+ my $sel = $pool->matchsolvable($solvable, $flags, $keyname);
+ sel = pool.matchsolvable(solvable, flags, keyname)
+ sel = pool.matchsolvable(solvable, flags, keyname)
+
+Create a selection by matching package dependencies against the specified
+solvable's provides.
+
void setpooljobs(Jobs *jobs)
$pool->setpooljobs(\@jobs);
pool.setpooljobs(jobs)
$repo->{name}
repo.name
repo.name
-
+
The repositories name. To libsolv, the name is just a string with no specific
meaning.
my @deps = $solvable->lookup_deparray($keyname);
deps = solvable.lookup_deparray(keyname)
deps = solvable.lookup_deparray(keyname)
-
+
Generic lookup methods. Retrieve data stored for the specific keyname.
The lookup_idarray() method will return an array of Ids, use
lookup_deparray if you want an array of Dependency objects instead.
*SELECTION_DOTARCH*::
Allow an ".<architecture>" suffix when matching names or
provides.
-
+
*SELECTION_REL*::
Allow the specification of a relation when matching names
or dependencies, e.g. "name >= 1.2".
Do a matchdepid operation and combine the result with the current selection.
+ void matchsolvable(Solvable solvable, int flags, Id keyname, Id marker = -1)
+ $sel->matchsolvable($solvable, $flags, $keyname);
+ sel.matchsolvable(solvable, flags, keyname)
+ sel.matchsolvable(solvable, flags, keyname)
+
+Do a matchsolvable operation and combine the result with the current selection.
+
<stringification>
my $str = $sel->str;
str = str(sel)
of the specified packages are installed, try to update the installed
packages to the specified versions. See the section about targeted
updates about more information.
-
+
*SOLVER_WEAKENDEPS*::
Allow to break the dependencies of the matching packages. Handle with care.
update A-2-1 (other: A-1-1)
erase B
-in active mode. If the mode contains SOLVER_TRANSACTION_SHOW_ALL, the
+in active mode. If the mode contains SOLVER_TRANSACTION_SHOW_ALL, the
passive mode list will be unchanged but the active mode list will just
contain A-2-1.
chksum.add_fp(file)
Add the contents of a file to the checksum.
-
+
void add_stat(const char *filename)
$chksum->add_stat($filename);
chksum.add_stat(filename)
The Repodata stores attributes for packages and the repository itself, each
repository can have multiple repodata areas. You normally only need to
directly access them if you implement lazy downloading of repository data.
-Repodata areas are created by calling the repository's add_repodata() method
+Repodata areas are created by calling the repository's add_repodata() method
or by using repo_add methods without the REPO_REUSE_REPODATA or REPO_USE_LOADING
flag.
Do not read any packages from the rpm database. This is useful
together with *-p* to only convert SUSE products.
+*-C*::
+Include the package changelog in the generated solv file.
+
*-X*::
Autoexpand SUSE pattern and product provides into packages.
Id handle;
Id subhandle;
Id *dircache;
+ int bad;
};
static int
case REPOKEY_TYPE_DIRNUMNUMARRAY:
case REPOKEY_TYPE_DIRSTRARRAY:
kv->id = repodata_translate_dir(data, fromdata, kv->id, 1, fromdata->repodataid == 1 ? cbdata->dircache : 0);
+ if (!kv->id)
+ {
+ cbdata->bad = 1; /* oops, cannot copy this */
+ return 0;
+ }
break;
case REPOKEY_TYPE_FIXARRAY:
cbdata->handle = repodata_new_handle(data);
return 0;
}
-static void
+static int
solvable_copy(Solvable *s, Solvable *r, Repodata *data, Id *dircache, Id **oldkeyskip)
{
int p, i;
/* copy all attributes */
if (!data || fromrepo->nrepodata < 2)
- return;
+ return 1;
cbdata.data = data;
cbdata.handle = s - pool->solvables;
cbdata.subhandle = 0;
cbdata.dircache = dircache;
+ cbdata.bad = 0;
p = r - fromrepo->pool->solvables;
if (fromrepo->nrepodata == 2)
{
Repodata *fromdata = repo_id2repodata(fromrepo, 1);
if (p >= fromdata->start && p < fromdata->end)
repodata_search(fromdata, p, 0, 0, solvable_copy_cb, &cbdata);
- return;
}
- keyskip = repo_create_keyskip(repo, p, oldkeyskip);
- FOR_REPODATAS(fromrepo, i, data)
+ else
+ {
+ keyskip = repo_create_keyskip(repo, p, oldkeyskip);
+ FOR_REPODATAS(fromrepo, i, data)
+ {
+ if (p >= data->start && p < data->end)
+ repodata_search_keyskip(data, p, 0, 0, keyskip, solvable_copy_cb, &cbdata);
+ }
+ }
+ if (cbdata.bad)
{
- if (p >= data->start && p < data->end)
- repodata_search_keyskip(data, p, 0, 0, keyskip, solvable_copy_cb, &cbdata);
+ repodata_unset_uninternalized(data, cbdata.handle, 0);
+ memset(s, 0, sizeof(*s));
+ s->repo = repo;
+ return 0;
}
+ return 1;
}
/* used to sort entries by package name that got returned in some database order */
if (id)
{
Solvable *r = ref->pool->solvables + ref->start + (id - 1);
- if (r->repo == ref)
- {
- solvable_copy(s, r, data, dircache, &oldkeyskip);
- continue;
- }
+ if (r->repo == ref && solvable_copy(s, r, data, dircache, &oldkeyskip))
+ continue;
}
}
res = getrpm_dbid(&state, dbid);
* <pkglist>
* <collection short="F8">
* <name>Fedora 8</name>
+ * <module name="pki-deps" stream="10.6" version="20181019123559" context="9edba152" arch="x86_64"/>
* <package arch="ppc64" name="imlib-debuginfo" release="6.fc8" src="http://download.fedoraproject.org/pub/fedora/linux/updates/8/ppc64/imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm" version="1.9.15">
* <filename>imlib-debuginfo-1.9.15-6.fc8.ppc64.rpm</filename>
* <reboot_suggested>True</reboot_suggested>
STATE_RELOGIN,
STATE_RIGHTS,
STATE_SEVERITY,
+ STATE_MODULE,
NUMSTATES
};
{ STATE_PKGLIST, "collection", STATE_COLLECTION, 0 },
{ STATE_COLLECTION, "name", STATE_NAME, 1 },
{ STATE_COLLECTION, "package", STATE_PACKAGE, 0 },
+ { STATE_COLLECTION, "module", STATE_MODULE, 0 },
{ STATE_PACKAGE, "filename", STATE_FILENAME, 1 },
{ STATE_PACKAGE, "reboot_suggested",STATE_REBOOT, 1 },
{ STATE_PACKAGE, "restart_suggested",STATE_RESTART, 1 },
repodata_set_id(pd->data, pd->collhandle, UPDATE_COLLECTION_ARCH, a);
break;
}
+ case STATE_MODULE:
+ {
+ const char *name = 0, *stream = 0, *version = 0, *context = 0, *arch = 0;
+ Id module_handle;
+
+ for (; *atts; atts += 2)
+ {
+ if (!strcmp(*atts, "arch"))
+ arch = atts[1];
+ else if (!strcmp(*atts, "name"))
+ name = atts[1];
+ else if (!strcmp(*atts, "stream"))
+ stream = atts[1];
+ else if (!strcmp(*atts, "version"))
+ version = atts[1];
+ else if (!strcmp(*atts, "context"))
+ context = atts[1];
+ }
+ module_handle = repodata_new_handle(pd->data);
+ if (name)
+ repodata_set_poolstr(pd->data, module_handle, UPDATE_MODULE_NAME, name);
+ if (stream)
+ repodata_set_poolstr(pd->data, module_handle, UPDATE_MODULE_STREAM, stream);
+ if (version)
+ repodata_set_poolstr(pd->data, module_handle, UPDATE_MODULE_VERSION, version);
+ if (context)
+ repodata_set_poolstr(pd->data, module_handle, UPDATE_MODULE_CONTEXT, context);
+ if (arch)
+ repodata_set_poolstr(pd->data, module_handle, UPDATE_MODULE_ARCH, arch);
+ repodata_add_flexarray(pd->data, pd->handle, UPDATE_MODULE, module_handle);
+ break;
+ }
default:
break;
{ DISTTYPE_DEB, "deb" },
{ DISTTYPE_ARCH, "arch" },
{ DISTTYPE_HAIKU, "haiku" },
+ { DISTTYPE_CONDA, "conda" },
{ 0, 0 }
};
{ REL_ELSE, "<ELSE>" },
{ REL_ERROR, "<ERROR>" },
{ REL_UNLESS, "<UNLESS>" },
+ { REL_CONDA, "<CONDA>" },
{ REL_LT, "<" },
{ 0, 0 }
};
-------------------------------------------------------------------
+Fri Mar 29 15:58:54 CET 2019 - mls@suse.de
+
+- repo_add_rpmdb: do not copy bad solvables from the old solv file
+- fix cleandeps updates not updating all packages
+- experimental DISTTYPE_CONDA and REL_CONDA support
+- bump version to 0.7.4
+
+-------------------------------------------------------------------
Wed Jan 30 15:51:36 CET 2019 - mls@suse.de
- fixed a couple of null pointer derefs
strpool.h dirpool.h knownid.h transaction.h rules.h problems.h
chksum.h dataiterator.h ${CMAKE_BINARY_DIR}/src/solvversion.h)
+IF (ENABLE_CONDA)
+ SET (libsolv_SRCS ${libsolv_SRCS} conda.c)
+ENDIF (ENABLE_CONDA)
+
+
SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
IF (HAVE_LINKER_VERSION_SCRIPT)
SET (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINK_FLAGS} -Wl,--version-script=${CMAKE_SOURCE_DIR}/src/libsolv.ver")
--- /dev/null
+/*
+ * Copyright (c) 2019, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * conda.c
+ *
+ * evr comparison and package matching for conda
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "conda.h"
+
+static const char *
+endseg(const char *seg, const char *end)
+{
+ for (; seg < end; seg++)
+ if (*seg == '.' || *seg == '-' || *seg == '_')
+ break;
+ return seg;
+}
+
+static const char *
+endpart(const char *seg, const char *end)
+{
+ if (seg == end)
+ return seg;
+ if (*seg >= '0' && *seg <= '9')
+ {
+ for (seg++; seg < end; seg++)
+ if (!(*seg >= '0' && *seg <= '9'))
+ break;
+ }
+ else if (*seg == '*')
+ {
+ for (seg++; seg < end; seg++)
+ if (*seg != '*')
+ break;
+ }
+ else
+ {
+ for (seg++; seg < end; seg++)
+ if ((*seg >= '0' && *seg <= '9') || *seg == '*')
+ break;
+ }
+ return seg;
+}
+
+/* C implementation of the version comparison code in conda/models/version.py */
+/* startswith == 1 : check if s1 starts with s2 */
+static int
+solv_vercmp_conda(const char *s1, const char *q1, const char *s2, const char *q2, int startswith)
+{
+ const char *s1p, *s2p;
+ const char *s1e, *s2e;
+ int r, isfirst;
+ const char *q2end = 0;
+
+ if (startswith)
+ {
+ for (q2end = q2; q2end > s2; q2end--)
+ if (q2end[-1] != '.' && q2end[-1] != '-' && q2end[-1] != '_')
+ break;
+ }
+ for (;;)
+ {
+ while (s1 < q1 && (*s1 == '.' || *s1 == '-' || *s1 == '_'))
+ s1++;
+ while (s2 < q2 && (*s2 == '.' || *s2 == '-' || *s2 == '_'))
+ s2++;
+ if (s1 == q1 && s2 == q2)
+ return 0;
+ if (startswith && s2 == q2)
+ return 0;
+ /* find end of component */
+ s1e = endseg(s1, q1);
+ s2e = endseg(s2, q2);
+
+ for (isfirst = 1; ; isfirst = 0)
+ {
+ if (s1 == s1e && s2 == s2e)
+ break;
+ if (s2 == q2end)
+ return 0;
+ s1p = endpart(s1, s1e);
+ s2p = endpart(s2, s2e);
+ /* prepend 0 if not numeric */
+ if (isfirst)
+ {
+ if (s1p != s1 && !(*s1 >= '0' && *s1 <= '9'))
+ s1p = s1;
+ if (s2p != s2 && !(*s2 >= '0' && *s2 <= '9'))
+ s2p = s2;
+ }
+ /* special case "post" */
+ if (s1p - s1 == 4 && !strncasecmp(s1, "post", 4))
+ {
+ if (s2p - s2 == 4 && !strncasecmp(s2, "post", 4))
+ {
+ s1 = s1p;
+ s2 = s2p;
+ continue;
+ }
+ return 1;
+ }
+ if (s2p - s2 == 4 && !strncasecmp(s2, "post", 4))
+ return -1;
+
+ if (isfirst || ((s1 == s1p || (*s1 >= '0' && *s1 <= '9')) && (s2 == s2p || (*s2 >= '0' && *s2 <= '9'))))
+ {
+ /* compare numbers */
+ while (s1 < s1p && *s1 == '0')
+ s1++;
+ while (s2 < s2p && *s2 == '0')
+ s2++;
+ if (s1p - s1 < s2p - s2)
+ return -1;
+ if (s1p - s1 > s2p - s2)
+ return 1;
+ r = s1p - s1 ? strncmp(s1, s2, s1p - s1) : 0;
+ if (r)
+ return r;
+ }
+ else if (s1 == s1p || (*s1 >= '0' && *s1 <= '9'))
+ return 1;
+ else if (s2 == s2p || (*s2 >= '0' && *s2 <= '9'))
+ return -1;
+ else
+ {
+ /* special case "dev" */
+ if (*s2 != '*' && s1p - s1 == 3 && !strncasecmp(s1, "dev", 3))
+ {
+ if (s2p - s2 == 3 && !strncasecmp(s2, "dev", 3))
+ {
+ s1 = s1p;
+ s2 = s2p;
+ continue;
+ }
+ return -1;
+ }
+ if (*s1 != '*' && s2p - s2 == 3 && !strncasecmp(s2, "dev", 3))
+ return 1;
+ /* compare strings */
+ r = s2p - s2 > s1p - s1 ? s1p - s1 : s2p - s2;
+ if (r)
+ r = strncasecmp(s1, s2, r);
+ if (r)
+ return r;
+ if (s1p - s1 < s2p - s2)
+ return -1;
+ if (s1p - s1 > s2p - s2)
+ return 1;
+ }
+ s1 = s1p;
+ s2 = s2p;
+ }
+ }
+}
+
+static int
+pool_evrcmp_conda_int(const char *evr1, const char *evr1e, const char *evr2, const char *evr2e, int startswith)
+{
+ static char zero[2] = {'0', 0};
+ const char *s1, *s2;
+ const char *r1, *r2;
+ int r;
+
+ /* split and compare epoch */
+ for (s1 = evr1; s1 < evr1e && *s1 >= '0' && *s1 <= '9'; s1++)
+ ;
+ for (s2 = evr2; s2 < evr2e && *s2 >= '0' && *s2 <= '9'; s2++)
+ ;
+ if (s1 == evr1 || s1 == evr1e || *s1 != '!')
+ s1 = 0;
+ if (s2 == evr1 || s2 == evr2e || *s2 != '!')
+ s2 = 0;
+ if (s1 || s2)
+ {
+ r = solv_vercmp_conda(s1 ? evr1 : zero, s1 ? s1 : zero + 1,
+ s2 ? evr2 : zero, s2 ? s2 : zero + 1, 0);
+ if (r)
+ return r;
+ if (s1)
+ evr1 = s1 + 1;
+ if (s2)
+ evr2 = s2 + 1;
+ }
+ /* split into version/localversion */
+ for (s1 = evr1, r1 = 0; s1 < evr1e; s1++)
+ if (*s1 == '+')
+ r1 = s1;
+ for (s2 = evr2, r2 = 0; s2 < evr2e; s2++)
+ if (*s2 == '+')
+ r2 = s2;
+ r = solv_vercmp_conda(evr1, r1 ? r1 : s1, evr2, r2 ? r2 : s2, r2 ? 0 : startswith);
+ if (r)
+ return r;
+ if (!r1 && !r2)
+ return 0;
+ if (!r1 && r2)
+ return -1;
+ if (r1 && !r2)
+ return 1;
+ return solv_vercmp_conda(r1 + 1, s1, r2 + 1, s2, startswith);
+}
+
+int
+pool_evrcmp_conda(const Pool *pool, const char *evr1, const char *evr2, int mode)
+{
+ if (evr1 == evr2)
+ return 0;
+ return pool_evrcmp_conda_int(evr1, evr1 + strlen(evr1), evr2, evr2 + strlen(evr2), 0);
+}
+
+static int
+regexmatch(const char *evr, const char *version, size_t versionlen)
+{
+ regex_t reg;
+ char *buf = solv_malloc(versionlen + 1);
+ int r;
+
+ memcpy(buf, version, versionlen);
+ buf[versionlen] = 0;
+ if (regcomp(®, buf, REG_EXTENDED | REG_NOSUB))
+ return 0;
+ r = regexec(®, evr, 0, NULL, 0);
+ regfree(®);
+ return r == 0;
+}
+
+static int
+globmatch(const char *evr, const char *version, size_t versionlen)
+{
+ regex_t reg;
+ char *buf = solv_malloc(2 * versionlen + 3);
+ size_t i, j;
+ int r;
+
+ buf[0] = '^';
+ j = 1;
+ for (i = 0, j = 1; i < versionlen; i++)
+ {
+ if (version[i] == '.' || version[i] == '+' || version[i] == '*')
+ buf[j++] = version[i] == '*' ? '.' : '\\';
+ buf[j++] = version[i];
+ }
+ buf[j++] = '$';
+ buf[j] = 0;
+ if (regcomp(®, buf, REG_EXTENDED | REG_NOSUB))
+ return 0;
+ r = regexec(®, evr, 0, NULL, 0);
+ regfree(®);
+ return r == 0;
+}
+
+/* return true if solvable s matches the version */
+/* see conda/models/version.py */
+static int
+solvable_conda_matchversion_single(Solvable *s, const char *version, size_t versionlen)
+{
+ const char *evr;
+ size_t i;
+ int r;
+
+ if (versionlen == 0 || (versionlen == 1 && *version == '*'))
+ return 1; /* matches every version */
+ evr = pool_id2str(s->repo->pool, s->evr);
+ if (versionlen >= 2 && version[0] == '^' && version[versionlen - 1] == '$')
+ return regexmatch(evr, version, versionlen);
+ if (version[0] == '=' || version[0] == '<' || version[0] == '>' || version[0] == '!' || version[0] == '~')
+ {
+ int flags = 0;
+ int oplen;
+ if (version[0] == '=')
+ flags = version[1] == '=' ? REL_EQ : 8;
+ else if (version[0] == '!' || version[0] == '~')
+ {
+ if (version[1] != '=')
+ return 0;
+ flags = version[0] == '!' ? REL_LT | REL_GT : 9;
+ }
+ else if (version[0] == '<' || version[0] == '>')
+ {
+ flags = version[0] == '<' ? REL_LT : REL_GT;
+ if (version[1] == '=')
+ flags |= REL_EQ;
+ }
+ else
+ return 0;
+ oplen = flags == 8 || flags == REL_LT || flags == REL_GT ? 1 : 2;
+ if (versionlen < oplen + 1)
+ return 0;
+ version += oplen;
+ versionlen -= oplen;
+ if (version[0] == '=' || version[0] == '<' || version[0] == '>' || version[0] == '!' || version[0] == '~')
+ return 0; /* bad chars after op */
+ if (versionlen >= 2 && version[versionlen - 2] == '.' && version[versionlen - 1] == '*')
+ {
+ if (flags == 8 || flags == (REL_GT | REL_EQ))
+ versionlen -= 2;
+ else if (flags == (REL_LT | REL_GT))
+ {
+ versionlen -= 2;
+ flags = 10;
+ }
+ else
+ return 0;
+ }
+ if (flags < 8)
+ {
+ /* we now have an op and a version */
+ r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 0);
+ if (r < 0)
+ return (flags & REL_LT) ? 1 : 0;
+ if (r == 0)
+ return (flags & REL_EQ) ? 1 : 0;
+ if (r > 0)
+ return (flags & REL_GT) ? 1 : 0;
+ return 0;
+ }
+ if (flags == 8 || flags == 10) /* startswith, not-startswith */
+ {
+ r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 1);
+ return flags == 8 ? r == 0 : r != 0;
+ }
+ else if (flags == 9) /* compatible release op */
+ {
+ r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 0);
+ if (r < 0)
+ return 0;
+ /* split off last component */
+ while (versionlen > 0 && version[versionlen - 1] != '.')
+ versionlen--;
+ if (versionlen < 2)
+ return 0;
+ versionlen--;
+ r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 1);
+ return r == 0 ? 1 : 0;
+ }
+ return 0;
+ }
+
+ /* do we have a '*' in the version */
+ for (i = 0; i < versionlen; i++)
+ if (version[i] == '*')
+ {
+ for (i++; i < versionlen; i++)
+ if (version[i] != '*')
+ break;
+ if (i < versionlen)
+ return globmatch(evr, version, versionlen);
+ }
+
+ if (versionlen > 1 && version[versionlen - 1] == '*')
+ {
+ /* startswith */
+ while (versionlen > 0 && version[versionlen - 1] == '*')
+ versionlen--;
+ while (versionlen > 0 && version[versionlen - 1] == '.')
+ versionlen--;
+ r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 1);
+ return r == 0 ? 1 : 0;
+ }
+ /* do we have a '@' in the version? */
+ for (i = 0; i < versionlen; i++)
+ if (version[i] == '@')
+ return strncmp(evr, version, versionlen) == 0 && evr[versionlen] == 0;
+ r = pool_evrcmp_conda_int(evr, evr + strlen(evr), version, version + versionlen, 0);
+ return r == 0 ? 1 : 0;
+}
+
+static int
+solvable_conda_matchversion_rec(Solvable *s, const char **versionp, const char *versionend)
+{
+ const char *version = *versionp;
+ int v, vor = 0, vand = -1; /* -1: doing OR, 0,1: doing AND */
+
+ if (version == versionend)
+ return -1;
+ for (;;)
+ {
+ if (*version == '(')
+ {
+ version++;
+ v = solvable_conda_matchversion_rec(s, &version, versionend);
+ if (v == -1 || version == versionend || *version != ')')
+ return -1;
+ version++;
+ }
+ else if (*version == ')' || *version == '|' || *version == ',')
+ return -1;
+ else
+ {
+ const char *vstart = version;
+ while (version < versionend && *version != '(' && *version != ')' && *version != '|' && *version != ',')
+ version++;
+ if (vand >= 0 ? !vand : vor)
+ v = 0; /* no need to call expensive matchversion if the result does not matter */
+ else
+ v = solvable_conda_matchversion_single(s, vstart, version - vstart) ? 1 : 0;
+ }
+ if (version == versionend || *version == ')')
+ {
+ *versionp = version;
+ return vor | (vand >= 0 ? (vand & v) : v);
+ }
+ if (*version == ',')
+ vand = vand >= 0 ? (vand & v) : v;
+ else if (*version == '|')
+ {
+ vor |= vand >= 0 ? (vand & v) : v;
+ vand = -1;
+ }
+ else
+ return -1;
+ version++;
+ }
+}
+
+/* return true if solvable s matches the version */
+/* see conda/models/match_spec.py */
+int
+solvable_conda_matchversion(Solvable *s, const char *version)
+{
+ const char *build, *versionend;
+ int r;
+ /* split off build */
+ if ((build = strchr(version, ' ')) != 0)
+ {
+ versionend = build++;
+ while (*build == ' ')
+ build++;
+ }
+ else
+ versionend = version + strlen(version);
+ r = solvable_conda_matchversion_rec(s, &version, versionend);
+ if (r != 1 || version != versionend)
+ return 0;
+ return r;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2019, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * conda.h
+ *
+ */
+
+#ifndef LIBSOLV_CONDA_H
+#define LIBSOLV_CONDA_H
+
+int pool_evrcmp_conda(const Pool *pool, const char *evr1, const char *evr2, int mode);
+int solvable_conda_matchversion(Solvable *s, const char *version);
+
+#endif /* LIBSOLV_CONDA_H */
+
#include "evr.h"
#include "pool.h"
+#ifdef ENABLE_CONDA
+#include "conda.h"
+#endif
#if defined(DEBIAN) || defined(MULTI_SEMANTICS)
#if defined(MULTI_SEMANTICS)
# define solv_vercmp (*(pool->disttype == DISTTYPE_DEB ? &solv_vercmp_deb : \
- pool->disttype == DISTTYPE_HAIKU ? solv_vercmp_haiku : \
+ pool->disttype == DISTTYPE_HAIKU ? &solv_vercmp_haiku : \
&solv_ver##cmp_rpm))
#elif defined(DEBIAN)
# define solv_vercmp solv_vercmp_deb
if (evr1 == evr2)
return 0;
+#ifdef ENABLE_CONDA
+ if (pool->disttype == DISTTYPE_CONDA)
+ return pool_evrcmp_conda(pool, evr1, evr2, mode);
+#endif
+
#if 0
POOL_DEBUG(DEBUG_EVRCMP, "evrcmp %s %s mode=%d\n", evr1, evr2, mode);
#endif
KNOWNID(SIGNATURE_EXPIRES, "signature:expires"),
KNOWNID(SIGNATURE_DATA, "signature:data"),
+/* 'content' of patch, usually list of modules */
+KNOWNID(UPDATE_MODULE, "update:module"), /* "name stream version context arch" */
+KNOWNID(UPDATE_MODULE_NAME, "update:module:name"), /* name */
+KNOWNID(UPDATE_MODULE_STREAM, "update:module:stream"), /* stream */
+KNOWNID(UPDATE_MODULE_VERSION, "update:module:version"), /* version */
+KNOWNID(UPDATE_MODULE_CONTEXT, "update:module:context"), /* context */
+KNOWNID(UPDATE_MODULE_ARCH, "update:module:arch"), /* architecture */
+
KNOWNID(ID_NUM_INTERNAL, 0)
#ifdef KNOWNID_INITIALIZE
{
s = pool->solvables + plist->elements[i];
- POOL_DEBUG(SOLV_DEBUG_POLICY, "- %s[%s]\n",
- pool_solvable2str(pool, s),
- (pool->installed && s->repo == pool->installed) ? "installed" : "not installed");
+ POOL_DEBUG(SOLV_DEBUG_POLICY, "- %s [%d]%s\n",
+ pool_solvable2str(pool, s), plist->elements[i],
+ (pool->installed && s->repo == pool->installed) ? "I" : "");
if (!best) /* if no best yet, the current is best */
{
#include "util.h"
#include "bitmap.h"
#include "evr.h"
+#ifdef ENABLE_CONDA
+#include "conda.h"
+#endif
#define SOLVABLE_BLOCK 255
case DISTTYPE_HAIKU:
pool->noarchid = ARCH_ANY;
break;
+ case DISTTYPE_CONDA:
+ pool->noarchid = ARCH_ANY;
+ break;
default:
return -1;
}
queue_push(&plist, p);
}
break;
+#ifdef ENABLE_CONDA
+ case REL_CONDA:
+ wp = pool_whatprovides(pool, name);
+ if (evr)
+ {
+ const char *evrstr = pool_id2str(pool, evr);
+ pp = pool->whatprovidesdata + wp;
+ while ((p = *pp++) != 0)
+ {
+ if (solvable_conda_matchversion(pool->solvables + p, evrstr))
+ queue_push(&plist, p);
+ else
+ wp = 0;
+ }
+ }
+ break;
+#endif
default:
break;
}
if (level > 2)
mask |= SOLV_DEBUG_PROPAGATE;
if (level > 3)
- mask |= SOLV_DEBUG_RULE_CREATION;
+ mask |= SOLV_DEBUG_RULE_CREATION | SOLV_DEBUG_WATCHES;
mask |= pool->debugmask & SOLV_DEBUG_TO_STDERR; /* keep bit */
pool->debugmask = mask;
}
#define DISTTYPE_DEB 1
#define DISTTYPE_ARCH 2
#define DISTTYPE_HAIKU 3
+#define DISTTYPE_CONDA 4
#define SOLV_FATAL (1<<0)
#define SOLV_ERROR (1<<1)
#define SOLV_DEBUG_JOB (1<<11)
#define SOLV_DEBUG_SOLVER (1<<12)
#define SOLV_DEBUG_TRANSACTION (1<<13)
+#define SOLV_DEBUG_WATCHES (1<<14)
#define SOLV_DEBUG_TO_STDERR (1<<30)
#define REL_ERROR 27 /* parse errors and the like */
#define REL_WITHOUT 28
#define REL_UNLESS 29 /* AND_NOT */
+#define REL_CONDA 30
#if !defined(__GNUC__) && !defined(__attribute__)
# define __attribute__(x)
if (!ISRELDEP(id))
return "";
rd = GETRELDEP(pool, id);
+
switch (rd->flags)
{
/* debian special cases < and > */
return " KIND ";
case REL_ELSE:
return pool->disttype == DISTTYPE_RPM ? " else " : " ELSE ";
+ case REL_CONDA:
+ return " ";
case REL_ERROR:
return " ERROR ";
default:
ap = *app;
if (!ap)
return;
+ if (!keyname)
+ {
+ *app = 0; /* delete all attributes */
+ return;
+ }
for (; *ap; ap += 2)
if (data->keys[*ap].name == keyname)
break;
#include <string.h> /* memcpy()/memset() or bcopy()/bzero() */
/* #include <assert.h> */ /* assert() */
#include <stdio.h>
-#include <sys/uio.h>
+/* #include <sys/uio.h> */
#include <unistd.h>
#include <inttypes.h>
Id *decisionmap = solv->decisionmap;
Id *watches = solv->watches + pool->nsolvables; /* place ptr in middle */
- POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n");
+ POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate level %d -----\n", level);
/* foreach non-propagated decision */
while (solv->propagate_index < solv->decisionq.count)
IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
{
- POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
+ POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate decision %d:", -pkg);
solver_printruleelement(solv, SOLV_DEBUG_PROPAGATE, 0, -pkg);
}
continue;
}
- IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+ IF_POOLDEBUG (SOLV_DEBUG_WATCHES)
{
- POOL_DEBUG(SOLV_DEBUG_PROPAGATE," watch triggered ");
- solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
+ POOL_DEBUG(SOLV_DEBUG_WATCHES, " watch triggered ");
+ solver_printrule(solv, SOLV_DEBUG_WATCHES, r);
}
/*
* if we found some p that is UNDEF or TRUE, move
* watch to it
*/
- IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
+ IF_POOLDEBUG (SOLV_DEBUG_WATCHES)
{
if (p > 0)
- POOL_DEBUG(SOLV_DEBUG_PROPAGATE, " -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
+ POOL_DEBUG(SOLV_DEBUG_WATCHES, " -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
else
- POOL_DEBUG(SOLV_DEBUG_PROPAGATE, " -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
+ POOL_DEBUG(SOLV_DEBUG_WATCHES, " -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
}
*rp = *next_rp;
} /* while we have non-decided decisions */
- POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end-----\n");
+ POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end -----\n");
return 0; /* all is well */
}
return level;
}
+/* one or more installed cleandeps packages in dq that are to be updated */
+/* we need to emulate the code in resolve_installed */
+static void
+do_cleandeps_update_filter(Solver *solv, Queue *dq)
+{
+ Pool *pool = solv->pool;
+ Repo *installed = solv->installed;
+ Id *specialupdaters = solv->specialupdaters;
+ Id p, p2, pp, d;
+ Queue q;
+ int i, j, k;
+
+ queue_init(&q);
+ for (i = 0; i < dq->count; i++)
+ {
+ Id p = dq->elements[i];
+ if (p < 0)
+ p = -p;
+ if (pool->solvables[p].repo != installed || !MAPTST(&solv->cleandepsmap, p - installed->start))
+ continue;
+ queue_empty(&q);
+ /* find updaters */
+ if (specialupdaters && (d = specialupdaters[p - installed->start]) != 0)
+ {
+ while ((p2 = pool->whatprovidesdata[d++]) != 0)
+ if (solv->decisionmap[p2] >= 0)
+ queue_push(&q, p2);
+ }
+ else
+ {
+ Rule *r = solv->rules + solv->updaterules + (p - installed->start);
+ if (r->p)
+ {
+ FOR_RULELITERALS(p2, pp, r)
+ if (solv->decisionmap[p2] >= 0)
+ queue_push(&q, p2);
+ }
+ }
+ if (q.count && solv->update_targets && solv->update_targets->elements[p - installed->start])
+ prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q);
+ /* mark all elements in dq that are in the updaters list */
+ dq->elements[i] = -p;
+ for (j = 0; j < dq->count; j++)
+ {
+ p = dq->elements[j];
+ if (p < 0)
+ continue;
+ for (k = 0; k < q.count; k++)
+ if (q.elements[k] == p)
+ {
+ dq->elements[j] = -p;
+ break;
+ }
+ }
+ }
+ /* now prune to marked elements */
+ for (i = j = 0; i < dq->count; i++)
+ if ((p = dq->elements[i]) < 0)
+ dq->elements[j++] = -p;
+ dq->count = j;
+ queue_free(&q);
+}
+
static int
resolve_dependencies(Solver *solv, int level, int disablerules, Queue *dq)
{
/* prune to cleandeps packages */
if (solv->cleandepsmap.size && solv->installed)
{
+ int cleandeps_update = 0;
Repo *installed = solv->installed;
for (j = 0; j < dq->count; j++)
if (pool->solvables[dq->elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq->elements[j] - installed->start))
- break;
+ {
+ if (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, dq->elements[j] - installed->start)))
+ {
+ cleandeps_update = 1; /* cleandeps package is marked for update */
+ continue;
+ }
+ break;
+ }
if (j < dq->count)
{
dq->elements[0] = dq->elements[j];
queue_truncate(dq, 1);
}
+ else if (cleandeps_update)
+ do_cleandeps_update_filter(solv, dq); /* special update filter */
}
if (dq->count > 1 && postponed >= 0)
else
solv->yumobsrules = solv->yumobsrules_end = solv->nrules;
- if (solv->havedisfavored && solv->strongrecommends)
+ if (solv->havedisfavored && solv->strongrecommends && solv->recommendsruleq)
solver_addrecommendsrules(solv);
else
solv->recommendsrules = solv->recommendsrules_end = solv->nrules;
#cmakedefine LIBSOLV_FEATURE_LINKED_PKGS
#cmakedefine LIBSOLV_FEATURE_COMPLEX_DEPS
#cmakedefine LIBSOLV_FEATURE_MULTI_SEMANTICS
+#cmakedefine LIBSOLV_FEATURE_CONDA
#cmakedefine LIBSOLVEXT_FEATURE_RPMPKG
#cmakedefine LIBSOLVEXT_FEATURE_RPMDB
--- /dev/null
+repo system 0 testtags <inline>
+#>=Pkg: a 1 1 x86_64
+#>=Req: b
+#>=Pkg: b 1 1 x86_64
+repo available 0 testtags <inline>
+#>=Pkg: a 2 1 x86_64
+#>=Req: b
+#>=Pkg: b 2 1 x86_64
+#>=Pkg: c 2 1 x86_64
+#>=Prv: b = 4
+repo available2 0 testtags <inline>
+#>=Pkg: b 3 1 x86_64
+system x86_64 rpm system
+
+job update all packages [cleandeps]
+result transaction,problems <inline>
+#>upgrade a-1-1.x86_64@system a-2-1.x86_64@available
+#>upgrade b-1-1.x86_64@system b-3-1.x86_64@available2
+nextjob
+job update repo available [cleandeps]
+result transaction,problems <inline>
+#>upgrade a-1-1.x86_64@system a-2-1.x86_64@available
+#>upgrade b-1-1.x86_64@system b-2-1.x86_64@available
usage(int status)
{
fprintf(stderr, "\nUsage:\n"
- "rpmdb2solv [-n] [-b <basefile>] [-p <productsdir>] [-r <root>]\n"
+ "rpmdb2solv [-P] [-C] [-n] [-b <basefile>] [-p <productsdir>] [-r <root>]\n"
" -n : No packages, do not read rpmdb, useful to only parse products\n"
" -p <productsdir> : Scan <productsdir> for .prod files, representing installed products\n"
" -r <root> : Prefix rpmdb path and <productsdir> with <root>\n"
" -o <solv> : Write .solv to file instead of stdout\n"
+ " -P : print percentage done\n"
+ " -C : include the changelog\n"
);
exit(status);
}