10 #include <unordered_set>
13 #include <ament_index_cpp/get_package_share_directory.hpp>
14 #include <ament_index_cpp/get_resource.hpp>
15 #include <ament_index_cpp/get_resources.hpp>
16 #include <rcutils/logging_macros.h>
24 R
"(^([a-zA-Z0-9_]+)/(?:(msg|srv|action)/)?([a-zA-Z0-9_]+)$)"};
31 R
"((?:^|\n)#include\s+(?:"|<)([a-zA-Z0-9_/]+)\.idl(?:"|>))"};
34 "bool",
"byte",
"char",
"float32",
"float64",
"int8",
"uint8",
35 "int16",
"uint16",
"int32",
"uint32",
"int64",
"uint64",
"string"};
44 const std::string& package_context) {
45 std::set<std::string> dependencies;
48 iter != std::sregex_iterator(); ++iter) {
49 std::string type = (*iter)[1];
53 if (type.find(
'/') == std::string::npos) {
54 dependencies.insert(package_context +
'/' + std::move(type));
56 dependencies.insert(std::move(type));
63 std::set<std::string> dependencies;
66 iter != std::sregex_iterator(); ++iter) {
67 dependencies.insert((*iter)[1]);
73 const std::string& package_context) {
80 throw std::runtime_error(
"switch is not exhaustive");
88 switch (definitionType) {
96 throw std::runtime_error(
"unknown definition type");
101 throw std::runtime_error(
"switch is not exhaustive");
107 "================================================================================\n";
108 switch (definition_identifier.
format) {
116 throw std::runtime_error(
"switch is not exhaustive");
125 std::vector<std::string> strings;
126 std::string::size_type pos = 0;
127 std::string::size_type prev = 0;
129 while ((pos = str.find(
delimiter, prev)) != std::string::npos) {
130 strings.push_back(str.substr(prev, pos - prev));
135 strings.push_back(str.substr(prev));
140 inline bool ends_with(
const std::string& str,
const std::string& suffix) {
141 return str.size() >= suffix.size() &&
142 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
146 const auto action_subtype_suffixes = {
154 for (
const auto& suffix : action_subtype_suffixes) {
156 return action_type.substr(0, action_type.length() - suffix.length());
164 const std::vector<std::string> service_subtype_suffixes = {
169 for (
const auto& suffix : service_subtype_suffixes) {
171 return service_type.substr(0, service_type.length() - suffix.length());
179 const std::string& package_context)
181 , text(
std::move(text))
194 throw std::invalid_argument(
"Invalid package resource name: " +
197 const std::string
package = match[1].str();
198 const std::string subfolder = match[2].str();
199 const std::string type_name = match[3].str();
202 std::string filename =
"";
203 if (subfolder ==
"action") {
208 }
else if (subfolder ==
"srv") {
218 const std::string share_dir = ament_index_cpp::get_package_share_directory(
package);
221 std::string index_contents;
222 if (!ament_index_cpp::get_resource(
"rosidl_interfaces",
package, index_contents)) {
228 const auto it = std::find_if(lines.begin(), lines.end(), [&filename](
const std::string& line) {
229 std::filesystem::path filePath(line);
230 return filePath.filename() == filename;
232 if (it == lines.end()) {
237 const std::string full_path = share_dir + std::filesystem::path::preferred_separator + *it;
238 std::ifstream file{full_path};
243 if (subfolder ==
"action") {
245 RCUTILS_LOG_ERROR_NAMED(
"foxglove_bridge",
246 "Action IDL definitions are currently not supported");
251 if (split_definitions.size() != 3) {
252 throw std::invalid_argument(
"Invalid action definition in " + filename +
253 ": Expected 3 definitions, got " +
254 std::to_string(split_definitions.size()));
257 const auto& goalDef = split_definitions[0];
258 const auto& resultDef = split_definitions[1];
259 const auto& feedbackDef = split_definitions[2];
264 const std::map<std::string, std::string> action_type_definitions = {
267 "unique_identifier_msgs/UUID goal_id\n"},
269 "int8 status\n" + resultDef},
271 "unique_identifier_msgs/UUID goal_id\n" + goalDef},
273 "bool accepted\nbuiltin_interfaces/msg/Time stamp"}};
277 for (
const auto& [action_suffix,
definition] : action_type_definitions) {
291 }
else if (subfolder ==
"srv") {
293 RCUTILS_LOG_ERROR_NAMED(
"foxglove_bridge",
294 "Service IDL definitions are currently not supported");
299 if (split_definitions.size() != 2) {
300 throw std::invalid_argument(
"Invalid service definition in " + filename +
301 ": Expected 2 definitions, got " +
302 std::to_string(split_definitions.size()));
305 const auto& requestDef = split_definitions[0];
306 const auto& responseDef = split_definitions[1];
307 const std::map<std::string, std::string> service_type_definitions = {
313 for (
const auto& [subType,
definition] : service_type_definitions) {
331 .emplace(definition_identifier,
333 std::string{std::istreambuf_iterator(file), {}},
package))
343 const std::string& root_package_resource_name) {
344 std::unordered_set<DefinitionIdentifier, DefinitionIdentifierHash> seen_deps;
349 std::string result = spec.
text;
352 bool inserted = seen_deps.insert(dep).second;
356 result += append_recursive(dep);
368 RCUTILS_LOG_WARN_NAMED(
"foxglove_bridge",
"no .msg definition for %s, falling back to IDL",
372 result =
delimiter(root_definition_identifier) + append_recursive(root_definition_identifier);
374 return std::make_pair(
format, result);