// Copyright 2023 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/buildtool/main/diagnose.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fmt/core.h" #include "gsl/gsl" #include "nlohmann/json.hpp" #include "src/buildtool/build_engine/analysed_target/analysed_target.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/build_engine/expression/target_result.hpp" #include "src/buildtool/build_engine/target_map/configured_target.hpp" #include "src/buildtool/build_engine/target_map/result_map.hpp" #include "src/buildtool/logging/log_level.hpp" #include "src/buildtool/logging/logger.hpp" #include "src/utils/cpp/json.hpp" namespace { namespace Base = BuildMaps::Base; namespace Target = BuildMaps::Target; [[nodiscard]] auto ResultToJson(TargetResult const& result) -> nlohmann::json { return nlohmann::ordered_json{ {"artifacts", result.artifact_stage->ToJson( Expression::JsonMode::SerializeAllButNodes)}, {"runfiles", result.runfiles->ToJson(Expression::JsonMode::SerializeAllButNodes)}, {"provides", result.provides->ToJson(Expression::JsonMode::SerializeAllButNodes)}}; } [[nodiscard]] auto TargetActionsToJson(AnalysedTargetPtr const& target) -> nlohmann::json { auto actions = nlohmann::json::array(); std::for_each(target->Actions().begin(), target->Actions().end(), [&actions](auto const& action) { actions.push_back(action->ToJson()); }); return actions; } [[nodiscard]] auto TreesToJson(AnalysedTargetPtr const& target) -> nlohmann::json { auto trees = nlohmann::json::object(); std::for_each( target->Trees().begin(), target->Trees().end(), [&trees](auto const& tree) { trees[tree->Id()] = tree->ToJson(); }); return trees; } void DumpActions(std::string const& file_path, AnalysisResult const& result) { auto const dump_string = IndentListsOnlyUntilDepth(TargetActionsToJson(result.target), 2, 1); if (file_path == "-") { Logger::Log( LogLevel::Info, "Actions for target {}:", result.id.ToString()); std::cout << dump_string << std::endl; } else { Logger::Log(LogLevel::Info, "Dumping actions for target {} to file '{}'.", result.id.ToString(), file_path); std::ofstream os(file_path); os << dump_string << std::endl; } } void DumpBlobs(std::string const& file_path, AnalysisResult const& result) { auto blobs = nlohmann::json::array(); for (auto const& s : result.target->Blobs()) { blobs.push_back(s); } auto const dump_string = blobs.dump(2); if (file_path == "-") { Logger::Log( LogLevel::Info, "Blobs for target {}:", result.id.ToString()); std::cout << dump_string << std::endl; } else { Logger::Log(LogLevel::Info, "Dumping blobs for target {} to file '{}'.", result.id.ToString(), file_path); std::ofstream os(file_path); os << dump_string << std::endl; } } void DumpVars(std::string const& file_path, AnalysisResult const& result) { auto vars = std::vector{}; vars.reserve(result.target->Vars().size()); for (auto const& x : result.target->Vars()) { vars.push_back(x); } std::sort(vars.begin(), vars.end()); auto const dump_string = nlohmann::json(vars).dump(); if (file_path == "-") { Logger::Log( LogLevel::Info, "Variables for target {}:", result.id.ToString()); std::cout << dump_string << std::endl; } else { Logger::Log(LogLevel::Info, "Dumping varables for target {} to file '{}'.", result.id.ToString(), file_path); std::ofstream os(file_path); os << dump_string << std::endl; } } void DumpTrees(std::string const& file_path, AnalysisResult const& result) { auto const dump_string = TreesToJson(result.target).dump(2); if (file_path == "-") { Logger::Log( LogLevel::Info, "Trees for target {}:", result.id.ToString()); std::cout << dump_string << std::endl; } else { Logger::Log(LogLevel::Info, "Dumping trees for target {} to file '{}'.", result.id.ToString(), file_path); std::ofstream os(file_path); os << dump_string << std::endl; } } void DumpProvides(std::string const& file_path, AnalysisResult const& result) { auto const dump_string = result.target->Result() .provides->ToJson(Expression::JsonMode::SerializeAllButNodes) .dump(2); if (file_path == "-") { Logger::Log(LogLevel::Info, "Provides map for target {}:", result.id.ToString()); std::cout << dump_string << std::endl; } else { Logger::Log(LogLevel::Info, "Dumping provides map for target {} to file '{}'.", result.id.ToString(), file_path); std::ofstream os(file_path); os << dump_string << std::endl; } } void DumpTargets(std::string const& file_path, std::vector const& target_ids, std::string const& target_qualifier = "") { auto repo_map = nlohmann::json::object(); auto conf_list = [&repo_map](Base::EntityName const& ref) -> nlohmann::json& { if (ref.IsAnonymousTarget()) { auto const& anon = ref.GetAnonymousTarget(); auto& anon_map = repo_map[Base::EntityName::kAnonymousMarker]; auto& rule_map = anon_map[anon.rule_map.ToIdentifier()]; return rule_map[anon.target_node.ToIdentifier()]; } auto const& named = ref.GetNamedTarget(); auto& location_map = repo_map[Base::EntityName::kLocationMarker]; auto& module_map = location_map[named.repository]; auto& target_map = module_map[named.module]; return target_map[named.name]; }; std::for_each( target_ids.begin(), target_ids.end(), [&conf_list](auto const& id) { if ((not id.target.IsNamedTarget()) or id.target.GetNamedTarget().reference_t == BuildMaps::Base::ReferenceType::kTarget) { conf_list(id.target).push_back(id.config.ToJson()); } }); auto const dump_string = IndentListsOnlyUntilDepth(repo_map, 2); if (file_path == "-") { Logger::Log( LogLevel::Info, "List of analysed {}targets:", target_qualifier); std::cout << dump_string << std::endl; } else { Logger::Log(LogLevel::Info, "Dumping list of analysed {}targets to file '{}'.", target_qualifier, file_path); std::ofstream os(file_path); os << dump_string << std::endl; } } auto DumpExpressionToMap(gsl::not_null const& map, ExpressionPtr const& expr) -> bool { auto const& id = expr->ToIdentifier(); if (not map->contains(id)) { (*map)[id] = expr->ToJson(); return true; } return false; } void DumpNodesInExpressionToMap(gsl::not_null const& map, ExpressionPtr const& expr) { if (expr->IsNode()) { if (DumpExpressionToMap(map, expr)) { auto const& node = expr->Node(); if (node.IsAbstract()) { DumpNodesInExpressionToMap(map, node.GetAbstract().target_fields); } else if (node.IsValue()) { DumpNodesInExpressionToMap(map, node.GetValue()); } } } else if (expr->IsList()) { for (auto const& entry : expr->List()) { DumpNodesInExpressionToMap(map, entry); } } else if (expr->IsMap()) { for (auto const& [_, value] : expr->Map()) { DumpNodesInExpressionToMap(map, value); } } else if (expr->IsResult()) { DumpNodesInExpressionToMap(map, expr->Result().provides); } } void DumpAnonymous(std::string const& file_path, std::vector const& target_ids) { auto anon_map = nlohmann::json{{"nodes", nlohmann::json::object()}, {"rule_maps", nlohmann::json::object()}}; std::for_each( target_ids.begin(), target_ids.end(), [&anon_map](auto const& id) { if (id.target.IsAnonymousTarget()) { auto const& anon_t = id.target.GetAnonymousTarget(); DumpExpressionToMap(&anon_map["rule_maps"], anon_t.rule_map); DumpNodesInExpressionToMap(&anon_map["nodes"], anon_t.target_node); } }); auto const dump_string = IndentListsOnlyUntilDepth(anon_map, 2); if (file_path == "-") { Logger::Log(LogLevel::Info, "List of anonymous target data:"); std::cout << dump_string << std::endl; } else { Logger::Log(LogLevel::Info, "Dumping list of anonymous target data to file '{}'.", file_path); std::ofstream os(file_path); os << dump_string << std::endl; } } void DumpNodes(std::string const& file_path, AnalysisResult const& result) { auto node_map = nlohmann::json::object(); DumpNodesInExpressionToMap(&node_map, result.target->Provides()); auto const dump_string = IndentListsOnlyUntilDepth(node_map, 2); if (file_path == "-") { Logger::Log( LogLevel::Info, "Target nodes of target {}:", result.id.ToString()); std::cout << dump_string << std::endl; } else { Logger::Log(LogLevel::Info, "Dumping target nodes of target {} to file '{}'.", result.id.ToString(), file_path); std::ofstream os(file_path); os << dump_string << std::endl; } } void DumpResult(std::string const& file_path, AnalysisResult const& result) { auto const dump_string = ResultToJson(result.target->Result()).dump(); if (file_path == "-") { Logger::Log( LogLevel::Info, "Result of target {}:", result.id.ToString()); std::cout << dump_string << std::endl; } else { Logger::Log(LogLevel::Info, "Dumping result of target {} to file '{}'.", result.id.ToString(), file_path); std::ofstream os{file_path}; os << dump_string << std::endl; } } } // namespace void DiagnoseResults(AnalysisResult const& result, DiagnosticArguments const& clargs) { Logger::Log( LogLevel::Info, "Result of{} target {}: {}", result.modified ? fmt::format(" input of action {} of", *result.modified) : "", result.id.ToString(), IndentOnlyUntilDepth( ResultToJson(result.target->Result()), 2, 2, std::unordered_map{{"/provides", 3}})); if (clargs.dump_result) { DumpResult(*clargs.dump_result, result); } if (clargs.dump_actions) { DumpActions(*clargs.dump_actions, result); } if (clargs.dump_blobs) { DumpBlobs(*clargs.dump_blobs, result); } if (clargs.dump_trees) { DumpTrees(*clargs.dump_trees, result); } if (clargs.dump_provides) { DumpProvides(*clargs.dump_provides, result); } if (clargs.dump_vars) { DumpVars(*clargs.dump_vars, result); } if (clargs.dump_targets) { DumpTargets(*clargs.dump_targets, result.result_map.ConfiguredTargets()); } if (clargs.dump_export_targets) { DumpTargets(*clargs.dump_export_targets, result.result_map.ExportTargets(), "export "); } if (clargs.dump_targets_graph) { auto graph = result.result_map.ConfiguredTargetsGraph().dump(2); Logger::Log(LogLevel::Info, "Dumping graph of configured-targets to file {}.", *clargs.dump_targets_graph); std::ofstream os(*clargs.dump_targets_graph); os << graph << std::endl; } if (clargs.dump_anonymous) { DumpAnonymous(*clargs.dump_anonymous, result.result_map.ConfiguredTargets()); } if (clargs.dump_nodes) { DumpNodes(*clargs.dump_nodes, result); } }