From 3a5222b2ecb6b33c4357a0bd63034740c24c7e1e Mon Sep 17 00:00:00 2001
From: Rainer Kartmann <rainer.kartmann@kit.edu>
Date: Tue, 7 Nov 2023 13:21:18 +0100
Subject: [PATCH] Handle ARON includes to packages with namespace

---
 .../codegeneration/typereader/xml/Reader.cpp  | 87 ++++++++++++++++---
 1 file changed, 76 insertions(+), 11 deletions(-)

diff --git a/source/RobotAPI/libraries/aron/codegeneration/typereader/xml/Reader.cpp b/source/RobotAPI/libraries/aron/codegeneration/typereader/xml/Reader.cpp
index 10aeca408..1955a7658 100644
--- a/source/RobotAPI/libraries/aron/codegeneration/typereader/xml/Reader.cpp
+++ b/source/RobotAPI/libraries/aron/codegeneration/typereader/xml/Reader.cpp
@@ -42,12 +42,13 @@ namespace armarx::aron::typereader::xml
     {
         /// Resolve a relative package path
         std::optional<fs::path>
-        resolveRelativePackagePath(const fs::path& path, const std::vector<fs::path>& includePaths)
+        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
@@ -56,20 +57,80 @@ 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)
             {
-                for (const std::string& includePath : finder.getIncludePathList())
+                armarx::CMakePackageFinder& finder = finders.emplace_back(packageName);
+                if (finder.packageFound())
                 {
-                    fs::path absPath = includePath / path;
-                    if (fs::is_regular_file(absPath))
+                    // 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)
+            {
+                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)
+                {
+                    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;
@@ -138,7 +199,9 @@ namespace armarx::aron::typereader::xml
             {
                 auto i = readCodeInclude(include, filePath.parent_path(), includePaths);
                 if (not i.empty())
+                {
                     this->systemIncludes.push_back(i);
+                }
             }
         }
 
@@ -149,7 +212,9 @@ namespace armarx::aron::typereader::xml
             {
                 auto i = readAronInclude(include, filePath.parent_path(), includePaths);
                 if (not i.empty())
+                {
                     this->aronIncludes.push_back(i);
+                }
             }
         }
 
-- 
GitLab