diff --git a/libdnf/hy-query.cpp b/libdnf/hy-query.cpp index d213b3dd08..deb5798f40 100644 --- a/libdnf/hy-query.cpp +++ b/libdnf/hy-query.cpp @@ -304,9 +304,9 @@ hy_add_filter_nevra_object(HyQuery query, HyNevra nevra, bool icase) } void -hy_add_filter_extras(HyQuery query) +hy_add_filter_extras(HyQuery query, bool with_evr) { - query->filterExtras(); + query->filterExtras(with_evr); } void diff --git a/libdnf/hy-query.h b/libdnf/hy-query.h index b8cfc14ec5..c24a1d90f1 100644 --- a/libdnf/hy-query.h +++ b/libdnf/hy-query.h @@ -103,7 +103,7 @@ bool hy_query_is_applied(const HyQuery query); const Map *hy_query_get_result(const HyQuery query); DnfSack *hy_query_get_sack(HyQuery query); void hy_add_filter_nevra_object(HyQuery query, HyNevra nevra, bool icase); -void hy_add_filter_extras(HyQuery query); +void hy_add_filter_extras(HyQuery query, bool with_evr); void hy_filter_recent(HyQuery query, const long unsigned int recent_limit); void hy_filter_duplicated(HyQuery query); GPtrArray * hy_query_get_advisory_pkgs(HyQuery query, int cmp_type); diff --git a/libdnf/sack/query.cpp b/libdnf/sack/query.cpp index e4682927a0..08ba0a5699 100644 --- a/libdnf/sack/query.cpp +++ b/libdnf/sack/query.cpp @@ -2471,7 +2471,7 @@ Query::empty() } void -Query::filterExtras() +Query::filterExtras(bool with_evr) { apply(); @@ -2485,31 +2485,46 @@ Query::filterExtras() return; } - // create query with available packages without non-modular excludes. As a extras should be - // considered anso packages in non-active modules + // create query with available packages without non-modular excludes, since extras should also + // consider packages in non-active modules Query query_available(pImpl->sack, Query::ExcludeFlags::IGNORE_REGULAR_EXCLUDES); query_available.available(); auto resultAvailable = query_available.pImpl->result.get(); Id id_available = -1; + NameArchEVRComparator nevra_cmp(pool); + // make vector of available solvables - std::vector namesArch; - namesArch.reserve(resultAvailable->size()); + std::vector availSolvables; + availSolvables.reserve(resultAvailable->size()); while ((id_available = resultAvailable->next(id_available)) != -1) { - namesArch.push_back(pool_id2solvable(pool, id_available)); + availSolvables.push_back(pool_id2solvable(pool, id_available)); + } + if (with_evr) { + std::sort(availSolvables.begin(), availSolvables.end(), nevra_cmp); + } else { + std::sort(availSolvables.begin(), availSolvables.end(), NameArchSolvableComparator); } - std::sort(namesArch.begin(), namesArch.end(), NameArchSolvableComparator); Id id_installed = -1; auto resultInstalled = query_installed.pImpl->result.get(); while ((id_installed = resultInstalled->next(id_installed)) != -1) { Solvable * s_installed = pool_id2solvable(pool, id_installed); - auto low = std::lower_bound(namesArch.begin(), namesArch.end(), s_installed, - NameArchSolvableComparator); - if (low == namesArch.end() || (*low)->name != s_installed->name || - (*low)->arch != s_installed->arch) { - MAPSET(resultMap, id_installed); + if (with_evr) { + auto low = std::lower_bound(availSolvables.begin(), availSolvables.end(), s_installed, + nevra_cmp); + if (low == availSolvables.end() || (*low)->name != s_installed->name || + (*low)->arch != s_installed->arch) { + MAPSET(resultMap, id_installed); + } + } else { + auto low = std::lower_bound(availSolvables.begin(), availSolvables.end(), s_installed, + NameArchSolvableComparator); + if (low == availSolvables.end() || (*low)->name != s_installed->name || + (*low)->arch != s_installed->arch) { + MAPSET(resultMap, id_installed); + } } } } diff --git a/libdnf/sack/query.hpp b/libdnf/sack/query.hpp index 306b24e30a..53c87fb007 100644 --- a/libdnf/sack/query.hpp +++ b/libdnf/sack/query.hpp @@ -169,11 +169,11 @@ struct Query { bool empty(); /** * @brief Applies all filters and keep only installed packages that have no available package - * with a same name and architecture. + * with a same name and architecture or NEVRA. * Excluded available packages are handled like other available packages. Modular excludes are * applied. */ - void filterExtras(); + void filterExtras(bool with_evr); void filterRecent(const long unsigned int recent_limit); void filterDuplicated(); int filterUnneeded(const Swdb &swdb, bool debug_solver); diff --git a/python/hawkey/query-py.cpp b/python/hawkey/query-py.cpp index a25a0d6bd2..805da53baa 100644 --- a/python/hawkey/query-py.cpp +++ b/python/hawkey/query-py.cpp @@ -603,10 +603,16 @@ duplicated_filter(_QueryObject *self, PyObject *unused) try } CATCH_TO_PYTHON static PyObject * -add_filter_extras(_QueryObject *self, PyObject *unused) try +add_filter_extras(_QueryObject *self, PyObject *args, PyObject *kwds) try { + PyObject *with_evr = NULL; + const char *kwlist[] = {"with_evr", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char**) kwlist, &PyBool_Type, &with_evr)) + return NULL; + gboolean c_with_evr = with_evr != NULL && PyObject_IsTrue(with_evr); + HyQuery self_query_copy = new libdnf::Query(*self->query); - self_query_copy->filterExtras(); + self_query_copy->filterExtras(c_with_evr); PyObject *final_query = queryToPyObject(self_query_copy, self->sack, Py_TYPE(self)); return final_query; } CATCH_TO_PYTHON @@ -1065,7 +1071,7 @@ static struct PyMethodDef query_methods[] = { {"available", (PyCFunction)add_available_filter, METH_NOARGS, NULL}, {"downgrades", (PyCFunction)add_downgrades_filter, METH_NOARGS, NULL}, {"duplicated", (PyCFunction)duplicated_filter, METH_NOARGS, NULL}, - {"extras", (PyCFunction)add_filter_extras, METH_NOARGS, NULL}, + {"extras", (PyCFunction)add_filter_extras, METH_KEYWORDS|METH_VARARGS, NULL}, {"installed", (PyCFunction)add_installed_filter, METH_NOARGS, NULL}, {"latest", (PyCFunction)add_filter_latest, METH_VARARGS, NULL}, {"union", (PyCFunction)q_union, METH_VARARGS, NULL},