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

Plugin API: *_plugin_get_last_exception: Return pointer to last exception #2052

Merged
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
1 change: 1 addition & 0 deletions bindings/libdnf5/plugin.i
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
%ignore libdnf_plugin_get_version;
%ignore libdnf_plugin_new_instance;
%ignore libdnf_plugin_delete_instance;
%ignore libdnf_plugin_get_last_exception;
%feature("director") IPlugin;
%include "libdnf5/plugin/iplugin.hpp"

Expand Down
7 changes: 7 additions & 0 deletions dnf5-plugins/automatic_plugin/automatic_cmd_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ std::vector<std::unique_ptr<Command>> AutomaticCmdPlugin::create_commands() {
}


std::exception_ptr last_exception;

} // namespace


Expand All @@ -67,9 +69,14 @@ PluginVersion dnf5_plugin_get_version(void) {
IPlugin * dnf5_plugin_new_instance([[maybe_unused]] ApplicationVersion application_version, Context & context) try {
return new AutomaticCmdPlugin(context);
} catch (...) {
last_exception = std::current_exception();
return nullptr;
}

void dnf5_plugin_delete_instance(IPlugin * plugin_object) {
delete plugin_object;
}

std::exception_ptr * dnf5_plugin_get_last_exception(void) {
return &last_exception;
}
7 changes: 7 additions & 0 deletions dnf5-plugins/builddep_plugin/builddep_cmd_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ std::vector<std::unique_ptr<Command>> BuildDepCmdPlugin::create_commands() {
}


std::exception_ptr last_exception;

} // namespace


Expand All @@ -67,9 +69,14 @@ PluginVersion dnf5_plugin_get_version(void) {
IPlugin * dnf5_plugin_new_instance([[maybe_unused]] ApplicationVersion application_version, Context & context) try {
return new BuildDepCmdPlugin(context);
} catch (...) {
last_exception = std::current_exception();
return nullptr;
}

void dnf5_plugin_delete_instance(IPlugin * plugin_object) {
delete plugin_object;
}

std::exception_ptr * dnf5_plugin_get_last_exception(void) {
return &last_exception;
}
7 changes: 7 additions & 0 deletions dnf5-plugins/changelog_plugin/changelog_cmd_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ std::vector<std::unique_ptr<Command>> ChangelogCmdPlugin::create_commands() {
}


std::exception_ptr last_exception;

} // namespace


Expand All @@ -67,9 +69,14 @@ PluginVersion dnf5_plugin_get_version(void) {
IPlugin * dnf5_plugin_new_instance([[maybe_unused]] ApplicationVersion application_version, Context & context) try {
return new ChangelogCmdPlugin(context);
} catch (...) {
last_exception = std::current_exception();
return nullptr;
}

void dnf5_plugin_delete_instance(IPlugin * plugin_object) {
delete plugin_object;
}

std::exception_ptr * dnf5_plugin_get_last_exception(void) {
return &last_exception;
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ std::vector<std::unique_ptr<Command>> ConfigManagerCmdPlugin::create_commands()
}


std::exception_ptr last_exception;

} // namespace


Expand All @@ -67,9 +69,14 @@ PluginVersion dnf5_plugin_get_version(void) {
IPlugin * dnf5_plugin_new_instance([[maybe_unused]] ApplicationVersion application_version, Context & context) try {
return new ConfigManagerCmdPlugin(context);
} catch (...) {
last_exception = std::current_exception();
return nullptr;
}

void dnf5_plugin_delete_instance(IPlugin * plugin_object) {
delete plugin_object;
}

std::exception_ptr * dnf5_plugin_get_last_exception(void) {
return &last_exception;
}
7 changes: 7 additions & 0 deletions dnf5-plugins/copr_plugin/copr_cmd_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ class CoprCmdPlugin : public IPlugin {
};


std::exception_ptr last_exception;

} // namespace


Expand All @@ -87,9 +89,14 @@ PluginVersion dnf5_plugin_get_version(void) {
IPlugin * dnf5_plugin_new_instance([[maybe_unused]] ApplicationVersion application_version, Context & context) try {
return new CoprCmdPlugin(context);
} catch (...) {
last_exception = std::current_exception();
return nullptr;
}

void dnf5_plugin_delete_instance(IPlugin * plugin_object) {
delete plugin_object;
}

std::exception_ptr * dnf5_plugin_get_last_exception(void) {
return &last_exception;
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ std::vector<std::unique_ptr<Command>> NeedsRestartingCmdPlugin::create_commands(
}


std::exception_ptr last_exception;

} // namespace


Expand All @@ -67,9 +69,14 @@ PluginVersion dnf5_plugin_get_version(void) {
IPlugin * dnf5_plugin_new_instance([[maybe_unused]] ApplicationVersion application_version, Context & context) try {
return new NeedsRestartingCmdPlugin(context);
} catch (...) {
last_exception = std::current_exception();
return nullptr;
}

void dnf5_plugin_delete_instance(IPlugin * plugin_object) {
delete plugin_object;
}

std::exception_ptr * dnf5_plugin_get_last_exception(void) {
return &last_exception;
}
7 changes: 7 additions & 0 deletions dnf5-plugins/repoclosure_plugin/repoclosure_cmd_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ std::vector<std::unique_ptr<Command>> RepoclosureCmdPlugin::create_commands() {
}


std::exception_ptr last_exception;

} // namespace


Expand All @@ -86,9 +88,14 @@ PluginVersion dnf5_plugin_get_version(void) {
IPlugin * dnf5_plugin_new_instance([[maybe_unused]] ApplicationVersion application_version, Context & context) try {
return new RepoclosureCmdPlugin(context);
} catch (...) {
last_exception = std::current_exception();
return nullptr;
}

void dnf5_plugin_delete_instance(IPlugin * plugin_object) {
delete plugin_object;
}

std::exception_ptr * dnf5_plugin_get_last_exception(void) {
return &last_exception;
}
7 changes: 7 additions & 0 deletions dnf5-plugins/reposync_plugin/reposync_cmd_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ std::vector<std::unique_ptr<Command>> ReposyncCmdPlugin::create_commands() {
}


std::exception_ptr last_exception;

} // namespace


Expand All @@ -86,9 +88,14 @@ PluginVersion dnf5_plugin_get_version(void) {
IPlugin * dnf5_plugin_new_instance([[maybe_unused]] ApplicationVersion application_version, Context & context) try {
return new ReposyncCmdPlugin(context);
} catch (...) {
last_exception = std::current_exception();
return nullptr;
}

void dnf5_plugin_delete_instance(IPlugin * plugin_object) {
delete plugin_object;
}

std::exception_ptr * dnf5_plugin_get_last_exception(void) {
return &last_exception;
}
28 changes: 24 additions & 4 deletions dnf5/include/dnf5/iplugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include "defs.h"

#include <cstdint>
#include <exception>
#include <vector>

namespace dnf5 {
Expand Down Expand Up @@ -82,24 +83,43 @@ class DNF_PLUGIN_API IPlugin {

extern "C" {

/// Returns the version of the API required by the plugin.
/// Returns the version of the API implemented by the plugin.
/// Same result as IPlugin::get_api_version(), but can be called without creating an IPlugin instance.
///
/// @return API version implemented by the plugin.
DNF_PLUGIN_API dnf5::PluginAPIVersion dnf5_plugin_get_api_version(void);

/// Returns the name of the plugin. It can be called at any time.
/// Returns the name of the plugin.
/// Same result as IPlugin::get_name(), but can be called without creating an IPlugin instance.
///
/// @return Plugin name
DNF_PLUGIN_API const char * dnf5_plugin_get_name(void);

/// Returns the version of the plugin. It can be called at any time.
/// Returns the version of the plugin.
/// Same result as IPlugin::get_version(), but can be called without creating an IPlugin instance.
///
/// @return Plugin version
DNF_PLUGIN_API dnf5::PluginVersion dnf5_plugin_get_version(void);

/// Creates a new plugin instance. Passes the API version to the plugin.
/// Creates a new plugin instance.
/// On failure, returns `nullptr` and saves the exception.
///
/// @param aplication_version Version of dnf application.
/// @param context Reference to the application context.
/// @return Pointer to the new plugin instance or `nullptr`.
DNF_PLUGIN_API dnf5::IPlugin * dnf5_plugin_new_instance(
dnf5::ApplicationVersion application_version, dnf5::Context & context);

/// Deletes plugin instance.
///
/// @param plugin_instance Plugin instance to delete.
DNF_PLUGIN_API void dnf5_plugin_delete_instance(dnf5::IPlugin * plugin_instance);

/// Returns a pointer to `std::exception_ptr` containing the last caught exception.
/// If no exception has occurred yet, returns a pointer to an empty `std::exception_ptr`.
///
/// @return Pointer to the `std::exception_ptr` containing the last caught exception.
DNF_PLUGIN_API std::exception_ptr * dnf5_plugin_get_last_exception(void);
}

#endif
29 changes: 28 additions & 1 deletion dnf5/plugins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ class PluginLibrary : public Plugin {
using TGetVersionFunc = decltype(&dnf5_plugin_get_version);
using TNewInstanceFunc = decltype(&dnf5_plugin_new_instance);
using TDeleteInstanceFunc = decltype(&dnf5_plugin_delete_instance);
using TGetLastException = decltype(&dnf5_plugin_get_last_exception);
TGetApiVersionFunc get_api_version{nullptr};
TGetNameFunc get_name{nullptr};
TGetVersionFunc get_version{nullptr};
TNewInstanceFunc new_instance{nullptr};
TDeleteInstanceFunc delete_instance{nullptr};
TGetLastException get_last_exception{nullptr};
utils::Library library;
};

Expand All @@ -73,9 +75,34 @@ PluginLibrary::PluginLibrary(Context & context, const std::string & library_path
new_instance = reinterpret_cast<TNewInstanceFunc>(library.get_address("dnf5_plugin_new_instance"));
delete_instance = reinterpret_cast<TDeleteInstanceFunc>(library.get_address("dnf5_plugin_delete_instance"));

try {
get_last_exception = reinterpret_cast<TGetLastException>(library.get_address("dnf5_plugin_get_last_exception"));
} catch (const std::runtime_error &) {
// The original plugin API did not have the "dnf5_plugin_get_last_exception" function.
// To maintain compatibility with older plugins, the "dnf5_plugin_get_last_exception" function is optional.
}

iplugin_instance = new_instance(dnf5::get_application_version(), context);
if (!iplugin_instance) {
throw std::runtime_error("Failed to create a dnf plugin instance");
auto & logger = *context.get_base().get_logger();
std::runtime_error plugin_exception("Failed to create a dnf plugin instance");
if (get_last_exception) {
if (auto * last_exception = get_last_exception()) {
try {
if (*last_exception) {
std::rethrow_exception(*last_exception);
}
} catch (const std::exception & ex) {
*last_exception = nullptr; // We no longer need to save the exception in the plugin.
logger.error("dnf5_plugin_new_instance: {}", ex.what());
std::throw_with_nested(std::move(plugin_exception));
} catch (...) {
*last_exception = nullptr; // We no longer need to save the exception in the plugin.
std::throw_with_nested(std::move(plugin_exception));
}
}
}
throw std::move(plugin_exception);
}
}

Expand Down
29 changes: 25 additions & 4 deletions include/libdnf5/plugin/iplugin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.
#include "libdnf5/defs.h"
#include "libdnf5/version.hpp"

#include <exception>
#include <string>
#include <vector>

Expand Down Expand Up @@ -142,24 +143,44 @@ class LIBDNF_PLUGIN_API IPlugin2_1 : public IPlugin {

extern "C" {

/// Returns the version of the API supported by the plugin.
/// Returns the version of the API implemented by the plugin.
/// Same result as IPlugin::get_api_version(), but can be called without creating an IPlugin instance.
///
/// @return API version implemented by the plugin.
LIBDNF_PLUGIN_API libdnf5::PluginAPIVersion libdnf_plugin_get_api_version(void);

/// Returns the name of the plugin. It can be called at any time.
/// Returns the name of the plugin.
/// Same result as IPlugin::get_name(), but can be called without creating an IPlugin instance.
///
/// @return Plugin name
LIBDNF_PLUGIN_API const char * libdnf_plugin_get_name(void);

/// Returns the version of the plugin. It can be called at any time.
/// Returns the version of the plugin.
/// Same result as IPlugin::get_version(), but can be called without creating an IPlugin instance.
///
/// @return Plugin version
LIBDNF_PLUGIN_API libdnf5::plugin::Version libdnf_plugin_get_version(void);

/// Creates a new plugin instance. Passes the API version to the plugin.
/// Creates a new plugin instance.
/// On failure, returns `nullptr` and saves the exception.
///
/// @param library_version Version of libdnf library.
/// @param data Private libdnf data passed to the plugin.
/// @param parser Parser with loaded plugin configuration file.
/// @return Pointer to the new plugin instance or `nullptr`.
LIBDNF_PLUGIN_API libdnf5::plugin::IPlugin * libdnf_plugin_new_instance(
libdnf5::LibraryVersion library_version, libdnf5::plugin::IPluginData & data, libdnf5::ConfigParser & parser);

/// Deletes plugin instance.
///
/// @param plugin_instance Plugin instance to delete.
LIBDNF_PLUGIN_API void libdnf_plugin_delete_instance(libdnf5::plugin::IPlugin * plugin_instance);

/// Returns a pointer to `std::exception_ptr` containing the last caught exception.
/// If no exception has occurred yet, returns a pointer to an empty `std::exception_ptr`.
///
/// @return Pointer to the `std::exception_ptr` containing the last caught exception.
LIBDNF_PLUGIN_API std::exception_ptr * libdnf_plugin_get_last_exception(void);
}

#endif
8 changes: 8 additions & 0 deletions libdnf5-plugins/actions/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1983,6 +1983,9 @@ void Actions::on_transaction(const libdnf5::base::Transaction & transaction, con
}
}


std::exception_ptr last_exception;

} // namespace

PluginAPIVersion libdnf_plugin_get_api_version(void) {
Expand All @@ -2003,9 +2006,14 @@ plugin::IPlugin * libdnf_plugin_new_instance(
libdnf5::ConfigParser & parser) try {
return new Actions(data, parser);
} catch (...) {
last_exception = std::current_exception();
return nullptr;
}

void libdnf_plugin_delete_instance(plugin::IPlugin * plugin_object) {
delete plugin_object;
}

std::exception_ptr * libdnf_plugin_get_last_exception(void) {
return &last_exception;
}
Loading