diff mbox series

[v4,09/11] qapi: golang: Generate command type

Message ID 20250214202944.69897-10-victortoso@redhat.com (mailing list archive)
State New
Headers show
Series [v4,01/11] qapi: golang: first level unmarshalling type | expand

Commit Message

Victor Toso Feb. 14, 2025, 8:29 p.m. UTC
This patch handles QAPI command types and generates data structures in
Go that handles it.

Note that command's id is part of the first layer of unmarshal, so it
is a member of protocol.go's Message type.

qapi:
 | ##
 | # @add-fd:
 | #
 | # Add a file descriptor, that was passed via SCM rights, to an fd set.
 | #
 | # @fdset-id: The ID of the fd set to add the file descriptor to.
 | #
 | # @opaque: A free-form string that can be used to describe the fd.
 | #
 | # Returns:
 | #     @AddfdInfo
 | #
 | # Errors:
 | #     - If file descriptor was not received, GenericError
 | #     - If @fdset-id is a negative value, GenericError
 | #
 | # .. note:: The list of fd sets is shared by all monitor connections.
 | #
 | # .. note:: If @fdset-id is not specified, a new fd set will be
 | #    created.
 | #
 | # Since: 1.2
 | #
 | # .. qmp-example::
 | #
 | #     -> { "execute": "add-fd", "arguments": { "fdset-id": 1 } }
 | #     <- { "return": { "fdset-id": 1, "fd": 3 } }
 | ##
 | { 'command': 'add-fd',
 |   'data': { '*fdset-id': 'int',
 |             '*opaque': 'str' },
 |   'returns': 'AddfdInfo' }

go:
 | // Add a file descriptor, that was passed via SCM rights, to an fd
 | // set.
 | //
 | // Returns:   @AddfdInfo
 | //
 | // Errors:   - If file descriptor was not received, GenericError   -
 | // If @fdset-id is a negative value, GenericError
 | //
 | // .. note:: The list of fd sets is shared by all monitor connections.
 | // .. note:: If @fdset-id is not specified, a new fd set will be
 | // created.
 | //
 | // Since: 1.2
 | //
 | // .. qmp-example::    -> { "execute": "add-fd", "arguments": {
 | // "fdset-id": 1 } }   <- { "return": { "fdset-id": 1, "fd": 3 } }
 | type AddFdCommand struct {
 | 	// The ID of the fd set to add the file descriptor to.
 | 	FdsetId *int64 `json:"fdset-id,omitempty"`
 | 	// A free-form string that can be used to describe the fd.
 | 	Opaque *string `json:"opaque,omitempty"`
 | }

Signed-off-by: Victor Toso <victortoso@redhat.com>
---
 scripts/qapi/golang/golang.py | 52 +++++++++++++++++++++++++++++++++--
 1 file changed, 50 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/scripts/qapi/golang/golang.py b/scripts/qapi/golang/golang.py
index b9a2c47137..a14970fb1f 100644
--- a/scripts/qapi/golang/golang.py
+++ b/scripts/qapi/golang/golang.py
@@ -316,7 +316,7 @@  def qapi_to_go_type_name(name: str, meta: Optional[str] = None) -> str:
     name += "".join(word.title() for word in words[1:])
 
     # Handle specific meta suffix
-    types = ["event"]
+    types = ["event", "command"]
     if meta in types:
         name = name[:-3] if name.endswith("Arg") else name
         name += meta.title().replace(" ", "")
@@ -1009,6 +1009,15 @@  def generate_template_alternate(
     return "\n" + content
 
 
+def generate_template_command(commands: dict[str, Tuple[str, str]]) -> str:
+    content = ""
+    for name in sorted(commands):
+        type_name, gocode = commands[name]
+        content += gocode
+
+    return content
+
+
 def generate_template_event(events: dict[str, Tuple[str, str]]) -> (str, str):
     content = ""
     methods = ""
@@ -1069,6 +1078,7 @@  def __init__(self, _: str):
         # Map each qapi type to the necessary Go imports
         types = {
             "alternate": ["encoding/json", "errors", "fmt"],
+            "command": [],
             "enum": [],
             "event": [],
             "struct": ["encoding/json"],
@@ -1080,6 +1090,7 @@  def __init__(self, _: str):
 
         self.schema: QAPISchema
         self.events: dict[str, Tuple[str, str]] = {}
+        self.commands: dict[str, Tuple[str, str]] = {}
         self.golang_package_name = "qapi"
         self.duplicate = list(gofiles)
         self.enums: dict[str, str] = {}
@@ -1140,6 +1151,8 @@  def visit_end(self) -> None:
         self.types["event"] += evtype
         self.interfaces["event"] += eviface
 
+        self.types["command"] += generate_template_command(self.commands)
+
     def visit_object_type(
         self,
         name: str,
@@ -1286,7 +1299,42 @@  def visit_command(
         allow_preconfig: bool,
         coroutine: bool,
     ) -> None:
-        pass
+        assert name == info.defn_name
+        assert name not in self.commands
+
+        type_name = qapi_to_go_type_name(name, info.defn_meta)
+
+        doc = self.docmap.get(name, None)
+        type_doc, _ = qapi_to_golang_struct_docs(doc)
+
+        content = ""
+        if boxed or not arg_type or not qapi_name_is_object(arg_type.name):
+            args: List[dict[str:str]] = []
+            if arg_type:
+                args.append(
+                    {
+                        "name": f"{arg_type.name}",
+                    }
+                )
+            content += string_to_code(
+                generate_struct_type(type_name, type_doc=type_doc, args=args)
+            )
+        else:
+            assert isinstance(arg_type, QAPISchemaObjectType)
+            content += string_to_code(
+                qapi_to_golang_struct(
+                    self,
+                    name,
+                    arg_type.info,
+                    arg_type.ifcond,
+                    arg_type.features,
+                    arg_type.base,
+                    arg_type.members,
+                    arg_type.branches,
+                )
+            )
+
+        self.commands[name] = (type_name, content)
 
     def visit_event(
         self,