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

Move rosidl_cmake Python module to a new package rosidl_pycommon #696

Merged
merged 3 commits into from
Aug 10, 2022
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
4 changes: 2 additions & 2 deletions rosidl_cmake/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
<buildtool_export_depend>ament_cmake</buildtool_export_depend>
<buildtool_export_depend>python3-empy</buildtool_export_depend>

<exec_depend>rosidl_adapter</exec_depend>
<exec_depend>rosidl_parser</exec_depend>
<!-- Forwarding Python module -->
<exec_depend>rosidl_pycommon</exec_depend>

<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
Expand Down
193 changes: 6 additions & 187 deletions rosidl_cmake/rosidl_cmake/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,192 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from io import StringIO
import json
import os
import pathlib
import re
import sys
import warnings

import em
from rosidl_parser.definition import IdlLocator
from rosidl_parser.parser import parse_idl_file
from rosidl_pycommon import * # noqa: F401, F403


def convert_camel_case_to_lower_case_underscore(value):
# insert an underscore before any upper case letter
# which is followed by a lower case letter
value = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', value)
# insert an underscore before any upper case letter
# which is preseded by a lower case letter or number
value = re.sub('([a-z0-9])([A-Z])', r'\1_\2', value)
return value.lower()


def read_generator_arguments(input_file):
with open(input_file, mode='r', encoding='utf-8') as h:
return json.load(h)


def get_newest_modification_time(target_dependencies):
newest_timestamp = None
for dep in target_dependencies:
ts = os.path.getmtime(dep)
if newest_timestamp is None or ts > newest_timestamp:
newest_timestamp = ts
return newest_timestamp


def generate_files(
generator_arguments_file, mapping, additional_context=None,
keep_case=False, post_process_callback=None
):
args = read_generator_arguments(generator_arguments_file)

template_basepath = pathlib.Path(args['template_dir'])
for template_filename in mapping.keys():
assert (template_basepath / template_filename).exists(), \
'Could not find template: ' + template_filename

latest_target_timestamp = get_newest_modification_time(args['target_dependencies'])
generated_files = []

for idl_tuple in args.get('idl_tuples', []):
idl_parts = idl_tuple.rsplit(':', 1)
assert len(idl_parts) == 2
locator = IdlLocator(*idl_parts)
idl_rel_path = pathlib.Path(idl_parts[1])
idl_stem = idl_rel_path.stem
if not keep_case:
idl_stem = convert_camel_case_to_lower_case_underscore(idl_stem)
try:
idl_file = parse_idl_file(locator)
for template_file, generated_filename in mapping.items():
generated_file = os.path.join(
args['output_dir'], str(idl_rel_path.parent),
generated_filename % idl_stem)
generated_files.append(generated_file)
data = {
'package_name': args['package_name'],
'interface_path': idl_rel_path,
'content': idl_file.content,
}
if additional_context is not None:
data.update(additional_context)
expand_template(
os.path.basename(template_file), data,
generated_file, minimum_timestamp=latest_target_timestamp,
template_basepath=template_basepath,
post_process_callback=post_process_callback)
except Exception as e:
print(
'Error processing idl file: ' +
str(locator.get_absolute_path()), file=sys.stderr)
raise(e)

return generated_files


template_prefix_path = []


def get_template_path(template_name):
global template_prefix_path
for basepath in template_prefix_path:
template_path = basepath / template_name
if template_path.exists():
return template_path
raise RuntimeError(f"Failed to find template '{template_name}'")


interpreter = None


def expand_template(
template_name, data, output_file, minimum_timestamp=None,
template_basepath=None, post_process_callback=None
):
# in the legacy API the first argument was the path to the template
if template_basepath is None:
template_name = pathlib.Path(template_name)
template_basepath = template_name.parent
template_name = template_name.name

global interpreter
output = StringIO()
interpreter = em.Interpreter(
output=output,
options={
em.BUFFERED_OPT: True,
em.RAW_OPT: True,
},
)

global template_prefix_path
template_prefix_path.append(template_basepath)
template_path = get_template_path(template_name)

# create copy before manipulating
data = dict(data)
_add_helper_functions(data)

try:
with template_path.open('r') as h:
template_content = h.read()
interpreter.invoke(
'beforeFile', name=template_name, file=h, locals=data)
interpreter.string(template_content, template_path, locals=data)
interpreter.invoke('afterFile')
except Exception as e: # noqa: F841
if os.path.exists(output_file):
os.remove(output_file)
print(f"{e.__class__.__name__} when expanding '{template_name}' into "
f"'{output_file}': {e}", file=sys.stderr)
raise
finally:
template_prefix_path.pop()

content = output.getvalue()
interpreter.shutdown()

if post_process_callback:
content = post_process_callback(content)

# only overwrite file if necessary
# which is either when the timestamp is too old or when the content is different
if os.path.exists(output_file):
timestamp = os.path.getmtime(output_file)
if minimum_timestamp is None or timestamp > minimum_timestamp:
with open(output_file, 'r', encoding='utf-8') as h:
if h.read() == content:
return
else:
# create folder if necessary
try:
os.makedirs(os.path.dirname(output_file))
except FileExistsError:
pass

with open(output_file, 'w', encoding='utf-8') as h:
h.write(content)


def _add_helper_functions(data):
data['TEMPLATE'] = _expand_template


def _expand_template(template_name, **kwargs):
global interpreter
template_path = get_template_path(template_name)
_add_helper_functions(kwargs)
with template_path.open('r') as h:
interpreter.invoke(
'beforeInclude', name=str(template_path), file=h, locals=kwargs)
content = h.read()
try:
interpreter.string(content, str(template_path), kwargs)
except Exception as e: # noqa: F841
print(f"{e.__class__.__name__} in template '{template_path}': {e}",
file=sys.stderr)
raise
interpreter.invoke('afterInclude')
warnings.warn(
"The 'rosidl_cmake' Python module is deprecated. Use 'rosidl_pycommon' instead.",
UserWarning
)
1 change: 0 additions & 1 deletion rosidl_generator_c/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ endif()
find_package(ament_cmake_python REQUIRED)
find_package(ament_cmake_ros REQUIRED)

ament_export_dependencies(rosidl_cmake)
ament_export_dependencies(rosidl_typesupport_interface)
ament_index_register_resource("rosidl_generator_packages")

Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_c/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

<buildtool_export_depend>ament_cmake_core</buildtool_export_depend>
<buildtool_export_depend>python3</buildtool_export_depend>
<buildtool_export_depend>rosidl_cmake</buildtool_export_depend>
<buildtool_export_depend>rosidl_pycommon</buildtool_export_depend>

<build_export_depend>rosidl_typesupport_interface</build_export_depend>
<build_export_depend>rcutils</build_export_depend>
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_c/resource/idl.h.em
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
@#######################################################################
@
@{
from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
include_parts = [package_name] + list(interface_path.parents[0].parts) + \
[convert_camel_case_to_lower_case_underscore(interface_path.stem)]
include_parts_detail = [package_name] + list(interface_path.parents[0].parts) + [
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_c/resource/idl__functions.c.em
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@# - content (IdlContent, list of elements, e.g. Messages or Services)
@#######################################################################
@{
from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
include_parts = [package_name] + list(interface_path.parents[0].parts) + [
'detail', convert_camel_case_to_lower_case_underscore(interface_path.stem)]
include_base = '/'.join(include_parts)
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_c/resource/idl__functions.h.em
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@# - content (IdlContent, list of elements, e.g. Messages or Services)
@#######################################################################
@{
from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
include_parts = [package_name] + list(interface_path.parents[0].parts) + [
'detail', convert_camel_case_to_lower_case_underscore(interface_path.stem)]
header_guard_variable = '__'.join([x.upper() for x in include_parts]) + \
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_c/resource/idl__struct.h.em
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@# - content (IdlContent, list of elements, e.g. Messages or Services)
@#######################################################################
@{
from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
include_parts = [package_name] + list(interface_path.parents[0].parts) + [
'detail', convert_camel_case_to_lower_case_underscore(interface_path.stem)]
header_guard_variable = '__'.join([x.upper() for x in include_parts]) + \
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_c/resource/idl__type_support.h.em
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@# - content (IdlContent, list of elements, e.g. Messages or Services)
@#######################################################################
@{
from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
include_parts = [package_name] + list(interface_path.parents[0].parts) + [
'detail', convert_camel_case_to_lower_case_underscore(interface_path.stem)]
header_guard_variable = '__'.join([x.upper() for x in include_parts]) + \
Expand Down
4 changes: 2 additions & 2 deletions rosidl_generator_c/rosidl_generator_c/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_cmake import generate_files
from rosidl_parser.definition import AbstractGenericString
from rosidl_parser.definition import AbstractSequence
from rosidl_parser.definition import AbstractString
Expand All @@ -24,6 +22,8 @@
from rosidl_parser.definition import CHARACTER_TYPES
from rosidl_parser.definition import NamespacedType
from rosidl_parser.definition import OCTET_TYPE
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
from rosidl_pycommon import generate_files


def generate_c(generator_arguments_file):
Expand Down
2 changes: 0 additions & 2 deletions rosidl_generator_cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ project(rosidl_generator_cpp)
find_package(ament_cmake REQUIRED)
find_package(ament_cmake_python REQUIRED)

ament_export_dependencies(rosidl_cmake)

ament_index_register_resource("rosidl_generator_packages")

ament_python_install_package(${PROJECT_NAME})
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_cpp/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<buildtool_export_depend>ament_cmake_core</buildtool_export_depend>
<buildtool_export_depend>python3</buildtool_export_depend>
<buildtool_export_depend>rosidl_cmake</buildtool_export_depend>
<buildtool_export_depend>rosidl_pycommon</buildtool_export_depend>

<!-- This is needed for the rosidl_message_type_support_t struct and visibility macros -->
<build_export_depend>rosidl_generator_c</build_export_depend>
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_cpp/resource/idl.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@#######################################################################
@
@{
from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
include_parts = [package_name] + list(interface_path.parents[0].parts) + \
[convert_camel_case_to_lower_case_underscore(interface_path.stem)]
include_parts_detail = [package_name] + list(interface_path.parents[0].parts) + [
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_cpp/resource/idl__builder.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@# - content (IdlContent, list of elements, e.g. Messages or Services)
@#######################################################################
@{
from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
include_parts = [package_name] + list(interface_path.parents[0].parts) + [
'detail', convert_camel_case_to_lower_case_underscore(interface_path.stem)]
include_base = '/'.join(include_parts)
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_cpp/resource/idl__struct.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@# - content (IdlContent, list of elements, e.g. Messages or Services)
@#######################################################################
@{
from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
include_parts = [package_name] + list(interface_path.parents[0].parts) + [
'detail', convert_camel_case_to_lower_case_underscore(interface_path.stem)]
header_guard_variable = '__'.join([x.upper() for x in include_parts]) + \
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_cpp/resource/idl__traits.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
@# - content (IdlContent, list of elements, e.g. Messages or Services)
@#######################################################################
@{
from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
include_parts = [package_name] + list(interface_path.parents[0].parts) + [
'detail', convert_camel_case_to_lower_case_underscore(interface_path.stem)]
include_base = '/'.join(include_parts)
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_cpp/resource/msg__struct.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ msvc_common_macros = ('DELETE', 'ERROR', 'NO_ERROR')
@# Collect necessary include directives for all members
@{
from collections import OrderedDict
from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
includes = OrderedDict()
for member in message.structure.members:
type_ = member.type
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_cpp/resource/msg__traits.hpp.em
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ message_fully_qualified_name = '/'.join(message.structure.namespaced_type.namesp
@# Collect necessary include directives for all members
@{
from collections import OrderedDict
from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_pycommon import convert_camel_case_to_lower_case_underscore
includes = OrderedDict()
for member in message.structure.members:
type_ = member.type
Expand Down
2 changes: 1 addition & 1 deletion rosidl_generator_cpp/rosidl_generator_cpp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

from ast import literal_eval

from rosidl_cmake import generate_files
from rosidl_parser.definition import AbstractGenericString
from rosidl_parser.definition import AbstractNestedType
from rosidl_parser.definition import AbstractSequence
Expand All @@ -26,6 +25,7 @@
from rosidl_parser.definition import FLOATING_POINT_TYPES
from rosidl_parser.definition import NamespacedType
from rosidl_parser.definition import UnboundedSequence
from rosidl_pycommon import generate_files


def generate_cpp(generator_arguments_file):
Expand Down
Loading