summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buildtool/main/TARGETS27
-rw-r--r--src/buildtool/main/cli.cpp209
-rw-r--r--src/buildtool/main/cli.hpp56
-rw-r--r--src/buildtool/main/diagnose.cpp314
-rw-r--r--src/buildtool/main/diagnose.hpp25
-rw-r--r--src/buildtool/main/main.cpp513
6 files changed, 631 insertions, 513 deletions
diff --git a/src/buildtool/main/TARGETS b/src/buildtool/main/TARGETS
index b74a5fe4..974c0e61 100644
--- a/src/buildtool/main/TARGETS
+++ b/src/buildtool/main/TARGETS
@@ -4,8 +4,7 @@
, "name": ["just"]
, "srcs": ["main.cpp"]
, "private-deps":
- [ ["src/buildtool/common", "cli"]
- , ["src/buildtool/common", "config"]
+ [ ["src/buildtool/common", "config"]
, ["src/buildtool/storage", "storage"]
, ["src/buildtool/compatibility", "compatibility"]
, ["src/buildtool/graph_traverser", "graph_traverser"]
@@ -24,10 +23,12 @@
, ["src/buildtool/execution_api/local", "config"]
, ["src/buildtool/execution_api/remote", "config"]
, "common"
+ , "cli"
, "version"
, "analyse"
, "install_cas"
, "describe"
+ , "diagnose"
, "constants"
]
, "stage": ["src", "buildtool", "main"]
@@ -68,6 +69,15 @@
, "hdrs": ["exit_codes.hpp"]
, "stage": ["src", "buildtool", "main"]
}
+, "cli":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["cli"]
+ , "hdrs": ["cli.hpp"]
+ , "srcs": ["cli.cpp"]
+ , "stage": ["src", "buildtool", "main"]
+ , "deps": [["src/buildtool/common", "cli"]]
+ , "private-deps": [["@", "gsl", "", "gsl"], "common"]
+ }
, "install_cas":
{ "type": ["@", "rules", "CC", "library"]
, "name": ["install_cas"]
@@ -110,6 +120,19 @@
, ["src/buildtool/build_engine/target_map", "target_map"]
]
}
+, "diagnose":
+ { "type": ["@", "rules", "CC", "library"]
+ , "name": ["diagnose"]
+ , "hdrs": ["diagnose.hpp"]
+ , "srcs": ["diagnose.cpp"]
+ , "stage": ["src", "buildtool", "main"]
+ , "deps":
+ [ "analyse"
+ , ["src/buildtool/common", "cli"]
+ , ["src/buildtool/build_engine/target_map", "result_map"]
+ ]
+ , "private-deps": [["src/utils/cpp", "json"], ["@", "json", "", "json"]]
+ }
, "version":
{ "type": ["@", "rules", "CC", "library"]
, "arguments_config": ["SOURCE_DATE_EPOCH", "VERSION_EXTRA_SUFFIX"]
diff --git a/src/buildtool/main/cli.cpp b/src/buildtool/main/cli.cpp
new file mode 100644
index 00000000..cb53acde
--- /dev/null
+++ b/src/buildtool/main/cli.cpp
@@ -0,0 +1,209 @@
+// 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/cli.hpp"
+
+#include "src/buildtool/main/exit_codes.hpp"
+
+#include <gsl/gsl>
+
+namespace {
+
+/// \brief Setup arguments for sub command "just describe".
+auto SetupDescribeCommandArguments(
+ gsl::not_null<CLI::App*> const& app,
+ gsl::not_null<CommandLineArguments*> const& clargs) {
+ SetupCommonArguments(app, &clargs->common);
+ SetupAnalysisArguments(app, &clargs->analysis, false);
+ SetupLogArguments(app, &clargs->log);
+ SetupDescribeArguments(app, &clargs->describe);
+}
+
+/// \brief Setup arguments for sub command "just analyse".
+auto SetupAnalyseCommandArguments(
+ gsl::not_null<CLI::App*> const& app,
+ gsl::not_null<CommandLineArguments*> const& clargs) {
+ SetupCommonArguments(app, &clargs->common);
+ SetupLogArguments(app, &clargs->log);
+ SetupAnalysisArguments(app, &clargs->analysis);
+ SetupCacheArguments(app, &clargs->endpoint);
+ SetupEndpointArguments(app, &clargs->endpoint);
+ SetupDiagnosticArguments(app, &clargs->diagnose);
+ SetupCompatibilityArguments(app);
+}
+
+/// \brief Setup arguments for sub command "just build".
+auto SetupBuildCommandArguments(
+ gsl::not_null<CLI::App*> const& app,
+ gsl::not_null<CommandLineArguments*> const& clargs) {
+ SetupCommonArguments(app, &clargs->common);
+ SetupLogArguments(app, &clargs->log);
+ SetupAnalysisArguments(app, &clargs->analysis);
+ SetupCacheArguments(app, &clargs->endpoint);
+ SetupEndpointArguments(app, &clargs->endpoint);
+ SetupCommonAuthArguments(app, &clargs->auth);
+ SetupClientAuthArguments(app, &clargs->cauth);
+ SetupCommonBuildArguments(app, &clargs->build);
+ SetupBuildArguments(app, &clargs->build);
+ SetupCompatibilityArguments(app);
+}
+
+/// \brief Setup arguments for sub command "just install".
+auto SetupInstallCommandArguments(
+ gsl::not_null<CLI::App*> const& app,
+ gsl::not_null<CommandLineArguments*> const& clargs) {
+ SetupBuildCommandArguments(app, clargs); // same as build
+ SetupStageArguments(app, &clargs->stage); // plus stage
+}
+
+/// \brief Setup arguments for sub command "just rebuild".
+auto SetupRebuildCommandArguments(
+ gsl::not_null<CLI::App*> const& app,
+ gsl::not_null<CommandLineArguments*> const& clargs) {
+ SetupBuildCommandArguments(app, clargs); // same as build
+ SetupRebuildArguments(app, &clargs->rebuild); // plus rebuild
+}
+
+/// \brief Setup arguments for sub command "just install-cas".
+auto SetupInstallCasCommandArguments(
+ gsl::not_null<CLI::App*> const& app,
+ gsl::not_null<CommandLineArguments*> const& clargs) {
+ SetupCompatibilityArguments(app);
+ SetupCacheArguments(app, &clargs->endpoint);
+ SetupEndpointArguments(app, &clargs->endpoint);
+ SetupCommonAuthArguments(app, &clargs->auth);
+ SetupClientAuthArguments(app, &clargs->cauth);
+ SetupFetchArguments(app, &clargs->fetch);
+ SetupLogArguments(app, &clargs->log);
+}
+
+/// \brief Setup arguments for sub command "just traverse".
+auto SetupTraverseCommandArguments(
+ gsl::not_null<CLI::App*> const& app,
+ gsl::not_null<CommandLineArguments*> const& clargs) {
+ SetupCommonArguments(app, &clargs->common);
+ SetupLogArguments(app, &clargs->log);
+ SetupCacheArguments(app, &clargs->endpoint);
+ SetupEndpointArguments(app, &clargs->endpoint);
+ SetupCommonAuthArguments(app, &clargs->auth);
+ SetupClientAuthArguments(app, &clargs->cauth);
+ SetupGraphArguments(app, &clargs->graph); // instead of analysis
+ SetupCommonBuildArguments(app, &clargs->build);
+ SetupBuildArguments(app, &clargs->build);
+ SetupStageArguments(app, &clargs->stage);
+ SetupCompatibilityArguments(app);
+}
+
+/// \brief Setup arguments for sub command "just gc".
+auto SetupGcCommandArguments(
+ gsl::not_null<CLI::App*> const& app,
+ gsl::not_null<CommandLineArguments*> const& clargs) {
+ SetupLogArguments(app, &clargs->log);
+ SetupCacheArguments(app, &clargs->endpoint);
+}
+
+/// \brief Setup arguments for sub command "just execute".
+auto SetupExecutionServiceCommandArguments(
+ gsl::not_null<CLI::App*> const& app,
+ gsl::not_null<CommandLineArguments*> const& clargs) {
+ SetupCompatibilityArguments(app);
+ SetupCommonBuildArguments(app, &clargs->build);
+ SetupCacheArguments(app, &clargs->endpoint);
+ SetupExecutionServiceArguments(app, &clargs->es);
+ SetupLogArguments(app, &clargs->log);
+ SetupCommonAuthArguments(app, &clargs->auth);
+ SetupServerAuthArguments(app, &clargs->sauth);
+}
+} // namespace
+
+auto ParseCommandLineArguments(int argc, char const* const* argv)
+ -> CommandLineArguments {
+ CLI::App app("just, a generic build tool");
+ app.option_defaults()->take_last();
+
+ auto* cmd_version = app.add_subcommand(
+ "version", "Print version information in JSON format.");
+ auto* cmd_describe = app.add_subcommand(
+ "describe", "Describe the rule generating a target.");
+ auto* cmd_analyse =
+ app.add_subcommand("analyse", "Analyse specified targets.");
+ auto* cmd_build = app.add_subcommand("build", "Build specified targets.");
+ auto* cmd_install =
+ app.add_subcommand("install", "Build and stage specified targets.");
+ auto* cmd_rebuild = app.add_subcommand(
+ "rebuild", "Rebuild and compare artifacts to cached build.");
+ auto* cmd_install_cas =
+ app.add_subcommand("install-cas", "Fetch and stage artifact from CAS.");
+ auto* cmd_gc =
+ app.add_subcommand("gc", "Trigger garbage collection of local cache.");
+ auto* cmd_execution = app.add_subcommand(
+ "execute", "Start single node execution service on this machine.");
+ auto* cmd_traverse =
+ app.group("") // group for creating hidden options
+ ->add_subcommand("traverse",
+ "Build and stage artifacts from graph file.");
+ app.require_subcommand(1);
+
+ CommandLineArguments clargs;
+ SetupDescribeCommandArguments(cmd_describe, &clargs);
+ SetupAnalyseCommandArguments(cmd_analyse, &clargs);
+ SetupBuildCommandArguments(cmd_build, &clargs);
+ SetupInstallCommandArguments(cmd_install, &clargs);
+ SetupRebuildCommandArguments(cmd_rebuild, &clargs);
+ SetupInstallCasCommandArguments(cmd_install_cas, &clargs);
+ SetupTraverseCommandArguments(cmd_traverse, &clargs);
+ SetupGcCommandArguments(cmd_gc, &clargs);
+ SetupExecutionServiceCommandArguments(cmd_execution, &clargs);
+ try {
+ app.parse(argc, argv);
+ } catch (CLI::Error& e) {
+ std::exit(app.exit(e));
+ } catch (std::exception const& ex) {
+ Logger::Log(LogLevel::Error, "Command line parse error: {}", ex.what());
+ std::exit(kExitFailure);
+ }
+
+ if (*cmd_version) {
+ clargs.cmd = SubCommand::kVersion;
+ }
+ else if (*cmd_describe) {
+ clargs.cmd = SubCommand::kDescribe;
+ }
+ else if (*cmd_analyse) {
+ clargs.cmd = SubCommand::kAnalyse;
+ }
+ else if (*cmd_build) {
+ clargs.cmd = SubCommand::kBuild;
+ }
+ else if (*cmd_install) {
+ clargs.cmd = SubCommand::kInstall;
+ }
+ else if (*cmd_rebuild) {
+ clargs.cmd = SubCommand::kRebuild;
+ }
+ else if (*cmd_install_cas) {
+ clargs.cmd = SubCommand::kInstallCas;
+ }
+ else if (*cmd_traverse) {
+ clargs.cmd = SubCommand::kTraverse;
+ }
+ else if (*cmd_gc) {
+ clargs.cmd = SubCommand::kGc;
+ }
+ else if (*cmd_execution) {
+ clargs.cmd = SubCommand::kExecute;
+ }
+
+ return clargs;
+}
diff --git a/src/buildtool/main/cli.hpp b/src/buildtool/main/cli.hpp
new file mode 100644
index 00000000..7a580ff6
--- /dev/null
+++ b/src/buildtool/main/cli.hpp
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef INCLUDED_SRC_BUILDTOOL_MAIN_CLI
+#define INCLUDED_SRC_BUILDTOOL_MAIN_CLI
+
+#include "src/buildtool/common/cli.hpp"
+
+enum class SubCommand {
+ kUnknown,
+ kVersion,
+ kDescribe,
+ kAnalyse,
+ kBuild,
+ kInstall,
+ kRebuild,
+ kInstallCas,
+ kTraverse,
+ kGc,
+ kExecute
+};
+
+struct CommandLineArguments {
+ SubCommand cmd{SubCommand::kUnknown};
+ CommonArguments common;
+ LogArguments log;
+ AnalysisArguments analysis;
+ DescribeArguments describe;
+ DiagnosticArguments diagnose;
+ EndpointArguments endpoint;
+ BuildArguments build;
+ StageArguments stage;
+ RebuildArguments rebuild;
+ FetchArguments fetch;
+ GraphArguments graph;
+ CommonAuthArguments auth;
+ ClientAuthArguments cauth;
+ ServerAuthArguments sauth;
+ ExecutionServiceArguments es;
+};
+
+auto ParseCommandLineArguments(int argc, char const* const* argv)
+ -> CommandLineArguments;
+
+#endif
diff --git a/src/buildtool/main/diagnose.cpp b/src/buildtool/main/diagnose.cpp
new file mode 100644
index 00000000..1c3552cd
--- /dev/null
+++ b/src/buildtool/main/diagnose.cpp
@@ -0,0 +1,314 @@
+// 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 "nlohmann/json.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<std::string>{};
+ 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 DumpTargets(std::string const& file_path,
+ std::vector<Target::ConfiguredTarget> 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<nlohmann::json*> const& map,
+ ExpressionPtr const& expr) -> bool {
+ auto const& id = expr->ToIdentifier();
+ if (not map->contains(id)) {
+ (*map)[id] = expr->ToJson();
+ return true;
+ }
+ return false;
+}
+
+// NOLINTNEXTLINE(misc-no-recursion)
+void DumpNodesInExpressionToMap(gsl::not_null<nlohmann::json*> 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<Target::ConfiguredTarget> 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;
+ }
+}
+} // namespace
+
+void DiagnoseResults(AnalysisResult const& result,
+ BuildMaps::Target::ResultTargetMap const& result_map,
+ 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<std::string, std::size_t>{{"/provides", 3}}));
+ 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_vars) {
+ DumpVars(*clargs.dump_vars, result);
+ }
+ if (clargs.dump_targets) {
+ DumpTargets(*clargs.dump_targets, result_map.ConfiguredTargets());
+ }
+ if (clargs.dump_export_targets) {
+ DumpTargets(
+ *clargs.dump_export_targets, result_map.ExportTargets(), "export ");
+ }
+ if (clargs.dump_targets_graph) {
+ auto graph = 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_map.ConfiguredTargets());
+ }
+ if (clargs.dump_nodes) {
+ DumpNodes(*clargs.dump_nodes, result);
+ }
+}
diff --git a/src/buildtool/main/diagnose.hpp b/src/buildtool/main/diagnose.hpp
new file mode 100644
index 00000000..79a150b8
--- /dev/null
+++ b/src/buildtool/main/diagnose.hpp
@@ -0,0 +1,25 @@
+// 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.
+
+#ifndef INCLUDED_SRC_BUILDTOOL_MAIN_DIAGNOSE_HPP
+#define INCLUDED_SRC_BUILDTOOL_MAIN_DIAGNOSE_HPP
+
+#include "src/buildtool/build_engine/target_map/result_map.hpp"
+#include "src/buildtool/common/cli.hpp"
+#include "src/buildtool/main/analyse.hpp"
+
+void DiagnoseResults(AnalysisResult const& result,
+ BuildMaps::Target::ResultTargetMap const& result_map,
+ DiagnosticArguments const& clargs);
+#endif
diff --git a/src/buildtool/main/main.cpp b/src/buildtool/main/main.cpp
index 8d2d4d2e..e362b7ef 100644
--- a/src/buildtool/main/main.cpp
+++ b/src/buildtool/main/main.cpp
@@ -26,13 +26,14 @@
#include "src/buildtool/build_engine/expression/expression.hpp"
#include "src/buildtool/build_engine/target_map/target_map.hpp"
#include "src/buildtool/common/artifact_description.hpp"
-#include "src/buildtool/common/cli.hpp"
#include "src/buildtool/common/repository_config.hpp"
#include "src/buildtool/compatibility/compatibility.hpp"
#include "src/buildtool/execution_api/local/config.hpp"
#include "src/buildtool/main/analyse.hpp"
+#include "src/buildtool/main/cli.hpp"
#include "src/buildtool/main/constants.hpp"
#include "src/buildtool/main/describe.hpp"
+#include "src/buildtool/main/diagnose.hpp"
#include "src/buildtool/main/exit_codes.hpp"
#include "src/buildtool/main/install_cas.hpp"
#include "src/buildtool/storage/config.hpp"
@@ -63,226 +64,6 @@ namespace {
namespace Base = BuildMaps::Base;
namespace Target = BuildMaps::Target;
-enum class SubCommand {
- kUnknown,
- kVersion,
- kDescribe,
- kAnalyse,
- kBuild,
- kInstall,
- kRebuild,
- kInstallCas,
- kTraverse,
- kGc,
- kExecute
-};
-
-struct CommandLineArguments {
- SubCommand cmd{SubCommand::kUnknown};
- CommonArguments common;
- LogArguments log;
- AnalysisArguments analysis;
- DescribeArguments describe;
- DiagnosticArguments diagnose;
- EndpointArguments endpoint;
- BuildArguments build;
- StageArguments stage;
- RebuildArguments rebuild;
- FetchArguments fetch;
- GraphArguments graph;
- CommonAuthArguments auth;
- ClientAuthArguments cauth;
- ServerAuthArguments sauth;
- ExecutionServiceArguments es;
-};
-
-/// \brief Setup arguments for sub command "just describe".
-auto SetupDescribeCommandArguments(
- gsl::not_null<CLI::App*> const& app,
- gsl::not_null<CommandLineArguments*> const& clargs) {
- SetupCommonArguments(app, &clargs->common);
- SetupAnalysisArguments(app, &clargs->analysis, false);
- SetupLogArguments(app, &clargs->log);
- SetupDescribeArguments(app, &clargs->describe);
-}
-
-/// \brief Setup arguments for sub command "just analyse".
-auto SetupAnalyseCommandArguments(
- gsl::not_null<CLI::App*> const& app,
- gsl::not_null<CommandLineArguments*> const& clargs) {
- SetupCommonArguments(app, &clargs->common);
- SetupLogArguments(app, &clargs->log);
- SetupAnalysisArguments(app, &clargs->analysis);
- SetupCacheArguments(app, &clargs->endpoint);
- SetupEndpointArguments(app, &clargs->endpoint);
- SetupDiagnosticArguments(app, &clargs->diagnose);
- SetupCompatibilityArguments(app);
-}
-
-/// \brief Setup arguments for sub command "just build".
-auto SetupBuildCommandArguments(
- gsl::not_null<CLI::App*> const& app,
- gsl::not_null<CommandLineArguments*> const& clargs) {
- SetupCommonArguments(app, &clargs->common);
- SetupLogArguments(app, &clargs->log);
- SetupAnalysisArguments(app, &clargs->analysis);
- SetupCacheArguments(app, &clargs->endpoint);
- SetupEndpointArguments(app, &clargs->endpoint);
- SetupCommonAuthArguments(app, &clargs->auth);
- SetupClientAuthArguments(app, &clargs->cauth);
- SetupCommonBuildArguments(app, &clargs->build);
- SetupBuildArguments(app, &clargs->build);
- SetupCompatibilityArguments(app);
-}
-
-/// \brief Setup arguments for sub command "just install".
-auto SetupInstallCommandArguments(
- gsl::not_null<CLI::App*> const& app,
- gsl::not_null<CommandLineArguments*> const& clargs) {
- SetupBuildCommandArguments(app, clargs); // same as build
- SetupStageArguments(app, &clargs->stage); // plus stage
-}
-
-/// \brief Setup arguments for sub command "just rebuild".
-auto SetupRebuildCommandArguments(
- gsl::not_null<CLI::App*> const& app,
- gsl::not_null<CommandLineArguments*> const& clargs) {
- SetupBuildCommandArguments(app, clargs); // same as build
- SetupRebuildArguments(app, &clargs->rebuild); // plus rebuild
-}
-
-/// \brief Setup arguments for sub command "just install-cas".
-auto SetupInstallCasCommandArguments(
- gsl::not_null<CLI::App*> const& app,
- gsl::not_null<CommandLineArguments*> const& clargs) {
- SetupCompatibilityArguments(app);
- SetupCacheArguments(app, &clargs->endpoint);
- SetupEndpointArguments(app, &clargs->endpoint);
- SetupCommonAuthArguments(app, &clargs->auth);
- SetupClientAuthArguments(app, &clargs->cauth);
- SetupFetchArguments(app, &clargs->fetch);
- SetupLogArguments(app, &clargs->log);
-}
-
-/// \brief Setup arguments for sub command "just traverse".
-auto SetupTraverseCommandArguments(
- gsl::not_null<CLI::App*> const& app,
- gsl::not_null<CommandLineArguments*> const& clargs) {
- SetupCommonArguments(app, &clargs->common);
- SetupLogArguments(app, &clargs->log);
- SetupCacheArguments(app, &clargs->endpoint);
- SetupEndpointArguments(app, &clargs->endpoint);
- SetupCommonAuthArguments(app, &clargs->auth);
- SetupClientAuthArguments(app, &clargs->cauth);
- SetupGraphArguments(app, &clargs->graph); // instead of analysis
- SetupCommonBuildArguments(app, &clargs->build);
- SetupBuildArguments(app, &clargs->build);
- SetupStageArguments(app, &clargs->stage);
- SetupCompatibilityArguments(app);
-}
-
-/// \brief Setup arguments for sub command "just gc".
-auto SetupGcCommandArguments(
- gsl::not_null<CLI::App*> const& app,
- gsl::not_null<CommandLineArguments*> const& clargs) {
- SetupLogArguments(app, &clargs->log);
- SetupCacheArguments(app, &clargs->endpoint);
-}
-
-/// \brief Setup arguments for sub command "just execute".
-auto SetupExecutionServiceCommandArguments(
- gsl::not_null<CLI::App*> const& app,
- gsl::not_null<CommandLineArguments*> const& clargs) {
- SetupCompatibilityArguments(app);
- SetupCommonBuildArguments(app, &clargs->build);
- SetupCacheArguments(app, &clargs->endpoint);
- SetupExecutionServiceArguments(app, &clargs->es);
- SetupLogArguments(app, &clargs->log);
- SetupCommonAuthArguments(app, &clargs->auth);
- SetupServerAuthArguments(app, &clargs->sauth);
-}
-
-auto ParseCommandLineArguments(int argc, char const* const* argv)
- -> CommandLineArguments {
- CLI::App app("just, a generic build tool");
- app.option_defaults()->take_last();
-
- auto* cmd_version = app.add_subcommand(
- "version", "Print version information in JSON format.");
- auto* cmd_describe = app.add_subcommand(
- "describe", "Describe the rule generating a target.");
- auto* cmd_analyse =
- app.add_subcommand("analyse", "Analyse specified targets.");
- auto* cmd_build = app.add_subcommand("build", "Build specified targets.");
- auto* cmd_install =
- app.add_subcommand("install", "Build and stage specified targets.");
- auto* cmd_rebuild = app.add_subcommand(
- "rebuild", "Rebuild and compare artifacts to cached build.");
- auto* cmd_install_cas =
- app.add_subcommand("install-cas", "Fetch and stage artifact from CAS.");
- auto* cmd_gc =
- app.add_subcommand("gc", "Trigger garbage collection of local cache.");
- auto* cmd_execution = app.add_subcommand(
- "execute", "Start single node execution service on this machine.");
- auto* cmd_traverse =
- app.group("") // group for creating hidden options
- ->add_subcommand("traverse",
- "Build and stage artifacts from graph file.");
- app.require_subcommand(1);
-
- CommandLineArguments clargs;
- SetupDescribeCommandArguments(cmd_describe, &clargs);
- SetupAnalyseCommandArguments(cmd_analyse, &clargs);
- SetupBuildCommandArguments(cmd_build, &clargs);
- SetupInstallCommandArguments(cmd_install, &clargs);
- SetupRebuildCommandArguments(cmd_rebuild, &clargs);
- SetupInstallCasCommandArguments(cmd_install_cas, &clargs);
- SetupTraverseCommandArguments(cmd_traverse, &clargs);
- SetupGcCommandArguments(cmd_gc, &clargs);
- SetupExecutionServiceCommandArguments(cmd_execution, &clargs);
- try {
- app.parse(argc, argv);
- } catch (CLI::Error& e) {
- std::exit(app.exit(e));
- } catch (std::exception const& ex) {
- Logger::Log(LogLevel::Error, "Command line parse error: {}", ex.what());
- std::exit(kExitFailure);
- }
-
- if (*cmd_version) {
- clargs.cmd = SubCommand::kVersion;
- }
- else if (*cmd_describe) {
- clargs.cmd = SubCommand::kDescribe;
- }
- else if (*cmd_analyse) {
- clargs.cmd = SubCommand::kAnalyse;
- }
- else if (*cmd_build) {
- clargs.cmd = SubCommand::kBuild;
- }
- else if (*cmd_install) {
- clargs.cmd = SubCommand::kInstall;
- }
- else if (*cmd_rebuild) {
- clargs.cmd = SubCommand::kRebuild;
- }
- else if (*cmd_install_cas) {
- clargs.cmd = SubCommand::kInstallCas;
- }
- else if (*cmd_traverse) {
- clargs.cmd = SubCommand::kTraverse;
- }
- else if (*cmd_gc) {
- clargs.cmd = SubCommand::kGc;
- }
- else if (*cmd_execution) {
- clargs.cmd = SubCommand::kExecute;
- }
-
- return clargs;
-}
-
void SetupDefaultLogging() {
LogConfig::SetLogLimit(kDefaultLogLevel);
LogConfig::SetSinks({LogSinkCmdLine::CreateFactory()});
@@ -911,296 +692,6 @@ auto DetermineRoots(CommonArguments const& cargs,
return {main_repo, main_ws_root};
}
-[[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<std::string>{};
- 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 DumpTargets(std::string const& file_path,
- std::vector<Target::ConfiguredTarget> 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<nlohmann::json*> const& map,
- ExpressionPtr const& expr) -> bool {
- auto const& id = expr->ToIdentifier();
- if (not map->contains(id)) {
- (*map)[id] = expr->ToJson();
- return true;
- }
- return false;
-}
-
-// NOLINTNEXTLINE(misc-no-recursion)
-void DumpNodesInExpressionToMap(gsl::not_null<nlohmann::json*> 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<Target::ConfiguredTarget> 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;
- }
-}
-
-[[nodiscard]] auto DiagnoseResults(AnalysisResult const& result,
- Target::ResultTargetMap const& result_map,
- 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<std::string, std::size_t>{{"/provides", 3}}));
- 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_vars) {
- DumpVars(*clargs.dump_vars, result);
- }
- if (clargs.dump_targets) {
- DumpTargets(*clargs.dump_targets, result_map.ConfiguredTargets());
- }
- if (clargs.dump_export_targets) {
- DumpTargets(
- *clargs.dump_export_targets, result_map.ExportTargets(), "export ");
- }
- if (clargs.dump_targets_graph) {
- auto graph = 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_map.ConfiguredTargets());
- }
- if (clargs.dump_nodes) {
- DumpNodes(*clargs.dump_nodes, result);
- }
-}
-
// Return disjoint maps for artifacts and runfiles
[[nodiscard]] auto ReadOutputArtifacts(AnalysedTargetPtr const& target)
-> std::pair<std::map<std::string, ArtifactDescription>,