summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/buildtool/build_engine/target_map/built_in_rules.cpp171
-rw-r--r--test/buildtool/build_engine/target_map/data_targets/tree_overlay/TARGETS4
-rw-r--r--test/buildtool/build_engine/target_map/target_map.test.cpp63
3 files changed, 195 insertions, 43 deletions
diff --git a/src/buildtool/build_engine/target_map/built_in_rules.cpp b/src/buildtool/build_engine/target_map/built_in_rules.cpp
index 00a10efe..c0015b29 100644
--- a/src/buildtool/build_engine/target_map/built_in_rules.cpp
+++ b/src/buildtool/build_engine/target_map/built_in_rules.cpp
@@ -86,7 +86,6 @@ auto const kTreeRuleFields = std::unordered_set<std::string>{"arguments_config",
"name",
"tainted",
"type"};
-
auto const kInstallRuleFields =
std::unordered_set<std::string>{"arguments_config",
"deps",
@@ -445,7 +444,8 @@ void TreeRuleWithDeps(
const BuildMaps::Base::FieldReader::Ptr& desc,
const BuildMaps::Target::TargetMap::SetterPtr& setter,
const BuildMaps::Target::TargetMap::LoggerPtr& logger,
- const gsl::not_null<BuildMaps::Target::ResultTargetMap*>& result_map) {
+ const gsl::not_null<BuildMaps::Target::ResultTargetMap*>& result_map,
+ std::optional<bool> disjoint_overlay) {
auto param_vars = desc->ReadStringList("arguments_config");
if (not param_vars) {
return;
@@ -497,45 +497,75 @@ void TreeRuleWithDeps(
{},
{}};
- // Compute the stage
- auto stage = ExpressionPtr{Expression::map_t{}};
- for (auto const& dep : dependency_values) {
- auto to_stage = ExpressionPtr{
- Expression::map_t{(*dep)->RunFiles(), (*dep)->Artifacts()}};
- auto dup = stage->Map().FindConflictingDuplicate(to_stage->Map());
- if (dup) {
- std::unordered_map<BuildMaps::Base::EntityName, AnalysedTargetPtr>
- deps_by_target;
- deps_by_target.reserve(dependency_keys.size());
- for (std::size_t i = 0; i < dependency_keys.size(); ++i) {
- deps_by_target.emplace(dependency_keys[i].target,
- *dependency_values[i]);
+ // Compute the resulting stage
+ auto result_stage = Expression::map_t::underlying_map_t{};
+ std::vector<Tree::Ptr> trees{};
+ std::vector<TreeOverlay::Ptr> tree_overlays{};
+
+ if (disjoint_overlay) {
+ TreeOverlay::to_overlay_t dep_trees{};
+ for (auto const& dep : dependency_values) {
+ std::unordered_map<std::string, ArtifactDescription> tree_content;
+ for (auto const& [input_path, artifact] :
+ (*dep)->Artifacts()->Map()) {
+ auto norm_path =
+ ToNormalPath(std::filesystem::path{input_path});
+ tree_content.emplace(std::move(norm_path),
+ artifact->Artifact());
}
- ReportStagingConflict(
- dup->get(), stage, to_stage, deps_by_target, logger);
- return;
+ auto tree = std::make_shared<Tree>(std::move(tree_content));
+ auto tree_id = tree->Id();
+ trees.emplace_back(std::move(tree));
+ dep_trees.emplace_back(ArtifactDescription::CreateTree(tree_id));
+ }
+ auto overlay_tree = std::make_shared<TreeOverlay>(std::move(dep_trees),
+ *disjoint_overlay);
+ auto overlay_tree_id = overlay_tree->Id();
+ tree_overlays.emplace_back(std::move(overlay_tree));
+ result_stage.emplace(
+ name, ArtifactDescription::CreateTreeOverlay(overlay_tree_id));
+ }
+ else {
+
+ auto stage = ExpressionPtr{Expression::map_t{}};
+ for (auto const& dep : dependency_values) {
+ auto to_stage = ExpressionPtr{
+ Expression::map_t{(*dep)->RunFiles(), (*dep)->Artifacts()}};
+ auto dup = stage->Map().FindConflictingDuplicate(to_stage->Map());
+ if (dup) {
+ std::unordered_map<BuildMaps::Base::EntityName,
+ AnalysedTargetPtr>
+ deps_by_target;
+ deps_by_target.reserve(dependency_keys.size());
+ for (std::size_t i = 0; i < dependency_keys.size(); ++i) {
+ deps_by_target.emplace(dependency_keys[i].target,
+ *dependency_values[i]);
+ }
+ ReportStagingConflict(
+ dup->get(), stage, to_stage, deps_by_target, logger);
+ return;
+ }
+ stage = ExpressionPtr{Expression::map_t{stage, to_stage}};
}
- stage = ExpressionPtr{Expression::map_t{stage, to_stage}};
- }
- // Result is the associated tree, located at name
- auto conflict = BuildMaps::Target::Utils::tree_conflict(stage);
- if (conflict) {
- (*logger)(fmt::format("TREE conflict on subtree {}", *conflict), true);
- return;
- }
- std::unordered_map<std::string, ArtifactDescription> tree_content;
- tree_content.reserve(stage->Map().size());
- for (auto const& [input_path, artifact] : stage->Map()) {
- auto norm_path = ToNormalPath(std::filesystem::path{input_path});
- tree_content.emplace(std::move(norm_path), artifact->Artifact());
+ // Result is the associated tree, located at name
+ auto conflict = BuildMaps::Target::Utils::tree_conflict(stage);
+ if (conflict) {
+ (*logger)(fmt::format("TREE conflict on subtree {}", *conflict),
+ true);
+ return;
+ }
+ std::unordered_map<std::string, ArtifactDescription> tree_content;
+ tree_content.reserve(stage->Map().size());
+ for (auto const& [input_path, artifact] : stage->Map()) {
+ auto norm_path = ToNormalPath(std::filesystem::path{input_path});
+ tree_content.emplace(std::move(norm_path), artifact->Artifact());
+ }
+ auto tree = std::make_shared<Tree>(std::move(tree_content));
+ auto tree_id = tree->Id();
+ trees.emplace_back(std::move(tree));
+ result_stage.emplace(name, ArtifactDescription::CreateTree(tree_id));
}
- auto tree = std::make_shared<Tree>(std::move(tree_content));
- auto tree_id = tree->Id();
- std::vector<Tree::Ptr> trees{};
- trees.emplace_back(std::move(tree));
- auto result_stage = Expression::map_t::underlying_map_t{};
- result_stage.emplace(name, ArtifactDescription::CreateTree(tree_id));
auto result = ExpressionPtr{Expression::map_t{result_stage}};
auto analysis_result = std::make_shared<AnalysedTarget const>(
@@ -545,7 +575,7 @@ void TreeRuleWithDeps(
std::vector<ActionDescription::Ptr>{},
std::vector<std::string>{},
std::move(trees),
- std::vector<TreeOverlay::Ptr>{},
+ std::move(tree_overlays),
std::move(vars_set),
std::move(tainted),
std::move(implied_export),
@@ -555,16 +585,25 @@ void TreeRuleWithDeps(
(*setter)(std::move(analysis_result));
}
-void TreeRule(
+void CommonTreeRule(
const gsl::not_null<AnalyseContext*>& context,
const nlohmann::json& desc_json,
const BuildMaps::Target::ConfiguredTarget& key,
const BuildMaps::Target::TargetMap::SubCallerPtr& subcaller,
const BuildMaps::Target::TargetMap::SetterPtr& setter,
const BuildMaps::Target::TargetMap::LoggerPtr& logger,
- const gsl::not_null<BuildMaps::Target::ResultTargetMap*>& result_map) {
+ const gsl::not_null<BuildMaps::Target::ResultTargetMap*>& result_map,
+ std::optional<bool> disjoint_overlay) {
+ std::string rule_name;
+ if (disjoint_overlay) {
+ rule_name =
+ *disjoint_overlay ? "disjoint_tree_overlay" : "tree overlay";
+ }
+ else {
+ rule_name = "tree";
+ }
auto desc = BuildMaps::Base::FieldReader::CreatePtr(
- desc_json, key.target, "tree target", logger);
+ desc_json, key.target, fmt::format("{} target", rule_name), logger);
desc->ExpectFields(kTreeRuleFields);
auto param_vars = desc->ReadStringList("arguments_config");
if (not param_vars) {
@@ -637,7 +676,8 @@ void TreeRule(
setter,
logger,
key,
- result_map](auto const& values) {
+ result_map,
+ disjoint_overlay](auto const& values) {
TreeRuleWithDeps(values,
dependency_keys,
name,
@@ -645,11 +685,54 @@ void TreeRule(
desc,
setter,
logger,
- result_map);
+ result_map,
+ disjoint_overlay);
},
logger);
}
+void TreeRule(
+ const gsl::not_null<AnalyseContext*>& context,
+ const nlohmann::json& desc_json,
+ const BuildMaps::Target::ConfiguredTarget& key,
+ const BuildMaps::Target::TargetMap::SubCallerPtr& subcaller,
+ const BuildMaps::Target::TargetMap::SetterPtr& setter,
+ const BuildMaps::Target::TargetMap::LoggerPtr& logger,
+ const gsl::not_null<BuildMaps::Target::ResultTargetMap*>& result_map) {
+ CommonTreeRule(context,
+ desc_json,
+ key,
+ subcaller,
+ setter,
+ logger,
+ result_map,
+ std::nullopt);
+}
+
+void DisjointTreeOverlayRule(
+ const gsl::not_null<AnalyseContext*>& context,
+ const nlohmann::json& desc_json,
+ const BuildMaps::Target::ConfiguredTarget& key,
+ const BuildMaps::Target::TargetMap::SubCallerPtr& subcaller,
+ const BuildMaps::Target::TargetMap::SetterPtr& setter,
+ const BuildMaps::Target::TargetMap::LoggerPtr& logger,
+ const gsl::not_null<BuildMaps::Target::ResultTargetMap*>& result_map) {
+ CommonTreeRule(
+ context, desc_json, key, subcaller, setter, logger, result_map, true);
+}
+
+void TreeOverlayRule(
+ const gsl::not_null<AnalyseContext*>& context,
+ const nlohmann::json& desc_json,
+ const BuildMaps::Target::ConfiguredTarget& key,
+ const BuildMaps::Target::TargetMap::SubCallerPtr& subcaller,
+ const BuildMaps::Target::TargetMap::SetterPtr& setter,
+ const BuildMaps::Target::TargetMap::LoggerPtr& logger,
+ const gsl::not_null<BuildMaps::Target::ResultTargetMap*>& result_map) {
+ CommonTreeRule(
+ context, desc_json, key, subcaller, setter, logger, result_map, false);
+}
+
void InstallRuleWithDeps(
const std::vector<BuildMaps::Target::ConfiguredTarget>& dependency_keys,
const std::vector<AnalysedTargetPtr const*>& dependency_values,
@@ -1674,6 +1757,8 @@ auto const kBuiltIns = std::unordered_map<
{"export", ExportRule},
{"file_gen", FileGenRule},
{"tree", TreeRule},
+ {"tree_overlay", TreeOverlayRule},
+ {"disjoint_tree_overlay", DisjointTreeOverlayRule},
{"symlink", SymlinkRule},
{"generic", GenericRule},
{"install", InstallRule},
diff --git a/test/buildtool/build_engine/target_map/data_targets/tree_overlay/TARGETS b/test/buildtool/build_engine/target_map/data_targets/tree_overlay/TARGETS
index 088d47de..5c5dd8bf 100644
--- a/test/buildtool/build_engine/target_map/data_targets/tree_overlay/TARGETS
+++ b/test/buildtool/build_engine/target_map/data_targets/tree_overlay/TARGETS
@@ -3,4 +3,8 @@
, "disjoint empty": {"type": ["tree_overlay", "disjoint overlay"]}
, "disjoint one stage":
{"type": ["tree_overlay", "disjoint overlay"], "deps": ["x"]}
+, "built-in, one stage":
+ {"type": "tree_overlay", "name": "the_tree", "deps": ["x"]}
+, "built-in, disjoint, one stage":
+ {"type": "disjoint_tree_overlay", "name": "the_tree", "deps": ["x"]}
}
diff --git a/test/buildtool/build_engine/target_map/target_map.test.cpp b/test/buildtool/build_engine/target_map/target_map.test.cpp
index 0b51355b..308e8325 100644
--- a/test/buildtool/build_engine/target_map/target_map.test.cpp
+++ b/test/buildtool/build_engine/target_map/target_map.test.cpp
@@ -1201,6 +1201,69 @@ TEST_CASE("built-in rules", "[target_map]") {
baz_result->Artifacts()->ToJson()["foo.txt."]["data"]["id"] ==
storage_config.Get().hash_function.HashBlobData("baz").HexString());
}
+
+ SECTION("tree_overlay") {
+ error = false;
+ error_msg = "NONE";
+ {
+ TaskSystem ts;
+ target_map.ConsumeAfterKeysReady(
+ &ts,
+ {BuildMaps::Target::ConfiguredTarget{
+ .target =
+ BuildMaps::Base::EntityName{
+ "", "tree_overlay", "built-in, one stage"},
+ .config = empty_config}},
+ [&result](auto values) { result = *values[0]; },
+ [&error, &error_msg](std::string const& msg, bool /*unused*/) {
+ error = true;
+ error_msg = msg;
+ });
+ }
+ CHECK(not error);
+ CHECK(error_msg == "NONE");
+ CHECK(result->Artifacts()->ToJson()["the_tree"]["type"] ==
+ "TREE_OVERLAY");
+ CHECK(result->Trees().size() == 1);
+ CHECK(result->Trees()[0]->ToJson()["x"]["type"] == "LOCAL");
+ CHECK(result->TreeOverlays().size() == 1);
+ CHECK(result->TreeOverlays()[0]->ToJson()["trees"].size() == 1);
+ CHECK(result->TreeOverlays()[0]->ToJson()["trees"][0]["type"] ==
+ "TREE");
+ CHECK(result->TreeOverlays()[0]->ToJson()["disjoint"] == false);
+ }
+
+ SECTION("disjoint_tree_overlay") {
+ error = false;
+ error_msg = "NONE";
+ {
+ TaskSystem ts;
+ target_map.ConsumeAfterKeysReady(
+ &ts,
+ {BuildMaps::Target::ConfiguredTarget{
+ .target = BuildMaps::Base::EntityName{"",
+ "tree_overlay",
+ "built-in, disjoint, "
+ "one stage"},
+ .config = empty_config}},
+ [&result](auto values) { result = *values[0]; },
+ [&error, &error_msg](std::string const& msg, bool /*unused*/) {
+ error = true;
+ error_msg = msg;
+ });
+ }
+ CHECK(not error);
+ CHECK(error_msg == "NONE");
+ CHECK(result->Artifacts()->ToJson()["the_tree"]["type"] ==
+ "TREE_OVERLAY");
+ CHECK(result->Trees().size() == 1);
+ CHECK(result->Trees()[0]->ToJson()["x"]["type"] == "LOCAL");
+ CHECK(result->TreeOverlays().size() == 1);
+ CHECK(result->TreeOverlays()[0]->ToJson()["trees"].size() == 1);
+ CHECK(result->TreeOverlays()[0]->ToJson()["trees"][0]["type"] ==
+ "TREE");
+ CHECK(result->TreeOverlays()[0]->ToJson()["disjoint"] == true);
+ }
}
TEST_CASE("target reference", "[target_map]") {