Skip to content

Commit

Permalink
libdnf5: rework plugin enablement
Browse files Browse the repository at this point in the history
- Pulled out the `Enabled` enum into `PluginEnabled`
- Add `EnabledPlugins` class that holds the logic for a set of plugins that are either enabled or disabled.
- Actually implemented the plugin enable/disable in `load_plugins`
  • Loading branch information
softwaresale committed Sep 29, 2023
1 parent 646c071 commit 32d50f3
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 8 deletions.
49 changes: 43 additions & 6 deletions libdnf5/plugin/plugins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ void Plugins::load_plugin_library(
logger.debug("End of loading plugins using the \"{}\" plugin.", name);
}

void Plugins::load_plugin(const std::string & config_file_path) {
void Plugins::load_plugin(const std::string & config_file_path, const EnabledPlugins &plugin_enablement) {
auto & logger = *base->get_logger();

libdnf5::ConfigParser parser;
Expand All @@ -156,7 +156,7 @@ void Plugins::load_plugin(const std::string & config_file_path) {
"Missing plugin name in configuration file \"{}\". \"{}\" will be used.", config_file_path, plugin_name);
}

enum class Enabled { NO, YES, HOST_ONLY, INSTALLROOT_ONLY } enabled;
PluginEnabled enabled;
const auto & enabled_str = parser.get_value("main", "enabled");
if (enabled_str == "host-only") {
enabled = Enabled::HOST_ONLY;
Expand All @@ -170,8 +170,11 @@ void Plugins::load_plugin(const std::string & config_file_path) {
}
}
const auto & installroot = base->get_config().get_installroot_option().get_value();
const bool is_enabled = enabled == Enabled::YES || (enabled == Enabled::HOST_ONLY && installroot == "/") ||
(enabled == Enabled::INSTALLROOT_ONLY && installroot != "/");

// try overriding the configuration file. If there's no override, use the config status
const bool is_enabled = plugin_enablement.plugin_enabled(plugin_name, installroot)
.value_or(EnabledPlugins::plugin_status_is_enabled(enabled, installroot));

if (!is_enabled) {
logger.debug("Skip disabled plugin \"{}\"", config_file_path);
return;
Expand All @@ -181,7 +184,7 @@ void Plugins::load_plugin(const std::string & config_file_path) {
load_plugin_library(std::move(parser), library_path, plugin_name);
}

void Plugins::load_plugins(const std::string & config_dir_path) {
void Plugins::load_plugins(const std::string & config_dir_path, const EnabledPlugins &plugin_enablement) {
auto & logger = *base->get_logger();
if (config_dir_path.empty())
throw PluginError(M_("Plugins::load_plugins(): config_dir_path cannot be empty"));
Expand All @@ -198,7 +201,7 @@ void Plugins::load_plugins(const std::string & config_dir_path) {
std::string failed_filenames;
for (const auto & path : config_paths) {
try {
load_plugin(path);
load_plugin(path, plugin_enablement);
} catch (const std::exception & ex) {
logger.error("Cannot load plugin \"{}\": {}", path.string(), ex.what());
if (!failed_filenames.empty()) {
Expand Down Expand Up @@ -262,4 +265,38 @@ void Plugins::finish() noexcept {
}
}

// plugin enablement classes
EnabledPlugins::EnabledPlugins(std::initializer_list<std::pair<std::string, PluginEnabled>> elements)
: enabled_plugins(elements)
{}

EnabledPlugins::EnabledPlugins(std::initializer_list<std::pair<std::string, bool>> elements) {
std::transform(elements.begin(), elements.end(), std::back_inserter(enabled_plugins), [](std::pair<std::string, bool> item) -> std::pair<std::string, PluginEnabled> {
return std::make_pair(item.first, item.second ? PluginEnabled::YES : PluginEnabled::NO);
});
}

void EnabledPlugins::push_back(std::string && plugin_pattern, libdnf5::plugin::PluginEnabled status) noexcept {
this->enabled_plugins.emplace_back(std::forward<std::string>(plugin_pattern), status);
}

void EnabledPlugins::push_back(std::string && plugin_pattern, bool enabled) noexcept {
this->push_back(std::forward<std::string>(plugin_pattern), enabled ? PluginEnabled::YES : PluginEnabled::NO);
}

bool EnabledPlugins::plugin_status_is_enabled(libdnf5::plugin::PluginEnabled status, const std::string & installroot) noexcept {
return status == PluginEnabled::YES || (status == PluginEnabled::HOST_ONLY && installroot == "/") ||
(status == PluginEnabled::INSTALLROOT_ONLY && installroot != "/");
}

std::optional<bool> EnabledPlugins::plugin_enabled(const std::string & plugin_name, const std::string & install_root) const noexcept {
for (const auto &[plugin_pattern, status] : enabled_plugins) {
if (sack::match_string(plugin_name, sack::QueryCmp::GLOB, plugin_pattern)) {
return {EnabledPlugins::plugin_status_is_enabled(status, install_root)};
}
}

return {};
}

} // namespace libdnf5::plugin
69 changes: 67 additions & 2 deletions libdnf5/plugin/plugins.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include <memory>
#include <string>
#include <vector>
#include <utility>
#include <optional>


namespace libdnf5::plugin {
Expand Down Expand Up @@ -69,6 +71,69 @@ class Plugin {
bool enabled{true};
};

enum class PluginEnabled {
NO, // = 0
YES, // = 1
HOST_ONLY, // = 2
INSTALLROOT_ONLY // = 3
};

/**
* Collection of enabled/disabled plugins
*/
class EnabledPlugins {
public:
/**
* Determines if the given plugin enablement status means the plugin is enabled. HOST_ONLY means 'enabled'
* iff installroot == '/'. INSTALLROOT_ONLY means 'enabled' iff installroot != '/'
* @param status Plugin enablement status to check
* @param installroot The install root. May be empty
* @return True if the plugin status corresponds to enabled, false otherwise
*/
static bool plugin_status_is_enabled(PluginEnabled status, const std::string &installroot) const noexcept;

EnabledPlugins(std::initializer_list<std::pair<std::string, PluginEnabled>> elements);
EnabledPlugins(std::initializer_list<std::pair<std::string, bool>> elements);

/**
* Pushes a new plugin enablement status to the history. The order of insertions is respected, so the last matching
* enable/disable request will be applied. For example, for the given requests:
* <p>
* { *, false }, { my-plugin, true }
* <p>
* all plugins except for my-plugin will be disabled.
*
* @param plugin_pattern The pattern of plugins to match
* @param status Enablement status
*/
void push_back(std::string &&plugin_pattern, PluginEnabled status) noexcept;

/**
* Adds a new enable/disable request.
* @param plugin_pattern Plugin pattern to match
* @param enabled True if enabled, false if disabled.
*/
void push_back(std::string &&plugin_pattern, bool enabled) noexcept;

/**
* Determines if a plugin specified here is enabled or not. If the plugin is specified here, then its enablement
* status is returned. If it is not specified, an empty optional is returned.
* @param plugin_name The plugin name to check. Globbing is enabled.
* @param install_root The install root of the system to optionally check against
* @return True if enabled and defined, false if disabled and defined, empty if not defined
*/
std::optional<bool> plugin_enabled(const std::string &plugin_name, const std::string &install_root = "") const noexcept;

/**
* Gets the enablement status of the given plugin name, or empty if it isn't defined here
* @param plugin_name The name of the plugin to check. Globbing is enabled.
* @return Status if plugin is defined here, empty otherwise
*/
std::optional<PluginEnabled> plugin_enabled_status(const std::string &plugin_name) const noexcept;

private:
std::vector<std::pair<std::string, PluginEnabled>> enabled_plugins;
};

/// Plugin manager
class Plugins {
Expand All @@ -80,10 +145,10 @@ class Plugins {
void register_plugin(std::unique_ptr<Plugin> && plugin);

/// Loads the plugin from the library defined by the configuration file config_file_path.
void load_plugin(const std::string & config_file_path);
void load_plugin(const std::string & config_file_path, const EnabledPlugins &plugin_enablement);

/// Loads plugins defined by configuration files in the directory.
void load_plugins(const std::string & config_dir_path);
void load_plugins(const std::string & config_dir_path, const EnabledPlugins &plugin_enablement);

/// Returns the number of registered plugins.
size_t count() const noexcept;
Expand Down

0 comments on commit 32d50f3

Please sign in to comment.