diff --git a/rosidl_adapter/CMakeLists.txt b/rosidl_adapter/CMakeLists.txt
index 643682935..b14b5518b 100644
--- a/rosidl_adapter/CMakeLists.txt
+++ b/rosidl_adapter/CMakeLists.txt
@@ -8,8 +8,10 @@ find_package(ament_cmake_python REQUIRED)
ament_python_install_package(${PROJECT_NAME})
if(BUILD_TESTING)
+ find_package(ament_cmake_pytest REQUIRED)
find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()
+ ament_add_pytest_test(pytest test)
endif()
ament_package(
@@ -25,8 +27,3 @@ install(PROGRAMS
scripts/msg2idl.py
scripts/srv2idl.py
DESTINATION lib/${PROJECT_NAME})
-
-if(BUILD_TESTING)
- find_package(ament_cmake_pytest REQUIRED)
- ament_add_pytest_test(pytest test)
-endif()
diff --git a/rosidl_adapter/package.xml b/rosidl_adapter/package.xml
index c546c3208..9f047bc0b 100644
--- a/rosidl_adapter/package.xml
+++ b/rosidl_adapter/package.xml
@@ -14,6 +14,7 @@
ament_cmake
python3-empy
+ rosidl_cli
ament_cmake_pytest
ament_lint_common
diff --git a/rosidl_adapter/rosidl_adapter/action/__init__.py b/rosidl_adapter/rosidl_adapter/action/__init__.py
index d4b128079..6e8719b6c 100644
--- a/rosidl_adapter/rosidl_adapter/action/__init__.py
+++ b/rosidl_adapter/rosidl_adapter/action/__init__.py
@@ -32,7 +32,7 @@ def convert_action_to_idl(package_dir, package_name, input_file, output_dir):
print(f'Writing output file: {abs_output_file}')
data = {
'pkg_name': package_name,
- 'relative_input_file': input_file,
+ 'relative_input_file': input_file.as_posix(),
'action': action,
}
diff --git a/rosidl_adapter/rosidl_adapter/cli.py b/rosidl_adapter/rosidl_adapter/cli.py
index dad3f0b39..f1f5bb5eb 100644
--- a/rosidl_adapter/rosidl_adapter/cli.py
+++ b/rosidl_adapter/rosidl_adapter/cli.py
@@ -19,6 +19,13 @@
from catkin_pkg.package import package_exists_at
from catkin_pkg.package import parse_package
+from rosidl_adapter.action import convert_action_to_idl
+from rosidl_adapter.msg import convert_msg_to_idl
+from rosidl_adapter.srv import convert_srv_to_idl
+
+from rosidl_cli.command.helpers import interface_path_as_tuple
+from rosidl_cli.command.translate.extensions import TranslateCommandExtension
+
def convert_files_to_idl(extension, conversion_function, argv=sys.argv[1:]):
parser = argparse.ArgumentParser(
@@ -48,3 +55,54 @@ def convert_files_to_idl(extension, conversion_function, argv=sys.argv[1:]):
package_dir, pkg.name,
interface_file.absolute().relative_to(package_dir),
interface_file.parent)
+
+
+class TranslateToIDL(TranslateCommandExtension):
+
+ output_format = 'idl'
+
+ def translate(
+ self,
+ package_name,
+ interface_files,
+ include_paths,
+ output_path
+ ):
+ translated_interface_files = []
+ for interface_file in interface_files:
+ prefix, interface_file = interface_path_as_tuple(interface_file)
+ output_dir = output_path / interface_file.parent
+ translated_interface_file = self.conversion_function(
+ prefix, package_name, interface_file, output_dir)
+ translated_interface_file = \
+ translated_interface_file.relative_to(output_path)
+ translated_interface_files.append(
+ f'{output_path}:{translated_interface_file.as_posix()}'
+ )
+ return translated_interface_files
+
+
+class TranslateMsgToIDL(TranslateToIDL):
+
+ input_format = 'msg'
+
+ @property
+ def conversion_function(self):
+ return convert_msg_to_idl
+
+
+class TranslateSrvToIDL(TranslateToIDL):
+
+ input_format = 'srv'
+
+ @property
+ def conversion_function(self):
+ return convert_srv_to_idl
+
+
+class TranslateActionToIDL(TranslateToIDL):
+ input_format = 'action'
+
+ @property
+ def conversion_function(self):
+ return convert_action_to_idl
diff --git a/rosidl_adapter/rosidl_adapter/msg/__init__.py b/rosidl_adapter/rosidl_adapter/msg/__init__.py
index 1cd056ada..322bd7277 100644
--- a/rosidl_adapter/rosidl_adapter/msg/__init__.py
+++ b/rosidl_adapter/rosidl_adapter/msg/__init__.py
@@ -32,7 +32,7 @@ def convert_msg_to_idl(package_dir, package_name, input_file, output_dir):
print(f'Writing output file: {abs_output_file}')
data = {
'pkg_name': package_name,
- 'relative_input_file': input_file,
+ 'relative_input_file': input_file.as_posix(),
'msg': msg,
}
diff --git a/rosidl_adapter/rosidl_adapter/srv/__init__.py b/rosidl_adapter/rosidl_adapter/srv/__init__.py
index 41ae4e053..c57b7013f 100644
--- a/rosidl_adapter/rosidl_adapter/srv/__init__.py
+++ b/rosidl_adapter/rosidl_adapter/srv/__init__.py
@@ -32,7 +32,7 @@ def convert_srv_to_idl(package_dir, package_name, input_file, output_dir):
print(f'Writing output file: {abs_output_file}')
data = {
'pkg_name': package_name,
- 'relative_input_file': input_file,
+ 'relative_input_file': input_file.as_posix(),
'srv': srv,
}
diff --git a/rosidl_adapter/setup.cfg b/rosidl_adapter/setup.cfg
new file mode 100644
index 000000000..bfb5cb4b2
--- /dev/null
+++ b/rosidl_adapter/setup.cfg
@@ -0,0 +1,5 @@
+[options.entry_points]
+rosidl_cli.command.translate.extensions =
+ msg2idl = rosidl_adapter.cli:TranslateMsgToIDL
+ srv2idl = rosidl_adapter.cli:TranslateSrvToIDL
+ action2idl = rosidl_adapter.cli:TranslateActionToIDL
diff --git a/rosidl_adapter/test/data/action/Test.action b/rosidl_adapter/test/data/action/Test.action
new file mode 100644
index 000000000..be9501b3a
--- /dev/null
+++ b/rosidl_adapter/test/data/action/Test.action
@@ -0,0 +1,21 @@
+# goal definition
+bool bool_value
+byte byte_value
+char char_value
+float32 float32_value
+float64 float64_value
+int8 int8_value
+uint8 uint8_value
+int16 int16_value
+uint16 uint16_value
+int32 int32_value
+uint32 uint32_value
+int64 int64_value
+uint64 uint64_value
+string string_value
+---
+# result definition
+bool ok
+---
+# feedback definition
+int32[] sequence
diff --git a/rosidl_adapter/test/data/action/Test.expected.idl b/rosidl_adapter/test/data/action/Test.expected.idl
new file mode 100644
index 000000000..bb5c4e698
--- /dev/null
+++ b/rosidl_adapter/test/data/action/Test.expected.idl
@@ -0,0 +1,50 @@
+// generated from rosidl_adapter/resource/action.idl.em
+// with input from test_msgs/action/Test.action
+// generated code does not contain a copyright notice
+
+
+module test_msgs {
+ module action {
+ @verbatim (language="comment", text=
+ " goal definition")
+ struct Test_Goal {
+ boolean bool_value;
+
+ octet byte_value;
+
+ uint8 char_value;
+
+ float float32_value;
+
+ double float64_value;
+
+ int8 int8_value;
+
+ uint8 uint8_value;
+
+ int16 int16_value;
+
+ uint16 uint16_value;
+
+ int32 int32_value;
+
+ uint32 uint32_value;
+
+ int64 int64_value;
+
+ uint64 uint64_value;
+
+ string string_value;
+ };
+ struct Test_Result {
+ @verbatim (language="comment", text=
+ " result definition")
+ boolean ok;
+ };
+ struct Test_Feedback {
+ @verbatim (language="comment", text=
+ " feedback definition")
+ sequence sequence;
+ };
+ };
+};
diff --git a/rosidl_adapter/test/data/msg/Test.expected.idl b/rosidl_adapter/test/data/msg/Test.expected.idl
new file mode 100644
index 000000000..71694d374
--- /dev/null
+++ b/rosidl_adapter/test/data/msg/Test.expected.idl
@@ -0,0 +1,36 @@
+// generated from rosidl_adapter/resource/msg.idl.em
+// with input from test_msgs/msg/Test.msg
+// generated code does not contain a copyright notice
+
+
+module test_msgs {
+ module msg {
+ struct Test {
+ boolean bool_value;
+
+ octet byte_value;
+
+ uint8 char_value;
+
+ float float32_value;
+
+ double float64_value;
+
+ int8 int8_value;
+
+ uint8 uint8_value;
+
+ int16 int16_value;
+
+ uint16 uint16_value;
+
+ int32 int32_value;
+
+ uint32 uint32_value;
+
+ int64 int64_value;
+
+ uint64 uint64_value;
+ };
+ };
+};
diff --git a/rosidl_adapter/test/data/msg/Test.msg b/rosidl_adapter/test/data/msg/Test.msg
new file mode 100644
index 000000000..eaf9b9ef3
--- /dev/null
+++ b/rosidl_adapter/test/data/msg/Test.msg
@@ -0,0 +1,13 @@
+bool bool_value
+byte byte_value
+char char_value
+float32 float32_value
+float64 float64_value
+int8 int8_value
+uint8 uint8_value
+int16 int16_value
+uint16 uint16_value
+int32 int32_value
+uint32 uint32_value
+int64 int64_value
+uint64 uint64_value
diff --git a/rosidl_adapter/test/data/srv/Test.expected.idl b/rosidl_adapter/test/data/srv/Test.expected.idl
new file mode 100644
index 000000000..dbb4dee01
--- /dev/null
+++ b/rosidl_adapter/test/data/srv/Test.expected.idl
@@ -0,0 +1,41 @@
+// generated from rosidl_adapter/resource/srv.idl.em
+// with input from test_msgs/srv/Test.srv
+// generated code does not contain a copyright notice
+
+
+module test_msgs {
+ module srv {
+ struct Test_Request {
+ boolean bool_value;
+
+ octet byte_value;
+
+ uint8 char_value;
+
+ float float32_value;
+
+ double float64_value;
+
+ int8 int8_value;
+
+ uint8 uint8_value;
+
+ int16 int16_value;
+
+ uint16 uint16_value;
+
+ int32 int32_value;
+
+ uint32 uint32_value;
+
+ int64 int64_value;
+
+ uint64 uint64_value;
+
+ string string_value;
+ };
+ struct Test_Response {
+ boolean ok;
+ };
+ };
+};
diff --git a/rosidl_adapter/test/data/srv/Test.srv b/rosidl_adapter/test/data/srv/Test.srv
new file mode 100644
index 000000000..934567d7f
--- /dev/null
+++ b/rosidl_adapter/test/data/srv/Test.srv
@@ -0,0 +1,16 @@
+bool bool_value
+byte byte_value
+char char_value
+float32 float32_value
+float64 float64_value
+int8 int8_value
+uint8 uint8_value
+int16 int16_value
+uint16 uint16_value
+int32 int32_value
+uint32 uint32_value
+int64 int64_value
+uint64 uint64_value
+string string_value
+---
+bool ok
diff --git a/rosidl_adapter/test/test_cli_extensions.py b/rosidl_adapter/test/test_cli_extensions.py
new file mode 100644
index 000000000..218d7bb41
--- /dev/null
+++ b/rosidl_adapter/test/test_cli_extensions.py
@@ -0,0 +1,85 @@
+# Copyright 2021 Open Source Robotics Foundation, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import filecmp
+import pathlib
+
+from rosidl_cli.command.translate.api import translate
+
+
+DATA_PATH = pathlib.Path(__file__).parent / 'data'
+
+
+def test_translation_extensions(tmp_path, capsys):
+ # NOTE(hidmic): pytest and empy do not play along,
+ # the latter expects some proxy will stay in sys.stdout
+ # and the former insists in overwriting it
+
+ with capsys.disabled(): # so do everything in one run
+ # Test .msg to .idl translation
+ idl_files = translate(
+ package_name='test_msgs',
+ interface_files=[
+ f'{DATA_PATH}:msg/Test.msg'],
+ output_path=tmp_path,
+ output_format='idl',
+ translators=['msg2idl']
+ )
+
+ assert len(idl_files) == 1
+ idl_file = idl_files[0]
+ assert idl_file == f'{tmp_path}:msg/Test.idl'
+ assert filecmp.cmp(
+ tmp_path / 'msg' / 'Test.idl',
+ DATA_PATH / 'msg' / 'Test.expected.idl',
+ shallow=False
+ )
+
+ # Test .srv to .idl translation
+ idl_files = translate(
+ package_name='test_msgs',
+ interface_files=[
+ f'{DATA_PATH}:srv/Test.srv'],
+ output_path=tmp_path,
+ output_format='idl',
+ translators=['srv2idl']
+ )
+
+ assert len(idl_files) == 1
+ idl_file = idl_files[0]
+ assert idl_file == f'{tmp_path}:srv/Test.idl'
+ assert filecmp.cmp(
+ tmp_path / 'srv' / 'Test.idl',
+ DATA_PATH / 'srv' / 'Test.expected.idl',
+ shallow=False
+ )
+
+ # Test .action to .idl translation
+ idl_files = translate(
+ package_name='test_msgs',
+ interface_files=[
+ f'{DATA_PATH}:action/Test.action'],
+ output_path=tmp_path,
+ output_format='idl',
+ translators=['action2idl']
+ )
+
+ assert len(idl_files) == 1
+ idl_file = idl_files[0]
+ assert idl_file == f'{tmp_path}:action/Test.idl'
+ assert filecmp.cmp(
+ tmp_path / 'action' / 'Test.idl',
+ DATA_PATH / 'action' / 'Test.expected.idl',
+ shallow=False
+ )