From fce16cc256ce120c9869437da819d9ad64a2ade4 Mon Sep 17 00:00:00 2001 From: Stewart Smith Date: Thu, 19 Dec 2024 16:35:02 -0800 Subject: [PATCH] Add --json output to advisory info Enable --json for 'dnf advisory info'. The same information as would be displayed as text is included in the JSON output. While the libscols code could be adapted to produce JSON as well, without serious reworking of key_value_table (and all callers), the produced JSON is quite weird, so we instead choose to implement the JSON output separately. --- dnf5/commands/advisory/advisory_info.cpp | 18 ++++- dnf5/commands/advisory/advisory_info.hpp | 3 + include/libdnf5-cli/output/advisoryinfo.hpp | 13 +++ libdnf5-cli/output/advisoryinfo.cpp | 90 +++++++++++++++++++++ 4 files changed, 120 insertions(+), 4 deletions(-) diff --git a/dnf5/commands/advisory/advisory_info.cpp b/dnf5/commands/advisory/advisory_info.cpp index 2c876627e..5e26c80b1 100644 --- a/dnf5/commands/advisory/advisory_info.cpp +++ b/dnf5/commands/advisory/advisory_info.cpp @@ -61,12 +61,22 @@ void AdvisoryInfoCommand::process_and_print_queries( advisories.filter_packages(installed_packages, libdnf5::sack::QueryCmp::GT); } - for (auto advisory : advisories) { - libdnf5::cli::output::AdvisoryInfo advisory_info; - output::AdvisoryAdapter cli_advisory(advisory); - advisory_info.add_advisory(cli_advisory); + if (ctx.get_json_output_requested()) { + libdnf5::cli::output::AdvisoryInfoJSON advisory_info; + for (auto advisory : advisories) { + output::AdvisoryAdapter cli_advisory(advisory); + advisory_info.add_advisory(cli_advisory); + } advisory_info.print(); std::cout << std::endl; + } else { + for (auto advisory : advisories) { + libdnf5::cli::output::AdvisoryInfo advisory_info; + output::AdvisoryAdapter cli_advisory(advisory); + advisory_info.add_advisory(cli_advisory); + advisory_info.print(); + std::cout << std::endl; + } } } diff --git a/dnf5/commands/advisory/advisory_info.hpp b/dnf5/commands/advisory/advisory_info.hpp index a4e9e9f5e..2a833b973 100644 --- a/dnf5/commands/advisory/advisory_info.hpp +++ b/dnf5/commands/advisory/advisory_info.hpp @@ -22,6 +22,8 @@ along with libdnf. If not, see . #include "advisory_subcommand.hpp" +#include + namespace dnf5 { class AdvisoryInfoCommand : public AdvisorySubCommand { @@ -31,6 +33,7 @@ class AdvisoryInfoCommand : public AdvisorySubCommand { void set_argument_parser() override { AdvisorySubCommand::set_argument_parser(); get_argument_parser_command()->set_description(_("Print details about advisories")); + create_json_option(*this); } protected: diff --git a/include/libdnf5-cli/output/advisoryinfo.hpp b/include/libdnf5-cli/output/advisoryinfo.hpp index 4f24e9785..cffada110 100644 --- a/include/libdnf5-cli/output/advisoryinfo.hpp +++ b/include/libdnf5-cli/output/advisoryinfo.hpp @@ -40,6 +40,19 @@ class LIBDNF_CLI_API AdvisoryInfo { std::unique_ptr p_impl; }; +class LIBDNF_CLI_API AdvisoryInfoJSON { +public: + AdvisoryInfoJSON(); + ~AdvisoryInfoJSON(); + + void add_advisory(IAdvisory & advisory); + void print(); + +private: + class LIBDNF_CLI_LOCAL Impl; + std::unique_ptr p_impl; +}; + } // namespace libdnf5::cli::output #endif // LIBDNF5_CLI_OUTPUT_ADVISORYLIST_HPP diff --git a/libdnf5-cli/output/advisoryinfo.cpp b/libdnf5-cli/output/advisoryinfo.cpp index b80ddf5c7..94dfe7f9f 100644 --- a/libdnf5-cli/output/advisoryinfo.cpp +++ b/libdnf5-cli/output/advisoryinfo.cpp @@ -22,6 +22,12 @@ along with libdnf. If not, see . #include "key_value_table.hpp" #include "utils/string.hpp" + +#include + + +#include + namespace libdnf5::cli::output { class AdvisoryInfo::Impl : public KeyValueTable { @@ -29,6 +35,17 @@ class AdvisoryInfo::Impl : public KeyValueTable { void add_advisory(IAdvisory & advisory); }; +class AdvisoryInfoJSON::Impl { +public: + Impl() { json_advisories = json_object_new_object(); }; + ~Impl() { json_object_put(json_advisories); }; + void add_advisory(IAdvisory & advisory); + void print() { + std::cout << json_object_to_json_string_ext(json_advisories, JSON_C_TO_STRING_PRETTY) << std::endl; + }; + json_object * json_advisories; +}; + void AdvisoryInfo::Impl::add_advisory(IAdvisory & advisory) { add_line("Name", advisory.get_name(), "bold"); @@ -81,17 +98,90 @@ void AdvisoryInfo::Impl::add_advisory(IAdvisory & advisory) { } } +void AdvisoryInfoJSON::Impl::add_advisory(IAdvisory & advisory) { + json_object * json_advisory = json_object_new_object(); + json_object_object_add(json_advisory, "Name", json_object_new_string(advisory.get_name().c_str())); + json_object_object_add(json_advisory, "Title", json_object_new_string(advisory.get_title().c_str())); + json_object_object_add(json_advisory, "Severity", json_object_new_string(advisory.get_severity().c_str())); + json_object_object_add(json_advisory, "Type", json_object_new_string(advisory.get_type().c_str())); + json_object_object_add(json_advisory, "Status", json_object_new_string(advisory.get_status().c_str())); + json_object_object_add(json_advisory, "Vendor", json_object_new_string(advisory.get_vendor().c_str())); + json_object_object_add( + json_advisory, + "Issued", + json_object_new_string(libdnf5::utils::string::format_epoch(advisory.get_buildtime()).c_str())); + json_object_object_add(json_advisory, "Description", json_object_new_string(advisory.get_description().c_str())); + json_object_object_add(json_advisory, "Message", json_object_new_string(advisory.get_message().c_str())); + json_object_object_add(json_advisory, "Rights", json_object_new_string(advisory.get_rights().c_str())); + + // References + json_object * json_references = json_object_new_array(); + for (auto & reference : advisory.get_references()) { + json_object * json_reference = json_object_new_object(); + json_object_object_add(json_reference, "Title", json_object_new_string(reference->get_title().c_str())); + json_object_object_add(json_reference, "Id", json_object_new_string(reference->get_id().c_str())); + json_object_object_add(json_reference, "Type", json_object_new_string(reference->get_type_cstring())); + json_object_object_add(json_reference, "Url", json_object_new_string(reference->get_url().c_str())); + json_object_array_add(json_references, json_reference); + } + json_object_object_add(json_advisory, "references", json_references); + + // Collections + json_object * json_collections = json_object_new_object(); + for (auto & collection : advisory.get_collections()) { + // Modules + auto modules = collection->get_modules(); + if (!modules.empty()) { + json_object * json_modules = json_object_new_array(); + auto module_iter = modules.begin(); + json_object_array_add(json_modules, json_object_new_string((*module_iter)->get_nsvca().c_str())); + module_iter++; + while (module_iter != modules.end()) { + json_object_array_add(json_modules, json_object_new_string((*module_iter)->get_nsvca().c_str())); + module_iter++; + } + json_object_object_add(json_collections, "modules", json_modules); + } + + // Packages + auto packages = collection->get_packages(); + if (!packages.empty()) { + json_object * json_pkgs = json_object_new_array(); + auto package_iter = packages.begin(); + json_object_array_add(json_pkgs, json_object_new_string((*package_iter)->get_nevra().c_str())); + package_iter++; + while (package_iter != packages.end()) { + json_object_array_add(json_pkgs, json_object_new_string((*package_iter)->get_nevra().c_str())); + package_iter++; + } + json_object_object_add(json_collections, "packages", json_pkgs); + } + json_object_object_add(json_advisory, "collections", json_collections); + } + json_object_object_add(json_advisories, advisory.get_name().c_str(), json_advisory); +} + AdvisoryInfo::AdvisoryInfo() : p_impl{new AdvisoryInfo::Impl} {} +AdvisoryInfoJSON::AdvisoryInfoJSON() : p_impl{new AdvisoryInfoJSON::Impl} {} AdvisoryInfo::~AdvisoryInfo() = default; +AdvisoryInfoJSON::~AdvisoryInfoJSON() = default; void AdvisoryInfo::add_advisory(IAdvisory & advisory) { p_impl->add_advisory(advisory); } +void AdvisoryInfoJSON::add_advisory(IAdvisory & advisory) { + p_impl->add_advisory(advisory); +} + void AdvisoryInfo::print() { p_impl->print(); } +void AdvisoryInfoJSON::print() { + p_impl->print(); +} + } // namespace libdnf5::cli::output