19#include "auto_apms_behavior_tree_core/node/node_manifest.hpp"
20#include "auto_apms_behavior_tree_core/node/node_registration_loader.hpp"
21#include "auto_apms_util/exceptions.hpp"
22#include "auto_apms_util/resource.hpp"
23#include "auto_apms_util/string.hpp"
27int main(
int argc,
char ** argv)
30 std::cerr <<
"create_node_manifest: Missing inputs! The program requires: \n\t1.) the yaml "
31 "node manifest files (separated by ';').\n\t2.) Build information for nodes supposed to be "
32 "registered during build time (List of '<class_name>@<library_build_path>@<registration_type>' "
33 "separated by ';').\n\t3.) The name of the package that provides the build targets.\n\t4.) Output "
34 "file for the complete node plugin manifest.\n\t";
35 std::cerr <<
"Usage: create_node_manifest <manifest_files> <build_infos> <build_package_name> "
41 std::vector<std::string> manifest_files;
43 manifest_files.push_back(std::filesystem::absolute(path).
string());
46 const std::string build_package_name = argv[3];
50 if (manifest_files.empty()) {
51 throw std::runtime_error(
"Argument manifest_files must not be empty");
53 if (output_file.empty()) {
54 throw std::runtime_error(
"Argument output_file must not be empty.");
58 if (output_file.extension() !=
".yaml") {
59 throw std::runtime_error(
"Output file '" + output_file.string() +
"' has wrong extension. Must be '.yaml'.");
63 std::map<std::string, std::string> library_paths_build_package;
64 std::map<std::string, std::string> registration_types_build_package;
65 std::map<std::string, std::string> reserved_names;
66 for (
const auto & build_info : build_infos) {
68 if (parts.size() != 3) {
69 throw std::runtime_error(
70 "Invalid build info entry ('" + build_info +
71 "'). Expected format: '<class_name>@<library_path>@<registration_type>'.");
73 const std::string & class_name = parts[0];
74 const std::string & build_path = parts[1];
75 const std::string & registration_type = parts[2];
76 if (library_paths_build_package.find(class_name) != library_paths_build_package.end()) {
77 throw std::runtime_error(
"Node class '" + class_name +
"' is specified multiple times in build infos.");
79 library_paths_build_package[class_name] = build_path;
80 registration_types_build_package[class_name] = registration_type;
81 reserved_names[class_name] = build_package_name;
99 std::set<std::string> exclude_build_package{build_package_name};
100 std::set<std::string> other_packages_with_node_plugins;
105 }
catch (
const auto_apms_util::exceptions::ResourceError & e) {
108 other_packages_with_node_plugins = {};
110 std::unique_ptr<Loader> loader_ptr =
nullptr;
111 if (!other_packages_with_node_plugins.empty()) {
114 Loader * ptr =
new Loader(
115 Loader::makeUnambiguousPluginClassLoader(
117 exclude_build_package, reserved_names));
118 loader_ptr = std::unique_ptr<Loader>(ptr);
122 std::set<std::string> library_paths;
123 std::map<std::string, std::string> registration_types;
124 for (
const auto & [node_name, params] : output_manifest.
map()) {
126 if (library_paths_build_package.find(params.class_name) != library_paths_build_package.end()) {
127 library_paths.insert(library_paths_build_package[params.class_name]);
128 registration_types[params.class_name] = registration_types_build_package[params.class_name];
133 if (loader_ptr !=
nullptr && loader_ptr->isClassAvailable(params.class_name)) {
134 library_paths.insert(loader_ptr->getClassLibraryPath(params.class_name));
135 registration_types[params.class_name] = loader_ptr->getClassType(params.class_name);
140 throw std::runtime_error(
141 "Class '" + params.class_name +
"' (associated with node '" + node_name +
142 "') cannot be found. It's not being built by this package (" + build_package_name +
143 ") and is also not provided by any other package installed on your machine. For a node to be discoverable, "
144 "one must register it using auto_apms_behavior_tree_register_nodes() in the "
145 "CMakeLists.txt of a ROS 2 package.");
149 output_manifest.
toFile(output_file);
155 for (
const auto & path : library_paths) {
156 if (!first) std::cout <<
';';
162 for (
const auto & [class_name, reg_type] : registration_types) {
163 if (!first) std::cout <<
';';
164 std::cout << class_name <<
'=' << reg_type;
167 }
catch (
const std::exception & e) {
168 std::cerr <<
"ERROR (create_node_manifest): " << e.what() <<
"\n";
Data structure for information about which behavior tree node plugin to load and how to configure the...
static NodeManifest fromFiles(const std::vector< std::string > &paths)
Create a node plugin manifest from multiple files. They are loaded in the given order.
const Map & map() const
Get a view of the internal map.
void toFile(const std::string &file_path) const
Write the node manifest to a file.
static const std::string BASE_CLASS_NAME
Name of the base class of all plugins to be loaded.
static const std::string BASE_PACKAGE_NAME
Name of the package that contains the base class for this plugin loader.
Class for loading plugin resources registered according to the conventions defined by the pluginlib p...
std::string trimWhitespaces(const std::string &str)
Trim whitespaces from both ends of a string.
std::vector< std::string > splitString(const std::string &str, const std::string &delimiter, bool remove_empty=true)
Split a string into multiple tokens using a specific delimiter string (Delimiter may consist of multi...
std::set< std::string > getPackagesWithPluginResources(const std::set< std::string > &exclude_packages={})
Get a list of all package names that register AutoAPMS plugin resources.
Powerful tooling for incorporating behavior trees for task development.