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\t5.) (optional) Previously generated manifest "
35 "entries from the same package for build-time parent resolution "
36 "(List of '<metadata_id>|<absolute_path>' separated by ';').\n\t";
37 std::cerr <<
"Usage: create_node_manifest <manifest_files> <build_infos> <build_package_name> "
38 "<output_file> [<local_manifest_entries>]\n";
43 std::vector<std::string> manifest_files;
45 manifest_files.push_back(std::filesystem::absolute(path).
string());
48 const std::string build_package_name = argv[3];
52 if (manifest_files.empty()) {
53 throw std::runtime_error(
"Argument manifest_files must not be empty");
55 if (output_file.empty()) {
56 throw std::runtime_error(
"Argument output_file must not be empty.");
60 if (output_file.extension() !=
".yaml") {
61 throw std::runtime_error(
"Output file '" + output_file.string() +
"' has wrong extension. Must be '.yaml'.");
65 std::map<std::string, std::string> library_paths_build_package;
66 std::map<std::string, std::string> registration_types_build_package;
67 std::map<std::string, std::string> reserved_names;
68 for (
const auto & build_info : build_infos) {
70 if (parts.size() != 3) {
71 throw std::runtime_error(
72 "Invalid build info entry ('" + build_info +
73 "'). Expected format: '<class_name>@<library_path>@<registration_type>'.");
75 const std::string & class_name = parts[0];
76 const std::string & build_path = parts[1];
77 const std::string & registration_type = parts[2];
78 if (library_paths_build_package.find(class_name) != library_paths_build_package.end()) {
79 throw std::runtime_error(
"Node class '" + class_name +
"' is specified multiple times in build infos.");
81 library_paths_build_package[class_name] = build_path;
82 registration_types_build_package[class_name] = registration_type;
83 reserved_names[class_name] = build_package_name;
91 if (parts.size() != 2)
continue;
92 const std::string & metadata_id = parts[0];
93 const std::string & file_path = parts[1];
94 if (!std::filesystem::exists(file_path))
continue;
96 const std::string identity_str =
97 build_package_name + _AUTO_APMS_BEHAVIOR_TREE_CORE__RESOURCE_IDENTITY_ALIAS_SEP + metadata_id;
100 }
catch (
const std::exception &) {
121 std::set<std::string> exclude_build_package{build_package_name};
122 std::set<std::string> other_packages_with_node_plugins;
127 }
catch (
const auto_apms_util::exceptions::ResourceError & e) {
130 other_packages_with_node_plugins = {};
132 std::unique_ptr<Loader> loader_ptr =
nullptr;
133 if (!other_packages_with_node_plugins.empty()) {
136 Loader * ptr =
new Loader(
137 Loader::makeUnambiguousPluginClassLoader(
139 exclude_build_package, reserved_names));
140 loader_ptr = std::unique_ptr<Loader>(ptr);
144 std::set<std::string> library_paths;
145 std::map<std::string, std::string> registration_types;
146 for (
const auto & [node_name, params] : output_manifest.
map()) {
148 if (library_paths_build_package.find(params.class_name) != library_paths_build_package.end()) {
149 library_paths.insert(library_paths_build_package[params.class_name]);
150 registration_types[params.class_name] = registration_types_build_package[params.class_name];
155 if (loader_ptr !=
nullptr && loader_ptr->isClassAvailable(params.class_name)) {
156 library_paths.insert(loader_ptr->getClassLibraryPath(params.class_name));
157 registration_types[params.class_name] = loader_ptr->getClassType(params.class_name);
162 throw std::runtime_error(
163 "Class '" + params.class_name +
"' (associated with node '" + node_name +
164 "') cannot be found. It's not being built by this package (" + build_package_name +
165 ") and is also not provided by any other package installed on your machine. For a node to be discoverable, "
166 "one must register it using auto_apms_behavior_tree_register_nodes() in the "
167 "CMakeLists.txt of a ROS 2 package.");
171 output_manifest.
toFile(output_file);
177 for (
const auto & path : library_paths) {
178 if (!first) std::cout <<
';';
184 for (
const auto & [class_name, reg_type] : registration_types) {
185 if (!first) std::cout <<
';';
186 std::cout << class_name <<
'=' << reg_type;
189 }
catch (
const std::exception & e) {
190 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 void registerLocalManifest(const NodeManifestResourceIdentity &id, const NodeManifest &manifest, bool allow_override=false)
Register a manifest in the process-local lookup table.
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.
Struct that encapsulates the identity string for a registered behavior tree node manifest.