diff --git a/ros2pkg/ros2pkg/api/create.py b/ros2pkg/ros2pkg/api/create.py index 1bbecf8e2..8126a6285 100644 --- a/ros2pkg/ros2pkg/api/create.py +++ b/ros2pkg/ros2pkg/api/create.py @@ -33,22 +33,22 @@ def _expand_template(template_file, data, output_file): output = StringIO() if em_has_configuration: config = Configuration( - defaultStdout=output, - deleteOnError=True, - rawErrors=True, - useProxy=True) + defaultStdout=output, + deleteOnError=True, + rawErrors=True, + useProxy=True) interpreter = em.Interpreter( - config=config, - dispatcher=False, - globals=data) + config=config, + dispatcher=False, + globals=data) else: interpreter = em.Interpreter( - output=output, - options={ - em.BUFFERED_OPT: True, - em.RAW_OPT: True, - }, - globals=data) + output=output, + options={ + em.BUFFERED_OPT: True, + em.RAW_OPT: True, + }, + globals=data) with open(template_file, 'r') as h: try: @@ -84,8 +84,8 @@ def _create_folder(folder_name, base_directory, exist_ok=True): def _create_template_file( - template_subdir, template_file_name, output_directory, output_file_name, template_config -): + template_subdir, template_file_name, output_directory, output_file_name, template_config + ): full_package = 'ros2pkg.resource.' + template_subdir with importlib_resources.path(full_package, template_file_name) as path: template_path = str(path) @@ -102,23 +102,23 @@ def create_package_environment(package, destination_directory): package_directory = _create_folder(package.name, destination_directory) package_xml_config = { - 'package_format': package.package_format, - 'package_name': package.name, - 'package_description': package.description, - 'maintainer_email': package.maintainers[0].email, - 'maintainer_name': package.maintainers[0].name, - 'package_license': package.licenses[0], - 'buildtool_dependencies': package.buildtool_depends, - 'dependencies': package.build_depends, - 'test_dependencies': package.test_depends, - 'exports': package.exports, - } + 'package_format': package.package_format, + 'package_name': package.name, + 'package_description': package.description, + 'maintainer_email': package.maintainers[0].email, + 'maintainer_name': package.maintainers[0].name, + 'package_license': package.licenses[0], + 'buildtool_dependencies': package.buildtool_depends, + 'dependencies': package.build_depends, + 'test_dependencies': package.test_depends, + 'exports': package.exports, + } _create_template_file( - 'package_environment', - 'package.xml.em', - package_directory, - 'package.xml', - package_xml_config) + 'package_environment', + 'package.xml.em', + package_directory, + 'package.xml', + package_xml_config) source_directory = None include_directory = None @@ -126,6 +126,9 @@ def create_package_environment(package, destination_directory): print('creating source and include folder') source_directory = _create_folder('src', package_directory) include_directory = _create_folder(package.name, package_directory + os.sep + 'include') + if package.get_build_type() == 'ament_cargo': + print('creating source folder') + source_directory = _create_folder('src', package_directory) if package.get_build_type() == 'ament_python': print('creating source folder') source_directory = _create_folder(package.name, package_directory) @@ -135,14 +138,14 @@ def create_package_environment(package, destination_directory): def populate_ament_python(package, package_directory, source_directory, python_node_name): setup_py_config = { - 'project_name': package.name, - 'maintainer_email': package.maintainers[0].email, - 'maintainer_name': package.maintainers[0].name, - 'package_license': package.licenses[0], - 'node_name': python_node_name, - 'test_dependencies': package.test_depends, - 'package_description': package.description - } + 'project_name': package.name, + 'maintainer_email': package.maintainers[0].email, + 'maintainer_name': package.maintainers[0].name, + 'package_license': package.licenses[0], + 'node_name': python_node_name, + 'test_dependencies': package.test_depends, + 'package_description': package.description + } _create_template_file('ament_python', 'setup.py.em', @@ -195,8 +198,8 @@ def populate_ament_python(package, package_directory, source_directory, python_n def populate_python_node(package, source_directory, python_node_name): main_py_config = { - 'project_name': package.name - } + 'project_name': package.name + } _create_template_file('ament_python', 'main.py.em', source_directory, @@ -215,101 +218,134 @@ def populate_python_libary(package, source_directory, python_library_name): def populate_cmake(package, package_directory, cpp_node_name, cpp_library_name): cmakelists_config = { - 'project_name': package.name, - 'dependencies': [str(dep) for dep in package.build_depends], - 'cpp_node_name': cpp_node_name, - 'cpp_library_name': cpp_library_name, - } + 'project_name': package.name, + 'dependencies': [str(dep) for dep in package.build_depends], + 'cpp_node_name': cpp_node_name, + 'cpp_library_name': cpp_library_name, + } _create_template_file( - 'cmake', - 'CMakeLists.txt.em', - package_directory, - 'CMakeLists.txt', - cmakelists_config) + 'cmake', + 'CMakeLists.txt.em', + package_directory, + 'CMakeLists.txt', + cmakelists_config) cmake_config = { - 'project_name': package.name, - 'cpp_library_name': cpp_library_name, - 'cpp_node_name': cpp_node_name, - } + 'project_name': package.name, + 'cpp_library_name': cpp_library_name, + 'cpp_node_name': cpp_node_name, + } _create_template_file( - 'cmake', - 'Config.cmake.in.em', - package_directory, - package.name + 'Config.cmake.in', - cmake_config) + 'cmake', + 'Config.cmake.in.em', + package_directory, + package.name + 'Config.cmake.in', + cmake_config) version_config = { - 'project_name': package.name, - } + 'project_name': package.name, + } _create_template_file( - 'cmake', - 'ConfigVersion.cmake.in.em', - package_directory, - package.name + 'ConfigVersion.cmake.in', - version_config) + 'cmake', + 'ConfigVersion.cmake.in.em', + package_directory, + package.name + 'ConfigVersion.cmake.in', + version_config) def populate_ament_cmake(package, package_directory, cpp_node_name, cpp_library_name): cmakelists_config = { - 'project_name': package.name, - 'dependencies': [str(dep) for dep in package.build_depends], - 'cpp_node_name': cpp_node_name, - 'cpp_library_name': cpp_library_name, - } + 'project_name': package.name, + 'dependencies': [str(dep) for dep in package.build_depends], + 'cpp_node_name': cpp_node_name, + 'cpp_library_name': cpp_library_name, + } _create_template_file( - 'ament_cmake', - 'CMakeLists.txt.em', - package_directory, - 'CMakeLists.txt', - cmakelists_config) + 'ament_cmake', + 'CMakeLists.txt.em', + package_directory, + 'CMakeLists.txt', + cmakelists_config) def populate_cpp_node(package, source_directory, cpp_node_name): cpp_node_config = { - 'package_name': package.name, - } + 'package_name': package.name, + } _create_template_file( - 'cpp', - 'main.cpp.em', - source_directory, - cpp_node_name + '.cpp', - cpp_node_config) + 'cpp', + 'main.cpp.em', + source_directory, + cpp_node_name + '.cpp', + cpp_node_config) def populate_cpp_library(package, source_directory, include_directory, cpp_library_name): class_name = cpp_library_name.replace('_', ' ').title() class_name = ''.join(x for x in class_name if not x.isspace()) cpp_header_config = { - 'package_name': package.name, - 'library_name': cpp_library_name, - 'class_name': class_name, - } + 'package_name': package.name, + 'library_name': cpp_library_name, + 'class_name': class_name, + } _create_template_file( - 'cpp', - 'header.hpp.em', - include_directory, - cpp_library_name + '.hpp', - cpp_header_config) + 'cpp', + 'header.hpp.em', + include_directory, + cpp_library_name + '.hpp', + cpp_header_config) cpp_library_config = { - 'package_name': package.name, - 'library_name': cpp_library_name, - 'class_name': class_name - } + 'package_name': package.name, + 'library_name': cpp_library_name, + 'class_name': class_name + } _create_template_file( - 'cpp', - 'library.cpp.em', - source_directory, - cpp_library_name + '.cpp', - cpp_library_config) + 'cpp', + 'library.cpp.em', + source_directory, + cpp_library_name + '.cpp', + cpp_library_config) visibility_config = { - 'package_name': package.name.upper(), - } + 'package_name': package.name.upper(), + } + _create_template_file( + 'cpp', + 'visibility_control.h.em', + include_directory, + 'visibility_control.h', + visibility_config) + + +def populate_ament_cargo(package, package_directory, cargo_library_name): + cargo_toml_config = { + 'project_name': package.name, + 'dependencies': [str(dep) for dep in package.build_depends], + 'cargo_library_name': cargo_library_name, + 'maintainer_email': package.maintainers[0].email, + 'maintainer_name': package.maintainers[0].name, + } + _create_template_file( + 'ament_cargo', + 'Cargo.toml.em', + package_directory, + 'Cargo.toml', + cargo_toml_config) + + +def populate_rust_node(package, source_directory, node_name): + if node_name is None: + node_name = f'{package.name}_node' + + cargo_node_config = { + 'package_name': package.name, + 'node_name': node_name + } + _create_template_file( - 'cpp', - 'visibility_control.h.em', - include_directory, - 'visibility_control.h', - visibility_config) + 'rust', + 'main.rs.em', + source_directory, + 'main.rs', + cargo_node_config) diff --git a/ros2pkg/ros2pkg/resource/ament_cargo/Cargo.toml.em b/ros2pkg/ros2pkg/resource/ament_cargo/Cargo.toml.em new file mode 100644 index 000000000..ff1f6ce6c --- /dev/null +++ b/ros2pkg/ros2pkg/resource/ament_cargo/Cargo.toml.em @@ -0,0 +1,26 @@ +[package] +name = "@project_name" +version = "0.0.1" +authors = ["@maintainer_name <@maintainer_email>"] +edition = "2021" + +[[bin]] +name = "@project_name" +path = "src/main.rs" + +[dependencies] +anyhow = {version = "1", features = ["backtrace"]} +rosidl_runtime_rs = "0.4" + +# This specific version is compatible with Rust 1.75 +backtrace = "=0.3.74" + +@[if dependencies]@ +@[ for dep in dependencies]@ +@dep = "*" +@[ end for]@ +@[else]@ +# uncomment the following section in order to fill in +# further dependencies manually. +# = "*" +@[end if]@ diff --git a/ros2pkg/ros2pkg/resource/ament_cargo/__init__.py b/ros2pkg/ros2pkg/resource/ament_cargo/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ros2pkg/ros2pkg/resource/rust/__init__.py b/ros2pkg/ros2pkg/resource/rust/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ros2pkg/ros2pkg/resource/rust/main.rs.em b/ros2pkg/ros2pkg/resource/rust/main.rs.em new file mode 100644 index 000000000..7ed0e7157 --- /dev/null +++ b/ros2pkg/ros2pkg/resource/rust/main.rs.em @@ -0,0 +1,13 @@ +use anyhow::Result; +use rclrs::{Context, CreateBasicExecutor, RclrsErrorFilter, SpinOptions}; + +/// Creates a ROS 2 context and node, prints a hello message, +/// then spins until shutdown. +fn main() -> Result<()> { + let context: Context = Context::default_from_env()?; + let mut executor = context.create_basic_executor(); + let _node = executor.create_node("@(node_name)")?; + println!("Hello from @(package_name) package!"); + executor.spin(SpinOptions::default()).first_error()?; + Ok(()) +} diff --git a/ros2pkg/ros2pkg/verb/create.py b/ros2pkg/ros2pkg/verb/create.py index ef2df5ad9..7348b08d9 100644 --- a/ros2pkg/ros2pkg/verb/create.py +++ b/ros2pkg/ros2pkg/verb/create.py @@ -27,6 +27,7 @@ from catkin_pkg.package import Person from ros2pkg.api.create import create_package_environment +from ros2pkg.api.create import populate_ament_cargo from ros2pkg.api.create import populate_ament_cmake from ros2pkg.api.create import populate_ament_python from ros2pkg.api.create import populate_cmake @@ -34,6 +35,7 @@ from ros2pkg.api.create import populate_cpp_node from ros2pkg.api.create import populate_python_libary from ros2pkg.api.create import populate_python_node +from ros2pkg.api.create import populate_rust_node from ros2pkg.verb import VerbExtension @@ -69,7 +71,7 @@ def add_arguments(self, parser, cli_name): parser.add_argument( '--build-type', default='ament_cmake', - choices=['cmake', 'ament_cmake', 'ament_python'], + choices=['cmake', 'ament_cmake', 'ament_cargo', 'ament_python'], help='The build type to process the package with') parser.add_argument( '--dependencies', @@ -141,6 +143,10 @@ def get_git_config(key: str) -> Optional[str]: else: buildtool_depends = ['ament_cmake'] + if args.build_type == 'ament_cargo': + buildtool_depends = ['ament_cargo'] + args.dependencies.append('rclrs') + test_dependencies = [] if args.build_type == 'ament_cmake': test_dependencies = ['ament_lint_auto', 'ament_lint_common'] @@ -199,6 +205,9 @@ def get_git_config(key: str) -> Optional[str]: if args.build_type == 'ament_cmake': populate_ament_cmake(package, package_directory, node_name, library_name) + if args.build_type == 'ament_cargo': + populate_ament_cargo(package, package_directory, library_name) + if args.build_type == 'ament_python': if not source_directory: return 'unable to create source folder in ' + args.destination_directory @@ -224,6 +233,13 @@ def get_git_config(key: str) -> Optional[str]: library_name ) + if args.build_type == 'ament_cargo': + populate_rust_node( + package, + source_directory, + node_name + ) + if args.license in available_licenses: with open(os.path.join(package_directory, 'LICENSE'), 'w') as outfp: for lic in available_licenses[args.license]: