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"};
 11
 12constexpr plugin::Version PLUGIN_VERSION{.major = 1, .minor = 0, .micro = 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 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 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