3. LIBDNF5 Plugin Template
Below is a template code for a LIBDNF5 plugin. For the complete tutorial on writing LIBDNF5 plugins, refer to LIBDNF5 Plugins.
libdnf5-plugins/template/template.cpp
1#include <libdnf5/base/base.hpp>
2#include <libdnf5/common/exception.hpp>
3#include <libdnf5/plugin/iplugin.hpp>
4
5#include <algorithm>
6
7using namespace libdnf5;
8
9namespace {
10
11constexpr const char * PLUGIN_NAME{"libdnf5_template_plugin"};
12constexpr plugin::Version PLUGIN_VERSION{.major = 1, .minor = 1, .micro = 0};
13constexpr PluginAPIVersion REQUIRED_PLUGIN_API_VERSION{.major = 2, .minor = 0};
14
15constexpr const char * attrs[]{"author.name", "author.email", "description", nullptr};
16constexpr const char * attrs_value[]{"Fatima Freedom", "dummy@email.com", "Plugin description."};
17
18class TemplatePlugin final : public plugin::IPlugin2_1 {
19public:
20 /// Implement custom constructor for the new plugin.
21 /// This is not necessary when you only need Base object for your implementation.
22 /// Optional to override.
23 TemplatePlugin(libdnf5::plugin::IPluginData & data, libdnf5::ConfigParser &) : IPlugin2_1(data) {}
24
25 /// Fill in the API version of your plugin.
26 /// This is used to check if the provided plugin API version is compatible with the library's plugin API version.
27 /// MANDATORY to override.
28 PluginAPIVersion get_api_version() const noexcept override { return REQUIRED_PLUGIN_API_VERSION; }
29
30 /// Enter the name of your new plugin.
31 /// This is used in log messages when an action or error related to the plugin occurs.
32 /// MANDATORY to override.
33 const char * get_name() const noexcept override { return PLUGIN_NAME; }
34
35 /// Fill in the version of your plugin.
36 /// This is utilized in informative and debugging log messages.
37 /// MANDATORY to override.
38 plugin::Version get_version() const noexcept override { return PLUGIN_VERSION; }
39
40 /// Add custom attributes, such as information about yourself and a description of the plugin.
41 /// These can be used to query plugin-specific data through the API.
42 /// Optional to override.
43 const char * const * get_attributes() const noexcept override { return attrs; }
44 const char * get_attribute(const char * attribute) const noexcept override {
45 for (size_t i = 0; attrs[i]; ++i) {
46 if (std::strcmp(attribute, attrs[i]) == 0) {
47 return attrs_value[i];
48 }
49 }
50 return nullptr;
51 }
52
53 /// Initialization method called after the Base object is created and before command-line arguments are parsed.
54 /// Optional to override.
55 void init() override {}
56
57 /// Cleanup method called when plugin objects are garbage collected.
58 /// Optional to override.
59 void finish() noexcept override {}
60
61 /// Override the hooks you want to implement.
62 void post_base_setup() override { post_base_magic(); }
63 void pre_transaction(const libdnf5::base::Transaction & transaction) override {
64 pre_transaction_magic(transaction);
65 };
66
67private:
68 void post_base_magic();
69 void pre_transaction_magic(const libdnf5::base::Transaction &);
70};
71
72/// Example how to implement additional logic after the Base is set up.
73void TemplatePlugin::post_base_magic() {
74 const auto & tsflags = get_base().get_config().get_tsflags_option().get_value();
75 if (std::find(tsflags.begin(), tsflags.end(), "noscripts") != tsflags.end()) {
76 libdnf_throw_assertion("Hey, we don't want a transaction without scriptlets!");
77 }
78}
79
80/// Example how to implement additional logic before starting the transaction.
81void TemplatePlugin::pre_transaction_magic(const libdnf5::base::Transaction & transaction) {
82 auto & base = get_base();
83 auto & logger = *base.get_logger();
84 logger.info("Libdnf5 template plugin: {} packages in transaction", transaction.get_transaction_packages_count());
85}
86
87// Global variable to store the last exception from plugin initialization
88// Allows capturing exceptions from C linkage functions that cannot propagate C++ exceptions
89std::exception_ptr last_exception;
90
91} // namespace
92
93/// Below is a block of functions with C linkage used for loading the plugin binaries from disk.
94/// All of these are MANDATORY to implement.
95
96/// Return plugin's API version.
97PluginAPIVersion libdnf_plugin_get_api_version(void) {
98 return REQUIRED_PLUGIN_API_VERSION;
99}
100
101/// Return plugin's name.
102const char * libdnf_plugin_get_name(void) {
103 return PLUGIN_NAME;
104}
105
106/// Return plugin's version.
107plugin::Version libdnf_plugin_get_version(void) {
108 return PLUGIN_VERSION;
109}
110
111/// Return the instance of the implemented plugin.
112plugin::IPlugin * libdnf_plugin_new_instance(
113 [[maybe_unused]] LibraryVersion library_version,
114 libdnf5::plugin::IPluginData & data,
115 libdnf5::ConfigParser & parser) try {
116 return new TemplatePlugin(data, parser);
117} catch (...) {
118 // Capture any exception that occurs during plugin instance creation
119 // std::current_exception() retrieves the current exception and stores it for later processing
120 last_exception = std::current_exception();
121
122 return nullptr; // Return nullptr as failure indicator (C function cannot throw exceptions)
123}
124
125/// Delete the plugin instance.
126void libdnf_plugin_delete_instance(plugin::IPlugin * plugin_object) {
127 delete plugin_object;
128}
129
130// libdnf5 use this function to determine the actual failure cause
131// when libdnf_plugin_new_instance() returns nullptr
132std::exception_ptr * libdnf_plugin_get_last_exception(void) {
133 return &last_exception;
134}
libdnf5-plugins/template/CMakeLists.txt
1# set gettext domain for translations
2set(GETTEXT_DOMAIN libdnf5-plugin-template)
3add_definitions(-DGETTEXT_DOMAIN=\"${GETTEXT_DOMAIN}\")
4
5# add your source files
6add_library(template_plugin MODULE template.cpp)
7
8# disable the 'lib' prefix in order to create template.so
9set_target_properties(template_plugin PROPERTIES PREFIX "")
10
11# link the libdnf5 library
12target_link_libraries(template_plugin PRIVATE libdnf5)
13
14# install the plugin into the common libdnf5-plugins location
15#install(TARGETS template_plugin LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/libdnf5/plugins/")
16
17# install default plugin configuration file
18#install(FILES "template.conf" DESTINATION "${CMAKE_INSTALL_FULL_SYSCONFDIR}/dnf/libdnf5-plugins")
libdnf5-plugins/template/template.conf
1[main]
2name = template_plugin
3enabled = yes
4
5# We can provide optional custom keys and sections.
6custom_key = some_value
7
8[custom]
9website = https://my-hosting/template-plugin.org