diff --git a/sdf/CMakeLists.txt b/sdf/CMakeLists.txt index 127458d91..133c4459d 100644 --- a/sdf/CMakeLists.txt +++ b/sdf/CMakeLists.txt @@ -15,7 +15,7 @@ add_dependencies(schema schema1_10) # Generate the EmbeddedSdf.cc file, which contains all the supported SDF # descriptions in a map of strings. The parser.cc file uses EmbeddedSdf.hh. execute_process( - COMMAND ${RUBY} ${CMAKE_SOURCE_DIR}/sdf/embedSdf.rb + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/sdf/embedSdf.py WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/sdf" OUTPUT_FILE "${PROJECT_BINARY_DIR}/src/EmbeddedSdf.cc" ) diff --git a/sdf/embedSdf.py b/sdf/embedSdf.py new file mode 100644 index 000000000..6e5af2f22 --- /dev/null +++ b/sdf/embedSdf.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python3 +from pathlib import Path + +""""Script for generating a C++ file that contains the content from all SDF files""" + +# The list of supported SDF specification versions. This will let us drop +# versions without removing the directories. +SUPPORTED_SDF_VERSIONS = ['1.9', '1.8', '1.7', '1.6', '1.5', '1.4', '1.3', '1.2'] + +# The list of supported SDF conversions. This list includes versions that +# a user can convert an existing SDF version to. +SUPPORTED_SDF_CONVERSIONS = ['1.9', '1.8', '1.7', '1.6', '1.5', '1.4', '1.3'] + +# whitespace indentation for C++ code +INDENTATION = ' ' + + +def get_copyright_notice() -> str: + """ + Provides the copyrigt notice for the C++ file + + :returns: copyright notice + """ + res = [] + res.append('/*') + res.append(' * Copyright 2022 Open Source Robotics Foundation') + res.append(' *') + res.append(' * Licensed under the Apache License, Version 2.0 (the "License");') + res.append(' * you may not use this file except in compliance with the License.') + res.append(' * You may obtain a copy of the License at') + res.append(' *') + res.append(' * http://www.apache.org/licenses/LICENSE-2.0') + res.append(' *') + res.append(' * Unless required by applicable law or agreed to in writing, software') + res.append(' * distributed under the License is distributed on an "AS IS" BASIS,') + res.append(' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.') + res.append(' * See the License for the specific language governing permissions and') + res.append(' * limitations under the License.') + res.append(' *') + res.append('*/') + res.append('') + return '\n'.join(res) + + +def get_file_header_prolog() -> str: + """ + Provides the include statement, namespace and variable declaration of the C++ file + + :returns: prolog of the C++ file + """ + res = [] + res.append('#include "EmbeddedSdf.hh"') + res.append('') + res.append('namespace sdf') + res.append('{') + res.append('inline namespace SDF_VERSION_NAMESPACE') + res.append('{') + res.append('/////////////////////////////////////////////////') + res.append('const std::map &GetEmbeddedSdf()') + res.append('{') + res.append(INDENTATION + 'static const std::map result {') + res.append('') + return '\n'.join(res) + + +def embed_sdf_content(arg_path: str, arg_file_content: str) -> str: + """ + Generates a string pair with the folder and filename as well as the content of the file + + :param arg_path: Foldername and filename of the SDF + :param arg_file_content: Content of the provided file + :returns: raw string literal mapping pair for the std::map + """ + res = [] + res.append('// NOLINT') + res.append('{') + res.append(f'"{arg_path}",') + res.append('R"__sdf_literal__(') + res.append(f'{arg_file_content}') + res.append(')__sdf_literal__"') + res.append('},') + res.append('') + return '\n'.join(res) + + +def get_map_content(arg_pathlist: Path) -> str: + """ + Generates a string pair with the folder and filename as well as the content + of the file in ascending order + + :param arg_pathlist: Foldername and all filenames inside it + :returns: mapping pairs for the std::map + """ + map_str = '' + files = [] + for path in pathlist: + files.append(str(path)) + # get ascending order + files.sort() + for file in files: + with Path(file).open() as f: + content = f.read() + map_str += embed_sdf_content(file, content) + return map_str + + +def get_file_header_epilog() -> str: + """ + Provides the return statement and the closing brackets of the C++ file + + :returns: epilog of the C++ file + """ + res = [] + res.append('') + res.append(INDENTATION + '};') + res.append('') + res.append(INDENTATION + 'return result;') + res.append('}') + res.append('') + res.append('}') + res.append('} // namespace sdf') + res.append('') + return '\n'.join(res) + + +if __name__ == "__main__": + copyright = get_copyright_notice() + prolog = get_file_header_prolog() + + map_str = "" + for sdf_version in SUPPORTED_SDF_VERSIONS: + pathlist = Path(sdf_version).glob('*.sdf') + map_str += get_map_content(pathlist) + + for sdf_conversion in SUPPORTED_SDF_CONVERSIONS: + pathlist = Path(sdf_conversion).glob('*.convert') + map_str += get_map_content(pathlist) + + # remove the last comma + map_str = map_str[:-2] + + epilog = get_file_header_epilog() + + output = copyright + prolog + map_str + epilog + + # output to stdin so that CMake can read it and create the appropriate file + print(output) diff --git a/sdf/embedSdf.rb b/sdf/embedSdf.rb deleted file mode 100755 index 488ff698d..000000000 --- a/sdf/embedSdf.rb +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env ruby - -# The list of supported SDF specification versions. This will let us drop -# versions without removing the directories. -supportedSdfVersions = ['1.10', '1.9', '1.8', '1.7', '1.6', '1.5', '1.4', '1.3', '1.2'] - -# The list of supported SDF conversions. This list includes versions that -# a user can convert an existing SDF version to. -supportedSdfConversions = ['1.10', '1.9', '1.8', '1.7', '1.6', '1.5', '1.4', '1.3'] - -puts %q! -#include "EmbeddedSdf.hh" - -namespace sdf { -inline namespace SDF_VERSION_NAMESPACE { - -const std::map &GetEmbeddedSdf() { - static const std::map result{ -! - -# Stores the contents of the file in the map. -def embed(pathname) - puts "{\"#{pathname}\", R\"__sdf_literal__(" - infile = File.open(pathname) - puts infile.read - puts ")__sdf_literal__\"}," -end - -# Embed the supported *.sdf files. -supportedSdfVersions.each do |version| - Dir.glob("#{version}/*.sdf").sort.each { |file| embed(file) } -end - -# Embed the supported *.convert files. -supportedSdfConversions.each do |version| - Dir.glob("#{version}/*.convert").sort.each { |file| embed(file) } -end -puts %q! - }; - return result; -} - -} -} -!