9 #include <unordered_set> 12 #include <ament_index_cpp/get_package_share_directory.hpp> 13 #include <ament_index_cpp/get_resource.hpp> 14 #include <ament_index_cpp/get_resources.hpp> 15 #include <rcutils/logging_macros.h> 21 R
"(^([a-zA-Z0-9_]+)/(?:(msg|srv|action)/)?([a-zA-Z0-9_]+)$)"}; 28 R
"((?:^|\n)#include\s+(?:"|<)([a-zA-Z0-9_/]+)\.idl(?:"|>))"}; 31 "bool",
"byte",
"char",
"float32",
"float64",
"int8",
"uint8",
32 "int16",
"uint16",
"int32",
"uint32",
"int64",
"uint64",
"string"};
35 const std::string& package_context) {
36 std::set<std::string> dependencies;
39 iter != std::sregex_iterator(); ++iter) {
40 std::string type = (*iter)[1];
44 if (type.find(
'/') == std::string::npos) {
45 dependencies.insert(package_context +
'/' + std::move(type));
47 dependencies.insert(std::move(type));
54 std::set<std::string> dependencies;
57 iter != std::sregex_iterator(); ++iter) {
58 dependencies.insert((*iter)[1]);
64 const std::string& package_context) {
71 throw std::runtime_error(
"switch is not exhaustive");
82 throw std::runtime_error(
"switch is not exhaustive");
88 "================================================================================\n";
89 switch (definition_identifier.
format) {
97 throw std::runtime_error(
"switch is not exhaustive");
106 std::vector<std::string> strings;
107 std::string::size_type pos = 0;
108 std::string::size_type prev = 0;
110 while ((pos = str.find(
delimiter, prev)) != std::string::npos) {
111 strings.push_back(str.substr(prev, pos - prev));
116 strings.push_back(str.substr(prev));
125 const std::string& action_definition) {
126 constexpr
char SEP[] =
"\n---\n";
128 const auto definitions =
split_string(action_definition, SEP);
129 if (definitions.size() != 3) {
130 throw std::invalid_argument(
"Invalid action definition:\n" + action_definition);
133 return {definitions[0], definitions[1], definitions[2]};
136 inline bool ends_with(
const std::string& str,
const std::string& suffix) {
137 return str.size() >= suffix.size() &&
138 0 == str.compare(str.size() - suffix.size(), suffix.size(), suffix);
142 const auto action_subtype_suffixes = {
150 for (
const auto& suffix : action_subtype_suffixes) {
152 return action_type.substr(0, action_type.length() - suffix.length());
160 const std::string& package_context)
162 , text(
std::move(text))
167 if (
auto it = msg_specs_by_definition_identifier_.find(definition_identifier);
168 it != msg_specs_by_definition_identifier_.end()) {
174 throw std::invalid_argument(
"Invalid package resource name: " +
177 const std::string
package = match[1].str();
178 const std::string subfolder = match[2].str();
179 const std::string type_name = match[3].str();
180 const bool is_action_type = subfolder ==
"action";
185 const std::string filename = is_action_type
186 ? action_name +
".action" 190 const std::string share_dir = ament_index_cpp::get_package_share_directory(
package);
193 std::string index_contents;
194 if (!ament_index_cpp::get_resource(
"rosidl_interfaces",
package, index_contents)) {
200 const auto it = std::find_if(lines.begin(), lines.end(), [&filename](
const std::string& line) {
201 std::filesystem::path filePath(line);
202 return filePath.filename() == filename;
204 if (it == lines.end()) {
209 const std::string full_path = share_dir + std::filesystem::path::preferred_separator + *it;
210 std::ifstream file{full_path};
214 const std::string contents{std::istreambuf_iterator(file), {}};
216 if (is_action_type) {
223 const std::map<std::string, std::string> action_type_definitions = {
226 "unique_identifier_msgs/UUID goal_id\n"},
228 "int8 status\n" + resultDef},
230 "unique_identifier_msgs/UUID goal_id\n" + goalDef},
232 "bool accepted\nbuiltin_interfaces/msg/Time stamp"}};
235 for (
const auto& [action_suffix,
definition] : action_type_definitions) {
239 msg_specs_by_definition_identifier_.emplace(
244 const auto it = msg_specs_by_definition_identifier_.find(definition_identifier);
245 if (it == msg_specs_by_definition_identifier_.end()) {
250 RCUTILS_LOG_ERROR_NAMED(
"foxglove_bridge",
251 "Action IDL definitions are currently not supported");
257 msg_specs_by_definition_identifier_
258 .emplace(definition_identifier,
269 const std::string& root_package_resource_name) {
270 std::unordered_set<DefinitionIdentifier, DefinitionIdentifierHash> seen_deps;
272 std::function<std::string(const DefinitionIdentifier&)> append_recursive =
274 const MessageSpec& spec = load_message_spec(definition_identifier);
275 std::string result = spec.
text;
278 bool inserted = seen_deps.insert(dep).second;
282 result += append_recursive(dep);
294 RCUTILS_LOG_WARN_NAMED(
"foxglove_bridge",
"no .msg definition for %s, falling back to IDL",
298 result =
delimiter(root_definition_identifier) + append_recursive(root_definition_identifier);
300 return std::make_pair(
format, result);
constexpr char ACTION_GOAL_SERVICE_SUFFIX[]
std::set< std::string > parse_dependencies(MessageDefinitionFormat format, const std::string &text, const std::string &package_context)
bool ends_with(const std::string &str, const std::string &suffix)
constexpr char SERVICE_RESPONSE_MESSAGE_SUFFIX[]
constexpr char ACTION_RESULT_SERVICE_SUFFIX[]
MessageDefinitionFormat format
MessageDefinitionFormat format
const MessageSpec & load_message_spec(const DefinitionIdentifier &definition_identifier)
static std::tuple< std::string, std::string, std::string > split_action_msg_definition(const std::string &action_definition)
Split an action definition into individual goal, result and feedback definitions. ...
static const char * extension_for_format(MessageDefinitionFormat format)
MessageSpec(MessageDefinitionFormat format, std::string text, const std::string &package_context)
const std::set< std::string > dependencies
static std::string delimiter(const DefinitionIdentifier &definition_identifier)
constexpr char ACTION_FEEDBACK_MESSAGE_SUFFIX[]
const char * what() const noexcept override
constexpr char SERVICE_REQUEST_MESSAGE_SUFFIX[]
static const std::regex PACKAGE_TYPENAME_REGEX
static const std::regex IDL_FIELD_TYPE_REGEX
std::pair< MessageDefinitionFormat, std::string > get_full_text(const std::string &package_resource_name)
static std::set< std::string > parse_msg_dependencies(const std::string &text, const std::string &package_context)
static const std::regex MSG_FIELD_TYPE_REGEX
static std::vector< std::string > split_string(const std::string &str, const std::string &delimiter="\)
std::string package_resource_name
static const std::unordered_set< std::string > PRIMITIVE_TYPES
const char * definition()
static std::set< std::string > parse_idl_dependencies(const std::string &text)
std::string remove_action_subtype(const std::string action_type)