diff --git a/dnf5/commands/repo/repo_list.cpp b/dnf5/commands/repo/repo_list.cpp index 3a7bc9389..e688712b8 100644 --- a/dnf5/commands/repo/repo_list.cpp +++ b/dnf5/commands/repo/repo_list.cpp @@ -19,6 +19,7 @@ along with libdnf. If not, see . #include "repo_list.hpp" +#include #include #include @@ -39,6 +40,8 @@ void RepoListCommand::set_argument_parser() { all->get_arg()->add_conflict_argument(*enabled->get_arg()); all->get_arg()->add_conflict_argument(*disabled->get_arg()); enabled->get_arg()->add_conflict_argument(*disabled->get_arg()); + + create_json_option(*this); } void RepoListCommand::run() { @@ -82,7 +85,12 @@ void RepoListCommand::print(const libdnf5::repo::RepoQuery & query, bool with_st cli_repos.emplace_back(new libdnf5::cli::output::RepoAdapter(repo)); } - libdnf5::cli::output::print_repolist_table(cli_repos, with_status, libdnf5::cli::output::COL_REPO_ID); + auto & ctx = get_context(); + if (ctx.get_json_output_requested()) { + libdnf5::cli::output::print_repolist_json(cli_repos); + } else { + libdnf5::cli::output::print_repolist_table(cli_repos, with_status, libdnf5::cli::output::COL_REPO_ID); + } } } // namespace dnf5 diff --git a/dnf5/context.cpp b/dnf5/context.cpp index 3ebebb22f..6415db577 100644 --- a/dnf5/context.cpp +++ b/dnf5/context.cpp @@ -173,6 +173,9 @@ class Context::Impl { void set_should_store_offline(bool should_store_offline) { this->should_store_offline = should_store_offline; } bool get_should_store_offline() const { return should_store_offline; } + void set_json_output_requested(bool json_output) { this->json_output = json_output; } + bool get_json_output_requested() const { return json_output; } + libdnf5::Base & get_base() { return base; }; std::vector> & get_setopts() { return setopts; } @@ -206,6 +209,7 @@ class Context::Impl { const char * comment{nullptr}; bool should_store_offline = false; + bool json_output = false; bool quiet{false}; bool dump_main_config{false}; @@ -658,6 +662,14 @@ bool Context::get_should_store_offline() const { return p_impl->get_should_store_offline(); } +void Context::set_json_output_requested(bool json_output) { + p_impl->set_json_output_requested(json_output); +} + +bool Context::get_json_output_requested() const { + return p_impl->get_json_output_requested(); +} + libdnf5::Base & Context::get_base() { return p_impl->get_base(); }; diff --git a/dnf5/include/dnf5/context.hpp b/dnf5/include/dnf5/context.hpp index e1448fdb1..cf1c530a3 100644 --- a/dnf5/include/dnf5/context.hpp +++ b/dnf5/include/dnf5/context.hpp @@ -149,6 +149,9 @@ class Context : public libdnf5::cli::session::Session { void set_should_store_offline(bool should_store_offline); bool get_should_store_offline() const; + void set_json_output_requested(bool json_output); + bool get_json_output_requested() const; + libdnf5::Base & get_base(); std::vector> & get_setopts(); diff --git a/dnf5/include/dnf5/shared_options.hpp b/dnf5/include/dnf5/shared_options.hpp index 49e2b36dc..522794006 100644 --- a/dnf5/include/dnf5/shared_options.hpp +++ b/dnf5/include/dnf5/shared_options.hpp @@ -63,10 +63,12 @@ void create_downloadonly_option(dnf5::Command & command); /// The value is stored in Context::transaction_store_path. void create_store_option(dnf5::Command & command); - /// Create the `--offline` option for a command provided as an argument. void create_offline_option(dnf5::Command & command); +/// Create the `--json` option for a command provided as an argument. +void create_json_option(dnf5::Command & command); + } // namespace dnf5 #endif // DNF5_COMMANDS_SHARED_OPTIONS_HPP diff --git a/dnf5/shared_options.cpp b/dnf5/shared_options.cpp index 59ffa0dcd..4042fe1ec 100644 --- a/dnf5/shared_options.cpp +++ b/dnf5/shared_options.cpp @@ -139,5 +139,22 @@ void create_store_option(dnf5::Command & command) { }); } +void create_json_option(dnf5::Command & command) { + auto & ctx = command.get_context(); + auto & parser = command.get_context().get_argument_parser(); + auto json = parser.add_new_named_arg("json"); + json->set_long_name("json"); + json->set_description("Request json output format"); + json->set_const_value("true"); + json->set_parse_hook_func([&ctx]( + [[maybe_unused]] libdnf5::cli::ArgumentParser::NamedArg * arg, + [[maybe_unused]] const char * option, + [[maybe_unused]] const char * value) { + ctx.set_json_output_requested(true); + return true; + }); + command.get_argument_parser_command()->register_named_arg(json); +} + } // namespace dnf5 diff --git a/include/libdnf5-cli/output/repolist.hpp b/include/libdnf5-cli/output/repolist.hpp index f0401d1ff..45680b0d2 100644 --- a/include/libdnf5-cli/output/repolist.hpp +++ b/include/libdnf5-cli/output/repolist.hpp @@ -31,6 +31,7 @@ namespace libdnf5::cli::output { enum { COL_REPO_ID, COL_REPO_NAME, COL_REPO_STATUS }; void print_repolist_table(const std::vector> & repos, bool with_status, size_t sort_column); +void print_repolist_json(const std::vector> & repos); } // namespace libdnf5::cli::output diff --git a/libdnf5-cli/CMakeLists.txt b/libdnf5-cli/CMakeLists.txt index 8cfa9d1e0..8025730db 100644 --- a/libdnf5-cli/CMakeLists.txt +++ b/libdnf5-cli/CMakeLists.txt @@ -41,6 +41,10 @@ pkg_check_modules(SMARTCOLS REQUIRED smartcols) list(APPEND LIBDNF5_CLI_PC_REQUIRES_PRIVATE "${SMARTCOLS_MODULE_NAME}") target_link_libraries(libdnf5-cli PRIVATE ${SMARTCOLS_LIBRARIES}) +pkg_check_modules(JSONC REQUIRED json-c) +include_directories(${JSONC_INCLUDE_DIRS}) +target_link_libraries(libdnf5-cli PRIVATE ${JSONC_LIBRARIES}) + # sort the pkg-config requires and concatenate them into a string list(SORT LIBDNF5_CLI_PC_REQUIRES) diff --git a/libdnf5-cli/output/repolist.cpp b/libdnf5-cli/output/repolist.cpp index d03b97803..ff215f8ee 100644 --- a/libdnf5-cli/output/repolist.cpp +++ b/libdnf5-cli/output/repolist.cpp @@ -21,6 +21,7 @@ along with libdnf. If not, see . #include "libdnf5-cli/tty.hpp" +#include #include namespace libdnf5::cli::output { @@ -75,4 +76,18 @@ void print_repolist_table(const std::vector> & repos, boo scols_unref_table(table); } + +void print_repolist_json([[maybe_unused]] const std::vector> & repos) { + json_object * json_repos = json_object_new_array(); + for (const auto & repo : repos) { + json_object * json_repo = json_object_new_object(); + json_object_object_add(json_repo, "id", json_object_new_string(repo->get_id().c_str())); + json_object_object_add(json_repo, "name", json_object_new_string(repo->get_name().c_str())); + json_object_object_add(json_repo, "is_enabled", json_object_new_boolean(repo->is_enabled())); + json_object_array_add(json_repos, json_repo); + } + std::cout << json_object_to_json_string_ext(json_repos, JSON_C_TO_STRING_PRETTY) << std::endl; + json_object_put(json_repos); +} + } // namespace libdnf5::cli::output