Skip to content

Commit 5aeca39

Browse files
Add general resource locator
1 parent 771e3f1 commit 5aeca39

File tree

4 files changed

+236
-0
lines changed

4 files changed

+236
-0
lines changed

tesseract_common/include/tesseract_common/resource_locator.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,36 @@ class ResourceLocator
6464
void serialize(Archive& ar, const unsigned int version); // NOLINT
6565
};
6666

67+
/**
68+
* @brief A general resource loaders using environment variable
69+
* @details Also can set this environment variable TESSERACT_RESOURCE_PATH
70+
* with ':' separated directories and then use the directires as package names
71+
*/
72+
class GeneralResourceLocator : public ResourceLocator
73+
{
74+
public:
75+
using Ptr = std::shared_ptr<GeneralResourceLocator>;
76+
using ConstPtr = std::shared_ptr<const GeneralResourceLocator>;
77+
GeneralResourceLocator();
78+
GeneralResourceLocator(const GeneralResourceLocator&) = default;
79+
GeneralResourceLocator& operator=(const GeneralResourceLocator&) = default;
80+
GeneralResourceLocator(GeneralResourceLocator&&) = default;
81+
GeneralResourceLocator& operator=(GeneralResourceLocator&&) = default;
82+
~GeneralResourceLocator() override = default;
83+
84+
std::shared_ptr<Resource> locateResource(const std::string& url) const override;
85+
86+
bool operator==(const GeneralResourceLocator& rhs) const;
87+
bool operator!=(const GeneralResourceLocator& rhs) const;
88+
89+
private:
90+
friend class boost::serialization::access;
91+
template <class Archive>
92+
void serialize(Archive& ar, const unsigned int version); // NOLINT
93+
94+
std::unordered_map<std::string, std::string> package_paths_;
95+
};
96+
6797
/** @brief Represents resource data available from a file or url */
6898
class Resource : public ResourceLocator
6999
{
@@ -203,6 +233,7 @@ class BytesResource : public tesseract_common::Resource
203233

204234
#include <boost/serialization/export.hpp>
205235
#include <boost/serialization/tracking.hpp>
236+
BOOST_CLASS_EXPORT_KEY2(tesseract_common::GeneralResourceLocator, "GeneralResourceLocator")
206237
BOOST_CLASS_EXPORT_KEY2(tesseract_common::SimpleLocatedResource, "SimpleLocatedResource")
207238
BOOST_CLASS_EXPORT_KEY2(tesseract_common::BytesResource, "BytesResource")
208239

tesseract_common/src/resource_locator.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@ TESSERACT_COMMON_IGNORE_WARNINGS_PUSH
3030
#include <console_bridge/console.h>
3131
#include <cassert>
3232
#include <iostream>
33+
#include <mutex>
3334
#include <boost/serialization/nvp.hpp>
3435
#include <boost/serialization/shared_ptr.hpp>
3536
#include <boost/serialization/vector.hpp>
37+
#include <boost/algorithm/string/classification.hpp>
38+
#include <boost/algorithm/string/split.hpp>
3639
TESSERACT_COMMON_IGNORE_WARNINGS_POP
3740

3841
#include <tesseract_common/resource_locator.h>
@@ -49,6 +52,111 @@ void ResourceLocator::serialize(Archive& /*ar*/, const unsigned int /*version*/)
4952
{
5053
}
5154

55+
GeneralResourceLocator::GeneralResourceLocator()
56+
{
57+
// This was added to allow user defined resource path
58+
// When using this within a snap you can map host ros package paths to this environment variable
59+
char* tesseract_resource_paths = std::getenv("TESSERACT_RESOURCE_PATH");
60+
if (tesseract_resource_paths != nullptr)
61+
{
62+
std::vector<std::string> tokens;
63+
#ifndef _WIN32
64+
boost::split(tokens, tesseract_resource_paths, boost::is_any_of(":"), boost::token_compress_on);
65+
#else
66+
boost::split(tokens, tesseract_resource_paths, boost::is_any_of(";"), boost::token_compress_on);
67+
#endif
68+
for (const auto& token : tokens)
69+
{
70+
tesseract_common::fs::path d(token);
71+
if (tesseract_common::fs::is_directory(d) && tesseract_common::fs::exists(d))
72+
{
73+
std::string dir_name = d.filename().string();
74+
if (package_paths_.find(dir_name) == package_paths_.end())
75+
package_paths_[dir_name] = token;
76+
}
77+
else
78+
{
79+
CONSOLE_BRIDGE_logWarn("Package Path does not exist: %s", token.c_str());
80+
}
81+
}
82+
}
83+
84+
char* ros_package_paths = std::getenv("ROS_PACKAGE_PATH");
85+
if (ros_package_paths != nullptr)
86+
{
87+
std::vector<std::string> tokens;
88+
#ifndef _WIN32
89+
boost::split(tokens, ros_package_paths, boost::is_any_of(":"), boost::token_compress_on);
90+
#else
91+
boost::split(tokens, ros_package_paths, boost::is_any_of(";"), boost::token_compress_on);
92+
#endif
93+
for (const auto& token : tokens)
94+
{
95+
tesseract_common::fs::path d(token);
96+
if (tesseract_common::fs::is_directory(d) && tesseract_common::fs::exists(d))
97+
{
98+
std::string dir_name = d.filename().string();
99+
if (package_paths_.find(dir_name) == package_paths_.end())
100+
package_paths_[dir_name] = token;
101+
}
102+
else
103+
{
104+
CONSOLE_BRIDGE_logError("Package Path does not exist: &s", token.c_str());
105+
}
106+
}
107+
}
108+
}
109+
110+
std::shared_ptr<Resource> GeneralResourceLocator::locateResource(const std::string& url) const
111+
{
112+
std::string mod_url = url;
113+
if (url.find("file:///") == 0)
114+
{
115+
mod_url.erase(0, strlen("file://"));
116+
size_t pos = mod_url.find('/');
117+
if (pos == std::string::npos)
118+
return nullptr;
119+
}
120+
else if (url.find("package://") == 0)
121+
{
122+
mod_url.erase(0, strlen("package://"));
123+
size_t pos = mod_url.find('/');
124+
if (pos == std::string::npos)
125+
return nullptr;
126+
127+
std::string package = mod_url.substr(0, pos);
128+
mod_url.erase(0, pos);
129+
130+
auto find_package = package_paths_.find(package);
131+
if (find_package != package_paths_.end())
132+
{
133+
mod_url = find_package->second + mod_url;
134+
}
135+
else
136+
{
137+
CONSOLE_BRIDGE_logError("Failed to find package resource %s for %s", package.c_str(), url.c_str());
138+
return nullptr;
139+
}
140+
}
141+
142+
if (!tesseract_common::fs::path(mod_url).is_complete())
143+
{
144+
CONSOLE_BRIDGE_logWarn("Resource not handled: %s", mod_url.c_str());
145+
return nullptr;
146+
}
147+
148+
return std::make_shared<SimpleLocatedResource>(url, mod_url, std::make_shared<GeneralResourceLocator>(*this));
149+
}
150+
151+
bool GeneralResourceLocator::operator==(const GeneralResourceLocator& /*rhs*/) const { return true; }
152+
bool GeneralResourceLocator::operator!=(const GeneralResourceLocator& /*rhs*/) const { return false; }
153+
154+
template <class Archive>
155+
void GeneralResourceLocator::serialize(Archive& ar, const unsigned int /*version*/)
156+
{
157+
ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(ResourceLocator);
158+
}
159+
52160
bool Resource::operator==(const Resource& /*rhs*/) const { return true; }
53161
bool Resource::operator!=(const Resource& /*rhs*/) const { return false; }
54162

@@ -213,8 +321,10 @@ void BytesResource::serialize(Archive& ar, const unsigned int /*version*/)
213321

214322
#include <tesseract_common/serialization.h>
215323
TESSERACT_SERIALIZE_ARCHIVES_INSTANTIATE(tesseract_common::ResourceLocator)
324+
TESSERACT_SERIALIZE_ARCHIVES_INSTANTIATE(tesseract_common::GeneralResourceLocator)
216325
TESSERACT_SERIALIZE_ARCHIVES_INSTANTIATE(tesseract_common::Resource)
217326
TESSERACT_SERIALIZE_ARCHIVES_INSTANTIATE(tesseract_common::SimpleLocatedResource)
218327
TESSERACT_SERIALIZE_ARCHIVES_INSTANTIATE(tesseract_common::BytesResource)
328+
BOOST_CLASS_EXPORT_IMPLEMENT(tesseract_common::GeneralResourceLocator)
219329
BOOST_CLASS_EXPORT_IMPLEMENT(tesseract_common::SimpleLocatedResource)
220330
BOOST_CLASS_EXPORT_IMPLEMENT(tesseract_common::BytesResource)

tesseract_common/test/resource_locator_unit.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,94 @@ TEST(ResourceLocatorUnit, SimpleResourceLocatorUnit) // NOLINT
8585
EXPECT_TRUE(resource_does_not_exist->getResourceContentStream() == nullptr);
8686
}
8787

88+
TEST(ResourceLocatorUnit, GeneralResourceLocatorUnit1) // NOLINT
89+
{
90+
using namespace tesseract_common;
91+
tesseract_common::fs::path file_path(__FILE__);
92+
tesseract_common::fs::path package_path = file_path.parent_path().parent_path();
93+
94+
#ifndef _WIN32
95+
std::string env_var = "TESSERACT_RESOURCE_PATH=" + package_path.string();
96+
#else
97+
std::string env_var = "TESSERACT_RESOURCE_PATH=" + package_path.string();
98+
#endif
99+
putenv(env_var.data());
100+
101+
ResourceLocator::Ptr locator = std::make_shared<GeneralResourceLocator>();
102+
103+
Resource::Ptr resource = locator->locateResource("package://tesseract_common/package.xml");
104+
EXPECT_TRUE(resource != nullptr);
105+
EXPECT_TRUE(resource->isFile());
106+
EXPECT_EQ(resource->getUrl(), "package://tesseract_common/package.xml");
107+
EXPECT_EQ(tesseract_common::fs::path(resource->getFilePath()), (package_path / "package.xml"));
108+
EXPECT_FALSE(resource->getResourceContents().empty());
109+
EXPECT_TRUE(resource->getResourceContentStream() != nullptr);
110+
111+
Resource::Ptr sub_resource = resource->locateResource("colcon.pkg");
112+
EXPECT_TRUE(sub_resource != nullptr);
113+
EXPECT_TRUE(sub_resource->isFile());
114+
EXPECT_EQ(sub_resource->getUrl(), "package://tesseract_common/colcon.pkg");
115+
EXPECT_EQ(tesseract_common::fs::path(sub_resource->getFilePath()), (package_path / "colcon.pkg"));
116+
EXPECT_FALSE(sub_resource->getResourceContents().empty());
117+
EXPECT_TRUE(sub_resource->getResourceContentStream() != nullptr);
118+
119+
tesseract_common::Resource::Ptr sub_resource_empty = sub_resource->locateResource("");
120+
EXPECT_TRUE(sub_resource_empty == nullptr);
121+
122+
tesseract_common::Resource::Ptr resource_empty = locator->locateResource("");
123+
EXPECT_TRUE(resource_empty == nullptr);
124+
125+
tesseract_common::Resource::Ptr resource_does_not_exist = locator->locateResource("package://tesseract_common/"
126+
"does_not_exist.txt");
127+
EXPECT_TRUE(resource_does_not_exist != nullptr);
128+
EXPECT_TRUE(resource_does_not_exist->getResourceContents().empty());
129+
EXPECT_TRUE(resource_does_not_exist->getResourceContentStream() == nullptr);
130+
}
131+
132+
TEST(ResourceLocatorUnit, GeneralResourceLocatorUnit2) // NOLINT
133+
{
134+
using namespace tesseract_common;
135+
tesseract_common::fs::path file_path(__FILE__);
136+
tesseract_common::fs::path package_path = file_path.parent_path().parent_path();
137+
138+
#ifndef _WIN32
139+
std::string env_var = "ROS_PACKAGE_PATH=" + package_path.string();
140+
#else
141+
std::string env_var = "ROS_PACKAGE_PATH=" + package_path.string();
142+
#endif
143+
putenv(env_var.data());
144+
145+
ResourceLocator::Ptr locator = std::make_shared<GeneralResourceLocator>();
146+
147+
Resource::Ptr resource = locator->locateResource("package://tesseract_common/package.xml");
148+
EXPECT_TRUE(resource != nullptr);
149+
EXPECT_TRUE(resource->isFile());
150+
EXPECT_EQ(resource->getUrl(), "package://tesseract_common/package.xml");
151+
EXPECT_EQ(tesseract_common::fs::path(resource->getFilePath()), (package_path / "package.xml"));
152+
EXPECT_FALSE(resource->getResourceContents().empty());
153+
EXPECT_TRUE(resource->getResourceContentStream() != nullptr);
154+
155+
Resource::Ptr sub_resource = resource->locateResource("colcon.pkg");
156+
EXPECT_TRUE(sub_resource != nullptr);
157+
EXPECT_TRUE(sub_resource->isFile());
158+
EXPECT_EQ(sub_resource->getUrl(), "package://tesseract_common/colcon.pkg");
159+
EXPECT_EQ(tesseract_common::fs::path(sub_resource->getFilePath()), (package_path / "colcon.pkg"));
160+
EXPECT_FALSE(sub_resource->getResourceContents().empty());
161+
EXPECT_TRUE(sub_resource->getResourceContentStream() != nullptr);
162+
163+
tesseract_common::Resource::Ptr sub_resource_empty = sub_resource->locateResource("");
164+
EXPECT_TRUE(sub_resource_empty == nullptr);
165+
166+
tesseract_common::Resource::Ptr resource_empty = locator->locateResource("");
167+
EXPECT_TRUE(resource_empty == nullptr);
168+
169+
tesseract_common::Resource::Ptr resource_does_not_exist = locator->locateResource("package://tesseract_common/"
170+
"does_not_exist.txt");
171+
EXPECT_TRUE(resource_does_not_exist != nullptr);
172+
EXPECT_TRUE(resource_does_not_exist->getResourceContents().empty());
173+
EXPECT_TRUE(resource_does_not_exist->getResourceContentStream() == nullptr);
174+
}
175+
88176
TEST(ResourceLocatorUnit, ByteResourceUnit) // NOLINT
89177
{
90178
using namespace tesseract_common;

tesseract_common/test/tesseract_common_serialization_unit.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,16 @@ TESSERACT_COMMON_IGNORE_WARNINGS_POP
3838
#include <tesseract_common/atomic_serialization.h>
3939
#include <tesseract_common/joint_state.h>
4040
#include <tesseract_common/manipulator_info.h>
41+
#include <tesseract_common/resource_locator.h>
4142

4243
using namespace tesseract_common;
4344

45+
TEST(TesseractCommonSerializeUnit, GeneralResourceLocator) // NOLINT
46+
{
47+
GeneralResourceLocator locator;
48+
tesseract_common::testSerialization<GeneralResourceLocator>(locator, "GeneralResourceLocator");
49+
}
50+
4451
TEST(TesseractCommonSerializeUnit, KinematicLimits) // NOLINT
4552
{
4653
KinematicLimits limits;

0 commit comments

Comments
 (0)