From b8d84f5cd8b2e8ff39b6d3c5f625cb458723a45e 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 | 88 +++++++++++++++++++++ 4 files changed, 118 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..ca9219454 100644 --- a/libdnf5-cli/output/advisoryinfo.cpp +++ b/libdnf5-cli/output/advisoryinfo.cpp @@ -22,6 +22,10 @@ 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 +33,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 +96,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