Line data Source code
1 : /*! 2 : * \file esys/repo/manifest/sync_manifest.cpp 3 : * \brief 4 : * 5 : * \cond 6 : * __legal_b__ 7 : * 8 : * Copyright (c) 2021-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/manifest/sync.h" 20 : 21 : #include <esys/trace/call.h> 22 : #include <esys/trace/macros.h> 23 : 24 : namespace esys::repo::manifest 25 : { 26 : 27 20 : Sync::Sync() 28 20 : : log::User() 29 : { 30 20 : } 31 : 32 60 : Sync::~Sync() = default; 33 : 34 2 : void Sync::set_branch(const std::string &branch) 35 : { 36 2 : m_branch = branch; 37 2 : } 38 : 39 25 : const std::string &Sync::get_branch() const 40 : { 41 25 : return m_branch; 42 : } 43 : 44 0 : void Sync::set_force(bool force) 45 : { 46 0 : m_force = force; 47 0 : } 48 : 49 1 : bool Sync::get_force() const 50 : { 51 1 : return m_force; 52 : } 53 : 54 0 : int Sync::is_manifest_modified(bool &modified) 55 : { 56 0 : int result_int = 0; 57 0 : ETRC_CALL_RET_NP(result_int); 58 : 59 0 : bool dirty = false; 60 0 : modified = false; 61 : 62 0 : if (get_git()->is_dirty(dirty).error()) return ETRC_RET(GIT_IS_DIRTY_FAILED); 63 : 64 0 : if (!dirty) return ETRC_RET(0); 65 : 66 0 : git::RepoStatus status; 67 : 68 0 : Result result = get_git()->get_status(status); 69 0 : if (result.error()) return ETRC_RET(GIT_GET_STATUS_FAILED); 70 : 71 0 : if (get_config_folder() == nullptr) return ETRC_RET(CONFIG_FOLDER_IS_NULL); 72 0 : auto config = get_config_folder()->get_config(); 73 0 : if (config == nullptr) return ETRC_RET(CONFIG_IS_NULL); 74 : 75 0 : auto rel_file_name = get_config_folder()->get_manifest_rel_file_name(); 76 : 77 0 : auto file_status_it = status.get_map_file_status().find(rel_file_name); 78 0 : if (file_status_it == status.get_map_file_status().end()) return ETRC_RET(0); 79 : 80 0 : auto file_status = file_status_it->second; 81 : 82 0 : warn("The manifest file has local changes!"); 83 0 : return ETRC_RET(0); 84 0 : } 85 : 86 20 : std::shared_ptr<GitHelper> Sync::new_git_helper() 87 : { 88 40 : auto git_helper = std::make_shared<GitHelper>(get_git(), get_logger_if()); 89 60 : get_git()->set_logger_if(git_helper); 90 20 : return git_helper; 91 0 : } 92 : 93 20 : Result Sync::run() 94 : { 95 20 : Result result; 96 20 : ETRC_CALL_RET_NP(result); 97 : 98 40 : if (get_git() == nullptr) return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_GIT_IS_NULLPTR)); 99 40 : if (get_git()->is_open()) return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_GIT_IS_NOT_OPENED)); 100 : 101 20 : auto git_helper = new_git_helper(); 102 : 103 20 : result = git_helper->open(get_config_folder()->get_manifest_repo_path(), get_log_level()); 104 20 : if (result.error()) 105 : { 106 0 : std::string err_str = "Couldn't open the manifest git repo"; 107 0 : error(err_str); 108 0 : return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_GIT_OPEN_FAILED, err_str)); 109 0 : } 110 20 : bool dirty = false; 111 20 : if (git_helper->is_dirty(dirty, get_log_level()).error()) 112 0 : return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_GIT_IS_DIRTY_FAILED)); 113 20 : if (dirty) 114 : { 115 0 : std::string err_str = "Sync manifest aborted: found changes in the git repo."; 116 0 : warn(err_str); 117 0 : git_helper->close_on_error(log::Level::DEBUG); 118 0 : return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMDSYNC_ABORTED_FOUND_CHANGES, err_str)); 119 0 : } 120 : 121 20 : result = git_helper->fetch(get_log_level()); 122 20 : if (result.error()) 123 : { 124 0 : std::string err_str = "Fetch failed on the manifest git repo"; 125 0 : error(err_str); 126 0 : git_helper->close_on_error(log::Level::DEBUG); 127 0 : return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_GIT_FETCH_FAILED, err_str)); 128 0 : } 129 : 130 38 : if (get_branch().empty()) return ETRC_RET(ESYSREPO_RESULT(normal_sync(*git_helper))); 131 4 : return ETRC_RET(ESYSREPO_RESULT(branch_sync(*git_helper))); 132 20 : } 133 : 134 19 : Result Sync::normal_sync(GitHelper &git_helper) 135 : { 136 19 : Result result; 137 19 : ETRC_CALL_RET_NP(result); 138 : 139 19 : bool detached = false; 140 19 : result = git_helper.is_detached(detached, get_log_level()); 141 19 : if (result.error()) 142 : { 143 0 : error("Couldn't detect if the git repo is detached or not."); 144 0 : git_helper.close_on_error(log::Level::DEBUG); 145 0 : return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK)); 146 : } 147 : 148 19 : if (detached) 149 : { 150 1 : warn("Sync manifest aborted: the git repo is detached."); 151 1 : git_helper.close_on_error(log::Level::DEBUG); 152 2 : return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK)); 153 : } 154 : 155 18 : git::Branches branches; 156 : 157 18 : result = git_helper.get_branches(branches, git::BranchType::LOCAL, get_log_level()); 158 18 : if (result.error()) 159 : { 160 0 : git_helper.close_on_error(log::Level::DEBUG); 161 0 : return ETRC_RET(ESYSREPO_RESULT(result)); 162 : } 163 : 164 36 : if (branches.get_head() == nullptr) 165 : { 166 0 : std::string err_str = "Couldn't get the HEAD."; 167 0 : error(err_str); 168 0 : git_helper.close_on_error(log::Level::DEBUG); 169 0 : return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_GIT_GET_HEAD_FAILED, err_str)); 170 0 : } 171 : 172 18 : std::vector<std::string> refs; 173 18 : git::MergeAnalysisResult merge_analysis_result; 174 18 : std::vector<git::CommitHash> commits; 175 : 176 18 : refs.push_back(branches.get_head()->get_remote_branch()); 177 : 178 18 : result = git_helper.merge_analysis(refs, merge_analysis_result, commits, get_log_level()); 179 18 : if (result.error()) 180 : { 181 0 : std::string err_str = "Merge analysis failed."; 182 0 : error(err_str); 183 0 : git_helper.close_on_error(log::Level::DEBUG); 184 0 : return ETRC_RET(ESYSREPO_RESULT(result, err_str)); 185 0 : } 186 : 187 18 : if (merge_analysis_result == git::MergeAnalysisResult::UP_TO_DATE) 188 : { 189 17 : info("Manifest up to date."); 190 17 : git_helper.close_on_error(log::Level::DEBUG); 191 34 : return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK)); 192 : } 193 1 : if (merge_analysis_result != git::MergeAnalysisResult::FASTFORWARD) 194 : { 195 0 : std::string err_str = "Sync manifest aborted: can't be fastforwarded."; 196 0 : warn(err_str); 197 0 : git_helper.close_on_error(log::Level::DEBUG); 198 0 : return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMDSYNC_GIT_CAN_NOT_BE_FAST_FORWARDED, err_str)); 199 0 : } 200 : 201 : // For a fastforward, there should be only one commit 202 1 : if (commits.size() != 1) 203 : { 204 0 : std::string err_str = "fastforward failed."; 205 0 : error(err_str); 206 0 : git_helper.close_on_error(log::Level::DEBUG); 207 0 : return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_GIT_MORE_THAN_ONE_COMMIT, err_str)); 208 0 : } 209 : 210 1 : info("Fastforward manifest ..."); 211 : 212 1 : result = git_helper.fastforward(commits[0], get_log_level()); 213 1 : if (result.error()) 214 : { 215 0 : std::string err_str = "Fastforward failed."; 216 0 : error(err_str); 217 0 : git_helper.close_on_error(log::Level::DEBUG); 218 0 : return ETRC_RET(ESYSREPO_RESULT(result, err_str)); 219 0 : } 220 1 : info("Fastforward manifest completed."); 221 1 : result = git_helper.close(log::Level::DEBUG); 222 2 : return ETRC_RET(ESYSREPO_RESULT(result)); 223 19 : } 224 : 225 2 : Result Sync::branch_sync(GitHelper &git_helper) 226 : { 227 2 : Result result; 228 2 : ETRC_CALL_RET_NP(result); 229 : 230 2 : result = git_helper.fetch(get_log_level()); 231 2 : if (result.error()) 232 : { 233 0 : git_helper.close_on_error(log::Level::DEBUG); 234 0 : return ETRC_RET(ESYSREPO_RESULT(result)); 235 : } 236 : 237 2 : Result_t<bool> has_branch = git_helper.has_branch(get_branch(), git::BranchType::LOCAL, get_log_level()); 238 : 239 2 : if (has_branch.error()) 240 : { 241 2 : warn("Manifest: error when trying to know if the following branch exits : " + get_branch() + "."); 242 2 : return ETRC_RET(ESYSREPO_RESULT(normal_sync(git_helper))); 243 : // return ESYSREPO_RESULT(has_branch); 244 : } 245 : 246 1 : if (!has_branch) return ETRC_RET(ESYSREPO_RESULT(normal_sync(git_helper))); 247 : 248 1 : result = git_helper.checkout(get_branch(), get_force(), get_log_level()); 249 1 : if (result.ok()) 250 2 : info("Manifest: checkout branch " + get_branch() + "."); 251 : else 252 0 : error("Manifest: failed to checkout branch " + get_branch() + "."); 253 1 : result = git_helper.close(log::Level::DEBUG); 254 2 : return ETRC_RET(ESYSREPO_RESULT(result)); 255 2 : } 256 : 257 0 : int Sync::process_repo() 258 : { 259 0 : return NOT_IMPLEMENTED; 260 : } 261 : 262 0 : int Sync::fetch_update() 263 : { 264 0 : return NOT_IMPLEMENTED; 265 : } 266 : 267 20 : void Sync::set_git(std::shared_ptr<GitBase> git) 268 : { 269 20 : m_git = git; 270 20 : } 271 : 272 80 : std::shared_ptr<GitBase> Sync::get_git() const 273 : { 274 80 : return m_git; 275 : } 276 : 277 20 : void Sync::set_config_folder(std::shared_ptr<ConfigFolder> config_folder) 278 : { 279 20 : m_config_folder = config_folder; 280 20 : } 281 : 282 20 : std::shared_ptr<ConfigFolder> Sync::get_config_folder() 283 : { 284 20 : return m_config_folder; 285 : } 286 : 287 0 : void Sync::set_log_level(log::Level log_level) 288 : { 289 0 : m_log_level = log_level; 290 0 : } 291 : 292 121 : log::Level Sync::get_log_level() 293 : { 294 121 : return m_log_level; 295 : } 296 : 297 : } // namespace esys::repo::manifest