// 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_BUILDTOOL_BUILD_ENGINE_BASE_MAPS_ENTITY_NAME_HPP #define INCLUDED_SRC_BUILDTOOL_BUILD_ENGINE_BASE_MAPS_ENTITY_NAME_HPP #include #include #include #include #include #include #include "fmt/core.h" #include "gsl/gsl" #include "nlohmann/json.hpp" #include "src/buildtool/build_engine/base_maps/entity_name_data.hpp" #include "src/buildtool/build_engine/expression/expression.hpp" #include "src/buildtool/build_engine/expression/expression_ptr.hpp" #include "src/buildtool/common/repository_config.hpp" namespace BuildMaps::Base { static inline auto IsString(const nlohmann::json& x) noexcept -> bool { return x.is_string(); } static inline auto IsString(const ExpressionPtr& x) noexcept -> bool { return x->IsString(); } // for compatibility with ExpressionPtr static inline auto GetList(const nlohmann::json& x) noexcept -> nlohmann::json const& { return x; } static inline auto GetList(const ExpressionPtr& x) noexcept -> Expression::list_t const& { return x->Value()->get(); } static inline auto IsList(const nlohmann::json& x) noexcept -> bool { return x.is_array(); } static inline auto IsList(const ExpressionPtr& x) noexcept -> bool { return x->IsList(); } template auto Size(const T& x) noexcept -> std::size_t { return x.size(); } static inline auto GetString(const nlohmann::json& x) -> std::string { return x.template get(); } static inline auto GetString(const ExpressionPtr& x) -> const std::string& { return x->String(); } static inline auto ToString(const nlohmann::json& x) -> std::string { return x.dump(); } static inline auto ToString(const ExpressionPtr& x) noexcept -> std::string { return x->ToString(); } static inline auto IsNone(const nlohmann::json& x) noexcept -> bool { return x.is_null(); } static inline auto IsNone(const ExpressionPtr& x) noexcept -> bool { return x->IsNone(); } template // IsList(list) == true and Size(list) == 2 [[nodiscard]] inline auto ParseEntityName_2(T const& list, EntityName const& current) noexcept -> std::optional { try { if (IsString(list[0]) and IsString(list[1])) { return EntityName{current.GetNamedTarget().repository, GetString(list[0]), GetString(list[1])}; } return std::nullopt; } catch (...) { return std::nullopt; } } template // IsList(list) == true [[nodiscard]] inline auto ParseEntityNameFSReference( std::string const& s0, // list[0] T const& list, std::size_t const list_size, EntityName const& current, std::optional> logger = std::nullopt) noexcept -> std::optional { try { auto get_ref_type = [](std::string const& s) -> ReferenceType { if (s == EntityName::kFileLocationMarker) { return ReferenceType::kFile; } if (s == EntityName::kGlobMarker) { return ReferenceType::kGlob; } if (s == EntityName::kSymlinkLocationMarker) { return ReferenceType::kSymlink; } return ReferenceType::kTree; }; auto const ref_type = get_ref_type(s0); if (list_size == 3) { if (IsString(list[2])) { auto const& name = GetString(list[2]); auto const& x = current.GetNamedTarget(); if (IsNone(list[1])) { return EntityName{x.repository, x.module, name, ref_type}; } if (IsString(list[1])) { auto const& middle = GetString(list[1]); if (middle == "." or middle == x.module) { return EntityName{ x.repository, x.module, name, ref_type}; } } if (logger) { (*logger)( fmt::format("Invalid module name {} for file reference", ToString(list[1]))); } } } return std::nullopt; } catch (...) { return std::nullopt; } } template // IsList(list) == true // list[0] == kRelativeLocationMarker [[nodiscard]] inline auto ParseEntityNameRelative( T const& list, std::size_t const list_size, EntityName const& current, std::optional> logger = std::nullopt) noexcept -> std::optional { try { if (list_size == 3 and IsString(list[1]) and IsString(list[2])) { auto const& relmodule = GetString(list[1]); auto const& name = GetString(list[2]); std::filesystem::path m{current.GetNamedTarget().module}; auto const& module = (m / relmodule).lexically_normal().string(); if (module.compare(0, 3, "../") != 0) { return EntityName{ current.GetNamedTarget().repository, module, name}; } if (logger) { (*logger)(fmt::format( "Relative module name {} is outside of workspace", relmodule)); } } return std::nullopt; } catch (...) { return std::nullopt; } } template // IsList(list) == true // list[0] == EntityName::kLocationMarker [[nodiscard]] inline auto ParseEntityNameLocation( T const& list, std::size_t const list_size, EntityName const& current, gsl::not_null const& repo_config, std::optional> logger = std::nullopt) noexcept -> std::optional { try { if (list_size == 4 and IsString(list[1]) and IsString(list[2]) and IsString(list[3])) { auto const& local_repo_name = GetString(list[1]); auto const& module = GetString(list[2]); auto const& target = GetString(list[3]); auto const* repo_name = repo_config->GlobalName( current.GetNamedTarget().repository, local_repo_name); if (repo_name != nullptr) { return EntityName{*repo_name, module, target}; } if (logger) { (*logger)(fmt::format("Cannot resolve repository name {}", local_repo_name)); } } return std::nullopt; } catch (...) { return std::nullopt; } } template // IsList(list) == true and Size(list) >= 3 [[nodiscard]] inline auto ParseEntityName_3( T const& list, std::size_t const list_size, EntityName const& current, gsl::not_null const& repo_config, std::optional> logger = std::nullopt) noexcept -> std::optional { try { // the first entry of the list must be a string if (IsString(list[0])) { auto const& s0 = GetString(list[0]); if (s0 == EntityName::kRelativeLocationMarker) { return ParseEntityNameRelative( list, list_size, current, logger); } if (s0 == EntityName::kLocationMarker) { return ParseEntityNameLocation( list, list_size, current, repo_config, logger); } if (s0 == EntityName::kAnonymousMarker and logger) { (*logger)(fmt::format( "Parsing anonymous target is not " "supported. Identifiers of anonymous targets should be " "obtained as FIELD value of anonymous fields")); } else if (s0 == EntityName::kFileLocationMarker or s0 == EntityName::kTreeLocationMarker or s0 == EntityName::kGlobMarker or s0 == EntityName::kSymlinkLocationMarker) { return ParseEntityNameFSReference( s0, list, list_size, current, logger); } } return std::nullopt; } catch (...) { return std::nullopt; } } template [[nodiscard]] inline auto ParseEntityName( T const& source, EntityName const& current, gsl::not_null const& repo_config, std::optional> logger = std::nullopt) noexcept -> std::optional { try { std::optional res = std::nullopt; if (IsString(source)) { const auto& x = current.GetNamedTarget(); return EntityName{x.repository, x.module, GetString(source)}; } if (IsList(source)) { auto const& list = GetList(source); const auto list_size = Size(list); if (list_size == 2) { res = ParseEntityName_2(list, current); } else if (list_size >= 3) { res = ParseEntityName_3( list, list_size, current, repo_config, logger); } } if (logger and (res == std::nullopt)) { (*logger)(fmt::format("Syntactically invalid entity name: {}.", ToString(source))); } return res; } catch (...) { return std::nullopt; } } [[nodiscard]] inline auto ParseEntityNameFromJson( nlohmann::json const& json, EntityName const& current, gsl::not_null const& repo_config, std::optional> logger = std::nullopt) noexcept -> std::optional { return ParseEntityName(json, current, repo_config, std::move(logger)); } [[nodiscard]] inline auto ParseEntityNameFromExpression( ExpressionPtr const& expr, EntityName const& current, gsl::not_null const& repo_config, std::optional> logger = std::nullopt) noexcept -> std::optional { return ParseEntityName(expr, current, repo_config, std::move(logger)); } } // namespace BuildMaps::Base #endif // INCLUDED_SRC_BUILDTOOL_BUILD_ENGINE_BASE_MAPS_ENTITY_NAME_HPP