LCOV - code coverage report
Current view: top level - src/esys/repo/exe - cmdinit.cpp (source / functions) Hit Total Coverage
Test: esysrepo_coverage.info Lines: 408 608 67.1 %
Date: 2026-09-26 15:38:18 Functions: 43 48 89.6 %

          Line data    Source code
       1             : /*!
       2             :  * \file esys/repo/exe/cmdinit.cpp
       3             :  * \brief
       4             :  *
       5             :  * \cond
       6             :  * __legal_b__
       7             :  *
       8             :  * Copyright (c) 2020-2023 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/cmdinit.h"
      20             : #include "esys/repo/filesystem.h"
      21             : #include "esys/repo/git/url.h"
      22             : #include "esys/repo/manifest/base.h"
      23             : #include "esys/repo/manifest/file.h"
      24             : #include "esys/repo/manifest/xmlfile.h"
      25             : #include "esys/repo/grepo/manifest.h"
      26             : #include "esys/repo/manifest/directorymngr.h"
      27             : 
      28             : #include <esys/trace/call.h>
      29             : #include <esys/trace/macros.h>
      30             : 
      31             : #include <boost/filesystem.hpp>
      32             : #include <boost/system/error_code.hpp>
      33             : 
      34             : #include <cassert>
      35             : #include <iostream>
      36             : #include <sstream>
      37             : 
      38             : namespace esys::repo::exe
      39             : {
      40             : 
      41          50 : CmdInit::CmdInit()
      42         100 :     : Cmd("Init")
      43             : {
      44          50 : }
      45             : 
      46          51 : CmdInit::~CmdInit() = default;
      47             : 
      48          52 : void CmdInit::set_url(const std::string &url)
      49             : {
      50          52 :     m_url = url;
      51          52 : }
      52             : 
      53         110 : const std::string &CmdInit::get_url() const
      54             : {
      55         110 :     return m_url;
      56             : }
      57             : 
      58          18 : void CmdInit::set_branch(const std::string &branch)
      59             : {
      60          18 :     m_branch = branch;
      61          18 : }
      62             : 
      63          34 : const std::string &CmdInit::get_branch() const
      64             : {
      65          34 :     return m_branch;
      66             : }
      67             : 
      68          16 : void CmdInit::set_rev_set(const std::string &rev_set)
      69             : {
      70          16 :     m_rev_set = rev_set;
      71          16 : }
      72             : 
      73          13 : const std::string &CmdInit::get_rev_set() const
      74             : {
      75          13 :     return m_rev_set;
      76             : }
      77             : 
      78          18 : void CmdInit::set_prefer_branch(const std::string &prefer_branch)
      79             : {
      80          18 :     m_prefer_branch = prefer_branch;
      81          18 : }
      82             : 
      83          43 : const std::string &CmdInit::get_prefer_branch() const
      84             : {
      85          43 :     return m_prefer_branch;
      86             : }
      87             : 
      88          15 : void CmdInit::set_manifest_name(const std::string &manifest_name)
      89             : {
      90          15 :     m_manifest_name = manifest_name;
      91          15 : }
      92             : 
      93          35 : const std::string &CmdInit::get_manifest_name() const
      94             : {
      95          35 :     return m_manifest_name;
      96             : }
      97             : 
      98          16 : void CmdInit::set_project_name(const std::string &project_name)
      99             : {
     100          16 :     m_project_name = project_name;
     101          16 : }
     102             : 
     103           3 : const std::string &CmdInit::get_project_name() const
     104             : {
     105           3 :     return m_project_name;
     106             : }
     107             : 
     108          20 : void CmdInit::set_manifest_local(const std::string &manifest_local)
     109             : {
     110          20 :     m_manifest_local = manifest_local;
     111          20 : }
     112             : 
     113          38 : const std::string &CmdInit::get_manifest_local() const
     114             : {
     115          38 :     return m_manifest_local;
     116             : }
     117             : 
     118          17 : void CmdInit::set_google_manifest(bool google_manifest)
     119             : {
     120          17 :     m_google_manifest = google_manifest;
     121          17 :     m_manifest_type = manifest::Type::GOOGLE_MANIFEST;
     122          17 : }
     123             : 
     124          33 : bool CmdInit::get_google_manifest() const
     125             : {
     126          33 :     return m_google_manifest;
     127             : }
     128             : 
     129          15 : void CmdInit::set_git_super_project(bool git_super_project)
     130             : {
     131          15 :     m_git_super_project = git_super_project;
     132          15 :     m_manifest_type = manifest::Type::GOOGLE_MANIFEST;
     133          15 : }
     134             : 
     135          56 : bool CmdInit::get_git_super_project() const
     136             : {
     137          56 :     return m_git_super_project;
     138             : }
     139             : 
     140          16 : void CmdInit::set_parse_mode(manifest::ParseMode mode)
     141             : {
     142          16 :     m_parse_mode = mode;
     143          16 : }
     144             : 
     145          42 : manifest::ParseMode CmdInit::get_parse_mode() const
     146             : {
     147          42 :     return m_parse_mode;
     148             : }
     149             : 
     150           0 : std::string CmdInit::get_extra_start_msg()
     151             : {
     152           0 :     if (!get_manifest_local().empty()) return "\n    local : " + get_manifest_local();
     153           0 :     return "\n    url : " + get_url();
     154             : }
     155             : 
     156          30 : Result CmdInit::impl_run()
     157             : {
     158          30 :     Result result;
     159          30 :     ETRC_CALL_RET_NP(result);
     160             : 
     161          30 :     if (get_git_super_project()) warn("The option --git-super is not implemented yet");
     162             : 
     163          30 :     result = only_one_folder_or_workspace();
     164          30 :     if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     165             : 
     166          30 :     result = load_esysrepo_folder();
     167          30 :     if (result.ok())
     168             :     {
     169           1 :         if (get_url().empty() && !get_project_name().empty())
     170             :         {
     171           0 :             info("Finding URL for project " + get_project_name() + " ...");
     172           0 :             result = find_url_from_project_name();
     173           0 :             if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     174           0 :             if (!get_url().empty()) info("Found URL : '" + get_url() + "'.");
     175             :         }
     176           2 :         return ETRC_RET(load_esysrepo_folder_succeeded());
     177             :     }
     178          58 :     return ETRC_RET(load_esysrepo_folder_failed());
     179          30 : }
     180             : 
     181           1 : Result CmdInit::load_esysrepo_folder_succeeded()
     182             : {
     183           1 :     Result result;
     184           1 :     ETRC_CALL_RET_NP(result);
     185             : 
     186           1 :     assert(get_config_folder() != nullptr);
     187           2 :     if (get_config_folder() == nullptr)
     188             :     {
     189           0 :         error("Internal error [CmdInit::load_esysrepo_folder_succeeded] get_config_folder() == nullptr");
     190           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR));
     191             :     }
     192             : 
     193           1 :     auto config = get_config_folder()->get_config();
     194           1 :     assert(config != nullptr);
     195           1 :     if (config == nullptr)
     196             :     {
     197           0 :         error("Internal error [CmdInit::load_esysrepo_folder_succeeded] config == nullptr");
     198           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR));
     199             :     }
     200             : 
     201           1 :     if (!get_manifest_local().empty())
     202             :     {
     203           0 :         boost::filesystem::path local_abs = boost::filesystem::absolute(get_manifest_local()).lexically_normal();
     204           0 :         boost::filesystem::path ws = boost::filesystem::absolute(get_workspace_path()).lexically_normal();
     205           0 :         std::string want = boost::filesystem::relative(local_abs, ws).generic_string();
     206           0 :         if (want.empty()) want = ".";
     207           0 :         if (want != config->get_manifest_local())
     208             :         {
     209           0 :             std::stringstream oss;
     210           0 :             oss << "Current manifest local is:" << std::endl;
     211           0 :             oss << "    '" << config->get_manifest_local() << "'" << std::endl;
     212           0 :             oss << "But --manifest-local given is different:" << std::endl;
     213           0 :             oss << "    '" << want << "'" << std::endl;
     214           0 :             oss << "Use --force if this is really wanted.";
     215           0 :             error(oss.str());
     216           0 :             return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_INCORRECT_PARAMETERS_IN_CONTEXT, oss.str()));
     217           0 :         }
     218           0 :         warn("Nothing to do: workspace already initialized from this local manifest.");
     219           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     220           0 :     }
     221             : 
     222           1 :     git::URL url(get_url());
     223           1 :     if (url != config->get_manifest_url())
     224             :     {
     225           0 :         std::stringstream oss;
     226             : 
     227           0 :         oss << "Current manifest url is:" << std::endl;
     228           0 :         oss << "    '" << config->get_manifest_url() << "'" << std::endl;
     229           0 :         oss << "But manifest url given is different:" << std::endl;
     230           0 :         oss << "    '" << get_url() << "'" << std::endl;
     231           0 :         oss << "Use --force if this is really wanted.";
     232           0 :         error(oss.str());
     233           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_INCORRECT_PARAMETERS_IN_CONTEXT, oss.str()));
     234           0 :     }
     235             : 
     236           1 :     if (get_branch().empty())
     237             :     {
     238           1 :         warn("Nothing to do as a branch is not provided");
     239           2 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     240             :     }
     241             : 
     242           0 :     boost::filesystem::path manifest_git_path = get_config_folder()->get_manifest_repo_path();
     243             : 
     244           0 :     auto git_helper = new_git_helper();
     245             : 
     246           0 :     debug(1, "Test debug, before git_helper");
     247           0 :     git_helper->debug(1, "Test debug with git_helper");
     248             : 
     249           0 :     result = git_helper->open(manifest_git_path.lexically_normal().make_preferred().string(), log::DEBUG);
     250           0 :     if (result.error())
     251             :     {
     252           0 :         std::string err_str = "Opening git repo holding the manifest failed.";
     253           0 :         error(err_str);
     254           0 :         return ETRC_RET(ESYSREPO_RESULT(result, err_str));
     255           0 :     }
     256             : 
     257           0 :     result = get_git()->checkout(get_branch() /*, get_force()*/);
     258           0 :     if (result.error())
     259             :     {
     260           0 :         std::string err_str = "Checkout branch failed.";
     261           0 :         error(err_str);
     262           0 :         return ETRC_RET(ESYSREPO_RESULT(result, err_str));
     263           0 :     }
     264             : 
     265           0 :     result = get_git()->close();
     266             : 
     267           0 :     return ETRC_RET(ESYSREPO_RESULT(result));
     268           2 : }
     269             : 
     270          29 : Result CmdInit::load_esysrepo_folder_failed()
     271             : {
     272          29 :     Result result;
     273          29 :     ETRC_CALL_RET_NP(result);
     274             : 
     275             :     // Since it failed, either there is no .esysrepo folder or the xml config
     276             :     // file is corrupted
     277          29 :     result = create_esysrepo_folder();
     278          29 :     if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     279             : 
     280             :     // Now there are 2 cases, we couldn't load be the ESysRepo config folder because
     281             :     // it got corrupted, or it's not there at all.
     282          29 :     result = fetch_manifest();
     283          30 :     if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     284             : 
     285          28 :     return ETRC_RET(Result::OK);
     286          29 : }
     287             : 
     288          29 : Result CmdInit::fetch_manifest()
     289             : {
     290          29 :     Result result;
     291          29 :     ETRC_CALL_RET_NP(result);
     292             : 
     293          33 :     if (!get_manifest_local().empty()) return ETRC_RET(fetch_local_manifest());
     294             : 
     295          25 :     if (get_google_manifest())
     296           4 :         return ETRC_RET(fetch_google_manifest());
     297          23 :     else if (get_git_super_project())
     298           0 :         return ETRC_RET(fetch_git_super_project());
     299             : 
     300             :     // Here we can't be sure, either it's a google manifest, a esysrepo manifest or a git super project
     301          46 :     return ETRC_RET(fetch_unknown_manifest());
     302          29 : }
     303             : 
     304          32 : std::string CmdInit::get_google_manifest_filename() const
     305             : {
     306          32 :     if (!get_manifest_name().empty()) return get_manifest_name();
     307          32 :     return "default.xml";
     308             : }
     309             : 
     310          25 : Result CmdInit::clone_manifest_repo(GitHelper &git_helper, std::string &git_repo_path)
     311             : {
     312          25 :     Result result;
     313          25 :     ETRC_CALL_RET_NP(result);
     314             : 
     315          50 :     if (get_git() == nullptr) return ETRC_RET(ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR));
     316             : 
     317          25 :     if (get_url().empty() && !get_project_name().empty())
     318             :     {
     319           2 :         info("Finding URL for project " + get_project_name() + " ...");
     320           1 :         result = find_url_from_project_name();
     321           1 :         if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     322           2 :         if (!get_url().empty()) info("Found URL : '" + get_url() + "'.");
     323             :     }
     324             : 
     325          25 :     if (get_url().empty())
     326             :     {
     327           0 :         error("URL is empty");
     328           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMDINIT_NO_URL));
     329             :     }
     330             : 
     331          25 :     boost::filesystem::path path = get_config_folder()->get_temp_path();
     332          25 :     path /= "unknown_manifest";
     333          50 :     git_repo_path = path.lexically_normal().make_preferred().string();
     334             : 
     335          25 :     debug(1, "Test debug, before git_helper");
     336          25 :     git_helper.debug(1, "Test debug with git_helper");
     337             : 
     338          25 :     result = git_helper.clone(get_url(), git_repo_path, false, log::DEBUG);
     339          25 :     if (result.error())
     340             :     {
     341           0 :         error("Cloning failed.");
     342           0 :         return ETRC_RET(ESYSREPO_RESULT(result));
     343             :     }
     344             : 
     345          25 :     if (!get_branch().empty())
     346             :     {
     347           2 :         result = get_git()->checkout(get_branch() /*, get_force()*/);
     348           2 :         if (result.error())
     349             :         {
     350           0 :             std::string err_str = "Cloning failed : checkout branch failed.";
     351           0 :             error(err_str);
     352           0 :             return ETRC_RET(ESYSREPO_RESULT(result, err_str));
     353           0 :         }
     354             :     }
     355             : 
     356          25 :     result = git_helper.close(log::DEBUG);
     357          25 :     if (result.error())
     358             :     {
     359           0 :         std::string err_str = "Cloning failed : can't clod the git repo.";
     360           0 :         error(err_str);
     361           0 :         return ETRC_RET(ESYSREPO_RESULT(result, err_str));
     362           0 :     }
     363             : 
     364          50 :     return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     365          25 : }
     366             : 
     367          16 : Result CmdInit::install_google_manifest(GitHelper &git_helper, const std::string &git_repo_path)
     368             : {
     369          16 :     Result result;
     370          16 :     ETRC_CALL_RET(result, git_repo_path);
     371             : 
     372          16 :     auto config = get_config_folder()->get_or_new_config();
     373          16 :     config->set_manifest_type(manifest::Type::GOOGLE_MANIFEST);
     374          16 :     config->set_manifest_format(manifest::Format::XML);
     375          16 :     config->set_manifest_url(get_url());
     376          16 :     config->set_parse_mode(get_parse_mode());
     377          16 :     if (!get_prefer_branch().empty()) config->set_prefer_branch(get_prefer_branch());
     378             : 
     379          16 :     boost::filesystem::path source = git_repo_path;
     380          32 :     boost::filesystem::path rel_source = boost::filesystem::relative(source);
     381          16 :     boost::filesystem::path target = get_config_folder()->get_path();
     382          32 :     boost::filesystem::path rel_target = boost::filesystem::relative(target);
     383          16 :     target /= grepo::Manifest::get_folder_name();
     384          32 :     rel_target = boost::filesystem::relative(target);
     385             : 
     386          16 :     bool result_bool = boost::filesystem::create_directory(target);
     387          16 :     if (!result_bool)
     388             :     {
     389           0 :         std::string err_str = "Couldn't create the folder : " + rel_target.string();
     390           0 :         error(err_str);
     391           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::FOLDER_CREATION_ERROR, err_str));
     392           0 :     }
     393          16 :     debug(0, "Created folder : " + rel_target.string());
     394             : 
     395          16 :     result = git_helper.move(source.string(), target.string(), true, log::Level::DEBUG);
     396          16 :     if (result == ResultCode::FAILED_TO_COPY) return ETRC_RET(ESYSREPO_RESULT(result));
     397          16 :     if (result == ResultCode::FAILED_TO_REMOVE_ALL)
     398           0 :         warn("While moving folder " + rel_source.string() + " some files were left behind.");
     399             : 
     400          16 :     std::string manifest_path = "grepo/" + get_google_manifest_filename();
     401          32 :     get_config_folder()->get_config()->set_manifest_path(manifest_path);
     402          48 :     return ETRC_RET(get_config_folder()->write_config_file());
     403          32 : }
     404             : 
     405           2 : Result CmdInit::fetch_google_manifest()
     406             : {
     407           2 :     Result result;
     408           2 :     ETRC_CALL_RET_NP(result);
     409             : 
     410           2 :     info("Using Google repo tool manifest (--google).");
     411             : 
     412           2 :     auto git_helper = new_git_helper();
     413           2 :     std::string git_repo_path;
     414             : 
     415           2 :     result = clone_manifest_repo(*git_helper, git_repo_path);
     416           2 :     if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     417             : 
     418           2 :     boost::filesystem::path file_path = git_repo_path;
     419           4 :     file_path /= get_google_manifest_filename();
     420             : 
     421           2 :     if (!boost::filesystem::exists(file_path))
     422             :     {
     423           0 :         std::string err_str = "Google repo manifest file not found: " + get_google_manifest_filename();
     424           0 :         error(err_str);
     425           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::FILE_NOT_EXISTING, err_str));
     426           0 :     }
     427             : 
     428           2 :     result = install_google_manifest(*git_helper, git_repo_path);
     429           4 :     return ETRC_RET(ESYSREPO_RESULT(result));
     430           4 : }
     431             : 
     432           0 : Result CmdInit::read_esysrepo_manifest(std::shared_ptr<Manifest> manifest, const std::string &filename)
     433             : {
     434           0 :     Result result;
     435           0 :     ETRC_CALL_RET_NP(result);
     436             : 
     437           0 :     manifest::File manifest_file;
     438             : 
     439           0 :     manifest_file.set_data(manifest);
     440           0 :     manifest_file.set_parse_mode(get_parse_mode());
     441           0 :     result = manifest_file.read(filename);
     442           0 :     return ETRC_RET(ESYSREPO_RESULT(result));
     443           0 : }
     444             : 
     445          12 : Result CmdInit::read_esysrepo_manifest_xml(std::shared_ptr<Manifest> manifest, const std::string &filename)
     446             : {
     447          12 :     Result result;
     448          12 :     ETRC_CALL_RET_NP(result);
     449             : 
     450          12 :     manifest::XMLFile manifest_file;
     451             : 
     452          24 :     manifest_file.set_data(manifest);
     453          12 :     manifest_file.set_parse_mode(get_parse_mode());
     454          12 :     result = manifest_file.read(filename);
     455          36 :     return ETRC_RET(ESYSREPO_RESULT(result));
     456          12 : }
     457             : 
     458           0 : Result CmdInit::read_esysrepo_manifest_json(std::shared_ptr<Manifest> manifest, const std::string &filename)
     459             : {
     460             :     //! \TODO
     461           0 :     return ESYSREPO_RESULT(ResultCode::NOT_IMPLEMENTED);
     462             : }
     463             : 
     464           9 : Result CmdInit::fetch_esysrepo_manifest(GitHelper &git_helper, const std::string &git_repo_path,
     465             :                                         const std::string &manifest_filename)
     466             : {
     467           9 :     Result result;
     468           9 :     ETRC_CALL_RET(result, git_repo_path, manifest_filename);
     469             : 
     470           9 :     std::string manifest_path;
     471           9 :     boost::filesystem::path manifest_filename_path = manifest_filename;
     472           9 :     std::string manifest_filename_ext = manifest_filename_path.extension().string();
     473             : 
     474           9 :     info("ESysRepo manifest detected.");
     475           9 :     debug(0, "Manifest filename : " + manifest_filename);
     476             : 
     477           9 :     auto config_file = get_config_folder()->get_or_new_config();
     478             : 
     479           9 :     config_file->set_manifest_type(manifest::Type::ESYSREPO_MANIFEST);
     480           9 :     config_file->set_manifest_url(get_url());
     481           9 :     config_file->set_parse_mode(get_parse_mode());
     482           9 :     if (!get_prefer_branch().empty()) config_file->set_prefer_branch(get_prefer_branch());
     483             : 
     484           9 :     boost::filesystem::path source = git_repo_path;
     485          18 :     boost::filesystem::path rel_source = boost::filesystem::relative(source);
     486           9 :     boost::filesystem::path target;
     487           9 :     boost::filesystem::path file_path = git_repo_path;
     488           9 :     file_path /= manifest_filename;
     489             : 
     490           9 :     std::shared_ptr<Manifest> manifest = std::make_shared<Manifest>();
     491             : 
     492           9 :     if (manifest_filename_ext == ".manifest")
     493             :     {
     494           0 :         result = read_esysrepo_manifest(manifest, file_path.string());
     495           0 :         if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     496             :     }
     497           9 :     else if (manifest_filename_ext == ".xml")
     498             :     {
     499          18 :         result = read_esysrepo_manifest_xml(manifest, file_path.string());
     500           9 :         if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     501           9 :         manifest->set_format(manifest::Format::XML);
     502           9 :         config_file->set_manifest_format(manifest::Format::XML);
     503             :     }
     504           0 :     else if (manifest_filename_ext == ".json")
     505             :     {
     506           0 :         result = read_esysrepo_manifest_json(manifest, file_path.string());
     507           0 :         if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     508           0 :         manifest->set_format(manifest::Format::JSON);
     509           0 :         config_file->set_manifest_format(manifest::Format::JSON);
     510             :     }
     511             :     else
     512             :     {
     513           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::MANIFEST_FILE_EXT_UNKNOWN, manifest_filename_ext));
     514             :     }
     515             : 
     516           9 :     config_file->set_manifest_format(manifest->get_format());
     517             : 
     518           9 :     if (manifest->get_kind() == manifest::Kind::NOT_SET) manifest->set_kind(manifest::Kind::ISOLATED);
     519             : 
     520           9 :     if (manifest->get_kind() == manifest::Kind::EMBEDDED)
     521             :     {
     522           1 :         info("Embedded kind.");
     523           1 :         config_file->set_manifest_kind(manifest::Kind::EMBEDDED);
     524           2 :         target = get_config_folder()->get_workspace_path();
     525           1 :         result = git_helper.move(source.string(), target.string(), true, log::Level::DEBUG);
     526           1 :         if (result == ResultCode::FAILED_TO_COPY) return ETRC_RET(ESYSREPO_RESULT(result));
     527           1 :         if (result == ResultCode::FAILED_TO_REMOVE_ALL)
     528           0 :             warn("While moving folder " + rel_source.string() + " some files were left behind.");
     529           1 :         target = "..";
     530           1 :         target /= manifest_filename;
     531           1 :         manifest_path = target.string();
     532             :     }
     533           8 :     else if (manifest->get_kind() == manifest::Kind::ISOLATED)
     534             :     {
     535           8 :         info("Isolated kind.");
     536           8 :         config_file->set_manifest_kind(manifest::Kind::ISOLATED);
     537          16 :         target = get_config_folder()->get_path();
     538             : 
     539           8 :         target /= manifest::Base::get_folder_name();
     540           8 :         boost::filesystem::path rel_target;
     541          16 :         rel_target = boost::filesystem::relative(target);
     542             : 
     543           8 :         bool result_bool = boost::filesystem::create_directory(target);
     544           8 :         if (!result_bool)
     545             :         {
     546           0 :             error("Couldn't create the folder : " + rel_target.string());
     547           0 :             return ETRC_RET(ESYSREPO_RESULT(ResultCode::FOLDER_CREATION_ERROR, target.string()));
     548             :         }
     549             :         else
     550           8 :             debug(0, "Created folder : " + rel_target.string());
     551             : 
     552           8 :         result = git_helper.move(source.string(), target.string(), true, log::Level::DEBUG);
     553           8 :         if (result == ResultCode::FAILED_TO_COPY) return ETRC_RET(ESYSREPO_RESULT(result));
     554           8 :         if (result == ResultCode::FAILED_TO_REMOVE_ALL)
     555           0 :             warn("While moving folder " + rel_source.string() + " some files were left behind.");
     556           8 :         target = manifest::Base::get_folder_name();
     557           8 :         target /= manifest_filename;
     558          24 :         manifest_path = target.generic_path().string();
     559           8 :     }
     560             :     else
     561           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::MANIFEST_KIND_UNKNOWN));
     562             : 
     563           9 :     config_file->set_manifest_path(manifest_path);
     564             : 
     565           9 :     if (!get_rev_set().empty())
     566             :     {
     567           0 :         result = manifest->select_revision_set(get_rev_set());
     568           0 :         if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     569           0 :         config_file->set_revision_set(get_rev_set());
     570             :     }
     571           9 :     if (!get_prefer_branch().empty()) config_file->set_prefer_branch(get_prefer_branch());
     572             : 
     573           9 :     result = get_config_folder()->write_config_file();
     574          18 :     return ETRC_RET(ESYSREPO_RESULT(result));
     575          18 : }
     576             : 
     577           0 : Result CmdInit::fetch_git_super_project()
     578             : {
     579           0 :     return ESYSREPO_RESULT(ResultCode::NOT_IMPLEMENTED);
     580             : }
     581             : 
     582             : namespace
     583             : {
     584             : 
     585          13 : boost::filesystem::path abs_norm(const boost::filesystem::path &path)
     586             : {
     587          13 :     return boost::filesystem::absolute(path).lexically_normal();
     588             : }
     589             : 
     590           3 : bool paths_same(const boost::filesystem::path &left, const boost::filesystem::path &right)
     591             : {
     592           3 :     boost::system::error_code ec;
     593           3 :     if (boost::filesystem::exists(left) && boost::filesystem::exists(right))
     594             :     {
     595           3 :         bool same = boost::filesystem::equivalent(left, right, ec);
     596           3 :         if (!ec) return same;
     597             :     }
     598           0 :     return abs_norm(left) == abs_norm(right);
     599             : }
     600             : 
     601           3 : std::string rel_generic(const boost::filesystem::path &from_dir, const boost::filesystem::path &target,
     602             :                         const std::string &fallback)
     603             : {
     604           3 :     boost::system::error_code ec;
     605           6 :     auto rel = boost::filesystem::relative(abs_norm(target), abs_norm(from_dir), ec);
     606           3 :     if (ec) return fallback.empty() ? "." : fallback;
     607           3 :     std::string text = rel.generic_string();
     608           3 :     if (text.empty()) return ".";
     609           6 :     return text;
     610           3 : }
     611             : 
     612           2 : bool is_native_manifest_filename(const boost::filesystem::path &file)
     613             : {
     614           2 :     const std::string name = file.filename().string();
     615           4 :     return name == ".esysrepo.manifest" || name == ".esysrepo.manifest.xml" || name == ".esysrepo.manifest.json";
     616           2 : }
     617             : 
     618             : } // namespace
     619             : 
     620           4 : Result CmdInit::fetch_local_manifest()
     621             : {
     622           4 :     Result result;
     623           4 :     ETRC_CALL_RET_NP(result);
     624             : 
     625           4 :     if (!get_branch().empty())
     626             :     {
     627           0 :         std::string err_str = "--manifest-branch / -b cannot be combined with --manifest-local / -l";
     628           0 :         error(err_str);
     629           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_INCORRECT_PARAMETERS_COMBINATION, err_str));
     630           0 :     }
     631             : 
     632           4 :     boost::filesystem::path local_path = abs_norm(get_manifest_local());
     633           4 :     if (!boost::filesystem::exists(local_path))
     634             :     {
     635           1 :         std::string err_str = "Local manifest path does not exist: " + local_path.string();
     636           1 :         error(err_str);
     637           2 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::PATH_NOT_EXISTING, err_str));
     638           1 :     }
     639             : 
     640           3 :     const bool is_file = boost::filesystem::is_regular_file(local_path);
     641           3 :     const bool is_dir = boost::filesystem::is_directory(local_path);
     642           3 :     if (!is_file && !is_dir)
     643             :     {
     644           0 :         std::string err_str = "Local manifest path is not a file or directory: " + local_path.string();
     645           0 :         error(err_str);
     646           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::PATH_NOT_EXISTING, err_str));
     647           0 :     }
     648             : 
     649           3 :     if (is_file && !get_manifest_name().empty())
     650             :     {
     651           0 :         std::string err_str = "--manifest-name / -m cannot be combined with --manifest-local pointing at a file";
     652           0 :         error(err_str);
     653           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_INCORRECT_PARAMETERS_COMBINATION, err_str));
     654           0 :     }
     655             : 
     656           3 :     boost::filesystem::path source_file;
     657           3 :     bool google_manifest = get_google_manifest();
     658           3 :     bool git_super = false;
     659             : 
     660           3 :     if (is_file)
     661             :     {
     662           2 :         source_file = local_path;
     663           2 :         if (!google_manifest) google_manifest = !is_native_manifest_filename(source_file) && source_file.extension() == ".xml";
     664             :     }
     665             :     else
     666             :     {
     667           1 :         if (get_google_manifest() || !get_manifest_name().empty())
     668             :         {
     669           0 :             source_file = local_path / (get_manifest_name().empty() ? get_google_manifest_filename() : get_manifest_name());
     670           0 :             if (!boost::filesystem::exists(source_file))
     671             :             {
     672           0 :                 std::string err_str = "Manifest file not found in folder: " + source_file.string();
     673           0 :                 error(err_str);
     674           0 :                 return ETRC_RET(ESYSREPO_RESULT(ResultCode::FILE_NOT_EXISTING, err_str));
     675           0 :             }
     676           0 :             google_manifest = get_google_manifest() || !is_native_manifest_filename(source_file);
     677             :         }
     678             :         else
     679             :         {
     680           1 :             const char *native_names[] = {".esysrepo.manifest", ".esysrepo.manifest.xml", ".esysrepo.manifest.json"};
     681           2 :             for (const char *name : native_names)
     682             :             {
     683           4 :                 boost::filesystem::path candidate = local_path / name;
     684           2 :                 if (boost::filesystem::exists(candidate))
     685             :                 {
     686           1 :                     source_file = candidate;
     687           1 :                     google_manifest = false;
     688           1 :                     break;
     689             :                 }
     690           2 :             }
     691           1 :             if (source_file.empty())
     692             :             {
     693           0 :                 boost::filesystem::path candidate = local_path / get_google_manifest_filename();
     694           0 :                 if (boost::filesystem::exists(candidate))
     695             :                 {
     696           0 :                     source_file = candidate;
     697             :                     google_manifest = true;
     698             :                 }
     699           0 :             }
     700           1 :             if (source_file.empty())
     701             :             {
     702           0 :                 boost::filesystem::path candidate = local_path / ".gitmodules";
     703           0 :                 if (boost::filesystem::exists(candidate))
     704             :                 {
     705           0 :                     source_file = candidate;
     706             :                     git_super = true;
     707             :                 }
     708           0 :             }
     709           1 :             if (source_file.empty())
     710             :             {
     711           0 :                 std::string err_str = "No manifest found in folder: " + local_path.string();
     712           0 :                 error(err_str);
     713           0 :                 return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMDINIT_NO_LOCAL_MANIFEST, err_str));
     714           0 :             }
     715             :         }
     716             :     }
     717             : 
     718           3 :     info("Using local manifest (no clone).");
     719           3 :     debug(0, "Local source : " + local_path.string());
     720           3 :     debug(0, "Manifest file : " + source_file.string());
     721             : 
     722           3 :     auto config = get_config_folder()->get_or_new_config();
     723           3 :     config->set_parse_mode(get_parse_mode());
     724           3 :     if (!get_prefer_branch().empty()) config->set_prefer_branch(get_prefer_branch());
     725           6 :     config->set_manifest_local(rel_generic(get_workspace_path(), local_path, get_manifest_local()));
     726             :     // No git remote for -l
     727           3 :     config->set_manifest_url("");
     728             : 
     729           3 :     boost::filesystem::path workspace = abs_norm(get_workspace_path());
     730           3 :     boost::filesystem::path source_dir = is_file ? local_path.parent_path() : local_path;
     731           3 :     const bool source_is_workspace = paths_same(source_dir, workspace);
     732             : 
     733           3 :     if (git_super)
     734             :     {
     735           0 :         info("Git submodule detected.");
     736           0 :         config->set_manifest_type(manifest::Type::GIT_SUPER_PROJECT);
     737           0 :         result = get_config_folder()->write_config_file();
     738           0 :         return ETRC_RET(ESYSREPO_RESULT(result));
     739             :     }
     740             : 
     741           3 :     if (google_manifest)
     742             :     {
     743           0 :         info("Google repo tool manifest detected.");
     744           0 :         config->set_manifest_type(manifest::Type::GOOGLE_MANIFEST);
     745           0 :         config->set_manifest_format(manifest::Format::XML);
     746           0 :         config->set_manifest_kind(manifest::Kind::ISOLATED);
     747             : 
     748           0 :         boost::filesystem::path dest_dir = get_config_folder()->get_path();
     749           0 :         dest_dir /= grepo::Manifest::get_folder_name();
     750           0 :         boost::system::error_code ec;
     751           0 :         boost::filesystem::create_directories(dest_dir, ec);
     752           0 :         if (ec)
     753             :         {
     754           0 :             error("Couldn't create the folder : " + dest_dir.string());
     755           0 :             return ETRC_RET(ESYSREPO_RESULT(ResultCode::FOLDER_CREATION_ERROR, dest_dir.string()));
     756             :         }
     757           0 :         boost::filesystem::path dest_file = dest_dir / source_file.filename();
     758           0 :         boost::filesystem::copy_file(source_file, dest_file, boost::filesystem::copy_options::overwrite_existing, ec);
     759           0 :         if (ec)
     760             :         {
     761           0 :             error("Couldn't copy the manifest file : " + source_file.string());
     762           0 :             return ETRC_RET(ESYSREPO_RESULT(ResultCode::FAILED_TO_COPY, source_file.string()));
     763             :         }
     764           0 :         config->set_manifest_path((boost::filesystem::path(grepo::Manifest::get_folder_name()) / source_file.filename())
     765             :                                       .generic_string());
     766           0 :         result = get_config_folder()->write_config_file();
     767           0 :         return ETRC_RET(ESYSREPO_RESULT(result));
     768           0 :     }
     769             : 
     770           3 :     info("ESysRepo manifest detected.");
     771           3 :     config->set_manifest_type(manifest::Type::ESYSREPO_MANIFEST);
     772             : 
     773           3 :     auto manifest = std::make_shared<Manifest>();
     774           3 :     std::string ext = source_file.extension().string();
     775          12 :     if (ext == ".manifest" || source_file.filename() == ".esysrepo.manifest")
     776             :     {
     777           0 :         result = read_esysrepo_manifest(manifest, source_file.string());
     778           0 :         if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     779             :     }
     780           3 :     else if (ext == ".xml")
     781             :     {
     782           6 :         result = read_esysrepo_manifest_xml(manifest, source_file.string());
     783           3 :         if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     784           3 :         manifest->set_format(manifest::Format::XML);
     785             :     }
     786           0 :     else if (ext == ".json")
     787             :     {
     788           0 :         result = read_esysrepo_manifest_json(manifest, source_file.string());
     789           0 :         if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     790           0 :         manifest->set_format(manifest::Format::JSON);
     791             :     }
     792             :     else
     793             :     {
     794           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::MANIFEST_FILE_EXT_UNKNOWN, ext));
     795             :     }
     796             : 
     797           3 :     if (manifest->get_kind() == manifest::Kind::NOT_SET) manifest->set_kind(manifest::Kind::ISOLATED);
     798           3 :     config->set_manifest_format(manifest->get_format());
     799             : 
     800           3 :     const bool leave_in_place = (manifest->get_kind() == manifest::Kind::EMBEDDED) && source_is_workspace;
     801           3 :     if (leave_in_place)
     802             :     {
     803           1 :         info("Embedded kind.");
     804           1 :         config->set_manifest_kind(manifest::Kind::EMBEDDED);
     805           1 :         boost::filesystem::path stored = "..";
     806           2 :         stored /= source_file.filename();
     807           1 :         config->set_manifest_path(stored.generic_string());
     808           1 :     }
     809             :     else
     810             :     {
     811           4 :         info(manifest->get_kind() == manifest::Kind::EMBEDDED ? "Embedded kind (source outside workspace, copying)."
     812             :                                                              : "Isolated kind.");
     813           2 :         config->set_manifest_kind(manifest::Kind::ISOLATED);
     814           2 :         boost::filesystem::path dest_dir = get_config_folder()->get_path();
     815           2 :         dest_dir /= manifest::Base::get_folder_name();
     816           2 :         boost::system::error_code ec;
     817           2 :         boost::filesystem::create_directories(dest_dir, ec);
     818           2 :         if (ec)
     819             :         {
     820           0 :             error("Couldn't create the folder : " + dest_dir.string());
     821           0 :             return ETRC_RET(ESYSREPO_RESULT(ResultCode::FOLDER_CREATION_ERROR, dest_dir.string()));
     822             :         }
     823           4 :         boost::filesystem::path dest_file = dest_dir / source_file.filename();
     824           2 :         boost::filesystem::copy_file(source_file, dest_file, boost::filesystem::copy_options::overwrite_existing, ec);
     825           2 :         if (ec)
     826             :         {
     827           0 :             error("Couldn't copy the manifest file : " + source_file.string());
     828           0 :             return ETRC_RET(ESYSREPO_RESULT(ResultCode::FAILED_TO_COPY, source_file.string()));
     829             :         }
     830           4 :         config->set_manifest_path(
     831           6 :             (boost::filesystem::path(manifest::Base::get_folder_name()) / source_file.filename()).generic_string());
     832           2 :     }
     833             : 
     834           3 :     if (!get_rev_set().empty())
     835             :     {
     836           0 :         result = manifest->select_revision_set(get_rev_set());
     837           0 :         if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     838           0 :         config->set_revision_set(get_rev_set());
     839             :     }
     840           3 :     if (!get_prefer_branch().empty()) config->set_prefer_branch(get_prefer_branch());
     841             : 
     842           3 :     result = get_config_folder()->write_config_file();
     843           6 :     return ETRC_RET(ESYSREPO_RESULT(result));
     844          17 : }
     845             : 
     846          23 : Result CmdInit::fetch_unknown_manifest()
     847             : {
     848          23 :     Result result;
     849          23 :     ETRC_CALL_RET_NP(result);
     850             : 
     851          23 :     info("Detecting the manifest type ...");
     852             : 
     853          23 :     auto git_helper = new_git_helper();
     854          23 :     std::string git_repo_path;
     855             : 
     856          23 :     result = clone_manifest_repo(*git_helper, git_repo_path);
     857          23 :     if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     858             : 
     859          23 :     boost::filesystem::path path = git_repo_path;
     860          23 :     boost::filesystem::path file_path = path;
     861          23 :     file_path /= ".esysrepo.manifest";
     862             : 
     863          23 :     if (boost::filesystem::exists(file_path))
     864             :     {
     865           0 :         result = fetch_esysrepo_manifest(*git_helper.get(), path.string(), ".esysrepo.manifest");
     866           0 :         return ETRC_RET(ESYSREPO_RESULT(result));
     867             :     }
     868             : 
     869          23 :     file_path = path;
     870          23 :     file_path /= ".esysrepo.manifest.xml";
     871             : 
     872          23 :     if (boost::filesystem::exists(file_path))
     873             :     {
     874           9 :         result = fetch_esysrepo_manifest(*git_helper.get(), path.string(), ".esysrepo.manifest.xml");
     875          18 :         return ETRC_RET(ESYSREPO_RESULT(result));
     876             :     }
     877             : 
     878          14 :     file_path = path;
     879          14 :     file_path /= ".esysrepo.manifest.json";
     880             : 
     881          14 :     if (boost::filesystem::exists(file_path))
     882             :     {
     883           0 :         result = fetch_esysrepo_manifest(*git_helper.get(), path.string(), ".esysrepo.manifest.json");
     884           0 :         return ETRC_RET(ESYSREPO_RESULT(result));
     885             :     }
     886             : 
     887          14 :     file_path = path;
     888          28 :     file_path /= get_google_manifest_filename();
     889             : 
     890          14 :     if (boost::filesystem::exists(file_path))
     891             :     {
     892          14 :         info("Google repo tool manifest detected.");
     893          14 :         result = install_google_manifest(*git_helper, git_repo_path);
     894          28 :         return ETRC_RET(ESYSREPO_RESULT(result));
     895             :     }
     896             : 
     897           0 :     file_path = path;
     898           0 :     file_path /= ".gitmodules";
     899             : 
     900           0 :     if (boost::filesystem::exists(file_path))
     901             :     {
     902           0 :         info("Git submodule detected.");
     903           0 :         auto config = get_config_folder()->get_or_new_config();
     904             : 
     905           0 :         config->set_manifest_type(manifest::Type::GIT_SUPER_PROJECT);
     906           0 :         config->set_manifest_url(get_url());
     907           0 :         if (!get_prefer_branch().empty()) config->set_prefer_branch(get_prefer_branch());
     908           0 :         boost::filesystem::path source = path.string();
     909           0 :         boost::filesystem::path target = get_config_folder()->get_workspace_path();
     910             : 
     911           0 :         result = git_helper->move(source.string(), target.string(), true, log::Level::DEBUG);
     912           0 :         if (result == ResultCode::FAILED_TO_COPY) return ETRC_RET(ESYSREPO_RESULT(result));
     913           0 :         if (result == ResultCode::FAILED_TO_REMOVE_ALL)
     914           0 :             warn("While moving folder " + source.string() + " some files were left behind.");
     915           0 :         return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     916           0 :     }
     917             : 
     918           0 :     return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMDINIT_FAILED_FETCH_UNKNOWN_MANIFEST));
     919          69 : }
     920             : 
     921          30 : Result CmdInit::load_esysrepo_folder()
     922             : {
     923          30 :     Result result;
     924          30 :     ETRC_CALL_RET_NP(result);
     925             : 
     926          30 :     auto config_folder = std::make_shared<ConfigFolder>();
     927          30 :     config_folder->set_logger_if(get_logger_if());
     928             : 
     929          60 :     set_config_folder(config_folder);
     930             : 
     931          30 :     ETRC_MSG("parent_path = " + get_workspace_path());
     932             : 
     933          30 :     result = config_folder->open(get_workspace_path(), false);
     934          90 :     return ETRC_RET(ESYSREPO_RESULT(result));
     935          30 : }
     936             : 
     937          29 : Result CmdInit::create_esysrepo_folder()
     938             : {
     939          29 :     Result result;
     940          29 :     ETRC_CALL_RET_NP(result);
     941             : 
     942          29 :     auto config_folder = get_config_folder();
     943          29 :     if (config_folder == nullptr)
     944             :     {
     945           0 :         config_folder = std::make_shared<ConfigFolder>();
     946           0 :         config_folder->set_logger_if(get_logger_if());
     947             : 
     948           0 :         set_config_folder(config_folder);
     949             :     }
     950             : 
     951          29 :     ETRC_MSG("parent_path = " + get_workspace_path());
     952             : 
     953          29 :     result = config_folder->create(get_workspace_path(), true);
     954          87 :     return ESYSREPO_RESULT(result);
     955          29 : }
     956             : 
     957           1 : Result CmdInit::find_url_from_project_name()
     958             : {
     959           1 :     Result result;
     960           1 :     ETRC_CALL_RET_NP(result);
     961             : 
     962           1 :     manifest::DirectoryMngr mngr;
     963             : 
     964           1 :     boost::filesystem::path path = get_config_folder()->get_temp_path();
     965           1 :     path /= "manifest_directories";
     966           1 :     mngr.set_folder_path(path.string());
     967             : 
     968           1 :     if (get_directories() == nullptr)
     969             :     {
     970           1 :         auto directories = std::make_shared<manifest::Directories>();
     971           1 :         directories->add_default_libesys();
     972             : 
     973           2 :         mngr.set_directories(directories);
     974           3 :         set_directories(directories);
     975           1 :     }
     976             : 
     977           1 :     result = mngr.load();
     978           1 :     if (result.error()) return ETRC_RET(ESYSREPO_RESULT(result));
     979             : 
     980           1 :     auto project = get_directories()->find_project(get_project_name());
     981           1 :     if (project == nullptr) return ETRC_RET(ESYSREPO_RESULT(ResultCode::GENERIC_ERROR));
     982             : 
     983           1 :     set_url(project->get_url_ssh());
     984           2 :     return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK));
     985           1 : }
     986             : 
     987           1 : void CmdInit::set_directories(std::shared_ptr<manifest::Directories> directories)
     988             : {
     989           1 :     m_directories = directories;
     990           1 : }
     991             : 
     992           2 : std::shared_ptr<manifest::Directories> CmdInit::get_directories() const
     993             : {
     994           2 :     return m_directories;
     995             : }
     996             : 
     997             : } // namespace esys::repo::exe

Generated by: LCOV version 1.14