Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[libdnf, actions plugin] Support for action options, option enabled and "plugin.version" variable #975

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions doc/libdnf5_plugins/actions.8.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Actions file format

Empty lines and lines that start with a '#' character (comment line) are ignored.

Each non-comment line defines an action and consists of five items separated by colons: ``callback_name:package_filter:direction:reserved:command``.
Each non-comment line defines an action and consists of five items separated by colons: ``callback_name:package_filter:direction:options:command``.

``callback_name``

Expand All @@ -69,6 +69,15 @@ Each non-comment line defines an action and consists of five items separated by
* ``in`` - packages coming to the system (downgrade, install, reinstall, upgrade)
* ``out`` - packages going out of the system (upgraded, downgraded, reinstalled, removed, replaced/obsoleted)

``options``
Options are separated by spaces. A space within an option can be written using escaping.

* ``enabled=<value>`` - the value specifies when the action is enabled (added in version 0.3.0)
ppisar marked this conversation as resolved.
Show resolved Hide resolved

* ``1`` - action is always enabled
ppisar marked this conversation as resolved.
Show resolved Hide resolved
* ``host-only`` - the action is only enabled for operations on the host
* ``installroot-only`` - the action is only enabled for operations in the alternative "installroot"

``command``
Any executable file with arguments.

Expand All @@ -79,6 +88,7 @@ Each non-comment line defines an action and consists of five items separated by
The following variables in the command will be substituted:

* ``${pid}`` - process ID
* ``${plugin.version}`` - version of the actions plugin (added in version 0.3.0)
* ``${conf.<option_name>}`` - option from base configuration
* ``${var.<variable_name>}`` - variable
* ``${tmp.<actions_plugin_variable_name>}`` - variable exists only in actions plugin context
Expand Down Expand Up @@ -118,9 +128,6 @@ Each non-comment line defines an action and consists of five items separated by
of when a particular ``package_filter`` is invoked depends on the position
of the corresponding package in the transaction.

``reserved``
Reserved for future use. Now empty.


Action standard output format
=============================
Expand All @@ -145,6 +152,7 @@ An example actions file:
pre_base_setup::::/usr/bin/sh -c echo\ -------------------------------------\ >>/tmp/actions-trans.log
pre_base_setup::::/usr/bin/sh -c date\ >>/tmp/actions-trans.log
pre_base_setup::::/usr/bin/sh -c echo\ libdnf5\ pre_base_setup\ was\ called.\ Process\ ID\ =\ '${pid}'.\ >>/tmp/actions-trans.log
pre_base_setup:::enabled=installroot-only:/usr/bin/sh -c echo\ run\ in\ alternative\ "installroot":\ installroot\ =\ '${conf.installroot}'\ >>/tmp/actions-trans.log

# Prints the value of the configuration option "defaultyes".
pre_base_setup::::/bin/sh -c echo\ 'pre_base_setup:\ conf.defaultyes=${{conf.defaultyes}}'\ >>\ {context.dnf.installroot}/actions.log
Expand Down
2 changes: 1 addition & 1 deletion libdnf5-plugins/actions/actions.conf
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[main]
name = actions
enabled = host-only
enabled = 1
55 changes: 45 additions & 10 deletions libdnf5-plugins/actions/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ using namespace libdnf5;
namespace {

constexpr const char * PLUGIN_NAME = "actions";
constexpr plugin::Version PLUGIN_VERSION{0, 2, 0};
constexpr plugin::Version PLUGIN_VERSION{0, 3, 0};

constexpr const char * attrs[]{"author.name", "author.email", "description", nullptr};
constexpr const char * attrs_value[]{"Jaroslav Rohel", "[email protected]", "Actions Plugin."};
Expand Down Expand Up @@ -215,6 +215,11 @@ std::pair<std::string, bool> Actions::substitute(
std::optional<std::string> var_value;
if (var_name == "pid") {
var_value = std::to_string(getpid());
} else if (var_name.starts_with("plugin.")) {
auto plugin_key = var_name.substr(7);
if (plugin_key == "version") {
var_value = fmt::format("{}.{}.{}", PLUGIN_VERSION.major, PLUGIN_VERSION.minor, PLUGIN_VERSION.micro);
}
} else if (var_name.starts_with("conf.")) {
auto config_opts = base.get_config().opt_binds();
auto it = config_opts.find(std::string(var_name.substr(5)));
Expand Down Expand Up @@ -389,36 +394,66 @@ void Actions::parse_action_files() {
auto pkg_filter_pos = line.find(':');
if (pkg_filter_pos == std::string::npos) {
throw ActionsPluginError(
M_("Error in file \"{}\" on line {}: \"HOOK:PKG_FILTER:DIRECTION::CMD\" format expected"),
M_("Error in file \"{}\" on line {}: \"HOOK:PKG_FILTER:DIRECTION:OPTIONS:CMD\" format expected"),
path.native(),
line_number);
}
++pkg_filter_pos;
auto direction_pos = line.find(':', pkg_filter_pos);
if (direction_pos == std::string::npos) {
throw ActionsPluginError(
M_("Error in file \"{}\" on line {}: \"HOOK:PKG_FILTER:DIRECTION::CMD\" format expected"),
M_("Error in file \"{}\" on line {}: \"HOOK:PKG_FILTER:DIRECTION:OPTIONS:CMD\" format expected"),
path.native(),
line_number);
}
++direction_pos;
auto reserved_pos = line.find(':', direction_pos);
if (reserved_pos == std::string::npos) {
auto options_pos = line.find(':', direction_pos);
if (options_pos == std::string::npos) {
throw ActionsPluginError(
M_("Error in file \"{}\" on line {}: \"HOOK:PKG_FILTER:DIRECTION::CMD\" format expected"),
M_("Error in file \"{}\" on line {}: \"HOOK:PKG_FILTER:DIRECTION:OPTIONS:CMD\" format expected"),
path.native(),
line_number);
}
++reserved_pos;
auto command_pos = line.find(':', reserved_pos);
++options_pos;
auto command_pos = line.find(':', options_pos);
if (command_pos == std::string::npos) {
throw ActionsPluginError(
M_("Error in file \"{}\" on line {}: \"HOOK:PKG_FILTER:DIRECTION::CMD\" format expected"),
M_("Error in file \"{}\" on line {}: \"HOOK:PKG_FILTER:DIRECTION:OPTIONS:CMD\" format expected"),
path.native(),
line_number);
}
++command_pos;

bool action_enabled{true};
auto options_str = line.substr(options_pos, command_pos - options_pos - 1);
const auto options = split(options_str);
for (const auto & opt : options) {
if (opt.starts_with("enabled=")) {
const auto value = opt.substr(8);
auto installroot_path = config.get_installroot_option().get_value();
bool installroot = installroot_path != "/";
if (value == "1") {
action_enabled = true;
} else if (value == "host-only") {
action_enabled = !installroot;
} else if (value == "installroot-only") {
action_enabled = installroot;
} else {
throw ActionsPluginError(
M_("Error in file \"{}\" on line {}: Unknown \"enabled\" option value \"{}\""),
path.native(),
line_number,
value);
}
} else {
throw ActionsPluginError(
M_("Error in file \"{}\" on line {}: Unknown option \"{}\""), path.native(), line_number, opt);
}
}
if (!action_enabled) {
continue;
}

enum class Hooks { PRE_BASE_SETUP, POST_BASE_SETUP, PRE_TRANS, POST_TRANS } hook;
if (line.starts_with("pre_base_setup:")) {
hook = Hooks::PRE_BASE_SETUP;
Expand Down Expand Up @@ -447,7 +482,7 @@ void Actions::parse_action_files() {
}
}

auto direction = line.substr(direction_pos, reserved_pos - direction_pos - 1);
auto direction = line.substr(direction_pos, options_pos - direction_pos - 1);
if (pkg_filter.empty() && !direction.empty()) {
throw ActionsPluginError(
M_("Error in file \"{}\" on line {}: Cannot use direction without package filter"),
Expand Down
Loading