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>' "
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> reserved_names;
65 for (
const auto & build_info : build_infos) {
67 if (parts.size() != 2) {
68 throw std::runtime_error(
"Invalid build info entry ('" + build_info +
"').");
70 const std::string & class_name = parts[0];
71 const std::string & build_path = parts[1];
72 if (library_paths_build_package.find(class_name) != library_paths_build_package.end()) {
73 throw std::runtime_error(
"Node class '" + class_name +
"' is specified multiple times in build infos.");
75 library_paths_build_package[class_name] = build_path;
76 reserved_names[class_name] = build_package_name;
94 std::set<std::string> exclude_build_package{build_package_name};
95 std::set<std::string> other_packages_with_node_plugins;
100 }
catch (
const auto_apms_util::exceptions::ResourceError & e) {
103 other_packages_with_node_plugins = {};
105 std::unique_ptr<Loader> loader_ptr =
nullptr;
106 if (!other_packages_with_node_plugins.empty()) {
109 Loader * ptr =
new Loader(Loader::makeUnambiguousPluginClassLoader(
111 exclude_build_package, reserved_names));
112 loader_ptr = std::unique_ptr<Loader>(ptr);
116 std::set<std::string> library_paths;
117 for (
const auto & [node_name, params] : output_manifest.
map()) {
119 if (library_paths_build_package.find(params.class_name) != library_paths_build_package.end()) {
120 library_paths.insert(library_paths_build_package[params.class_name]);
125 if (loader_ptr !=
nullptr && loader_ptr->isClassAvailable(params.class_name)) {
126 library_paths.insert(loader_ptr->getClassLibraryPath(params.class_name));
131 throw std::runtime_error(
132 "Node '" + node_name +
"' (Class '" + params.class_name +
133 "') cannot be found. It's not being built by this package (" + build_package_name +
134 ") and is also not provided by any other package. For a node to be discoverable, "
135 "one must register it using auto_apms_behavior_tree_declare_nodes() in the "
136 "CMakeLists.txt of a ROS 2 package.");
140 output_manifest.
toFile(output_file);
144 for (
const auto & path : library_paths) std::cout << path <<
';';
145 }
catch (
const std::exception & e) {
146 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.
Useful tooling for incorporating behavior trees for task development.