summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/buildtool/common/cli.hpp10
-rw-r--r--src/buildtool/main/TARGETS1
-rw-r--r--src/buildtool/main/install_cas.cpp98
3 files changed, 109 insertions, 0 deletions
diff --git a/src/buildtool/common/cli.hpp b/src/buildtool/common/cli.hpp
index 74ff0cce..a49b2f6b 100644
--- a/src/buildtool/common/cli.hpp
+++ b/src/buildtool/common/cli.hpp
@@ -119,6 +119,7 @@ struct RebuildArguments {
struct FetchArguments {
std::string object_id{};
std::optional<std::filesystem::path> output_path{};
+ std::optional<std::filesystem::path> sub_path{};
bool remember{false};
bool raw_tree{};
};
@@ -518,6 +519,15 @@ static inline auto SetupFetchArguments(
"Install path for the artifact. (omit to dump to stdout)")
->type_name("PATH");
+ app->add_option_function<std::string>(
+ "-P,--sub-object-path",
+ [clargs](auto const& rel_path) {
+ clargs->sub_path = ToNormalPath(rel_path).relative_path();
+ },
+ "Select the sub-object at the specified path (if artifact is a "
+ "tree).")
+ ->type_name("PATH");
+
app->add_flag("--raw-tree",
clargs->raw_tree,
"Dump raw tree object (omit pretty printing)");
diff --git a/src/buildtool/main/TARGETS b/src/buildtool/main/TARGETS
index 01ed747c..8ff214d0 100644
--- a/src/buildtool/main/TARGETS
+++ b/src/buildtool/main/TARGETS
@@ -83,6 +83,7 @@
, "private-deps":
[ ["src/buildtool/compatibility", "compatibility"]
, ["src/buildtool/crypto", "hash_function"]
+ , ["src/buildtool/execution_api/bazel_msg", "bazel_msg_factory"]
, ["src/buildtool/execution_api/remote", "config"]
, ["src/buildtool/logging", "logging"]
]
diff --git a/src/buildtool/main/install_cas.cpp b/src/buildtool/main/install_cas.cpp
index cdeca553..1c0290df 100644
--- a/src/buildtool/main/install_cas.cpp
+++ b/src/buildtool/main/install_cas.cpp
@@ -16,6 +16,9 @@
#include "src/buildtool/compatibility/compatibility.hpp"
#include "src/buildtool/crypto/hash_function.hpp"
+#ifndef BOOTSTRAP_BUILD_TOOL
+#include "src/buildtool/execution_api/bazel_msg/bazel_msg_factory.hpp"
+#endif
#include "src/buildtool/execution_api/remote/config.hpp"
namespace {
@@ -76,6 +79,101 @@ auto FetchAndInstallArtifacts(
}
}
+ if (clargs.sub_path) {
+ std::filesystem::path sofar{};
+ for (auto const& segment : *clargs.sub_path) {
+ if (object_info.type != ObjectType::Tree) {
+ Logger::Log(
+ LogLevel::Warning,
+ "Non-tree found at path '{}', cannot follow to '{}'",
+ sofar.string(),
+ segment.string());
+ break;
+ }
+ auto data = api->RetrieveToMemory(object_info);
+ if (not data) {
+ Logger::Log(LogLevel::Error,
+ "Failed to retrieve artifact {} at path '{}'",
+ object_info.ToString(),
+ sofar.string());
+ return false;
+ }
+ if (Compatibility::IsCompatible()) {
+ auto directory =
+ BazelMsgFactory::MessageFromString<bazel_re::Directory>(
+ *data);
+ if (not directory) {
+ Logger::Log(
+ LogLevel::Warning,
+ "Failed to parse directory message at path '{}'",
+ sofar.string());
+ break;
+ }
+ std::optional<Artifact::ObjectInfo> new_object_info{};
+ if (not BazelMsgFactory::ReadObjectInfosFromDirectory(
+ *directory,
+ [&new_object_info, &segment](auto path, auto info) {
+ if (path == segment) {
+ new_object_info = info;
+ }
+ return true;
+ })) {
+ Logger::Log(
+ LogLevel::Warning,
+ "Failed to process directory message at path '{}'",
+ sofar.string());
+ break;
+ }
+ if (not new_object_info) {
+ Logger::Log(LogLevel::Warning,
+ "Entry {} not found at path '{}'",
+ segment.string(),
+ sofar.string());
+ break;
+ }
+ object_info = *new_object_info;
+ }
+ else {
+ auto entries = GitRepo::ReadTreeData(
+ *data,
+ HashFunction::ComputeTreeHash(*data).Bytes(),
+ [](auto const& /*unused*/) { return true; },
+ /*is_hex_id=*/false);
+ if (not entries) {
+ Logger::Log(LogLevel::Warning,
+ "Failed to parse tree {} at path '{}'",
+ object_info.ToString(),
+ sofar.string());
+ break;
+ }
+ std::optional<Artifact::ObjectInfo> new_object_info{};
+ if (not BazelMsgFactory::ReadObjectInfosFromGitTree(
+ *entries,
+ [&new_object_info, &segment](auto path, auto info) {
+ if (path == segment) {
+ new_object_info = info;
+ }
+ return true;
+ })) {
+ Logger::Log(LogLevel::Warning,
+ "Failed to process tree entries at path '{}'",
+ sofar.string());
+ break;
+ }
+
+ if (not new_object_info) {
+ Logger::Log(LogLevel::Warning,
+ "Entry {} not found at path '{}'",
+ segment.string(),
+ sofar.string());
+ break;
+ }
+ object_info = *new_object_info;
+ }
+ sofar /= segment;
+ }
+ }
+
if (clargs.output_path) {
auto output_path = (*clargs.output_path / "").parent_path();
if (FileSystemManager::IsDirectory(output_path)) {