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 56 : 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 28 : 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 28 : CmdManifest::CmdManifest() 75 56 : : Cmd("Manifest") 76 : { 77 28 : } 78 : 79 28 : CmdManifest::~CmdManifest() = default; 80 : 81 1 : void CmdManifest::set_task(Task task) 82 : { 83 1 : m_task = task; 84 1 : } 85 : 86 3 : CmdManifest::Task CmdManifest::get_task() const 87 : { 88 3 : 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 1 : void CmdManifest::set_output_file(const std::string &output_file) 124 : { 125 1 : m_output_file = output_file; 126 1 : } 127 : 128 4 : const std::string &CmdManifest::get_output_file() const 129 : { 130 4 : return m_output_file; 131 : } 132 : 133 3 : Result CmdManifest::update_revision_as_head() 134 : { 135 11 : for (auto location : get_manifest()->get_locations()) 136 : { 137 31 : for (auto repo : location->get_repos()) 138 : { 139 52 : Result result = update_revision_as_head(repo); 140 26 : if (result.error()) return ESYSREPO_RESULT(result); 141 52 : } 142 5 : } 143 3 : return ESYSREPO_RESULT(ResultCode::OK); 144 : } 145 : 146 26 : Result CmdManifest::update_revision_as_head(std::shared_ptr<manifest::Repository> repo) 147 : { 148 26 : auto git_helper = new_git_helper(); 149 : 150 26 : boost::filesystem::path repo_path = get_config_folder()->get_workspace_path(); 151 26 : repo_path /= repo->get_path(); 152 78 : repo_path = boost::filesystem::absolute(repo_path).lexically_normal().make_preferred(); 153 : 154 26 : std::string revision = repo->get_revision(); 155 64 : if (revision.empty()) revision = get_manifest()->get_default_revision(); 156 : 157 26 : Result rresult = git_helper->open(repo_path.string(), log::Level::DEBUG); 158 26 : if (rresult.error()) return ESYSREPO_RESULT(rresult); 159 : 160 26 : rresult = git_helper->fetch(log::Level::DEBUG); 161 26 : if (rresult.error()) return ESYSREPO_RESULT(rresult); 162 : 163 26 : std::string hash; 164 26 : rresult = git_helper->get_hash(revision, hash, log::Level::DEBUG); 165 26 : if (rresult.error()) 166 : { 167 0 : git_helper->close_on_error(log::Level::DEBUG); 168 0 : return ESYSREPO_RESULT(rresult); 169 : } 170 26 : repo->set_revision(hash); 171 : 172 26 : return git_helper->close(log::Level::DEBUG); 173 52 : } 174 : 175 3 : Result CmdManifest::do_revision_as_head() 176 : { 177 3 : Result result = only_one_folder_or_workspace(); 178 3 : if (result.error()) return ESYSREPO_RESULT(result); 179 : 180 3 : result = open_esysrepo_folder(); 181 3 : if (result.error()) return ESYSREPO_RESULT(result); 182 : 183 3 : result = load_manifest(); 184 3 : if (result.error()) return ESYSREPO_RESULT(result); 185 : 186 3 : result = update_revision_as_head(); 187 3 : if (result.error()) 188 : { 189 0 : std::string err_str = "Failed to get the revision as HEAD"; 190 0 : error(err_str); 191 0 : return ESYSREPO_RESULT(result, err_str); 192 0 : } 193 : 194 3 : std::shared_ptr<std::ofstream> fos; 195 3 : std::ostream *os = nullptr; 196 : 197 3 : if (get_output_file().empty()) 198 : os = &std::cout; 199 : else 200 : { 201 1 : fos = std::make_shared<std::ofstream>(get_output_file()); 202 1 : os = fos.get(); 203 : } 204 : 205 3 : std::shared_ptr<manifest::FileBase> file; 206 : 207 6 : switch (get_manifest()->get_type()) 208 : { 209 2 : case manifest::Type::GOOGLE_MANIFEST: file = std::make_shared<grepo::Manifest>(); break; 210 4 : case manifest::Type::ESYSREPO_MANIFEST: file = std::make_shared<manifest::XMLFile>(); break; 211 0 : default: error("Manifest format not supported."); return generic_error(-1); 212 : } 213 : 214 3 : file->set_data(get_manifest()); 215 3 : result = file->write(*os); 216 : 217 3 : if (fos != nullptr) fos->close(); 218 6 : return ESYSREPO_RESULT(result); 219 6 : } 220 : 221 0 : Result CmdManifest::do_list_dirs() 222 : { 223 0 : UserFolder user_folder; 224 : 225 0 : auto result = user_folder.read(); 226 0 : if (result.error()) return ESYSREPO_RESULT(result); 227 : 228 0 : if (user_folder.get_user_config() == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR); 229 : 230 0 : auto mds = user_folder.get_user_config()->get_manifest_directories(); 231 0 : if (mds == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR); 232 : 233 0 : std::ostringstream oss; 234 : 235 0 : for (auto idx = 0; idx < mds->get_items().size(); ++idx) 236 : { 237 0 : auto md = mds->get_items()[idx]; 238 0 : oss.str(""); 239 : 240 0 : oss << "[" << idx << "] " << md->get_name() << std::endl; 241 0 : oss << " " << md->get_url_ssh() << std::endl; 242 0 : oss << " " << md->get_url_https(); 243 : 244 0 : info(oss.str()); 245 0 : } 246 0 : return ESYSREPO_RESULT(ResultCode::OK); 247 0 : } 248 : 249 0 : Result CmdManifest::do_list_projects() 250 : { 251 0 : UserFolder user_folder; 252 : 253 0 : auto result = user_folder.read(); 254 0 : if (result.error()) return ESYSREPO_RESULT(result); 255 : 256 0 : if (user_folder.get_user_config() == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR); 257 : 258 0 : auto mds = user_folder.get_user_config()->get_manifest_directories(); 259 0 : if (mds == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR); 260 : 261 0 : manifest::DirectoryMngr mngr; 262 : 263 0 : mngr.set_folder_path(user_folder.get_user_config()->get_manifest_directories_path()); 264 0 : mngr.set_directories(mds); 265 : 266 0 : result = mngr.load(); 267 0 : if (result.error()) return ESYSREPO_RESULT(result); 268 : 269 0 : std::ostringstream oss; 270 : 271 0 : for (auto idx = 0; idx < mds->get_items().size(); ++idx) 272 : { 273 0 : auto md = mds->get_items()[idx]; 274 0 : oss.str(""); 275 : 276 0 : oss << "[" << idx << "] " << md->get_name() << std::endl; 277 0 : oss << " urls:" << std::endl; 278 0 : oss << " " << md->get_url_ssh() << std::endl; 279 0 : oss << " " << md->get_url_https(); 280 : 281 0 : if (md->get_directory() == nullptr) 282 : { 283 0 : warn("Manifest directory has no projects."); 284 0 : continue; 285 : } 286 0 : oss << std::endl << " projects:"; 287 0 : for (auto dir : md->get_directory()->get_items()) 288 : { 289 0 : oss << std::endl << " " << dir->get_name(); 290 : // oss << " " << dir 291 0 : } 292 : 293 0 : info(oss.str()); 294 0 : } 295 0 : return ESYSREPO_RESULT(ResultCode::OK); 296 0 : } 297 : 298 0 : Result CmdManifest::do_add_dir() 299 : { 300 0 : UserFolder user_folder; 301 : 302 0 : auto result = user_folder.read(); 303 0 : if (result.error()) return ESYSREPO_RESULT(result); 304 : 305 0 : if (user_folder.get_user_config() == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR); 306 : 307 0 : auto mds = user_folder.get_user_config()->get_manifest_directories(); 308 0 : if (mds == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR); 309 : 310 0 : auto item = std::make_shared<manifest::Directories::Item>(); 311 0 : item->set_name(get_task_add_dir().get_name()); 312 0 : item->set_url_ssh(get_task_add_dir().get_url_ssh()); 313 0 : item->set_url_https(get_task_add_dir().get_url_https()); 314 : 315 0 : mds->add_item(item->get_name(), item); 316 : 317 0 : result = user_folder.write(); 318 0 : if (result.error()) return ESYSREPO_RESULT(result); 319 : 320 0 : info("Added manifest directory '" + get_task_del_dir().get_name() + "'."); 321 0 : return ESYSREPO_RESULT(ResultCode::OK); 322 0 : } 323 : 324 0 : Result CmdManifest::do_del_dir() 325 : { 326 0 : UserFolder user_folder; 327 : 328 0 : auto result = user_folder.read(); 329 0 : if (result.error()) return ESYSREPO_RESULT(result); 330 : 331 0 : if (user_folder.get_user_config() == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR); 332 : 333 0 : auto mds = user_folder.get_user_config()->get_manifest_directories(); 334 0 : if (mds == nullptr) return ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR); 335 : 336 0 : result = mds->del_item(get_task_del_dir().get_name()); 337 0 : if (result.error()) return ESYSREPO_RESULT(result); 338 : 339 0 : result = user_folder.write(); 340 0 : if (result.error()) return ESYSREPO_RESULT(result); 341 : 342 0 : info("Deleted manifest directory '" + get_task_del_dir().get_name() + "'."); 343 0 : return ESYSREPO_RESULT(ResultCode::OK); 344 0 : } 345 : 346 3 : Result CmdManifest::impl_run() 347 : { 348 3 : Result result; 349 3 : ETRC_CALL_RET_NP(result); 350 : 351 3 : switch (get_task()) 352 : { 353 3 : case Task::REVISION_AS_HEAD: 354 6 : case Task::NOT_SET: return ETRC_RET(do_revision_as_head()); 355 0 : case Task::LIST_DIRS: return ETRC_RET(do_list_dirs()); 356 0 : case Task::LIST_PROJECTS: return ETRC_RET(do_list_projects()); 357 0 : case Task::ADD_DIR: return ETRC_RET(do_add_dir()); 358 0 : case Task::DEL_DIR: return ETRC_RET(do_del_dir()); 359 0 : default: return ETRC_RET(ESYSREPO_RESULT(ResultCode::INTERNAL_ERROR)); 360 : } 361 : return ETRC_RET(ESYSREPO_RESULT(ResultCode::OK)); 362 3 : } 363 : 364 : } // namespace esys::repo::exe