Skip to content

Commit

Permalink
Add --json output to advisory info
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
stewartsmith committed Dec 24, 2024
1 parent 2af228e commit fce16cc
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 4 deletions.
18 changes: 14 additions & 4 deletions dnf5/commands/advisory/advisory_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions dnf5/commands/advisory/advisory_info.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.

#include "advisory_subcommand.hpp"

#include <dnf5/shared_options.hpp>

namespace dnf5 {

class AdvisoryInfoCommand : public AdvisorySubCommand {
Expand All @@ -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:
Expand Down
13 changes: 13 additions & 0 deletions include/libdnf5-cli/output/advisoryinfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,19 @@ class LIBDNF_CLI_API AdvisoryInfo {
std::unique_ptr<Impl> 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<Impl> p_impl;
};

} // namespace libdnf5::cli::output

#endif // LIBDNF5_CLI_OUTPUT_ADVISORYLIST_HPP
90 changes: 90 additions & 0 deletions libdnf5-cli/output/advisoryinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,30 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include "key_value_table.hpp"
#include "utils/string.hpp"


#include <json.h>


#include <iostream>

namespace libdnf5::cli::output {

class AdvisoryInfo::Impl : public KeyValueTable {
public:
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");
Expand Down Expand Up @@ -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

0 comments on commit fce16cc

Please sign in to comment.