diff --git a/doc/libdnf5_plugins/actions.8.rst b/doc/libdnf5_plugins/actions.8.rst index 280107994..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. @@ -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 from base configuration * ``${var.}`` - variable * ``${tmp.}`` - variable exists only in actions plugin context @@ -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 ============================= @@ -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 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 diff --git a/libdnf5-plugins/actions/actions.cpp b/libdnf5-plugins/actions/actions.cpp index 3516b5761..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."}; @@ -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))); @@ -389,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); } @@ -397,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; @@ -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"),