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
4#include <algorithm>
5
6using namespace libdnf5;
7
8namespace {
9
10constexpr const char * PLUGIN_NAME{"template"};
11constexpr plugin::Version PLUGIN_VERSION{.major = 1, .minor = 0, .micro = 0};
12constexpr PluginAPIVersion REQUIRED_PLUGIN_API_VERSION{.major = 2, .minor = 0};
13
14constexpr const char * attrs[]{"author.name", "author.email", "description", nullptr};
15constexpr const char * attrs_value[]{"Fatima Freedom", "dummy@email.com", "Plugin description."};
16
17class TemplatePlugin : public plugin::IPlugin {
18public:
19 /// Implement custom constructor for the new plugin.
20 /// This is not necessary when you only need Base object for your implementation.
21 /// Optional to override.
22 TemplatePlugin(libdnf5::Base & base, libdnf5::ConfigParser &) : IPlugin(base) {}
23
24 /// Fill in the API version of your plugin.
25 /// This is used to check if the provided plugin API version is compatible with the library's plugin API version.
26 /// MANDATORY to override.
27 PluginAPIVersion get_api_version() const noexcept override { return REQUIRED_PLUGIN_API_VERSION; }
28
29 /// Enter the name of your new plugin.
30 /// This is used in log messages when an action or error related to the plugin occurs.
31 /// MANDATORY to override.
32 const char * get_name() const noexcept override { return PLUGIN_NAME; }
33
34 /// Fill in the version of your plugin.
35 /// This is utilized in informative and debugging log messages.
36 /// MANDATORY to override.
37 plugin::Version get_version() const noexcept override { return PLUGIN_VERSION; }
38
39 /// Add custom attributes, such as information about yourself and a description of the plugin.
40 /// These can be used to query plugin-specific data through the API.
41 /// Optional to override.
42 const char * const * get_attributes() const noexcept override { return attrs; }
43 const char * get_attribute(const char * attribute) const noexcept override {
44 for (size_t i = 0; attrs[i]; ++i) {
45 if (std::strcmp(attribute, attrs[i]) == 0) {
46 return attrs_value[i];
47 }
48 }
49 return nullptr;
50 }
51
52 /// Initialization method called after the Base object is created and before command-line arguments are parsed.
53 /// Optional to override.
54 void init() override {}
55
56 /// Cleanup method called when plugin objects are garbage collected.
57 /// Optional to override.
58 void finish() noexcept override {}
59
60 /// Override the hooks you want to implement.
61 void post_base_setup() override { post_base_magic(); }
62 void pre_transaction(const libdnf5::base::Transaction & transaction) override {
63 pre_transaction_magic(transaction);
64 };
65
66private:
67 void post_base_magic();
68 void pre_transaction_magic(const libdnf5::base::Transaction &);
69};
70
71/// Example how to implement additional logic after the Base is set up.
72void TemplatePlugin::post_base_magic() {
73 const auto & tsflags = get_base().get_config().get_tsflags_option().get_value();
74 if (std::find(tsflags.begin(), tsflags.end(), "noscripts") != tsflags.end()) {
75 libdnf_throw_assertion("Hey, we don't want a transaction without scriptlets!");
76 }
77}
78
79/// Example how to implement additional logic before starting the transaction.
80void TemplatePlugin::pre_transaction_magic(const libdnf5::base::Transaction & transaction) {
81 transaction.set_description("This is our important transaction.");
82}
83
84} // namespace
85
86/// Below is a block of functions with C linkage used for loading the plugin binaries from disk.
87/// All of these are MANDATORY to implement.
88
89/// Return plugin's API version.
90PluginAPIVersion libdnf_plugin_get_api_version(void) {
91 return REQUIRED_PLUGIN_API_VERSION;
92}
93
94/// Return plugin's name.
95const char * libdnf_plugin_get_name(void) {
96 return PLUGIN_NAME;
97}
98
99/// Return plugin's version.
100plugin::Version libdnf_plugin_get_version(void) {
101 return PLUGIN_VERSION;
102}
103
104/// Return the instance of the implemented plugin.
105plugin::IPlugin * libdnf_plugin_new_instance(
106 [[maybe_unused]] LibraryVersion library_version, libdnf5::Base & base, libdnf5::ConfigParser & parser) try {
107 return new TemplatePlugin(base, parser);
108} catch (...) {
109 return nullptr;
110}
111
112/// Delete the plugin instance.
113void libdnf_plugin_delete_instance(plugin::IPlugin * plugin_object) {
114 delete plugin_object;
115}
libdnf5-plugins/template/CMakeLists.txt
1# setup conditional build
2if(NOT WITH_PLUGIN_TEMPLATE)
3 return()
4endif()
5
6# set gettext domain for translations
7add_definitions(-DGETTEXT_DOMAIN=\"libdnf5\")
8
9# add your source files
10add_library(template MODULE template.cpp)
11
12# disable the 'lib' prefix in order to create template.so
13set_target_properties(template PROPERTIES PREFIX "")
14
15# link the libdnf5 library
16target_link_libraries(template PRIVATE libdnf5)
17
18# install the plugin into the common libdnf5-plugins location
19install(TARGETS template LIBRARY DESTINATION "${CMAKE_INSTALL_FULL_LIBDIR}/libdnf5/plugins/")
libdnf5-plugins/template/template.conf
1[main]
2name = template
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