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
00029
00030 #include <cstdlib>
00031 #include <algorithm>
00032 #include <cstdio>
00033 #include <cstring>
00034 #include <cerrno>
00035 #include <climits>
00036 #include <string>
00037 #include <vector>
00038 #include <stack>
00039 #include <queue>
00040 #include <cassert>
00041 #if !defined(WIN32)
00042 #include <unistd.h>
00043 #include <dirent.h>
00044 #include <sys/time.h>
00045 #include <sys/file.h>
00046 #endif
00047 #include <stdexcept>
00048 #include <time.h>
00049 #include <sstream>
00050 #include <iterator>
00051
00052
00053 #if defined(_MSC_VER) // msvc only
00054 #define F_OK 0x00
00055 #else // non msvc only
00056 #include <libgen.h>
00057 #endif
00058
00059 #if defined(WIN32) //
00060 #include <direct.h>
00061 #include <winsock2.h>
00062 #include <time.h>
00063 #include <windows.h>
00064 #include <io.h>
00065 #include <fcntl.h>
00066 #define PATH_MAX MAX_PATH
00067 #define snprintf _snprintf
00068 #define popen _popen
00069 #define pclose _pclose
00070 #define getcwd _getcwd
00071 #define mkdir(a,b) _mkdir(a)
00072 #define fdopen _fdopen
00073 #define access _access
00074 #endif
00075
00076
00077 #include "tinyxml-2.5.3/tinyxml.h"
00078 #include "rospack/rospack.h"
00079 using namespace std;
00080
00081
00082 const double DEFAULT_MAX_CACHE_AGE = 60.0;
00083 const int MAX_DEPENDENCY_TREE_DEPTH = 1000;
00084 const int MAX_DIRECTORY_DEPTH = 1000;
00085
00086
00087 #include <sys/stat.h>
00088 #ifndef S_ISDIR
00089 #if defined(WIN32)
00090 #define S_ISDIR(x) (((x) & FILE_ATTRIBUTE_DIRECTORY) != 0)
00091 #else
00092 #define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR)
00093 #endif
00094 #endif
00095
00096 namespace rospack
00097 {
00098
00099 ROSPack *g_rospack = NULL;
00100
00101 #ifdef __APPLE__
00102 const string g_ros_os("osx");
00103 #else
00104 #if defined(WIN32)
00105 const string g_ros_os("win32");
00106 #else
00107 const string g_ros_os("linux");
00108 #endif
00109 #endif
00110
00111 #if defined(WIN32)
00112
00113
00114
00115 const char *fs_delim = "\\";
00116 const char *path_delim = ";";
00117 #else
00118 const char *fs_delim = "/";
00119 const char *path_delim = ":";
00120 #endif
00121
00122 inline string ToUnixPathDelim(string path)
00123 {
00124 #if defined(WIN32)
00125
00126
00127
00128 string token("\\");
00129 for (string::size_type ii = path.find(token); ii != string::npos;
00130 ii = path.find(token, ii))
00131 {
00132 path.replace(ii, token.length(), string("/"));
00133 }
00134 #endif
00135 return path;
00136 }
00137
00138 Package::Package(string _path) : path(_path),
00139 deps_calculated(false), direct_deps_calculated(false),
00140 descendants_calculated(false), manifest_loaded(false)
00141 {
00142 vector<string> name_tokens;
00143 string_split(path, name_tokens, fs_delim);
00144 name = name_tokens.back();
00145 }
00146 bool Package::is_package(string path)
00147 {
00148 return file_exists(path + string(fs_delim) + "manifest.xml");
00149 }
00150 bool Package::is_no_subdirs(string path)
00151 {
00152 return file_exists(path + string(fs_delim) + "rospack_nosubdirs");
00153 }
00154 const VecPkg &Package::deps1()
00155 {
00156 return direct_deps();
00157 }
00158 const VecPkg &Package::deps(traversal_order_t order, int depth)
00159 {
00160 if (depth > MAX_DEPENDENCY_TREE_DEPTH)
00161 {
00162 fprintf(stderr,"[rospack] woah! expanding the dependency tree made it blow "
00163 "up.\n There must be a circular dependency somewhere.\n");
00164 throw runtime_error(string("circular dependency"));
00165 }
00166 if (deps_calculated)
00167 return _deps;
00168
00169 VecPkg my_dd = direct_deps();
00170 for (VecPkg::iterator i = my_dd.begin(); i != my_dd.end(); ++i)
00171 {
00172 VecPkg d = (*i)->deps(order, depth+1);
00173 if (order == PREORDER)
00174 _deps.push_back(*i);
00175 for (VecPkg::iterator j = d.begin(); j != d.end(); ++j)
00176 {
00177
00178
00179 bool have = false;
00180 VecPkg::iterator prior_loc;
00181 for (VecPkg::iterator k = _deps.begin(); k != _deps.end() && !have; ++k)
00182 if ((*k) == (*j))
00183 {
00184 prior_loc = k;
00185 have = true;
00186 }
00187 if (have && order == PREORDER)
00188 {
00189 _deps.erase(prior_loc);
00190 _deps.push_back(*j);
00191 }
00192 else if (!have)
00193 _deps.push_back(*j);
00194 }
00195 if (order == POSTORDER)
00196 {
00197
00198 bool have = false;
00199 for (VecPkg::iterator k = _deps.begin(); k != _deps.end() && !have; ++k)
00200 if ((*k) == (*i))
00201 have = true;
00202 if (!have)
00203 _deps.push_back(*i);
00204 }
00205 }
00206 deps_calculated = true;
00207 return _deps;
00208 }
00209 string Package::manifest_path()
00210 {
00211 return path + string(fs_delim) + "manifest.xml";
00212 }
00213 string Package::flags(string lang, string attrib)
00214 {
00215 VecPkg d = deps(PREORDER);
00216 string s;
00217
00218
00219 if(!g_rospack->opt_deps_only)
00220 s += this->direct_flags(lang, attrib) + string(" ");
00221 for (VecPkg::iterator i = d.begin(); i != d.end(); ++i)
00222 {
00223 string f = (*i)->direct_flags(lang, attrib);
00224 if (f.length())
00225 s += f + string(" ");
00226 }
00227 return s;
00228 }
00229
00230 string Package::rosdep()
00231 {
00232 string sd;
00233 rospack_tinyxml::TiXmlElement *mroot = manifest_root();
00234 for(rospack_tinyxml::TiXmlElement *sd_ele = mroot->FirstChildElement("rosdep");
00235 sd_ele;
00236 sd_ele = sd_ele->NextSiblingElement("rosdep"))
00237 {
00238 const char *att_str;
00239 if((att_str = sd_ele->Attribute("name")))
00240 sd += string("name: ") + string(att_str);
00241 sd += string("\n");
00242 }
00243
00244 return sd;
00245 }
00246
00247 string Package::versioncontrol()
00248 {
00249 string sd;
00250 rospack_tinyxml::TiXmlElement *mroot = manifest_root();
00251 for(rospack_tinyxml::TiXmlElement *sd_ele = mroot->FirstChildElement("versioncontrol");
00252 sd_ele;
00253 sd_ele = sd_ele->NextSiblingElement("versioncontrol"))
00254 {
00255 const char *att_str;
00256 if((att_str = sd_ele->Attribute("type")))
00257 sd += string("type: ") + string(att_str);
00258 if((att_str = sd_ele->Attribute("url")))
00259 sd += string("\turl: ") + string(att_str);
00260 sd += string("\n");
00261 }
00262
00263 return sd;
00264 }
00265
00266 vector<pair<string, string> > Package::plugins()
00267 {
00268 vector<pair<string, string> > plugins;
00269
00270 VecPkg deplist;
00271
00272
00273 if(g_rospack->opt_top.size())
00274 {
00275 Package* gtp = g_get_pkg(g_rospack->opt_top);
00276 deplist = gtp->deps(Package::POSTORDER);
00277 deplist.push_back(gtp);
00278 }
00279
00280 VecPkg desc1 = descendants1();
00281 desc1.push_back(this);
00282 VecPkg::iterator it = desc1.begin();
00283 VecPkg::iterator end = desc1.end();
00284 for (; it != end; ++it)
00285 {
00286
00287
00288 if(deplist.size())
00289 {
00290 bool found = false;
00291 for(VecPkg::const_iterator dit = deplist.begin();
00292 dit != deplist.end();
00293 dit++)
00294 {
00295 if((*dit)->name == (*it)->name)
00296 {
00297 found = true;
00298 break;
00299 }
00300 }
00301 if(!found)
00302 continue;
00303 }
00304 std::string flags = (*it)->direct_flags(name, g_rospack->opt_attrib);
00305 if (!flags.empty())
00306 {
00307 plugins.push_back(make_pair((*it)->name, flags));
00308 }
00309 }
00310
00311 return plugins;
00312 }
00313
00314
00315 VecPkg Package::descendants1()
00316 {
00317 VecPkg children;
00318
00319
00320
00321
00322 VecPkg pkgs_copy(pkgs);
00323 for (VecPkg::iterator p = pkgs_copy.begin(); p != pkgs_copy.end(); ++p)
00324 {
00325
00326
00327 try
00328 {
00329 if ((*p)->has_parent(name))
00330 children.push_back(*p);
00331 }
00332 catch (runtime_error &e)
00333 {
00334 }
00335 }
00336 return children;
00337 }
00338
00339 const vector<Package *> &Package::descendants(int depth)
00340 {
00341 if (depth > MAX_DEPENDENCY_TREE_DEPTH)
00342 {
00343 fprintf(stderr, "[rospack] woah! circular dependency in the ros tree! aaaaaa!\n");
00344 throw runtime_error(string("circular dependency"));
00345 }
00346 if (descendants_calculated)
00347 return _descendants;
00348 VecPkg desc_with_dups;
00349 for (VecPkg::iterator p = pkgs.begin(); p != pkgs.end(); ++p)
00350 {
00351
00352
00353 try
00354 {
00355 if ((*p)->has_parent(name))
00356 {
00357 desc_with_dups.push_back(*p);
00358 const VecPkg &p_desc = (*p)->descendants(depth+1);
00359 for (VecPkg::const_iterator q = p_desc.begin();
00360 q != p_desc.end(); ++q)
00361 desc_with_dups.push_back(*q);
00362 }
00363 }
00364 catch (runtime_error &e)
00365 {
00366 }
00367 }
00368 _descendants.clear();
00369 for (VecPkg::iterator p = desc_with_dups.begin();
00370 p != desc_with_dups.end(); ++p)
00371 {
00372 bool found = false;
00373 for (VecPkg::iterator q = _descendants.begin();
00374 q != _descendants.end() && !found; ++q)
00375 if ((*q)->name == (*p)->name)
00376 found = true;
00377 if (!found)
00378 _descendants.push_back(*p);
00379 }
00380 descendants_calculated = true;
00381 return _descendants;
00382 }
00383
00384
00385 bool Package::has_parent(string pkg)
00386 {
00387 vector<Package *> parents = direct_deps(true);
00388 for (VecPkg::iterator i = parents.begin(); i != parents.end(); ++i)
00389 if ((*i)->name == pkg)
00390 return true;
00391 return false;
00392 }
00393
00394 const vector<Package *> &Package::direct_deps(bool missing_package_as_warning)
00395 {
00396 if (direct_deps_calculated)
00397 return _direct_deps;
00398 #ifdef VERBOSE_DEBUG
00399 fprintf(stderr, "calculating direct deps for package [%s]\n", name.c_str());
00400 #endif
00401 rospack_tinyxml::TiXmlElement *mroot = manifest_root();
00402 rospack_tinyxml::TiXmlNode *dep_node = 0;
00403 while ((dep_node = mroot->IterateChildren(string("depend"), dep_node)))
00404 {
00405 rospack_tinyxml::TiXmlElement *dep_ele = dep_node->ToElement();
00406 assert(dep_ele);
00407 const char *dep_pkgname = dep_ele->Attribute("package");
00408 if (!dep_pkgname)
00409 {
00410 fprintf(stderr,"[rospack] bad depend syntax (no 'package' attribute) in [%s]\n",
00411 manifest_path().c_str());
00412 throw runtime_error(string("invalid manifest"));
00413 }
00414 else if(dep_pkgname == name)
00415 {
00416 fprintf(stderr,"[rospack] package [%s] depends on itself (%s).\n",
00417 name.c_str(), manifest_path().c_str());
00418 throw runtime_error(string("self-dependency"));
00419 }
00420
00421
00422 char* dep_pkgname_copy = strdup(dep_pkgname);
00423 #ifdef VERBOSE_DEBUG
00424 fprintf(stderr, "direct_deps: pkg %s has dep %s\n", name.c_str(), dep_pkgname_copy);
00425 #endif
00426 try
00427 {
00428 _direct_deps.push_back(g_get_pkg(dep_pkgname_copy));
00429 }
00430 catch (runtime_error &e)
00431 {
00432 if (missing_package_as_warning)
00433 {
00434
00435 if(g_rospack->opt_warn_on_missing_deps)
00436 {
00437 fprintf(stderr, "[rospack] warning: couldn't find dependency [%s] of [%s]\n",
00438 dep_pkgname_copy, name.c_str());
00439 }
00440 }
00441 else
00442 {
00443 fprintf(stderr, "[rospack] couldn't find dependency [%s] of [%s]\n",
00444 dep_pkgname_copy, name.c_str());
00445 free(dep_pkgname_copy);
00446 throw runtime_error(string("missing dependency"));
00447 }
00448 }
00449 free(dep_pkgname_copy);
00450 }
00451 direct_deps_calculated = true;
00452 return _direct_deps;
00453 }
00454
00455 string Package::cpp_message_flags(bool cflags, bool lflags)
00456 {
00457 bool msg_exists = file_exists((path + "/msg_gen/generated").c_str());
00458 bool srv_exists = file_exists((path + "/srv_gen/generated").c_str());
00459
00460 string flags;
00461
00462 if (cflags)
00463 {
00464 if (msg_exists)
00465 {
00466 flags += string(" -I") + path + "/msg_gen/cpp/include";
00467 }
00468
00469 if (srv_exists)
00470 {
00471 flags += string(" -I") + path + "/srv_gen/cpp/include";
00472 }
00473 }
00474
00475
00476
00477 #if 0
00478 if (lflags)
00479 {
00480 if (msg_exists)
00481 {
00482 flags += string(" -L") + path + "/lib";
00483 flags += string(" -Wl,-rpath,") + path + "/lib";
00484 flags += " -l" + package->name + "msgs";
00485 }
00486
00487 if (srv_exists)
00488 {
00489
00490 if (!msg_exists)
00491 {
00492 flags += string(" -L") + path + "/lib";
00493 flags += string(" -Wl,-rpath,") + path + "/lib";
00494 }
00495
00496 flags += " -l" + package->name + "srvs";
00497 }
00498 }
00499 #endif
00500
00501 flags += " ";
00502 return flags;
00503 }
00504
00505 string Package::direct_flags(string lang, string attrib)
00506 {
00507 rospack_tinyxml::TiXmlElement *mroot = manifest_root();
00508 rospack_tinyxml::TiXmlElement *export_ele = mroot->FirstChildElement("export");
00509 string str;
00510 if (export_ele)
00511 {
00512 bool os_match = false;
00513 rospack_tinyxml::TiXmlElement *best_usage = NULL;
00514 for (rospack_tinyxml::TiXmlElement *lang_ele = export_ele->FirstChildElement(lang);
00515 lang_ele; lang_ele = lang_ele->NextSiblingElement(lang))
00516 {
00517 const char *os_str;
00518 if ((os_str = lang_ele->Attribute("os")))
00519 {
00520 if(g_ros_os == string(os_str))
00521 {
00522 if(os_match)
00523 {
00524 fprintf(stderr, "[rospack] warning: ignoring duplicate \"%s\" tag with os=\"%s\" in export block\n",
00525 lang.c_str(), os_str);
00526 }
00527 else
00528 {
00529 best_usage = lang_ele;
00530 os_match = true;
00531 }
00532 }
00533 }
00534 if(!os_match)
00535 {
00536 if (!best_usage)
00537 best_usage = lang_ele;
00538 else if(!os_str)
00539 {
00540 fprintf(stderr, "[rospack] warning: ignoring duplicate \"%s\" tag in export block\n",
00541 lang.c_str());
00542 }
00543 }
00544 }
00545
00546
00547
00548
00549 if (best_usage)
00550 {
00551 const char *cstr = best_usage->Attribute(attrib.c_str());
00552 if (cstr)
00553 {
00554 str = cstr;
00555 while (1)
00556 {
00557 int i = str.find(string("${prefix}"));
00558 if (i < 0)
00559 break;
00560 str.replace(i, string("${prefix}").length(), path);
00561 }
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573 string cmd = string("ret=\"") + str + string("\" && echo $ret");
00574
00575
00576 string token("\n");
00577 for (string::size_type s = cmd.find(token); s != string::npos;
00578 s = cmd.find(token, s))
00579 {
00580 cmd.replace(s,token.length(),string(" "));
00581 }
00582
00583 FILE* p;
00584 if(!(p = popen(cmd.c_str(), "r")))
00585 {
00586 fprintf(stderr, "[rospack] warning: failed to execute backquote "
00587 "expression \"%s\" in [%s]\n",
00588 cmd.c_str(), manifest_path().c_str());
00589 string errmsg = string("error in backquote expansion for ") + g_rospack->opt_package;
00590 throw runtime_error(errmsg);
00591 }
00592 else
00593 {
00594 char buf[8192];
00595 memset(buf,0,sizeof(buf));
00596
00597 do
00598 {
00599 clearerr(p);
00600 while(fgets(buf + strlen(buf),sizeof(buf)-strlen(buf)-1,p));
00601 } while(ferror(p) && errno == EINTR);
00602
00603 if(pclose(p) != 0)
00604 {
00605 fprintf(stderr, "[rospack] warning: got non-zero exit status from executing backquote expression \"%s\" in [%s]\n",
00606 cmd.c_str(), manifest_path().c_str());
00607 string errmsg = string("error in backquote expansion for ") + g_rospack->opt_package;
00608 throw runtime_error(errmsg);
00609 }
00610 else
00611 {
00612
00613 buf[strlen(buf)-1] = '\0';
00614
00615 str = string(buf);
00616 }
00617 }
00618 }
00619 }
00620 }
00621
00622 if (lang == "cpp")
00623 {
00624 if (attrib == "cflags")
00625 {
00626
00627 str += cpp_message_flags(true, false);
00628 }
00629 else if (attrib == "lflags")
00630 {
00631
00632 str += cpp_message_flags(false, true);
00633 }
00634 }
00635
00636 return str;
00637 }
00638
00639 void Package::load_manifest()
00640 {
00641 if (manifest_loaded)
00642 return;
00643 if (!manifest.LoadFile(manifest_path()))
00644 {
00645 string errmsg = string("error parsing manifest file at [") + manifest_path().c_str() + string("]");
00646 fprintf(stderr, "[rospack] warning: error parsing manifest file at [%s]\n",
00647 manifest_path().c_str());
00648
00649 manifest_loaded = true;
00650 throw runtime_error(errmsg);
00651 }
00652 }
00653
00654 rospack_tinyxml::TiXmlElement *Package::manifest_root()
00655 {
00656 load_manifest();
00657 rospack_tinyxml::TiXmlElement *ele = manifest.RootElement();
00658 if (!ele)
00659 {
00660 string errmsg = string("error parsing manifest file at [") + manifest_path().c_str() + string("]");
00661 throw runtime_error(errmsg);
00662 }
00663 return ele;
00664 }
00665
00666
00667 void Package::accumulate_deps(AccList& acc_list, Package* to)
00668 {
00669 VecPkg dd = direct_deps();
00670 for(VecPkg::iterator it = dd.begin();
00671 it != dd.end();
00672 ++it)
00673 {
00674 if((*it)->name == to->name)
00675 {
00676 Acc acc;
00677 acc.push_back(this);
00678 acc.push_back(to);
00679 acc_list.push_back(acc);
00680 }
00681 else
00682 {
00683 AccList l;
00684 (*it)->accumulate_deps(l, to);
00685 for(AccList::iterator lit = l.begin();
00686 lit != l.end();
00687 ++lit)
00688 {
00689 lit->push_front(this);
00690 acc_list.push_back(*lit);
00691 }
00692 }
00693 }
00694 }
00695
00696 VecPkg Package::pkgs;
00697 VecPkg Package::deleted_pkgs;
00698
00700
00701
00702 ROSPack::ROSPack() :
00703 ros_root(NULL),
00704 opt_deps_only(false),
00705 opt_profile_length(0),
00706 opt_profile_zombie_only(false),
00707 opt_warn_on_missing_deps(true),
00708 opt_display_duplicate_pkgs(false),
00709 opt_quiet(false),
00710 cache_lock_failed(false),
00711 crawled(false),
00712 my_argc(0),
00713 my_argv(NULL),
00714 total_num_pkgs(0),
00715 duplicate_packages_found(false)
00716 {
00717 g_rospack = this;
00718 Package::pkgs.reserve(500);
00719 ros_root = getenv("ROS_ROOT");
00720 if (!ros_root)
00721 {
00722 fprintf(stderr,"[rospack] ROS_ROOT is not defined in the environment.\n");
00723 throw runtime_error(string("no ROS_ROOT"));
00724 }
00725 if (!file_exists(ros_root))
00726 {
00727 fprintf(stderr,"[rospack] the path specified as ROS_ROOT is not "
00728 "accessible. Please ensure that this environment variable "
00729 "is set and is writeable by your user account.\n");
00730 throw runtime_error(string("no ROS_ROOT"));
00731 }
00732
00733 crawl_for_packages();
00734 }
00735
00736 ROSPack::~ROSPack()
00737 {
00738 for (VecPkg::iterator p = Package::pkgs.begin();
00739 p != Package::pkgs.end(); ++p)
00740 delete (*p);
00741 Package::pkgs.clear();
00742 for (VecPkg::iterator p = Package::deleted_pkgs.begin();
00743 p != Package::deleted_pkgs.end(); ++p)
00744 delete (*p);
00745 Package::deleted_pkgs.clear();
00746 freeArgv();
00747 }
00748
00749 const char* ROSPack::usage()
00750 {
00751 return "USAGE: rospack <command> [options] [package]\n"
00752 " Allowed commands:\n"
00753 " help\n"
00754 " find [package]\n"
00755 " list\n"
00756 " list-names\n"
00757 " list-duplicates\n"
00758 " langs\n"
00759 " depends [package] (alias: deps)\n"
00760 " depends-manifests [package] (alias: deps-manifests)\n"
00761 " depends-msgsrv [package] (alias: deps-msgsrv)\n"
00762 " depends1 [package] (alias: deps1)\n"
00763 " depends-indent [package] (alias: deps-indent)\n"
00764 " depends-why --target=<target> [package] (alias: deps-why)\n"
00765 " rosdep [package] (alias: rosdeps)\n"
00766 " rosdep0 [package] (alias: rosdeps0)\n"
00767 " vcs [package]\n"
00768 " vcs0 [package]\n"
00769 " depends-on [package]\n"
00770 " depends-on1 [package]\n"
00771 " export [--deps-only] --lang=<lang> --attrib=<attrib> [package]\n"
00772 " plugins --attrib=<attrib> [--top=<toppkg>] [package]\n"
00773 " cflags-only-I [--deps-only] [package]\n"
00774 " cflags-only-other [--deps-only] [package]\n"
00775 " libs-only-L [--deps-only] [package]\n"
00776 " libs-only-l [--deps-only] [package]\n"
00777 " libs-only-other [--deps-only] [package]\n"
00778 " profile [--length=<length>] [--zombie-only]\n"
00779 " Extra options:\n"
00780 " -q Quiets error reports.\n\n"
00781 " If [package] is omitted, the current working directory\n"
00782 " is used (if it contains a manifest.xml).\n\n";
00783 }
00784
00785 Package *ROSPack::get_pkg(string pkgname)
00786 {
00787 for (VecPkg::iterator p = Package::pkgs.begin();
00788 p != Package::pkgs.end(); ++p)
00789 {
00790 if ((*p)->name == pkgname)
00791 {
00792 if(!crawled)
00793 {
00794
00795
00796 std::string manifest_path = (*p)->path + fs_delim + "manifest.xml";
00797 struct stat s;
00798 int ret;
00799 while((ret = stat(manifest_path.c_str(), &s)) != 0 &&
00800 errno == EINTR);
00801 if(ret == 0)
00802 {
00803
00804 return (*p);
00805 }
00806 else
00807 {
00808
00809 fprintf(stderr, "[rospack] warning: invalid cached location %s for package %s; forcing recrawl\n",
00810 (*p)->path.c_str(),
00811 (*p)->name.c_str());
00812 break;
00813 }
00814 }
00815 else
00816 {
00817
00818 return (*p);
00819 }
00820 }
00821 }
00822 if (!crawled)
00823 {
00824 crawl_for_packages(true);
00825 return get_pkg(pkgname);
00826 }
00827 string errmsg = string("couldn't find package [") + pkgname + string("]");
00828 throw runtime_error(errmsg);
00829 return NULL;
00830 }
00831
00832 int ROSPack::cmd_depends_on(bool include_indirect)
00833 {
00834
00835
00836
00837
00838
00839 if(opt_package.size() == 0)
00840 {
00841 string errmsg = string("no package name given, and current directory is not a package root");
00842 throw runtime_error(errmsg);
00843 }
00844
00845
00846 opt_warn_on_missing_deps = false;
00847
00848
00849
00850
00851
00852 crawl_for_packages(true);
00853
00854 Package* p;
00855 try
00856 {
00857 p = get_pkg(opt_package);
00858 }
00859 catch(runtime_error)
00860 {
00861 fprintf(stderr, "[rospack] warning: package %s doesn't exist\n",
00862 opt_package.c_str());
00863
00864
00865 p = add_package(opt_package);
00866 }
00867 assert(p);
00868 const VecPkg descendants = include_indirect ? p->descendants()
00869 : p->descendants1();
00870 for (VecPkg::const_iterator p = descendants.begin();
00871 p != descendants.end(); ++p)
00872 {
00873
00874 output_acc += (*p)->name + "\n";
00875 }
00876 return 0;
00877 }
00878
00879
00880 int ROSPack::cmd_depends_why()
00881 {
00882 AccList acc_list;
00883 Package* from = get_pkg(opt_package);
00884 Package* to = get_pkg(opt_target);
00885 from->accumulate_deps(acc_list, to);
00886 printf("Dependency chains from %s to %s:\n",
00887 from->name.c_str(), to->name.c_str());
00888 for(AccList::iterator lit = acc_list.begin();
00889 lit != acc_list.end();
00890 ++lit)
00891 {
00892 printf("* ");
00893 for(Acc::iterator ait = lit->begin();
00894 ait != lit->end();
00895 ++ait)
00896 {
00897 if(ait != lit->begin())
00898 printf("-> ");
00899 printf("%s ", (*ait)->name.c_str());
00900 }
00901 printf("\n");
00902 }
00903 return 0;
00904 }
00905
00906 int ROSPack::cmd_find()
00907 {
00908
00909 Package *p = get_pkg(opt_package);
00910
00911 output_acc += ToUnixPathDelim(p->path) + "\n";
00912 return 0;
00913 }
00914
00915 int ROSPack::cmd_deps()
00916 {
00917 VecPkg d = get_pkg(opt_package)->deps(Package::POSTORDER);
00918 for (VecPkg::iterator i = d.begin(); i != d.end(); ++i)
00919 {
00920
00921 output_acc += ToUnixPathDelim((*i)->name) + "\n";
00922 }
00923 return 0;
00924 }
00925
00926 int ROSPack::cmd_deps_manifests()
00927 {
00928 VecPkg d = get_pkg(opt_package)->deps(Package::POSTORDER);
00929 for (VecPkg::iterator i = d.begin(); i != d.end(); ++i)
00930 {
00931
00932 output_acc += ToUnixPathDelim((*i)->path + "/manifest.xml ");
00933 }
00934
00935 output_acc += "\n";
00936 return 0;
00937 }
00938
00939 int ROSPack::cmd_deps_msgsrv()
00940 {
00941 VecPkg d = get_pkg(opt_package)->deps(Package::POSTORDER);
00942 for (VecPkg::iterator i = d.begin(); i != d.end(); ++i)
00943 {
00944 Package* p = *i;
00945 bool msg_exists = file_exists(ToUnixPathDelim(p->path + "/msg_gen/generated").c_str());
00946 bool srv_exists = file_exists(ToUnixPathDelim(p->path + "/srv_gen/generated").c_str());
00947
00948 if (msg_exists)
00949 {
00950 output_acc += ToUnixPathDelim(p->path + "/msg_gen/generated ");
00951 }
00952
00953 if (srv_exists)
00954 {
00955 output_acc += ToUnixPathDelim(p->path + "/srv_gen/generated ");
00956 }
00957 }
00958 output_acc += "\n";
00959 return 0;
00960 }
00961
00962 int ROSPack::cmd_deps1()
00963 {
00964 VecPkg d = get_pkg(opt_package)->deps1();
00965 for (VecPkg::iterator i = d.begin(); i != d.end(); ++i)
00966 {
00967
00968 output_acc += ToUnixPathDelim((*i)->name) + "\n";
00969 }
00970 return 0;
00971 }
00972
00973 int ROSPack::cmd_depsindent(Package* pkg, int indent)
00974 {
00975 VecPkg d = pkg->deps1();
00976
00977 for (VecPkg::iterator i = d.begin(); i != d.end(); ++i)
00978 {
00979 for(int s=0; s<indent; s++)
00980 {
00981
00982 output_acc += " ";
00983 }
00984
00985 output_acc += ToUnixPathDelim((*i)->name) + "\n";
00986 cmd_depsindent(*i, indent+2);
00987 }
00988 return 0;
00989 }
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006 static bool space(char c) { return isspace(c); }
01007 static bool not_space(char c) { return !isspace(c); }
01008 static vector<string> split_space(const string& str)
01009 {
01010 typedef string::const_iterator iter;
01011 vector<string> ret;
01012 iter i = str.begin();
01013 while (i != str.end())
01014 {
01015 i = find_if(i, str.end(), not_space);
01016 iter j = find_if(i, str.end(), space);
01017 if (i != str.end())
01018 while (j != str.end() && *(j-1) == '\\')
01019 j = find_if(j+1, str.end(), space);
01020 ret.push_back(string(i, j));
01021 i = j;
01022 }
01023 return ret;
01024 }
01025
01026 string ROSPack::snarf_libs(string flags, bool invert)
01027 {
01028 vector<string> tokens = split_space(flags);
01029 string snarfed;
01030 for (size_t i = 0; i < tokens.size(); ++i)
01031 {
01032
01033 if (invert)
01034 {
01035 if ((tokens[i].substr(0, 2) != "-l") &&
01036 (tokens[i].length() < 2 || tokens[i][0] != '/' || tokens[i].substr(tokens[i].length()-2) != ".a"))
01037 snarfed += (snarfed.length() ? " " : "" ) + tokens[i];
01038 }
01039 else
01040 {
01041 if (tokens[i].substr(0, 2) == "-l")
01042 snarfed += (snarfed.length() ? " " : "" ) + tokens[i].substr(2);
01043 else if (tokens[i].length() > 2 && tokens[i][0] == '/' && tokens[i].substr(tokens[i].length()-2) == ".a")
01044 snarfed += (snarfed.length() ? " " : "" ) + tokens[i];
01045 }
01046 }
01047 return snarfed;
01048 }
01049
01050 string ROSPack::snarf_flags(string flags, string prefix, bool invert)
01051 {
01052 vector<string> tokens = split_space(flags);
01053 string snarfed;
01054 for (size_t i = 0; i < tokens.size(); ++i)
01055 {
01056 if ((tokens[i].substr(0, prefix.length()) == prefix) ^ invert)
01057 {
01058 snarfed += (snarfed.length() ? " " : "" ) + tokens[i].substr(invert ? 0 : prefix.length());
01059 }
01060 }
01061 return snarfed;
01062 }
01063
01064 int ROSPack::cmd_libs_only(string token)
01065 {
01066 string lflags = get_pkg(opt_package)->flags("cpp", "lflags");;
01067 if(!token.compare("-other"))
01068 {
01069 lflags = snarf_libs(lflags, true);
01070 lflags = snarf_flags(lflags, "-L", true);
01071 }
01072 else if(!token.compare("-l"))
01073 {
01074 lflags = snarf_libs(lflags);
01075 }
01076 else
01077 {
01078 lflags = snarf_flags(lflags, token);
01079 lflags = deduplicate_tokens(lflags);
01080 }
01081
01082 output_acc += ToUnixPathDelim(lflags) + "\n";
01083 return 0;
01084 }
01085
01086 int ROSPack::cmd_cflags_only(string token)
01087 {
01088 string cflags = get_pkg(opt_package)->flags("cpp", "cflags");
01089 if(!token.compare("-other"))
01090 cflags = snarf_flags(cflags, "-I", true);
01091 else
01092 {
01093 cflags = snarf_flags(cflags, token);
01094 cflags = deduplicate_tokens(cflags);
01095 }
01096
01097 output_acc += ToUnixPathDelim(cflags) + "\n";
01098 return 0;
01099 }
01100
01101 void ROSPack::export_flags(string pkg, string lang, string attrib)
01102 {
01103 string flags = get_pkg(pkg)->flags(lang, attrib);
01104
01105 output_acc += ToUnixPathDelim(flags) + "\n";
01106 }
01107
01108 int ROSPack::cmd_versioncontrol(int depth)
01109 {
01110 string sds;
01111
01112 sds += get_pkg(opt_package)->versioncontrol();
01113
01114 if(depth < 0)
01115 {
01116 VecPkg descs = get_pkg(opt_package)->deps(Package::POSTORDER);
01117 for(VecPkg::iterator dit = descs.begin();
01118 dit != descs.end();
01119 dit++)
01120 {
01121 sds += (*dit)->versioncontrol();
01122 }
01123 }
01124
01125
01126 output_acc += sds;
01127 return 0;
01128 }
01129
01130 int ROSPack::cmd_rosdep(int depth)
01131 {
01132 string sds;
01133 sds += get_pkg(opt_package)->rosdep();
01134
01135 if(depth < 0)
01136 {
01137 VecPkg descs = get_pkg(opt_package)->deps(Package::POSTORDER);
01138 for(VecPkg::iterator dit = descs.begin();
01139 dit != descs.end();
01140 dit++)
01141 {
01142 sds += (*dit)->rosdep();
01143 }
01144 }
01145
01146
01147 output_acc += sds;
01148 return 0;
01149 }
01150
01151 int ROSPack::cmd_export()
01152 {
01153 export_flags(opt_package, opt_lang, opt_attrib);
01154 return 0;
01155 }
01156
01157 int ROSPack::cmd_plugins()
01158 {
01159
01160 opt_warn_on_missing_deps = false;
01161
01162 Package* p = get_pkg(opt_package);
01163
01164 vector<pair<string, string> > plugins = p->plugins();
01165 vector<pair<string, string> >::iterator it = plugins.begin();
01166 vector<pair<string, string> >::iterator end = plugins.end();
01167 for (; it != end; ++it)
01168 {
01169
01170 output_acc += it->first + " " + it->second + "\n";
01171 }
01172
01173 return 0;
01174 }
01175
01176 void ROSPack::freeArgv()
01177 {
01178 if(my_argc)
01179 {
01180 for(int i=0;i<my_argc;i++)
01181 free(my_argv[i]);
01182 free(my_argv);
01183 }
01184 my_argc = 0;
01185 my_argv = NULL;
01186 }
01187
01188 int ROSPack::run(const std::string& cmd)
01189 {
01190 std::vector<std::string> cmd_list;
01191
01192
01193
01194
01195 string_split(cmd, cmd_list, " ");
01196
01197
01198 freeArgv();
01199
01200 my_argc = (int)cmd_list.size() + 1;
01201 my_argv = (char**)malloc(sizeof(char*) * my_argc);
01202 my_argv[0] = strdup("rospack");
01203 for(int i=1;i<my_argc;i++)
01204 my_argv[i] = strdup(cmd_list[i-1].c_str());
01205
01206 return run(my_argc, my_argv);
01207 }
01208
01209 int ROSPack::run(int argc, char **argv)
01210 {
01211 assert(argc >= 2);
01212 int i;
01213 const char* opt_deps_name = "--deps-only";
01214 const char* opt_zombie_name = "--zombie-only";
01215 const char* opt_lang_name = "--lang=";
01216 const char* opt_attrib_name = "--attrib=";
01217 const char* opt_length_name = "--length=";
01218 const char* opt_top_name = "--top=";
01219 const char* opt_target_name = "--target=";
01220 const char* opt_quiet_name = "-q";
01221
01222
01223 opt_deps_only = false;
01224
01225 opt_lang = string("");
01226
01227 opt_attrib = string("");
01228
01229 opt_length = string("");
01230
01231 opt_top = string("");
01232
01233 opt_target = string("");
01234
01235 opt_package = string("");
01236
01237 opt_profile_length = 0;
01238
01239 opt_profile_zombie_only = false;
01240
01241 opt_warn_on_missing_deps = true;
01242
01243 opt_display_duplicate_pkgs = false;
01244
01245 output_acc = string("");
01246
01247 string errmsg = string(usage());
01248
01249 i=1;
01250 const char* cmd = argv[i++];
01251
01252 for(;i<argc;i++)
01253 {
01254 if(!strcmp(argv[i], opt_deps_name))
01255 opt_deps_only=true;
01256 else if(!strcmp(argv[i], opt_zombie_name))
01257 opt_profile_zombie_only=true;
01258 else if(!strcmp(argv[i], opt_quiet_name))
01259 opt_quiet=true;
01260 else if(!strncmp(argv[i], opt_target_name, strlen(opt_target_name)))
01261 {
01262 if(opt_target.size())
01263 throw runtime_error(errmsg);
01264 else if(strlen(argv[i]) > strlen(opt_target_name))
01265 opt_target = string(argv[i]+strlen(opt_target_name));
01266 else
01267 throw runtime_error(errmsg);
01268 }
01269 else if(!strncmp(argv[i], opt_lang_name, strlen(opt_lang_name)))
01270 {
01271 if(opt_lang.size())
01272 throw runtime_error(errmsg);
01273 else if(strlen(argv[i]) > strlen(opt_lang_name))
01274 opt_lang = string(argv[i]+strlen(opt_lang_name));
01275 else
01276 throw runtime_error(errmsg);
01277 }
01278 else if(!strncmp(argv[i], opt_attrib_name, strlen(opt_attrib_name)))
01279 {
01280 if(opt_attrib.size())
01281 throw runtime_error(errmsg);
01282 else if(strlen(argv[i]) > strlen(opt_attrib_name))
01283 opt_attrib = string(argv[i]+strlen(opt_attrib_name));
01284 else
01285 throw runtime_error(errmsg);
01286 }
01287 else if(!strncmp(argv[i], opt_length_name, strlen(opt_length_name)))
01288 {
01289 if(strlen(argv[i]) > strlen(opt_length_name))
01290 opt_length = string(argv[i]+strlen(opt_length_name));
01291 else
01292 throw runtime_error(errmsg);
01293 }
01294 else if(!strncmp(argv[i], opt_top_name, strlen(opt_top_name)))
01295 {
01296 if(strlen(argv[i]) > strlen(opt_top_name))
01297 opt_top = string(argv[i]+strlen(opt_top_name));
01298 else
01299 throw runtime_error(errmsg);
01300 }
01301 else
01302 break;
01303 }
01304
01305 if((strcmp(cmd, "depends-why") && strcmp(cmd, "deps-why")) && opt_target.size())
01306 throw runtime_error(errmsg);
01307
01308 if((!strcmp(cmd, "depends-why") || !strcmp(cmd, "deps-why")) && !opt_target.size())
01309 throw runtime_error(errmsg);
01310
01311 if(strcmp(cmd, "profile") && (opt_length.size() || opt_profile_zombie_only))
01312 throw runtime_error(errmsg);
01313
01314
01315 if(strcmp(cmd, "plugins") && opt_top.size())
01316 throw runtime_error(errmsg);
01317
01318
01319 if((strcmp(cmd, "export") && strcmp(cmd, "plugins")) &&
01320 opt_attrib.size())
01321 throw runtime_error(errmsg);
01322
01323
01324 if((strcmp(cmd, "export") && opt_lang.size()))
01325 throw runtime_error(errmsg);
01326
01327
01328 if(!strcmp(cmd, "export") && (!opt_lang.size() || !opt_attrib.size()))
01329 throw runtime_error(errmsg);
01330
01331
01332 if(!strcmp(cmd, "plugins") && !opt_attrib.size())
01333 throw runtime_error(errmsg);
01334
01335 if(opt_deps_only &&
01336 strcmp(cmd, "export") &&
01337 strcmp(cmd, "cflags-only-I") &&
01338 strcmp(cmd, "cflags-only-other") &&
01339 strcmp(cmd, "libs-only-L") &&
01340 strcmp(cmd, "libs-only-l") &&
01341 strcmp(cmd, "libs-only-other"))
01342 throw runtime_error(errmsg);
01343
01344 if(i < argc)
01345 {
01346 if(!strcmp(cmd, "help") ||
01347 !strcmp(cmd, "list") ||
01348 !strcmp(cmd, "list-names") ||
01349 !strcmp(cmd, "list-duplicates") ||
01350 !strcmp(cmd, "langs") ||
01351 !strcmp(cmd, "profile"))
01352 throw runtime_error(errmsg);
01353
01354 opt_package = string(argv[i++]);
01355 }
01356
01357 else
01358 {
01359 char buf[1024];
01360 if(getcwd(buf,sizeof(buf)))
01361 {
01362 if(Package::is_package("."))
01363 {
01364 #if defined(_MSC_VER)
01365
01366 char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
01367 _splitpath_s(buf, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME,
01368 ext, _MAX_EXT);
01369 char filename[_MAX_FNAME + _MAX_EXT];
01370 if (ext[0] != '\0')
01371 {
01372 _makepath_s(filename, _MAX_FNAME + _MAX_EXT, NULL, NULL, fname, ext);
01373 opt_package = string(filename);
01374 }
01375 else
01376 opt_package = string(fname);
01377 #else
01378 opt_package = string(basename(buf));
01379 #endif
01380 }
01381 }
01382 }
01383
01384 if (i != argc)
01385 throw runtime_error(errmsg);
01386
01387 if (!strcmp(cmd, "profile"))
01388 {
01389 if (opt_length.size())
01390 opt_profile_length = atoi(opt_length.c_str());
01391 else
01392 {
01393 if(opt_profile_zombie_only)
01394 opt_profile_length = -1;
01395 else
01396 opt_profile_length = 20;
01397 }
01398 #ifdef VERBOSE_DEBUG
01399 fprintf(stderr, "profile_length = %d\n", opt_profile_length);
01400 #endif
01401
01402 crawl_for_packages(true);
01403 return 0;
01404 }
01405 else if (!strcmp(cmd, "find"))
01406 return cmd_find();
01407 else if (!strcmp(cmd, "list"))
01408 return cmd_print_package_list(true);
01409 else if (!strcmp(cmd, "list-names"))
01410 return cmd_print_package_list(false);
01411 else if (!strcmp(cmd, "list-duplicates"))
01412 return cmd_list_duplicates();
01413 else if (!strcmp(cmd, "langs"))
01414 return cmd_print_langs_list();
01415 else if (!strcmp(cmd, "depends") || !strcmp(cmd, "deps"))
01416 return cmd_deps();
01417 else if (!strcmp(cmd, "depends-manifests") || !strcmp(cmd, "deps-manifests"))
01418 return cmd_deps_manifests();
01419 else if (!strcmp(cmd, "depends-msgsrv") || !strcmp(cmd, "deps-msgsrv"))
01420 return cmd_deps_msgsrv();
01421 else if (!strcmp(cmd, "depends1") || !strcmp(cmd, "deps1"))
01422 return cmd_deps1();
01423 else if (!strcmp(cmd, "depends-indent") || !strcmp(cmd, "deps-indent"))
01424 return cmd_depsindent(get_pkg(opt_package), 0);
01425 else if (!strcmp(cmd, "depends-on"))
01426 return cmd_depends_on(true);
01427 else if (!strcmp(cmd, "depends-why") || !strcmp(cmd, "deps-why"))
01428 return cmd_depends_why();
01429 else if (!strcmp(cmd, "depends-on1"))
01430 return cmd_depends_on(false);
01431
01432
01433
01434
01435 else if (!strcmp(cmd, "export"))
01436 return cmd_export();
01437 else if (!strcmp(cmd, "plugins"))
01438 return cmd_plugins();
01439 else if (!strcmp(cmd, "rosdep") || !strcmp(cmd, "rosdeps"))
01440 return cmd_rosdep(-1);
01441 else if (!strcmp(cmd, "rosdep0") || !strcmp(cmd, "rosdeps0"))
01442 return cmd_rosdep(0);
01443 else if (!strcmp(cmd, "vcs"))
01444 return cmd_versioncontrol(-1);
01445 else if (!strcmp(cmd, "vcs0"))
01446 return cmd_versioncontrol(0);
01447 else if (!strcmp(cmd, "libs-only-l"))
01448 return cmd_libs_only("-l");
01449 else if (!strcmp(cmd, "libs-only-L"))
01450 return cmd_libs_only("-L");
01451 else if (!strcmp(cmd, "libs-only-other"))
01452 return cmd_libs_only("-other");
01453 else if (!strcmp(cmd, "cflags-only-I"))
01454 return cmd_cflags_only("-I");
01455 else if (!strcmp(cmd, "cflags-only-other"))
01456 return cmd_cflags_only("-other");
01457 else if (!strcmp(cmd, "help"))
01458 fputs(usage(), stderr);
01459 else
01460 {
01461 throw runtime_error(errmsg);
01462 }
01463 return 0;
01464 }
01465
01466 int ROSPack::cmd_print_package_list(bool print_path)
01467 {
01468 for (VecPkg::iterator i = Package::pkgs.begin();
01469 i != Package::pkgs.end(); ++i)
01470 if (print_path)
01471 {
01472
01473 output_acc += (*i)->name + " " + (*i)->path + "\n";
01474 }
01475 else
01476 {
01477
01478 output_acc += (*i)->name + "\n";
01479 }
01480 return 0;
01481 }
01482
01483 int ROSPack::cmd_list_duplicates()
01484 {
01485
01486 opt_display_duplicate_pkgs = true;
01487 crawl_for_packages(true);
01488
01489
01490 if(duplicate_packages_found)
01491 return 1;
01492 else
01493 return 0;
01494 }
01495
01496 int ROSPack::cmd_print_langs_list()
01497 {
01498
01499 opt_warn_on_missing_deps = false;
01500
01501
01502 VecPkg lang_pkgs;
01503 Package* roslang;
01504
01505 roslang = get_pkg("roslang");
01506 assert(roslang);
01507
01508 lang_pkgs = roslang->descendants1();
01509
01510
01511 char *disable = getenv("ROS_LANG_DISABLE");
01512 vector<string> disable_list;
01513 if(disable)
01514 string_split(disable, disable_list, ":");
01515
01516 for(VecPkg::const_iterator i = lang_pkgs.begin();
01517 i != lang_pkgs.end();
01518 ++i)
01519 {
01520 vector<string>::const_iterator j;
01521 for(j = disable_list.begin();
01522 j != disable_list.end();
01523 ++j)
01524 {
01525 if((*j) == (*i)->name)
01526 break;
01527 }
01528 if(j == disable_list.end())
01529 {
01530
01531 output_acc += (*i)->name + " ";
01532 }
01533 }
01534
01535 output_acc += "\n";
01536 return 0;
01537 }
01538
01539 string ROSPack::getCachePath()
01540 {
01541 string cache_file_name;
01542 char* ros_home = getenv("ROS_HOME");
01543
01544 if (ros_home)
01545 {
01546
01547
01548
01549
01550 #if defined(WIN32)
01551 std::string ros_home_slash = ros_home + std::string("\\");
01552 #else
01553 std::string ros_home_slash = ros_home + std::string("/");
01554 #endif
01555 struct stat s;
01556 if(stat(ros_home_slash.c_str(), &s))
01557 {
01558 if(mkdir(ros_home_slash.c_str(), 0700) != 0)
01559 {
01560 perror("[rospack] WARNING: cannot create rospack cache directory");
01561 }
01562 }
01563 cache_file_name = ros_home_slash + std::string("rospack_cache");
01564 }
01565 else
01566 {
01567 #if defined(WIN32)
01568 char* home_drive = getenv("HOMEDRIVE");
01569 char* home_path = getenv("HOMEPATH");
01570 if ( home_drive && home_path ) {
01571 std::string dotros = std::string(getenv("HOMEDRIVE")) + std::string(home_path) + std::string("\\.ros");
01572 struct stat s;
01573 if(stat(dotros.c_str(), &s))
01574 {
01575 if(mkdir(dotros.c_str(), 0700) != 0) {
01576 std::cerr << "[rospack] WARNING: cannot create rospack cache directory" << std::endl;
01577 }
01578 }
01579 cache_file_name = dotros + "\\rospack_cache";
01580 }
01581 #else // UNIX
01582 ros_home = getenv("HOME");
01583 if (ros_home)
01584 {
01585
01586
01587 std::string dotros = ros_home + std::string("/.ros/");
01588 struct stat s;
01589 if(stat(dotros.c_str(), &s))
01590 {
01591 if(mkdir(dotros.c_str(), 0700) != 0)
01592 perror("[rospack] WARNING: cannot create rospack cache directory");
01593 }
01594 cache_file_name = dotros + "rospack_cache";
01595 }
01596 #endif
01597 }
01598 return cache_file_name;
01599 }
01600
01601 bool ROSPack::cache_is_good()
01602 {
01603 string cache_path = getCachePath();
01604
01605 double cache_max_age = DEFAULT_MAX_CACHE_AGE;
01606 const char *user_cache_time_str = getenv("ROS_CACHE_TIMEOUT");
01607 if(user_cache_time_str)
01608 cache_max_age = atof(user_cache_time_str);
01609 if(cache_max_age == 0.0)
01610 return false;
01611 struct stat s;
01612 if (stat(cache_path.c_str(), &s) == 0)
01613 {
01614 double dt = difftime(time(NULL), s.st_mtime);
01615 #ifdef VERBOSE_DEBUG
01616 fprintf(stderr, "cache age: %f\n", dt);
01617 #endif
01618
01619
01620 if ((cache_max_age > 0.0) && (dt > cache_max_age))
01621 return false;
01622 }
01623
01624 FILE *cache = fopen(cache_path.c_str(), "r");
01625 if (!cache)
01626 return false;
01627
01628
01629 char linebuf[30000];
01630 bool ros_root_ok = false, ros_package_path_ok = false;
01631 const char *ros_package_path = getenv("ROS_PACKAGE_PATH");
01632 for(;;)
01633 {
01634 if (!fgets(linebuf, sizeof(linebuf), cache))
01635 break;
01636 linebuf[strlen(linebuf)-1] = 0;
01637 if (linebuf[0] == '#')
01638 {
01639 if (!strncmp("#ROS_ROOT=", linebuf, 10))
01640 {
01641 if (!strcmp(linebuf+10, ros_root))
01642 ros_root_ok = true;
01643 }
01644 else if (!strncmp("#ROS_PACKAGE_PATH=", linebuf, 18))
01645 {
01646 if (!ros_package_path)
01647 {
01648 if (!strlen(linebuf+18))
01649 ros_package_path_ok = true;
01650 }
01651 else if (!strcmp(linebuf+18, getenv("ROS_PACKAGE_PATH")))
01652 ros_package_path_ok = true;
01653 }
01654 }
01655 else
01656 break;
01657 }
01658 fclose(cache);
01659 return ros_root_ok && ros_package_path_ok;
01660 }
01661
01662 class CrawlQueueEntry
01663 {
01664 public:
01665 string path;
01666 double start_time, elapsed_time;
01667 size_t start_num_pkgs;
01668 bool has_manifest;
01669 CrawlQueueEntry(string _path)
01670 : path(_path), start_time(0), elapsed_time(0),
01671 start_num_pkgs(0), has_manifest(false){ }
01672 bool operator>(const CrawlQueueEntry &rhs) const
01673 {
01674 return elapsed_time > rhs.elapsed_time;
01675 }
01676 };
01677
01678 double ROSPack::time_since_epoch()
01679 {
01680 #if defined(WIN32)
01681 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
01682 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
01683 #else
01684 #define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
01685 #endif
01686 FILETIME ft;
01687 unsigned __int64 tmpres = 0;
01688
01689 GetSystemTimeAsFileTime(&ft);
01690 tmpres |= ft.dwHighDateTime;
01691 tmpres <<= 32;
01692 tmpres |= ft.dwLowDateTime;
01693 tmpres /= 10;
01694 tmpres -= DELTA_EPOCH_IN_MICROSECS;
01695 return static_cast<double>(tmpres) / 1e6;
01696 #else
01697 struct timeval tod;
01698 gettimeofday(&tod, NULL);
01699 return tod.tv_sec + 1e-6 * tod.tv_usec;
01700 #endif
01701 }
01702
01703
01704 Package* ROSPack::add_package(string path)
01705 {
01706
01707 Package* newp = new Package(path);
01708 Package* return_p = newp;
01709
01710 bool dup = false;
01711 for(std::vector<Package *>::const_iterator it = Package::pkgs.begin();
01712 it != Package::pkgs.end();
01713 it++)
01714 {
01715 if((*it)->name == newp->name)
01716 {
01717 dup=true;
01718 return_p = *it;
01719
01720 if(opt_display_duplicate_pkgs)
01721 output_acc += (*it)->path + " " + newp->path + "\n";
01722
01723 duplicate_packages_found = true;
01724 break;
01725 }
01726 }
01727 if(dup)
01728 delete newp;
01729 else
01730 Package::pkgs.push_back(newp);
01731
01732 return return_p;
01733 }
01734
01735 void ROSPack::crawl_for_packages(bool force_crawl)
01736 {
01737 for (VecPkg::iterator p = Package::pkgs.begin();
01738 p != Package::pkgs.end(); ++p)
01739 Package::deleted_pkgs.push_back(*p);
01740 Package::pkgs.clear();
01741
01742 if(!force_crawl && cache_is_good())
01743 {
01744 string cache_path = getCachePath();
01745 FILE *cache = fopen(cache_path.c_str(), "r");
01746 if (cache)
01747 {
01748 #ifdef VERBOSE_DEBUG
01749 fprintf(stderr, "trying to use cache...\n");
01750 #endif
01751 char linebuf[30000];
01752 for(;;)
01753 {
01754 if (!fgets(linebuf, sizeof(linebuf), cache))
01755 break;
01756 if (linebuf[0] == '#')
01757 continue;
01758 char *newline_pos = strchr(linebuf, '\n');
01759 if (newline_pos)
01760 *newline_pos = 0;
01761
01762 add_package(linebuf);
01763 }
01764 fclose(cache);
01765 return;
01766 }
01767 }
01768
01769
01770 #ifdef VERBOSE_DEBUG
01771 fprintf(stderr, "building cache\n");
01772 #endif
01773 deque<CrawlQueueEntry> q;
01774 q.push_back(CrawlQueueEntry(ros_root));
01775 if (char *rpp = getenv("ROS_PACKAGE_PATH"))
01776 {
01777 vector<string> rppvec;
01778 string_split(rpp, rppvec, path_delim);
01779 sanitize_rppvec(rppvec);
01780 for (vector<string>::iterator i = rppvec.begin(); i != rppvec.end(); ++i)
01781 {
01782 if(!i->size())
01783 continue;
01784 else if (!Package::is_package(*i) && Package::is_no_subdirs(*i))
01785 fprintf(stderr, "[rospack] WARNING: non-package directory in "
01786 "ROS_PACKAGE_PATH marked rospack_nosubdirs:\n\t%s\n",
01787 i->c_str());
01788 else
01789 q.push_back(CrawlQueueEntry(*i));
01790 }
01791 }
01792 const double crawl_start_time = time_since_epoch();
01793 priority_queue<CrawlQueueEntry, vector<CrawlQueueEntry>,
01794 greater<CrawlQueueEntry> > profile;
01795 while (!q.empty())
01796 {
01797 CrawlQueueEntry cqe = q.front();
01798 q.pop_front();
01799
01800
01801
01802 path_components.reserve(MAX_DIRECTORY_DEPTH+1);
01803
01804 string_split(cqe.path, path_components, fs_delim);
01805 if(path_components.size() > MAX_DIRECTORY_DEPTH)
01806 {
01807 fprintf(stderr,"[rospack] Exceeded maximum directory depth of %d at %s. There must be a self-referencing symlink somewhere.\n", MAX_DIRECTORY_DEPTH, cqe.path.c_str());
01808 throw runtime_error(string("circular directory structure"));
01809 }
01810
01811
01812 if (Package::is_package(cqe.path))
01813 {
01814
01815 add_package(cqe.path);
01816 continue;
01817 }
01818
01819
01820 if (opt_profile_length != 0)
01821 {
01822 if (cqe.start_time != 0)
01823 {
01824
01825
01826
01827
01828 cqe.elapsed_time = time_since_epoch() - cqe.start_time;
01829
01830
01831
01832
01833
01834 if(cqe.start_num_pkgs < total_num_pkgs)
01835 cqe.has_manifest = true;
01836 if(!opt_profile_zombie_only || !cqe.has_manifest)
01837 {
01838 profile.push(cqe);
01839 if ((opt_profile_length > 0) && (profile.size() > opt_profile_length))
01840 profile.pop();
01841 }
01842 continue;
01843 }
01844 cqe.start_time = time_since_epoch();
01845 cqe.start_num_pkgs = total_num_pkgs;
01846 q.push_front(cqe);
01847 }
01848 #if defined(WIN32)
01849 WIN32_FIND_DATA find_file_data;
01850 HANDLE hfind = INVALID_HANDLE_VALUE;
01851 if ((hfind = FindFirstFile((cqe.path + "\\*").c_str(),
01852 &find_file_data)) == INVALID_HANDLE_VALUE)
01853 {
01854 fprintf(stderr, "[rospack] FindFirstFile error %u while crawling %s\n",
01855 GetLastError(), cqe.path.c_str());
01856 continue;
01857 }
01858
01859 do
01860 {
01861 if (find_file_data.dwFileAttributes != FILE_ATTRIBUTE_DIRECTORY ) {
01862 continue;
01863 }
01864 if (find_file_data.cFileName[0] == '.') {
01865 continue;
01866 }
01867 string child_path = cqe.path + fs_delim + string(find_file_data.cFileName);
01868 if (Package::is_package(child_path))
01869 {
01870 total_num_pkgs++;
01871
01872 Package* newp = new Package(child_path);
01873
01874 bool dup = false;
01875 for(std::vector<Package *>::const_iterator it = Package::pkgs.begin();
01876 it != Package::pkgs.end();
01877 it++)
01878 {
01879 if((*it)->name == newp->name)
01880 {
01881 dup=true;
01882 break;
01883 }
01884 }
01885 if(dup)
01886 delete newp;
01887 else
01888 {
01889 Package::pkgs.push_back(newp);
01890 }
01891 }
01892
01893 else if (!Package::is_no_subdirs(child_path))
01894 q.push_front(CrawlQueueEntry(child_path));
01895 }
01896 while (FindNextFile(hfind, &find_file_data) != 0);
01897 DWORD last_error = GetLastError();
01898 FindClose(hfind);
01899 if (last_error != ERROR_NO_MORE_FILES)
01900 {
01901 fprintf(stderr, "[rospack] FindNextFile error %u while crawling %s\n",
01902 GetLastError(), cqe.path.c_str());
01903 continue;
01904 }
01905 #else
01906 DIR *d = opendir(cqe.path.c_str());
01907 if (!d)
01908 {
01909 fprintf(stderr, "[rospack] opendir error [%s] while crawling %s\n",
01910 strerror(errno), cqe.path.c_str());
01911 continue;
01912 }
01913 struct dirent *ent;
01914 while ((ent = readdir(d)) != NULL)
01915 {
01916 struct stat s;
01917 string child_path = cqe.path + fs_delim + string(ent->d_name);
01918 int ret;
01919 while ((ret = stat(child_path.c_str(), &s)) != 0 &&
01920 errno == EINTR);
01921 if (ret != 0)
01922 continue;
01923 if (!S_ISDIR(s.st_mode))
01924 continue;
01925 if (ent->d_name[0] == '.')
01926 continue;
01927 if (Package::is_package(child_path))
01928 {
01929 total_num_pkgs++;
01930 add_package(child_path);
01931 }
01932
01933 else if (!Package::is_no_subdirs(child_path))
01934 q.push_front(CrawlQueueEntry(child_path));
01935 }
01936 closedir(d);
01937 #endif
01938 }
01939 crawled = true;
01940 const double crawl_elapsed_time = time_since_epoch() - crawl_start_time;
01941
01942
01943 string cache_path(getCachePath());
01944 if(!cache_path.size())
01945 {
01946 fprintf(stderr, "[rospack] No location available to write cache file. Try setting ROS_HOME or HOME.\n");
01947 }
01948 else
01949 {
01950 char tmp_cache_dir[PATH_MAX];
01951 char tmp_cache_path[PATH_MAX];
01952 strncpy(tmp_cache_dir, cache_path.c_str(), sizeof(tmp_cache_dir));
01953 #if defined(_MSC_VER)
01954
01955 char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
01956 _splitpath_s(tmp_cache_dir, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME,
01957 ext, _MAX_EXT);
01958 char full_dir[_MAX_DRIVE + _MAX_DIR];
01959 _makepath_s(full_dir, _MAX_DRIVE + _MAX_DIR, drive, dir, NULL, NULL);
01960 snprintf(tmp_cache_path, sizeof(tmp_cache_path), "%s\\.rospack_cache.XXXXXX", full_dir);
01961 #elif defined(__MINGW32__)
01962 char* temp_name = tempnam(dirname(tmp_cache_dir),".rospack_cache.");
01963 snprintf(tmp_cache_path, sizeof(tmp_cache_path), temp_name);
01964 delete temp_name;
01965 #else
01966 snprintf(tmp_cache_path, sizeof(tmp_cache_path), "%s/.rospack_cache.XXXXXX", dirname(tmp_cache_dir));
01967 #endif
01968 #if defined(__MINGW32__)
01969
01970
01971 int fd = open(tmp_cache_path, O_RDWR | O_EXCL | _O_CREAT, 0644);
01972 if (fd < 0)
01973 {
01974 fprintf(stderr, "[rospack] Unable to create temporary cache file %s: %u\n",
01975 tmp_cache_path, errno);
01976 }
01977 else
01978 {
01979 FILE *cache = fdopen(fd, "w");
01980 #elif defined(WIN32)
01981 if (_mktemp_s(tmp_cache_path, PATH_MAX) != 0)
01982 {
01983 fprintf(stderr,
01984 "[rospack] Unable to generate temporary cache file name: %u",
01985 GetLastError());
01986 }
01987 else
01988 {
01989 FILE *cache = fopen(tmp_cache_path, "w");
01990 #else
01991 int fd = mkstemp(tmp_cache_path);
01992 if (fd < 0)
01993 {
01994 fprintf(stderr, "[rospack] Unable to create temporary cache file %s: %s\n",
01995 tmp_cache_path, strerror(errno));
01996 }
01997 else
01998 {
01999 FILE *cache = fdopen(fd, "w");
02000 #endif
02001 if (!cache)
02002 {
02003 fprintf(stderr, "[rospack] Unable open cache file %s: %s\n",
02004 tmp_cache_path, strerror(errno));
02005 }
02006 else
02007 {
02008 char *rpp = getenv("ROS_PACKAGE_PATH");
02009 fprintf(cache, "#ROS_ROOT=%s\n#ROS_PACKAGE_PATH=%s\n", ros_root,
02010 (rpp ? rpp : ""));
02011 for (VecPkg::iterator pkg = Package::pkgs.begin();
02012 pkg != Package::pkgs.end(); ++pkg)
02013 fprintf(cache, "%s\n", (*pkg)->path.c_str());
02014 fclose(cache);
02015 if(file_exists(cache_path.c_str()))
02016 remove(cache_path.c_str());
02017 if(rename(tmp_cache_path, cache_path.c_str()) < 0)
02018 {
02019 fprintf(stderr, "[rospack] Error: failed to rename cache file %s to %s: %s\n",
02020 tmp_cache_path, cache_path.c_str(), strerror(errno));
02021 }
02022 }
02023 }
02024 }
02025
02026 if (opt_profile_length)
02027 {
02028
02029 stack<CrawlQueueEntry> reverse_profile;
02030
02031
02032 vector<string> zombie_dirs;
02033 zombie_dirs.reserve(profile.size());
02034 while (!profile.empty())
02035 {
02036 reverse_profile.push(profile.top());
02037 zombie_dirs.push_back(profile.top().path);
02038 profile.pop();
02039 }
02040 if(!opt_profile_zombie_only)
02041 {
02042
02043
02044
02045
02046 char buf[16];
02047 snprintf(buf, sizeof(buf), "%.6f", crawl_elapsed_time);
02048 output_acc += "\nFull tree crawl took " + string(buf) + " seconds.\n";
02049 output_acc += "Directories marked with (*) contain no manifest. You may\n";
02050 output_acc += "want to delete these directories.\n";
02051 output_acc += "To get just of list of directories without manifests,\n";
02052 output_acc += "re-run the profile with --zombie-only\n.";
02053 output_acc += "-------------------------------------------------------------\n";
02054 }
02055 while (!reverse_profile.empty())
02056 {
02057 CrawlQueueEntry cqe = reverse_profile.top();
02058 reverse_profile.pop();
02059
02060 if(!opt_profile_zombie_only)
02061 {
02062
02063
02064
02065
02066 char buf[16];
02067 snprintf(buf, sizeof(buf), "%.6f", cqe.elapsed_time);
02068 output_acc += string(buf) + " ";
02069 if(cqe.has_manifest)
02070 output_acc += " ";
02071 else
02072 output_acc += "* ";
02073 output_acc += cqe.path;
02074 output_acc += "\n";
02075 }
02076 else
02077 {
02078 bool dup = false;
02079
02080
02081
02082 if(file_exists(cqe.path + fs_delim + "stack.xml") ||
02083 file_exists(cqe.path + fs_delim + "app.xml"))
02084 {
02085 continue;
02086 }
02087
02088
02089 for(vector<string>::const_iterator it = zombie_dirs.begin();
02090 it != zombie_dirs.end();
02091 ++it)
02092 {
02093 if((cqe.path.size() > it->size()) &&
02094 (cqe.path.substr(0,it->size()) == (*it)))
02095 {
02096 dup = true;
02097 break;
02098 }
02099 }
02100 if(dup)
02101 continue;
02102
02103
02104 output_acc += cqe.path + "\n";
02105 }
02106 }
02107 if(!opt_profile_zombie_only)
02108 {
02109
02110 output_acc += "\n";
02111 }
02112 }
02113 }
02114
02115 VecPkg ROSPack::partial_crawl(const string &path)
02116 {
02117 deque<CrawlQueueEntry> q;
02118 q.push_back(CrawlQueueEntry(path));
02119 VecPkg partial_pkgs;
02120 while (!q.empty())
02121 {
02122 CrawlQueueEntry cqe = q.front();
02123
02124 q.pop_front();
02125 #if defined(WIN32)
02126 WIN32_FIND_DATA find_file_data;
02127 HANDLE hfind = INVALID_HANDLE_VALUE;
02128 if ((hfind = FindFirstFile((cqe.path + "\\*").c_str(),
02129 &find_file_data)) == INVALID_HANDLE_VALUE)
02130 {
02131 fprintf(stderr, "[rospack] FindFirstFile error %u while crawling %s\n",
02132 GetLastError(), cqe.path.c_str());
02133 continue;
02134 }
02135
02136 do
02137 {
02138 if (!S_ISDIR(find_file_data.dwFileAttributes))
02139 continue;
02140 if (find_file_data.cFileName[0] == '.')
02141 continue;
02142 string child_path = cqe.path + fs_delim + string(find_file_data.cFileName);
02143 if (Package::is_package(child_path))
02144 {
02145
02146 Package* newp = new Package(child_path);
02147
02148 bool dup = false;
02149 for(std::vector<Package *>::const_iterator it = partial_pkgs.begin();
02150 it != partial_pkgs.end();
02151 it++)
02152 {
02153 if((*it)->name == newp->name)
02154 {
02155 dup=true;
02156 break;
02157 }
02158 }
02159 if(dup)
02160 delete newp;
02161 else
02162 partial_pkgs.push_back(newp);
02163 }
02164
02165 else if (!Package::is_no_subdirs(child_path))
02166 q.push_front(CrawlQueueEntry(child_path));
02167 }
02168 while (FindNextFile(hfind, &find_file_data) != 0);
02169 DWORD last_error = GetLastError();
02170 FindClose(hfind);
02171 if (last_error != ERROR_NO_MORE_FILES)
02172 {
02173 fprintf(stderr, "[rospack] FindNextFile error %u while crawling %s\n",
02174 GetLastError(), cqe.path.c_str());
02175 continue;
02176 }
02177 #else
02178 DIR *d = opendir(cqe.path.c_str());
02179 if (!d)
02180 {
02181 fprintf(stderr, "[rospack] opendir error [%s] while crawling %s\n",
02182 strerror(errno), cqe.path.c_str());
02183 continue;
02184 }
02185 struct dirent *ent;
02186 while ((ent = readdir(d)) != NULL)
02187 {
02188 struct stat s;
02189 string child_path = cqe.path + fs_delim + string(ent->d_name);
02190 int ret;
02191 while ((ret = stat(child_path.c_str(), &s)) != 0 &&
02192 errno == EINTR);
02193 if (ret != 0)
02194 continue;
02195 if (!S_ISDIR(s.st_mode))
02196 continue;
02197 if (ent->d_name[0] == '.')
02198 continue;
02199 if (Package::is_package(child_path))
02200 {
02201
02202 Package* newp = new Package(child_path);
02203
02204 bool dup = false;
02205 for(std::vector<Package *>::const_iterator it = partial_pkgs.begin();
02206 it != partial_pkgs.end();
02207 it++)
02208 {
02209 if((*it)->name == newp->name)
02210 {
02211 dup=true;
02212 break;
02213 }
02214 }
02215 if(dup)
02216 delete newp;
02217 else
02218 partial_pkgs.push_back(newp);
02219 }
02220
02221 else if (!Package::is_no_subdirs(child_path))
02222 q.push_front(CrawlQueueEntry(child_path));
02223 }
02224 closedir(d);
02225 #endif
02226 }
02227 return partial_pkgs;
02228 }
02229
02231
02232 void string_split(const string &s, vector<string> &t, const string &d)
02233 {
02234 t.clear();
02235 size_t start = 0, end;
02236 while ((end = s.find_first_of(d, start)) != string::npos)
02237 {
02238 if((end-start) > 0)
02239 t.push_back(s.substr(start, end-start));
02240 start = end + 1;
02241 }
02242 if(start < s.size())
02243 t.push_back(s.substr(start));
02244 }
02245
02246
02247
02248
02249 string ROSPack::deduplicate_tokens(const string& s)
02250 {
02251 vector<string> in;
02252 vector<string> out;
02253 string_split(s, in, " ");
02254 for(int i=0; i<in.size(); i++)
02255 {
02256 bool dup = false;
02257 for(int j=0; j<out.size(); j++)
02258 {
02259 if(!out[j].compare(in[i]))
02260 {
02261 dup = true;
02262 break;
02263 }
02264 }
02265 if(!dup)
02266 out.push_back(in[i]);
02267 }
02268
02269 string res;
02270 for(int j=0; j<out.size(); j++)
02271 {
02272 if(!j)
02273 res += out[j];
02274 else
02275 res += string(" ") + out[j];
02276 }
02277
02278 return res;
02279 }
02280
02281 bool file_exists(const string &fname)
02282 {
02283
02284
02285 return (access(fname.c_str(), F_OK) == 0);
02286 }
02287
02288 Package *g_get_pkg(const string &name)
02289 {
02290
02291 return g_rospack->get_pkg(name);
02292 }
02293
02294 void ROSPack::sanitize_rppvec(std::vector<std::string> &rppvec)
02295 {
02296
02297 for (size_t i = 0; i < rppvec.size(); i++)
02298 {
02299 size_t last_slash_pos;
02300 while((last_slash_pos = rppvec[i].find_last_of("/")) == rppvec[i].length()-1)
02301 {
02302 fprintf(stderr, "[rospack] warning: trailing slash found in "
02303 "ROS_PACKAGE_PATH\n");
02304 rppvec[i].erase(last_slash_pos);
02305 }
02306 }
02307 }
02308
02309 }