LCOV - code coverage report
Current view: top level - src/esys/repo/grepo - manifestimpl_grepo.cpp (source / functions) Hit Total Coverage
Test: esysrepo_coverage.info Lines: 200 213 93.9 %
Date: 2026-08-01 10:43:40 Functions: 20 20 100.0 %

          Line data    Source code
       1             : /*!
       2             :  * \file esys/repo/grepo/manifestimpl_grepo.cpp
       3             :  * \brief
       4             :  *
       5             :  * \cond
       6             :  * __legal_b__
       7             :  *
       8             :  * Copyright (c) 2020-2021 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/grepo/manifestimpl.h"
      20             : #include "esys/repo/grepo/manifest.h"
      21             : #include "esys/repo/manifest/repository.h"
      22             : 
      23             : #include <esysfile/xml/writer.h>
      24             : #include <esysfile/xml/attr.h>
      25             : 
      26             : #include <boost/filesystem.hpp>
      27             : #include <boost/tokenizer.hpp>
      28             : 
      29             : namespace esys::repo::grepo
      30             : {
      31             : 
      32          27 : ManifestImpl::ManifestImpl(Manifest *self)
      33          27 :     : m_self(self)
      34             : {
      35          27 : }
      36             : 
      37          79 : ManifestImpl::~ManifestImpl() = default;
      38             : 
      39          25 : Result ManifestImpl::read(const std::string &filename)
      40             : {
      41          25 :     m_repo_no_locations.clear();
      42             : 
      43          25 :     m_file = std::make_shared<esysfile::xml::File>();
      44          25 :     m_file->set_root_node_name("manifest");
      45             : 
      46          50 :     if (self()->get_data() == nullptr) self()->set_data(std::make_shared<repo::Manifest>());
      47             : 
      48          25 :     self()->get_data()->clear();
      49             : 
      50          25 :     int result = m_file->read(filename);
      51          25 :     if (result < 0) return ESYSREPO_RESULT(ResultCode::MANIFEST_ERROR_PARSING_FILE, filename);
      52             : 
      53          25 :     self()->get_data()->set_type(manifest::Type::GOOGLE_MANIFEST);
      54          25 :     self()->get_data()->set_kind(manifest::Kind::ISOLATED);
      55             : 
      56          50 :     return read(m_file->get_data());
      57             : }
      58             : 
      59           4 : Result ManifestImpl::write_xml()
      60             : {
      61           8 :     if (self()->get_data() == nullptr) return ESYSREPO_RESULT(ResultCode::MANIFEST_XML_DATA_NULLPTR);
      62             : 
      63           4 :     m_xml_data = std::make_shared<esysfile::xml::Data>();
      64             : 
      65           4 :     m_xml_data->set_root_node_name("manifest");
      66             : 
      67           4 :     write_remotes();
      68          12 :     write_default(m_xml_data, self()->get_data());
      69           4 :     Result result = write_projects();
      70           8 :     return ESYSREPO_RESULT(result);
      71           4 : }
      72             : 
      73           2 : Result ManifestImpl::write(const std::string &filename)
      74             : {
      75           2 :     Result result = write_xml();
      76           2 :     if (result.error()) return ESYSREPO_RESULT(result);
      77             : 
      78           2 :     esysfile::xml::Writer writer;
      79             : 
      80           4 :     writer.set_data(m_xml_data);
      81             : 
      82           2 :     int result_int = writer.write(filename);
      83           2 :     if (result_int < 0) return ESYSREPO_RESULT(ResultCode::RAW_INT_ERROR, result_int);
      84           2 :     return ESYSREPO_RESULT(ResultCode::OK);
      85           2 : }
      86             : 
      87           1 : Result ManifestImpl::write(std::ostream &os)
      88             : {
      89           1 :     Result result = write_xml();
      90           1 :     if (write_xml().error()) return ESYSREPO_RESULT(result);
      91             : 
      92           1 :     esysfile::xml::Writer writer;
      93             : 
      94           1 :     writer.set_indent(4);
      95           2 :     writer.set_data(m_xml_data);
      96             : 
      97           1 :     int result_int = writer.write(os);
      98           1 :     if (result_int < 0) return ESYSREPO_RESULT(ResultCode::RAW_INT_ERROR, result_int);
      99           1 :     return ESYSREPO_RESULT(ResultCode::OK);
     100           1 : }
     101             : 
     102           4 : void ManifestImpl::write_remotes()
     103             : {
     104          12 :     for (auto &remote : self()->get_data()->get_locations())
     105             :     {
     106          20 :         write_remote(m_xml_data, remote);
     107             :     }
     108           4 : }
     109             : 
     110           4 : void ManifestImpl::write_remote(std::shared_ptr<esysfile::xml::Element> parent,
     111             :                                 std::shared_ptr<manifest::Location> location)
     112             : {
     113           4 :     std::shared_ptr<esysfile::xml::Element> remote_el;
     114             : 
     115           8 :     remote_el = std::make_shared<esysfile::xml::Element>();
     116             : 
     117           4 :     remote_el->set_name("remote");
     118           4 :     remote_el->add_attr("name", location->get_name());
     119           4 :     remote_el->add_attr("fetch", location->get_address());
     120             : 
     121          12 :     parent->add_element(remote_el);
     122             : }
     123             : 
     124           4 : void ManifestImpl::write_default(std::shared_ptr<esysfile::xml::Element> parent,
     125             :                                  std::shared_ptr<repo::Manifest> manifest)
     126             : {
     127           4 :     std::shared_ptr<esysfile::xml::Element> default_el;
     128             : 
     129           8 :     default_el = std::make_shared<esysfile::xml::Element>();
     130             : 
     131           4 :     default_el->set_name("default");
     132           8 :     if (!manifest->get_default_revision().empty()) default_el->add_attr("revision", manifest->get_default_revision());
     133          16 :     if (manifest->get_default_location()) default_el->add_attr("remote", manifest->get_default_location()->get_name());
     134           7 :     if (manifest->get_default_job_count() != 1) default_el->add_attr("sync-j", manifest->get_default_job_count());
     135             : 
     136          12 :     parent->add_element(default_el);
     137           4 : }
     138             : 
     139           4 : Result ManifestImpl::write_projects()
     140             : {
     141          12 :     for (auto &remote : self()->get_data()->get_locations())
     142             :     {
     143          29 :         for (auto &project : remote->get_repos())
     144             :         {
     145         100 :             Result result = write_project(m_xml_data, project);
     146          25 :             if (result.error()) return ESYSREPO_RESULT(result);
     147          25 :         }
     148             :     }
     149           4 :     return ESYSREPO_RESULT(ResultCode::OK);
     150             : }
     151             : 
     152          25 : Result ManifestImpl::write_project(std::shared_ptr<esysfile::xml::Element> parent,
     153             :                                    std::shared_ptr<manifest::Repository> repository)
     154             : {
     155          25 :     std::shared_ptr<esysfile::xml::Element> project_el;
     156             : 
     157          50 :     project_el = std::make_shared<esysfile::xml::Element>();
     158             : 
     159          25 :     project_el->set_name("project");
     160             : 
     161          25 :     if (repository->get_path().empty()) return ESYSREPO_RESULT(ResultCode::MANIFEST_REPOSITORY_WITHOUT_PATH);
     162          25 :     project_el->add_attr("path", repository->get_path());
     163             : 
     164          25 :     if (repository->get_location() == nullptr) return ESYSREPO_RESULT(ResultCode::MANIFEST_REPOSITORY_WITHOUT_LOCATION);
     165             : 
     166          25 :     bool add_location = true;
     167             : 
     168          75 :     if (self()->get_data()->get_default_location() != nullptr)
     169             :     {
     170          75 :         if (repository->get_location()->get_name() == self()->get_data()->get_default_location()->get_name())
     171             :             add_location = false;
     172             :     }
     173           0 :     if (add_location) project_el->add_attr("remote", repository->get_location()->get_name());
     174             : 
     175          25 :     if (repository->get_name().empty()) return ESYSREPO_RESULT(ResultCode::MANIFEST_REPOSITORY_WITHOUT_NAME);
     176          25 :     project_el->add_attr("name", repository->get_name());
     177             : 
     178          37 :     if (!repository->get_revision().empty()) project_el->add_attr("revision", repository->get_revision());
     179             : 
     180          25 :     auto &groups = repository->get_groups();
     181          25 :     if (groups.size() != 0)
     182             :     {
     183          15 :         std::string groups_str;
     184             : 
     185          33 :         for (auto group : groups)
     186             :         {
     187          18 :             if (groups_str.size() != 0) groups_str += ",";
     188             : 
     189          36 :             groups_str += group->get_name();
     190             :         }
     191             : 
     192          30 :         project_el->add_attr("groups", groups_str);
     193          15 :     }
     194             : 
     195          50 :     parent->add_element(project_el);
     196          25 :     return ESYSREPO_RESULT(ResultCode::OK);
     197          25 : }
     198             : 
     199          25 : Result ManifestImpl::read(std::shared_ptr<esysfile::xml::Data> data)
     200             : {
     201          25 :     std::shared_ptr<manifest::Location> location;
     202             : 
     203         282 :     for (auto element : data->get_elements())
     204             :     {
     205         514 :         Result result = read(element);
     206         257 :         if (result.error()) return ESYSREPO_RESULT(result);
     207         514 :     }
     208             : 
     209          25 :     for (auto it = m_repo_no_locations.begin(); it != m_repo_no_locations.end();)
     210             :     {
     211           0 :         location = self()->get_data()->find_location((*it)->get_name());
     212           0 :         if (location != nullptr)
     213             :         {
     214           0 :             location->add_repo(*it);
     215           0 :             m_repo_no_locations.erase(it);
     216             :         }
     217             :         else
     218           0 :             ++it;
     219             :     }
     220             : 
     221          25 :     if (m_repo_no_locations.size() != 0) return ESYSREPO_RESULT(ResultCode::MANIFEST_NO_LOCATIONS_DEFINED);
     222          25 :     return ESYSREPO_RESULT(ResultCode::OK);
     223          25 : }
     224             : 
     225         257 : Result ManifestImpl::read(std::shared_ptr<esysfile::xml::Element> el)
     226             : {
     227         257 :     Result result;
     228             : 
     229         257 :     if (el->get_name() == "remote")
     230          78 :         result = read_remote(el);
     231         231 :     else if (el->get_name() == "default")
     232          69 :         result = read_default(el);
     233         208 :     else if (el->get_name() == "project")
     234         600 :         result = read_project(el);
     235           8 :     else if (el->get_name() == "include")
     236           6 :         result = read_include(el);
     237           6 :     else if (el->get_name() != "#comment")
     238             :     {
     239           0 :         return ESYSREPO_RESULT(ResultCode::MANIFEST_ELEMENT_UNKNOWN, el->get_name());
     240             :     }
     241         514 :     return ESYSREPO_RESULT(result);
     242         257 : }
     243             : 
     244          26 : Result ManifestImpl::read_remote(std::shared_ptr<esysfile::xml::Element> el)
     245             : {
     246          26 :     auto location = std::make_shared<manifest::Location>();
     247             : 
     248          78 :     for (auto attr : el->get_attrs())
     249             :     {
     250          52 :         if (attr->get_name() == "name")
     251          26 :             location->set_name(attr->get_value());
     252          26 :         else if (attr->get_name() == "fetch")
     253          26 :             location->set_address(attr->get_value());
     254             :         else
     255             :         {
     256           0 :             return ESYSREPO_RESULT(ResultCode::MANIFEST_ATTRIBUTE_UNKNOWN, el->get_name() + ": " + attr->get_name());
     257             :         }
     258          52 :     }
     259             : 
     260          78 :     self()->get_data()->add_location(location);
     261             : 
     262          26 :     return ESYSREPO_RESULT(ResultCode::OK);
     263          26 : }
     264             : 
     265          23 : Result ManifestImpl::read_default(std::shared_ptr<esysfile::xml::Element> el)
     266             : {
     267          92 :     for (auto attr : el->get_attrs())
     268             :     {
     269          69 :         if (attr->get_name() == "revision")
     270          46 :             self()->get_data()->set_default_revision(attr->get_value());
     271          46 :         else if (attr->get_name() == "remote")
     272          46 :             self()->get_data()->set_default_location(attr->get_value());
     273          23 :         else if (attr->get_name() == "sync-j")
     274             :         {
     275          23 :             int value = 0;
     276          23 :             int result = attr->get_value(value);
     277          23 :             if (result < 0)
     278           0 :                 return ESYSREPO_RESULT(ResultCode::MANIFEST_INCORRECT_ATTRIBUTE_VALUE,
     279             :                                        el->get_name() + "." + attr->get_name());
     280          46 :             self()->get_data()->set_default_job_count(value);
     281             :         }
     282             :         else
     283             :         {
     284           0 :             return ESYSREPO_RESULT(ResultCode::MANIFEST_ATTRIBUTE_UNKNOWN, el->get_name() + ": " + attr->get_name());
     285             :         }
     286          69 :     }
     287          23 :     return ESYSREPO_RESULT(ResultCode::OK);
     288             : }
     289             : 
     290          75 : Result ManifestImpl::read_groups(std::shared_ptr<manifest::Repository> project, const std::string &groups_str)
     291             : {
     292          75 :     typedef boost::tokenizer<boost::char_separator<char>> tokenizer;
     293          75 :     boost::char_separator<char> sep(", ");
     294          75 :     tokenizer tokens(groups_str, sep);
     295             : 
     296         165 :     for (tokenizer::iterator it = tokens.begin(); it != tokens.end(); ++it)
     297             :     {
     298          90 :         auto group = self()->get_data()->get_groups().find_or_new_group_by_name(*it);
     299          90 :         project->get_groups().push_back(group.get());
     300         270 :         group->add_repo(project);
     301         165 :     }
     302          75 :     return ESYSREPO_RESULT(ResultCode::OK);
     303         150 : }
     304             : 
     305         200 : Result ManifestImpl::read_project(std::shared_ptr<esysfile::xml::Element> el)
     306             : {
     307         200 :     auto project = std::make_shared<manifest::Repository>();
     308         200 :     std::shared_ptr<manifest::Location> location;
     309             : 
     310         815 :     for (auto attr : el->get_attrs())
     311             :     {
     312         615 :         if (attr->get_name() == "name")
     313         200 :             project->set_name(attr->get_value());
     314         415 :         else if (attr->get_name() == "path")
     315         200 :             project->set_path(attr->get_value());
     316         215 :         else if (attr->get_name() == "revision")
     317          87 :             project->set_revision(attr->get_value());
     318         128 :         else if (attr->get_name() == "groups")
     319             :         {
     320         150 :             Result result = read_groups(project, attr->get_value());
     321             :             //! \TODO handle errors
     322          75 :         }
     323          53 :         else if (attr->get_name() == "remote")
     324             :         {
     325         106 :             location = self()->get_data()->find_location(attr->get_value());
     326          53 :             project->set_location(attr->get_value());
     327             : 
     328          53 :             if (location == nullptr) m_repo_no_locations.push_back(project);
     329             :         }
     330             :         else
     331             :         {
     332           0 :             return ESYSREPO_RESULT(ResultCode::MANIFEST_ATTRIBUTE_UNKNOWN, el->get_name() + ": " + attr->get_name());
     333             :         }
     334         615 :     }
     335             : 
     336         200 :     if (location == nullptr)
     337             :     {
     338             :         // It means that the default remote is to be used.
     339         441 :         if (self()->get_data()->get_default_location() != nullptr)
     340         735 :             self()->get_data()->get_default_location()->add_repo(project);
     341             :         else
     342           0 :             return ESYSREPO_RESULT(ResultCode::MANIFEST_NO_DEFAULT_LOCATION);
     343             :     }
     344             :     else
     345         159 :         location->add_repo(project);
     346             : 
     347         200 :     return ESYSREPO_RESULT(ResultCode::OK);
     348         400 : }
     349             : 
     350           2 : Result ManifestImpl::read_include(std::shared_ptr<esysfile::xml::Element> el)
     351             : {
     352           2 :     if (el->get_name() != "include") return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR);
     353             : 
     354           2 :     auto include = std::make_shared<manifest::Include>();
     355           2 :     std::string name;
     356           2 :     std::string value;
     357             : 
     358           4 :     for (auto attr : el->get_attrs())
     359             :     {
     360           2 :         name = attr->get_name();
     361           2 :         value = attr->get_value();
     362           2 :         if (name == "name")
     363             :         {
     364           2 :             if (boost::filesystem::exists(value))
     365             :             {
     366           0 :                 include->set_name(value);
     367             :             }
     368             :             else
     369             :             {
     370             :                 // Here we assume that the include is relative to the folder "manifests"
     371           2 :                 boost::filesystem::path full_path = self()->get_filename();
     372           2 :                 boost::filesystem::path rel_path = "manifests";
     373           4 :                 full_path = full_path.parent_path();
     374           2 :                 rel_path /= value;
     375           2 :                 full_path /= rel_path;
     376             : 
     377           2 :                 if (boost::filesystem::exists(full_path))
     378           2 :                     include->set_name(full_path.string());
     379             :                 else
     380             :                 {
     381             :                     // TBD: ERROR
     382             :                 }
     383           2 :             }
     384             :         }
     385           2 :     }
     386           6 :     self()->get_data()->add_include(include);
     387           2 :     return ESYSREPO_RESULT(ResultCode::OK);
     388           4 : }
     389             : 
     390         708 : Manifest *ManifestImpl::self() const
     391             : {
     392         708 :     return m_self;
     393             : }
     394             : 
     395             : } // namespace esys::repo::grepo

Generated by: LCOV version 1.14