summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/man/just.1.org21
-rw-r--r--src/buildtool/common/TARGETS1
-rw-r--r--src/buildtool/common/artifact.cpp24
-rw-r--r--src/buildtool/common/artifact.hpp3
-rw-r--r--src/buildtool/main/main.cpp16
-rw-r--r--test/buildtool/common/TARGETS12
-rw-r--r--test/buildtool/common/common.test.cpp42
7 files changed, 106 insertions, 13 deletions
diff --git a/share/man/just.1.org b/share/man/just.1.org
index c66c1c62..1f1d2e07 100644
--- a/share/man/just.1.org
+++ b/share/man/just.1.org
@@ -182,9 +182,24 @@ rule definition can also reside in a git-tree root.
** install-cas
-~install-cas~ fetches artifacts from CAS (Content Addressable Storage)
-by means of their object identifier with the format
-~[<hash>:<size>:<type>]~. Depending on whether the output path is set
+~install-cas~ fetches artifacts from CAS (Content Addressable
+Storage) by means of their object identifier. The canonical format
+of an object identifier is ~[<hash>:<size>:<type>]~; however, when
+parsing an object identifier, ~install-cas~ uses the following
+default rules, to make usage more simple.
+- The square brackets are optional.
+- If the size is missing (e.g., because the argument contains no
+ colon), or cannot be parsed as a number, this is not an error,
+ and the value ~0~ is assumed. While this is almost never the
+ correct size, many CAS implementations, including the local CAS
+ of just itself, ignore the size for lookups.
+- From the type, only the first letter (~f~ for non-executable
+ file, ~x~ for executable file, and ~t~ for tree) is significant;
+ the rest is ignored. If the type is missing (e.g., because the
+ argument contains less than two colons), or its first letter is
+ not one of the valid ones, ~f~ is assumed.
+
+Depending on whether the output path is set
or not, the behavior is different.
*** Output path is omitted
diff --git a/src/buildtool/common/TARGETS b/src/buildtool/common/TARGETS
index 4cc2dcbf..5d06723a 100644
--- a/src/buildtool/common/TARGETS
+++ b/src/buildtool/common/TARGETS
@@ -30,6 +30,7 @@
, "identifier.hpp"
, "statistics.hpp"
]
+ , "srcs": ["artifact.cpp"]
, "deps":
[ "bazel_types"
, ["src/buildtool/crypto", "hash_function"]
diff --git a/src/buildtool/common/artifact.cpp b/src/buildtool/common/artifact.cpp
new file mode 100644
index 00000000..fc3c5b6e
--- /dev/null
+++ b/src/buildtool/common/artifact.cpp
@@ -0,0 +1,24 @@
+#include "src/buildtool/common/artifact.hpp"
+
+#include <string>
+
+auto Artifact::ObjectInfo::LiberalFromString(std::string const& s) noexcept
+ -> Artifact::ObjectInfo {
+ std::istringstream iss(s);
+ std::string id{};
+ std::string size_str{"0"};
+ std::string type{"f"};
+ if (iss.peek() == '[') {
+ (void)iss.get();
+ }
+ std::getline(iss, id, ':');
+ if (not iss.eof()) {
+ std::getline(iss, size_str, ':');
+ }
+ if (not iss.eof()) {
+ std::getline(iss, type, ']');
+ }
+ auto size = static_cast<std::size_t>(std::atol(size_str.c_str()));
+ return Artifact::ObjectInfo{ArtifactDigest{id, size},
+ FromChar(*type.c_str())};
+}
diff --git a/src/buildtool/common/artifact.hpp b/src/buildtool/common/artifact.hpp
index 6c97ab24..3f68a351 100644
--- a/src/buildtool/common/artifact.hpp
+++ b/src/buildtool/common/artifact.hpp
@@ -86,6 +86,9 @@ class Artifact {
}
return std::nullopt;
}
+
+ [[nodiscard]] static auto LiberalFromString(
+ std::string const& s) noexcept -> ObjectInfo;
};
explicit Artifact(ArtifactIdentifier id) noexcept : id_{std::move(id)} {}
diff --git a/src/buildtool/main/main.cpp b/src/buildtool/main/main.cpp
index e3c1385a..4c977955 100644
--- a/src/buildtool/main/main.cpp
+++ b/src/buildtool/main/main.cpp
@@ -1160,32 +1160,28 @@ void ReportTaintedness(const AnalysisResult& result) {
[[nodiscard]] auto FetchAndInstallArtifacts(
gsl::not_null<IExecutionApi*> const& api,
FetchArguments const& clargs) -> bool {
- auto object_info = Artifact::ObjectInfo::FromString(clargs.object_id);
- if (not object_info) {
- Logger::Log(
- LogLevel::Error, "failed to parse object id {}.", clargs.object_id);
- return false;
- }
+ auto object_info =
+ Artifact::ObjectInfo::LiberalFromString(clargs.object_id);
if (clargs.output_path) {
auto output_path = (*clargs.output_path / "").parent_path();
if (FileSystemManager::IsDirectory(output_path)) {
- output_path /= object_info->digest.hash();
+ output_path /= object_info.digest.hash();
}
if (not FileSystemManager::CreateDirectory(output_path.parent_path()) or
- not api->RetrieveToPaths({*object_info}, {output_path})) {
+ not api->RetrieveToPaths({object_info}, {output_path})) {
Logger::Log(LogLevel::Error, "failed to retrieve artifact.");
return false;
}
Logger::Log(LogLevel::Info,
"artifact {} was installed to {}",
- object_info->ToString(),
+ object_info.ToString(),
output_path.string());
}
else { // dump to stdout
- if (not api->RetrieveToFds({*object_info}, {dup(fileno(stdout))})) {
+ if (not api->RetrieveToFds({object_info}, {dup(fileno(stdout))})) {
Logger::Log(LogLevel::Error, "failed to dump artifact.");
return false;
}
diff --git a/test/buildtool/common/TARGETS b/test/buildtool/common/TARGETS
index 8890b8b8..c52301b4 100644
--- a/test/buildtool/common/TARGETS
+++ b/test/buildtool/common/TARGETS
@@ -33,6 +33,17 @@
]
, "stage": ["test", "buildtool", "common"]
}
+, "common":
+ { "type": ["@", "rules", "CC/test", "test"]
+ , "name": ["common"]
+ , "srcs": ["common.test.cpp"]
+ , "deps":
+ [ ["@", "catch2", "", "catch2"]
+ , ["test", "catch-main"]
+ , ["src/buildtool/common", "common"]
+ ]
+ , "stage": ["test", "buildtool", "common"]
+ }
, "repository_config":
{ "type": ["@", "rules", "CC/test", "test"]
, "name": ["repository_config"]
@@ -52,6 +63,7 @@
[ "action_description"
, "artifact_description"
, "artifact_factory"
+ , "common"
, "repository_config"
]
}
diff --git a/test/buildtool/common/common.test.cpp b/test/buildtool/common/common.test.cpp
new file mode 100644
index 00000000..ea5af597
--- /dev/null
+++ b/test/buildtool/common/common.test.cpp
@@ -0,0 +1,42 @@
+#include "catch2/catch.hpp"
+#include "src/buildtool/common/artifact.hpp"
+
+TEST_CASE("ObjectInfo::LiberalFromString", "[artifcat]") {
+ auto expected = *Artifact::ObjectInfo::FromString(
+ "[5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689:11:f]");
+ auto expected_as_tree = *Artifact::ObjectInfo::FromString(
+ "[5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689:0:t]");
+
+ CHECK(Artifact::ObjectInfo::LiberalFromString(
+ "[5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689:11:f]") == expected);
+ CHECK(Artifact::ObjectInfo::LiberalFromString(
+ "5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689:11:f]") == expected);
+ CHECK(Artifact::ObjectInfo::LiberalFromString(
+ "[5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689:11:f") == expected);
+ CHECK(Artifact::ObjectInfo::LiberalFromString(
+ "5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689:11:f") == expected);
+ CHECK(Artifact::ObjectInfo::LiberalFromString(
+ "5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689:11:file") == expected);
+ CHECK(Artifact::ObjectInfo::LiberalFromString(
+ "5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689:11:notavalidletter") ==
+ expected);
+
+ // Without size, which is not honored in equality
+ CHECK(Artifact::ObjectInfo::LiberalFromString(
+ "5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689") == expected);
+ CHECK(Artifact::ObjectInfo::LiberalFromString(
+ "5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689:") == expected);
+ // Syntactically invalid size should be ignored
+ CHECK(Artifact::ObjectInfo::LiberalFromString(
+ "5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689:xyz") == expected);
+
+ CHECK(Artifact::ObjectInfo::LiberalFromString(
+ "5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689::t") ==
+ expected_as_tree);
+ CHECK(Artifact::ObjectInfo::LiberalFromString(
+ "5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689::tree") ==
+ expected_as_tree);
+ CHECK(Artifact::ObjectInfo::LiberalFromString(
+ "5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689:xyz:t") ==
+ expected_as_tree);
+}