rospack.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008, Willow Garage, Inc., Morgan Quigley
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  * * Redistributions of source code must retain the above copyright notice,
7  * this list of conditions and the following disclaimer.
8  * * Redistributions in binary form must reproduce the above copyright
9  * notice, this list of conditions and the following disclaimer in the
10  * documentation and/or other materials provided with the distribution.
11  * * Neither the names of Stanford University or Willow Garage, Inc. nor the names of its
12  * contributors may be used to endorse or promote products derived from
13  * this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <Python.h>
29 #include "rospack/rospack.h"
30 #include "utils.h"
31 #include "tinyxml2.h"
32 
33 #include <boost/algorithm/string.hpp>
34 #include <boost/filesystem.hpp>
35 #include <boost/functional/hash.hpp>
36 #include <stdexcept>
37 
38 #if defined(WIN32)
39  #include <windows.h>
40  #include <direct.h>
41  #include <fcntl.h> // for O_RDWR, O_EXCL, O_CREAT
42  // simple workaround - could have issues though. See
43  // http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010
44  // for potentially better solutions. Similar probably applies for some of the others
45  #define snprintf _snprintf
46  #define pclose _pclose
47  #define popen _popen
48  #define PATH_MAX MAX_PATH
49  #if defined(__MINGW32__)
50  #include <libgen.h> // for dirname
51  #endif
52  #if defined(_MSC_VER)
53  #include <io.h> // _mktemp_s
54  #endif
55 #else
56  #include <sys/types.h>
57  #include <libgen.h>
58  #include <pwd.h>
59  #include <unistd.h>
60  #include <sys/time.h>
61 #endif
62 
63 #include <algorithm>
64 #include <climits>
65 #include <iostream>
66 
67 #include <sys/stat.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <time.h>
71 #include <string.h>
72 #include <errno.h>
73 
74 /* re-define some String functions for python 2.x */
75 #if PY_VERSION_HEX < 0x03000000
76 #undef PyBytes_AsString
77 #undef PyUnicode_AsUTF8
78 #undef PyUnicode_FromString
79 #define PyBytes_AsString PyString_AsString
80 #define PyUnicode_AsUTF8 PyString_AsString
81 #define PyUnicode_FromString PyString_FromString
82 #endif
83 
84 // TODO:
85 // recrawl on:
86 // package not found in cache
87 // package found in cache, but no manifest.xml present in filesystem
88 
89 namespace fs = boost::filesystem;
90 
91 namespace rospack
92 {
93 static const char* MANIFEST_TAG_PACKAGE = "package";
94 static const char* MANIFEST_TAG_STACK = "stack";
95 static const char* ROSPACK_MANIFEST_NAME = "manifest.xml";
96 static const char* ROSPACKAGE_MANIFEST_NAME = "package.xml";
97 static const char* ROSSTACK_MANIFEST_NAME = "stack.xml";
98 static const char* ROSPACK_CACHE_PREFIX = "rospack_cache";
99 static const char* ROSSTACK_CACHE_PREFIX = "rosstack_cache";
100 static const char* ROSPACK_NOSUBDIRS = "rospack_nosubdirs";
101 static const char* CATKIN_IGNORE = "CATKIN_IGNORE";
102 static const char* DOTROS_NAME = ".ros";
103 static const char* MSG_GEN_GENERATED_DIR = "msg_gen";
104 static const char* MSG_GEN_GENERATED_FILE = "generated";
105 static const char* SRV_GEN_GENERATED_DIR = "srv_gen";
106 static const char* SRV_GEN_GENERATED_FILE = "generated";
107 static const char* MANIFEST_TAG_ROSDEP = "rosdep";
108 static const char* MANIFEST_TAG_VERSIONCONTROL = "versioncontrol";
109 static const char* MANIFEST_TAG_EXPORT = "export";
110 static const char* MANIFEST_ATTR_NAME = "name";
111 static const char* MANIFEST_ATTR_TYPE = "type";
112 static const char* MANIFEST_ATTR_URL = "url";
113 static const char* MANIFEST_PREFIX = "${prefix}";
114 static const int MAX_CRAWL_DEPTH = 1000;
115 static const int MAX_DEPENDENCY_DEPTH = 1000;
116 static const double DEFAULT_MAX_CACHE_AGE = 60.0;
117 
118 tinyxml2::XMLElement* get_manifest_root(Stackage* stackage);
119 double time_since_epoch();
120 
121 #ifdef __APPLE__
122  static const std::string g_ros_os = "osx";
123 #else
124  #if defined(WIN32)
125  static const std::string g_ros_os = "win32";
126  #else
127  static const std::string g_ros_os = "linux";
128  #endif
129 #endif
130 
131 class Exception : public std::runtime_error
132 {
133  public:
134  Exception(const std::string& what)
135  : std::runtime_error(what)
136  {}
137 };
138 
139 class Stackage
140 {
141  public:
142  // \brief name of the stackage
143  std::string name_;
144  // \brief absolute path to the stackage
145  std::string path_;
146  // \brief absolute path to the stackage manifest
147  std::string manifest_path_;
148  // \brief filename of the stackage manifest
149  std::string manifest_name_;
150  // \brief package's license with a support for multi-license.
151  std::vector<std::string> licenses_;
152  // \brief have we already loaded the manifest?
154  // \brief TinyXML structure, filled in during parsing
155  tinyxml2::XMLDocument manifest_;
156  std::vector<Stackage*> deps_;
160 
161  Stackage(const std::string& name,
162  const std::string& path,
163  const std::string& manifest_path,
164  const std::string& manifest_name) :
165  name_(name),
166  path_(path),
167  manifest_path_(manifest_path),
168  manifest_name_(manifest_name),
169  manifest_loaded_(false),
170  manifest_(true, tinyxml2::COLLAPSE_WHITESPACE),
171  deps_computed_(false),
172  is_metapackage_(false)
173  {
175  }
176 
178  {
179  assert(is_wet_package_);
180  assert(manifest_loaded_);
181  // get name from package.xml instead of folder name
182  tinyxml2::XMLElement* root = get_manifest_root(this);
183  tinyxml2::XMLElement* el = root->FirstChildElement("name");
184  if(el)
185  name_ = el->GetText();
186  // Get license texts, where there may be multiple elements for.
187  std::string tagname_license = "license";
188  for(el = root->FirstChildElement(tagname_license.c_str()); el; el = el->NextSiblingElement(tagname_license.c_str()))
189  {
190  licenses_.push_back(el->GetText());
191  }
192  // check if package is a metapackage
193  for(el = root->FirstChildElement("export"); el; el = el->NextSiblingElement("export"))
194  {
195  if(el->FirstChildElement("metapackage"))
196  {
197  is_metapackage_ = true;
198  break;
199  }
200  }
201  }
202 
203  bool isStack() const
204  {
206  }
207 
208  bool isPackage() const
209  {
211  }
212 
213 };
214 
216 {
217  public:
218  std::string path_;
219  bool zombie_;
220  double start_time_;
221  double crawl_time_;
223  DirectoryCrawlRecord(std::string path,
224  double start_time,
225  size_t start_num_pkgs) :
226  path_(path),
227  zombie_(false),
228  start_time_(start_time),
229  crawl_time_(0.0),
230  start_num_pkgs_(start_num_pkgs) {}
231 };
234 {
235  return (i->crawl_time_ < j->crawl_time_);
236 }
237 
239 // Rosstackage methods (public/protected)
241 Rosstackage::Rosstackage(const std::string& manifest_name,
242  const std::string& cache_prefix,
243  const std::string& name,
244  const std::string& tag) :
245  manifest_name_(manifest_name),
246  cache_prefix_(cache_prefix),
247  crawled_(false),
248  name_(name),
249  tag_(tag)
250 {
251 }
252 
254 {
255  clearStackages();
256 }
257 
259 {
260  for(boost::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
261  it != stackages_.end();
262  ++it)
263  {
264  delete it->second;
265  }
266  stackages_.clear();
267  dups_.clear();
268 }
269 
270 void
271 Rosstackage::logWarn(const std::string& msg,
272  bool append_errno)
273 {
274  log("Warning", msg, append_errno);
275 }
276 void
277 Rosstackage::logError(const std::string& msg,
278  bool append_errno)
279 {
280  log("Error", msg, append_errno);
281 }
282 
283 bool
284 Rosstackage::getSearchPathFromEnv(std::vector<std::string>& sp)
285 {
286  char* rpp = getenv("ROS_PACKAGE_PATH");
287  if(rpp)
288  {
289  // I can't see that boost filesystem has an elegant cross platform
290  // representation for this anywhere like qt/python have.
291  #if defined(WIN32)
292  const char *path_delim = ";";
293  #else
294  const char *path_delim = ":";
295  #endif
296 
297  std::vector<std::string> rpp_strings;
298  boost::split(rpp_strings, rpp,
299  boost::is_any_of(path_delim),
300  boost::token_compress_on);
301  for(std::vector<std::string>::const_iterator it = rpp_strings.begin();
302  it != rpp_strings.end();
303  ++it)
304  {
305  sp.push_back(*it);
306  }
307  }
308  return true;
309 }
310 
311 void
313 {
314  quiet_ = quiet;
315 }
316 
317 bool
318 Rosstackage::isStackage(const std::string& path)
319 {
320  try
321  {
322  if(!fs::is_directory(path))
323  return false;
324  }
325  catch(fs::filesystem_error& e)
326  {
327  logWarn(std::string("error while looking at ") + path + ": " + e.what());
328  return false;
329  }
330 
331  try
332  {
333  for(fs::directory_iterator dit = fs::directory_iterator(path);
334  dit != fs::directory_iterator();
335  ++dit)
336  {
337  if(!fs::is_regular_file(dit->path()))
338  continue;
339 
340  if(dit->path().filename() == manifest_name_)
341  return true;
342 
343  // finding a package.xml is acceptable
344  if(dit->path().filename() == ROSPACKAGE_MANIFEST_NAME)
345  return true;
346  }
347  }
348  catch(fs::filesystem_error& e)
349  {
350  // suppress logging of error message if reading of directory failed
351  // due to missing permission
352  if(e.code().value() != EACCES)
353  {
354  logWarn(std::string("error while crawling ") + path + ": " + e.what() + "; " + e.code().message());
355  }
356  }
357  return false;
358 }
359 
360 void
361 Rosstackage::crawl(std::vector<std::string> search_path,
362  bool force)
363 {
364  if(!force)
365  {
366  bool same_search_paths = (search_path == search_paths_);
367 
368  // if search paths differ, try to reading the cache corresponding to the new paths
369  if(!same_search_paths && readCache())
370  {
371  // If the cache was valid, then the paths in the cache match the ones
372  // we've been asked to crawl. Store them, so that later, methods
373  // like find() can refer to them when recrawling.
374  search_paths_ = search_path;
375  return;
376  }
377 
378  if(crawled_ && same_search_paths)
379  return;
380  }
381 
382  // We're about to crawl, so clear internal storage (in case this is the second
383  // run in this process).
384  clearStackages();
385  search_paths_ = search_path;
386 
387  std::vector<DirectoryCrawlRecord*> dummy;
388  boost::unordered_set<std::string> dummy2;
389  for(std::vector<std::string>::const_iterator p = search_paths_.begin();
390  p != search_paths_.end();
391  ++p)
392  crawlDetail(*p, force, 1, false, dummy, dummy2);
393 
394  crawled_ = true;
395 
396  writeCache();
397 }
398 
399 bool
400 Rosstackage::inStackage(std::string& name)
401 {
402  fs::path path;
403  try
404  {
405  // Search upward, as suggested in #3697. This method is only used when
406  // a package is not given on the command-line, and so should not have
407  // performance impact in common usage.
408  for(fs::path path = fs::current_path();
409  !path.empty();
410  path = path.parent_path())
411  {
412  if(Rosstackage::isStackage(path.string()))
413  {
414 #if !defined(BOOST_FILESYSTEM_VERSION) || (BOOST_FILESYSTEM_VERSION == 2)
415  name = fs::path(path).filename();
416 #else
417  // in boostfs3, filename() returns a path, which needs to be stringified
418  name = fs::path(path).filename().string();
419 #endif
420  return true;
421  }
422  }
423  // Search failed.
424  return false;
425  }
426  catch(fs::filesystem_error& e)
427  {
428  // can't determine current directory, or encountered trouble while
429  // searching upward; too bad
430  return false;
431  }
432 }
433 
434 
435 bool
436 Rosstackage::find(const std::string& name, std::string& path)
437 {
438  Stackage* s = findWithRecrawl(name);
439  if(s)
440  {
441  path = s->path_;
442  return true;
443  }
444  else
445  return false;
446 }
447 
448 bool
449 Rosstackage::contents(const std::string& name,
450  std::set<std::string>& packages)
451 {
452  Rospack rp2;
453  boost::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.find(name);
454  if(it != stackages_.end())
455  {
456  std::vector<std::string> search_paths;
457  search_paths.push_back(it->second->path_);
458  rp2.crawl(search_paths, true);
459  std::set<std::pair<std::string, std::string> > names_paths;
460  rp2.list(names_paths);
461  for(std::set<std::pair<std::string, std::string> >::const_iterator iit = names_paths.begin();
462  iit != names_paths.end();
463  ++iit)
464  packages.insert(iit->first);
465  return true;
466  }
467  else
468  {
469  logError(std::string("stack ") + name + " not found");
470  return false;
471  }
472 }
473 
474 bool
475 Rosstackage::contains(const std::string& name,
476  std::string& stack,
477  std::string& path)
478 {
479  Rospack rp2;
480  for(boost::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
481  it != stackages_.end();
482  ++it)
483  {
484  std::vector<std::string> search_paths;
485  search_paths.push_back(it->second->path_);
486  rp2.crawl(search_paths, true);
487  std::set<std::pair<std::string, std::string> > names_paths;
488  rp2.list(names_paths);
489  for(std::set<std::pair<std::string, std::string> >::const_iterator iit = names_paths.begin();
490  iit != names_paths.end();
491  ++iit)
492  {
493  if(iit->first == name)
494  {
495  stack = it->first;
496  path = it->second->path_;
497  return true;
498  }
499  }
500  }
501 
502  logError(std::string("stack containing package ") + name + " not found");
503  return false;
504 }
505 
506 void
507 Rosstackage::list(std::set<std::pair<std::string, std::string> >& list)
508 {
509  for(boost::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
510  it != stackages_.end();
511  ++it)
512  {
513  std::pair<std::string, std::string> item;
514  item.first = it->first;
515  item.second = it->second->path_;
516  list.insert(item);
517  }
518 }
519 
520 void
521 Rosstackage::listDuplicates(std::vector<std::string>& dups)
522 {
523  dups.resize(dups_.size());
524  int i = 0;
525  for(boost::unordered_map<std::string, std::vector<std::string> >::const_iterator it = dups_.begin();
526  it != dups_.end();
527  ++it)
528  {
529  dups[i] = it->first;
530  i++;
531  }
532 }
533 
534 void
535 Rosstackage::listDuplicatesWithPaths(std::map<std::string, std::vector<std::string> >& dups)
536 {
537  dups.clear();
538  for(boost::unordered_map<std::string, std::vector<std::string> >::const_iterator it = dups_.begin();
539  it != dups_.end();
540  ++it)
541  {
542  dups[it->first].resize(it->second.size());
543  int j = 0;
544  for(std::vector<std::string>::const_iterator jt = it->second.begin();
545  jt != it->second.end();
546  ++jt)
547  {
548  dups[it->first][j] = *jt;
549  j++;
550  }
551  }
552 }
553 
554 bool
555 Rosstackage::deps(const std::string& name, bool direct,
556  std::vector<std::string>& deps)
557 {
558  std::vector<Stackage*> stackages;
559  // Disable errors for the first try
560  bool old_quiet = quiet_;
561  bool result = true;
562  setQuiet(true);
563  if(!depsDetail(name, direct, stackages))
564  {
565  // Recrawl
566  crawl(search_paths_, true);
567  stackages.clear();
568  setQuiet(old_quiet);
569  if(!depsDetail(name, direct, stackages))
570  result = false;
571  }
572  setQuiet(old_quiet);
573  for(std::vector<Stackage*>::const_iterator it = stackages.begin();
574  it != stackages.end();
575  ++it)
576  deps.push_back((*it)->name_);
577  return result;
578 }
579 
580 bool
581 Rosstackage::depsOn(const std::string& name, bool direct,
582  std::vector<std::string>& deps)
583 {
584  std::vector<Stackage*> stackages;
585  bool result = depsOnDetail(name, direct, stackages);
586  for(std::vector<Stackage*>::const_iterator it = stackages.begin();
587  it != stackages.end();
588  ++it)
589  deps.push_back((*it)->name_);
590  return result;
591 }
592 
593 bool
594 Rosstackage::depsIndent(const std::string& name, bool direct,
595  std::vector<std::string>& deps)
596 {
597  Stackage* stackage = findWithRecrawl(name);
598  if(!stackage)
599  return false;
600  bool result = true;
601  try
602  {
603  result = computeDeps(stackage);
604  std::vector<Stackage*> deps_vec;
605  boost::unordered_set<Stackage*> deps_hash;
606  std::vector<std::string> indented_deps;
607  gatherDepsFull(stackage, direct, POSTORDER, 0, deps_hash, deps_vec, true, indented_deps);
608  for(std::vector<std::string>::const_iterator it = indented_deps.begin();
609  it != indented_deps.end();
610  ++it)
611  deps.push_back(*it);
612  }
613  catch(Exception& e)
614  {
615  logError(e.what());
616  return false;
617  }
618  return result;
619 }
620 
621 bool
622 Rosstackage::depsWhy(const std::string& from,
623  const std::string& to,
624  std::string& output)
625 {
626  Stackage* from_s = findWithRecrawl(from);
627  if(!from_s)
628  return false;
629  Stackage* to_s = findWithRecrawl(to);
630  if(!to_s)
631  return false;
632 
633  bool result = true;
634  std::list<std::list<Stackage*> > acc_list;
635  try
636  {
637  result = depsWhyDetail(from_s, to_s, acc_list);
638  }
639  catch(Exception& e)
640  {
641  logError(e.what());
642  return true;
643  }
644  output.append(std::string("Dependency chains from ") +
645  from + " to " + to + ":\n");
646  for(std::list<std::list<Stackage*> >::const_iterator it = acc_list.begin();
647  it != acc_list.end();
648  ++it)
649  {
650  output.append("* ");
651  for(std::list<Stackage*>::const_iterator iit = it->begin();
652  iit != it->end();
653  ++iit)
654  {
655  if(iit != it->begin())
656  output.append("-> ");
657  output.append((*iit)->name_ + " ");
658  }
659  output.append("\n");
660  }
661  return result;
662 }
663 
664 bool
665 Rosstackage::depsManifests(const std::string& name, bool direct,
666  std::vector<std::string>& manifests)
667 {
668  Stackage* stackage = findWithRecrawl(name);
669  if(!stackage)
670  return false;
671  bool result = true;
672  try
673  {
674  result = computeDeps(stackage);
675  std::vector<Stackage*> deps_vec;
676  gatherDeps(stackage, direct, POSTORDER, deps_vec);
677  for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
678  it != deps_vec.end();
679  ++it)
680  manifests.push_back((*it)->manifest_path_);
681  }
682  catch(Exception& e)
683  {
684  logError(e.what());
685  return false;
686  }
687  return result;
688 }
689 
690 bool
691 Rosstackage::rosdeps(const std::string& name, bool direct,
692  std::set<std::string>& rosdeps)
693 {
694  Stackage* stackage = findWithRecrawl(name);
695  if(!stackage)
696  return false;
697  bool result = true;
698  try
699  {
700  result = computeDeps(stackage);
701  std::vector<Stackage*> deps_vec;
702  // rosdeps include the current package
703  deps_vec.push_back(stackage);
704  if(!direct)
705  gatherDeps(stackage, direct, POSTORDER, deps_vec);
706  for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
707  it != deps_vec.end();
708  ++it)
709  {
710  if (!stackage->is_wet_package_)
711  {
713  }
714  else
715  {
716  // package format 1 tags
717  _rosdeps(*it, rosdeps, "build_depend");
718  _rosdeps(*it, rosdeps, "buildtool_depend");
719  _rosdeps(*it, rosdeps, "run_depend");
720  // package format 2 tags
721  _rosdeps(*it, rosdeps, "build_export_depend");
722  _rosdeps(*it, rosdeps, "buildtool_export_depend");
723  _rosdeps(*it, rosdeps, "exec_depend");
724  _rosdeps(*it, rosdeps, "depend");
725  _rosdeps(*it, rosdeps, "doc_depend");
726  _rosdeps(*it, rosdeps, "test_depend");
727  }
728  }
729  }
730  catch(Exception& e)
731  {
732  logError(e.what());
733  return false;
734  }
735  return result;
736 }
737 
738 void
739 Rosstackage::_rosdeps(Stackage* stackage, std::set<std::string>& rosdeps, const char* tag_name)
740 {
741  tinyxml2::XMLElement* root = get_manifest_root(stackage);
742  for(tinyxml2::XMLElement* ele = root->FirstChildElement(tag_name);
743  ele;
744  ele = ele->NextSiblingElement(tag_name))
745  {
746  if(!stackage->is_wet_package_)
747  {
748  const char *att_str;
749  if((att_str = ele->Attribute(MANIFEST_ATTR_NAME)))
750  {
751  rosdeps.insert(std::string("name: ") + att_str);
752  }
753  }
754  else
755  {
756  const char* dep_pkgname = ele->GetText();
757  if(isSysPackage(dep_pkgname))
758  {
759  rosdeps.insert(std::string("name: ") + dep_pkgname);
760  }
761  }
762  }
763 }
764 
765 bool
766 Rosstackage::vcs(const std::string& name, bool direct,
767  std::vector<std::string>& vcs)
768 {
769  Stackage* stackage = findWithRecrawl(name);
770  if(!stackage)
771  return false;
772  bool result = true;
773  try
774  {
775  result = computeDeps(stackage);
776  std::vector<Stackage*> deps_vec;
777  // vcs include the current package
778  deps_vec.push_back(stackage);
779  if(!direct)
780  gatherDeps(stackage, direct, POSTORDER, deps_vec);
781  for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
782  it != deps_vec.end();
783  ++it)
784  {
785  tinyxml2::XMLElement* root = get_manifest_root(*it);
786  for(tinyxml2::XMLElement* ele = root->FirstChildElement(MANIFEST_TAG_VERSIONCONTROL);
787  ele;
788  ele = ele->NextSiblingElement(MANIFEST_TAG_VERSIONCONTROL))
789  {
790  std::string result;
791  const char *att_str;
792  if((att_str = ele->Attribute(MANIFEST_ATTR_TYPE)))
793  {
794  result.append("type: ");
795  result.append(att_str);
796  }
797  if((att_str = ele->Attribute(MANIFEST_ATTR_URL)))
798  {
799  result.append("\turl: ");
800  result.append(att_str);
801  }
802  vcs.push_back(result);
803  }
804  }
805  }
806  catch(Exception& e)
807  {
808  logError(e.what());
809  return false;
810  }
811  return result;
812 }
813 
814 bool
815 Rosstackage::cpp_exports(const std::string& name, const std::string& type,
816  const std::string& attrib, bool deps_only,
817  std::vector<std::pair<std::string, bool> >& flags)
818 {
819  Stackage* stackage = findWithRecrawl(name);
820  if(!stackage)
821  return false;
822 
823  static bool init_py = false;
824  static PyObject* pName;
825  static PyObject* pModule;
826  static PyObject* pDict;
827  static PyObject* pFunc;
828 
829  bool result = true;
830  try
831  {
832  result = computeDeps(stackage);
833  std::vector<Stackage*> deps_vec;
834  if(!deps_only)
835  deps_vec.push_back(stackage);
836  gatherDeps(stackage, false, PREORDER, deps_vec, true);
837  for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
838  it != deps_vec.end();
839  ++it)
840  {
841  if(!(*it)->is_wet_package_)
842  {
843  std::vector<std::string> dry_flags;
844  if(!exports_dry_package(*it, "cpp", attrib, dry_flags))
845  {
846  return false;
847  }
848  for(std::vector<std::string>::const_iterator it = dry_flags.begin(); it != dry_flags.end(); ++it)
849  {
850  flags.push_back(std::pair<std::string, bool>(*it, false));
851  }
852  }
853  else
854  {
855  initPython();
856  PyGILState_STATE gstate = PyGILState_Ensure();
857 
858  if(!init_py)
859  {
860  init_py = true;
861  pName = PyUnicode_FromString("rosdep2.rospack");
862  pModule = PyImport_Import(pName);
863  if(!pModule)
864  {
865  PyErr_Print();
866  PyGILState_Release(gstate);
867  std::string errmsg = "could not find python module 'rosdep2.rospack'. is rosdep up-to-date (at least 0.10.4)?";
868  throw Exception(errmsg);
869  }
870  pDict = PyModule_GetDict(pModule);
871  pFunc = PyDict_GetItemString(pDict, "call_pkg_config");
872  }
873 
874  if(!PyCallable_Check(pFunc))
875  {
876  PyErr_Print();
877  PyGILState_Release(gstate);
878  std::string errmsg = "could not find python function 'rosdep2.rospack.call_pkg_config'. is rosdep up-to-date (at least 0.10.7)?";
879  throw Exception(errmsg);
880  }
881 
882  PyObject* pArgs = PyTuple_New(2);
883  PyObject* pOpt = PyUnicode_FromString(type.c_str());
884  PyTuple_SetItem(pArgs, 0, pOpt);
885  PyObject* pPkg = PyUnicode_FromString((*it)->name_.c_str());
886  PyTuple_SetItem(pArgs, 1, pPkg);
887  PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
888  Py_DECREF(pArgs);
889 
890  if(!pValue)
891  {
892  PyErr_Print();
893  PyGILState_Release(gstate);
894  std::string errmsg = "could not call python function 'rosdep2.rospack.call_pkg_config'";
895  throw Exception(errmsg);
896  }
897  if(pValue == Py_None)
898  {
899  Py_DECREF(pValue);
900  std::string errmsg = "python function 'rosdep2.rospack.call_pkg_config' could not call 'pkg-config " + type + " " + (*it)->name_ + "' without errors";
901  throw Exception(errmsg);
902  }
903 
904  flags.push_back(std::pair<std::string, bool>(PyBytes_AsString(pValue), true));
905  Py_DECREF(pValue);
906 
907  // we want to keep the static objects alive for repeated access
908  // so skip all garbage collection until process ends
909  //Py_DECREF(pFunc);
910  //Py_DECREF(pModule);
911  //Py_DECREF(pName);
912  //Py_Finalize();
913 
914  PyGILState_Release(gstate);
915  }
916  }
917  }
918  catch(Exception& e)
919  {
920  logError(e.what());
921  return false;
922  }
923  return result;
924 }
925 
926 bool
927 Rosstackage::reorder_paths(const std::string& paths, std::string& reordered)
928 {
929  static bool init_py = false;
930  static PyObject* pName;
931  static PyObject* pModule;
932  static PyObject* pFunc;
933 
934  initPython();
935  PyGILState_STATE gstate = PyGILState_Ensure();
936 
937  if(!init_py)
938  {
939  init_py = true;
940  pName = PyUnicode_FromString("catkin_pkg.rospack");
941  pModule = PyImport_Import(pName);
942  if(!pModule)
943  {
944  PyErr_Print();
945  PyGILState_Release(gstate);
946  std::string errmsg = "could not find python module 'catkin_pkg.rospack'. is catkin_pkg up-to-date (at least 0.1.8)?";
947  throw Exception(errmsg);
948  }
949  PyObject* pDict = PyModule_GetDict(pModule);
950  pFunc = PyDict_GetItemString(pDict, "reorder_paths");
951  }
952 
953  if(!PyCallable_Check(pFunc))
954  {
955  PyErr_Print();
956  PyGILState_Release(gstate);
957  std::string errmsg = "could not find python function 'catkin_pkg.rospack.reorder_paths'. is catkin_pkg up-to-date (at least 0.1.8)?";
958  throw Exception(errmsg);
959  }
960 
961 
962  PyObject* pArgs = PyTuple_New(1);
963  PyTuple_SetItem(pArgs, 0, PyUnicode_FromString(paths.c_str()));
964  PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
965  Py_DECREF(pArgs);
966 
967  if(!pValue)
968  {
969  PyErr_Print();
970  PyGILState_Release(gstate);
971  std::string errmsg = "could not call python function 'catkin_pkg.rospack.reorder_paths'";
972  throw Exception(errmsg);
973  }
974 
975  reordered = PyUnicode_AsUTF8(pValue);
976  Py_DECREF(pValue);
977 
978  // we want to keep the static objects alive for repeated access
979  // so skip all garbage collection until process ends
980  //Py_DECREF(pFunc);
981  //Py_DECREF(pModule);
982  //Py_DECREF(pName);
983  //Py_Finalize();
984 
985  PyGILState_Release(gstate);
986 
987  return true;
988 }
989 
990 bool
991 Rosstackage::exports(const std::string& name, const std::string& lang,
992  const std::string& attrib, bool deps_only,
993  std::vector<std::string>& flags)
994 {
995  Stackage* stackage = findWithRecrawl(name);
996  if(!stackage)
997  return false;
998  bool result = true;
999  try
1000  {
1001  result = computeDeps(stackage);
1002  std::vector<Stackage*> deps_vec;
1003  if(!deps_only)
1004  deps_vec.push_back(stackage);
1005  gatherDeps(stackage, false, PREORDER, deps_vec);
1006  for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
1007  it != deps_vec.end();
1008  ++it)
1009  {
1010  if (!exports_dry_package(*it, lang, attrib, flags))
1011  {
1012  return false;
1013  }
1014  }
1015  }
1016  catch(Exception& e)
1017  {
1018  logError(e.what());
1019  return false;
1020  }
1021  return result;
1022 }
1023 
1024 bool
1025 Rosstackage::exports_dry_package(Stackage* stackage, const std::string& lang,
1026  const std::string& attrib,
1027  std::vector<std::string>& flags)
1028 {
1029  tinyxml2::XMLElement* root = get_manifest_root(stackage);
1030  for(tinyxml2::XMLElement* ele = root->FirstChildElement(MANIFEST_TAG_EXPORT);
1031  ele;
1032  ele = ele->NextSiblingElement(MANIFEST_TAG_EXPORT))
1033  {
1034  bool os_match = false;
1035  const char *best_match = NULL;
1036  for(tinyxml2::XMLElement* ele2 = ele->FirstChildElement(lang.c_str());
1037  ele2;
1038  ele2 = ele2->NextSiblingElement(lang.c_str()))
1039  {
1040  const char *os_str;
1041  if ((os_str = ele2->Attribute("os")))
1042  {
1043  if(g_ros_os == std::string(os_str))
1044  {
1045  if(os_match)
1046  logWarn(std::string("ignoring duplicate ") + lang + " tag with os=" + os_str + " in export block");
1047  else
1048  {
1049  best_match = ele2->Attribute(attrib.c_str());
1050  os_match = true;
1051  }
1052  }
1053  }
1054  if(!os_match)
1055  {
1056  if(!best_match)
1057  best_match = ele2->Attribute(attrib.c_str());
1058  else
1059  logWarn(std::string("ignoring duplicate ") + lang + " tag in export block");
1060  }
1061 
1062  }
1063  if(best_match)
1064  {
1065  std::string expanded_str;
1066  if(!expandExportString(stackage, best_match, expanded_str))
1067  return false;
1068  flags.push_back(expanded_str);
1069  }
1070  }
1071  // We automatically point to msg_gen and msg_srv directories if
1072  // certain files are present.
1073  // But only if we're looking for cpp/cflags, #3884.
1074  if((lang == "cpp") && (attrib == "cflags"))
1075  {
1076  fs::path msg_gen = fs::path(stackage->path_) / MSG_GEN_GENERATED_DIR;
1077  fs::path srv_gen = fs::path(stackage->path_) / SRV_GEN_GENERATED_DIR;
1078  if(fs::is_regular_file(msg_gen / MSG_GEN_GENERATED_FILE))
1079  {
1080  msg_gen /= fs::path("cpp") / "include";
1081  flags.push_back(std::string("-I" + msg_gen.string()));
1082  }
1083  if(fs::is_regular_file(srv_gen / SRV_GEN_GENERATED_FILE))
1084  {
1085  srv_gen /= fs::path("cpp") / "include";
1086  flags.push_back(std::string("-I" + srv_gen.string()));
1087  }
1088  }
1089  return true;
1090 }
1091 
1092 bool
1093 Rosstackage::plugins(const std::string& name, const std::string& attrib,
1094  const std::string& top,
1095  std::vector<std::string>& flags)
1096 {
1097  // Find everybody who depends directly on the package in question
1098  std::vector<Stackage*> stackages;
1099  bool result = depsOnDetail(name, true, stackages, true);
1100  // Also look in the package itself
1101  boost::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.find(name);
1102  if(it != stackages_.end())
1103  {
1104  // don't warn here; it was done in depsOnDetail()
1105  stackages.push_back(it->second);
1106  }
1107  // If top was given, filter to include only those package on which top
1108  // depends.
1109  if(top.size())
1110  {
1111  std::vector<Stackage*> top_deps;
1112  result &= depsDetail(top, false, top_deps);
1113  boost::unordered_set<Stackage*> top_deps_set;
1114  for(std::vector<Stackage*>::iterator it = top_deps.begin();
1115  it != top_deps.end();
1116  ++it)
1117  top_deps_set.insert(*it);
1118  std::vector<Stackage*>::iterator it = stackages.begin();
1119  while(it != stackages.end())
1120  {
1121  if((*it)->name_ != top &&
1122  (top_deps_set.find(*it) == top_deps_set.end()))
1123  it = stackages.erase(it);
1124  else
1125  ++it;
1126  }
1127  }
1128  // Now go looking for the manifest data
1129  for(std::vector<Stackage*>::const_iterator it = stackages.begin();
1130  it != stackages.end();
1131  ++it)
1132  {
1133  tinyxml2::XMLElement* root = get_manifest_root(*it);
1134  for(tinyxml2::XMLElement* ele = root->FirstChildElement(MANIFEST_TAG_EXPORT);
1135  ele;
1136  ele = ele->NextSiblingElement(MANIFEST_TAG_EXPORT))
1137  {
1138  for(tinyxml2::XMLElement* ele2 = ele->FirstChildElement(name.c_str());
1139  ele2;
1140  ele2 = ele2->NextSiblingElement(name.c_str()))
1141  {
1142  const char *att_str;
1143  if((att_str = ele2->Attribute(attrib.c_str())))
1144  {
1145  std::string expanded_str;
1146  if(!expandExportString(*it, att_str, expanded_str))
1147  {
1148  result = false;
1149  continue;
1150  }
1151  flags.push_back((*it)->name_ + " " + expanded_str);
1152  }
1153  }
1154  }
1155  }
1156  return result;
1157 }
1158 
1159 bool
1160 Rosstackage::depsMsgSrv(const std::string& name, bool direct,
1161  std::vector<std::string>& gens)
1162 {
1163  Stackage* stackage = findWithRecrawl(name);
1164  if(!stackage)
1165  return false;
1166  bool result = true;
1167  try
1168  {
1169  result = computeDeps(stackage);
1170  std::vector<Stackage*> deps_vec;
1171  gatherDeps(stackage, direct, POSTORDER, deps_vec);
1172  for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
1173  it != deps_vec.end();
1174  ++it)
1175  {
1176  fs::path msg_gen = fs::path((*it)->path_) /
1179  fs::path srv_gen = fs::path((*it)->path_) /
1182  if(fs::is_regular_file(msg_gen))
1183  gens.push_back(msg_gen.string());
1184  if(fs::is_regular_file(srv_gen))
1185  gens.push_back(srv_gen.string());
1186  }
1187  }
1188  catch(Exception& e)
1189  {
1190  logError(e.what());
1191  return false;
1192  }
1193  return result;
1194 }
1195 
1197 // Rosstackage methods (private)
1199 
1200 void
1201 Rosstackage::log(const std::string& level,
1202  const std::string& msg,
1203  bool append_errno)
1204 {
1205  if(quiet_)
1206  return;
1207  fprintf(stderr, "[%s] %s: %s",
1208  name_.c_str(), level.c_str(), msg.c_str());
1209  if(append_errno)
1210  fprintf(stderr, ": %s", strerror(errno));
1211  fprintf(stderr, "\n");
1212 }
1213 
1214 
1215 Stackage*
1216 Rosstackage::findWithRecrawl(const std::string& name)
1217 {
1218  if(stackages_.count(name))
1219  return stackages_[name];
1220  else
1221  {
1222  // Try to recrawl, in case we loaded from cache
1223  crawl(search_paths_, true);
1224  if(stackages_.count(name))
1225  return stackages_[name];
1226  }
1227 
1228  logError(get_manifest_type() + " '" + name + "' not found");
1229  return NULL;
1230 }
1231 
1232 bool
1233 Rosstackage::depsDetail(const std::string& name, bool direct,
1234  std::vector<Stackage*>& deps)
1235 {
1236  // No recrawl here, because we're in a recursive function. Rely on the
1237  // top level to do it.
1238  if(!stackages_.count(name))
1239  {
1240  logError(std::string("no such package ") + name);
1241  return false;
1242  }
1243  Stackage* stackage = stackages_[name];
1244  bool result = true;
1245  try
1246  {
1247  result = computeDeps(stackage);
1248  std::vector<Stackage*> deps_vec;
1249  gatherDeps(stackage, direct, POSTORDER, deps_vec);
1250  for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
1251  it != deps_vec.end();
1252  ++it)
1253  deps.push_back(*it);
1254  }
1255  catch(Exception& e)
1256  {
1257  logError(e.what());
1258  return false;
1259  }
1260  return result;
1261 }
1262 
1263 bool
1265  Stackage* to,
1266  std::list<std::list<Stackage*> >& acc_list)
1267 {
1268  bool result = computeDeps(from);
1269  for(std::vector<Stackage*>::const_iterator it = from->deps_.begin();
1270  it != from->deps_.end();
1271  ++it)
1272  {
1273  if((*it)->name_ == to->name_)
1274  {
1275  std::list<Stackage*> acc;
1276  acc.push_back(from);
1277  acc.push_back(to);
1278  acc_list.push_back(acc);
1279  }
1280  else
1281  {
1282  std::list<std::list<Stackage*> > l;
1283  result &= depsWhyDetail(*it, to, l);
1284  for(std::list<std::list<Stackage*> >::iterator iit = l.begin();
1285  iit != l.end();
1286  ++iit)
1287  {
1288  iit->push_front(from);
1289  acc_list.push_back(*iit);
1290  }
1291  }
1292  }
1293  return result;
1294 }
1295 
1296 bool
1297 Rosstackage::depsOnDetail(const std::string& name, bool direct,
1298  std::vector<Stackage*>& deps, bool ignore_missing)
1299 {
1300  // No recrawl here, because depends-on always forces a crawl at the
1301  // start.
1302  if(!stackages_.count(name))
1303  {
1304  logError(std::string("no such package ") + name);
1305  return false;
1306  }
1307  try
1308  {
1309  for(boost::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
1310  it != stackages_.end();
1311  ++it)
1312  {
1313  computeDeps(it->second, true, ignore_missing);
1314  std::vector<Stackage*> deps_vec;
1315  gatherDeps(it->second, direct, POSTORDER, deps_vec);
1316  for(std::vector<Stackage*>::const_iterator iit = deps_vec.begin();
1317  iit != deps_vec.end();
1318  ++iit)
1319  {
1320  if((*iit)->name_ == name)
1321  {
1322  deps.push_back(it->second);
1323  break;
1324  }
1325  }
1326  }
1327  }
1328  catch(Exception& e)
1329  {
1330  logError(e.what());
1331  return false;
1332  }
1333  return true;
1334 }
1335 
1336 bool
1337 Rosstackage::profile(const std::vector<std::string>& search_path,
1338  bool zombie_only,
1339  int length,
1340  std::vector<std::string>& dirs)
1341 {
1342  double start = time_since_epoch();
1343  std::vector<DirectoryCrawlRecord*> dcrs;
1344  boost::unordered_set<std::string> dcrs_hash;
1345  for(std::vector<std::string>::const_iterator p = search_path.begin();
1346  p != search_path.end();
1347  ++p)
1348  {
1349  crawlDetail(*p, true, 1, true, dcrs, dcrs_hash);
1350  }
1351  if(!zombie_only)
1352  {
1353  double total = time_since_epoch() - start;
1354  char buf[16];
1355  snprintf(buf, sizeof(buf), "%.6f", total);
1356  dirs.push_back(std::string("Full tree crawl took ") + buf + " seconds.");
1357  dirs.push_back("Directories marked with (*) contain no manifest. You may");
1358  dirs.push_back("want to delete these directories.");
1359  dirs.push_back("To get just of list of directories without manifests,");
1360  dirs.push_back("re-run the profile with --zombie-only");
1361  dirs.push_back("-------------------------------------------------------------");
1362  }
1363  std::sort(dcrs.begin(), dcrs.end(), cmpDirectoryCrawlRecord);
1364  std::reverse(dcrs.begin(), dcrs.end());
1365  int i=0;
1366  for(std::vector<DirectoryCrawlRecord*>::const_iterator it = dcrs.begin();
1367  it != dcrs.end();
1368  ++it)
1369  {
1370  if(zombie_only)
1371  {
1372  if((*it)->zombie_)
1373  {
1374  if(length < 0 || i < length)
1375  dirs.push_back((*it)->path_);
1376  i++;
1377  }
1378  }
1379  else
1380  {
1381  char buf[16];
1382  snprintf(buf, sizeof(buf), "%.6f", (*it)->crawl_time_);
1383  if(length < 0 || i < length)
1384  dirs.push_back(std::string(buf) + " " +
1385  ((*it)->zombie_ ? "* " : " ") +
1386  (*it)->path_);
1387  i++;
1388  }
1389  delete *it;
1390  }
1391 
1392  writeCache();
1393  return 0;
1394 }
1395 
1396 void
1397 Rosstackage::addStackage(const std::string& path)
1398 {
1399 #if !defined(BOOST_FILESYSTEM_VERSION) || (BOOST_FILESYSTEM_VERSION == 2)
1400  std::string name = fs::path(path).filename();
1401 #else
1402  // in boostfs3, filename() returns a path, which needs to be stringified
1403  std::string name = fs::path(path).filename().string();
1404 #endif
1405 
1406  Stackage* stackage = 0;
1407  fs::path dry_manifest_path = fs::path(path) / manifest_name_;
1408  fs::path wet_manifest_path = fs::path(path) / ROSPACKAGE_MANIFEST_NAME;
1409  if(fs::is_regular_file(dry_manifest_path))
1410  {
1411  stackage = new Stackage(name, path, dry_manifest_path.string(), manifest_name_);
1412  }
1413  else if(fs::is_regular_file(wet_manifest_path))
1414  {
1415  stackage = new Stackage(name, path, wet_manifest_path.string(), ROSPACKAGE_MANIFEST_NAME);
1416  loadManifest(stackage);
1417  stackage->update_wet_information();
1418  }
1419  else
1420  {
1421  return;
1422  }
1423 
1424  // skip the stackage if it is not of correct type
1425  if( (stackage->is_wet_package_ &&
1427  (!stackage->is_wet_package_ &&
1428  (manifest_name_ == ROSSTACK_MANIFEST_NAME && stackage->isPackage()) ||
1429  (manifest_name_ == ROSPACK_MANIFEST_NAME && stackage->isStack())) )
1430  {
1431  delete stackage;
1432  return;
1433  }
1434 
1435  if(stackages_.find(stackage->name_) != stackages_.end())
1436  {
1437  if (dups_.find(stackage->name_) == dups_.end())
1438  {
1439  std::vector<std::string> dups;
1440  dups.push_back(stackages_[stackage->name_]->path_);
1441  dups_[stackage->name_] = dups;
1442  }
1443  dups_[stackage->name_].push_back(stackage->path_);
1444  delete stackage;
1445  return;
1446  }
1447 
1448  stackages_[stackage->name_] = stackage;
1449 }
1450 
1451 void
1452 Rosstackage::crawlDetail(const std::string& path,
1453  bool force,
1454  int depth,
1455  bool collect_profile_data,
1456  std::vector<DirectoryCrawlRecord*>& profile_data,
1457  boost::unordered_set<std::string>& profile_hash)
1458 {
1459  if(depth > MAX_CRAWL_DEPTH)
1460  throw Exception("maximum depth exceeded during crawl");
1461 
1462  try
1463  {
1464  if(!fs::is_directory(path))
1465  return;
1466  }
1467  catch(fs::filesystem_error& e)
1468  {
1469  logWarn(std::string("error while looking at ") + path + ": " + e.what());
1470  return;
1471  }
1472 
1473  fs::path catkin_ignore = fs::path(path) / CATKIN_IGNORE;
1474  try
1475  {
1476  if(fs::is_regular_file(catkin_ignore))
1477  return;
1478  }
1479  catch(fs::filesystem_error& e)
1480  {
1481  logWarn(std::string("error while looking for ") + catkin_ignore.string() + ": " + e.what());
1482  }
1483 
1484  if(isStackage(path))
1485  {
1486  addStackage(path);
1487  return;
1488  }
1489 
1490  fs::path nosubdirs = fs::path(path) / ROSPACK_NOSUBDIRS;
1491  try
1492  {
1493  if(fs::is_regular_file(nosubdirs))
1494  return;
1495  }
1496  catch(fs::filesystem_error& e)
1497  {
1498  logWarn(std::string("error while looking for ") + nosubdirs.string() + ": " + e.what());
1499  }
1500 
1501  // We've already checked above whether CWD contains the kind of manifest
1502  // we're looking for. Don't recurse if we encounter a rospack manifest,
1503  // to avoid having rosstack finding stacks inside packages, #3816.
1504  fs::path rospack_manifest = fs::path(path) / ROSPACK_MANIFEST_NAME;
1505  try
1506  {
1507  if(fs::is_regular_file(rospack_manifest))
1508  return;
1509  }
1510  catch(fs::filesystem_error& e)
1511  {
1512  logWarn(std::string("error while looking for ") + rospack_manifest.string() + ": " + e.what());
1513  }
1514 
1515  DirectoryCrawlRecord* dcr = NULL;
1516  if(collect_profile_data)
1517  {
1518  if(profile_hash.find(path) == profile_hash.end())
1519  {
1520  dcr = new DirectoryCrawlRecord(path,
1521  time_since_epoch(),
1522  stackages_.size());
1523  profile_data.push_back(dcr);
1524  profile_hash.insert(path);
1525  }
1526  }
1527 
1528  try
1529  {
1530  for(fs::directory_iterator dit = fs::directory_iterator(path);
1531  dit != fs::directory_iterator();
1532  ++dit)
1533  {
1534  if(fs::is_directory(dit->path()))
1535  {
1536 #if !defined(BOOST_FILESYSTEM_VERSION) || (BOOST_FILESYSTEM_VERSION == 2)
1537  std::string name = dit->path().filename();
1538 #else
1539  // in boostfs3, filename() returns a path, which needs to be stringified
1540  std::string name = dit->path().filename().string();
1541 #endif
1542  // Ignore directories starting with '.'
1543  if(name.size() == 0 || name[0] == '.')
1544  continue;
1545 
1546  crawlDetail(dit->path().string(), force, depth+1,
1547  collect_profile_data, profile_data, profile_hash);
1548  }
1549  }
1550  }
1551  catch(fs::filesystem_error& e)
1552  {
1553  // suppress logging of error message if reading of directory failed
1554  // due to missing permission
1555  if(e.code().value() != EACCES)
1556  {
1557  logWarn(std::string("error while crawling ") + path + ": " + e.what());
1558  }
1559  }
1560 
1561  if(collect_profile_data && dcr != NULL)
1562  {
1563  // Measure the elapsed time
1564  dcr->crawl_time_ = time_since_epoch() - dcr->start_time_;
1565  // If the number of packages didn't change while crawling,
1566  // then this directory is a zombie
1567  if(stackages_.size() == dcr->start_num_pkgs_)
1568  dcr->zombie_ = true;
1569  }
1570 }
1571 
1572 void
1574 {
1575  if(stackage->manifest_loaded_)
1576  return;
1577 
1578  if(stackage->manifest_.LoadFile(stackage->manifest_path_.c_str()) != tinyxml2::XML_SUCCESS)
1579  {
1580  std::string errmsg = std::string("error parsing manifest of package ") +
1581  stackage->name_ + " at " + stackage->manifest_path_;
1582  throw Exception(errmsg);
1583  }
1584  stackage->manifest_loaded_ = true;
1585 }
1586 
1587 bool
1588 Rosstackage::computeDeps(Stackage* stackage, bool ignore_errors, bool ignore_missing)
1589 {
1590  if(stackage->deps_computed_)
1591  return true;
1592 
1593  try
1594  {
1595  loadManifest(stackage);
1596  get_manifest_root(stackage);
1597  }
1598  catch(Exception& e)
1599  {
1600  if(!ignore_errors && !quiet_)
1601  logError(e.what());
1602  return false;
1603  }
1604  if (!stackage->is_wet_package_)
1605  {
1606  if (!computeDepsInternal(stackage, ignore_errors, "depend", ignore_missing))
1607  return false;
1608  stackage->deps_computed_ = true;
1609  return true;
1610  }
1611  // package format 1 tags
1612  bool result = computeDepsInternal(stackage, ignore_errors, "run_depend", ignore_missing);
1613  // package format 2 tags
1614  result &= computeDepsInternal(stackage, ignore_errors, "exec_depend", ignore_missing);
1615  result &= computeDepsInternal(stackage, ignore_errors, "depend", ignore_missing);
1616  if (result)
1617  stackage->deps_computed_ = true;
1618  return result;
1619 }
1620 
1621 bool
1622 Rosstackage::computeDepsInternal(Stackage* stackage, bool ignore_errors, const std::string& depend_tag, bool ignore_missing)
1623 {
1624  tinyxml2::XMLElement* root;
1625  root = get_manifest_root(stackage);
1626 
1627  bool result = true;
1628  const char* dep_pkgname;
1629  for(tinyxml2::XMLElement *dep_ele = root->FirstChildElement(depend_tag.c_str());
1630  dep_ele;
1631  dep_ele = dep_ele->NextSiblingElement(depend_tag.c_str()))
1632  {
1633  if (!stackage->is_wet_package_)
1634  {
1635  dep_pkgname = dep_ele->Attribute(tag_.c_str());
1636  }
1637  else
1638  {
1639  dep_pkgname = dep_ele->GetText();
1640  }
1641  if(!dep_pkgname)
1642  {
1643  result = false;
1644  if(!ignore_errors && !quiet_)
1645  {
1646  std::string errmsg = std::string("bad depend syntax (no 'package/stack' attribute) in manifest ") + stackage->name_ + " at " + stackage->manifest_path_;
1647  logError(errmsg);
1648  }
1649  }
1650  else if(dep_pkgname == stackage->name_)
1651  {
1652  result = false;
1653  if(!ignore_errors && !quiet_)
1654  {
1655  std::string errmsg = get_manifest_type() + " '" + stackage->name_ + "' depends on itself";
1656  logError(errmsg);
1657  }
1658  }
1659  else if(!stackages_.count(dep_pkgname))
1660  {
1661  if (stackage->is_wet_package_ && (ignore_missing || isSysPackage(dep_pkgname)))
1662  {
1663  continue;
1664  }
1665  result = false;
1666  if(ignore_errors)
1667  {
1668  Stackage* dep = new Stackage(dep_pkgname, "", "", "");
1669  stackage->deps_.push_back(dep);
1670  }
1671  else if (!quiet_)
1672  {
1673  std::string errmsg = get_manifest_type() + " '" + stackage->name_ + "' depends on non-existent package '" + dep_pkgname + "' and rosdep claims that it is not a system dependency. Check the ROS_PACKAGE_PATH or try calling 'rosdep update'";
1674  logError(errmsg);
1675  }
1676  }
1677  else
1678  {
1679  Stackage* dep = stackages_[dep_pkgname];
1680  if (std::find(stackage->deps_.begin(), stackage->deps_.end(), dep) == stackage->deps_.end())
1681  {
1682  stackage->deps_.push_back(dep);
1683  result &= computeDeps(dep, ignore_errors, ignore_missing);
1684  }
1685  }
1686  }
1687  return result;
1688 }
1689 
1690 void
1692 {
1693  static bool initialized = false;
1694  if(!initialized)
1695  {
1696  initialized = true;
1697  Py_InitializeEx(0);
1698  }
1699 }
1700 
1701 bool
1702 Rosstackage::isSysPackage(const std::string& pkgname)
1703 {
1704  static std::map<std::string, bool> cache;
1705  if(cache.find(pkgname) != cache.end())
1706  {
1707  return cache.find(pkgname)->second;
1708  }
1709 
1710  initPython();
1711  PyGILState_STATE gstate = PyGILState_Ensure();
1712 
1713  static PyObject* pModule = 0;
1714  static PyObject* pDict = 0;
1715  if(!pModule)
1716  {
1717  PyObject* pName = PyUnicode_FromString("rosdep2.rospack");
1718  pModule = PyImport_Import(pName);
1719  Py_DECREF(pName);
1720  if(!pModule)
1721  {
1722  PyErr_Print();
1723  PyGILState_Release(gstate);
1724  std::string errmsg = "could not find python module 'rosdep2.rospack'. is rosdep up-to-date (at least 0.10.4)?";
1725  throw Exception(errmsg);
1726  }
1727  pDict = PyModule_GetDict(pModule);
1728  }
1729 
1730  static PyObject* pView = 0;
1731  if(!pView)
1732  {
1733  PyObject* pFunc = PyDict_GetItemString(pDict, "init_rospack_interface");
1734  if(!PyCallable_Check(pFunc))
1735  {
1736  PyErr_Print();
1737  PyGILState_Release(gstate);
1738  std::string errmsg = "could not find python function 'rosdep2.rospack.init_rospack_interface'. is rosdep up-to-date (at least 0.10.4)?";
1739  throw Exception(errmsg);
1740  }
1741  pView = PyObject_CallObject(pFunc, NULL);
1742  if(!pView)
1743  {
1744  PyErr_Print();
1745  PyGILState_Release(gstate);
1746  std::string errmsg = "could not call python function 'rosdep2.rospack.init_rospack_interface'";
1747  throw Exception(errmsg);
1748  }
1749  }
1750  static bool rospack_view_not_empty = false;
1751  if(!rospack_view_not_empty)
1752  {
1753  PyObject* pFunc = PyDict_GetItemString(pDict, "is_view_empty");
1754  if(!PyCallable_Check(pFunc))
1755  {
1756  PyErr_Print();
1757  PyGILState_Release(gstate);
1758  std::string errmsg = "could not find python function 'rosdep2.rospack.is_view_empty'. is rosdep up-to-date (at least 0.10.8)?";
1759  throw Exception(errmsg);
1760  }
1761  PyObject* pArgs = PyTuple_New(1);
1762  PyTuple_SetItem(pArgs, 0, pView);
1763  PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
1764  Py_INCREF(pView); // in order to keep the view when garbaging pArgs
1765  Py_DECREF(pArgs);
1766  if(PyObject_IsTrue(pValue))
1767  {
1768  PyErr_Print();
1769  PyGILState_Release(gstate);
1770  std::string errmsg = "the rosdep view is empty: call 'sudo rosdep init' and 'rosdep update'";
1771  throw Exception(errmsg);
1772  }
1773  rospack_view_not_empty = true;
1774  }
1775 
1776  PyObject* pFunc = PyDict_GetItemString(pDict, "is_system_dependency");
1777  if(!PyCallable_Check(pFunc))
1778  {
1779  PyErr_Print();
1780  PyGILState_Release(gstate);
1781  std::string errmsg = "could not call python function 'rosdep2.rospack.is_system_dependency'. is rosdep up-to-date (at least 0.10.4)?";
1782  throw Exception(errmsg);
1783  }
1784 
1785  PyObject* pArgs = PyTuple_New(2);
1786  PyTuple_SetItem(pArgs, 0, pView);
1787  PyObject* pDep = PyUnicode_FromString(pkgname.c_str());
1788  PyTuple_SetItem(pArgs, 1, pDep);
1789  PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
1790  Py_INCREF(pView); // in order to keep the view when garbaging pArgs
1791  Py_DECREF(pArgs);
1792 
1793  bool value = PyObject_IsTrue(pValue);
1794  Py_DECREF(pValue);
1795 
1796  // we want to keep the static objects alive for repeated access
1797  // so skip all garbage collection until process ends
1798  //Py_DECREF(pView);
1799  //Py_DECREF(pDict);
1800  //Py_DECREF(pModule);
1801  //Py_Finalize();
1802 
1803  PyGILState_Release(gstate);
1804 
1805  cache[pkgname] = value;
1806 
1807  return value;
1808 }
1809 
1810 void
1811 Rosstackage::gatherDeps(Stackage* stackage, bool direct,
1812  traversal_order_t order,
1813  std::vector<Stackage*>& deps,
1814  bool no_recursion_on_wet)
1815 {
1816  boost::unordered_set<Stackage*> deps_hash;
1817  std::vector<std::string> indented_deps;
1818  gatherDepsFull(stackage, direct, order, 0,
1819  deps_hash, deps, false, indented_deps, no_recursion_on_wet);
1820 }
1821 
1822 void
1823 _gatherDepsFull(Stackage* stackage, bool direct,
1824  traversal_order_t order, int depth,
1825  boost::unordered_set<Stackage*>& deps_hash,
1826  std::vector<Stackage*>& deps,
1827  bool get_indented_deps,
1828  std::vector<std::string>& indented_deps,
1829  bool no_recursion_on_wet,
1830  std::vector<std::string>& dep_chain)
1831 {
1832  if(stackage->is_wet_package_ && no_recursion_on_wet)
1833  {
1834  return;
1835  }
1836 
1837  if(direct && (stackage->is_wet_package_ || !no_recursion_on_wet))
1838  {
1839  for(std::vector<Stackage*>::const_iterator it = stackage->deps_.begin();
1840  it != stackage->deps_.end();
1841  ++it)
1842  deps.push_back(*it);
1843  return;
1844  }
1845 
1846  if(depth > MAX_DEPENDENCY_DEPTH) {
1847  std::string cycle;
1848  for(std::vector<std::string>::const_iterator it = dep_chain.begin();
1849  it != dep_chain.end();
1850  ++it)
1851  {
1852  std::vector<std::string>::const_iterator begin = dep_chain.begin();
1853  std::vector<std::string>::const_iterator cycle_begin = std::find(begin, it, *it);
1854  if(cycle_begin != it) {
1855  cycle = ": ";
1856  for(std::vector<std::string>::const_iterator jt = cycle_begin; jt != it; ++jt) {
1857  if(jt != cycle_begin) cycle += ", ";
1858  cycle += *jt;
1859  }
1860  break;
1861  }
1862  }
1863  throw Exception(std::string("maximum dependency depth exceeded (likely circular dependency") + cycle + ")");
1864  }
1865 
1866  for(std::vector<Stackage*>::const_iterator it = stackage->deps_.begin();
1867  it != stackage->deps_.end();
1868  ++it)
1869  {
1870  if(get_indented_deps)
1871  {
1872  std::string indented_dep;
1873  for(int i=0; i<depth; i++)
1874  indented_dep.append(" ");
1875  indented_dep.append((*it)->name_);
1876  indented_deps.push_back(indented_dep);
1877  }
1878 
1879  bool first = (deps_hash.find(*it) == deps_hash.end());
1880  if(first)
1881  {
1882  deps_hash.insert(*it);
1883  // We maintain the vector because the original rospack guaranteed
1884  // ordering in dep reporting.
1885  if(order == PREORDER)
1886  deps.push_back(*it);
1887  }
1888  if(!(*it)->is_wet_package_ || !no_recursion_on_wet)
1889  {
1890  // We always descend, even if we're encountering this stackage for the
1891  // nth time, so that we'll throw an error on recursive dependencies
1892  // (detected via max stack depth being exceeded).
1893  dep_chain.push_back((*it)->name_);
1894  _gatherDepsFull(*it, direct, order, depth+1, deps_hash, deps,
1895  get_indented_deps, indented_deps,
1896  no_recursion_on_wet, dep_chain);
1897  dep_chain.pop_back();
1898  }
1899  if(first)
1900  {
1901  if(order == POSTORDER)
1902  deps.push_back(*it);
1903  }
1904  }
1905 }
1906 
1907 // Pre-condition: computeDeps(stackage) succeeded
1908 void
1909 Rosstackage::gatherDepsFull(Stackage* stackage, bool direct,
1910  traversal_order_t order, int depth,
1911  boost::unordered_set<Stackage*>& deps_hash,
1912  std::vector<Stackage*>& deps,
1913  bool get_indented_deps,
1914  std::vector<std::string>& indented_deps,
1915  bool no_recursion_on_wet)
1916 {
1917  std::vector<std::string> dep_chain;
1918  dep_chain.push_back(stackage->name_);
1919  _gatherDepsFull(stackage, direct,
1920  order, depth,
1921  deps_hash,
1922  deps,
1923  get_indented_deps,
1924  indented_deps,
1925  no_recursion_on_wet,
1926  dep_chain);
1927 }
1928 
1929 std::string
1931 {
1932  fs::path cache_path;
1933 
1934  char* ros_home = getenv("ROS_HOME");
1935  if(ros_home)
1936  cache_path = ros_home;
1937  else
1938  {
1939  // Get the user's home directory by looking up the password entry based
1940  // on UID. If that doesn't work, we fall back on examining $HOME,
1941  // knowing that that can cause trouble when mixed with sudo (#2884).
1942 #if defined(WIN32)
1943  char* home_drive = getenv("HOMEDRIVE");
1944  char* home_path = getenv("HOMEPATH");
1945  if(home_drive && home_path)
1946  cache_path = fs::path(home_drive) / fs::path(home_path) / fs::path(DOTROS_NAME);
1947 #else // UNIX
1948  char* home_path;
1949  struct passwd* passwd_ent;
1950  // Look up based on effective UID, just in case we got here by set-uid
1951  if((passwd_ent = getpwuid(geteuid())))
1952  home_path = passwd_ent->pw_dir;
1953  else
1954  home_path = getenv("HOME");
1955  if(home_path)
1956  cache_path = fs::path(home_path) / fs::path(DOTROS_NAME);
1957 #endif
1958  }
1959 
1960  // If it doesn't exist, create the directory that will hold the cache
1961  try
1962  {
1963  if(!fs::is_directory(cache_path))
1964  {
1965  fs::create_directory(cache_path);
1966  }
1967  }
1968  catch(fs::filesystem_error& e)
1969  {
1970  logWarn(std::string("cannot create rospack cache directory ") +
1971  cache_path.string() + ": " + e.what());
1972  }
1973  cache_path /= cache_prefix_ + "_" + getCacheHash();
1974  return cache_path.string();
1975 }
1976 
1977 std::string
1979 {
1980  size_t value = 0;
1981  char* rpp = getenv("ROS_PACKAGE_PATH");
1982  if(rpp != NULL) {
1983  boost::hash<std::string> hash_func;
1984  value = hash_func(rpp);
1985  }
1986  char buffer[21];
1987  snprintf(buffer, 21, "%020lu", value);
1988  return buffer;
1989 }
1990 
1991 bool
1993 {
1994  FILE* cache = validateCache();
1995  if(cache)
1996  {
1997  // We're about to read from the cache, so clear internal storage (in case this is
1998  // the second run in this process).
1999  clearStackages();
2000  char linebuf[30000];
2001  for(;;)
2002  {
2003  if (!fgets(linebuf, sizeof(linebuf), cache))
2004  break; // error in read operation
2005  if (linebuf[0] == '#')
2006  continue;
2007  char* newline_pos = strchr(linebuf, '\n');
2008  if(newline_pos)
2009  *newline_pos = 0;
2010  addStackage(linebuf);
2011  }
2012  fclose(cache);
2013  return true;
2014  }
2015  else
2016  return false;
2017 }
2018 
2019 // TODO: replace the contents of the method with some fancy cross-platform
2020 // boost thing.
2021 void
2023 {
2024  // Write the results of this crawl to the cache file. At each step, give
2025  // up on error, printing a warning to stderr.
2026  std::string cache_path = getCachePath();
2027  if(!cache_path.size())
2028  {
2029  logWarn("no location available to write cache file. Try setting ROS_HOME or HOME.");
2030  }
2031  else
2032  {
2033  size_t len = cache_path.size() + 1;
2034  char *tmp_cache_dir = new char[len];
2035  strncpy(tmp_cache_dir, cache_path.c_str(), len);
2036 #if defined(_MSC_VER)
2037  // No dirname on Windows; use _splitpath_s instead
2038  char tmp_cache_path[PATH_MAX];
2039  char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
2040  _splitpath_s(tmp_cache_dir, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME,
2041  ext, _MAX_EXT);
2042  char full_dir[_MAX_DRIVE + _MAX_DIR];
2043  _makepath_s(full_dir, _MAX_DRIVE + _MAX_DIR, drive, dir, NULL, NULL);
2044  snprintf(tmp_cache_path, sizeof(tmp_cache_path), "%s\\.rospack_cache.XXXXXX", full_dir);
2045 #elif defined(__MINGW32__)
2046  char tmp_cache_path[PATH_MAX];
2047  char* temp_name = tempnam(dirname(tmp_cache_dir),".rospack_cache.");
2048  snprintf(tmp_cache_path, sizeof(tmp_cache_path), temp_name);
2049  delete temp_name;
2050 #else
2051  char *temp_dirname = dirname(tmp_cache_dir);
2052  len = strlen(temp_dirname) + 22 + 1;
2053  char *tmp_cache_path = new char[len];
2054  snprintf(tmp_cache_path, len, "%s/.rospack_cache.XXXXXX", temp_dirname);
2055 #endif
2056 #if defined(__MINGW32__)
2057  // There is no equivalent of mkstemp or _mktemp_s on mingw, so we resort to a slightly problematic
2058  // tempnam (above) and mktemp method. This has the miniscule chance of a race condition.
2059  int fd = open(tmp_cache_path, O_RDWR | O_EXCL | _O_CREAT, 0644);
2060  if (fd < 0)
2061  {
2062  logWarn(std::string("unable to create temporary cache file ") +
2063  tmp_cache_path, true);
2064  }
2065  else
2066  {
2067  FILE *cache = fdopen(fd, "w");
2068 #elif defined(WIN32)
2069  if (_mktemp_s(tmp_cache_path, PATH_MAX) != 0)
2070  {
2071  fprintf(stderr,
2072  "[rospack] Unable to generate temporary cache file name: %u",
2073  GetLastError());
2074  }
2075  else
2076  {
2077  FILE *cache = fopen(tmp_cache_path, "w");
2078 #else
2079  mode_t mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
2080  int fd = mkstemp(tmp_cache_path);
2081  umask(mask);
2082  if (fd < 0)
2083  {
2084  fprintf(stderr, "[rospack] Unable to create temporary cache file %s: %s\n",
2085  tmp_cache_path, strerror(errno));
2086  }
2087  else
2088  {
2089  FILE *cache = fdopen(fd, "w");
2090 #endif
2091  if (!cache)
2092  {
2093  fprintf(stderr, "[rospack] Unable open cache file %s: %s\n",
2094  tmp_cache_path, strerror(errno));
2095  }
2096  else
2097  {
2098  char *rpp = getenv("ROS_PACKAGE_PATH");
2099  fprintf(cache, "#ROS_PACKAGE_PATH=%s\n", (rpp ? rpp : ""));
2100  for(boost::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
2101  it != stackages_.end();
2102  ++it)
2103  fprintf(cache, "%s\n", it->second->path_.c_str());
2104  fclose(cache);
2105  if(fs::exists(cache_path))
2106  remove(cache_path.c_str());
2107  if(rename(tmp_cache_path, cache_path.c_str()) < 0)
2108  {
2109  fprintf(stderr, "[rospack] Error: failed to rename cache file %s to %s: %s\n",
2110  tmp_cache_path, cache_path.c_str(), strerror(errno));
2111  }
2112  }
2113  }
2114  delete[] tmp_cache_dir;
2115 #if !defined(_MSC_VER) && !defined(__MINGW32__)
2116  delete[] tmp_cache_path;
2117 #endif
2118  }
2119 }
2120 
2121 FILE*
2123 {
2124  std::string cache_path = getCachePath();
2125  // first see if it's new enough
2126  double cache_max_age = DEFAULT_MAX_CACHE_AGE;
2127  const char *user_cache_time_str = getenv("ROS_CACHE_TIMEOUT");
2128  if(user_cache_time_str)
2129  cache_max_age = atof(user_cache_time_str);
2130  if(cache_max_age == 0.0)
2131  return NULL;
2132 
2133  // try to open it
2134  FILE* cache = fopen(cache_path.c_str(), "r");
2135  if(!cache)
2136  return NULL; // it's not readable by us. sad.
2137 
2138  struct stat s;
2139  if(fstat(fileno(cache), &s) == -1)
2140  {
2141  fclose(cache);
2142  return NULL;
2143  }
2144 
2145  double dt = difftime(time(NULL), s.st_mtime);
2146  // Negative cache_max_age means it's always new enough. It's dangerous
2147  // for the user to set this, but rosbash uses it.
2148  if ((cache_max_age > 0.0) && (dt > cache_max_age))
2149  {
2150  fclose(cache);
2151  return NULL;
2152  }
2153 
2154  // see if ROS_PACKAGE_PATH matches
2155  char linebuf[30000];
2156  bool ros_package_path_ok = false;
2157  const char* ros_package_path = getenv("ROS_PACKAGE_PATH");
2158  for(;;)
2159  {
2160  if(!fgets(linebuf, sizeof(linebuf), cache))
2161  break;
2162  linebuf[strlen(linebuf)-1] = 0; // get rid of trailing newline
2163  if (linebuf[0] == '#')
2164  {
2165  if(!strncmp("#ROS_PACKAGE_PATH=", linebuf, 18))
2166  {
2167  if(!ros_package_path)
2168  {
2169  if(!strlen(linebuf+18))
2170  ros_package_path_ok = true;
2171  }
2172  else if(!strcmp(linebuf+18, ros_package_path))
2173  ros_package_path_ok = true;
2174  }
2175  }
2176  else
2177  break; // we're out of the header. nothing more matters to this check.
2178  }
2179  if(ros_package_path_ok)
2180  {
2181  // seek to the beginning and pass back the stream (instead of closing
2182  // and later reopening, which is a race condition, #1666)
2183  fseek(cache, 0, SEEK_SET);
2184  return cache;
2185  }
2186  else
2187  {
2188  fclose(cache);
2189  return NULL;
2190  }
2191 }
2192 
2193 bool
2195  const std::string& instring,
2196  std::string& outstring)
2197 {
2198  outstring = instring;
2199  for(std::string::size_type i = outstring.find(MANIFEST_PREFIX);
2200  i != std::string::npos;
2201  i = outstring.find(MANIFEST_PREFIX))
2202  {
2203  outstring.replace(i, std::string(MANIFEST_PREFIX).length(),
2204  stackage->path_);
2205  }
2206 
2207  // skip substitution attempt when the string neither contains
2208  // a dollar sign for $(command) and $envvar nor
2209  // a backtick wrapping a command
2210  if (outstring.find_first_of("$`") == std::string::npos)
2211  {
2212  return true;
2213  }
2214 
2215  // Do backquote substitution. E.g., if we find this string:
2216  // `pkg-config --cflags gdk-pixbuf-2.0`
2217  // We replace it with the result of executing the command
2218  // contained within the backquotes (reading from its stdout), which
2219  // might be something like:
2220  // -I/usr/include/gtk-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
2221 
2222  // Construct and execute the string
2223  // We do the assignment first to ensure that if backquote expansion (or
2224  // anything else) fails, we'll get a non-zero exit status from pclose().
2225  std::string cmd = std::string("ret=\"") + outstring + "\" && echo $ret";
2226 
2227  // Remove embedded newlines
2228  std::string token("\n");
2229  for (std::string::size_type s = cmd.find(token);
2230  s != std::string::npos;
2231  s = cmd.find(token, s))
2232  cmd.replace(s,token.length(),std::string(" "));
2233 
2234  FILE* p;
2235  if(!(p = popen(cmd.c_str(), "r")))
2236  {
2237  std::string errmsg =
2238  std::string("failed to execute backquote expression ") +
2239  cmd + " in " +
2240  stackage->manifest_path_;
2241  logWarn(errmsg, true);
2242  return false;
2243  }
2244  else
2245  {
2246  char buf[8192];
2247  memset(buf,0,sizeof(buf));
2248  // Read the command's output
2249  do
2250  {
2251  clearerr(p);
2252  while(fgets(buf + strlen(buf),sizeof(buf)-strlen(buf)-1,p));
2253  } while(ferror(p) && errno == EINTR);
2254  // Close the subprocess, checking exit status
2255  if(pclose(p) != 0)
2256  {
2257  std::string errmsg =
2258  std::string("got non-zero exit status from executing backquote expression ") +
2259  cmd + " in " +
2260  stackage->manifest_path_;
2261  return false;
2262  }
2263  else
2264  {
2265  // Strip trailing newline, which was added by our call to echo
2266  buf[strlen(buf)-1] = '\0';
2267  // Replace the backquote expression with the new text
2268  outstring = buf;
2269  }
2270  }
2271 
2272  return true;
2273 }
2274 
2276 // Rospack methods
2281  ROSPACK_NAME,
2283 {
2284 }
2285 
2286 const char*
2288 {
2289  return "USAGE: rospack <command> [options] [package]\n"
2290  " Allowed commands:\n"
2291  " help\n"
2292  " cflags-only-I [--deps-only] [package]\n"
2293  " cflags-only-other [--deps-only] [package]\n"
2294  " depends [package] (alias: deps)\n"
2295  " depends-indent [package] (alias: deps-indent)\n"
2296  " depends-manifests [package] (alias: deps-manifests)\n"
2297  " depends-msgsrv [package] (alias: deps-msgsrv)\n"
2298  " depends-on [package]\n"
2299  " depends-on1 [package]\n"
2300  " depends-why --target=<target> [package] (alias: deps-why)\n"
2301  " depends1 [package] (alias: deps1)\n"
2302  " export [--deps-only] --lang=<lang> --attrib=<attrib> [package]\n"
2303  " find [package]\n"
2304  " langs\n"
2305  " libs-only-L [--deps-only] [package]\n"
2306  " libs-only-l [--deps-only] [package]\n"
2307  " libs-only-other [--deps-only] [package]\n"
2308  " list\n"
2309  " list-duplicates\n"
2310  " list-names\n"
2311  " plugins --attrib=<attrib> [--top=<toppkg>] [package]\n"
2312  " profile [--length=<length>] [--zombie-only]\n"
2313  " rosdep [package] (alias: rosdeps)\n"
2314  " rosdep0 [package] (alias: rosdeps0)\n"
2315  " vcs [package]\n"
2316  " vcs0 [package]\n"
2317  " Extra options:\n"
2318  " -q Quiets error reports.\n\n"
2319  " If [package] is omitted, the current working directory\n"
2320  " is used (if it contains a package.xml or manifest.xml).\n\n";
2321 }
2322 
2324 {
2325  return "package";
2326 }
2327 
2329 // Rosstack methods
2334  ROSSTACK_NAME,
2336 {
2337 }
2338 
2339 const char*
2341 {
2342  return "USAGE: rosstack [options] <command> [stack]\n"
2343  " Allowed commands:\n"
2344  " help\n"
2345  " find [stack]\n"
2346  " contents [stack]\n"
2347  " list\n"
2348  " list-names\n"
2349  " depends [stack] (alias: deps)\n"
2350  " depends-manifests [stack] (alias: deps-manifests)\n"
2351  " depends1 [stack] (alias: deps1)\n"
2352  " depends-indent [stack] (alias: deps-indent)\n"
2353  " depends-why --target=<target> [stack] (alias: deps-why)\n"
2354  " depends-on [stack]\n"
2355  " depends-on1 [stack]\n"
2356  " contains [package]\n"
2357  " contains-path [package]\n"
2358  " profile [--length=<length>] \n\n"
2359  " If [stack] is omitted, the current working directory\n"
2360  " is used (if it contains a stack.xml).\n\n";
2361 }
2362 
2364 {
2365  return "stack";
2366 }
2367 
2368 tinyxml2::XMLElement*
2370 {
2371  tinyxml2::XMLElement* ele = stackage->manifest_.RootElement();
2372  if(!ele)
2373  {
2374  std::string errmsg = std::string("error parsing manifest of package ") +
2375  stackage->name_ + " at " + stackage->manifest_path_;
2376  throw Exception(errmsg);
2377  }
2378  return ele;
2379 }
2380 
2381 double
2383 {
2384 #if defined(WIN32)
2385  #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
2386  #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
2387  #else
2388  #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
2389  #endif
2390  FILETIME ft;
2391  unsigned __int64 tmpres = 0;
2392 
2393  GetSystemTimeAsFileTime(&ft);
2394  tmpres |= ft.dwHighDateTime;
2395  tmpres <<= 32;
2396  tmpres |= ft.dwLowDateTime;
2397  tmpres /= 10;
2398  tmpres -= DELTA_EPOCH_IN_MICROSECS;
2399  return static_cast<double>(tmpres) / 1e6;
2400 #else
2401  struct timeval tod;
2402  gettimeofday(&tod, NULL);
2403  return tod.tv_sec + 1e-6 * tod.tv_usec;
2404 #endif
2405 }
2406 
2407 
2408 
2409 } // namespace rospack
rospack::Exception::Exception
Exception(const std::string &what)
Definition: rospack.cpp:134
rospack::Rosstackage::depsManifests
bool depsManifests(const std::string &name, bool direct, std::vector< std::string > &manifests)
List the manifests of a stackage's dependencies. Used by rosbuild.
Definition: rospack.cpp:665
rospack::traversal_order_t
traversal_order_t
Definition: rospack.h:126
rospack::Rospack::usage
virtual const char * usage()
Usage statement.
Definition: rospack.cpp:2287
rospack::MANIFEST_PREFIX
static const char * MANIFEST_PREFIX
Definition: rospack.cpp:113
rospack::Rosstackage::writeCache
void writeCache()
Definition: rospack.cpp:2022
rospack::Rosstackage::listDuplicatesWithPaths
void listDuplicatesWithPaths(std::map< std::string, std::vector< std::string > > &dups)
Identify duplicate stackages and provide their paths. Forces crawl.
Definition: rospack.cpp:535
rospack::Rosstackage::rosdeps
bool rosdeps(const std::string &name, bool direct, std::set< std::string > &rosdeps)
Compute rosdep entries that are declared in manifest of a package and its dependencies....
Definition: rospack.cpp:691
rospack::Rosstack::usage
virtual const char * usage()
Usage statement.
Definition: rospack.cpp:2340
rospack::Rospack::Rospack
Rospack()
Constructor.
Definition: rospack.cpp:2278
rospack::Stackage::manifest_loaded_
bool manifest_loaded_
Definition: rospack.cpp:153
rospack::SRV_GEN_GENERATED_FILE
static const char * SRV_GEN_GENERATED_FILE
Definition: rospack.cpp:106
rospack::Rosstackage::computeDeps
bool computeDeps(Stackage *stackage, bool ignore_errors=false, bool ignore_missing=false)
Definition: rospack.cpp:1588
rospack::Rosstackage::getSearchPathFromEnv
bool getSearchPathFromEnv(std::vector< std::string > &sp)
Helper method to construct a directory search path by looking at relevant environment variables....
Definition: rospack.cpp:284
rospack::Rosstackage::isSysPackage
bool isSysPackage(const std::string &pkgname)
Definition: rospack.cpp:1702
rospack::DOTROS_NAME
static const char * DOTROS_NAME
Definition: rospack.cpp:102
rospack::Rosstackage::expandExportString
bool expandExportString(Stackage *stackage, const std::string &instring, std::string &outstring)
Definition: rospack.cpp:2194
rospack::Exception
Definition: rospack.cpp:131
rospack::Rospack
Package crawler. Create one of these to operate on a package tree. Call public methods inherited from...
Definition: rospack.h:560
rospack::MSG_GEN_GENERATED_FILE
static const char * MSG_GEN_GENERATED_FILE
Definition: rospack.cpp:104
rospack::Stackage::update_wet_information
void update_wet_information()
Definition: rospack.cpp:177
PyUnicode_FromString
#define PyUnicode_FromString
Definition: rospack.cpp:81
rospack::Rosstackage::_rosdeps
void _rosdeps(Stackage *stackage, std::set< std::string > &rosdeps, const char *tag_name)
Definition: rospack.cpp:739
rospack::DEFAULT_MAX_CACHE_AGE
static const double DEFAULT_MAX_CACHE_AGE
Definition: rospack.cpp:116
rospack::Rosstackage::depsOn
bool depsOn(const std::string &name, bool direct, std::vector< std::string > &deps)
Compute reverse dependencies of a stackage (i.e., stackages that depend on this stackage)....
Definition: rospack.cpp:581
rospack::Rosstackage::list
void list(std::set< std::pair< std::string, std::string > > &list)
List names and paths of all stackages.
Definition: rospack.cpp:507
rospack.h
PyBytes_AsString
#define PyBytes_AsString
defined(WIN32)
Definition: rospack.cpp:79
rospack::Stackage::is_wet_package_
bool is_wet_package_
Definition: rospack.cpp:158
rospack::Rosstackage::cache_prefix_
std::string cache_prefix_
Definition: rospack.h:145
rospack::Rosstackage::computeDepsInternal
bool computeDepsInternal(Stackage *stackage, bool ignore_errors, const std::string &depend_tag, bool ignore_missing=false)
Definition: rospack.cpp:1622
rospack::DirectoryCrawlRecord::start_num_pkgs_
size_t start_num_pkgs_
Definition: rospack.cpp:222
rospack::Rosstackage::depsIndent
bool depsIndent(const std::string &name, bool direct, std::vector< std::string > &deps)
Definition: rospack.cpp:594
rospack::Rosstackage::cpp_exports
bool cpp_exports(const std::string &name, const std::string &type, const std::string &attrib, bool deps_only, std::vector< std::pair< std::string, bool > > &flags)
Compute cpp exports declared in a package and its dependencies. Used by rosbuild.
Definition: rospack.cpp:815
rospack::Rosstackage::plugins
bool plugins(const std::string &name, const std::string &attrib, const std::string &top, std::vector< std::string > &flags)
Compute exported plugins declared in packages that depend on a package. Forces crawl....
Definition: rospack.cpp:1093
rospack::ROSSTACK_MANIFEST_NAME
static const char * ROSSTACK_MANIFEST_NAME
Definition: rospack.cpp:97
rospack::Rosstackage::findWithRecrawl
Stackage * findWithRecrawl(const std::string &name)
Definition: rospack.cpp:1216
rospack::Rosstackage::find
bool find(const std::string &name, std::string &path)
Look for a stackage.
Definition: rospack.cpp:436
rospack::ROSPACK_MANIFEST_NAME
static const char * ROSPACK_MANIFEST_NAME
Definition: rospack.cpp:95
rospack::ROSPACK_NOSUBDIRS
static const char * ROSPACK_NOSUBDIRS
Definition: rospack.cpp:100
rospack::Stackage::licenses_
std::vector< std::string > licenses_
Definition: rospack.cpp:151
rospack::Rosstackage::log
void log(const std::string &level, const std::string &msg, bool append_errno)
Definition: rospack.cpp:1201
rospack::Rosstackage::vcs
bool vcs(const std::string &name, bool direct, std::vector< std::string > &vcs)
Compute vcs entries that are declared in manifest of a package and its dependencies....
Definition: rospack.cpp:766
rospack::Rosstackage::Rosstackage
Rosstackage(const std::string &manifest_name, const std::string &cache_prefix, const std::string &name, const std::string &tag)
Constructor, only used by derived classes.
Definition: rospack.cpp:241
rospack::Rosstack::Rosstack
Rosstack()
Constructor.
Definition: rospack.cpp:2331
rospack::PREORDER
@ PREORDER
Definition: rospack.h:129
rospack::Rosstackage::logError
void logError(const std::string &msg, bool append_errno=false)
Log a error (usually goes to stderr).
Definition: rospack.cpp:277
rospack::MANIFEST_TAG_EXPORT
static const char * MANIFEST_TAG_EXPORT
Definition: rospack.cpp:109
rospack::MANIFEST_ATTR_NAME
static const char * MANIFEST_ATTR_NAME
Definition: rospack.cpp:110
rospack::Stackage::isPackage
bool isPackage() const
Definition: rospack.cpp:208
rospack::MANIFEST_TAG_ROSDEP
static const char * MANIFEST_TAG_ROSDEP
Definition: rospack.cpp:107
rospack::Rosstackage::profile
bool profile(const std::vector< std::string > &search_path, bool zombie_only, int length, std::vector< std::string > &dirs)
Definition: rospack.cpp:1337
rospack::Rosstackage::name_
std::string name_
Definition: rospack.h:147
rospack::get_manifest_root
tinyxml2::XMLElement * get_manifest_root(Stackage *stackage)
Definition: rospack.cpp:2369
rospack::Rosstackage::addStackage
void addStackage(const std::string &path)
Definition: rospack.cpp:1397
rospack::Rosstackage::quiet_
bool quiet_
Definition: rospack.h:149
rospack::Rosstackage::crawl
void crawl(std::vector< std::string > search_path, bool force)
Crawl the filesystem, accumulating a database of stackages. May read results from a cache file instea...
Definition: rospack.cpp:361
rospack::Rosstackage::logWarn
void logWarn(const std::string &msg, bool append_errno=false)
Log a warning (usually goes to stderr).
Definition: rospack.cpp:271
rospack::Stackage::Stackage
Stackage(const std::string &name, const std::string &path, const std::string &manifest_path, const std::string &manifest_name)
Definition: rospack.cpp:161
rospack::ROSPACKAGE_MANIFEST_NAME
static const char * ROSPACKAGE_MANIFEST_NAME
Definition: rospack.cpp:96
utils.h
rospack::Rosstackage::depsDetail
bool depsDetail(const std::string &name, bool direct, std::vector< Stackage * > &deps)
Compute dependencies of a stackage (i.e., stackages that this stackages depends on),...
Definition: rospack.cpp:1233
rospack::Rosstackage::validateCache
FILE * validateCache()
Definition: rospack.cpp:2122
rospack::Rospack::get_manifest_type
virtual std::string get_manifest_type()
Definition: rospack.cpp:2323
rospack::Stackage::manifest_
tinyxml2::XMLDocument manifest_
Definition: rospack.cpp:155
rospack::POSTORDER
@ POSTORDER
Definition: rospack.h:128
rospack::Rosstackage::inStackage
bool inStackage(std::string &name)
Is the current working directory a stackage?
Definition: rospack.cpp:400
rospack::Rosstackage::exports
bool exports(const std::string &name, const std::string &lang, const std::string &attrib, bool deps_only, std::vector< std::string > &flags)
Compute exports declared in a package and its dependencies. Used by rosbuild.
Definition: rospack.cpp:991
rospack::DirectoryCrawlRecord
Definition: rospack.cpp:215
rospack::CATKIN_IGNORE
static const char * CATKIN_IGNORE
Definition: rospack.cpp:101
rospack::MANIFEST_TAG_PACKAGE
static const char * MANIFEST_TAG_PACKAGE
Definition: rospack.cpp:93
rospack::DirectoryCrawlRecord::path_
std::string path_
Definition: rospack.cpp:218
rospack::Rosstackage::crawled_
bool crawled_
Definition: rospack.h:146
rospack::Stackage::path_
std::string path_
Definition: rospack.cpp:145
rospack::Rosstackage::getCachePath
std::string getCachePath()
Definition: rospack.cpp:1930
rospack::DirectoryCrawlRecord::zombie_
bool zombie_
Definition: rospack.cpp:219
rospack::Stackage::is_metapackage_
bool is_metapackage_
Definition: rospack.cpp:159
rospack::g_ros_os
static const std::string g_ros_os
Definition: rospack.cpp:127
rospack::Stackage::isStack
bool isStack() const
Definition: rospack.cpp:203
rospack::Rosstackage::contents
bool contents(const std::string &name, std::set< std::string > &packages)
Compute the packages that are contained in a stack.
Definition: rospack.cpp:449
rospack::MANIFEST_TAG_STACK
static const char * MANIFEST_TAG_STACK
Definition: rospack.cpp:94
rospack::Rosstackage::depsWhy
bool depsWhy(const std::string &from, const std::string &to, std::string &output)
Definition: rospack.cpp:622
rospack::Rosstackage::tag_
std::string tag_
Definition: rospack.h:148
rospack::Rosstackage::gatherDepsFull
void gatherDepsFull(Stackage *stackage, bool direct, traversal_order_t order, int depth, boost::unordered_set< Stackage * > &deps_hash, std::vector< Stackage * > &deps, bool get_indented_deps, std::vector< std::string > &indented_deps, bool no_recursion_on_wet=false)
Definition: rospack.cpp:1909
rospack::ROSSTACK_CACHE_PREFIX
static const char * ROSSTACK_CACHE_PREFIX
Definition: rospack.cpp:99
rospack::Rosstackage::depsOnDetail
bool depsOnDetail(const std::string &name, bool direct, std::vector< Stackage * > &deps, bool ignore_missing=false)
Compute reverse dependencies of a stackage (i.e., stackages that depend on this stackage),...
Definition: rospack.cpp:1297
rospack::Rosstackage::clearStackages
void clearStackages()
Definition: rospack.cpp:258
rospack::Rosstackage::gatherDeps
void gatherDeps(Stackage *stackage, bool direct, traversal_order_t order, std::vector< Stackage * > &deps, bool no_recursion_on_wet=false)
Definition: rospack.cpp:1811
rospack::Rosstackage::crawlDetail
void crawlDetail(const std::string &path, bool force, int depth, bool collect_profile_data, std::vector< DirectoryCrawlRecord * > &profile_data, boost::unordered_set< std::string > &profile_hash)
Definition: rospack.cpp:1452
rospack::Rosstackage::exports_dry_package
bool exports_dry_package(Stackage *stackage, const std::string &lang, const std::string &attrib, std::vector< std::string > &flags)
Compute exports declared in a dry package.
Definition: rospack.cpp:1025
rospack::MAX_DEPENDENCY_DEPTH
static const int MAX_DEPENDENCY_DEPTH
Definition: rospack.cpp:115
rospack::Rosstackage::initPython
void initPython()
Definition: rospack.cpp:1691
PyUnicode_AsUTF8
#define PyUnicode_AsUTF8
Definition: rospack.cpp:80
rospack::cmpDirectoryCrawlRecord
bool cmpDirectoryCrawlRecord(DirectoryCrawlRecord *i, DirectoryCrawlRecord *j)
Definition: rospack.cpp:232
rospack::Rosstackage::search_paths_
std::vector< std::string > search_paths_
Definition: rospack.h:150
rospack::Rosstackage::deps
bool deps(const std::string &name, bool direct, std::vector< std::string > &deps)
Compute dependencies of a stackage (i.e., stackages that this stackages depends on).
Definition: rospack.cpp:555
rospack::Stackage::manifest_name_
std::string manifest_name_
Definition: rospack.cpp:149
rospack::Rosstackage::setQuiet
void setQuiet(bool quiet)
Control warning and error console output.
Definition: rospack.cpp:312
rospack::Rosstackage::manifest_name_
std::string manifest_name_
Definition: rospack.h:144
rospack::MAX_CRAWL_DEPTH
static const int MAX_CRAWL_DEPTH
Definition: rospack.cpp:114
rospack::ROSPACK_CACHE_PREFIX
static const char * ROSPACK_CACHE_PREFIX
Definition: rospack.cpp:98
rospack::MANIFEST_ATTR_TYPE
static const char * MANIFEST_ATTR_TYPE
Definition: rospack.cpp:111
rospack
Definition: rospack.h:123
rospack::Rosstackage::depsMsgSrv
bool depsMsgSrv(const std::string &name, bool direct, std::vector< std::string > &gens)
List the marker files in a packages's dependencies that indicate that those packages contain auto-gen...
Definition: rospack.cpp:1160
rospack::Rosstackage::dups_
boost::unordered_map< std::string, std::vector< std::string > > dups_
Definition: rospack.h:151
rospack::Rosstackage
The base class for package/stack ("stackage") crawlers. Users of the library should use the functiona...
Definition: rospack.h:141
rospack::DirectoryCrawlRecord::crawl_time_
double crawl_time_
Definition: rospack.cpp:221
rospack::Rosstack::get_manifest_type
virtual std::string get_manifest_type()
Definition: rospack.cpp:2363
rospack::Rosstackage::readCache
bool readCache()
Definition: rospack.cpp:1992
rospack::Rosstackage::loadManifest
void loadManifest(Stackage *stackage)
Definition: rospack.cpp:1573
rospack::_gatherDepsFull
void _gatherDepsFull(Stackage *stackage, bool direct, traversal_order_t order, int depth, boost::unordered_set< Stackage * > &deps_hash, std::vector< Stackage * > &deps, bool get_indented_deps, std::vector< std::string > &indented_deps, bool no_recursion_on_wet, std::vector< std::string > &dep_chain)
Definition: rospack.cpp:1823
rospack::Stackage::name_
std::string name_
Definition: rospack.cpp:143
rospack::Rosstackage::~Rosstackage
virtual ~Rosstackage()
Destructor.
Definition: rospack.cpp:253
rospack::Stackage
Definition: rospack.cpp:139
rospack::ROSPACK_NAME
static const char * ROSPACK_NAME
Definition: utils.h:42
rospack::Rosstackage::reorder_paths
bool reorder_paths(const std::string &paths, std::string &reordered)
Reorder the paths according to the workspace chaining.
Definition: rospack.cpp:927
rospack::Stackage::deps_computed_
bool deps_computed_
Definition: rospack.cpp:157
rospack::Stackage::manifest_path_
std::string manifest_path_
Definition: rospack.cpp:147
rospack::MANIFEST_ATTR_URL
static const char * MANIFEST_ATTR_URL
Definition: rospack.cpp:112
rospack::Rosstackage::isStackage
bool isStackage(const std::string &path)
Definition: rospack.cpp:318
rospack::Rosstackage::depsWhyDetail
bool depsWhyDetail(Stackage *from, Stackage *to, std::list< std::list< Stackage * > > &acc_list)
Definition: rospack.cpp:1264
rospack::DirectoryCrawlRecord::DirectoryCrawlRecord
DirectoryCrawlRecord(std::string path, double start_time, size_t start_num_pkgs)
Definition: rospack.cpp:223
rospack::Rosstackage::stackages_
boost::unordered_map< std::string, Stackage * > stackages_
Definition: rospack.h:152
rospack::Rosstackage::get_manifest_type
virtual std::string get_manifest_type()
Definition: rospack.h:553
rospack::DirectoryCrawlRecord::start_time_
double start_time_
Definition: rospack.cpp:220
rospack::Rosstackage::listDuplicates
void listDuplicates(std::vector< std::string > &dups)
Identify duplicate stackages. Forces crawl.
Definition: rospack.cpp:521
rospack::MANIFEST_TAG_VERSIONCONTROL
static const char * MANIFEST_TAG_VERSIONCONTROL
Definition: rospack.cpp:108
rospack::time_since_epoch
double time_since_epoch()
Definition: rospack.cpp:2382
rospack::ROSSTACK_NAME
static const char * ROSSTACK_NAME
Definition: utils.h:43
rospack::SRV_GEN_GENERATED_DIR
static const char * SRV_GEN_GENERATED_DIR
Definition: rospack.cpp:105
rospack::MSG_GEN_GENERATED_DIR
static const char * MSG_GEN_GENERATED_DIR
Definition: rospack.cpp:103
rospack::Stackage::deps_
std::vector< Stackage * > deps_
Definition: rospack.cpp:156
rospack::Rosstackage::getCacheHash
std::string getCacheHash()
Definition: rospack.cpp:1978
rospack::Rosstackage::contains
bool contains(const std::string &name, std::string &stack, std::string &path)
Find the stack that contains a package.
Definition: rospack.cpp:475


rospack
Author(s): Brian Gerkey, Morgan Quigley, Dirk Thomas
autogenerated on Wed Mar 2 2022 00:54:50