Line data Source code
1 : /*! 2 : * \file esys/repo/cli/cmdmanifest_cli.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/cli/cmdmanifest.h" 20 : #include "esys/repo/manifest/merge.h" 21 : #include "esys/repo/manifest/parsemode.h" 22 : 23 : #include <esys/md/rend/styled_string.h> 24 : 25 : #include <termcolor/termcolor.hpp> 26 : 27 : #include <boost/filesystem.hpp> 28 : 29 : #include <vector> 30 : 31 : namespace esys::repo::cli 32 : { 33 : 34 : #include "esys/repo/cli/cmdmanifest_doc.cpp" 35 : 36 17 : CmdManifest::CmdManifest(AppBase *app) 37 34 : : BaseType(app, "manifest", "Manifest tools") 38 : { 39 17 : } 40 : 41 17 : CmdManifest::~CmdManifest() = default; 42 : 43 3 : std::shared_ptr<po::options_description> CmdManifest::get_desc() 44 : { 45 3 : auto desc = Cmd::get_desc(); 46 3 : if (desc != nullptr) return desc; 47 : 48 3 : desc = std::make_shared<po::options_description>("Manifest options"); 49 : // clang-format off 50 3 : desc->add_options() 51 3 : ("help,h", "produce help message") 52 3 : ("revision-as-HEAD,r", "Save revisions as current HEAD") 53 3 : ("output-file,o", po::value<std::string>(), "File to save the manifest to") 54 3 : ("list-dirs,l", "List all manifest directories") 55 3 : ("list-projects,p", po::value<std::string>()->implicit_value(""), 56 : "List all projects from one or all manifest directories") 57 3 : ("add-dir,a", po::value<std::string>(), "Add a manifest directory <name> <ssh> <https>") 58 3 : ("del-dir,d", po::value<std::string>(), "Delete a manifest directory <name>") 59 3 : ("format", po::value<std::string>(), "merge output format: native (default) or google") 60 3 : ("on-conflict", po::value<std::string>(), "merge collision policy: fail (default), prefer-first, prefer-last") 61 3 : ("strict", po::value<bool>()->default_value(false)->implicit_value(true), 62 : "fail on unknown manifest XML when merging") 63 : ; 64 : // clang-format on 65 6 : Cmd::set_desc(desc); 66 3 : return desc; 67 0 : } 68 : 69 8 : int CmdManifest::configure_cmd(CmdType &cmd) 70 : { 71 8 : const auto sub = get_sub_args(); 72 8 : const bool is_merge = !sub.empty() && sub[0] == "merge"; 73 24 : const bool other_task = get_vm().count("revision-as-HEAD") || get_vm().count("list-dirs") 74 37 : || get_vm().count("list-projects") || get_vm().count("add-dir") || get_vm().count("del-dir"); 75 : 76 8 : if (is_merge && other_task) 77 : { 78 1 : error("manifest merge cannot be combined with -r, --list-dirs, --list-projects, --add-dir, or --del-dir"); 79 1 : return -1; 80 : } 81 : 82 7 : if (is_merge) 83 : { 84 2 : if (sub.size() < 3) 85 : { 86 1 : error("manifest merge requires at least two input files"); 87 1 : return -1; 88 : } 89 1 : cmd.set_task(CmdType::Task::MERGE); 90 1 : std::vector<std::string> inputs(sub.begin() + 1, sub.end()); 91 1 : cmd.set_merge_inputs(inputs); 92 2 : if (get_vm().count("format")) 93 : { 94 2 : const auto fmt = get_vm()["format"].as<std::string>(); 95 1 : if (fmt == "native") 96 1 : cmd.set_merge_format(esys::repo::manifest::Merge::OutputFormat::Native); 97 0 : else if (fmt == "google") 98 0 : cmd.set_merge_format(esys::repo::manifest::Merge::OutputFormat::Google); 99 : else 100 : { 101 0 : error("--format must be native or google"); 102 0 : return -1; 103 : } 104 1 : } 105 2 : if (get_vm().count("on-conflict")) 106 : { 107 2 : const auto pol = get_vm()["on-conflict"].as<std::string>(); 108 1 : if (pol == "fail") 109 0 : cmd.set_on_conflict(esys::repo::manifest::Merge::OnConflict::Fail); 110 1 : else if (pol == "prefer-first") 111 0 : cmd.set_on_conflict(esys::repo::manifest::Merge::OnConflict::PreferFirst); 112 1 : else if (pol == "prefer-last") 113 1 : cmd.set_on_conflict(esys::repo::manifest::Merge::OnConflict::PreferLast); 114 : else 115 : { 116 0 : error("--on-conflict must be fail, prefer-first, or prefer-last"); 117 0 : return -1; 118 : } 119 1 : } 120 2 : if (get_vm()["strict"].as<bool>()) cmd.set_merge_parse_mode(esys::repo::manifest::ParseMode::Strict); 121 4 : if (get_vm().count("output-file")) cmd.set_output_file(get_vm()["output-file"].as<std::string>()); 122 1 : return 0; 123 1 : } 124 : 125 10 : if (get_vm().count("revision-as-HEAD")) 126 0 : cmd.set_task(CmdType::Task::REVISION_AS_HEAD); 127 10 : else if (get_vm().count("list-dirs")) 128 0 : cmd.set_task(CmdType::Task::LIST_DIRS); 129 10 : else if (get_vm().count("list-projects")) 130 : { 131 0 : cmd.set_task(CmdType::Task::LIST_PROJECTS); 132 0 : cmd.set_dirs(get_vm()["list-projects"].as<std::string>()); 133 : } 134 10 : else if (get_vm().count("add-dir")) 135 : { 136 0 : CmdType::TaskAddDir add_dir; 137 : 138 0 : add_dir.set_name(get_vm()["add-dir"].as<std::string>()); 139 : 140 0 : for (auto const &url : get_sub_args()) 141 : { 142 0 : if (url.find("ssh://") != std::string::npos) 143 0 : add_dir.set_url_ssh(url); 144 0 : else if (url.find("https://") != std::string::npos) 145 0 : add_dir.set_url_https(url); 146 : else 147 0 : error("url not known protocol for '" + url + "'"); 148 0 : } 149 : 150 0 : cmd.set_task_add_dir(add_dir); 151 0 : } 152 10 : else if (get_vm().count("del-dir")) 153 : { 154 0 : CmdType::TaskDelDir del_dir; 155 : 156 0 : del_dir.set_name(get_vm()["del-dir"].as<std::string>()); 157 : 158 0 : cmd.set_task_del_dir(del_dir); 159 0 : } 160 10 : if (get_vm().count("output-file")) cmd.set_output_file(get_vm()["output-file"].as<std::string>()); 161 : 162 : return 0; 163 8 : } 164 : 165 0 : int CmdManifest::print_doc(std::ostream &os) 166 : { 167 0 : os << cmdmanifest_doc_strings; 168 0 : return 0; 169 : } 170 : 171 : } // namespace esys::repo::cli