dnf5: Support --installed-from-repo= for repoquery/list/info

Adds the `--installed-from-repo=` option to `dnf5 repoquery` `dnf5 list`
and `dnf5 info` commands. This new filter allows users to narrow down
the displayed installed packages to only those that originated from
a specified repositories ID.
This commit is contained in:
Jaroslav Rohel 2025-06-16 12:13:31 +02:00
parent 3dc4352a98
commit 38c183c229
10 changed files with 70 additions and 3 deletions

View File

@ -58,4 +58,32 @@ void create_from_repo_option(Command & command, std::vector<std::string> & from_
command.get_argument_parser_command()->register_named_arg(from_repo_opt);
}
libdnf5::cli::ArgumentParser::NamedArg * create_installed_from_repo_option(
Command & command, std::vector<std::string> & from_repos, bool detect_conflict) {
auto & parser = command.get_context().get_argument_parser();
auto * from_repo_opt = parser.add_new_named_arg("installed-from-repo");
from_repo_opt->set_long_name("installed-from-repo");
from_repo_opt->set_description(
_("Filters installed packages by the ID of the repository they were installed from."));
from_repo_opt->set_has_value(true);
from_repo_opt->set_arg_value_help(_("REPO_ID,..."));
from_repo_opt->set_parse_hook_func(
[&from_repos, detect_conflict](
libdnf5::cli::ArgumentParser::NamedArg *, [[maybe_unused]] const char * option, const char * value) {
if (!detect_conflict || from_repos.empty()) {
from_repos = libdnf5::OptionStringList(value).get_value();
} else {
if (from_repos != libdnf5::OptionStringList(value).get_value()) {
throw libdnf5::cli::ArgumentParserConflictingArgumentsError(
M_("\"--installed-from_repo\" already defined with diferent value"));
}
}
return true;
});
command.get_argument_parser_command()->register_named_arg(from_repo_opt);
return from_repo_opt;
}
} // namespace dnf5

View File

@ -35,6 +35,13 @@ namespace dnf5 {
// if "--from-repo" was already defined with a different value.
void create_from_repo_option(Command & command, std::vector<std::string> & from_repos, bool detect_conflict);
// Creates a new named argument "--installed-from-repo=REPO_ID,...".
// When the argument is used, the list of REPO_IDs is split and the items are stored in the `from_repos` vector.
// If `detect_conflict` is true, a `libdnf5::cli::ArgumentParserConflictingArgumentsError` exception is thrown
// if "--from-repo" was already defined with a different value.
libdnf5::cli::ArgumentParser::NamedArg * create_installed_from_repo_option(
Command & command, std::vector<std::string> & from_repos, bool detect_conflict);
} // namespace dnf5
#endif // DNF5_COMMANDS_FROM_REPO_HPP

View File

@ -19,6 +19,8 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include "list.hpp"
#include "../from_repo.hpp"
#include <dnf5/shared_options.hpp>
#include <libdnf5-cli/output/package_list_sections.hpp>
#include <libdnf5/rpm/package_query.hpp>
@ -59,6 +61,8 @@ void ListCommand::set_argument_parser() {
show_duplicates = std::make_unique<libdnf5::cli::session::BoolOption>(
*this, "showduplicates", '\0', _("Show all versions of the packages, not only the latest ones."), false);
create_installed_from_repo_option(*this, installed_from_repos, true);
auto conflicts =
parser.add_conflict_args_group(std::make_unique<std::vector<libdnf5::cli::ArgumentParser::Argument *>>());
@ -168,7 +172,11 @@ void ListCommand::run() {
auto sections = create_output();
libdnf5::rpm::PackageQuery installed(base_query);
installed.filter_installed();
if (installed_from_repos.empty()) {
installed.filter_installed();
} else {
installed.filter_from_repo_id(installed_from_repos, libdnf5::sack::QueryCmp::GLOB);
}
// TODO(mblaha) currently only the installed version and upgrades
// are highlighted to make the output a bit saner

View File

@ -63,6 +63,8 @@ private:
// show all NEVRAs, not only the latest one
std::unique_ptr<libdnf5::cli::session::BoolOption> show_duplicates{nullptr};
std::vector<std::string> installed_from_repos;
};

View File

@ -19,6 +19,8 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include "repoquery.hpp"
#include "../from_repo.hpp"
#include "libdnf5-cli/output/adapters/package_tmpl.hpp"
#include <dnf5/shared_options.hpp>
@ -133,6 +135,11 @@ void RepoqueryCommand::set_argument_parser() {
installed->link_value(installed_option);
cmd.register_named_arg(installed);
{
auto * option = create_installed_from_repo_option(*this, installed_from_repos, true);
only_outputs_installed->push_back(option);
}
// FILTERS ONLY FOR INSTALLED PACKAGES:
leaves_option = dynamic_cast<libdnf5::OptionBool *>(
@ -460,8 +467,9 @@ void RepoqueryCommand::configure() {
auto & context = get_context();
context.update_repo_metadata_from_specs(pkg_specs);
system_repo_needed = installed_option->get_value() || userinstalled_option->get_value() ||
duplicates->get_value() || leaves_option->get_value() || unneeded->get_value() ||
extras->get_value() || upgrades->get_value() || installonly->get_value();
!installed_from_repos.empty() || duplicates->get_value() || leaves_option->get_value() ||
unneeded->get_value() || extras->get_value() || upgrades->get_value() ||
installonly->get_value();
context.set_load_system_repo(system_repo_needed);
context.update_repo_metadata_from_advisory_options(
advisory_name->get_value(),
@ -600,6 +608,10 @@ void RepoqueryCommand::run() {
result_query.filter_duplicates();
}
if (!installed_from_repos.empty()) {
result_query.filter_from_repo_id(installed_from_repos, libdnf5::sack::QueryCmp::GLOB);
}
if (unneeded->get_value()) {
result_query.filter_unneeded();
}

View File

@ -91,6 +91,8 @@ private:
std::unique_ptr<AdvisorySeverityOption> advisory_severity{nullptr};
std::unique_ptr<BzOption> advisory_bz{nullptr};
std::unique_ptr<CveOption> advisory_cve{nullptr};
std::vector<std::string> installed_from_repos;
};

View File

@ -0,0 +1,2 @@
``--installed-from-repo=REPO_ID,...``
| Filters installed packages by the ID of the repository they were installed from.

View File

@ -40,6 +40,8 @@ Options
``--showduplicates``
| Show all versions of the packages, not only the latest one.
.. include:: ../_shared/options/installed-from-repo.rst
``--installed``
| List only installed packages.

View File

@ -40,6 +40,8 @@ Options
``--showduplicates``
| Show all versions of the packages, not only the latest one.
.. include:: ../_shared/options/installed-from-repo.rst
``--installed``
| List only installed packages.

View File

@ -82,6 +82,8 @@ Options
| Query installed packages.
| Can be combined with ``--available`` to query both installed and available packages.
.. include:: ../_shared/options/installed-from-repo.rst
``--installonly``
| Limit to installed installonly packages.