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 26 : Sync::Sync() 28 26 : : log::User() 29 : { 30 26 : } 31 : 32 76 : Sync::~Sync() = default; 33 : 34 5 : void Sync::set_branch(const std::string &branch) 35 : { 36 5 : m_branch = branch; 37 5 : } 38 : 39 37 : const std::string &Sync::get_branch() const 40 : { 41 37 : return m_branch; 42 : } 43 : 44 0 : void Sync::set_force(bool force) 45 : { 46 0 : m_force = force; 47 0 : } 48 : 49 2 : bool Sync::get_force() const 50 : { 51 2 : 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 25 : std::shared_ptr<GitHelper> Sync::new_git_helper() 87 : { 88 50 : auto git_helper = std::make_shared<GitHelper>(get_git(), get_logger_if()); 89 75 : get_git()->set_logger_if(git_helper); 90 25 : return git_helper; 91 0 : } 92 : 93 25 : Result Sync::run() 94 : { 95 25 : Result result; 96 25 : ETRC_CALL_RET_NP(result); 97 : 98 50 : if (get_git() == nullptr) return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_GIT_IS_NULLPTR)); 99 50 : if (get_git()->is_open()) return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_GIT_IS_NOT_OPENED)); 100 : 101 25 : auto git_helper = new_git_helper(); 102 : 103 25 : result = git_helper->open(get_config_folder()->get_manifest_repo_path(), get_log_level()); 104 25 : 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 25 : bool dirty = false; 111 25 : if (git_helper->is_dirty(dirty, get_log_level()).error()) 112 0 : return ETRC_RET(ESYSREPO_RESULT(ResultCode::CMD_GIT_IS_DIRTY_FAILED)); 113 25 : 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 25 : result = git_helper->fetch(get_log_level()); 122 25 : 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 45 : if (get_branch().empty()) return ETRC_RET(ESYSREPO_RESULT(normal_sync(*git_helper))); 131 10 : return ETRC_RET(ESYSREPO_RESULT(branch_sync(*git_helper))); 132 25 : } 133 : 134 23 : Result Sync::normal_sync(GitHelper &git_helper) 135 : { 136 23 : Result result; 137 23 : ETRC_CALL_RET_NP(result); 138 : 139 23 : bool detached = false; 140 23 : result = git_helper.is_detached(detached, get_log_level()); 141 23 : 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 23 : 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 22 : git::Branches branches; 156 : 157 22 : result = git_helper.get_branches(branches, git::BranchType::LOCAL, get_log_level()); 158 22 : 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 44 : 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 22 : std::vector<std::string> refs; 173 22 : git::MergeAnalysisResult merge_analysis_result; 174 22 : std::vector<git::CommitHash> commits; 175 : 176 22 : refs.push_back(branches.get_head()->get_remote_branch()); 177 : 178 22 : result = git_helper.merge_analysis(refs, merge_analysis_result, commits, get_log_level()); 179 22 : 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 22 : if (merge_analysis_result == git::MergeAnalysisResult::UP_TO_DATE) 188 : { 189 21 : info("Manifest up to date."); 190 21 : git_helper.close_on_error(log::Level::DEBUG); 191 42 : 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 23 : } 224 : 225 5 : Result Sync::branch_sync(GitHelper &git_helper) 226 : { 227 5 : Result result; 228 5 : ETRC_CALL_RET_NP(result); 229 : 230 5 : result = git_helper.fetch(get_log_level()); 231 5 : 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 5 : Result_t<bool> has_branch = git_helper.has_branch(get_branch(), git::BranchType::LOCAL, get_log_level()); 238 : 239 5 : if (has_branch.error()) 240 : { 241 6 : warn("Manifest: error when trying to know if the following branch exits : " + get_branch() + "."); 242 6 : return ETRC_RET(ESYSREPO_RESULT(normal_sync(git_helper))); 243 : // return ESYSREPO_RESULT(has_branch); 244 : } 245 : 246 2 : if (!has_branch) return ETRC_RET(ESYSREPO_RESULT(normal_sync(git_helper))); 247 : 248 2 : result = git_helper.checkout(get_branch(), get_force(), get_log_level()); 249 2 : if (result.ok()) 250 4 : info("Manifest: checkout branch " + get_branch() + "."); 251 : else 252 0 : error("Manifest: failed to checkout branch " + get_branch() + "."); 253 2 : result = git_helper.close(log::Level::DEBUG); 254 4 : return ETRC_RET(ESYSREPO_RESULT(result)); 255 5 : } 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 25 : void Sync::set_git(std::shared_ptr<GitBase> git) 268 : { 269 25 : m_git = git; 270 25 : } 271 : 272 100 : std::shared_ptr<GitBase> Sync::get_git() const 273 : { 274 100 : return m_git; 275 : } 276 : 277 25 : void Sync::set_config_folder(std::shared_ptr<ConfigFolder> config_folder) 278 : { 279 25 : m_config_folder = config_folder; 280 25 : } 281 : 282 25 : std::shared_ptr<ConfigFolder> Sync::get_config_folder() 283 : { 284 25 : 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 155 : log::Level Sync::get_log_level() 293 : { 294 155 : return m_log_level; 295 : } 296 : 297 : } // namespace esys::repo::manifest