From 03c2a501493e1f3abadf0add4c609d6cd1ada1b2 Mon Sep 17 00:00:00 2001 From: Jaroslav Rohel Date: Tue, 10 Oct 2023 15:06:45 +0200 Subject: [PATCH 1/3] [libdnf, actions plugin] Support for "plugin.version" variable --- doc/libdnf5_plugins/actions.8.rst | 1 + libdnf5-plugins/actions/actions.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/doc/libdnf5_plugins/actions.8.rst b/doc/libdnf5_plugins/actions.8.rst index 280107994..8d0110154 100644 --- a/doc/libdnf5_plugins/actions.8.rst +++ b/doc/libdnf5_plugins/actions.8.rst @@ -79,6 +79,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 from base configuration * ``${var.}`` - variable * ``${tmp.}`` - variable exists only in actions plugin context diff --git a/libdnf5-plugins/actions/actions.cpp b/libdnf5-plugins/actions/actions.cpp index 3516b5761..75b146ee3 100644 --- a/libdnf5-plugins/actions/actions.cpp +++ b/libdnf5-plugins/actions/actions.cpp @@ -215,6 +215,11 @@ std::pair Actions::substitute( std::optional 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))); From 466770d71f78f41d268066cf2bce56c02acb2c49 Mon Sep 17 00:00:00 2001 From: Jaroslav Rohel Date: Tue, 10 Oct 2023 15:57:28 +0200 Subject: [PATCH 2/3] [libdnf, actions plugin] Support for action options, option enabled The fourth item in the action definition has been reserved. It is now used to set additional action options. Options are separated by spaces. A space within an option can be written using escaping. One option is now supported - `enabled=`. Supported values of `value`: * `1` - action is always enabled * `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" Action can allways be disabled by commenting out the action line. --- doc/libdnf5_plugins/actions.8.rst | 15 ++++++--- libdnf5-plugins/actions/actions.cpp | 50 +++++++++++++++++++++++------ 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/doc/libdnf5_plugins/actions.8.rst b/doc/libdnf5_plugins/actions.8.rst index 8d0110154..8d50604a3 100644 --- a/doc/libdnf5_plugins/actions.8.rst +++ b/doc/libdnf5_plugins/actions.8.rst @@ -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`` @@ -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=`` - the value specifies when the action is enabled (added in version 0.3.0) + + * ``1`` - action is always enabled + * ``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. @@ -119,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 ============================= @@ -146,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 diff --git a/libdnf5-plugins/actions/actions.cpp b/libdnf5-plugins/actions/actions.cpp index 75b146ee3..5929121fb 100644 --- a/libdnf5-plugins/actions/actions.cpp +++ b/libdnf5-plugins/actions/actions.cpp @@ -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", "jrohel@redhat.com", "Actions Plugin."}; @@ -394,7 +394,7 @@ 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); } @@ -402,28 +402,58 @@ void Actions::parse_action_files() { 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; @@ -452,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"), From cfd5538c8b12305473b5d1f128e823a12f829c60 Mon Sep 17 00:00:00 2001 From: Jaroslav Rohel Date: Sat, 14 Oct 2023 12:07:38 +0200 Subject: [PATCH 3/3] [libdnf, actions plugin] actions.conf: Set "enabled" to "1" "Enabled" can now be set for each action separately. However, to enable actions, the "actions" plugin must be enabled. If "enabled" for the "actions" plugin is set to `host-only`, the action will not be performed for the alternate installroot even if it is enabled for the action. --- libdnf5-plugins/actions/actions.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdnf5-plugins/actions/actions.conf b/libdnf5-plugins/actions/actions.conf index 6e26cbf09..8b15f9e3c 100644 --- a/libdnf5-plugins/actions/actions.conf +++ b/libdnf5-plugins/actions/actions.conf @@ -1,3 +1,3 @@ [main] name = actions -enabled = host-only +enabled = 1