LCOV - code coverage report
Current view: top level - src/esys/repo/exe - cmdmanifest.cpp (source / functions) Hit Total Coverage
Test: esysrepo_coverage.info Lines: 84 241 34.9 %
Date: 2026-11-07 22:18:26 Functions: 17 38 44.7 %

          Line data    Source code
       1             : /*!
       2             :  * \file esys/repo/exe/cmdmanifest.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/exe/cmdmanifest.h"
      20             : #include "esys/repo/manifest/file.h"
      21             : #include "esys/repo/grepo/manifest.h"
      22             : #include "esys/repo/manifest/directorymngr.h"
      23             : #include "esys/repo/manifest/repository.h"
      24             : #include "esys/repo/manifest/xmlfile.h"
      25             : #include "esys/repo/githelper.h"
      26             : #include "esys/repo/userfolder.h"
      27             : 
      28             : #include <esys/trace/call.h>
      29             : #include <esys/trace/macros.h>
      30             : 
      31             : #include <boost/filesystem.hpp>
      32             : 
      33             : #include <iostream>
      34             : #include <fstream>
      35             : #include <sstream>
      36             : 
      37             : namespace esys::repo::exe
      38             : {
      39             : 
      40          64 : CmdManifest::TaskDelDir::TaskDelDir() = default;
      41             : 
      42           0 : void CmdManifest::TaskDelDir::set_name(const std::string &name)
      43             : {
      44           0 :     m_name = name;
      45           0 : }
      46             : 
      47           0 : const std::string &CmdManifest::TaskDelDir::get_name() const
      48             : {
      49           0 :     return m_name;
      50             : }
      51             : 
      52          32 : CmdManifest::TaskAddDir::TaskAddDir() = default;
      53             : 
      54           0 : void CmdManifest::TaskAddDir::set_url_ssh(const std::string &url_ssh)
      55             : {
      56           0 :     m_url_ssh = url_ssh;
      57           0 : }
      58             : 
      59           0 : const std::string &CmdManifest::TaskAddDir::get_url_ssh() const
      60             : {
      61           0 :     return m_url_ssh;
      62             : }
      63             : 
      64           0 : void CmdManifest::TaskAddDir::set_url_https(const std::string &url_https)
      65             : {
      66           0 :     m_url_https = url_https;
      67           0 : }
      68             : 
      69           0 : const std::string &CmdManifest::TaskAddDir::get_url_https() const
      70             : {
      71           0 :     return m_url_https;
      72             : }
      73             : 
      74          32 : CmdManifest::CmdManifest()
      75          64 :     : Cmd("Manifest")
      76             : {
      77          32 : }
      78             : 
      79          32 : CmdManifest::~CmdManifest() = default;
      80             : 
      81           2 : void CmdManifest::set_task(Task task)
      82             : {
      83           2 :     m_task = task;
      84           2 : }
      85             : 
      86           4 : CmdManifest::Task CmdManifest::get_task() const
      87             : {
      88           4 :     return m_task;
      89             : }
      90             : 
      91           0 : void CmdManifest::set_task_add_dir(const TaskAddDir &task_add_dir)
      92             : {
      93           0 :     m_task_add_dir = task_add_dir;
      94           0 :     set_task(Task::ADD_DIR);
      95           0 : }
      96             : 
      97           0 : const CmdManifest::TaskAddDir &CmdManifest::get_task_add_dir() const
      98             : {
      99           0 :     return m_task_add_dir;
     100             : }
     101             : 
     102           0 : void CmdManifest::set_task_del_dir(const TaskDelDir &task_del_dir)
     103             : {
     104           0 :     m_task_del_dir = task_del_dir;
     105           0 :     set_task(Task::DEL_DIR);
     106           0 : }
     107             : 
     108           0 : const CmdManifest::TaskDelDir &CmdManifest::get_task_del_dir() const
     109             : {
     110           0 :     return m_task_del_dir;
     111             : }
     112             : 
     113           0 : void CmdManifest::set_dirs(const std::string &dirs)
     114             : {
     115           0 :     m_dirs = dirs;
     116           0 : }
     117             : 
     118           0 : const std::string &CmdManifest::get_dirs() const
     119             : {
     120           0 :     return m_dirs;
     121             : }
     122             : 
     123           2 : void CmdManifest::set_output_file(const std::string &output_file)
     124             : {
     125           2 :     m_output_file = output_file;
     126           2 : }
     127             : 
     128           5 : const std::string &CmdManifest::get_output_file() const
     129             : {
     130           5 :     return m_output_file;
     131             : }
     132             : 
     133           1 : void CmdManifest::set_merge_inputs(const std::vector<std::string> &paths)
     134             : {
     135           1 :     m_merge_inputs = paths;
     136           1 : }
     137             : 
     138           1 : const std::vector<std::string> &CmdManifest::get_merge_inputs() const
     139             : {
     140           1 :     return m_merge_inputs;
     141             : }
     142             : 
     143           1 : void CmdManifest::set_on_conflict(manifest::Merge::OnConflict on_conflict)
     144             : {
     145           1 :     m_on_conflict = on_conflict;
     146           1 : }
     147             : 
     148           1 : manifest::Merge::OnConflict CmdManifest::get_on_conflict() const
     149             : {
     150           1 :     return m_on_conflict;
     151             : }
     152             : 
     153           1 : void CmdManifest::set_merge_format(manifest::Merge::OutputFormat format)
     154             : {
     155           1 :     m_merge_format = format;
     156           1 : }
     157             : 
     158           0 : manifest::Merge::OutputFormat CmdManifest::get_merge_format() const
     159             : {
     160           0 :     return m_merge_format;
     161             : }
     162             : 
     163           0 : void CmdManifest::set_merge_parse_mode(manifest::ParseMode mode)
     164             : {
     165           0 :     m_merge_parse_mode = mode;
     166           0 : }
     167             : 
     168           0 : manifest::ParseMode CmdManifest::get_merge_parse_mode() const
     169             : {
     170           0 :     return m_merge_parse_mode;
     171             : }
     172             : 
     173           3 : Result CmdManifest::update_revision_as_head()
     174             : {
     175          11 :     for (auto location : get_manifest()->get_locations())
     176             :     {
     177          31 :         for (auto repo : location->get_repos())
     178             :         {
     179          52 :             Result result = update_revision_as_head(repo);
     180          26 :             if (result.error()) return ESYSREPO_RESULT(result);
     181          52 :         }
     182           5 :     }
     183           3 :     return ESYSREPO_RESULT(ResultCode::OK);
     184             : }
     185             : 
     186          26 : Result CmdManifest::update_revision_as_head(std::shared_ptr<manifest::Repository> repo)
     187             : {
     188          26 :     auto git_helper = new_git_helper();
     189             : 
     190          26 :     boost::filesystem::path repo_path = get_config_folder()->get_workspace_path();
     191          26 :     repo_path /= repo->get_path();
     192          78 :     repo_path = boost::filesystem::absolute(repo_path).lexically_normal().make_preferred();
     193             : 
     194          26 :     std::string revision = repo->get_revision();
     195          64 :     if (revision.empty()) revision = get_manifest()->get_default_revision();
     196             : 
     197          26 :     Result rresult = git_helper->open(repo_path.string(), log::Level::DEBUG);
     198          26 :     if (rresult.error()) return ESYSREPO_RESULT(rresult);
     199             : 
     200          26 :     rresult = git_helper->fetch(log::Level::DEBUG);
     201          26 :     if (rresult.error()) return ESYSREPO_RESULT(rresult);
     202             : 
     203          26 :     std::string hash;
     204          26 :     rresult = git_helper->get_hash(revision, hash, log::Level::DEBUG);
     205          26 :     if (rresult.error())
     206             :     {
     207           0 :         git_helper->close_on_error(log::Level::DEBUG);
     208           0 :         return ESYSREPO_RESULT(rresult);
     209             :     }
     210          26 :     repo->set_revision(hash);
     211             : 
     212          26 :     return git_helper->close(log::Level::DEBUG);
     213          52 : }
     214             : 
     215           3 : Result CmdManifest::do_revision_as_head()
     216             : {
     217           3 :     Result result = only_one_folder_or_workspace();
     218           3 :     if (result.error()) return ESYSREPO_RESULT(result);
     219             : 
     220           3 :     result = open_esysrepo_folder();
     221           3 :     if (result.error()) return ESYSREPO_RESULT(result);
     222             : 
     223           3 :     result = load_manifest();
     224           3 :     if (result.error()) return ESYSREPO_RESULT(result);
     225             : 
     226           3 :     result = update_revision_as_head();
     227           3 :     if (result.error())
     228             :     {
     229           0 :         std::string err_str = "Failed to get the revision as HEAD";
     230           0 :         error(err_str);
     231           0 :         return ESYSREPO_RESULT(result, err_str);
     232           0 :     }
     233             : 
     234           3 :     std::shared_ptr<std::ofstream> fos;
     235           3 :     std::ostream *os = nullptr;
     236             : 
     237           3 :     if (get_output_file().empty())
     238             :         os = &std::cout;
     239             :     else
     240             :     {
     241           1 :         fos = std::make_shared<std::ofstream>(get_output_file());
     242           1 :         os = fos.get();
     243             :     }
     244             : 
     245           3 :     std::shared_ptr<manifest::FileBase> file;
     246             : 
     247           6 :     switch (get_manifest()->get_type())
     248             :     {
     249           2 :         case manifest::Type::GOOGLE_MANIFEST: file = std::make_shared<grepo::Manifest>(); break;
     250           4 :         case manifest::Type::ESYSREPO_MANIFEST: file = std::make_shared<manifest::XMLFile>(); break;
     251           0 :         default: error("Manifest format not supported."); return generic_error(-1);
     252             :     }
     253             : 
     254           3 :     file->set_data(get_manifest());
     255           3 :     result = file->write(*os);
     256             : 
     257           3 :     if (fos != nullptr) fos->close();
     258           6 :     return ESYSREPO_RESULT(result);
     259           6 : }
     260             : 
     261           0 : Result CmdManifest::do_list_dirs()
     262             : {
     263           0 :     UserFolder user_folder;
     264             : 
     265           0 :     auto result = user_folder.read();
     266           0 :     if (result.error()) return ESYSREPO_RESULT(result);
     267             : 
     268           0 :     if (user_folder.get_user_config() == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR);
     269             : 
     270           0 :     auto mds = user_folder.get_user_config()->get_manifest_directories();
     271           0 :     if (mds == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR);
     272             : 
     273           0 :     std::ostringstream oss;
     274             : 
     275           0 :     for (auto idx = 0; idx < mds->get_items().size(); ++idx)
     276             :     {
     277           0 :         auto md = mds->get_items()[idx];
     278           0 :         oss.str("");
     279             : 
     280           0 :         oss << "[" << idx << "] " << md->get_name() << std::endl;
     281           0 :         oss << "    " << md->get_url_ssh() << std::endl;
     282           0 :         oss << "    " << md->get_url_https();
     283             : 
     284           0 :         info(oss.str());
     285           0 :     }
     286           0 :     return ESYSREPO_RESULT(ResultCode::OK);
     287           0 : }
     288             : 
     289           0 : Result CmdManifest::do_list_projects()
     290             : {
     291           0 :     UserFolder user_folder;
     292             : 
     293           0 :     auto result = user_folder.read();
     294           0 :     if (result.error()) return ESYSREPO_RESULT(result);
     295             : 
     296           0 :     if (user_folder.get_user_config() == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR);
     297             : 
     298           0 :     auto mds = user_folder.get_user_config()->get_manifest_directories();
     299           0 :     if (mds == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR);
     300             : 
     301           0 :     manifest::DirectoryMngr mngr;
     302             : 
     303           0 :     mngr.set_folder_path(user_folder.get_user_config()->get_manifest_directories_path());
     304           0 :     mngr.set_directories(mds);
     305             : 
     306           0 :     result = mngr.load();
     307           0 :     if (result.error()) return ESYSREPO_RESULT(result);
     308             : 
     309           0 :     std::ostringstream oss;
     310             : 
     311           0 :     for (auto idx = 0; idx < mds->get_items().size(); ++idx)
     312             :     {
     313           0 :         auto md = mds->get_items()[idx];
     314           0 :         oss.str("");
     315             : 
     316           0 :         oss << "[" << idx << "] " << md->get_name() << std::endl;
     317           0 :         oss << "    urls:" << std::endl;
     318           0 :         oss << "        " << md->get_url_ssh() << std::endl;
     319           0 :         oss << "        " << md->get_url_https();
     320             : 
     321           0 :         if (md->get_directory() == nullptr)
     322             :         {
     323           0 :             warn("Manifest directory has no projects.");
     324           0 :             continue;
     325             :         }
     326           0 :         oss << std::endl << "    projects:";
     327           0 :         for (auto dir : md->get_directory()->get_items())
     328             :         {
     329           0 :             oss << std::endl << "        " << dir->get_name();
     330             :             // oss << "            " << dir
     331           0 :         }
     332             : 
     333           0 :         info(oss.str());
     334           0 :     }
     335           0 :     return ESYSREPO_RESULT(ResultCode::OK);
     336           0 : }
     337             : 
     338           0 : Result CmdManifest::do_add_dir()
     339             : {
     340           0 :     UserFolder user_folder;
     341             : 
     342           0 :     auto result = user_folder.read();
     343           0 :     if (result.error()) return ESYSREPO_RESULT(result);
     344             : 
     345           0 :     if (user_folder.get_user_config() == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR);
     346             : 
     347           0 :     auto mds = user_folder.get_user_config()->get_manifest_directories();
     348           0 :     if (mds == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR);
     349             : 
     350           0 :     auto item = std::make_shared<manifest::Directories::Item>();
     351           0 :     item->set_name(get_task_add_dir().get_name());
     352           0 :     item->set_url_ssh(get_task_add_dir().get_url_ssh());
     353           0 :     item->set_url_https(get_task_add_dir().get_url_https());
     354             : 
     355           0 :     mds->add_item(item->get_name(), item);
     356             : 
     357           0 :     result = user_folder.write();
     358           0 :     if (result.error()) return ESYSREPO_RESULT(result);
     359             : 
     360           0 :     info("Added manifest directory '" + get_task_del_dir().get_name() + "'.");
     361           0 :     return ESYSREPO_RESULT(ResultCode::OK);
     362           0 : }
     363             : 
     364           0 : Result CmdManifest::do_del_dir()
     365             : {
     366           0 :     UserFolder user_folder;
     367             : 
     368           0 :     auto result = user_folder.read();
     369           0 :     if (result.error()) return ESYSREPO_RESULT(result);
     370             : 
     371           0 :     if (user_folder.get_user_config() == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR);
     372             : 
     373           0 :     auto mds = user_folder.get_user_config()->get_manifest_directories();
     374           0 :     if (mds == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR);
     375             : 
     376           0 :     result = mds->del_item(get_task_del_dir().get_name());
     377           0 :     if (result.error()) return ESYSREPO_RESULT(result);
     378             : 
     379           0 :     result = user_folder.write();
     380           0 :     if (result.error()) return ESYSREPO_RESULT(result);
     381             : 
     382           0 :     info("Deleted manifest directory '" + get_task_del_dir().get_name() + "'.");
     383           0 :     return ESYSREPO_RESULT(ResultCode::OK);
     384           0 : }
     385             : 
     386           0 : Result CmdManifest::do_merge()
     387             : {
     388           0 :     manifest::Merge merge;
     389           0 :     merge.set_inputs(get_merge_inputs());
     390           0 :     merge.set_output(get_output_file());
     391           0 :     merge.set_on_conflict(get_on_conflict());
     392           0 :     merge.set_output_format(get_merge_format());
     393           0 :     merge.set_parse_mode(get_merge_parse_mode());
     394             : 
     395           0 :     Result result = merge.run();
     396           0 :     if (result.error())
     397             :     {
     398           0 :         std::ostringstream oss;
     399           0 :         oss << result;
     400           0 :         error(oss.str());
     401           0 :         return ESYSREPO_RESULT(result);
     402           0 :     }
     403             : 
     404           0 :     if (!get_output_file().empty())
     405             :     {
     406           0 :         info("Wrote merged manifest to '" + merge.get_resolved_output() + "'.");
     407           0 :         return ESYSREPO_RESULT(ResultCode::OK);
     408             :     }
     409             : 
     410           0 :     if (merge.get_result() == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR);
     411             : 
     412           0 :     std::shared_ptr<manifest::FileBase> file;
     413           0 :     if (get_merge_format() == manifest::Merge::OutputFormat::Google)
     414           0 :         file = std::make_shared<grepo::Manifest>();
     415             :     else
     416           0 :         file = std::make_shared<manifest::XMLFile>();
     417           0 :     file->set_data(merge.get_result());
     418           0 :     return file->write(std::cout);
     419           0 : }
     420             : 
     421           3 : Result CmdManifest::impl_run()
     422             : {
     423           3 :     Result result;
     424           3 :     ETRC_CALL_RET_NP(result);
     425             : 
     426           3 :     switch (get_task())
     427             :     {
     428           3 :         case Task::REVISION_AS_HEAD:
     429           6 :         case Task::NOT_SET: return ETRC_RET(do_revision_as_head());
     430           0 :         case Task::LIST_DIRS: return ETRC_RET(do_list_dirs());
     431           0 :         case Task::LIST_PROJECTS: return ETRC_RET(do_list_projects());
     432           0 :         case Task::ADD_DIR: return ETRC_RET(do_add_dir());
     433           0 :         case Task::DEL_DIR: return ETRC_RET(do_del_dir());
     434           0 :         case Task::MERGE: return ETRC_RET(do_merge());
     435           0 :         default: return ETRC_RET(ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR));
     436             :     }
     437             :     return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     438           3 : }
     439             : 
     440             : } // namespace esys::repo::exe

Generated by: LCOV version 1.14