1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
|
// 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_EXECUTION_API_BAZEL_MSG_BAZEL_MSG_FACTORY_HPP
#define INCLUDED_SRC_BUILDTOOL_EXECUTION_API_BAZEL_MSG_BAZEL_MSG_FACTORY_HPP
#include <chrono>
#include <filesystem>
#include <functional>
#include <iterator>
#include <map>
#include <optional>
#include <string>
#include <variant>
#include <vector>
#include "gsl/gsl"
#include "src/buildtool/common/artifact.hpp"
#include "src/buildtool/common/artifact_blob.hpp"
#include "src/buildtool/common/artifact_digest.hpp"
#include "src/buildtool/common/bazel_types.hpp"
#include "src/buildtool/crypto/hash_function.hpp"
#include "src/buildtool/execution_api/bazel_msg/directory_tree.hpp"
#include "src/buildtool/file_system/object_type.hpp"
#include "src/buildtool/logging/log_level.hpp"
#include "src/buildtool/logging/logger.hpp"
#include "src/utils/cpp/expected.hpp"
/// \brief Factory for creating Bazel API protobuf messages.
/// Responsible for creating protobuf messages necessary for Bazel API server
/// communication.
class BazelMsgFactory {
public:
/// \brief Store or otherwise process a blob. Returns success flag.
using BlobProcessFunc = std::function<bool(ArtifactBlob&&)>;
using LinkDigestResolveFunc =
std::function<void(std::vector<ArtifactDigest> const&,
gsl::not_null<std::vector<std::string>*> const&)>;
using PathReadFunc = std::function<std::optional<std::filesystem::path>(
ArtifactDigest const&,
ObjectType)>;
using GitReadFunc = std::function<std::optional<
std::variant<std::filesystem::path, std::string>>(ArtifactDigest const&,
ObjectType)>;
using BlobStoreFunc = std::function<std::optional<ArtifactDigest>(
std::variant<std::filesystem::path, std::string> const&,
bool)>;
using FileStoreFunc = std::function<
std::optional<ArtifactDigest>(std::filesystem::path const&, bool)>;
using SymlinkStoreFunc =
std::function<std::optional<ArtifactDigest>(std::string const&)>;
using TreeStoreFunc =
std::function<std::optional<ArtifactDigest>(std::string const&)>;
using RehashedDigestReadFunc =
std::function<expected<std::optional<Artifact::ObjectInfo>,
std::string>(ArtifactDigest const&)>;
using RehashedDigestStoreFunc =
std::function<std::optional<std::string>(ArtifactDigest const&,
ArtifactDigest const&,
ObjectType)>;
/// \brief Create Directory digest from artifact tree structure. Uses
/// compatible HashFunction for hashing. Recursively traverse entire tree
/// and create blobs for sub-directories.
/// \param tree Directory tree of artifacts.
/// \param resolve_links Function for resolving symlinks.
/// \param process_blob Function for processing Directory blobs.
/// \returns Digest representing the entire tree.
[[nodiscard]] static auto CreateDirectoryDigestFromTree(
DirectoryTreePtr const& tree,
LinkDigestResolveFunc const& resolve_links,
BlobProcessFunc const& process_blob) noexcept
-> std::optional<ArtifactDigest>;
/// \brief Create Directory digest from an owned Git tree.
/// Recursively traverse entire tree and store files and directories.
/// Used to convert from native to compatible representation of trees.
/// \param digest Digest of a Git tree.
/// \param read_git Function for reading Git tree entries. Reading from
/// CAS returns the CAS path, while reading from Git CAS
/// returns content directly. This differentiation is
/// made to avoid unnecessary storing blobs in memory.
/// \param store_file Function for storing file via path or content.
/// \param store_dir Function for storing Directory blobs.
/// \param store_symlink Function for storing symlink via content.
/// \param read_rehashed Function to read mapping between digests.
/// \param store_rehashed Function to store mapping between digests.
/// \returns Digest representing the entire tree directory, or error string
/// on failure.
[[nodiscard]] static auto CreateDirectoryDigestFromGitTree(
ArtifactDigest const& digest,
GitReadFunc const& read_git,
BlobStoreFunc const& store_file,
TreeStoreFunc const& store_dir,
SymlinkStoreFunc const& store_symlink,
RehashedDigestReadFunc const& read_rehashed,
RehashedDigestStoreFunc const& store_rehashed) noexcept
-> expected<ArtifactDigest, std::string>;
/// \brief Create Git tree digest from an owned Directory.
/// Recursively traverse entire directory and store blobs and trees.
/// Used to convert from compatible to native representation of trees.
/// \param digest Digest of a bazel directory.
/// \param read_path Function for reading CAS path of compatible
/// blobs.
/// \param store_file Function for storing local file via path.
/// \param store_tree Function for storing Git trees.
/// \param store_symlink Function for storing symlink via content.
/// \param read_rehashed Function for retrieving cached digests.
/// \param store_rehashed Function to register digests for caching.
/// \returns Digest of a Git tree representing the entire bazel Directory,
/// or error string on failure.
[[nodiscard]] static auto CreateGitTreeDigestFromDirectory(
ArtifactDigest const& digest,
PathReadFunc const& read_path,
FileStoreFunc const& store_file,
TreeStoreFunc const& store_tree,
SymlinkStoreFunc const& store_symlink,
RehashedDigestReadFunc const& read_rehashed,
RehashedDigestStoreFunc const& store_rehashed) noexcept
-> expected<ArtifactDigest, std::string>;
/// \brief Create Directory digest from local file root.
/// Recursively traverse entire root and store files and directories.
/// \param root Path to local file root.
/// \param store_file Function for storing local file via path.
/// \param store_dir Function for storing Directory blobs.
/// \param store_symlink Function for storing symlink via content.
/// \returns Digest representing the entire file root.
[[nodiscard]] static auto CreateDirectoryDigestFromLocalTree(
std::filesystem::path const& root,
FileStoreFunc const& store_file,
TreeStoreFunc const& store_dir,
SymlinkStoreFunc const& store_symlink) noexcept
-> std::optional<ArtifactDigest>;
/// \brief Create Git tree digest from local file root.
/// Recursively traverse entire root and store files and directories.
/// \param root Path to local file root.
/// \param store_file Function for storing local file via path.
/// \param store_tree Function for storing git trees.
/// \param store_symlink Function for storing symlink via content.
/// \returns Digest representing the entire file root.
[[nodiscard]] static auto CreateGitTreeDigestFromLocalTree(
std::filesystem::path const& root,
FileStoreFunc const& store_file,
TreeStoreFunc const& store_tree,
SymlinkStoreFunc const& store_symlink) noexcept
-> std::optional<ArtifactDigest>;
struct ActionDigestRequest;
/// \brief Creates Action digest from command line.
/// As part of the internal process, it creates an ActionBundle and
/// CommandBundle that can be captured via BlobStoreFunc.
/// \returns Digest representing the action.
[[nodiscard]] static auto CreateActionDigestFromCommandLine(
ActionDigestRequest const& request) -> std::optional<ArtifactDigest>;
/// \brief Create message vector from std::map.
/// \param[in] input map
/// \tparam T protobuf message type. It must be a name-value
/// message (i.e. class methods T::set_name(std::string) and
/// T::set_value(std::string) must exist)
template <class T>
[[nodiscard]] static auto CreateMessageVectorFromMap(
std::map<std::string, std::string> const& input) noexcept
-> std::vector<T> {
std::vector<T> output{};
std::transform(std::begin(input),
std::end(input),
std::back_inserter(output),
[](auto const& key_val) {
T msg;
msg.set_name(key_val.first);
msg.set_value(key_val.second);
return msg;
});
return output;
}
template <class T>
[[nodiscard]] static auto MessageFromString(std::string const& blob)
-> std::optional<T> {
T msg{};
if (msg.ParseFromString(blob)) {
return msg;
}
Logger::Log(LogLevel::Error, "failed to parse message from string");
return std::nullopt;
}
};
struct BazelMsgFactory::ActionDigestRequest final {
using BlobStoreFunc = std::function<void(ArtifactBlob&&)>;
template <typename T>
using VectorPtr = gsl::not_null<std::vector<T> const*>;
/// \brief The command line.
VectorPtr<std::string> const command_line;
/// \brief The workingg direcotry
gsl::not_null<std::string const*> const cwd;
/// \brief The paths of output files.
VectorPtr<std::string> const output_files;
/// \brief The paths of output directories.
VectorPtr<std::string> const output_dirs;
/// \brief Generic output paths (indicates protocol >=v2.1 should be used).
VectorPtr<std::string> const output_paths;
/// \brief The environment variables set.
VectorPtr<bazel_re::Command_EnvironmentVariable> const env_vars;
/// \brief The target platform's properties.
VectorPtr<bazel_re::Platform_Property> const properties;
/// \brief The Digest of the execution directory.
gsl::not_null<ArtifactDigest const*> const exec_dir;
/// \brief Hash function to be used.
HashFunction const hash_function;
/// \brief The command execution timeout.
std::chrono::milliseconds const timeout;
/// \brief Skip action cache.
bool skip_action_cache;
/// \brief Function for storing action and cmd bundles.
std::optional<BlobStoreFunc> const store_blob = std::nullopt;
};
#endif // INCLUDED_SRC_BUILDTOOL_EXECUTION_API_BAZEL_MSG_BAZEL_MSG_FACTORY_HPP
|