diff --git a/ros2model/api/model_generator/message_generator.py b/ros2model/api/model_generator/message_generator.py index 9163fb5..7b704ab 100644 --- a/ros2model/api/model_generator/message_generator.py +++ b/ros2model/api/model_generator/message_generator.py @@ -25,7 +25,7 @@ from ament_index_python import get_package_share_directory Template_Folder_ROS = Path(get_package_share_directory("ros2model") + "/templates") - Template_ROS = Path(Template_Folder_ROS / "message.ros2.j2") + Template_ROS = Path(Template_Folder_ROS / "message.ros.j2") except ImportError: Template_ROS = None @@ -35,7 +35,7 @@ def __init__(self, template_path=None) -> None: if template_path != None: self.template_path = Path(template_path).resolve() elif Template_ROS != None and Template_ROS.is_file(): - self.template_path = Template + self.template_path = Template_ROS elif Template.is_file(): self.template_path = Template else: diff --git a/ros2model/api/runtime_parser/rossystem_runtime_parser.py b/ros2model/api/runtime_parser/rossystem_runtime_parser.py index a3e5497..9100323 100644 --- a/ros2model/api/runtime_parser/rossystem_runtime_parser.py +++ b/ros2model/api/runtime_parser/rossystem_runtime_parser.py @@ -1,3 +1,6 @@ +from typing import List, Optional + +from pydantic import Field from ros2model.api.runtime_parser.rosmodel_runtime_parser import ( save_to_file, get_node_graph_names, @@ -5,10 +8,20 @@ ) import ros2model.core.metamodels.metamodel_ros as ROSModel from pathlib import Path +from ros2model.core.utils import find_process_by_node_name + + +class RuntimeGraphName(ROSModel.GraphName): + artifact_name: Optional[str] = None + pkg_name: Optional[str] = None + + +class RuntimeNode(ROSModel.Node): + name: RuntimeGraphName class RuntimeRossystem(ROSModel.Rossystem): - pass + nodes: List[RuntimeNode] = Field(default_factory=list) def __init__(self, *, system: ROSModel.Rossystem, **data): super().__init__(name=system.name, **data) @@ -16,13 +29,19 @@ def __init__(self, *, system: ROSModel.Rossystem, **data): def get_nodes(self): nodes = get_node_graph_names() for n in nodes: - print("node name: ", n.namespace, n.name, n.full_name) + pkg, artifact = find_process_by_node_name(n.name, n.namespace) + parsed_node = parse( ROSModel.GraphName( - name=n.name, namespace=n.namespace, full_name=n.full_name + name=n.name, + namespace=n.namespace, + full_name=n.full_name, ) ) - self.nodes.append(parsed_node) + runtime_node = RuntimeNode(**parsed_node.model_dump()) + runtime_node.name.artifact_name = artifact + runtime_node.name.pkg_name = pkg + self.nodes.append(runtime_node) def name_system_file(grapg_name: ROSModel.GraphName): diff --git a/ros2model/verb/runtime_system.py b/ros2model/verb/runtime_system.py index a8251f5..bb75cdc 100644 --- a/ros2model/verb/runtime_system.py +++ b/ros2model/verb/runtime_system.py @@ -6,6 +6,7 @@ from ros2model.api.model_generator.system_generator import SystemGenerator import ros2model.api.runtime_parser.rossystem_runtime_parser as RuntimeParser import ros2model.core.metamodels.metamodel_ros as ROSModel +from ament_index_python import get_package_share_directory class RuntimeVerb(VerbExtension): @@ -36,13 +37,24 @@ def add_arguments(self, parser, cli_name): help="Consider hidden topics, services or actions.", ) + def get_template(self): + template_folder_ros = Path( + get_package_share_directory("ros2model") + "/templates" + ) + return ( + Path(template_folder_ros / "runtime_rossystem.rossystem.j2") + .absolute() + .as_posix() + ) + def main(self, *, args): output_file = Path(args.output_file) system_name = output_file.name if output_file.is_absolute() != True: output_file = output_file.resolve() - generator = SystemGenerator() + print(self.get_template()) + generator = SystemGenerator(template_path=self.get_template()) system = RuntimeParser.RuntimeRossystem( system=ROSModel.Rossystem(name=system_name) diff --git a/setup.py b/setup.py index 5541e5f..5ccc64e 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,12 @@ ("share/ament_index/resource_index/packages", ["resource/" + package_name]), ( "share/" + package_name + "/templates", - ["templates/component.ros2.j2", "templates/rossystem.rossystem.j2"], + [ + "templates/component.ros2.j2", + "templates/rossystem.rossystem.j2", + "templates/runtime_rossystem.rossystem.j2", + "templates/message.ros.j2", + ], ), ], install_requires=[ diff --git a/templates/rossystem.rossystem.j2 b/templates/rossystem.rossystem.j2 index ff3c5da..b82dc37 100644 --- a/templates/rossystem.rossystem.j2 +++ b/templates/rossystem.rossystem.j2 @@ -2,8 +2,8 @@ nodes: {% for node in model.nodes %} "{{ node.name.full_name }}": - from: "TODO.{{ node.name.full_name }}" - {% if node.publisher | length > 0 or node.subscriber | length > 0 or node.actionserver | length > 0 or node.actionclient | length > 0 or node.serviceserver | length > 0 or node.serviceclient | length > 0%} + from: "{{ node.name.full_name }}" + {% if node.publisher | length > 0 or node.subscriber | length > 0 or node.actionserver | length > 0 or node.actionclient | length > 0 or node.serviceserver | length > 0 or node.serviceclient | length > 0 %} interfaces: {% for interface in node.publisher %} - "{{ interface.name }}": pub-> "TODO::{{ interface.name }}" diff --git a/templates/runtime_rossystem.rossystem.j2 b/templates/runtime_rossystem.rossystem.j2 new file mode 100644 index 0000000..e08ea33 --- /dev/null +++ b/templates/runtime_rossystem.rossystem.j2 @@ -0,0 +1,40 @@ +{{ model.name }}: + nodes: + {% for node in model.nodes %} + "{{ node.name.full_name }}": + from: "{{ node.name.pkg_name }}.{{ node.name.full_name }}" + {% if node.publisher | length > 0 or node.subscriber | length > 0 or node.actionserver | length > 0 or node.actionclient | length > 0 or node.serviceserver | length > 0 or node.serviceclient | length > 0 %} + interfaces: + {% for interface in node.publisher %} + - "{{ interface.name }}": pub-> "TODO::{{ interface.name }}" + {% endfor %} + {% for interface in node.subscriber %} + - "{{ interface.name }}": sub-> "TODO::{{ interface.name }}" + {% endfor %} + {% for interface in node.actionserver %} + - "{{ interface.name }}": as-> "TODO::{{ interface.name }}" + {% endfor %} + {% for interface in node.actionclient %} + - "{{ interface.name }}": ac-> "TODO::{{ interface.name }}" + {% endfor %} + {% for interface in node.serviceserver %} + - "{{ interface.name }}": ss-> "{{ node.name.artifact_name }}::{{ interface.name }}" + {% endfor %} + {% for interface in node.serviceclient %} + - "{{ interface.name }}": sc-> "TODO::{{ interface.name }}" + {% endfor %} + {% endif %} + {% if node.parameter | length > 0 %} + parameters: + {% for parameter in node.parameter %} + - {{ parameter.name }}: "TODO::{{ parameter.name }}" + {% if parameter.type == "String" %} + value: "{{ parameter.value }}" + {% elif parameter.type == "Boolean" %} + value: {{ parameter.value | lower }} + {% else %} + value: {{ parameter.value }} + {% endif %} + {% endfor %} + {% endif %} + {% endfor %} diff --git a/test/outputs/test_system.rossystem b/test/outputs/test_system.rossystem index 4ad2bf9..f6ab271 100644 --- a/test/outputs/test_system.rossystem +++ b/test/outputs/test_system.rossystem @@ -1,7 +1,7 @@ test_system: nodes: "/map_server": - from: "TODO./map_server" + from: "/map_server" interfaces: - "map_metadata": pub-> "TODO::map_metadata" - "map": pub-> "TODO::map" diff --git a/test/unittest/test_generate_component.py b/test/unittest/test_generate_component.py index 76177da..a2d7790 100644 --- a/test/unittest/test_generate_component.py +++ b/test/unittest/test_generate_component.py @@ -43,10 +43,6 @@ ], ) -from devtools import pprint - -# pprint(test_model) - test_dir = "test" output_folder = Path(__file__).parent.parent / "outputs" diff --git a/test/unittest/test_generate_system.py b/test/unittest/test_generate_system.py index 1aec531..5013bd7 100644 --- a/test/unittest/test_generate_system.py +++ b/test/unittest/test_generate_system.py @@ -43,7 +43,7 @@ test_system: nodes: "/map_server": - from: "TODO./map_server" + from: "/map_server" interfaces: - "map_metadata": pub-> "TODO::map_metadata" - "map": pub-> "TODO::map" @@ -58,7 +58,7 @@ """ -class test_message_generator(unittest.TestCase): +class test_system_generator(unittest.TestCase): def setUp(self) -> None: self.generator = SystemGenerator() self.test_dir = Path(test_dir) @@ -72,6 +72,7 @@ def test_generate_pkg(self): ) with open(Path(self.output_dir / f"{test_model.name}.rossystem"), "r") as file: data = file.read() + self.assertEqual(expect_result.strip(), data.strip())