diff options
-rw-r--r-- | share/man/just.1.org | 21 | ||||
-rw-r--r-- | src/buildtool/common/TARGETS | 1 | ||||
-rw-r--r-- | src/buildtool/common/artifact.cpp | 24 | ||||
-rw-r--r-- | src/buildtool/common/artifact.hpp | 3 | ||||
-rw-r--r-- | src/buildtool/main/main.cpp | 16 | ||||
-rw-r--r-- | test/buildtool/common/TARGETS | 12 | ||||
-rw-r--r-- | test/buildtool/common/common.test.cpp | 42 |
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); +} |