LCOV - code coverage report
Current view: top level - src/esys/repo/sharing - providerregistry_sharing.cpp (source / functions) Hit Total Coverage
Test: esysrepo_coverage.info Lines: 65 76 85.5 %
Date: 2026-11-07 22:18:26 Functions: 10 11 90.9 %

          Line data    Source code
       1             : /*!
       2             :  * \file esys/repo/sharing/providerregistry_sharing.cpp
       3             :  * \brief Explicit shareable providers (ADR-0039/0040)
       4             :  *
       5             :  * \cond
       6             :  * __legal_b__
       7             :  *
       8             :  * Copyright (c) 2026 Michel Gillet
       9             :  * Distributed under the MIT License.
      10             :  * (See accompanying file LICENSE.txt or
      11             :  * copy at https://opensource.org/licenses/MIT)
      12             :  *
      13             :  * __legal_e__
      14             :  * \endcond
      15             :  *
      16             :  */
      17             : 
      18             : #include "esys/repo/esysrepo_prec.h"
      19             : #include "esys/repo/sharing/providerregistry.h"
      20             : #include "esys/repo/sharing/identity.h"
      21             : #include "esys/repo/errorinfo.h"
      22             : #include "esys/repo/manifest.h"
      23             : #include "esys/repo/manifest/location.h"
      24             : #include "esys/repo/manifest/repository.h"
      25             : 
      26             : namespace esys::repo::sharing
      27             : {
      28             : 
      29           4 : void Provider::set_repository(std::shared_ptr<manifest::Repository> repo)
      30             : {
      31           4 :     m_repository = std::move(repo);
      32           4 : }
      33             : 
      34           4 : std::shared_ptr<manifest::Repository> Provider::get_repository() const
      35             : {
      36           4 :     return m_repository;
      37             : }
      38             : 
      39           4 : void Provider::set_normalized_identity(const std::string &identity)
      40             : {
      41           4 :     m_normalized_identity = identity;
      42           4 : }
      43             : 
      44           1 : const std::string &Provider::get_normalized_identity() const
      45             : {
      46           1 :     return m_normalized_identity;
      47             : }
      48             : 
      49           4 : void Provider::set_config(const Config &config)
      50             : {
      51           4 :     m_config = config;
      52           4 : }
      53             : 
      54           0 : const Config &Provider::get_config() const
      55             : {
      56           0 :     return m_config;
      57             : }
      58             : 
      59          29 : Result ProviderRegistry::build(const Manifest &manifest)
      60             : {
      61          29 :     clear();
      62             : 
      63          64 :     for (const auto &loc : manifest.get_locations())
      64             :     {
      65          35 :         if (!loc) continue;
      66         216 :         for (const auto &repo : loc->get_repos())
      67             :         {
      68         181 :             if (!repo || !repo->get_sharing().has_value()) continue;
      69             : 
      70           4 :             if (repo->get_path() == "." || repo->get_path() == "./")
      71             :             {
      72           0 :                 return ESYSREPO_RESULT(ResultCode::SHARING_ROOT_PROVIDER,
      73             :                                        "workspace root path=\".\" cannot be a sharing provider");
      74             :             }
      75             : 
      76           4 :             const Config &cfg = *repo->get_sharing();
      77             : 
      78             :             // Prefer primary addr; also register alt_addr as same provider identity set
      79           4 :             std::string url = Identity::compose_location_url(loc->get_address(), repo->get_name());
      80           4 :             auto id = Identity::normalize(url);
      81           4 :             if (id.error())
      82             :             {
      83           0 :                 std::string msg = "provider identity normalize failed for path=" + repo->get_path();
      84           0 :                 if (id.get_error_info() && !id.get_error_info()->get_text().empty())
      85           0 :                     msg += ": " + id.get_error_info()->get_text();
      86           0 :                 return ESYSREPO_RESULT(id.get_result_code(), msg);
      87           0 :             }
      88             : 
      89           4 :             Provider provider;
      90           8 :             provider.set_repository(repo);
      91           4 :             provider.set_normalized_identity(id.get());
      92           4 :             provider.set_config(cfg);
      93           4 :             const std::size_t index = m_providers.size();
      94           4 :             m_providers.push_back(provider);
      95           4 :             m_by_identity[id.get()].push_back(index);
      96             : 
      97           4 :             if (!loc->get_alt_address().empty())
      98             :             {
      99           1 :                 std::string alt_url = Identity::compose_location_url(loc->get_alt_address(), repo->get_name());
     100           1 :                 auto alt_id = Identity::normalize(alt_url);
     101           5 :                 if (!alt_id.error() && alt_id.get() != id.get())
     102             :                 {
     103             :                     // Same provider reachable under alt spelling — index alias to same Provider
     104           0 :                     m_by_identity[alt_id.get()].push_back(index);
     105             :                 }
     106           1 :             }
     107           4 :         }
     108             :     }
     109             : 
     110          29 :     return ESYSREPO_RESULT(ResultCode::OK);
     111             : }
     112             : 
     113          29 : void ProviderRegistry::clear()
     114             : {
     115          29 :     m_providers.clear();
     116          29 :     m_by_identity.clear();
     117          29 : }
     118             : 
     119          57 : const std::vector<Provider> &ProviderRegistry::get_providers() const
     120             : {
     121          57 :     return m_providers;
     122             : }
     123             : 
     124           1 : std::set<std::string> ProviderRegistry::registered_identities() const
     125             : {
     126           1 :     std::set<std::string> out;
     127           2 :     for (const auto &p : m_providers) out.insert(p.get_normalized_identity());
     128             :     // Include alt aliases that map to providers
     129           2 :     for (const auto &pair : m_by_identity) out.insert(pair.first);
     130           1 :     return out;
     131           0 : }
     132             : 
     133           3 : Result_t<std::shared_ptr<Provider>> ProviderRegistry::match(const std::string &normalized_identity) const
     134             : {
     135           3 :     auto it = m_by_identity.find(normalized_identity);
     136           3 :     if (it == m_by_identity.end() || it->second.empty())
     137           0 :         return Result_t<std::shared_ptr<Provider>>(std::shared_ptr<Provider>{});
     138             : 
     139             :     // Deduplicate indices (addr + alt_addr can both point at same provider)
     140           3 :     std::set<std::size_t> unique(it->second.begin(), it->second.end());
     141           3 :     if (unique.size() > 1)
     142             :     {
     143           1 :         std::string msg = "ambiguous sharing providers for identity '" + normalized_identity + "':";
     144           3 :         for (std::size_t idx : unique)
     145             :         {
     146           2 :             const auto &repo = m_providers[idx].get_repository();
     147           2 :             msg += " ";
     148           4 :             msg += repo ? repo->get_path() : "?";
     149           2 :         }
     150           2 :         return Result_t<std::shared_ptr<Provider>>(ESYSREPO_RESULT(ResultCode::SHARING_AMBIGUOUS_PROVIDER, msg));
     151           1 :     }
     152             : 
     153           2 :     auto provider = std::make_shared<Provider>(m_providers[*unique.begin()]);
     154           6 :     return Result_t<std::shared_ptr<Provider>>(provider);
     155           6 : }
     156             : 
     157             : } // namespace esys::repo::sharing

Generated by: LCOV version 1.14