rtt_ros.cpp
Go to the documentation of this file.
1 #include <cstdlib>
2 #include <list>
3 #include <queue>
4 #include <sstream>
5 #include <set>
6 
7 #include <boost/filesystem.hpp>
8 #include <boost/version.hpp>
9 
10 #include <libxml/parser.h>
11 #include <libxml/xpath.h>
12 #include <libxml/xpathInternals.h>
13 #include <libxml/tree.h>
14 
15 #include <rtt/RTT.hpp>
17 
19 #include <rtt/Logger.hpp>
20 
21 #include <ros/package.h>
22 #include <rospack/rospack.h>
23 
24 #include <rtt_ros/rtt_ros.h>
25 
26 
27 bool rtt_ros::import(const std::string& package)
28 {
29  RTT::Logger::In in("ROSService::import(\""+package+"\")");
30 
31  boost::shared_ptr<RTT::ComponentLoader> loader = RTT::ComponentLoader::Instance();
32 
33  // List of packages which could not be loaded
34  std::vector<std::string> missing_packages;
35 
36  // Get the dependencies for a given ROS package --> deps
37  try {
38  // Get the package paths
39  std::vector<std::string> ros_package_paths;
40  rospack::Rospack rpack;
41  rpack.setQuiet(true);
42  rpack.getSearchPathFromEnv(ros_package_paths);
43 
44  RTT::log(RTT::Debug) << "Loading dependencies for ROS package \""<< package << "\" from: ";
45  for(size_t i=0; i<ros_package_paths.size(); i++) { RTT::log(RTT::Debug) << ros_package_paths[i]; }
47 
48  rpack.crawl(ros_package_paths,true);
49 
50  if ( ros_package_paths.size() == 0 ) {
51  RTT::log(RTT::Error) << "No paths in the ROS_PACKAGE_PATH environment variable! Could not load ROS package \"" << package << "\"" << RTT::endlog();
52  return false;
53  }
54 
55  // Add all rtt_ros/plugin_depend dependencies to package names
56  std::vector<std::string> deps_to_import;
57  std::vector<std::string> search_paths;
58  rpack.setQuiet(true);
59 
60  // Read the package.xml for this package
61  std::queue<std::string> dep_names;
62  dep_names.push(package);
63  deps_to_import.push_back(package);
64 
65  xmlChar * rtt_plugin_depend_xpath = xmlCharStrdup("/package/export/rtt_ros/plugin_depend/text()");
66 
67  while(!dep_names.empty())
68  {
69  namespace fs = boost::filesystem;
70 
71  // Get the next dep name, store the dep path
72  std::string dep_name, dep_path;
73  dep_name = dep_names.front();
74  dep_names.pop();
75 
76  bool dep_found = rpack.find(dep_name,dep_path);
77 
78  if(!dep_found) {
79  RTT::log(RTT::Error) << "Could not find ROS package \""<< dep_name << "\" in ROS_PACKAGE_PATH environment variable." <<RTT::endlog();
80  continue;
81  }
82 
83  // Construct the package.xml path
84  fs::path package_xml_path = fs::path(dep_path) / "package.xml";
85  bool is_rosbuild_package = false;
86 
87  // Check if package.xml file exists
88  if(!boost::filesystem::is_regular_file( package_xml_path.string() ) ) {
89 
90  // Fall back to manifest.xml for rosbuild packages
91  package_xml_path = fs::path(dep_path) / "manifest.xml";
92  is_rosbuild_package = true;
93 
94  if(!boost::filesystem::is_regular_file( package_xml_path.string() ) ) {
95  RTT::log(RTT::Error) << "No package.xml or manifest.xml file for ROS package \""<< dep_name << "\" found at "<<package_xml_path.branch_path() <<RTT::endlog();
96  continue;
97  }
98  }
99 
100  // Add package path to the list of search paths
101  if (is_rosbuild_package) {
102  search_paths.push_back((fs::path(dep_path) / "lib" / "orocos").string());
103  }
104 
105  // Read in package.xml/manifest.xml
106  xmlInitParser();
107 
108  // libxml structures
109  xmlDocPtr package_doc;
110  xmlXPathContextPtr xpath_ctx;
111  xmlXPathObjectPtr xpath_obj;
112 
113  // Load package.xml
114  package_doc = xmlParseFile(package_xml_path.string().c_str());
115  xpath_ctx = xmlXPathNewContext(package_doc);
116 
117  // Get the text of the rtt_ros <plugin_depend>s
118  xpath_obj = xmlXPathEvalExpression(rtt_plugin_depend_xpath, xpath_ctx);
119 
120  // Iterate through the nodes
121  if(xmlXPathNodeSetIsEmpty(xpath_obj->nodesetval)) {
122  RTT::log(RTT::Debug) << "ROS package \""<< dep_name << "\" has no RTT plugin dependencies." <<RTT::endlog();
123  } else {
124  RTT::log(RTT::Debug) << "ROS package \""<< dep_name << "\" has "<<xpath_obj->nodesetval->nodeNr<<" RTT plugin dependencies." <<RTT::endlog();
125 
126  for(int i=0; i < xpath_obj->nodesetval->nodeNr; i++) {
127  if(xpath_obj->nodesetval->nodeTab[i]) {
128  std::ostringstream oss;
129  xmlChar * dep_str = xmlNodeGetContent(xpath_obj->nodesetval->nodeTab[i]);
130  oss << dep_str;
131  xmlFree(dep_str);
132  RTT::log(RTT::Debug) << "Found dependency \""<< oss.str() << "\"" <<RTT::endlog();
133  dep_names.push(oss.str());
134 
135  // Add the dep to the list of deps to import
136  deps_to_import.push_back(oss.str());
137  }
138  }
139  }
140 
141  xmlXPathFreeObject(xpath_obj);
142  xmlXPathFreeContext(xpath_ctx);
143  xmlFreeDoc(package_doc);
144  xmlCleanupParser();
145  }
146  xmlFree(rtt_plugin_depend_xpath);
147 
148  // Build path list by prepending paths from search_paths list to the RTT component path in reverse order without duplicates
149  std::set<std::string> search_paths_seen;
150  std::string path_list = loader->getComponentPath();
151  for(std::vector<std::string>::reverse_iterator it = search_paths.rbegin();
152  it != search_paths.rend();
153  ++it)
154  {
155  if (search_paths_seen.count(*it)) continue;
156  path_list = *it + ":" + path_list;
157  search_paths_seen.insert(*it);
158  }
159 
160  RTT::log(RTT::Debug) << "Attempting to load RTT plugins from "<<deps_to_import.size()<<" packages..." << RTT::endlog();
161 
162  // Import each package dependency and the package itself (in deps_to_import[0])
163  for(std::vector<std::string>::reverse_iterator it = deps_to_import.rbegin();
164  it != deps_to_import.rend();
165  ++it)
166  {
167  // Check if it's already been imported
168  if(*it == "rtt_ros" || loader->isImported(*it)) {
169  RTT::log(RTT::Debug) << "Package dependency '"<< *it <<"' already imported." << RTT::endlog();
170  continue;
171  }
172 
173  // Import the dependency
174  if(loader->import(*it, path_list)) {
175  RTT::log(RTT::Debug) << "Importing Orocos components from ROS package \""<<*it<<"\" SUCCEEDED.";
176  } else {
177  // Temporarily store the name of the missing package
178  missing_packages.push_back(*it);
179  RTT::log(RTT::Debug) << "Importing Orocos components from ROS package \""<<*it<<"\" FAILED.";
180  }
182  }
183 
184  } catch(std::string arg) {
185  RTT::log(RTT::Debug) << "While processing the dependencies of " << package << ": Dependency is not a ros package: " << arg << RTT::endlog();
186  missing_packages.push_back(arg);
187  }
188 
189  // Report success or failure
190  if(missing_packages.size() == 0) {
191  RTT::log(RTT::Info) << "Loaded plugins from ROS package \"" << package << "\" and its dependencies." << RTT::endlog();
192  } else {
193  RTT::log(RTT::Warning) << "Could not load RTT plugins from the following ROS packages (they might be empty, in which case this message can be ignored): "<< RTT::endlog();
194  for(std::vector<std::string>::iterator it = missing_packages.begin();
195  it != missing_packages.end();
196  ++it)
197  {
198  RTT::log(RTT::Warning) << " - " << *it<< RTT::endlog();
199  }
200  }
201 
202  return missing_packages.size() == 0;
203 }
void setQuiet(bool quiet)
std::string str()
static boost::shared_ptr< ComponentLoader > Instance()
bool import(const std::string &package)
Import a ROS package and all of its rtt_ros/plugin_depend dependencies.
Definition: rtt_ros.cpp:27
bool getSearchPathFromEnv(std::vector< std::string > &sp)
void crawl(std::vector< std::string > search_path, bool force)
bool find(const std::string &name, std::string &path)
static Logger & log()
static Logger::LogFunction endlog()


rtt_ros
Author(s): Ruben Smits
autogenerated on Mon May 10 2021 02:44:45