aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ericson <John.Ericson@Obsidian.Systems>2023-02-17 18:37:35 -0500
committerJohn Ericson <John.Ericson@Obsidian.Systems>2023-04-07 08:34:58 -0400
commitfe9cbe838c3d59e2768b92d8cab0e5a2674f5bfb (patch)
tree1c92e24a305083a0c7c13dcff76f39507f712315
parent81dfc2b01231c65137017de092c8506838fadd94 (diff)
Create `Derivation::fromJSON`
And test, of course
-rw-r--r--src/libstore/content-address.hh5
-rw-r--r--src/libstore/derivations.cc105
-rw-r--r--src/libstore/derivations.hh35
-rw-r--r--src/libstore/tests/derivation.cc61
-rw-r--r--src/libutil/comparator.hh10
5 files changed, 197 insertions, 19 deletions
diff --git a/src/libstore/content-address.hh b/src/libstore/content-address.hh
index 19fdfc1eb..368a7ec48 100644
--- a/src/libstore/content-address.hh
+++ b/src/libstore/content-address.hh
@@ -3,6 +3,7 @@
#include <variant>
#include "hash.hh"
+#include "comparator.hh"
namespace nix {
@@ -30,6 +31,8 @@ struct TextHash {
* Hash of the contents of the text/file.
*/
Hash hash;
+
+ GENERATE_CMP(TextHash, me->hash);
};
/**
@@ -46,6 +49,8 @@ struct FixedOutputHash {
Hash hash;
std::string printMethodAlgo() const;
+
+ GENERATE_CMP(FixedOutputHash, me->method, me->hash);
};
/**
diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc
index 06cc69056..ea4abb352 100644
--- a/src/libstore/derivations.cc
+++ b/src/libstore/derivations.cc
@@ -889,6 +889,7 @@ std::optional<BasicDerivation> Derivation::tryResolve(
return resolved;
}
+
const Hash impureOutputHash = hashString(htSHA256, "impure");
nlohmann::json DerivationOutput::toJSON(
@@ -916,6 +917,73 @@ nlohmann::json DerivationOutput::toJSON(
return res;
}
+
+DerivationOutput DerivationOutput::fromJSON(
+ const Store & store, std::string_view drvName, std::string_view outputName,
+ const nlohmann::json & _json)
+{
+ std::set<std::string_view> keys;
+ auto json = (std::map<std::string, nlohmann::json>) _json;
+
+ for (const auto & [key, _] : json)
+ keys.insert(key);
+
+ auto methodAlgo = [&]() -> std::pair<FileIngestionMethod, HashType> {
+ std::string hashAlgo = json["hashAlgo"];
+ auto method = FileIngestionMethod::Flat;
+ if (hashAlgo.substr(0, 2) == "r:") {
+ method = FileIngestionMethod::Recursive;
+ hashAlgo = hashAlgo.substr(2);
+ }
+ auto hashType = parseHashType(hashAlgo);
+ return { method, hashType };
+ };
+
+ if (keys == (std::set<std::string_view> { "path" })) {
+ return DerivationOutput::InputAddressed {
+ .path = store.parseStorePath((std::string) json["path"]),
+ };
+ }
+
+ else if (keys == (std::set<std::string_view> { "path", "hashAlgo", "hash" })) {
+ auto [method, hashType] = methodAlgo();
+ auto dof = DerivationOutput::CAFixed {
+ .hash = {
+ .method = method,
+ .hash = Hash::parseNonSRIUnprefixed((std::string) json["hash"], hashType),
+ },
+ };
+ if (dof.path(store, drvName, outputName) != store.parseStorePath((std::string) json["path"]))
+ throw Error("Path doesn't match derivation output");
+ return dof;
+ }
+
+ else if (keys == (std::set<std::string_view> { "hashAlgo" })) {
+ auto [method, hashType] = methodAlgo();
+ return DerivationOutput::CAFloating {
+ .method = method,
+ .hashType = hashType,
+ };
+ }
+
+ else if (keys == (std::set<std::string_view> { })) {
+ return DerivationOutput::Deferred {};
+ }
+
+ else if (keys == (std::set<std::string_view> { "hashAlgo", "impure" })) {
+ auto [method, hashType] = methodAlgo();
+ return DerivationOutput::Impure {
+ .method = method,
+ .hashType = hashType,
+ };
+ }
+
+ else {
+ throw Error("invalid JSON for derivation output");
+ }
+}
+
+
nlohmann::json Derivation::toJSON(const Store & store) const
{
nlohmann::json res = nlohmann::json::object();
@@ -950,4 +1018,41 @@ nlohmann::json Derivation::toJSON(const Store & store) const
return res;
}
+
+Derivation Derivation::fromJSON(
+ const Store & store, std::string_view drvName,
+ const nlohmann::json & json)
+{
+ Derivation res;
+
+ {
+ auto & outputsObj = json["outputs"];
+ for (auto & [outputName, output] : outputsObj.items()) {
+ res.outputs.insert_or_assign(
+ outputName,
+ DerivationOutput::fromJSON(store, drvName, outputName, output));
+ }
+ }
+
+ {
+ auto & inputsList = json["inputSrcs"];
+ for (auto & input : inputsList)
+ res.inputSrcs.insert(store.parseStorePath(static_cast<const std::string &>(input)));
+ }
+
+ {
+ auto & inputDrvsObj = json["inputDrvs"];
+ for (auto & [inputDrvPath, inputOutputs] : inputDrvsObj.items())
+ res.inputDrvs[store.parseStorePath(inputDrvPath)] =
+ static_cast<const StringSet &>(inputOutputs);
+ }
+
+ res.platform = json["system"];
+ res.builder = json["builder"];
+ res.args = json["args"];
+ res.env = json["env"];
+
+ return res;
+}
+
}
diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh
index e12bd2119..0722dc61d 100644
--- a/src/libstore/derivations.hh
+++ b/src/libstore/derivations.hh
@@ -7,6 +7,7 @@
#include "content-address.hh"
#include "repair-flag.hh"
#include "sync.hh"
+#include "comparator.hh"
#include <map>
#include <variant>
@@ -24,6 +25,8 @@ class Store;
struct DerivationOutputInputAddressed
{
StorePath path;
+
+ GENERATE_CMP(DerivationOutputInputAddressed, me->path);
};
/**
@@ -44,6 +47,8 @@ struct DerivationOutputCAFixed
* @param outputName The name of this output.
*/
StorePath path(const Store & store, std::string_view drvName, std::string_view outputName) const;
+
+ GENERATE_CMP(DerivationOutputCAFixed, me->hash);
};
/**
@@ -62,13 +67,17 @@ struct DerivationOutputCAFloating
* How the serialization will be hashed
*/
HashType hashType;
+
+ GENERATE_CMP(DerivationOutputCAFloating, me->method, me->hashType);
};
/**
* Input-addressed output which depends on a (CA) derivation whose hash
* isn't known yet.
*/
-struct DerivationOutputDeferred {};
+struct DerivationOutputDeferred {
+ GENERATE_CMP(DerivationOutputDeferred);
+};
/**
* Impure output which is moved to a content-addressed location (like
@@ -85,6 +94,8 @@ struct DerivationOutputImpure
* How the serialization will be hashed
*/
HashType hashType;
+
+ GENERATE_CMP(DerivationOutputImpure, me->method, me->hashType);
};
typedef std::variant<
@@ -125,6 +136,11 @@ struct DerivationOutput : _DerivationOutputRaw
const Store & store,
std::string_view drvName,
std::string_view outputName) const;
+ static DerivationOutput fromJSON(
+ const Store & store,
+ std::string_view drvName,
+ std::string_view outputName,
+ const nlohmann::json & json);
};
typedef std::map<std::string, DerivationOutput> DerivationOutputs;
@@ -273,6 +289,15 @@ struct BasicDerivation
DerivationOutputsAndOptPaths outputsAndOptPaths(const Store & store) const;
static std::string_view nameFromPath(const StorePath & storePath);
+
+ GENERATE_CMP(BasicDerivation,
+ me->outputs,
+ me->inputSrcs,
+ me->platform,
+ me->builder,
+ me->args,
+ me->env,
+ me->name);
};
struct Derivation : BasicDerivation
@@ -313,6 +338,14 @@ struct Derivation : BasicDerivation
Derivation(BasicDerivation && bd) : BasicDerivation(std::move(bd)) { }
nlohmann::json toJSON(const Store & store) const;
+ static Derivation fromJSON(
+ const Store & store,
+ std::string_view drvName,
+ const nlohmann::json & json);
+
+ GENERATE_CMP(Derivation,
+ static_cast<const BasicDerivation &>(*me),
+ me->inputDrvs);
};
diff --git a/src/libstore/tests/derivation.cc b/src/libstore/tests/derivation.cc
index 12be8504d..8993cd80b 100644
--- a/src/libstore/tests/derivation.cc
+++ b/src/libstore/tests/derivation.cc
@@ -11,15 +11,29 @@ class DerivationTest : public LibStoreTest
{
};
-#define TEST_JSON(TYPE, NAME, STR, VAL, ...) \
- TEST_F(DerivationTest, TYPE ## _ ## NAME ## _to_json) { \
- using nlohmann::literals::operator "" _json; \
- ASSERT_EQ( \
- STR ## _json, \
- (TYPE { VAL }).toJSON(*store __VA_OPT__(,) __VA_ARGS__)); \
+#define TEST_JSON(NAME, STR, VAL, DRV_NAME, OUTPUT_NAME) \
+ TEST_F(DerivationTest, DerivationOutput_ ## NAME ## _to_json) { \
+ using nlohmann::literals::operator "" _json; \
+ ASSERT_EQ( \
+ STR ## _json, \
+ (DerivationOutput { VAL }).toJSON( \
+ *store, \
+ DRV_NAME, \
+ OUTPUT_NAME)); \
+ } \
+ \
+ TEST_F(DerivationTest, DerivationOutput_ ## NAME ## _from_json) { \
+ using nlohmann::literals::operator "" _json; \
+ ASSERT_EQ( \
+ DerivationOutput { VAL }, \
+ DerivationOutput::fromJSON( \
+ *store, \
+ DRV_NAME, \
+ OUTPUT_NAME, \
+ STR ## _json)); \
}
-TEST_JSON(DerivationOutput, inputAddressed,
+TEST_JSON(inputAddressed,
R"({
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
})",
@@ -28,7 +42,7 @@ TEST_JSON(DerivationOutput, inputAddressed,
}),
"drv-name", "output-name")
-TEST_JSON(DerivationOutput, caFixed,
+TEST_JSON(caFixed,
R"({
"hashAlgo": "r:sha256",
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
@@ -42,7 +56,7 @@ TEST_JSON(DerivationOutput, caFixed,
}),
"drv-name", "output-name")
-TEST_JSON(DerivationOutput, caFloating,
+TEST_JSON(caFloating,
R"({
"hashAlgo": "r:sha256"
})",
@@ -52,12 +66,12 @@ TEST_JSON(DerivationOutput, caFloating,
}),
"drv-name", "output-name")
-TEST_JSON(DerivationOutput, deferred,
+TEST_JSON(deferred,
R"({ })",
DerivationOutput::Deferred { },
"drv-name", "output-name")
-TEST_JSON(DerivationOutput, impure,
+TEST_JSON(impure,
R"({
"hashAlgo": "r:sha256",
"impure": true
@@ -68,7 +82,27 @@ TEST_JSON(DerivationOutput, impure,
}),
"drv-name", "output-name")
-TEST_JSON(Derivation, impure,
+#undef TEST_JSON
+
+#define TEST_JSON(NAME, STR, VAL, DRV_NAME) \
+ TEST_F(DerivationTest, Derivation_ ## NAME ## _to_json) { \
+ using nlohmann::literals::operator "" _json; \
+ ASSERT_EQ( \
+ STR ## _json, \
+ (Derivation { VAL }).toJSON(*store)); \
+ } \
+ \
+ TEST_F(DerivationTest, Derivation_ ## NAME ## _from_json) { \
+ using nlohmann::literals::operator "" _json; \
+ ASSERT_EQ( \
+ Derivation { VAL }, \
+ Derivation::fromJSON( \
+ *store, \
+ DRV_NAME, \
+ STR ## _json)); \
+ }
+
+TEST_JSON(simple,
R"({
"inputSrcs": [
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"
@@ -117,7 +151,8 @@ TEST_JSON(Derivation, impure,
},
};
drv;
- }))
+ }),
+ "drv-name")
#undef TEST_JSON
diff --git a/src/libutil/comparator.hh b/src/libutil/comparator.hh
index 2b5424b3d..9f661c5c3 100644
--- a/src/libutil/comparator.hh
+++ b/src/libutil/comparator.hh
@@ -17,12 +17,12 @@
* }
* ```
*/
-#define GENERATE_ONE_CMP(COMPARATOR, MY_TYPE, FIELDS...) \
+#define GENERATE_ONE_CMP(COMPARATOR, MY_TYPE, ...) \
bool operator COMPARATOR(const MY_TYPE& other) const { \
- const MY_TYPE* me = this; \
- auto fields1 = std::make_tuple( FIELDS ); \
- me = &other; \
- auto fields2 = std::make_tuple( FIELDS ); \
+ __VA_OPT__(const MY_TYPE* me = this;) \
+ auto fields1 = std::make_tuple( __VA_ARGS__ ); \
+ __VA_OPT__(me = &other;) \
+ auto fields2 = std::make_tuple( __VA_ARGS__ ); \
return fields1 COMPARATOR fields2; \
}
#define GENERATE_EQUAL(args...) GENERATE_ONE_CMP(==, args)