Skip to content
Snippets Groups Projects
Commit f6b859fa authored by Rainer Kartmann's avatar Rainer Kartmann
Browse files

Merge branch 'fix/aron-include-for-projects-with-namespace' into 'master'

Fix/aron include for projects with namespace

See merge request !400
parents 50ede194 3a5222b2
No related branches found
No related tags found
1 merge request!400Fix/aron include for projects with namespace
Pipeline #15875 passed
......@@ -21,25 +21,19 @@
* GNU General Public License
*/
// STD/STL
// Header
#include "Reader.h"
#include <sstream>
// Simox
#include <SimoxUtility/algorithm/string/string_tools.h>
#include <SimoxUtility/algorithm/vector.hpp>
// ArmarX
#include <ArmarXCore/core/rapidxml/wrapper/RapidXmlReader.h>
#include <ArmarXCore/core/system/cmake/CMakePackageFinder.h>
#include <RobotAPI/libraries/aron/codegeneration/typereader/xml/Data.h>
#include <RobotAPI/libraries/aron/core/type/variant/Factory.h>
namespace armarx::aron::typereader::xml
{
namespace fs = std::filesystem;
......@@ -47,12 +41,14 @@ namespace armarx::aron::typereader::xml
namespace
{
/// Resolve a relative package path
std::optional<fs::path> resolveRelativePackagePath(const fs::path& path, const std::vector<fs::path>& includePaths)
std::optional<fs::path>
resolveRelativePackagePath(const fs::path& filepath,
const std::vector<fs::path>& includePaths)
{
// new behavior: using provided include paths
for (const auto& includePath : includePaths)
{
fs::path absPath = includePath / path;
fs::path absPath = includePath / filepath;
if (fs::is_regular_file(absPath))
{
// path is valid
......@@ -61,27 +57,89 @@ namespace armarx::aron::typereader::xml
}
// legacy behavior: using cmake package finder paths
const std::string package = *path.begin();
armarx::CMakePackageFinder finder(package);
if (finder.packageFound())
std::vector<std::string> packageNameCandidates;
{
auto it = filepath.begin();
std::string packageName = *it;
packageNameCandidates.push_back(packageName);
++it;
if (it != filepath.end())
{
packageName += "_" + it->string();
packageNameCandidates.push_back(packageName);
}
}
std::vector<armarx::CMakePackageFinder> finders;
size_t foundFinderIndex = 0;
size_t numberOfFoundCandidates = 0;
for (const std::string& packageName : packageNameCandidates)
{
armarx::CMakePackageFinder& finder = finders.emplace_back(packageName);
if (finder.packageFound())
{
// TODO: In theory, we could also consider whether the requested file exists in
// the found package (see check below).
numberOfFoundCandidates++;
foundFinderIndex = finders.size() - 1;
}
}
if (numberOfFoundCandidates == 0)
{
std::stringstream msg;
msg << "No package matching the ARON include " << filepath
<< " found. Tried CMake project names:";
for (const std::string& packageName : packageNameCandidates)
{
msg << " '" << packageName << "',";
}
throw error::AronException(__PRETTY_FUNCTION__, msg.str());
}
if (numberOfFoundCandidates > 1)
{
for (const std::string& includePath : finder.getIncludePathList())
std::stringstream msg;
msg << "The ARON include " << filepath << " is ambiguous: The following "
<< numberOfFoundCandidates
<< " CMake projects matching the include were found:";
ARMARX_CHECK_EQUAL(packageNameCandidates.size(), finders.size());
for (size_t i = 0; i < packageNameCandidates.size(); ++i)
{
fs::path absPath = includePath / path;
if (fs::is_regular_file(absPath))
if (finders[i].packageFound())
{
// path is valid
return absPath;
msg << "\n- project '" << packageNameCandidates[i] << "' at '"
<< finders[i].getPackageDir() << "'";
}
}
return std::nullopt;
throw error::AronException(__PRETTY_FUNCTION__, msg.str());
}
ARMARX_CHECK_EQUAL(numberOfFoundCandidates, 1);
ARMARX_CHECK_LESS(foundFinderIndex, finders.size());
CMakePackageFinder& finder = finders.at(foundFinderIndex);
ARMARX_CHECK(finder.packageFound());
for (const std::string& includePath : finder.getIncludePathList())
{
fs::path absPath = includePath / filepath;
if (fs::is_regular_file(absPath))
{
// path is valid
return absPath;
}
}
return std::nullopt;
}
}
} // namespace
void Reader::parseFile(const std::string& _filename, const std::vector<std::filesystem::path>& includePaths)
void
Reader::parseFile(const std::string& _filename,
const std::vector<std::filesystem::path>& includePaths)
{
std::string filename = _filename;
......@@ -93,7 +151,9 @@ namespace armarx::aron::typereader::xml
parseFile(std::filesystem::path(filename), includePaths);
}
void Reader::parseFile(const std::filesystem::path& _file, const std::vector<std::filesystem::path>& includePaths)
void
Reader::parseFile(const std::filesystem::path& _file,
const std::vector<std::filesystem::path>& includePaths)
{
fs::path file = _file;
if (not std::filesystem::exists(file))
......@@ -102,7 +162,10 @@ namespace armarx::aron::typereader::xml
auto p = resolveRelativePackagePath(file, includePaths);
if (not p)
{
throw error::AronException(__PRETTY_FUNCTION__, "Could not find the file " + file.string() + ". Tried include paths: " + simox::alg::to_string(includePaths));
throw error::AronException(
__PRETTY_FUNCTION__,
"Could not find the file " + file.string() +
". Tried include paths: " + simox::alg::to_string(includePaths));
}
file = *p;
}
......@@ -112,7 +175,10 @@ namespace armarx::aron::typereader::xml
}
// private method reading nodes
void Reader::parse(const RapidXmlReaderPtr& reader, const std::filesystem::path& filePath, const std::vector<std::filesystem::path>& includePaths)
void
Reader::parse(const RapidXmlReaderPtr& reader,
const std::filesystem::path& filePath,
const std::vector<std::filesystem::path>& includePaths)
{
RapidXmlReaderNode root = reader->getRoot();
......@@ -132,7 +198,10 @@ namespace armarx::aron::typereader::xml
for (const auto& include : (*codeincludes).nodes())
{
auto i = readCodeInclude(include, filePath.parent_path(), includePaths);
if (not i.empty()) this->systemIncludes.push_back(i);
if (not i.empty())
{
this->systemIncludes.push_back(i);
}
}
}
......@@ -142,7 +211,10 @@ namespace armarx::aron::typereader::xml
for (const auto& include : (*aronincludes).nodes())
{
auto i = readAronInclude(include, filePath.parent_path(), includePaths);
if (not i.empty()) this->aronIncludes.push_back(i);
if (not i.empty())
{
this->aronIncludes.push_back(i);
}
}
}
......@@ -151,10 +223,14 @@ namespace armarx::aron::typereader::xml
{
for (const auto& include : (*includes).nodes())
{
if (util::HasTagName(include, constantes::SYSTEM_INCLUDE_TAG)) // if its a system include tag then we know that it must be a code include
if (util::HasTagName(
include,
constantes::
SYSTEM_INCLUDE_TAG)) // if its a system include tag then we know that it must be a code include
{
auto i = readCodeInclude(include, filePath.parent_path(), includePaths);
if (not i.empty()) this->systemIncludes.push_back(i);
if (not i.empty())
this->systemIncludes.push_back(i);
}
else
{
......@@ -171,17 +247,20 @@ namespace armarx::aron::typereader::xml
what = util::GetAttribute(include, constantes::INCLUDE_ATTRIBUTE_NAME);
}
if (not what.empty() && std::filesystem::path(what) != filePath) // did we found something?
if (not what.empty() &&
std::filesystem::path(what) != filePath) // did we found something?
{
if (simox::alg::ends_with(what, ARON_FILE_SUFFIX))
{
auto i = readAronInclude(include, filePath.parent_path(), includePaths);
if (not i.empty()) this->aronIncludes.push_back(i);
if (not i.empty())
this->aronIncludes.push_back(i);
}
else // we believe that this is a code include since it is not an xml file
{
auto i = readCodeInclude(include, filePath.parent_path(), includePaths);
if (not i.empty()) this->systemIncludes.push_back(i);
if (not i.empty())
this->systemIncludes.push_back(i);
}
}
}
......@@ -195,13 +274,18 @@ namespace armarx::aron::typereader::xml
{
if (util::HasTagName(generateType, constantes::OBJECT_TAG))
{
for (const auto& additionalInclude : getAdditionalIncludesFromReplacements(generateType, filePath.parent_path()))
for (const auto& additionalInclude : getAdditionalIncludesFromReplacements(
generateType, filePath.parent_path()))
{
RapidXmlReaderPtr reader = RapidXmlReader::FromXmlString("<PackagePath package=\""+additionalInclude.first+"\" path=\""+additionalInclude.second+"\"/>");
RapidXmlReaderPtr reader = RapidXmlReader::FromXmlString(
"<PackagePath package=\"" + additionalInclude.first + "\" path=\"" +
additionalInclude.second + "\"/>");
auto node = reader->getRoot();
auto i = this->readAronInclude(node, filePath, includePaths);
if (not i.empty() && std::find(this->aronIncludes.begin(), this->aronIncludes.end(), i) == this->aronIncludes.end())
if (not i.empty() &&
std::find(this->aronIncludes.begin(), this->aronIncludes.end(), i) ==
this->aronIncludes.end())
{
this->aronIncludes.push_back(i);
}
......@@ -218,26 +302,37 @@ namespace armarx::aron::typereader::xml
if (util::HasTagName(generateType, constantes::OBJECT_TAG))
{
const auto nav = readGenerateObject(generateType);
generateObjects.push_back(factory.allGeneratedPublicObjects.at(nav->getObjectName()));
generateObjects.push_back(
factory.allGeneratedPublicObjects.at(nav->getObjectName()));
continue;
}
if (util::HasTagName(generateType, constantes::INT_ENUM_TAG))
{
const auto nav = readGenerateIntEnum(generateType);
generateIntEnums.push_back(factory.allGeneratedPublicIntEnums.at(nav->getEnumName()));
generateIntEnums.push_back(
factory.allGeneratedPublicIntEnums.at(nav->getEnumName()));
continue;
}
throw error::ValueNotValidException("XMLReader", "parse", "Could not find a valid tag inside generatetypes", generateType.name());
throw error::ValueNotValidException(
"XMLReader",
"parse",
"Could not find a valid tag inside generatetypes",
generateType.name());
}
}
else
{
throw error::AronException(__PRETTY_FUNCTION__, "No generate types found in aron xml '" + filePath.string() + "'.");
throw error::AronException(__PRETTY_FUNCTION__,
"No generate types found in aron xml '" + filePath.string() +
"'.");
}
}
std::pair<std::string, std::string> Reader::readPackagePathInclude(const RapidXmlReaderNode& node, const std::filesystem::path&, const std::vector<std::filesystem::path>& includePaths)
std::pair<std::string, std::string>
Reader::readPackagePathInclude(const RapidXmlReaderNode& node,
const std::filesystem::path&,
const std::vector<std::filesystem::path>& includePaths)
{
util::EnforceTagName(node, constantes::PACKAGE_PATH_TAG);
std::string package = util::GetAttribute(node, constantes::PACKAGE_ATTRIBUTE_NAME);
......@@ -250,15 +345,23 @@ namespace armarx::aron::typereader::xml
path = simox::alg::replace_all(path, ">", "");
const std::filesystem::path includepath(package + "/" + path);
if (std::optional<fs::path> resolvedPackagePath = resolveRelativePackagePath(includepath, includePaths); resolvedPackagePath.has_value())
if (std::optional<fs::path> resolvedPackagePath =
resolveRelativePackagePath(includepath, includePaths);
resolvedPackagePath.has_value())
{
return {package + "/" + path, "<" + package + "/" + path + ">"};
}
throw error::AronException(__PRETTY_FUNCTION__, "Could not find an file `" + includepath.string() + "`. Search paths are: " + simox::alg::to_string(includePaths));
throw error::AronException(
__PRETTY_FUNCTION__,
"Could not find an file `" + includepath.string() +
"`. Search paths are: " + simox::alg::to_string(includePaths));
}
std::pair<std::string, std::string> Reader::readInclude(const RapidXmlReaderNode& node, const std::filesystem::path& filepath, const std::vector<std::filesystem::path>& includePaths)
std::pair<std::string, std::string>
Reader::readInclude(const RapidXmlReaderNode& node,
const std::filesystem::path& filepath,
const std::vector<std::filesystem::path>& includePaths)
{
util::EnforceTagName(node, constantes::INCLUDE_TAG);
std::string value = util::GetAttribute(node, constantes::INCLUDE_ATTRIBUTE_NAME);
......@@ -270,7 +373,10 @@ namespace armarx::aron::typereader::xml
return {value, "<" + value + ">"};
}
std::pair<std::string, std::string> Reader::readSystemInclude(const RapidXmlReaderNode& node, const std::filesystem::path&, const std::vector<std::filesystem::path>& includePaths)
std::pair<std::string, std::string>
Reader::readSystemInclude(const RapidXmlReaderNode& node,
const std::filesystem::path&,
const std::vector<std::filesystem::path>& includePaths)
{
util::EnforceTagName(node, constantes::SYSTEM_INCLUDE_TAG);
std::string value = util::GetAttribute(node, constantes::INCLUDE_ATTRIBUTE_NAME);
......@@ -282,7 +388,10 @@ namespace armarx::aron::typereader::xml
return {"", "<" + value + ">"};
}
std::string Reader::readCodeInclude(const RapidXmlReaderNode& node, const std::filesystem::path& filepath, const std::vector<std::filesystem::path>& includePaths)
std::string
Reader::readCodeInclude(const RapidXmlReaderNode& node,
const std::filesystem::path& filepath,
const std::vector<std::filesystem::path>& includePaths)
{
if (util::HasTagName(node, constantes::PACKAGE_PATH_TAG))
{
......@@ -297,10 +406,14 @@ namespace armarx::aron::typereader::xml
return readSystemInclude(node, filepath, includePaths).second;
}
throw error::ValueNotValidException(__PRETTY_FUNCTION__, "Could not parse a code include. The tag is wrong.", node.name());
throw error::ValueNotValidException(
__PRETTY_FUNCTION__, "Could not parse a code include. The tag is wrong.", node.name());
}
std::string Reader::readAronInclude(const RapidXmlReaderNode& node, const std::filesystem::path& filepath, const std::vector<std::filesystem::path>& includePaths)
std::string
Reader::readAronInclude(const RapidXmlReaderNode& node,
const std::filesystem::path& filepath,
const std::vector<std::filesystem::path>& includePaths)
{
std::string include;
std::string include_unescaped;
......@@ -320,7 +433,8 @@ namespace armarx::aron::typereader::xml
if (not include.empty()) // we found something
{
// autoinclude the code file (suffix will be replaced by correct language)
std::string codeinclude = simox::alg::replace_last(include, ARON_FILE_SUFFIX, CODE_FILE_SUFFIX);
std::string codeinclude =
simox::alg::replace_last(include, ARON_FILE_SUFFIX, CODE_FILE_SUFFIX);
this->systemIncludes.push_back(codeinclude);
// parse parent xml file and add objects to alreday known
......@@ -342,17 +456,22 @@ namespace armarx::aron::typereader::xml
return include;
}
throw error::ValueNotValidException(__PRETTY_FUNCTION__, "Could not parse an aron include. The tag is wrong.", node.name());
throw error::ValueNotValidException(
__PRETTY_FUNCTION__, "Could not parse an aron include. The tag is wrong.", node.name());
}
std::vector<std::pair<std::string, std::string>> Reader::getAdditionalIncludesFromReplacements(const RapidXmlReaderNode& node, const std::filesystem::path& filePath)
std::vector<std::pair<std::string, std::string>>
Reader::getAdditionalIncludesFromReplacements(const RapidXmlReaderNode& node,
const std::filesystem::path& filePath)
{
std::vector<std::pair<std::string, std::string>> ret;
for (const auto& repl : constantes::REPLACEMENTS)
{
auto replacement = repl.second;
if (not replacement.additionalAronDTOXMLIncludePackagePath.first.empty() && not replacement.additionalAronDTOXMLIncludePackagePath.second.empty() && util::HasTagName(node, repl.first))
if (not replacement.additionalAronDTOXMLIncludePackagePath.first.empty() &&
not replacement.additionalAronDTOXMLIncludePackagePath.second.empty() &&
util::HasTagName(node, repl.first))
{
// we found a string that will be replaced so we might need to add a default include
ret.push_back(replacement.additionalAronDTOXMLIncludePackagePath);
......@@ -374,15 +493,17 @@ namespace armarx::aron::typereader::xml
return ret;
}
type::ObjectPtr Reader::readGenerateObject(const RapidXmlReaderNode& node)
type::ObjectPtr
Reader::readGenerateObject(const RapidXmlReaderNode& node)
{
util::EnforceTagName(node, constantes::OBJECT_TAG);
return type::Object::DynamicCastAndCheck(factory.create(node, Path()));
}
type::IntEnumPtr Reader::readGenerateIntEnum(const RapidXmlReaderNode& node)
type::IntEnumPtr
Reader::readGenerateIntEnum(const RapidXmlReaderNode& node)
{
util::EnforceTagName(node, constantes::INT_ENUM_TAG);
return type::IntEnum::DynamicCastAndCheck(factory.create(node, Path()));
}
}
} // namespace armarx::aron::typereader::xml
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment