00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "rospack/rospack.h"
00029 #include "utils.h"
00030 #include "tinyxml.h"
00031
00032 #include <boost/filesystem.hpp>
00033 #include <boost/algorithm/string.hpp>
00034 #include <stdexcept>
00035
00036 #if defined(WIN32)
00037 #include <windows.h>
00038 #include <direct.h>
00039 #include <fcntl.h>
00040
00041
00042
00043 #define snprintf _snprintf
00044 #define pclose _pclose
00045 #define popen _popen
00046 #define PATH_MAX MAX_PATH
00047 #if defined(__MINGW32__)
00048 #include <libgen.h>
00049 #endif
00050 #if defined(_MSC_VER)
00051 #include <io.h>
00052 #endif
00053 #else //!defined(WIN32)
00054 #include <sys/types.h>
00055 #include <libgen.h>
00056 #include <pwd.h>
00057 #include <unistd.h>
00058 #include <sys/time.h>
00059 #endif
00060
00061 #include <algorithm>
00062 #include <climits>
00063
00064 #include <sys/stat.h>
00065 #include <stdio.h>
00066 #include <stdlib.h>
00067 #include <time.h>
00068 #include <string.h>
00069 #include <errno.h>
00070
00071 #include <Python.h>
00072
00073
00074 #if PY_VERSION_HEX >= 0x03000000
00075 #define PyString_AsString PyBytes_AsString
00076 #define PyString_FromString PyBytes_FromString
00077 #endif
00078
00079
00080
00081
00082
00083
00084 namespace fs = boost::filesystem;
00085
00086 namespace rospack
00087 {
00088 static const char* MANIFEST_TAG_PACKAGE = "package";
00089 static const char* MANIFEST_TAG_STACK = "stack";
00090 static const char* ROSPACK_MANIFEST_NAME = "manifest.xml";
00091 static const char* ROSPACKAGE_MANIFEST_NAME = "package.xml";
00092 static const char* ROSSTACK_MANIFEST_NAME = "stack.xml";
00093 static const char* ROSPACK_CACHE_NAME = "rospack_cache";
00094 static const char* ROSSTACK_CACHE_NAME = "rosstack_cache";
00095 static const char* ROSPACK_NOSUBDIRS = "rospack_nosubdirs";
00096 static const char* CATKIN_IGNORE = "CATKIN_IGNORE";
00097 static const char* DOTROS_NAME = ".ros";
00098 static const char* MSG_GEN_GENERATED_DIR = "msg_gen";
00099 static const char* MSG_GEN_GENERATED_FILE = "generated";
00100 static const char* SRV_GEN_GENERATED_DIR = "srv_gen";
00101 static const char* SRV_GEN_GENERATED_FILE = "generated";
00102 static const char* MANIFEST_TAG_ROSDEP = "rosdep";
00103 static const char* MANIFEST_TAG_VERSIONCONTROL = "versioncontrol";
00104 static const char* MANIFEST_TAG_EXPORT = "export";
00105 static const char* MANIFEST_ATTR_NAME = "name";
00106 static const char* MANIFEST_ATTR_TYPE = "type";
00107 static const char* MANIFEST_ATTR_URL = "url";
00108 static const char* MANIFEST_PREFIX = "${prefix}";
00109 static const int MAX_CRAWL_DEPTH = 1000;
00110 static const int MAX_DEPENDENCY_DEPTH = 1000;
00111 static const double DEFAULT_MAX_CACHE_AGE = 60.0;
00112
00113 TiXmlElement* get_manifest_root(Stackage* stackage);
00114 double time_since_epoch();
00115
00116 #ifdef __APPLE__
00117 static const std::string g_ros_os = "osx";
00118 #else
00119 #if defined(WIN32)
00120 static const std::string g_ros_os = "win32";
00121 #else
00122 static const std::string g_ros_os = "linux";
00123 #endif
00124 #endif
00125
00126 class Exception : public std::runtime_error
00127 {
00128 public:
00129 Exception(const std::string& what)
00130 : std::runtime_error(what)
00131 {}
00132 };
00133
00134 class Stackage
00135 {
00136 public:
00137
00138 std::string name_;
00139
00140 std::string path_;
00141
00142 std::string manifest_path_;
00143
00144 std::string manifest_name_;
00145
00146 bool manifest_loaded_;
00147
00148 TiXmlDocument manifest_;
00149 std::vector<Stackage*> deps_;
00150 bool deps_computed_;
00151 bool is_wet_package_;
00152 bool is_metapackage_;
00153
00154 Stackage(const std::string& name,
00155 const std::string& path,
00156 const std::string& manifest_path,
00157 const std::string& manifest_name) :
00158 name_(name),
00159 path_(path),
00160 manifest_path_(manifest_path),
00161 manifest_name_(manifest_name),
00162 manifest_loaded_(false),
00163 deps_computed_(false),
00164 is_metapackage_(false)
00165 {
00166 is_wet_package_ = manifest_name_ == ROSPACKAGE_MANIFEST_NAME;
00167 }
00168
00169 void update_wet_information()
00170 {
00171 assert(is_wet_package_);
00172 assert(manifest_loaded_);
00173
00174 TiXmlElement* root = get_manifest_root(this);
00175 for(TiXmlElement* el = root->FirstChildElement("name"); el; el = el->NextSiblingElement("name"))
00176 {
00177 name_ = el->GetText();
00178 break;
00179 }
00180
00181 for(TiXmlElement* el = root->FirstChildElement("export"); el; el = el->NextSiblingElement("export"))
00182 {
00183 if(el->FirstChildElement("metapackage"))
00184 {
00185 is_metapackage_ = true;
00186 break;
00187 }
00188 }
00189 }
00190
00191 bool isStack() const
00192 {
00193 return manifest_name_ == MANIFEST_TAG_STACK || (is_wet_package_ && is_metapackage_);
00194 }
00195
00196 bool isPackage() const
00197 {
00198 return manifest_name_ == MANIFEST_TAG_PACKAGE || (is_wet_package_ && !is_metapackage_);
00199 }
00200
00201 };
00202
00203 class DirectoryCrawlRecord
00204 {
00205 public:
00206 std::string path_;
00207 bool zombie_;
00208 double start_time_;
00209 double crawl_time_;
00210 size_t start_num_pkgs_;
00211 DirectoryCrawlRecord(std::string path,
00212 double start_time,
00213 size_t start_num_pkgs) :
00214 path_(path),
00215 zombie_(false),
00216 start_time_(start_time),
00217 crawl_time_(0.0),
00218 start_num_pkgs_(start_num_pkgs) {}
00219 };
00220 bool cmpDirectoryCrawlRecord(DirectoryCrawlRecord* i,
00221 DirectoryCrawlRecord* j)
00222 {
00223 return (i->crawl_time_ < j->crawl_time_);
00224 }
00225
00227
00229 Rosstackage::Rosstackage(const std::string& manifest_name,
00230 const std::string& cache_name,
00231 const std::string& name,
00232 const std::string& tag) :
00233 manifest_name_(manifest_name),
00234 cache_name_(cache_name),
00235 crawled_(false),
00236 name_(name),
00237 tag_(tag)
00238 {
00239 }
00240
00241 void
00242 Rosstackage::logWarn(const std::string& msg,
00243 bool append_errno)
00244 {
00245 log("Warning", msg, append_errno);
00246 }
00247 void
00248 Rosstackage::logError(const std::string& msg,
00249 bool append_errno)
00250 {
00251 log("Error", msg, append_errno);
00252 }
00253
00254 bool
00255 Rosstackage::getSearchPathFromEnv(std::vector<std::string>& sp)
00256 {
00257 char* rr = getenv("ROS_ROOT");
00258 char* rpp = getenv("ROS_PACKAGE_PATH");
00259
00260
00261 if(rr)
00262 {
00263 try
00264 {
00265 if(fs::is_directory(rr))
00266 sp.push_back(rr);
00267 else
00268 logWarn(std::string("ROS_ROOT=") + rr + " is not a directory");
00269 }
00270 catch(fs::filesystem_error& e)
00271 {
00272 logWarn(std::string("error while looking at ROS_ROOT ") + rr + ": " + e.what());
00273 }
00274 }
00275 if(rpp)
00276 {
00277
00278
00279 #if defined(WIN32)
00280 const char *path_delim = ";";
00281 #else //!defined(WIN32)
00282 const char *path_delim = ":";
00283 #endif
00284
00285 std::vector<std::string> rpp_strings;
00286 boost::split(rpp_strings, rpp,
00287 boost::is_any_of(path_delim),
00288 boost::token_compress_on);
00289 for(std::vector<std::string>::const_iterator it = rpp_strings.begin();
00290 it != rpp_strings.end();
00291 ++it)
00292 {
00293 sp.push_back(*it);
00294 }
00295 }
00296 return true;
00297 }
00298
00299 void
00300 Rosstackage::setQuiet(bool quiet)
00301 {
00302 quiet_ = quiet;
00303 }
00304
00305 bool
00306 Rosstackage::isStackage(const std::string& path)
00307 {
00308 try
00309 {
00310 if(!fs::is_directory(path))
00311 return false;
00312 }
00313 catch(fs::filesystem_error& e)
00314 {
00315 logWarn(std::string("error while looking at ") + path + ": " + e.what());
00316 return false;
00317 }
00318
00319 try
00320 {
00321 for(fs::directory_iterator dit = fs::directory_iterator(path);
00322 dit != fs::directory_iterator();
00323 ++dit)
00324 {
00325 if(!fs::is_regular_file(dit->path()))
00326 continue;
00327
00328 if(dit->path().filename() == manifest_name_)
00329 return true;
00330
00331
00332 if(dit->path().filename() == ROSPACKAGE_MANIFEST_NAME)
00333 return true;
00334 }
00335 }
00336 catch(fs::filesystem_error& e)
00337 {
00338 logWarn(std::string("error while crawling ") + path + ": " + e.what());
00339 }
00340 return false;
00341 }
00342
00343 void
00344 Rosstackage::crawl(std::vector<std::string> search_path,
00345 bool force)
00346 {
00347 if(!force)
00348 {
00349 if(readCache())
00350 {
00351
00352
00353
00354 search_paths_.clear();
00355 for(std::vector<std::string>::const_iterator it = search_path.begin();
00356 it != search_path.end();
00357 ++it)
00358 search_paths_.push_back(*it);
00359 return;
00360 }
00361
00362 if(crawled_)
00363 {
00364 bool same_paths = true;
00365 if(search_paths_.size() != search_path.size())
00366 same_paths = false;
00367 else
00368 {
00369 for(unsigned int i=0; i<search_paths_.size(); i++)
00370 {
00371 if(search_paths_[i] != search_path[i])
00372 {
00373 same_paths = false;
00374 break;
00375 }
00376 }
00377 }
00378
00379 if(same_paths)
00380 return;
00381 }
00382 }
00383
00384
00385 std::tr1::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
00386 while(it != stackages_.end())
00387 {
00388 delete it->second;
00389 it = stackages_.erase(it);
00390 }
00391 dups_.clear();
00392 search_paths_.clear();
00393 for(std::vector<std::string>::const_iterator it = search_path.begin();
00394 it != search_path.end();
00395 ++it)
00396 search_paths_.push_back(*it);
00397
00398 std::vector<DirectoryCrawlRecord*> dummy;
00399 std::tr1::unordered_set<std::string> dummy2;
00400 for(std::vector<std::string>::const_iterator p = search_paths_.begin();
00401 p != search_paths_.end();
00402 ++p)
00403 crawlDetail(*p, force, 1, false, dummy, dummy2);
00404
00405 crawled_ = true;
00406
00407 writeCache();
00408 }
00409
00410 bool
00411 Rosstackage::inStackage(std::string& name)
00412 {
00413 fs::path path;
00414 try
00415 {
00416
00417
00418
00419 for(fs::path path = fs::current_path();
00420 !path.empty();
00421 path = path.parent_path())
00422 {
00423 if(Rosstackage::isStackage(path.string()))
00424 {
00425 #if !defined(BOOST_FILESYSTEM_VERSION) || (BOOST_FILESYSTEM_VERSION == 2)
00426 name = fs::path(path).filename();
00427 #else
00428
00429 name = fs::path(path).filename().string();
00430 #endif
00431 return true;
00432 }
00433 }
00434
00435 return false;
00436 }
00437 catch(fs::filesystem_error& e)
00438 {
00439
00440
00441 return false;
00442 }
00443 }
00444
00445
00446 bool
00447 Rosstackage::find(const std::string& name, std::string& path)
00448 {
00449 Stackage* s = findWithRecrawl(name);
00450 if(s)
00451 {
00452 path = s->path_;
00453 return true;
00454 }
00455 else
00456 return false;
00457 }
00458
00459 bool
00460 Rosstackage::contents(const std::string& name,
00461 std::set<std::string>& packages)
00462 {
00463 Rospack rp2;
00464 std::tr1::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.find(name);
00465 if(it != stackages_.end())
00466 {
00467 std::vector<std::string> search_paths;
00468 search_paths.push_back(it->second->path_);
00469 rp2.crawl(search_paths, true);
00470 std::set<std::pair<std::string, std::string> > names_paths;
00471 rp2.list(names_paths);
00472 for(std::set<std::pair<std::string, std::string> >::const_iterator iit = names_paths.begin();
00473 iit != names_paths.end();
00474 ++iit)
00475 packages.insert(iit->first);
00476 return true;
00477 }
00478 else
00479 {
00480 logError(std::string("stack ") + name + " not found");
00481 return false;
00482 }
00483 }
00484
00485 bool
00486 Rosstackage::contains(const std::string& name,
00487 std::string& stack,
00488 std::string& path)
00489 {
00490 Rospack rp2;
00491 for(std::tr1::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
00492 it != stackages_.end();
00493 ++it)
00494 {
00495 std::vector<std::string> search_paths;
00496 search_paths.push_back(it->second->path_);
00497 rp2.crawl(search_paths, true);
00498 std::set<std::pair<std::string, std::string> > names_paths;
00499 rp2.list(names_paths);
00500 for(std::set<std::pair<std::string, std::string> >::const_iterator iit = names_paths.begin();
00501 iit != names_paths.end();
00502 ++iit)
00503 {
00504 if(iit->first == name)
00505 {
00506 stack = it->first;
00507 path = it->second->path_;
00508 return true;
00509 }
00510 }
00511 }
00512
00513 logError(std::string("stack containing package ") + name + " not found");
00514 return false;
00515 }
00516
00517 void
00518 Rosstackage::list(std::set<std::pair<std::string, std::string> >& list)
00519 {
00520 for(std::tr1::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
00521 it != stackages_.end();
00522 ++it)
00523 {
00524 std::pair<std::string, std::string> item;
00525 item.first = it->first;
00526 item.second = it->second->path_;
00527 list.insert(item);
00528 }
00529 }
00530
00531 void
00532 Rosstackage::listDuplicates(std::vector<std::string>& dups)
00533 {
00534 dups.resize(dups_.size());
00535 int i = 0;
00536 for(std::tr1::unordered_map<std::string, std::vector<std::string> >::const_iterator it = dups_.begin();
00537 it != dups_.end();
00538 ++it)
00539 {
00540 dups[i] = it->first;
00541 i++;
00542 }
00543 }
00544
00545 void
00546 Rosstackage::listDuplicatesWithPaths(std::map<std::string, std::vector<std::string> >& dups)
00547 {
00548 dups.clear();
00549 for(std::tr1::unordered_map<std::string, std::vector<std::string> >::const_iterator it = dups_.begin();
00550 it != dups_.end();
00551 ++it)
00552 {
00553 dups[it->first].resize(it->second.size());
00554 int j = 0;
00555 for(std::vector<std::string>::const_iterator jt = it->second.begin();
00556 jt != it->second.end();
00557 ++jt)
00558 {
00559 dups[it->first][j] = *jt;
00560 j++;
00561 }
00562 }
00563 }
00564
00565 bool
00566 Rosstackage::deps(const std::string& name, bool direct,
00567 std::vector<std::string>& deps)
00568 {
00569 std::vector<Stackage*> stackages;
00570
00571 bool old_quiet = quiet_;
00572 setQuiet(true);
00573 if(!depsDetail(name, direct, stackages))
00574 {
00575
00576 crawl(search_paths_, true);
00577 stackages.clear();
00578 setQuiet(old_quiet);
00579 if(!depsDetail(name, direct, stackages))
00580 return false;
00581 }
00582 setQuiet(old_quiet);
00583 for(std::vector<Stackage*>::const_iterator it = stackages.begin();
00584 it != stackages.end();
00585 ++it)
00586 deps.push_back((*it)->name_);
00587 return true;
00588 }
00589
00590 bool
00591 Rosstackage::depsOn(const std::string& name, bool direct,
00592 std::vector<std::string>& deps)
00593 {
00594 std::vector<Stackage*> stackages;
00595 if(!depsOnDetail(name, direct, stackages))
00596 return false;
00597 for(std::vector<Stackage*>::const_iterator it = stackages.begin();
00598 it != stackages.end();
00599 ++it)
00600 deps.push_back((*it)->name_);
00601 return true;
00602 }
00603
00604 bool
00605 Rosstackage::depsIndent(const std::string& name, bool direct,
00606 std::vector<std::string>& deps)
00607 {
00608 Stackage* stackage = findWithRecrawl(name);
00609 if(!stackage)
00610 return false;
00611 try
00612 {
00613 computeDeps(stackage);
00614 std::vector<Stackage*> deps_vec;
00615 std::tr1::unordered_set<Stackage*> deps_hash;
00616 std::vector<std::string> indented_deps;
00617 gatherDepsFull(stackage, direct, POSTORDER, 0, deps_hash, deps_vec, true, indented_deps);
00618 for(std::vector<std::string>::const_iterator it = indented_deps.begin();
00619 it != indented_deps.end();
00620 ++it)
00621 deps.push_back(*it);
00622 }
00623 catch(Exception& e)
00624 {
00625 logError(e.what());
00626 return false;
00627 }
00628 return true;
00629 }
00630
00631 bool
00632 Rosstackage::depsWhy(const std::string& from,
00633 const std::string& to,
00634 std::string& output)
00635 {
00636 Stackage* from_s = findWithRecrawl(from);
00637 if(!from_s)
00638 return false;
00639 Stackage* to_s = findWithRecrawl(to);
00640 if(!to_s)
00641 return false;
00642
00643 std::list<std::list<Stackage*> > acc_list;
00644 try
00645 {
00646 depsWhyDetail(from_s, to_s, acc_list);
00647 }
00648 catch(Exception& e)
00649 {
00650 logError(e.what());
00651 return true;
00652 }
00653 output.append(std::string("Dependency chains from ") +
00654 from + " to " + to + ":\n");
00655 for(std::list<std::list<Stackage*> >::const_iterator it = acc_list.begin();
00656 it != acc_list.end();
00657 ++it)
00658 {
00659 output.append("* ");
00660 for(std::list<Stackage*>::const_iterator iit = it->begin();
00661 iit != it->end();
00662 ++iit)
00663 {
00664 if(iit != it->begin())
00665 output.append("-> ");
00666 output.append((*iit)->name_ + " ");
00667 }
00668 output.append("\n");
00669 }
00670 return true;
00671 }
00672
00673 bool
00674 Rosstackage::depsManifests(const std::string& name, bool direct,
00675 std::vector<std::string>& manifests)
00676 {
00677 Stackage* stackage = findWithRecrawl(name);
00678 if(!stackage)
00679 return false;
00680 try
00681 {
00682 computeDeps(stackage);
00683 std::vector<Stackage*> deps_vec;
00684 gatherDeps(stackage, direct, POSTORDER, deps_vec);
00685 for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
00686 it != deps_vec.end();
00687 ++it)
00688 manifests.push_back((*it)->manifest_path_);
00689 }
00690 catch(Exception& e)
00691 {
00692 logError(e.what());
00693 return false;
00694 }
00695 return true;
00696 }
00697
00698 bool
00699 Rosstackage::rosdeps(const std::string& name, bool direct,
00700 std::set<std::string>& rosdeps)
00701 {
00702 Stackage* stackage = findWithRecrawl(name);
00703 if(!stackage)
00704 return false;
00705 try
00706 {
00707 computeDeps(stackage);
00708 std::vector<Stackage*> deps_vec;
00709
00710 deps_vec.push_back(stackage);
00711 if(!direct)
00712 gatherDeps(stackage, direct, POSTORDER, deps_vec);
00713 for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
00714 it != deps_vec.end();
00715 ++it)
00716 {
00717 if (!stackage->is_wet_package_)
00718 {
00719 _rosdeps(*it, rosdeps, MANIFEST_TAG_ROSDEP);
00720 }
00721 else
00722 {
00723
00724 _rosdeps(*it, rosdeps, "build_depend");
00725 _rosdeps(*it, rosdeps, "buildtool_depend");
00726 _rosdeps(*it, rosdeps, "run_depend");
00727
00728 _rosdeps(*it, rosdeps, "build_export_depend");
00729 _rosdeps(*it, rosdeps, "buildtool_export_depend");
00730 _rosdeps(*it, rosdeps, "exec_depend");
00731 _rosdeps(*it, rosdeps, "depend");
00732 _rosdeps(*it, rosdeps, "doc_depend");
00733 _rosdeps(*it, rosdeps, "test_depend");
00734 }
00735 }
00736 }
00737 catch(Exception& e)
00738 {
00739 logError(e.what());
00740 return false;
00741 }
00742 return true;
00743 }
00744
00745 void
00746 Rosstackage::_rosdeps(Stackage* stackage, std::set<std::string>& rosdeps, const char* tag_name)
00747 {
00748 TiXmlElement* root = get_manifest_root(stackage);
00749 for(TiXmlElement* ele = root->FirstChildElement(tag_name);
00750 ele;
00751 ele = ele->NextSiblingElement(tag_name))
00752 {
00753 if(!stackage->is_wet_package_)
00754 {
00755 const char *att_str;
00756 if((att_str = ele->Attribute(MANIFEST_ATTR_NAME)))
00757 {
00758 rosdeps.insert(std::string("name: ") + att_str);
00759 }
00760 }
00761 else
00762 {
00763 const char* dep_pkgname = ele->GetText();
00764 if(isSysPackage(dep_pkgname))
00765 {
00766 rosdeps.insert(std::string("name: ") + dep_pkgname);
00767 }
00768 }
00769 }
00770 }
00771
00772 bool
00773 Rosstackage::vcs(const std::string& name, bool direct,
00774 std::vector<std::string>& vcs)
00775 {
00776 Stackage* stackage = findWithRecrawl(name);
00777 if(!stackage)
00778 return false;
00779 try
00780 {
00781 computeDeps(stackage);
00782 std::vector<Stackage*> deps_vec;
00783
00784 deps_vec.push_back(stackage);
00785 if(!direct)
00786 gatherDeps(stackage, direct, POSTORDER, deps_vec);
00787 for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
00788 it != deps_vec.end();
00789 ++it)
00790 {
00791 TiXmlElement* root = get_manifest_root(*it);
00792 for(TiXmlElement* ele = root->FirstChildElement(MANIFEST_TAG_VERSIONCONTROL);
00793 ele;
00794 ele = ele->NextSiblingElement(MANIFEST_TAG_VERSIONCONTROL))
00795 {
00796 std::string result;
00797 const char *att_str;
00798 if((att_str = ele->Attribute(MANIFEST_ATTR_TYPE)))
00799 {
00800 result.append("type: ");
00801 result.append(att_str);
00802 }
00803 if((att_str = ele->Attribute(MANIFEST_ATTR_URL)))
00804 {
00805 result.append("\turl: ");
00806 result.append(att_str);
00807 }
00808 vcs.push_back(result);
00809 }
00810 }
00811 }
00812 catch(Exception& e)
00813 {
00814 logError(e.what());
00815 return false;
00816 }
00817 return true;
00818 }
00819
00820 bool
00821 Rosstackage::cpp_exports(const std::string& name, const std::string& type,
00822 const std::string& attrib, bool deps_only,
00823 std::vector<std::pair<std::string, bool> >& flags)
00824 {
00825 Stackage* stackage = findWithRecrawl(name);
00826 if(!stackage)
00827 return false;
00828
00829 static bool init_py = false;
00830 static PyObject* pName;
00831 static PyObject* pModule;
00832 static PyObject* pDict;
00833 static PyObject* pFunc;
00834
00835 try
00836 {
00837 computeDeps(stackage);
00838 std::vector<Stackage*> deps_vec;
00839 if(!deps_only)
00840 deps_vec.push_back(stackage);
00841 gatherDeps(stackage, false, PREORDER, deps_vec, true);
00842 for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
00843 it != deps_vec.end();
00844 ++it)
00845 {
00846 if(!(*it)->is_wet_package_)
00847 {
00848 std::vector<std::string> dry_flags;
00849 if(!exports_dry_package(*it, "cpp", attrib, dry_flags))
00850 {
00851 return false;
00852 }
00853 for(std::vector<std::string>::const_iterator it = dry_flags.begin(); it != dry_flags.end(); ++it)
00854 {
00855 flags.push_back(std::pair<std::string, bool>(*it, false));
00856 }
00857 }
00858 else
00859 {
00860 initPython();
00861 PyGILState_STATE gstate = PyGILState_Ensure();
00862
00863 if(!init_py)
00864 {
00865 init_py = true;
00866 pName = PyString_FromString("rosdep2.rospack");
00867 pModule = PyImport_Import(pName);
00868 if(!pModule)
00869 {
00870 PyErr_Print();
00871 PyGILState_Release(gstate);
00872 std::string errmsg = "could not find python module 'rosdep2.rospack'. is rosdep up-to-date (at least 0.10.4)?";
00873 throw Exception(errmsg);
00874 }
00875 pDict = PyModule_GetDict(pModule);
00876 pFunc = PyDict_GetItemString(pDict, "call_pkg_config");
00877 }
00878
00879 if(!PyCallable_Check(pFunc))
00880 {
00881 PyErr_Print();
00882 PyGILState_Release(gstate);
00883 std::string errmsg = "could not find python function 'rosdep2.rospack.call_pkg_config'. is rosdep up-to-date (at least 0.10.7)?";
00884 throw Exception(errmsg);
00885 }
00886
00887 PyObject* pArgs = PyTuple_New(2);
00888 PyObject* pOpt = PyString_FromString(type.c_str());
00889 PyTuple_SetItem(pArgs, 0, pOpt);
00890 PyObject* pPkg = PyString_FromString((*it)->name_.c_str());
00891 PyTuple_SetItem(pArgs, 1, pPkg);
00892 PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
00893 Py_DECREF(pArgs);
00894
00895 if(!pValue)
00896 {
00897 PyErr_Print();
00898 PyGILState_Release(gstate);
00899 std::string errmsg = "could not call python function 'rosdep2.rospack.call_pkg_config'";
00900 throw Exception(errmsg);
00901 }
00902 if(pValue == Py_None)
00903 {
00904 Py_DECREF(pValue);
00905 std::string errmsg = "python function 'rosdep2.rospack.call_pkg_config' could not call 'pkg-config " + type + " " + (*it)->name_ + "' without errors";
00906 throw Exception(errmsg);
00907 }
00908
00909 flags.push_back(std::pair<std::string, bool>(PyString_AsString(pValue), true));
00910 Py_DECREF(pValue);
00911
00912
00913
00914
00915
00916
00917
00918
00919 PyGILState_Release(gstate);
00920 }
00921 }
00922 }
00923 catch(Exception& e)
00924 {
00925 logError(e.what());
00926 return false;
00927 }
00928 return true;
00929 }
00930
00931 bool
00932 Rosstackage::reorder_paths(const std::string& paths, std::string& reordered)
00933 {
00934 static bool init_py = false;
00935 static PyObject* pName;
00936 static PyObject* pModule;
00937 static PyObject* pFunc;
00938
00939 initPython();
00940 PyGILState_STATE gstate = PyGILState_Ensure();
00941
00942 if(!init_py)
00943 {
00944 init_py = true;
00945 pName = PyString_FromString("catkin_pkg.rospack");
00946 pModule = PyImport_Import(pName);
00947 if(!pModule)
00948 {
00949 PyErr_Print();
00950 PyGILState_Release(gstate);
00951 std::string errmsg = "could not find python module 'catkin_pkg.rospack'. is catkin_pkg up-to-date (at least 0.1.8)?";
00952 throw Exception(errmsg);
00953 }
00954 PyObject* pDict = PyModule_GetDict(pModule);
00955 pFunc = PyDict_GetItemString(pDict, "reorder_paths");
00956 }
00957
00958 if(!PyCallable_Check(pFunc))
00959 {
00960 PyErr_Print();
00961 PyGILState_Release(gstate);
00962 std::string errmsg = "could not find python function 'catkin_pkg.rospack.reorder_paths'. is catkin_pkg up-to-date (at least 0.1.8)?";
00963 throw Exception(errmsg);
00964 }
00965
00966
00967 PyObject* pArgs = PyTuple_New(1);
00968 PyTuple_SetItem(pArgs, 0, PyString_FromString(paths.c_str()));
00969 PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
00970 Py_DECREF(pArgs);
00971
00972 if(!pValue)
00973 {
00974 PyErr_Print();
00975 PyGILState_Release(gstate);
00976 std::string errmsg = "could not call python function 'catkin_pkg.rospack.reorder_paths'";
00977 throw Exception(errmsg);
00978 }
00979
00980 reordered = PyString_AsString(pValue);
00981 Py_DECREF(pValue);
00982
00983
00984
00985
00986
00987
00988
00989
00990 PyGILState_Release(gstate);
00991
00992 return true;
00993 }
00994
00995 bool
00996 Rosstackage::exports(const std::string& name, const std::string& lang,
00997 const std::string& attrib, bool deps_only,
00998 std::vector<std::string>& flags)
00999 {
01000 Stackage* stackage = findWithRecrawl(name);
01001 if(!stackage)
01002 return false;
01003 try
01004 {
01005 computeDeps(stackage);
01006 std::vector<Stackage*> deps_vec;
01007 if(!deps_only)
01008 deps_vec.push_back(stackage);
01009 gatherDeps(stackage, false, PREORDER, deps_vec);
01010 for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
01011 it != deps_vec.end();
01012 ++it)
01013 {
01014 if (!exports_dry_package(*it, lang, attrib, flags))
01015 {
01016 return false;
01017 }
01018 }
01019 }
01020 catch(Exception& e)
01021 {
01022 logError(e.what());
01023 return false;
01024 }
01025 return true;
01026 }
01027
01028 bool
01029 Rosstackage::exports_dry_package(Stackage* stackage, const std::string& lang,
01030 const std::string& attrib,
01031 std::vector<std::string>& flags)
01032 {
01033 TiXmlElement* root = get_manifest_root(stackage);
01034 for(TiXmlElement* ele = root->FirstChildElement(MANIFEST_TAG_EXPORT);
01035 ele;
01036 ele = ele->NextSiblingElement(MANIFEST_TAG_EXPORT))
01037 {
01038 bool os_match = false;
01039 const char *best_match = NULL;
01040 for(TiXmlElement* ele2 = ele->FirstChildElement(lang);
01041 ele2;
01042 ele2 = ele2->NextSiblingElement(lang))
01043 {
01044 const char *os_str;
01045 if ((os_str = ele2->Attribute("os")))
01046 {
01047 if(g_ros_os == std::string(os_str))
01048 {
01049 if(os_match)
01050 logWarn(std::string("ignoring duplicate ") + lang + " tag with os=" + os_str + " in export block");
01051 else
01052 {
01053 best_match = ele2->Attribute(attrib.c_str());
01054 os_match = true;
01055 }
01056 }
01057 }
01058 if(!os_match)
01059 {
01060 if(!best_match)
01061 best_match = ele2->Attribute(attrib.c_str());
01062 else
01063 logWarn(std::string("ignoring duplicate ") + lang + " tag in export block");
01064 }
01065
01066 }
01067 if(best_match)
01068 {
01069 std::string expanded_str;
01070 if(!expandExportString(stackage, best_match, expanded_str))
01071 return false;
01072 flags.push_back(expanded_str);
01073 }
01074 }
01075
01076
01077
01078 if((lang == "cpp") && (attrib == "cflags"))
01079 {
01080 fs::path msg_gen = fs::path(stackage->path_) / MSG_GEN_GENERATED_DIR;
01081 fs::path srv_gen = fs::path(stackage->path_) / SRV_GEN_GENERATED_DIR;
01082 if(fs::is_regular_file(msg_gen / MSG_GEN_GENERATED_FILE))
01083 {
01084 msg_gen /= fs::path("cpp") / "include";
01085 flags.push_back(std::string("-I" + msg_gen.string()));
01086 }
01087 if(fs::is_regular_file(srv_gen / SRV_GEN_GENERATED_FILE))
01088 {
01089 srv_gen /= fs::path("cpp") / "include";
01090 flags.push_back(std::string("-I" + srv_gen.string()));
01091 }
01092 }
01093 return true;
01094 }
01095
01096 bool
01097 Rosstackage::plugins(const std::string& name, const std::string& attrib,
01098 const std::string& top,
01099 std::vector<std::string>& flags)
01100 {
01101
01102 std::vector<Stackage*> stackages;
01103 if(!depsOnDetail(name, true, stackages, true))
01104 return false;
01105
01106 std::tr1::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.find(name);
01107 if(it != stackages_.end())
01108 {
01109
01110 stackages.push_back(it->second);
01111 }
01112
01113
01114 if(top.size())
01115 {
01116 std::vector<Stackage*> top_deps;
01117 if(!depsDetail(top, false, top_deps))
01118 return false;
01119 std::tr1::unordered_set<Stackage*> top_deps_set;
01120 for(std::vector<Stackage*>::iterator it = top_deps.begin();
01121 it != top_deps.end();
01122 ++it)
01123 top_deps_set.insert(*it);
01124 std::vector<Stackage*>::iterator it = stackages.begin();
01125 while(it != stackages.end())
01126 {
01127 if((*it)->name_ != top &&
01128 (top_deps_set.find(*it) == top_deps_set.end()))
01129 it = stackages.erase(it);
01130 else
01131 ++it;
01132 }
01133 }
01134
01135 for(std::vector<Stackage*>::const_iterator it = stackages.begin();
01136 it != stackages.end();
01137 ++it)
01138 {
01139 TiXmlElement* root = get_manifest_root(*it);
01140 for(TiXmlElement* ele = root->FirstChildElement(MANIFEST_TAG_EXPORT);
01141 ele;
01142 ele = ele->NextSiblingElement(MANIFEST_TAG_EXPORT))
01143 {
01144 for(TiXmlElement* ele2 = ele->FirstChildElement(name);
01145 ele2;
01146 ele2 = ele2->NextSiblingElement(name))
01147 {
01148 const char *att_str;
01149 if((att_str = ele2->Attribute(attrib.c_str())))
01150 {
01151 std::string expanded_str;
01152 if(!expandExportString(*it, att_str, expanded_str))
01153 return false;
01154 flags.push_back((*it)->name_ + " " + expanded_str);
01155 }
01156 }
01157 }
01158 }
01159 return true;
01160 }
01161
01162 bool
01163 Rosstackage::depsMsgSrv(const std::string& name, bool direct,
01164 std::vector<std::string>& gens)
01165 {
01166 Stackage* stackage = findWithRecrawl(name);
01167 if(!stackage)
01168 return false;
01169 try
01170 {
01171 computeDeps(stackage);
01172 std::vector<Stackage*> deps_vec;
01173 gatherDeps(stackage, direct, POSTORDER, deps_vec);
01174 for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
01175 it != deps_vec.end();
01176 ++it)
01177 {
01178 fs::path msg_gen = fs::path((*it)->path_) /
01179 MSG_GEN_GENERATED_DIR /
01180 MSG_GEN_GENERATED_FILE;
01181 fs::path srv_gen = fs::path((*it)->path_) /
01182 SRV_GEN_GENERATED_DIR /
01183 SRV_GEN_GENERATED_FILE;
01184 if(fs::is_regular_file(msg_gen))
01185 gens.push_back(msg_gen.string());
01186 if(fs::is_regular_file(srv_gen))
01187 gens.push_back(srv_gen.string());
01188 }
01189 }
01190 catch(Exception& e)
01191 {
01192 logError(e.what());
01193 return false;
01194 }
01195 return true;
01196 }
01197
01199
01201
01202 void
01203 Rosstackage::log(const std::string& level,
01204 const std::string& msg,
01205 bool append_errno)
01206 {
01207 if(quiet_)
01208 return;
01209 fprintf(stderr, "[%s] %s: %s",
01210 name_.c_str(), level.c_str(), msg.c_str());
01211 if(append_errno)
01212 fprintf(stderr, ": %s", strerror(errno));
01213 fprintf(stderr, "\n");
01214 }
01215
01216
01217 Stackage*
01218 Rosstackage::findWithRecrawl(const std::string& name)
01219 {
01220 if(stackages_.count(name))
01221 return stackages_[name];
01222 else
01223 {
01224
01225 crawl(search_paths_, true);
01226 if(stackages_.count(name))
01227 return stackages_[name];
01228 }
01229
01230 logError(std::string("stack/package ") + name + " not found");
01231 return NULL;
01232 }
01233
01234 bool
01235 Rosstackage::depsDetail(const std::string& name, bool direct,
01236 std::vector<Stackage*>& deps)
01237 {
01238
01239
01240 if(!stackages_.count(name))
01241 {
01242 logError(std::string("no such package ") + name);
01243 return false;
01244 }
01245 Stackage* stackage = stackages_[name];
01246 try
01247 {
01248 computeDeps(stackage);
01249 std::vector<Stackage*> deps_vec;
01250 gatherDeps(stackage, direct, POSTORDER, deps_vec);
01251 for(std::vector<Stackage*>::const_iterator it = deps_vec.begin();
01252 it != deps_vec.end();
01253 ++it)
01254 deps.push_back(*it);
01255 }
01256 catch(Exception& e)
01257 {
01258 logError(e.what());
01259 return false;
01260 }
01261 return true;
01262 }
01263
01264 void
01265 Rosstackage::depsWhyDetail(Stackage* from,
01266 Stackage* to,
01267 std::list<std::list<Stackage*> >& acc_list)
01268 {
01269 computeDeps(from);
01270 for(std::vector<Stackage*>::const_iterator it = from->deps_.begin();
01271 it != from->deps_.end();
01272 ++it)
01273 {
01274 if((*it)->name_ == to->name_)
01275 {
01276 std::list<Stackage*> acc;
01277 acc.push_back(from);
01278 acc.push_back(to);
01279 acc_list.push_back(acc);
01280 }
01281 else
01282 {
01283 std::list<std::list<Stackage*> > l;
01284 depsWhyDetail(*it, to, l);
01285 for(std::list<std::list<Stackage*> >::iterator iit = l.begin();
01286 iit != l.end();
01287 ++iit)
01288 {
01289 iit->push_front(from);
01290 acc_list.push_back(*iit);
01291 }
01292 }
01293 }
01294 }
01295
01296 bool
01297 Rosstackage::depsOnDetail(const std::string& name, bool direct,
01298 std::vector<Stackage*>& deps, bool ignore_missing)
01299 {
01300
01301
01302 if(!stackages_.count(name))
01303 logWarn(std::string("no such package ") + name);
01304 try
01305 {
01306 for(std::tr1::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
01307 it != stackages_.end();
01308 ++it)
01309 {
01310 computeDeps(it->second, true, ignore_missing);
01311 std::vector<Stackage*> deps_vec;
01312 gatherDeps(it->second, direct, POSTORDER, deps_vec);
01313 for(std::vector<Stackage*>::const_iterator iit = deps_vec.begin();
01314 iit != deps_vec.end();
01315 ++iit)
01316 {
01317 if((*iit)->name_ == name)
01318 {
01319 deps.push_back(it->second);
01320 break;
01321 }
01322 }
01323 }
01324 }
01325 catch(Exception& e)
01326 {
01327 logError(e.what());
01328 return false;
01329 }
01330 return true;
01331 }
01332
01333 bool
01334 Rosstackage::profile(const std::vector<std::string>& search_path,
01335 bool zombie_only,
01336 int length,
01337 std::vector<std::string>& dirs)
01338 {
01339 double start = time_since_epoch();
01340 std::vector<DirectoryCrawlRecord*> dcrs;
01341 std::tr1::unordered_set<std::string> dcrs_hash;
01342 for(std::vector<std::string>::const_iterator p = search_path.begin();
01343 p != search_path.end();
01344 ++p)
01345 {
01346 crawlDetail(*p, true, 1, true, dcrs, dcrs_hash);
01347 }
01348 if(!zombie_only)
01349 {
01350 double total = time_since_epoch() - start;
01351 char buf[16];
01352 snprintf(buf, sizeof(buf), "%.6f", total);
01353 dirs.push_back(std::string("Full tree crawl took ") + buf + " seconds.");
01354 dirs.push_back("Directories marked with (*) contain no manifest. You may");
01355 dirs.push_back("want to delete these directories.");
01356 dirs.push_back("To get just of list of directories without manifests,");
01357 dirs.push_back("re-run the profile with --zombie-only");
01358 dirs.push_back("-------------------------------------------------------------");
01359 }
01360 std::sort(dcrs.begin(), dcrs.end(), cmpDirectoryCrawlRecord);
01361 std::reverse(dcrs.begin(), dcrs.end());
01362 int i=0;
01363 for(std::vector<DirectoryCrawlRecord*>::const_iterator it = dcrs.begin();
01364 it != dcrs.end();
01365 ++it)
01366 {
01367 if(zombie_only)
01368 {
01369 if((*it)->zombie_)
01370 {
01371 if(length < 0 || i < length)
01372 dirs.push_back((*it)->path_);
01373 i++;
01374 }
01375 }
01376 else
01377 {
01378 char buf[16];
01379 snprintf(buf, sizeof(buf), "%.6f", (*it)->crawl_time_);
01380 if(length < 0 || i < length)
01381 dirs.push_back(std::string(buf) + " " +
01382 ((*it)->zombie_ ? "* " : " ") +
01383 (*it)->path_);
01384 i++;
01385 }
01386 delete *it;
01387 }
01388
01389 writeCache();
01390 return 0;
01391 }
01392
01393 void
01394 Rosstackage::addStackage(const std::string& path)
01395 {
01396 #if !defined(BOOST_FILESYSTEM_VERSION) || (BOOST_FILESYSTEM_VERSION == 2)
01397 std::string name = fs::path(path).filename();
01398 #else
01399
01400 std::string name = fs::path(path).filename().string();
01401 #endif
01402
01403 Stackage* stackage = 0;
01404 fs::path dry_manifest_path = fs::path(path) / manifest_name_;
01405 fs::path wet_manifest_path = fs::path(path) / ROSPACKAGE_MANIFEST_NAME;
01406 if(fs::is_regular_file(dry_manifest_path))
01407 {
01408 stackage = new Stackage(name, path, dry_manifest_path.string(), manifest_name_);
01409 }
01410 else if(fs::is_regular_file(wet_manifest_path))
01411 {
01412 stackage = new Stackage(name, path, wet_manifest_path.string(), ROSPACKAGE_MANIFEST_NAME);
01413 loadManifest(stackage);
01414 stackage->update_wet_information();
01415 }
01416 else
01417 {
01418 return;
01419 }
01420
01421
01422 if((manifest_name_ == ROSSTACK_MANIFEST_NAME && stackage->isPackage()) ||
01423 (manifest_name_ == ROSPACK_MANIFEST_NAME && stackage->isStack()))
01424 {
01425 return;
01426 }
01427
01428 if(stackages_.find(stackage->name_) != stackages_.end())
01429 {
01430 if (dups_.find(stackage->name_) == dups_.end())
01431 {
01432 std::vector<std::string> dups;
01433 dups.push_back(stackages_[stackage->name_]->path_);
01434 dups_[stackage->name_] = dups;
01435 }
01436 dups_[stackage->name_].push_back(stackage->path_);
01437 return;
01438 }
01439
01440 stackages_[stackage->name_] = stackage;
01441 }
01442
01443 void
01444 Rosstackage::crawlDetail(const std::string& path,
01445 bool force,
01446 int depth,
01447 bool collect_profile_data,
01448 std::vector<DirectoryCrawlRecord*>& profile_data,
01449 std::tr1::unordered_set<std::string>& profile_hash)
01450 {
01451 if(depth > MAX_CRAWL_DEPTH)
01452 throw Exception("maximum depth exceeded during crawl");
01453
01454 try
01455 {
01456 if(!fs::is_directory(path))
01457 return;
01458 }
01459 catch(fs::filesystem_error& e)
01460 {
01461 logWarn(std::string("error while looking at ") + path + ": " + e.what());
01462 return;
01463 }
01464
01465 fs::path catkin_ignore = fs::path(path) / CATKIN_IGNORE;
01466 try
01467 {
01468 if(fs::is_regular_file(catkin_ignore))
01469 return;
01470 }
01471 catch(fs::filesystem_error& e)
01472 {
01473 logWarn(std::string("error while looking for ") + catkin_ignore.string() + ": " + e.what());
01474 }
01475
01476 if(isStackage(path))
01477 {
01478 addStackage(path);
01479 return;
01480 }
01481
01482 fs::path nosubdirs = fs::path(path) / ROSPACK_NOSUBDIRS;
01483 try
01484 {
01485 if(fs::is_regular_file(nosubdirs))
01486 return;
01487 }
01488 catch(fs::filesystem_error& e)
01489 {
01490 logWarn(std::string("error while looking for ") + nosubdirs.string() + ": " + e.what());
01491 }
01492
01493
01494
01495
01496 fs::path rospack_manifest = fs::path(path) / ROSPACK_MANIFEST_NAME;
01497 try
01498 {
01499 if(fs::is_regular_file(rospack_manifest))
01500 return;
01501 }
01502 catch(fs::filesystem_error& e)
01503 {
01504 logWarn(std::string("error while looking for ") + rospack_manifest.string() + ": " + e.what());
01505 }
01506
01507 DirectoryCrawlRecord* dcr = NULL;
01508 if(collect_profile_data)
01509 {
01510 if(profile_hash.find(path) == profile_hash.end())
01511 {
01512 dcr = new DirectoryCrawlRecord(path,
01513 time_since_epoch(),
01514 stackages_.size());
01515 profile_data.push_back(dcr);
01516 profile_hash.insert(path);
01517 }
01518 }
01519
01520 try
01521 {
01522 for(fs::directory_iterator dit = fs::directory_iterator(path);
01523 dit != fs::directory_iterator();
01524 ++dit)
01525 {
01526 if(fs::is_directory(dit->path()))
01527 {
01528 #if !defined(BOOST_FILESYSTEM_VERSION) || (BOOST_FILESYSTEM_VERSION == 2)
01529 std::string name = dit->path().filename();
01530 #else
01531
01532 std::string name = dit->path().filename().string();
01533 #endif
01534
01535 if(name.size() == 0 || name[0] == '.')
01536 continue;
01537
01538 crawlDetail(dit->path().string(), force, depth+1,
01539 collect_profile_data, profile_data, profile_hash);
01540 }
01541 }
01542 }
01543 catch(fs::filesystem_error& e)
01544 {
01545 logWarn(std::string("error while crawling ") + path + ": " + e.what());
01546 }
01547
01548 if(collect_profile_data && dcr != NULL)
01549 {
01550
01551 dcr->crawl_time_ = time_since_epoch() - dcr->start_time_;
01552
01553
01554 if(stackages_.size() == dcr->start_num_pkgs_)
01555 dcr->zombie_ = true;
01556 }
01557 }
01558
01559 void
01560 Rosstackage::loadManifest(Stackage* stackage)
01561 {
01562 if(stackage->manifest_loaded_)
01563 return;
01564
01565 if(!stackage->manifest_.LoadFile(stackage->manifest_path_))
01566 {
01567 std::string errmsg = std::string("error parsing manifest of package ") +
01568 stackage->name_ + " at " + stackage->manifest_path_;
01569 throw Exception(errmsg);
01570 }
01571 stackage->manifest_loaded_ = true;
01572 }
01573
01574 void
01575 Rosstackage::computeDeps(Stackage* stackage, bool ignore_errors, bool ignore_missing)
01576 {
01577 if(stackage->deps_computed_)
01578 return;
01579
01580 stackage->deps_computed_ = true;
01581
01582 try
01583 {
01584 loadManifest(stackage);
01585 get_manifest_root(stackage);
01586 }
01587 catch(Exception& e)
01588 {
01589 if(ignore_errors)
01590 return;
01591 else
01592 throw e;
01593 }
01594 if (!stackage->is_wet_package_)
01595 {
01596 computeDepsInternal(stackage, ignore_errors, "depend", ignore_missing);
01597 }
01598 else
01599 {
01600
01601 computeDepsInternal(stackage, ignore_errors, "run_depend", ignore_missing);
01602
01603 computeDepsInternal(stackage, ignore_errors, "exec_depend", ignore_missing);
01604 computeDepsInternal(stackage, ignore_errors, "depend", ignore_missing);
01605 }
01606 }
01607
01608 void
01609 Rosstackage::computeDepsInternal(Stackage* stackage, bool ignore_errors, const std::string& depend_tag, bool ignore_missing)
01610 {
01611 TiXmlElement* root;
01612 root = get_manifest_root(stackage);
01613
01614 TiXmlNode *dep_node = NULL;
01615 const char* dep_pkgname;
01616 while((dep_node = root->IterateChildren(depend_tag, dep_node)))
01617 {
01618 TiXmlElement *dep_ele = dep_node->ToElement();
01619 if (!stackage->is_wet_package_)
01620 {
01621 dep_pkgname = dep_ele->Attribute(tag_.c_str());
01622 }
01623 else
01624 {
01625 dep_pkgname = dep_ele->GetText();
01626 }
01627 if(!dep_pkgname)
01628 {
01629 if(!ignore_errors)
01630 {
01631 std::string errmsg = std::string("bad depend syntax (no 'package/stack' attribute) in manifest ") + stackage->name_ + " at " + stackage->manifest_path_;
01632 throw Exception(errmsg);
01633 }
01634 }
01635 else if(dep_pkgname == stackage->name_)
01636 {
01637 if(!ignore_errors)
01638 {
01639 std::string errmsg = std::string("package/stack ") + stackage->name_ + " depends on itself";
01640 throw Exception(errmsg);
01641 }
01642 }
01643 else if(!stackages_.count(dep_pkgname))
01644 {
01645 if (stackage->is_wet_package_ && (ignore_missing || isSysPackage(dep_pkgname)))
01646 {
01647 continue;
01648 }
01649 if(ignore_errors)
01650 {
01651 Stackage* dep = new Stackage(dep_pkgname, "", "", "");
01652 stackage->deps_.push_back(dep);
01653 }
01654 else
01655 {
01656 std::string errmsg = std::string("package/stack '") + 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'";
01657 throw Exception(errmsg);
01658 }
01659 }
01660 else
01661 {
01662 Stackage* dep = stackages_[dep_pkgname];
01663 if (std::find(stackage->deps_.begin(), stackage->deps_.end(), dep) == stackage->deps_.end())
01664 {
01665 stackage->deps_.push_back(dep);
01666 computeDeps(dep, ignore_errors, ignore_missing);
01667 }
01668 }
01669 }
01670 }
01671
01672 void
01673 Rosstackage::initPython()
01674 {
01675 static bool initialized = false;
01676 if(!initialized)
01677 {
01678 initialized = true;
01679 Py_InitializeEx(0);
01680 }
01681 }
01682
01683 bool
01684 Rosstackage::isSysPackage(const std::string& pkgname)
01685 {
01686 static std::map<std::string, bool> cache;
01687 if(cache.find(pkgname) != cache.end())
01688 {
01689 return cache.find(pkgname)->second;
01690 }
01691
01692 initPython();
01693 PyGILState_STATE gstate = PyGILState_Ensure();
01694
01695 static PyObject* pModule = 0;
01696 static PyObject* pDict = 0;
01697 if(!pModule)
01698 {
01699 PyObject* pName = PyString_FromString("rosdep2.rospack");
01700 pModule = PyImport_Import(pName);
01701 Py_DECREF(pName);
01702 if(!pModule)
01703 {
01704 PyErr_Print();
01705 PyGILState_Release(gstate);
01706 std::string errmsg = "could not find python module 'rosdep2.rospack'. is rosdep up-to-date (at least 0.10.4)?";
01707 throw Exception(errmsg);
01708 }
01709 pDict = PyModule_GetDict(pModule);
01710 }
01711
01712 static PyObject* pView = 0;
01713 if(!pView)
01714 {
01715 PyObject* pFunc = PyDict_GetItemString(pDict, "init_rospack_interface");
01716 if(!PyCallable_Check(pFunc))
01717 {
01718 PyErr_Print();
01719 PyGILState_Release(gstate);
01720 std::string errmsg = "could not find python function 'rosdep2.rospack.init_rospack_interface'. is rosdep up-to-date (at least 0.10.4)?";
01721 throw Exception(errmsg);
01722 }
01723 pView = PyObject_CallObject(pFunc, NULL);
01724 if(!pView)
01725 {
01726 PyErr_Print();
01727 PyGILState_Release(gstate);
01728 std::string errmsg = "could not call python function 'rosdep2.rospack.init_rospack_interface'";
01729 throw Exception(errmsg);
01730 }
01731 }
01732 static bool rospack_view_not_empty = false;
01733 if(!rospack_view_not_empty)
01734 {
01735 PyObject* pFunc = PyDict_GetItemString(pDict, "is_view_empty");
01736 if(!PyCallable_Check(pFunc))
01737 {
01738 PyErr_Print();
01739 PyGILState_Release(gstate);
01740 std::string errmsg = "could not find python function 'rosdep2.rospack.is_view_empty'. is rosdep up-to-date (at least 0.10.8)?";
01741 throw Exception(errmsg);
01742 }
01743 PyObject* pArgs = PyTuple_New(1);
01744 PyTuple_SetItem(pArgs, 0, pView);
01745 PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
01746 Py_INCREF(pView);
01747 Py_DECREF(pArgs);
01748 if(PyObject_IsTrue(pValue))
01749 {
01750 PyErr_Print();
01751 PyGILState_Release(gstate);
01752 std::string errmsg = "the rosdep view is empty: call 'sudo rosdep init' and 'rosdep update'";
01753 throw Exception(errmsg);
01754 }
01755 rospack_view_not_empty = true;
01756 }
01757
01758 PyObject* pFunc = PyDict_GetItemString(pDict, "is_system_dependency");
01759 if(!PyCallable_Check(pFunc))
01760 {
01761 PyErr_Print();
01762 PyGILState_Release(gstate);
01763 std::string errmsg = "could not call python function 'rosdep2.rospack.is_system_dependency'. is rosdep up-to-date (at least 0.10.4)?";
01764 throw Exception(errmsg);
01765 }
01766
01767 PyObject* pArgs = PyTuple_New(2);
01768 PyTuple_SetItem(pArgs, 0, pView);
01769 PyObject* pDep = PyString_FromString(pkgname.c_str());
01770 PyTuple_SetItem(pArgs, 1, pDep);
01771 PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
01772 Py_INCREF(pView);
01773 Py_DECREF(pArgs);
01774
01775 bool value = PyObject_IsTrue(pValue);
01776 Py_DECREF(pValue);
01777
01778
01779
01780
01781
01782
01783
01784
01785 PyGILState_Release(gstate);
01786
01787 cache[pkgname] = value;
01788
01789 return value;
01790 }
01791
01792 void
01793 Rosstackage::gatherDeps(Stackage* stackage, bool direct,
01794 traversal_order_t order,
01795 std::vector<Stackage*>& deps,
01796 bool no_recursion_on_wet)
01797 {
01798 std::tr1::unordered_set<Stackage*> deps_hash;
01799 std::vector<std::string> indented_deps;
01800 gatherDepsFull(stackage, direct, order, 0,
01801 deps_hash, deps, false, indented_deps, no_recursion_on_wet);
01802 }
01803
01804 void
01805 _gatherDepsFull(Stackage* stackage, bool direct,
01806 traversal_order_t order, int depth,
01807 std::tr1::unordered_set<Stackage*>& deps_hash,
01808 std::vector<Stackage*>& deps,
01809 bool get_indented_deps,
01810 std::vector<std::string>& indented_deps,
01811 bool no_recursion_on_wet,
01812 std::vector<std::string>& dep_chain)
01813 {
01814 if(stackage->is_wet_package_ && no_recursion_on_wet)
01815 {
01816 return;
01817 }
01818
01819 if(direct && (stackage->is_wet_package_ || !no_recursion_on_wet))
01820 {
01821 for(std::vector<Stackage*>::const_iterator it = stackage->deps_.begin();
01822 it != stackage->deps_.end();
01823 ++it)
01824 deps.push_back(*it);
01825 return;
01826 }
01827
01828 if(depth > MAX_DEPENDENCY_DEPTH) {
01829 std::string cycle;
01830 for(std::vector<std::string>::const_iterator it = dep_chain.begin();
01831 it != dep_chain.end();
01832 ++it)
01833 {
01834 std::vector<std::string>::const_iterator begin = dep_chain.begin();
01835 std::vector<std::string>::const_iterator cycle_begin = std::find(begin, it, *it);
01836 if(cycle_begin != it) {
01837 cycle = ": ";
01838 for(std::vector<std::string>::const_iterator jt = cycle_begin; jt != it; ++jt) {
01839 if(jt != cycle_begin) cycle += ", ";
01840 cycle += *jt;
01841 }
01842 break;
01843 }
01844 }
01845 throw Exception(std::string("maximum dependency depth exceeded (likely circular dependency") + cycle + ")");
01846 }
01847
01848 for(std::vector<Stackage*>::const_iterator it = stackage->deps_.begin();
01849 it != stackage->deps_.end();
01850 ++it)
01851 {
01852 if(get_indented_deps)
01853 {
01854 std::string indented_dep;
01855 for(int i=0; i<depth; i++)
01856 indented_dep.append(" ");
01857 indented_dep.append((*it)->name_);
01858 indented_deps.push_back(indented_dep);
01859 }
01860
01861 bool first = (deps_hash.find(*it) == deps_hash.end());
01862 if(first)
01863 {
01864 deps_hash.insert(*it);
01865
01866
01867 if(order == PREORDER)
01868 deps.push_back(*it);
01869 }
01870 if(!(*it)->is_wet_package_ || !no_recursion_on_wet)
01871 {
01872
01873
01874
01875 dep_chain.push_back((*it)->name_);
01876 _gatherDepsFull(*it, direct, order, depth+1, deps_hash, deps,
01877 get_indented_deps, indented_deps,
01878 no_recursion_on_wet, dep_chain);
01879 dep_chain.pop_back();
01880 }
01881 if(first)
01882 {
01883 if(order == POSTORDER)
01884 deps.push_back(*it);
01885 }
01886 }
01887 }
01888
01889
01890 void
01891 Rosstackage::gatherDepsFull(Stackage* stackage, bool direct,
01892 traversal_order_t order, int depth,
01893 std::tr1::unordered_set<Stackage*>& deps_hash,
01894 std::vector<Stackage*>& deps,
01895 bool get_indented_deps,
01896 std::vector<std::string>& indented_deps,
01897 bool no_recursion_on_wet)
01898 {
01899 std::vector<std::string> dep_chain;
01900 dep_chain.push_back(stackage->name_);
01901 _gatherDepsFull(stackage, direct,
01902 order, depth,
01903 deps_hash,
01904 deps,
01905 get_indented_deps,
01906 indented_deps,
01907 no_recursion_on_wet,
01908 dep_chain);
01909 }
01910
01911 std::string
01912 Rosstackage::getCachePath()
01913 {
01914 fs::path cache_path;
01915
01916 char* ros_home = getenv("ROS_HOME");
01917 if(ros_home)
01918 cache_path = ros_home;
01919 else
01920 {
01921
01922
01923
01924 #if defined(WIN32)
01925 char* home_drive = getenv("HOMEDRIVE");
01926 char* home_path = getenv("HOMEPATH");
01927 if(home_drive && home_path)
01928 cache_path = fs::path(home_drive) / fs::path(home_path) / fs::path(DOTROS_NAME);
01929 #else // UNIX
01930 char* home_path;
01931 struct passwd* passwd_ent;
01932
01933 if((passwd_ent = getpwuid(geteuid())))
01934 home_path = passwd_ent->pw_dir;
01935 else
01936 home_path = getenv("HOME");
01937 if(home_path)
01938 cache_path = fs::path(home_path) / fs::path(DOTROS_NAME);
01939 #endif
01940 }
01941
01942
01943 try
01944 {
01945 if(!fs::is_directory(cache_path))
01946 {
01947 fs::create_directory(cache_path);
01948 }
01949 }
01950 catch(fs::filesystem_error& e)
01951 {
01952 logWarn(std::string("cannot create rospack cache directory ") +
01953 cache_path.string() + ": " + e.what());
01954 }
01955 cache_path /= cache_name_;
01956 return cache_path.string();
01957 }
01958
01959 bool
01960 Rosstackage::readCache()
01961 {
01962 FILE* cache = validateCache();
01963 if(cache)
01964 {
01965 char linebuf[30000];
01966 for(;;)
01967 {
01968 if (!fgets(linebuf, sizeof(linebuf), cache))
01969 break;
01970 if (linebuf[0] == '#')
01971 continue;
01972 char* newline_pos = strchr(linebuf, '\n');
01973 if(newline_pos)
01974 *newline_pos = 0;
01975 addStackage(linebuf);
01976 }
01977 fclose(cache);
01978 return true;
01979 }
01980 else
01981 return false;
01982 }
01983
01984
01985
01986 void
01987 Rosstackage::writeCache()
01988 {
01989
01990
01991 std::string cache_path = getCachePath();
01992 if(!cache_path.size())
01993 {
01994 logWarn("no location available to write cache file. Try setting ROS_HOME or HOME.");
01995 }
01996 else
01997 {
01998 char tmp_cache_dir[PATH_MAX];
01999 char tmp_cache_path[PATH_MAX];
02000 strncpy(tmp_cache_dir, cache_path.c_str(), sizeof(tmp_cache_dir));
02001 #if defined(_MSC_VER)
02002
02003 char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
02004 _splitpath_s(tmp_cache_dir, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME,
02005 ext, _MAX_EXT);
02006 char full_dir[_MAX_DRIVE + _MAX_DIR];
02007 _makepath_s(full_dir, _MAX_DRIVE + _MAX_DIR, drive, dir, NULL, NULL);
02008 snprintf(tmp_cache_path, sizeof(tmp_cache_path), "%s\\.rospack_cache.XXXXXX", full_dir);
02009 #elif defined(__MINGW32__)
02010 char* temp_name = tempnam(dirname(tmp_cache_dir),".rospack_cache.");
02011 snprintf(tmp_cache_path, sizeof(tmp_cache_path), temp_name);
02012 delete temp_name;
02013 #else
02014 snprintf(tmp_cache_path, sizeof(tmp_cache_path), "%s/.rospack_cache.XXXXXX", dirname(tmp_cache_dir));
02015 #endif
02016 #if defined(__MINGW32__)
02017
02018
02019 int fd = open(tmp_cache_path, O_RDWR | O_EXCL | _O_CREAT, 0644);
02020 if (fd < 0)
02021 {
02022 logWarn(std::string("unable to create temporary cache file ") +
02023 tmp_cache_path, true);
02024 }
02025 else
02026 {
02027 FILE *cache = fdopen(fd, "w");
02028 #elif defined(WIN32)
02029 if (_mktemp_s(tmp_cache_path, PATH_MAX) != 0)
02030 {
02031 fprintf(stderr,
02032 "[rospack] Unable to generate temporary cache file name: %u",
02033 GetLastError());
02034 }
02035 else
02036 {
02037 FILE *cache = fopen(tmp_cache_path, "w");
02038 #else
02039 int fd = mkstemp(tmp_cache_path);
02040 if (fd < 0)
02041 {
02042 fprintf(stderr, "[rospack] Unable to create temporary cache file %s: %s\n",
02043 tmp_cache_path, strerror(errno));
02044 }
02045 else
02046 {
02047 FILE *cache = fdopen(fd, "w");
02048 #endif
02049 if (!cache)
02050 {
02051 fprintf(stderr, "[rospack] Unable open cache file %s: %s\n",
02052 tmp_cache_path, strerror(errno));
02053 }
02054 else
02055 {
02056
02057 char *rr = getenv("ROS_ROOT");
02058 fprintf(cache, "#ROS_ROOT=%s\n", (rr ? rr : ""));
02059
02060 char *rpp = getenv("ROS_PACKAGE_PATH");
02061 fprintf(cache, "#ROS_PACKAGE_PATH=%s\n", (rpp ? rpp : ""));
02062 for(std::tr1::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
02063 it != stackages_.end();
02064 ++it)
02065 fprintf(cache, "%s\n", it->second->path_.c_str());
02066 fclose(cache);
02067 if(fs::exists(cache_path))
02068 remove(cache_path.c_str());
02069 if(rename(tmp_cache_path, cache_path.c_str()) < 0)
02070 {
02071 fprintf(stderr, "[rospack] Error: failed to rename cache file %s to %s: %s\n",
02072 tmp_cache_path, cache_path.c_str(), strerror(errno));
02073 }
02074 }
02075 }
02076 }
02077 }
02078
02079 FILE*
02080 Rosstackage::validateCache()
02081 {
02082 std::string cache_path = getCachePath();
02083
02084 double cache_max_age = DEFAULT_MAX_CACHE_AGE;
02085 const char *user_cache_time_str = getenv("ROS_CACHE_TIMEOUT");
02086 if(user_cache_time_str)
02087 cache_max_age = atof(user_cache_time_str);
02088 if(cache_max_age == 0.0)
02089 return NULL;
02090 struct stat s;
02091 if(stat(cache_path.c_str(), &s) == 0)
02092 {
02093 double dt = difftime(time(NULL), s.st_mtime);
02094
02095
02096 if ((cache_max_age > 0.0) && (dt > cache_max_age))
02097 return NULL;
02098 }
02099
02100 FILE* cache = fopen(cache_path.c_str(), "r");
02101 if(!cache)
02102 return NULL;
02103
02104
02105 char linebuf[30000];
02106 bool ros_root_ok = false;
02107 bool ros_package_path_ok = false;
02108
02109 const char* ros_root = getenv("ROS_ROOT");
02110 const char* ros_package_path = getenv("ROS_PACKAGE_PATH");
02111 for(;;)
02112 {
02113 if(!fgets(linebuf, sizeof(linebuf), cache))
02114 break;
02115 linebuf[strlen(linebuf)-1] = 0;
02116 if (linebuf[0] == '#')
02117 {
02118 if (!strncmp("#ROS_ROOT=", linebuf, 10))
02119 {
02120 if(!ros_root)
02121 {
02122 if(!strlen(linebuf+10))
02123 ros_root_ok = true;
02124 }
02125 else if (!strcmp(linebuf+10, ros_root))
02126 ros_root_ok = true;
02127 }
02128 else if(!strncmp("#ROS_PACKAGE_PATH=", linebuf, 18))
02129 {
02130 if(!ros_package_path)
02131 {
02132 if(!strlen(linebuf+18))
02133 ros_package_path_ok = true;
02134 }
02135 else if(!strcmp(linebuf+18, ros_package_path))
02136 ros_package_path_ok = true;
02137 }
02138 }
02139 else
02140 break;
02141 }
02142 if(ros_root_ok && ros_package_path_ok)
02143 {
02144
02145
02146 fseek(cache, 0, SEEK_SET);
02147 return cache;
02148 }
02149 else
02150 {
02151 fclose(cache);
02152 return NULL;
02153 }
02154 }
02155
02156 bool
02157 Rosstackage::expandExportString(Stackage* stackage,
02158 const std::string& instring,
02159 std::string& outstring)
02160 {
02161 outstring = instring;
02162 for(std::string::size_type i = outstring.find(MANIFEST_PREFIX);
02163 i != std::string::npos;
02164 i = outstring.find(MANIFEST_PREFIX))
02165 {
02166 outstring.replace(i, std::string(MANIFEST_PREFIX).length(),
02167 stackage->path_);
02168 }
02169
02170 if (outstring.find_first_of("$`") == std::string::npos)
02171 {
02172 return true;
02173 }
02174
02175
02176
02177
02178
02179
02180
02181
02182
02183
02184
02185 std::string cmd = std::string("ret=\"") + outstring + "\" && echo $ret";
02186
02187
02188 std::string token("\n");
02189 for (std::string::size_type s = cmd.find(token);
02190 s != std::string::npos;
02191 s = cmd.find(token, s))
02192 cmd.replace(s,token.length(),std::string(" "));
02193
02194 FILE* p;
02195 if(!(p = popen(cmd.c_str(), "r")))
02196 {
02197 std::string errmsg =
02198 std::string("failed to execute backquote expression ") +
02199 cmd + " in " +
02200 stackage->manifest_path_;
02201 logWarn(errmsg, true);
02202 return false;
02203 }
02204 else
02205 {
02206 char buf[8192];
02207 memset(buf,0,sizeof(buf));
02208
02209 do
02210 {
02211 clearerr(p);
02212 while(fgets(buf + strlen(buf),sizeof(buf)-strlen(buf)-1,p));
02213 } while(ferror(p) && errno == EINTR);
02214
02215 if(pclose(p) != 0)
02216 {
02217 std::string errmsg =
02218 std::string("got non-zero exit status from executing backquote expression ") +
02219 cmd + " in " +
02220 stackage->manifest_path_;
02221 return false;
02222 }
02223 else
02224 {
02225
02226 buf[strlen(buf)-1] = '\0';
02227
02228 outstring = buf;
02229 }
02230 }
02231
02232 return true;
02233 }
02234
02236
02238 Rospack::Rospack() :
02239 Rosstackage(ROSPACK_MANIFEST_NAME,
02240 ROSPACK_CACHE_NAME,
02241 ROSPACK_NAME,
02242 MANIFEST_TAG_PACKAGE)
02243 {
02244 }
02245
02246 Rosstackage::~Rosstackage()
02247 {
02248 for(std::tr1::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
02249 it != stackages_.end();
02250 ++it)
02251 {
02252 delete it->second;
02253 }
02254 }
02255
02256 const char*
02257 Rospack::usage()
02258 {
02259 return "USAGE: rospack <command> [options] [package]\n"
02260 " Allowed commands:\n"
02261 " help\n"
02262 " cflags-only-I [--deps-only] [package]\n"
02263 " cflags-only-other [--deps-only] [package]\n"
02264 " depends [package] (alias: deps)\n"
02265 " depends-indent [package] (alias: deps-indent)\n"
02266 " depends-manifests [package] (alias: deps-manifests)\n"
02267 " depends-msgsrv [package] (alias: deps-msgsrv)\n"
02268 " depends-on [package]\n"
02269 " depends-on1 [package]\n"
02270 " depends-why --target=<target> [package] (alias: deps-why)\n"
02271 " depends1 [package] (alias: deps1)\n"
02272 " export [--deps-only] --lang=<lang> --attrib=<attrib> [package]\n"
02273 " find [package]\n"
02274 " langs\n"
02275 " libs-only-L [--deps-only] [package]\n"
02276 " libs-only-l [--deps-only] [package]\n"
02277 " libs-only-other [--deps-only] [package]\n"
02278 " list\n"
02279 " list-duplicates\n"
02280 " list-names\n"
02281 " plugins --attrib=<attrib> [--top=<toppkg>] [package]\n"
02282 " profile [--length=<length>] [--zombie-only]\n"
02283 " rosdep [package] (alias: rosdeps)\n"
02284 " rosdep0 [package] (alias: rosdeps0)\n"
02285 " vcs [package]\n"
02286 " vcs0 [package]\n"
02287 " Extra options:\n"
02288 " -q Quiets error reports.\n\n"
02289 " If [package] is omitted, the current working directory\n"
02290 " is used (if it contains a manifest.xml).\n\n";
02291 }
02292
02294
02296 Rosstack::Rosstack() :
02297 Rosstackage(ROSSTACK_MANIFEST_NAME,
02298 ROSSTACK_CACHE_NAME,
02299 ROSSTACK_NAME,
02300 MANIFEST_TAG_STACK)
02301 {
02302 }
02303
02304 const char*
02305 Rosstack::usage()
02306 {
02307 return "USAGE: rosstack [options] <command> [stack]\n"
02308 " Allowed commands:\n"
02309 " help\n"
02310 " find [stack]\n"
02311 " contents [stack]\n"
02312 " list\n"
02313 " list-names\n"
02314 " depends [stack] (alias: deps)\n"
02315 " depends-manifests [stack] (alias: deps-manifests)\n"
02316 " depends1 [stack] (alias: deps1)\n"
02317 " depends-indent [stack] (alias: deps-indent)\n"
02318 " depends-why --target=<target> [stack] (alias: deps-why)\n"
02319 " depends-on [stack]\n"
02320 " depends-on1 [stack]\n"
02321 " contains [package]\n"
02322 " contains-path [package]\n"
02323 " profile [--length=<length>] \n\n"
02324 " If [stack] is omitted, the current working directory\n"
02325 " is used (if it contains a stack.xml).\n\n";
02326 }
02327
02328 TiXmlElement*
02329 get_manifest_root(Stackage* stackage)
02330 {
02331 TiXmlElement* ele = stackage->manifest_.RootElement();
02332 if(!ele)
02333 {
02334 std::string errmsg = std::string("error parsing manifest of package ") +
02335 stackage->name_ + " at " + stackage->manifest_path_;
02336 throw Exception(errmsg);
02337 }
02338 return ele;
02339 }
02340
02341 double
02342 time_since_epoch()
02343 {
02344 #if defined(WIN32)
02345 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
02346 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
02347 #else
02348 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
02349 #endif
02350 FILETIME ft;
02351 unsigned __int64 tmpres = 0;
02352
02353 GetSystemTimeAsFileTime(&ft);
02354 tmpres |= ft.dwHighDateTime;
02355 tmpres <<= 32;
02356 tmpres |= ft.dwLowDateTime;
02357 tmpres /= 10;
02358 tmpres -= DELTA_EPOCH_IN_MICROSECS;
02359 return static_cast<double>(tmpres) / 1e6;
02360 #else
02361 struct timeval tod;
02362 gettimeofday(&tod, NULL);
02363 return tod.tv_sec + 1e-6 * tod.tv_usec;
02364 #endif
02365 }
02366
02367
02368
02369 }