summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/other_tools/just_mr/TARGETS1
-rw-r--r--src/other_tools/just_mr/utils.cpp31
-rw-r--r--src/other_tools/just_mr/utils.hpp16
-rw-r--r--src/other_tools/repo_map/TARGETS16
-rw-r--r--src/other_tools/repo_map/repos_to_setup_map.cpp603
-rw-r--r--src/other_tools/repo_map/repos_to_setup_map.hpp38
6 files changed, 705 insertions, 0 deletions
diff --git a/src/other_tools/just_mr/TARGETS b/src/other_tools/just_mr/TARGETS
index 77fe8d75..24a6b289 100644
--- a/src/other_tools/just_mr/TARGETS
+++ b/src/other_tools/just_mr/TARGETS
@@ -7,6 +7,7 @@
[ ["src/utils/cpp", "tmp_dir"]
, ["src/buildtool/execution_api/local", "config"]
, ["src/buildtool/main", "constants"]
+ , ["src/buildtool/build_engine/expression", "expression"]
]
, "stage": ["src", "other_tools", "just_mr"]
, "private-deps":
diff --git a/src/other_tools/just_mr/utils.cpp b/src/other_tools/just_mr/utils.cpp
index 4d668bc6..f0ca606c 100644
--- a/src/other_tools/just_mr/utils.cpp
+++ b/src/other_tools/just_mr/utils.cpp
@@ -100,4 +100,35 @@ void AddDistfileToCAS(std::filesystem::path const& distfile,
}
}
+// NOLINTNEXTLINE(misc-no-recursion)
+auto ResolveRepo(ExpressionPtr const& repo_desc,
+ ExpressionPtr const& repos,
+ gsl::not_null<std::unordered_set<std::string>*> const& seen)
+ -> std::optional<ExpressionPtr> {
+ if (not repo_desc->IsString()) {
+ return repo_desc;
+ }
+ auto desc_str = repo_desc->String();
+ if (seen->contains(desc_str)) {
+ // cyclic dependency
+ return std::nullopt;
+ }
+ [[maybe_unused]] auto insert_res = seen->insert(desc_str);
+ return ResolveRepo(repos[desc_str]["repository"], repos, seen);
+}
+
+auto ResolveRepo(ExpressionPtr const& repo_desc,
+ ExpressionPtr const& repos) noexcept
+ -> std::optional<ExpressionPtr> {
+ std::unordered_set<std::string> seen = {};
+ try {
+ return ResolveRepo(repo_desc, repos, &seen);
+ } catch (std::exception const& e) {
+ Logger::Log(LogLevel::Error,
+ "Config: while resolving dependencies: {}",
+ e.what());
+ return std::nullopt;
+ }
+}
+
} // namespace JustMR::Utils
diff --git a/src/other_tools/just_mr/utils.hpp b/src/other_tools/just_mr/utils.hpp
index 2da0155a..dffed7c1 100644
--- a/src/other_tools/just_mr/utils.hpp
+++ b/src/other_tools/just_mr/utils.hpp
@@ -18,6 +18,7 @@
#include <unordered_set>
#include "nlohmann/json.hpp"
+#include "src/buildtool/build_engine/expression/configuration.hpp"
#include "src/buildtool/execution_api/local/config.hpp"
#include "src/buildtool/main/constants.hpp"
#include "src/utils/cpp/tmp_dir.hpp"
@@ -152,6 +153,21 @@ namespace Utils {
void AddDistfileToCAS(std::filesystem::path const& distfile,
JustMR::PathsPtr const& just_mr_paths) noexcept;
+/// \brief Recursive part of the ResolveRepo function.
+/// Keeps track of repository names to detect any cyclic dependencies.
+auto ResolveRepo(ExpressionPtr const& repo_desc,
+ ExpressionPtr const& repos,
+ gsl::not_null<std::unordered_set<std::string>*> const& seen)
+ -> std::optional<ExpressionPtr>;
+
+/// \brief Resolves any cyclic dependency issues and follows the repository
+/// dependencies until the one containing the WS root is found.
+/// Returns a repository entry as an ExpressionPtr, or nullopt if cyclic
+/// dependency found.
+auto ResolveRepo(ExpressionPtr const& repo_desc,
+ ExpressionPtr const& repos) noexcept
+ -> std::optional<ExpressionPtr>;
+
} // namespace Utils
} // namespace JustMR
diff --git a/src/other_tools/repo_map/TARGETS b/src/other_tools/repo_map/TARGETS
new file mode 100644
index 00000000..905e09c8
--- /dev/null
+++ b/src/other_tools/repo_map/TARGETS
@@ -0,0 +1,16 @@
+{ "repos_to_setup_map":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["repos_to_setup_map"]
+ , "hdrs": ["repos_to_setup_map.hpp"]
+ , "srcs": ["repos_to_setup_map.cpp"]
+ , "deps":
+ [ ["src/other_tools/root_maps", "commit_git_map"]
+ , ["src/other_tools/root_maps", "content_git_map"]
+ , ["src/other_tools/root_maps", "distdir_git_map"]
+ , ["src/other_tools/root_maps", "fpath_git_map"]
+ , ["src/buildtool/build_engine/expression", "expression"]
+ ]
+ , "stage": ["src", "other_tools", "repo_map"]
+ , "private-deps": [["src/other_tools/just_mr", "utils"]]
+ }
+}
diff --git a/src/other_tools/repo_map/repos_to_setup_map.cpp b/src/other_tools/repo_map/repos_to_setup_map.cpp
new file mode 100644
index 00000000..04c3229d
--- /dev/null
+++ b/src/other_tools/repo_map/repos_to_setup_map.cpp
@@ -0,0 +1,603 @@
+// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/other_tools/repo_map/repos_to_setup_map.hpp"
+
+#include "src/other_tools/just_mr/utils.hpp"
+
+namespace {
+
+/// \brief Updates output config with specific keys from input config.
+void SetReposTakeOver(gsl::not_null<nlohmann::json*> const& cfg,
+ ExpressionPtr const& repos,
+ std::string const& repo_name) {
+ if (repos.IsNotNull()) {
+ for (auto const& key : kTakeOver) {
+ auto repos_repo_name = repos->Get(repo_name, Expression::none_t{});
+ if (repos_repo_name.IsNotNull()) {
+ auto value = repos_repo_name->Get(key, Expression::none_t{});
+ if (value.IsNotNull()) {
+ (*cfg)[key] = value.ToJson();
+ }
+ }
+ }
+ }
+}
+
+/// \brief Perform checkout for a Git type repository.
+/// Guarantees the logger is called exactly once with fatal if a failure occurs.
+void GitCheckout(ExpressionPtr const& repo_desc,
+ ExpressionPtr&& repos,
+ std::string const& repo_name,
+ gsl::not_null<CommitGitMap*> const& commit_git_map,
+ gsl::not_null<TaskSystem*> const& ts,
+ ReposToSetupMap::SetterPtr const& setter,
+ ReposToSetupMap::LoggerPtr const& logger) {
+ // enforce mandatory fields
+ auto repo_desc_commit = repo_desc->At("commit");
+ if (not repo_desc_commit) {
+ (*logger)("GitCheckout: Mandatory field \'commit\' is missing",
+ /*fatal=*/true);
+ return;
+ }
+ if (not repo_desc_commit->get()->IsString()) {
+ (*logger)(
+ "GitCheckout: Unsupported value for mandatory field \'commit\'",
+ /*fatal=*/true);
+ return;
+ }
+ auto repo_desc_repository = repo_desc->At("repository");
+ if (not repo_desc_repository) {
+ (*logger)("GitCheckout: Mandatory field \'repository\' is missing",
+ /*fatal=*/true);
+ return;
+ }
+ if (not repo_desc_repository->get()->IsString()) {
+ (*logger)(
+ "GitCheckout: Unsupported value for mandatory field "
+ "\'repository\'",
+ /*fatal=*/true);
+ return;
+ }
+ auto repo_desc_branch = repo_desc->At("branch");
+ if (not repo_desc_branch) {
+ (*logger)("GitCheckout: Mandatory field \'branch\' is missing",
+ /*fatal=*/true);
+ return;
+ }
+ if (not repo_desc_branch->get()->IsString()) {
+ (*logger)(
+ "GitCheckout: Unsupported value for mandatory field \'branch\'",
+ /*fatal=*/true);
+ return;
+ }
+ auto repo_desc_subdir = repo_desc->Get("subdir", Expression::none_t{});
+ auto subdir = std::filesystem::path((repo_desc_subdir->IsString())
+ ? repo_desc_subdir->String()
+ : "")
+ .lexically_normal();
+ // populate struct
+ GitRepoInfo git_repo_info = {
+ repo_desc_commit->get()->String(), /* hash */
+ repo_desc_repository->get()->String(), /* repo_url */
+ repo_desc_branch->get()->String(), /* branch */
+ subdir.empty() ? "." : subdir.string() /* subdir */
+ };
+ // get the WS root as git tree
+ commit_git_map->ConsumeAfterKeysReady(
+ ts,
+ {std::move(git_repo_info)},
+ [repos = std::move(repos), repo_name, setter, logger](
+ auto const& values) {
+ auto ws_root = *values[0];
+ nlohmann::json cfg({});
+ cfg["workspace_root"] = ws_root;
+ SetReposTakeOver(&cfg, repos, repo_name);
+ (*setter)(std::move(cfg));
+ },
+ [logger, repo_name](auto const& msg, bool fatal) {
+ (*logger)(fmt::format("While setting the workspace root for "
+ "repository {} of type git:\n{}",
+ repo_name,
+ msg),
+ fatal);
+ });
+}
+
+/// \brief Perform checkout for an archive type repository.
+/// Guarantees the logger is called exactly once with fatal if a failure occurs.
+void ArchiveCheckout(ExpressionPtr const& repo_desc,
+ ExpressionPtr&& repos,
+ std::string const& repo_name,
+ std::string const& repo_type,
+ gsl::not_null<ContentGitMap*> const& content_git_map,
+ gsl::not_null<TaskSystem*> const& ts,
+ ReposToSetupMap::SetterPtr const& setter,
+ ReposToSetupMap::LoggerPtr const& logger) {
+ // enforce mandatory fields
+ auto repo_desc_content = repo_desc->At("content");
+ if (not repo_desc_content) {
+ (*logger)("ArchiveCheckout: Mandatory field \'content\' is missing",
+ /*fatal=*/true);
+ return;
+ }
+ if (not repo_desc_content->get()->IsString()) {
+ (*logger)(
+ "ArchiveCheckout: Unsupported value for mandatory field "
+ "\'content\'",
+ /*fatal=*/true);
+ return;
+ }
+ auto repo_desc_fetch = repo_desc->At("fetch");
+ if (not repo_desc_fetch) {
+ (*logger)("ArchiveCheckout: Mandatory field \'fetch\' is missing",
+ /*fatal=*/true);
+ return;
+ }
+ if (not repo_desc_fetch->get()->IsString()) {
+ (*logger)(
+ "ArchiveCheckout: Unsupported value for mandatory field "
+ "\'fetch\'",
+ /*fatal=*/true);
+ return;
+ }
+ auto repo_desc_subdir = repo_desc->Get("subdir", Expression::none_t{});
+ auto subdir = std::filesystem::path(repo_desc_subdir->IsString()
+ ? repo_desc_subdir->String()
+ : "")
+ .lexically_normal();
+ auto repo_desc_distfile = repo_desc->Get("distfile", Expression::none_t{});
+ auto repo_desc_sha256 = repo_desc->Get("sha256", Expression::none_t{});
+ auto repo_desc_sha512 = repo_desc->Get("sha512", Expression::none_t{});
+ // populate struct
+ ArchiveRepoInfo archive_repo_info = {
+ {
+ repo_desc_content->get()->String(), /* content */
+ repo_desc_distfile->IsString()
+ ? std::make_optional(repo_desc_distfile->String())
+ : std::nullopt, /* distfile */
+ repo_desc_fetch->get()->String(), /* fetch_url */
+ repo_desc_sha256->IsString()
+ ? std::make_optional(repo_desc_sha256->String())
+ : std::nullopt, /* sha256 */
+ repo_desc_sha512->IsString()
+ ? std::make_optional(repo_desc_sha512->String())
+ : std::nullopt /* sha512 */
+ }, /* archive */
+ repo_type, /* repo_type */
+ subdir.empty() ? "." : subdir.string() /* subdir */
+ };
+ // get the WS root as git tree
+ content_git_map->ConsumeAfterKeysReady(
+ ts,
+ {std::move(archive_repo_info)},
+ [repos = std::move(repos), repo_name, setter, logger](
+ auto const& values) {
+ auto ws_root = *values[0];
+ nlohmann::json cfg({});
+ cfg["workspace_root"] = ws_root;
+ SetReposTakeOver(&cfg, repos, repo_name);
+ (*setter)(std::move(cfg));
+ },
+ [logger, repo_name, repo_type](auto const& msg, bool fatal) {
+ (*logger)(fmt::format("While setting the workspace root for "
+ "repository {} of type {}:\n{}",
+ repo_name,
+ repo_type,
+ msg),
+ fatal);
+ });
+}
+
+/// \brief Perform checkout for a file type repository.
+/// Guarantees the logger is called exactly once with fatal if a failure occurs.
+void FileCheckout(ExpressionPtr const& repo_desc,
+ ExpressionPtr&& repos,
+ std::string const& repo_name,
+ gsl::not_null<FilePathGitMap*> const& fpath_git_map,
+ gsl::not_null<TaskSystem*> const& ts,
+ ReposToSetupMap::SetterPtr const& setter,
+ ReposToSetupMap::LoggerPtr const& logger) {
+ // enforce mandatory fields
+ auto repo_desc_path = repo_desc->At("path");
+ if (not repo_desc_path) {
+ (*logger)("FileCheckout: Mandatory field \'path\' is missing",
+ /*fatal=*/true);
+ return;
+ }
+ if (not repo_desc_path->get()->IsString()) {
+ (*logger)(
+ "FileCheckout: Unsupported value for mandatory field \'path\'",
+ /*fatal=*/true);
+ return;
+ }
+ // get absolute path
+ auto fpath = ToNormalPath(
+ std::filesystem::absolute(repo_desc_path->get()->String()));
+ // check to_git pragma
+ auto repo_desc_pragma = repo_desc->At("pragma");
+ auto pragma_to_git =
+ repo_desc_pragma ? repo_desc_pragma->get()->At("to_git") : std::nullopt;
+ if (pragma_to_git and pragma_to_git->get()->IsBool() and
+ pragma_to_git->get()->Bool()) {
+ // get the WS root as git tree
+ fpath_git_map->ConsumeAfterKeysReady(
+ ts,
+ {std::move(fpath)},
+ [repos = std::move(repos), repo_name, setter, logger](
+ auto const& values) {
+ auto ws_root = *values[0];
+ nlohmann::json cfg({});
+ cfg["workspace_root"] = ws_root;
+ SetReposTakeOver(&cfg, repos, repo_name);
+ (*setter)(std::move(cfg));
+ },
+ [logger, repo_name](auto const& msg, bool fatal) {
+ (*logger)(fmt::format("While setting the workspace root for "
+ "repository {} of type file:\n{}",
+ repo_name,
+ msg),
+ fatal);
+ });
+ }
+ else {
+ // get the WS root as filesystem location
+ nlohmann::json cfg({});
+ cfg["workspace_root"] =
+ nlohmann::json::array({"file", fpath.string()}); // explicit array
+ SetReposTakeOver(&cfg, repos, repo_name);
+ (*setter)(std::move(cfg));
+ }
+}
+
+/// \brief Perform checkout for a distdir type repository.
+/// Guarantees the logger is called exactly once with fatal if a failure occurs.
+void DistdirCheckout(ExpressionPtr const& repo_desc,
+ ExpressionPtr&& repos,
+ std::string const& repo_name,
+ gsl::not_null<ContentCASMap*> const& content_cas_map,
+ gsl::not_null<DistdirGitMap*> const& distdir_git_map,
+ gsl::not_null<TaskSystem*> const& ts,
+ ReposToSetupMap::SetterPtr const& setter,
+ ReposToSetupMap::LoggerPtr const& logger) {
+ // enforce mandatory fields
+ auto repo_desc_repositories = repo_desc->At("repositories");
+ if (not repo_desc_repositories) {
+ (*logger)(
+ "DistdirCheckout: Mandatory field \'repositories\' is missing",
+ /*fatal=*/true);
+ return;
+ }
+ if (not repo_desc_repositories->get()->IsList()) {
+ (*logger)(
+ "DistdirCheckout: Unsupported value for mandatory field "
+ "\'repositories\'",
+ /*fatal=*/true);
+ return;
+ }
+ // map of distfile to content
+ auto distdir_content =
+ std::make_shared<std::unordered_map<std::string, std::string>>();
+ // get distdir list
+ auto distdir_repos = repo_desc_repositories->get()->List();
+ // create list of archives to fetch
+ std::vector<ArchiveContent> dist_repos_to_fetch{};
+ for (auto const& dist_repo : distdir_repos) {
+ // get name of dist_repo
+ auto dist_repo_name = dist_repo->String();
+ // check that repo name exists
+ auto repos_dist_repo_name = repos->At(dist_repo_name);
+ if (not repos_dist_repo_name) {
+ (*logger)(fmt::format("DistdirCheckout: no repository named {}",
+ dist_repo_name),
+ /*fatal=*/true);
+ return;
+ }
+ auto repo_desc = repos_dist_repo_name->get()->At("repository");
+ if (not repo_desc) {
+ (*logger)(
+ fmt::format("DistdirCheckout: mandatory key \'repository\' "
+ "missing for repository {}",
+ dist_repo_name),
+ /*fatal=*/true);
+ return;
+ }
+ auto resolved_repo_desc =
+ JustMR::Utils::ResolveRepo(repo_desc->get(), repos);
+ if (not resolved_repo_desc) {
+ (*logger)(
+ fmt::format("DistdirCheckout: found cyclic dependency for "
+ "repository {}",
+ dist_repo_name),
+ /*fatal=*/true);
+ return;
+ }
+ auto repo_type = (*resolved_repo_desc)->At("type");
+ if (not repo_type) {
+ (*logger)(
+ fmt::format("DistdirCheckout: mandatory key \'type\' missing "
+ "for repository {}",
+ dist_repo_name),
+ /*fatal=*/true);
+ return;
+ }
+ if (not repo_type->get()->IsString()) {
+ (*logger)(fmt::format("DistdirCheckout: unsupported value for key "
+ "\'type\' for repository {}",
+ dist_repo_name),
+ /*fatal=*/true);
+ return;
+ }
+ // get repo_type
+ auto repo_type_str = repo_type->get()->String();
+ if (not kCheckoutTypeMap.contains(repo_type_str)) {
+ (*logger)(fmt::format("DistdirCheckout: unknown type {} for "
+ "repository {}",
+ repo_type_str,
+ dist_repo_name),
+ /*fatal=*/true);
+ return;
+ }
+ // only do work if repo is archive type
+ if (kCheckoutTypeMap.at(repo_type_str) == CheckoutType::Archive) {
+ // check mandatory fields
+ auto repo_desc_content = (*resolved_repo_desc)->At("content");
+ if (not repo_desc_content) {
+ (*logger)(
+ "DistdirCheckout: Mandatory field \'content\' is "
+ "missing",
+ /*fatal=*/true);
+ return;
+ }
+ if (not repo_desc_content->get()->IsString()) {
+ (*logger)(
+ "DistdirCheckout: Unsupported value for mandatory "
+ "field \'content\'",
+ /*fatal=*/true);
+ return;
+ }
+ auto repo_desc_fetch = (*resolved_repo_desc)->At("fetch");
+ if (not repo_desc_fetch) {
+ (*logger)(
+ "DistdirCheckout: Mandatory field \'fetch\' is missing",
+ /*fatal=*/true);
+ return;
+ }
+ if (not repo_desc_fetch->get()->IsString()) {
+ (*logger)(
+ "DistdirCheckout: Unsupported value for mandatory "
+ "field \'fetch\'",
+ /*fatal=*/true);
+ return;
+ }
+ auto repo_desc_distfile =
+ (*resolved_repo_desc)->Get("distfile", Expression::none_t{});
+ auto repo_desc_sha256 =
+ (*resolved_repo_desc)->Get("sha256", Expression::none_t{});
+ auto repo_desc_sha512 =
+ (*resolved_repo_desc)->Get("sha512", Expression::none_t{});
+
+ ArchiveContent archive = {
+ repo_desc_content->get()->String(), /* content */
+ repo_desc_distfile->IsString()
+ ? std::make_optional(repo_desc_distfile->String())
+ : std::nullopt, /* distfile */
+ repo_desc_fetch->get()->String(), /* fetch_url */
+ repo_desc_sha256->IsString()
+ ? std::make_optional(repo_desc_sha256->String())
+ : std::nullopt, /* sha256 */
+ repo_desc_sha512->IsString()
+ ? std::make_optional(repo_desc_sha512->String())
+ : std::nullopt /* sha512 */
+ }; /* archive */
+
+ // add to distdir content map
+ auto repo_distfile =
+ (archive.distfile ? archive.distfile.value()
+ : std::filesystem::path(archive.fetch_url)
+ .filename()
+ .string());
+ distdir_content->insert_or_assign(repo_distfile, archive.content);
+ // add to fetch list
+ dist_repos_to_fetch.emplace_back(std::move(archive));
+ }
+ }
+ // fetch the gathered distdir repos into CAS
+ content_cas_map->ConsumeAfterKeysReady(
+ ts,
+ dist_repos_to_fetch,
+ [distdir_content = std::move(distdir_content),
+ repos = std::move(repos),
+ repo_name,
+ distdir_git_map,
+ ts,
+ setter,
+ logger]([[maybe_unused]] auto const& values) mutable {
+ // repos are in CAS
+ // get hash of distdir content
+ auto distdir_content_id =
+ HashFunction::ComputeBlobHash(
+ nlohmann::json(*distdir_content).dump())
+ .HexString();
+ // get the WS root as git tree
+ DistdirInfo distdir_info = {distdir_content_id, distdir_content};
+ distdir_git_map->ConsumeAfterKeysReady(
+ ts,
+ {std::move(distdir_info)},
+ [repos = std::move(repos), repo_name, setter, logger](
+ auto const& values) {
+ auto ws_root = *values[0];
+ nlohmann::json cfg({});
+ cfg["workspace_root"] = ws_root;
+ SetReposTakeOver(&cfg, repos, repo_name);
+ (*setter)(std::move(cfg));
+ },
+ [logger, repo_name](auto const& msg, bool fatal) {
+ (*logger)(
+ fmt::format("While setting the workspace root for "
+ "repository {} of type distdir:\n{}",
+ repo_name,
+ msg),
+ fatal);
+ });
+ },
+ [logger, repo_name](auto const& msg, bool fatal) {
+ (*logger)(fmt::format("While fetching archives for distdir "
+ "repository {}:\n{}",
+ repo_name,
+ msg),
+ fatal);
+ });
+}
+
+} // namespace
+
+auto CreateReposToSetupMap(std::shared_ptr<Configuration> const& config,
+ std::optional<std::string> const& main,
+ bool interactive,
+ gsl::not_null<CommitGitMap*> const& commit_git_map,
+ gsl::not_null<ContentGitMap*> const& content_git_map,
+ gsl::not_null<FilePathGitMap*> const& fpath_git_map,
+ gsl::not_null<ContentCASMap*> const& content_cas_map,
+ gsl::not_null<DistdirGitMap*> const& distdir_git_map,
+ std::size_t jobs) -> ReposToSetupMap {
+ auto setup_repo = [config,
+ main,
+ interactive,
+ commit_git_map,
+ content_git_map,
+ fpath_git_map,
+ content_cas_map,
+ distdir_git_map](auto ts,
+ auto setter,
+ auto logger,
+ auto /* unused */,
+ auto const& key) {
+ auto repos = (*config)["repositories"];
+ if (main && (key == *main) && interactive) {
+ // no repository checkout required
+ nlohmann::json cfg({});
+ SetReposTakeOver(&cfg, repos, key);
+ (*setter)(std::move(cfg));
+ }
+ else {
+ // repository requires checkout
+ auto repo_desc_key = repos->At(key);
+ if (not repo_desc_key) {
+ (*logger)(fmt::format("Config: missing config entry "
+ "for repository {}",
+ key),
+ /*fatal=*/true);
+ return;
+ }
+ auto repo_desc = repo_desc_key->get()->At("repository");
+ if (not repo_desc) {
+ (*logger)(fmt::format("Config: mandatory key \'repository\' "
+ "missing for repository {}",
+ key),
+ /*fatal=*/true);
+ return;
+ }
+ auto resolved_repo_desc =
+ JustMR::Utils::ResolveRepo(repo_desc->get(), repos);
+ if (not resolved_repo_desc) {
+ (*logger)(fmt::format("Config: found cyclic dependency for "
+ "repository {}",
+ key),
+ /*fatal=*/true);
+ return;
+ }
+ auto repo_type = (*resolved_repo_desc)->At("type");
+ if (not repo_type) {
+ (*logger)(fmt::format("Config: mandatory key \'type\' missing "
+ "for repository {}",
+ key),
+ /*fatal=*/true);
+ return;
+ }
+ if (not repo_type->get()->IsString()) {
+ (*logger)(fmt::format("Config: unsupported value for key "
+ "\'type\' for repository {}",
+ key),
+ /*fatal=*/true);
+ return;
+ }
+ // get repo_type
+ auto repo_type_str = repo_type->get()->String();
+ if (not kCheckoutTypeMap.contains(repo_type_str)) {
+ (*logger)(
+ fmt::format("Config: unknown type {} for repository {}",
+ repo_type_str,
+ key),
+ /*fatal=*/true);
+ return;
+ }
+ // setup a wrapped_logger
+ auto wrapped_logger = std::make_shared<AsyncMapConsumerLogger>(
+ [&logger, repo_name = key](auto const& msg, bool fatal) {
+ (*logger)(
+ fmt::format("While checking out repository {}:\n{}",
+ repo_name,
+ msg),
+ fatal);
+ });
+ // do checkout
+ switch (kCheckoutTypeMap.at(repo_type_str)) {
+ case CheckoutType::Git: {
+ GitCheckout(*resolved_repo_desc,
+ std::move(repos),
+ key,
+ commit_git_map,
+ ts,
+ setter,
+ wrapped_logger);
+ break;
+ }
+ case CheckoutType::Archive: {
+ ArchiveCheckout(*resolved_repo_desc,
+ std::move(repos),
+ key,
+ repo_type_str,
+ content_git_map,
+ ts,
+ setter,
+ wrapped_logger);
+ break;
+ }
+ case CheckoutType::File: {
+ FileCheckout(*resolved_repo_desc,
+ std::move(repos),
+ key,
+ fpath_git_map,
+ ts,
+ setter,
+ wrapped_logger);
+ break;
+ }
+ case CheckoutType::Distdir: {
+ DistdirCheckout(*resolved_repo_desc,
+ std::move(repos),
+ key,
+ content_cas_map,
+ distdir_git_map,
+ ts,
+ setter,
+ wrapped_logger);
+ break;
+ }
+ }
+ }
+ };
+ return AsyncMapConsumer<std::string, nlohmann::json>(setup_repo, jobs);
+}
diff --git a/src/other_tools/repo_map/repos_to_setup_map.hpp b/src/other_tools/repo_map/repos_to_setup_map.hpp
new file mode 100644
index 00000000..f2f7eb43
--- /dev/null
+++ b/src/other_tools/repo_map/repos_to_setup_map.hpp
@@ -0,0 +1,38 @@
+// Copyright 2022 Huawei Cloud Computing Technology Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef INCLUDED_SRC_OTHER_TOOLS_REPO_MAP_REPOS_TO_SETUP_MAP_HPP
+#define INCLUDED_SRC_OTHER_TOOLS_REPO_MAP_REPOS_TO_SETUP_MAP_HPP
+
+#include "src/buildtool/build_engine/expression/configuration.hpp"
+#include "src/other_tools/root_maps/commit_git_map.hpp"
+#include "src/other_tools/root_maps/content_git_map.hpp"
+#include "src/other_tools/root_maps/distdir_git_map.hpp"
+#include "src/other_tools/root_maps/fpath_git_map.hpp"
+
+/// \brief Maps a global repo name to a JSON object containing the workspace
+/// root and the TAKE_OVER fields.
+using ReposToSetupMap = AsyncMapConsumer<std::string, nlohmann::json>;
+
+auto CreateReposToSetupMap(std::shared_ptr<Configuration> const& config,
+ std::optional<std::string> const& main,
+ bool interactive,
+ gsl::not_null<CommitGitMap*> const& commit_git_map,
+ gsl::not_null<ContentGitMap*> const& content_git_map,
+ gsl::not_null<FilePathGitMap*> const& fpath_git_map,
+ gsl::not_null<ContentCASMap*> const& content_cas_map,
+ gsl::not_null<DistdirGitMap*> const& distdir_git_map,
+ std::size_t jobs) -> ReposToSetupMap;
+
+#endif // INCLUDED_SRC_OTHER_TOOLS_REPO_MAP_REPOS_TO_SETUP_MAP_HPP \ No newline at end of file