list, list-names, deps, and deps1 are working

This commit is contained in:
Brian Gerkey 2011-10-22 17:27:31 +00:00
parent 500d283b49
commit 4e374754e8
3 changed files with 342 additions and 124 deletions

View File

@ -29,6 +29,7 @@
#include "tinyxml-2.5.3/tinyxml.h" #include "tinyxml-2.5.3/tinyxml.h"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#if !defined(WIN32) #if !defined(WIN32)
#include <sys/types.h> #include <sys/types.h>
@ -55,31 +56,55 @@ static const std::string ROSPACK_CACHE_NAME = "rospack_cache";
static const std::string ROSSTACK_CACHE_NAME = "rosstack_cache"; static const std::string ROSSTACK_CACHE_NAME = "rosstack_cache";
static const std::string DOTROS_NAME = ".ros"; static const std::string DOTROS_NAME = ".ros";
static const int MAX_CRAWL_DEPTH = 1000; static const int MAX_CRAWL_DEPTH = 1000;
static const int MAX_DEPENDENCY_DEPTH = 1000;
static const double DEFAULT_MAX_CACHE_AGE = 60.0; static const double DEFAULT_MAX_CACHE_AGE = 60.0;
///////////////////////////////////////////////////////////// class Exception : public std::runtime_error
// Stackage methods
/////////////////////////////////////////////////////////////
Stackage::Stackage(const std::string& name,
const std::string& path,
const std::string& manifest_path) :
name_(name),
path_(path),
manifest_path_(manifest_path)
{ {
} public:
Exception(const std::string& what)
: std::runtime_error(what)
{}
};
class Stackage
{
public:
// \brief name of the stackage
std::string name_;
// \brief absolute path to the stackage
std::string path_;
// \brief absolute path to the stackage manifest
std::string manifest_path_;
// \brief have we already loaded the manifest?
bool manifest_loaded_;
// \brief TinyXML structure, filled in during parsing
rospack_tinyxml::TiXmlDocument manifest_;
std::vector<Stackage*> deps;
bool deps_computed_;
Stackage(const std::string& name,
const std::string& path,
const std::string& manifest_path) :
name_(name),
path_(path),
manifest_path_(manifest_path),
manifest_loaded_(false),
deps_computed_(false)
{
}
};
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
// Rosstackage methods (public/protected) // Rosstackage methods (public/protected)
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
Rosstackage::Rosstackage(std::string manifest_name, Rosstackage::Rosstackage(std::string manifest_name,
std::string cache_name, std::string cache_name,
crawl_direction_t crawl_dir, crawl_direction_t crawl_dir):
int max_crawl_depth) :
manifest_name_(manifest_name), manifest_name_(manifest_name),
cache_name_(cache_name), cache_name_(cache_name),
crawl_dir_(crawl_dir), crawl_dir_(crawl_dir),
max_crawl_depth_(max_crawl_depth),
crawled_(false) crawled_(false)
{ {
} }
@ -87,7 +112,7 @@ Rosstackage::Rosstackage(std::string manifest_name,
void void
Rosstackage::debug_dump() Rosstackage::debug_dump()
{ {
for(std::map<std::string, Stackage*>::const_iterator it = stackages_.begin(); for(std::tr1::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
it != stackages_.end(); it != stackages_.end();
++it) ++it)
{ {
@ -122,14 +147,59 @@ Rosstackage::crawl(const std::vector<std::string>& search_path,
writeCache(); writeCache();
} }
std::string bool
Rosstackage::find(const std::string& name) Rosstackage::find(const std::string& name, std::string& path)
{ {
std::map<std::string, Stackage*>::const_iterator it = stackages_.find(name); std::tr1::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.find(name);
if(it != stackages_.end()) if(it != stackages_.end())
return it->second->path_; {
path = it->second->path_;
return true;
}
else else
return ""; {
log_error("librospack", std::string("package ") + name + " not found");
return false;
}
}
void
Rosstackage::list(std::vector<std::pair<std::string, std::string> >& list)
{
list.resize(stackages_.size());
int i = 0;
for(std::tr1::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
it != stackages_.end();
++it)
{
list[i].first = it->first;
list[i].second = it->second->path_;
i++;
}
}
bool
Rosstackage::deps(const std::string& name, bool direct,
std::vector<std::string>& deps)
{
if(!stackages_.count(name))
{
log_error("librospack", std::string("no such package ") + name);
return false;
}
Stackage* stackage = stackages_[name];
try
{
computeDeps(stackage);
std::tr1::unordered_set<std::string> deps_hash;
gatherDeps(stackage, direct, 0, deps_hash, deps);
}
catch(Exception& e)
{
log_error("librospack", e.what());
return false;
}
return true;
} }
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
@ -171,8 +241,6 @@ Rosstackage::addStackage(const std::string& path)
} }
fs::path manifest_path = fs::path(path) / manifest_name_; fs::path manifest_path = fs::path(path) / manifest_name_;
stackages_[name] = new Stackage(name, path, manifest_path.string()); stackages_[name] = new Stackage(name, path, manifest_path.string());
// TODO
loadManifest(stackages_[name]);
} }
void void
@ -180,8 +248,8 @@ Rosstackage::crawlDetail(const std::string& path,
bool force, bool force,
int depth) int depth)
{ {
if(depth > max_crawl_depth_) if(depth > MAX_CRAWL_DEPTH)
throw Exception("Maximum depth exceeded during crawl"); throw Exception("maximum depth exceeded during crawl");
if(!fs::is_directory(path)) if(!fs::is_directory(path))
return; return;
@ -218,13 +286,90 @@ Rosstackage::loadManifest(Stackage* stackage)
if(!stackage->manifest_.LoadFile(stackage->manifest_path_)) if(!stackage->manifest_.LoadFile(stackage->manifest_path_))
{ {
std::string errmsg = std::string("Error parsing manifest of package ") + std::string errmsg = std::string("error parsing manifest of package ") +
stackage->name_ + " at [" + stackage->manifest_path_ + "]"; stackage->name_ + " at " + stackage->manifest_path_;
throw Exception(errmsg); throw Exception(errmsg);
} }
stackage->manifest_loaded_ = true; stackage->manifest_loaded_ = true;
} }
rospack_tinyxml::TiXmlElement*
Rosstackage::getManifestRoot(Stackage* stackage)
{
loadManifest(stackage);
rospack_tinyxml::TiXmlElement* ele = stackage->manifest_.RootElement();
if(!ele)
{
std::string errmsg = std::string("error parsing manifest of package ") +
stackage->name_ + " at " + stackage->manifest_path_;
throw Exception(errmsg);
}
return ele;
}
void
Rosstackage::computeDeps(Stackage* stackage)
{
if(stackage->deps_computed_)
return;
stackage->deps_computed_ = true;
rospack_tinyxml::TiXmlElement* root = getManifestRoot(stackage);
rospack_tinyxml::TiXmlNode *dep_node = NULL;
while((dep_node = root->IterateChildren("depend", dep_node)))
{
rospack_tinyxml::TiXmlElement *dep_ele = dep_node->ToElement();
const char* dep_pkgname = dep_ele->Attribute("package");
if(!dep_pkgname)
{
std::string errmsg = std::string("bad depend syntax (no 'package' attribute) in manifest ") + stackage->name_ + " at " + stackage->manifest_path_;
throw Exception(errmsg);
}
else if(dep_pkgname == stackage->name_)
{
std::string errmsg = std::string("package ") + stackage->name_ + " depends on itself";
throw Exception(errmsg);
}
else if(!stackages_.count(dep_pkgname))
{
std::string errmsg = std::string("package ") + stackage->name_ + " depends on non-existent package " + dep_pkgname;
throw Exception(errmsg);
}
else
{
Stackage* dep = stackages_[dep_pkgname];
stackage->deps.push_back(dep);
computeDeps(dep);
}
}
}
// Pre-condition: computeDeps(stackage) succeeded
void
Rosstackage::gatherDeps(Stackage* stackage, bool direct, int depth,
std::tr1::unordered_set<std::string>& deps_hash,
std::vector<std::string>& deps)
{
if(depth > MAX_DEPENDENCY_DEPTH)
throw Exception("maximum dependency depth exceeded (likely circular dependency)");
for(std::vector<Stackage*>::const_iterator it = stackage->deps.begin();
it != stackage->deps.end();
++it)
{
if(deps_hash.find((*it)->name_) == deps_hash.end())
{
deps_hash.insert((*it)->name_);
if(!direct)
gatherDeps(*it, direct, depth+1, deps_hash, deps);
// We maintain the vector because the original rospack guaranteed
// ordering in dep reporting.
deps.push_back((*it)->name_);
}
}
}
std::string std::string
Rosstackage::getCachePath() Rosstackage::getCachePath()
{ {
@ -265,7 +410,7 @@ Rosstackage::getCachePath()
} }
catch(fs::filesystem_error& e) catch(fs::filesystem_error& e)
{ {
rospack_warn("librospack", log_warn("librospack",
std::string("cannot create rospack cache directory ") + std::string("cannot create rospack cache directory ") +
cache_path.string() + ": " + e.what()); cache_path.string() + ": " + e.what());
} }
@ -313,7 +458,7 @@ Rosstackage::writeCache()
std::string cache_path = getCachePath(); std::string cache_path = getCachePath();
if(!cache_path.size()) if(!cache_path.size())
{ {
rospack_warn("librospack", log_warn("librospack",
"no location available to write cache file. Try setting ROS_HOME or HOME."); "no location available to write cache file. Try setting ROS_HOME or HOME.");
} }
else else
@ -342,7 +487,7 @@ Rosstackage::writeCache()
int fd = open(tmp_cache_path, O_RDWR | O_EXCL | _O_CREAT, 0644); int fd = open(tmp_cache_path, O_RDWR | O_EXCL | _O_CREAT, 0644);
if (fd < 0) if (fd < 0)
{ {
rospack_warn("librospack", log_warn("librospack",
std::string("unable to create temporary cache file ") + std::string("unable to create temporary cache file ") +
tmp_cache_path, true); tmp_cache_path, true);
} }
@ -383,7 +528,7 @@ Rosstackage::writeCache()
char *rpp = getenv("ROS_PACKAGE_PATH"); char *rpp = getenv("ROS_PACKAGE_PATH");
fprintf(cache, "#ROS_PACKAGE_PATH=%s\n", (rpp ? rpp : "")); fprintf(cache, "#ROS_PACKAGE_PATH=%s\n", (rpp ? rpp : ""));
for(std::map<std::string, Stackage*>::const_iterator it = stackages_.begin(); for(std::tr1::unordered_map<std::string, Stackage*>::const_iterator it = stackages_.begin();
it != stackages_.end(); it != stackages_.end();
++it) ++it)
fprintf(cache, "%s\n", it->second->path_.c_str()); fprintf(cache, "%s\n", it->second->path_.c_str());
@ -460,8 +605,7 @@ Rosstackage::validateCache()
Rospack::Rospack() : Rospack::Rospack() :
Rosstackage(ROSPACK_MANIFEST_NAME, Rosstackage(ROSPACK_MANIFEST_NAME,
ROSPACK_CACHE_NAME, ROSPACK_CACHE_NAME,
CRAWL_DOWN, CRAWL_DOWN)
MAX_CRAWL_DEPTH)
{ {
} }
@ -477,8 +621,7 @@ void Rospack::crawl(const std::vector<std::string>& search_path,
Rosstack::Rosstack() : Rosstack::Rosstack() :
Rosstackage(ROSSTACK_MANIFEST_NAME, Rosstackage(ROSSTACK_MANIFEST_NAME,
ROSSTACK_CACHE_NAME, ROSSTACK_CACHE_NAME,
CRAWL_UP, CRAWL_UP)
MAX_CRAWL_DEPTH)
{ {
} }
@ -488,11 +631,35 @@ void Rosstack::crawl(const std::vector<std::string>& search_path,
Rosstackage::crawl(search_path, force); Rosstackage::crawl(search_path, force);
} }
void
get_search_path_from_env(std::vector<std::string>& sp)
{
char* rr = getenv("ROS_ROOT");
char* rpp = getenv("ROS_PACKAGE_PATH");
if(rr)
sp.push_back(rr);
if(rpp)
{
std::vector<std::string> rpp_strings;
boost::split(rpp_strings, rpp,
boost::is_any_of(":"),
boost::token_compress_on);
for(std::vector<std::string>::const_iterator it = rpp_strings.begin();
it != rpp_strings.end();
++it)
{
sp.push_back(*it);
}
}
}
// Simple console output helpers // Simple console output helpers
void rospack_log(const std::string& name, void log(const std::string& name,
const std::string& level, const std::string& level,
const std::string& msg, const std::string& msg,
bool append_errno) bool append_errno)
{ {
fprintf(stderr, "[%s] %s: %s", fprintf(stderr, "[%s] %s: %s",
name.c_str(), level.c_str(), msg.c_str()); name.c_str(), level.c_str(), msg.c_str());
@ -501,17 +668,17 @@ void rospack_log(const std::string& name,
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
void rospack_warn(const std::string& name, void log_warn(const std::string& name,
const std::string& msg, const std::string& msg,
bool append_errno) bool append_errno)
{ {
rospack_log(name, "Warning", msg, append_errno); log(name, "Warning", msg, append_errno);
} }
void rospack_error(const std::string& name, void log_error(const std::string& name,
const std::string& msg, const std::string& msg,
bool append_errno) bool append_errno)
{ {
rospack_log(name, "Error", msg, append_errno); log(name, "Error", msg, append_errno);
} }
} // namespace rospack } // namespace rospack

View File

@ -31,6 +31,8 @@
#include "tinyxml-2.5.3/tinyxml.h" #include "tinyxml-2.5.3/tinyxml.h"
#include <boost/tr1/unordered_set.hpp>
#include <boost/tr1/unordered_map.hpp>
#include <string> #include <string>
#include <map> #include <map>
#include <vector> #include <vector>
@ -39,46 +41,14 @@
namespace rospack namespace rospack
{ {
class Stackage
{
public:
// \brief name of the stackage
std::string name_;
// \brief absolute path to the stackage
std::string path_;
// \brief absolute path to the stackage manifest
std::string manifest_path_;
// \brief have we already loaded the manifest?
bool manifest_loaded_;
// \brief TinyXML structure, filled in during parsing
rospack_tinyxml::TiXmlDocument manifest_;
Stackage(const std::string& name,
const std::string& path,
const std::string& manifest_path);
};
class Package : public Stackage
{
};
class Stack : public Stackage
{
};
typedef enum typedef enum
{ {
CRAWL_UP, CRAWL_UP,
CRAWL_DOWN CRAWL_DOWN
} crawl_direction_t; } crawl_direction_t;
class Exception : public std::runtime_error class Stackage;
{ class rospack_tinyxml::TiXmlElement;
public:
Exception(const std::string& what)
: std::runtime_error(what)
{}
};
class Rosstackage class Rosstackage
{ {
@ -86,7 +56,6 @@ class Rosstackage
std::string manifest_name_; std::string manifest_name_;
std::string cache_name_; std::string cache_name_;
crawl_direction_t crawl_dir_; crawl_direction_t crawl_dir_;
int max_crawl_depth_;
bool crawled_; bool crawled_;
bool isStackage(const std::string& path); bool isStackage(const std::string& path);
@ -95,22 +64,28 @@ class Rosstackage
bool force, bool force,
int depth); int depth);
void loadManifest(Stackage* stackage); void loadManifest(Stackage* stackage);
void computeDeps(Stackage* stackage);
void gatherDeps(Stackage* stackage, bool direct, int depth,
std::tr1::unordered_set<std::string>& deps_hash,
std::vector<std::string>& deps);
rospack_tinyxml::TiXmlElement* getManifestRoot(Stackage* stackage);
std::string getCachePath(); std::string getCachePath();
bool readCache(); bool readCache();
void writeCache(); void writeCache();
bool validateCache(); bool validateCache();
protected: protected:
std::map<std::string, Stackage*> stackages_; std::tr1::unordered_map<std::string, Stackage*> stackages_;
void crawl(const std::vector<std::string>& search_path, bool force); void crawl(const std::vector<std::string>& search_path, bool force);
public: public:
Rosstackage(std::string manifest_name, Rosstackage(std::string manifest_name,
std::string cache_name, std::string cache_name,
crawl_direction_t crawl_dir, crawl_direction_t crawl_dir);
int max_crawl_depth);
std::string find(const std::string& name); bool find(const std::string& name, std::string& path);
void list(std::vector<std::pair<std::string, std::string> >& list);
bool deps(const std::string& name, bool direct, std::vector<std::string>& deps);
void debug_dump(); void debug_dump();
}; };
@ -133,14 +108,15 @@ class Rosstack : public Rosstackage
Rosstack(); Rosstack();
}; };
void get_search_path_from_env(std::vector<std::string>& sp);
// Simple console output helpers // Simple console output helpers
void rospack_warn(const std::string& name, void log_warn(const std::string& name,
const std::string& msg, const std::string& msg,
bool append_errno = false); bool append_errno = false);
void rospack_error(const std::string& name, void log_error(const std::string& name,
const std::string& msg, const std::string& msg,
bool append_errno = false); bool append_errno = false);
} // namespace rospack } // namespace rospack

View File

@ -27,13 +27,47 @@
#include "rp.h" #include "rp.h"
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream> #include <iostream>
#include <stdlib.h> #include <stdlib.h>
using namespace rospack;
namespace po = boost::program_options; namespace po = boost::program_options;
const char* usage()
{
return "USAGE: rospack <command> [options] [package]\n"
" Allowed commands:\n"
" help\n"
" find [package]\n"
" list\n"
" list-names\n"
" list-duplicates\n"
" langs\n"
" depends [package] (alias: deps)\n"
" depends-manifests [package] (alias: deps-manifests)\n"
" depends-msgsrv [package] (alias: deps-msgsrv)\n"
" depends1 [package] (alias: deps1)\n"
" depends-indent [package] (alias: deps-indent)\n"
" depends-why --target=<target> [package] (alias: deps-why)\n"
" rosdep [package] (alias: rosdeps)\n"
" rosdep0 [package] (alias: rosdeps0)\n"
" vcs [package]\n"
" vcs0 [package]\n"
" depends-on [package]\n"
" depends-on1 [package]\n"
" export [--deps-only] --lang=<lang> --attrib=<attrib> [package]\n"
" plugins --attrib=<attrib> [--top=<toppkg>] [package]\n"
" cflags-only-I [--deps-only] [package]\n"
" cflags-only-other [--deps-only] [package]\n"
" libs-only-L [--deps-only] [package]\n"
" libs-only-l [--deps-only] [package]\n"
" libs-only-other [--deps-only] [package]\n"
" profile [--length=<length>] [--zombie-only]\n"
" Extra options:\n"
" -q Quiets error reports.\n\n"
" If [package] is omitted, the current working directory\n"
" is used (if it contains a manifest.xml).\n\n";
}
int int
parse_args(int argc, char** argv, po::variables_map& vm) parse_args(int argc, char** argv, po::variables_map& vm)
{ {
@ -57,7 +91,7 @@ parse_args(int argc, char** argv, po::variables_map& vm)
} }
catch(boost::program_options::error e) catch(boost::program_options::error e)
{ {
rospack_error("rospack", std::string("failed to parse command-line options: ") + e.what()); rospack::log_error("rospack", std::string("failed to parse command-line options: ") + e.what());
// TODO: print USAGE // TODO: print USAGE
return 1; return 1;
} }
@ -66,29 +100,6 @@ parse_args(int argc, char** argv, po::variables_map& vm)
return 0; return 0;
} }
void
get_search_path_from_env(std::vector<std::string>& sp)
{
char* rr = getenv("ROS_ROOT");
char* rpp = getenv("ROS_PACKAGE_PATH");
if(rr)
sp.push_back(rr);
if(rpp)
{
std::vector<std::string> rpp_strings;
boost::split(rpp_strings, rpp,
boost::is_any_of(":"),
boost::token_compress_on);
for(std::vector<std::string>::const_iterator it = rpp_strings.begin();
it != rpp_strings.end();
++it)
{
sp.push_back(*it);
}
}
}
int int
main(int argc, char** argv) main(int argc, char** argv)
{ {
@ -99,9 +110,9 @@ main(int argc, char** argv)
if(ret) if(ret)
return ret; return ret;
Rospack rp; rospack::Rospack rp;
std::vector<std::string> search_path; std::vector<std::string> search_path;
get_search_path_from_env(search_path); rospack::get_search_path_from_env(search_path);
rp.crawl(search_path, false); rp.crawl(search_path, false);
std::string command; std::string command;
@ -110,10 +121,14 @@ main(int argc, char** argv)
command = vm["command"].as<std::string>(); command = vm["command"].as<std::string>();
if(vm.count("package")) if(vm.count("package"))
package = vm["package"].as<std::string>(); package = vm["package"].as<std::string>();
else
{
// TODO: try to determine package from directory context
}
if(!command.size()) if(!command.size())
{ {
rospack_error("rospack", "no command given"); rospack::log_error("rospack", "no command given");
return 1; return 1;
} }
@ -121,16 +136,76 @@ main(int argc, char** argv)
{ {
if(!package.size()) if(!package.size())
{ {
rospack_error("rospack", "no package given for find command"); rospack::log_error("rospack", "no package given for find command");
return 1; return 1;
} }
std::string path = rp.find(package); std::string path;
printf("%s\n", path.c_str()); if(!rp.find(package, path))
return 1;
else
{
printf("%s\n", path.c_str());
return 0;
}
}
else if(command == "list")
{
std::vector<std::pair<std::string, std::string> > list;
rp.list(list);
for(std::vector<std::pair<std::string, std::string> >::const_iterator it = list.begin();
it != list.end();
++it)
{
printf("%s %s\n", it->first.c_str(), it->second.c_str());
}
}
else if(command == "list-names")
{
std::vector<std::pair<std::string, std::string> > list;
rp.list(list);
for(std::vector<std::pair<std::string, std::string> >::const_iterator it = list.begin();
it != list.end();
++it)
{
printf("%s\n", it->first.c_str());
}
}
else if(command == "list-duplicates")
{
rospack::log_error("rospack",
std::string("command ") + command + " not implemented");
return 1;
}
else if(command == "langs")
{
rospack::log_error("rospack",
std::string("command ") + command + " not implemented");
return 1;
}
else if(command == "depends" || command == "deps" ||
command == "depends1" || command == "deps1")
{
std::vector<std::string> deps;
if(!rp.deps(package, (command == "depends1" || command == "deps1"), deps))
return 1;
else
{
for(std::vector<std::string>::const_iterator it = deps.begin();
it != deps.end();
++it)
printf("%s\n", it->c_str());
return 0;
}
}
else if(command == "help")
{
printf("%s", usage());
return 0;
} }
else else
{ {
rospack_error("rospack", rospack::log_error("rospack",
std::string("command ") + command + " not implemented"); std::string("command ") + command + " not implemented");
return 1; return 1;
} }