sdbus++: events: create event classes
Generate an equivalent amount of exception class as the `errors.yaml`
supported and convert the examples to use it.
Tested:
```
‣ Type=error Endian=l Flags=1 Version=1 Cookie=9 ReplyCookie=2 Timestamp="Tue 2024-09-17 18:21:35.649674 UTC"
Sender=:1.2489 Destination=:1.2495
ErrorName=net.poettering.Calculator.DivisionByZero ErrorMessage="Attempted to divide by zero."
UniqueName=:1.2489
MESSAGE "s" {
STRING "Attempted to divide by zero.";
};
```
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Change-Id: I4b2671838639d1e8be1ccdf655b699a98b9c2116
diff --git a/example/calculator-aserver.cpp b/example/calculator-aserver.cpp
index 33a582a..7a5051e 100644
--- a/example/calculator-aserver.cpp
+++ b/example/calculator-aserver.cpp
@@ -21,7 +21,7 @@
auto method_call(divide_t, auto x,
auto y) -> sdbusplus::async::task<divide_t::return_type>
{
- using sdbusplus::error::net::poettering::calculator::DivisionByZero;
+ using sdbusplus::error::net::poettering::Calculator::DivisionByZero;
if (y == 0)
{
status(State::Error);
diff --git a/example/calculator-server.cpp b/example/calculator-server.cpp
index 7ee4218..2d0efca 100644
--- a/example/calculator-server.cpp
+++ b/example/calculator-server.cpp
@@ -1,5 +1,4 @@
#include <net/poettering/Calculator/client.hpp>
-#include <net/poettering/Calculator/error.hpp>
#include <net/poettering/Calculator/server.hpp>
#include <sdbusplus/server.hpp>
@@ -29,7 +28,7 @@
*/
int64_t divide(int64_t x, int64_t y) override
{
- using sdbusplus::error::net::poettering::calculator::DivisionByZero;
+ using sdbusplus::error::net::poettering::Calculator::DivisionByZero;
if (y == 0)
{
status(State::Error);
diff --git a/example/yaml/net/poettering/Calculator.interface.yaml b/example/yaml/net/poettering/Calculator.interface.yaml
index f130e59..affc2d4 100644
--- a/example/yaml/net/poettering/Calculator.interface.yaml
+++ b/example/yaml/net/poettering/Calculator.interface.yaml
@@ -40,7 +40,7 @@
description: >
The result of (x/y).
errors:
- - self.Error.DivisionByZero
+ - self.DivisionByZero
- name: Clear
flags:
- unprivileged
@@ -65,7 +65,7 @@
description: >
The name of the owner of the Calculator.
errors:
- - self.Error.PermissionDenied
+ - self.PermissionDenied
signals:
- name: Cleared
description: >
diff --git a/include/sdbusplus/exception.hpp b/include/sdbusplus/exception.hpp
index e7e31ea..a9ddab0 100644
--- a/include/sdbusplus/exception.hpp
+++ b/include/sdbusplus/exception.hpp
@@ -41,6 +41,32 @@
int get_errno() const noexcept override;
};
+/** base exception for all new errors and events created by the sdbus++
+ * generator */
+template <typename Event>
+struct generated_event : public generated_exception
+{
+ const char* name() const noexcept override
+ {
+ return Event::errName;
+ }
+
+ const char* description() const noexcept override
+ {
+ return Event::errDesc;
+ }
+
+ const char* what() const noexcept override
+ {
+ return Event::errWhat;
+ }
+
+ int get_errno() const noexcept override
+ {
+ return Event::errErrno;
+ }
+};
+
/** base exception class for all errors generated by sdbusplus itself. */
struct internal_exception : public exception
{};
diff --git a/tools/sdbusplus/event.py b/tools/sdbusplus/event.py
index dd343cf..36d4673 100644
--- a/tools/sdbusplus/event.py
+++ b/tools/sdbusplus/event.py
@@ -24,8 +24,9 @@
class EventElement(NamedElement):
def __init__(self, **kwargs):
+ self.is_error = kwargs.pop("is_error", False)
self.deprecated = kwargs.pop("deprecated", None)
- self.errno = kwargs.pop("errno", None)
+ self.errno = kwargs.pop("errno", "EIO")
self.languages = {
key: EventLanguage(**kwargs.pop(key, {})) for key in ["en"]
}
@@ -39,6 +40,25 @@
super(EventElement, self).__init__(**kwargs)
+ def __getattribute__(self, name):
+ lam = {"description": lambda: self.__description()}.get(name)
+
+ if lam:
+ return lam()
+ try:
+ return super(EventElement, self).__getattribute__(name)
+ except Exception:
+ raise AttributeError(
+ "Attribute '%s' not found in %s.EventElement"
+ % (name, self.__module__)
+ )
+
+ def __description(self):
+ en = self.languages["en"]
+ if en.description:
+ return en.description
+ return en.message
+
@staticmethod
def syslog_severity(severity: str) -> str:
return {
@@ -81,7 +101,9 @@
def __init__(self, **kwargs):
self.version = kwargs.pop("version")
- self.errors = [EventElement(**n) for n in kwargs.pop("errors", [])]
+ self.errors = [
+ EventElement(**n, is_error=True) for n in kwargs.pop("errors", [])
+ ]
self.events = [EventElement(**n) for n in kwargs.pop("events", [])]
super(Event, self).__init__(**kwargs)
diff --git a/tools/sdbusplus/interface.py b/tools/sdbusplus/interface.py
index d801814..eade1de 100644
--- a/tools/sdbusplus/interface.py
+++ b/tools/sdbusplus/interface.py
@@ -44,14 +44,22 @@
includes = []
for e in inc_list:
e = e.replace("self.", self.name + ".")
- n = "/".join(
- e.split(".")[:-2], # ignore the Error.Name
- )
- includes.append(f"{n}/error.hpp")
+ if ".Error." in e:
+ n = "/".join(
+ e.split(".")[:-2], # ignore the Error.Name at the end
+ )
+ includes.append(f"{n}/error.hpp")
+ else:
+ n = "/".join(
+ e.split(".")[:-1], # ignore the .Name at the end
+ )
+ includes.append(f"{n}/event.hpp")
return sorted(set(includes))
def errorNamespacedClass(self, error):
error = error.replace("self.", self.name + ".")
+ if ".Error" not in error:
+ error = "error." + error
return "sdbusplus::" + "::".join(error.split("."))
def enum_includes(self, inc_list):
diff --git a/tools/sdbusplus/templates/event.hpp.mako b/tools/sdbusplus/templates/event.hpp.mako
index e69de29..78a31d9 100644
--- a/tools/sdbusplus/templates/event.hpp.mako
+++ b/tools/sdbusplus/templates/event.hpp.mako
@@ -0,0 +1,12 @@
+struct ${event.CamelCase} final :
+ public sdbusplus::exception::generated_event<${event.CamelCase}>
+{
+ static constexpr auto errName =
+ "${events.name}.${event.name}";
+ static constexpr auto errDesc =
+ "${event.description}";
+ static constexpr auto errWhat =
+ "${events.name}.${event.name}: ${event.description}";
+
+ static constexpr auto errErrno = ${event.errno};
+};
diff --git a/tools/sdbusplus/templates/event.md.mako b/tools/sdbusplus/templates/event.md.mako
index 012d833..de6a69b 100644
--- a/tools/sdbusplus/templates/event.md.mako
+++ b/tools/sdbusplus/templates/event.md.mako
@@ -8,7 +8,7 @@
${event.languages["en"].message}
% endif
-% if event.errno:
+% if event.is_error:
- severity: `${event.severity}`
- errno: `${event.errno}`
% endif
diff --git a/tools/sdbusplus/templates/events.hpp.mako b/tools/sdbusplus/templates/events.hpp.mako
index e69de29..434cc0b 100644
--- a/tools/sdbusplus/templates/events.hpp.mako
+++ b/tools/sdbusplus/templates/events.hpp.mako
@@ -0,0 +1,30 @@
+/* Events for ${events.name}
+ * Version: ${events.version}
+ */
+#pragma once
+#include <sdbusplus/exception.hpp>
+
+#include <cerrno>
+
+%if events.errors:
+
+namespace sdbusplus::error::${events.cppNamespacedClass()}
+{
+% for e in events.errors:
+
+${events.render(loader, "event.hpp.mako", events=events, event=e)}\
+% endfor
+
+} // namespace sdbusplus::error::${events.cppNamespacedClass()}
+%endif
+%if events.errors:
+
+namespace sdbusplus::event::${events.cppNamespacedClass()}
+{
+% for e in events.events:
+
+${events.render(loader, "event.hpp.mako", events=events, event=e)}\
+% endfor
+
+} // namespace sdbusplus::event::${events.cppNamespacedClass()}
+%endif