summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/concepts/overview.org13
-rw-r--r--src/buildtool/build_engine/base_maps/entity_name.hpp21
-rw-r--r--src/buildtool/build_engine/base_maps/entity_name_data.hpp6
-rw-r--r--src/buildtool/build_engine/target_map/target_map.cpp240
-rw-r--r--src/buildtool/main/main.cpp3
5 files changed, 193 insertions, 90 deletions
diff --git a/doc/concepts/overview.org b/doc/concepts/overview.org
index 13d5d04b..a7230066 100644
--- a/doc/concepts/overview.org
+++ b/doc/concepts/overview.org
@@ -134,6 +134,11 @@ to in target files.
second position (where normally the module would be) is necessary
to ensure the name has length more than 2 to distinguish it from
a reference to the module ~"FILE"~.
+- A reference to an collection, given by a shell pattern, of explicit
+ source files in the top-level directory of the same module,
+ specified as ~["GLOB", null, pattern]~. The explicit ~null~ at
+ second position is required for the same reason as in the explicit
+ file reference.
- A reference to a tree target in the same module, specified as
~["TREE", null, name]~. The explicit ~null~ at second position is
required for the same reason as in the explicit file reference.
@@ -179,6 +184,14 @@ the relative path of the file to the module root and the value the
file artifact located at the specified location. The runfiles are
the same as the artifacts and the provides map is empty.
+**** Collection of files given by a shell pattern
+
+A collection of files given by a shell pattern has, both as artifacts
+and runfiles, the (necessarily disjoint) union of the artifact
+maps of the (zero or more) source targets that match the pattern.
+Only /files/ in the /top-level/ directory of the given modules are
+considered for matches. The provides map is empty.
+
**** Trees
A tree describes a directory. Internally, however, it is a single
diff --git a/src/buildtool/build_engine/base_maps/entity_name.hpp b/src/buildtool/build_engine/base_maps/entity_name.hpp
index 49744ed4..2b5ddd57 100644
--- a/src/buildtool/build_engine/base_maps/entity_name.hpp
+++ b/src/buildtool/build_engine/base_maps/entity_name.hpp
@@ -98,25 +98,23 @@ template <typename T>
std::nullopt) noexcept -> std::optional<EntityName> {
try {
bool const is_file = s0 == EntityName::kFileLocationMarker;
+ auto const ref_type =
+ s0 == EntityName::kFileLocationMarker
+ ? ReferenceType::kFile
+ : (s0 == EntityName::kGlobMarker ? ReferenceType::kGlob
+ : ReferenceType::kTree);
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,
- (is_file ? ReferenceType::kFile
- : ReferenceType::kTree)};
+ 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,
- (is_file ? ReferenceType::kFile
- : ReferenceType::kTree)};
+ return EntityName{
+ x.repository, x.module, name, ref_type};
}
}
if (logger) {
@@ -219,7 +217,8 @@ template <typename T>
"obtained as FIELD value of anonymous fields"));
}
else if (s0 == EntityName::kFileLocationMarker or
- s0 == EntityName::kTreeLocationMarker) {
+ s0 == EntityName::kTreeLocationMarker or
+ s0 == EntityName::kGlobMarker) {
return ParseEntityNameFSReference(
s0, list, list_size, current, logger);
}
diff --git a/src/buildtool/build_engine/base_maps/entity_name_data.hpp b/src/buildtool/build_engine/base_maps/entity_name_data.hpp
index e3ecf607..902c9b38 100644
--- a/src/buildtool/build_engine/base_maps/entity_name_data.hpp
+++ b/src/buildtool/build_engine/base_maps/entity_name_data.hpp
@@ -24,7 +24,7 @@ struct AnonymousTarget {
}
};
-enum class ReferenceType : std::int8_t { kTarget, kFile, kTree };
+enum class ReferenceType : std::int8_t { kTarget, kFile, kTree, kGlob };
struct NamedTarget {
std::string repository{};
@@ -65,6 +65,7 @@ class EntityName {
static constexpr auto kLocationMarker = "@";
static constexpr auto kFileLocationMarker = "FILE";
static constexpr auto kTreeLocationMarker = "TREE";
+ static constexpr auto kGlobMarker = "GLOB";
static constexpr auto kRelativeLocationMarker = "./";
static constexpr auto kAnonymousMarker = "#";
@@ -119,6 +120,9 @@ class EntityName {
else if (x.reference_t == ReferenceType::kTree) {
j.push_back(kTreeLocationMarker);
}
+ else if (x.reference_t == ReferenceType::kGlob) {
+ j.push_back(kGlobMarker);
+ }
j.push_back(x.module);
j.push_back(x.name);
}
diff --git a/src/buildtool/build_engine/target_map/target_map.cpp b/src/buildtool/build_engine/target_map/target_map.cpp
index 087bcacb..66e1ec73 100644
--- a/src/buildtool/build_engine/target_map/target_map.cpp
+++ b/src/buildtool/build_engine/target_map/target_map.cpp
@@ -6,6 +6,8 @@
#include <string>
#include <utility>
+#include <fnmatch.h>
+
#include "fmt/format.h"
#include "nlohmann/json.hpp"
#include "src/buildtool/build_engine/base_maps/field_reader.hpp"
@@ -1411,6 +1413,55 @@ void TreeTarget(
});
}
+void GlobResult(const std::vector<AnalysedTargetPtr const*>& values,
+ const BuildMaps::Target::TargetMap::SetterPtr& setter) {
+ auto result = Expression::map_t::underlying_map_t{};
+ for (auto const& value : values) {
+ for (auto const& [k, v] : (*value)->Artifacts()->Map()) {
+ result[k] = v;
+ }
+ }
+ auto stage = ExpressionPtr{Expression::map_t{result}};
+ auto target = std::make_shared<AnalysedTarget>(
+ TargetResult{stage, Expression::kEmptyMap, stage},
+ std::vector<ActionDescription::Ptr>{},
+ std::vector<std::string>{},
+ std::vector<Tree::Ptr>{},
+ std::unordered_set<std::string>{},
+ std::set<std::string>{});
+ (*setter)(std::move(target));
+}
+
+void GlobTargetWithDirEntry(
+ const BuildMaps::Base::EntityName& key,
+ const gsl::not_null<TaskSystem*>& ts,
+ const BuildMaps::Target::TargetMap::SetterPtr& setter,
+ const BuildMaps::Target::TargetMap::LoggerPtr& logger,
+ const gsl::not_null<BuildMaps::Base::SourceTargetMap*>& source_target_map,
+ const FileRoot::DirectoryEntries& dir) {
+ auto const& target = key.GetNamedTarget();
+ auto const& pattern = target.name;
+ std::vector<BuildMaps::Base::EntityName> matches;
+ for (auto const& x : dir.FilesIterator()) {
+ if (fnmatch(pattern.c_str(), x.c_str(), 0) == 0) {
+ matches.emplace_back(BuildMaps::Base::EntityName{
+ target.repository,
+ target.module,
+ x,
+ BuildMaps::Base::ReferenceType::kFile});
+ }
+ }
+ source_target_map->ConsumeAfterKeysReady(
+ ts,
+ matches,
+ [setter](auto values) { GlobResult(values, setter); },
+ [logger](auto const& msg, bool fatal) {
+ (*logger)(
+ fmt::format("While handling matching file targets:\n{}", msg),
+ fatal);
+ });
+}
+
} // namespace
namespace BuildMaps::Target {
@@ -1422,84 +1473,117 @@ auto CreateTargetMap(
directory_entries_map,
const gsl::not_null<ResultTargetMap*>& result_map,
std::size_t jobs) -> TargetMap {
- auto target_reader =
- [source_target_map,
- targets_file_map,
- rule_map,
- result_map,
- directory_entries_map](
- auto ts, auto setter, auto logger, auto subcaller, auto key) {
- if (key.target.IsAnonymousTarget()) {
- withTargetNode(
- key, rule_map, ts, subcaller, setter, logger, result_map);
- }
- else if (key.target.GetNamedTarget().reference_t ==
- BuildMaps::Base::ReferenceType::kTree) {
-
- auto wrapped_logger = std::make_shared<AsyncMapConsumerLogger>(
- [logger, target = key.target](auto const& msg, bool fatal) {
- (*logger)(fmt::format("While analysing {} as explicit "
- "tree reference:\n{}",
- target.ToString(),
- msg),
- fatal);
- });
- TreeTarget(key,
- ts,
- subcaller,
- setter,
- wrapped_logger,
- result_map,
- directory_entries_map);
- }
- else if (key.target.GetNamedTarget().reference_t ==
- BuildMaps::Base::ReferenceType::kFile) {
- // Not a defined target, treat as source target
- source_target_map->ConsumeAfterKeysReady(
- ts,
- {key.target},
- [setter](auto values) {
- (*setter)(AnalysedTargetPtr{*values[0]});
- },
- [logger, target = key.target](auto const& msg, auto fatal) {
- (*logger)(fmt::format("While analysing target {} as "
- "explicit source target:\n{}",
- target.ToString(),
- msg),
- fatal);
- });
- }
- else {
- targets_file_map->ConsumeAfterKeysReady(
- ts,
- {key.target.ToModule()},
- [key,
- source_target_map,
- rule_map,
- ts,
- subcaller = std::move(subcaller),
- setter = std::move(setter),
- logger,
- result_map](auto values) {
- withTargetsFile(key,
- *values[0],
- source_target_map,
- rule_map,
- ts,
- subcaller,
- setter,
- logger,
- result_map);
- },
- [logger, target = key.target](auto const& msg, auto fatal) {
- (*logger)(fmt::format("While searching targets "
- "description for {}:\n{}",
- target.ToString(),
- msg),
- fatal);
- });
- }
- };
+ auto target_reader = [source_target_map,
+ targets_file_map,
+ rule_map,
+ result_map,
+ directory_entries_map](auto ts,
+ auto setter,
+ auto logger,
+ auto subcaller,
+ auto key) {
+ if (key.target.IsAnonymousTarget()) {
+ withTargetNode(
+ key, rule_map, ts, subcaller, setter, logger, result_map);
+ }
+ else if (key.target.GetNamedTarget().reference_t ==
+ BuildMaps::Base::ReferenceType::kTree) {
+
+ auto wrapped_logger = std::make_shared<AsyncMapConsumerLogger>(
+ [logger, target = key.target](auto const& msg, bool fatal) {
+ (*logger)(fmt::format("While analysing {} as explicit "
+ "tree reference:\n{}",
+ target.ToString(),
+ msg),
+ fatal);
+ });
+ TreeTarget(key,
+ ts,
+ subcaller,
+ setter,
+ wrapped_logger,
+ result_map,
+ directory_entries_map);
+ }
+ else if (key.target.GetNamedTarget().reference_t ==
+ BuildMaps::Base::ReferenceType::kFile) {
+ // Not a defined target, treat as source target
+ source_target_map->ConsumeAfterKeysReady(
+ ts,
+ {key.target},
+ [setter](auto values) {
+ (*setter)(AnalysedTargetPtr{*values[0]});
+ },
+ [logger, target = key.target](auto const& msg, auto fatal) {
+ (*logger)(fmt::format("While analysing target {} as "
+ "explicit source target:\n{}",
+ target.ToString(),
+ msg),
+ fatal);
+ });
+ }
+ else if (key.target.GetNamedTarget().reference_t ==
+ BuildMaps::Base::ReferenceType::kGlob) {
+ auto wrapped_logger = std::make_shared<AsyncMapConsumerLogger>(
+ [logger, target = key.target](auto const& msg, bool fatal) {
+ (*logger)(fmt::format("While analysing {} as glob:\n{}",
+ target.ToString(),
+ msg),
+ fatal);
+ });
+ auto const& target = key.target;
+ directory_entries_map->ConsumeAfterKeysReady(
+ ts,
+ {target.ToModule()},
+ [target, ts, setter, wrapped_logger, source_target_map](
+ auto values) {
+ GlobTargetWithDirEntry(target,
+ ts,
+ setter,
+ wrapped_logger,
+ source_target_map,
+ *values[0]);
+ },
+ [target, logger](auto const& msg, bool fatal) {
+ (*logger)(fmt::format("While reading directory for {}:\n{}",
+ target.ToString(),
+ msg),
+ fatal);
+ }
+
+ );
+ }
+ else {
+ targets_file_map->ConsumeAfterKeysReady(
+ ts,
+ {key.target.ToModule()},
+ [key,
+ source_target_map,
+ rule_map,
+ ts,
+ subcaller = std::move(subcaller),
+ setter = std::move(setter),
+ logger,
+ result_map](auto values) {
+ withTargetsFile(key,
+ *values[0],
+ source_target_map,
+ rule_map,
+ ts,
+ subcaller,
+ setter,
+ logger,
+ result_map);
+ },
+ [logger, target = key.target](auto const& msg, auto fatal) {
+ (*logger)(fmt::format("While searching targets "
+ "description for {}:\n{}",
+ target.ToString(),
+ msg),
+ fatal);
+ });
+ }
+ };
return AsyncMapConsumer<ConfiguredTarget, AnalysedTargetPtr>(target_reader,
jobs);
}
diff --git a/src/buildtool/main/main.cpp b/src/buildtool/main/main.cpp
index 30035819..c904f689 100644
--- a/src/buildtool/main/main.cpp
+++ b/src/buildtool/main/main.cpp
@@ -949,6 +949,9 @@ auto DetermineNonExplicitTarget(
case Base::ReferenceType::kTree:
std::cout << id.ToString() << " is a tree." << std::endl;
return std::nullopt;
+ case Base::ReferenceType::kGlob:
+ std::cout << id.ToString() << " is a glob." << std::endl;
+ return std::nullopt;
case Base::ReferenceType::kTarget:
return id;
}