forked from lix-project/lix
Create Derivation::fromJSON
And test, of course
This commit is contained in:
parent
81dfc2b012
commit
fe9cbe838c
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include "hash.hh"
|
#include "hash.hh"
|
||||||
|
#include "comparator.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
@ -30,6 +31,8 @@ struct TextHash {
|
||||||
* Hash of the contents of the text/file.
|
* Hash of the contents of the text/file.
|
||||||
*/
|
*/
|
||||||
Hash hash;
|
Hash hash;
|
||||||
|
|
||||||
|
GENERATE_CMP(TextHash, me->hash);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,6 +49,8 @@ struct FixedOutputHash {
|
||||||
Hash hash;
|
Hash hash;
|
||||||
|
|
||||||
std::string printMethodAlgo() const;
|
std::string printMethodAlgo() const;
|
||||||
|
|
||||||
|
GENERATE_CMP(FixedOutputHash, me->method, me->hash);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -889,6 +889,7 @@ std::optional<BasicDerivation> Derivation::tryResolve(
|
||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Hash impureOutputHash = hashString(htSHA256, "impure");
|
const Hash impureOutputHash = hashString(htSHA256, "impure");
|
||||||
|
|
||||||
nlohmann::json DerivationOutput::toJSON(
|
nlohmann::json DerivationOutput::toJSON(
|
||||||
|
@ -916,6 +917,73 @@ nlohmann::json DerivationOutput::toJSON(
|
||||||
return res;
|
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 Derivation::toJSON(const Store & store) const
|
||||||
{
|
{
|
||||||
nlohmann::json res = nlohmann::json::object();
|
nlohmann::json res = nlohmann::json::object();
|
||||||
|
@ -950,4 +1018,41 @@ nlohmann::json Derivation::toJSON(const Store & store) const
|
||||||
return res;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "content-address.hh"
|
#include "content-address.hh"
|
||||||
#include "repair-flag.hh"
|
#include "repair-flag.hh"
|
||||||
#include "sync.hh"
|
#include "sync.hh"
|
||||||
|
#include "comparator.hh"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
@ -24,6 +25,8 @@ class Store;
|
||||||
struct DerivationOutputInputAddressed
|
struct DerivationOutputInputAddressed
|
||||||
{
|
{
|
||||||
StorePath path;
|
StorePath path;
|
||||||
|
|
||||||
|
GENERATE_CMP(DerivationOutputInputAddressed, me->path);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,6 +47,8 @@ struct DerivationOutputCAFixed
|
||||||
* @param outputName The name of this output.
|
* @param outputName The name of this output.
|
||||||
*/
|
*/
|
||||||
StorePath path(const Store & store, std::string_view drvName, std::string_view outputName) const;
|
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
|
* How the serialization will be hashed
|
||||||
*/
|
*/
|
||||||
HashType hashType;
|
HashType hashType;
|
||||||
|
|
||||||
|
GENERATE_CMP(DerivationOutputCAFloating, me->method, me->hashType);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Input-addressed output which depends on a (CA) derivation whose hash
|
* Input-addressed output which depends on a (CA) derivation whose hash
|
||||||
* isn't known yet.
|
* isn't known yet.
|
||||||
*/
|
*/
|
||||||
struct DerivationOutputDeferred {};
|
struct DerivationOutputDeferred {
|
||||||
|
GENERATE_CMP(DerivationOutputDeferred);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Impure output which is moved to a content-addressed location (like
|
* Impure output which is moved to a content-addressed location (like
|
||||||
|
@ -85,6 +94,8 @@ struct DerivationOutputImpure
|
||||||
* How the serialization will be hashed
|
* How the serialization will be hashed
|
||||||
*/
|
*/
|
||||||
HashType hashType;
|
HashType hashType;
|
||||||
|
|
||||||
|
GENERATE_CMP(DerivationOutputImpure, me->method, me->hashType);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::variant<
|
typedef std::variant<
|
||||||
|
@ -125,6 +136,11 @@ struct DerivationOutput : _DerivationOutputRaw
|
||||||
const Store & store,
|
const Store & store,
|
||||||
std::string_view drvName,
|
std::string_view drvName,
|
||||||
std::string_view outputName) const;
|
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;
|
typedef std::map<std::string, DerivationOutput> DerivationOutputs;
|
||||||
|
@ -273,6 +289,15 @@ struct BasicDerivation
|
||||||
DerivationOutputsAndOptPaths outputsAndOptPaths(const Store & store) const;
|
DerivationOutputsAndOptPaths outputsAndOptPaths(const Store & store) const;
|
||||||
|
|
||||||
static std::string_view nameFromPath(const StorePath & storePath);
|
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
|
struct Derivation : BasicDerivation
|
||||||
|
@ -313,6 +338,14 @@ struct Derivation : BasicDerivation
|
||||||
Derivation(BasicDerivation && bd) : BasicDerivation(std::move(bd)) { }
|
Derivation(BasicDerivation && bd) : BasicDerivation(std::move(bd)) { }
|
||||||
|
|
||||||
nlohmann::json toJSON(const Store & store) const;
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,15 +11,29 @@ class DerivationTest : public LibStoreTest
|
||||||
{
|
{
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TEST_JSON(TYPE, NAME, STR, VAL, ...) \
|
#define TEST_JSON(NAME, STR, VAL, DRV_NAME, OUTPUT_NAME) \
|
||||||
TEST_F(DerivationTest, TYPE ## _ ## NAME ## _to_json) { \
|
TEST_F(DerivationTest, DerivationOutput_ ## NAME ## _to_json) { \
|
||||||
using nlohmann::literals::operator "" _json; \
|
using nlohmann::literals::operator "" _json; \
|
||||||
ASSERT_EQ( \
|
ASSERT_EQ( \
|
||||||
STR ## _json, \
|
STR ## _json, \
|
||||||
(TYPE { VAL }).toJSON(*store __VA_OPT__(,) __VA_ARGS__)); \
|
(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"({
|
R"({
|
||||||
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
|
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
|
||||||
})",
|
})",
|
||||||
|
@ -28,7 +42,7 @@ TEST_JSON(DerivationOutput, inputAddressed,
|
||||||
}),
|
}),
|
||||||
"drv-name", "output-name")
|
"drv-name", "output-name")
|
||||||
|
|
||||||
TEST_JSON(DerivationOutput, caFixed,
|
TEST_JSON(caFixed,
|
||||||
R"({
|
R"({
|
||||||
"hashAlgo": "r:sha256",
|
"hashAlgo": "r:sha256",
|
||||||
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
|
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
|
||||||
|
@ -42,7 +56,7 @@ TEST_JSON(DerivationOutput, caFixed,
|
||||||
}),
|
}),
|
||||||
"drv-name", "output-name")
|
"drv-name", "output-name")
|
||||||
|
|
||||||
TEST_JSON(DerivationOutput, caFloating,
|
TEST_JSON(caFloating,
|
||||||
R"({
|
R"({
|
||||||
"hashAlgo": "r:sha256"
|
"hashAlgo": "r:sha256"
|
||||||
})",
|
})",
|
||||||
|
@ -52,12 +66,12 @@ TEST_JSON(DerivationOutput, caFloating,
|
||||||
}),
|
}),
|
||||||
"drv-name", "output-name")
|
"drv-name", "output-name")
|
||||||
|
|
||||||
TEST_JSON(DerivationOutput, deferred,
|
TEST_JSON(deferred,
|
||||||
R"({ })",
|
R"({ })",
|
||||||
DerivationOutput::Deferred { },
|
DerivationOutput::Deferred { },
|
||||||
"drv-name", "output-name")
|
"drv-name", "output-name")
|
||||||
|
|
||||||
TEST_JSON(DerivationOutput, impure,
|
TEST_JSON(impure,
|
||||||
R"({
|
R"({
|
||||||
"hashAlgo": "r:sha256",
|
"hashAlgo": "r:sha256",
|
||||||
"impure": true
|
"impure": true
|
||||||
|
@ -68,7 +82,27 @@ TEST_JSON(DerivationOutput, impure,
|
||||||
}),
|
}),
|
||||||
"drv-name", "output-name")
|
"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"({
|
R"({
|
||||||
"inputSrcs": [
|
"inputSrcs": [
|
||||||
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"
|
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"
|
||||||
|
@ -117,7 +151,8 @@ TEST_JSON(Derivation, impure,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
drv;
|
drv;
|
||||||
}))
|
}),
|
||||||
|
"drv-name")
|
||||||
|
|
||||||
#undef TEST_JSON
|
#undef TEST_JSON
|
||||||
|
|
||||||
|
|
|
@ -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 { \
|
bool operator COMPARATOR(const MY_TYPE& other) const { \
|
||||||
const MY_TYPE* me = this; \
|
__VA_OPT__(const MY_TYPE* me = this;) \
|
||||||
auto fields1 = std::make_tuple( FIELDS ); \
|
auto fields1 = std::make_tuple( __VA_ARGS__ ); \
|
||||||
me = &other; \
|
__VA_OPT__(me = &other;) \
|
||||||
auto fields2 = std::make_tuple( FIELDS ); \
|
auto fields2 = std::make_tuple( __VA_ARGS__ ); \
|
||||||
return fields1 COMPARATOR fields2; \
|
return fields1 COMPARATOR fields2; \
|
||||||
}
|
}
|
||||||
#define GENERATE_EQUAL(args...) GENERATE_ONE_CMP(==, args)
|
#define GENERATE_EQUAL(args...) GENERATE_ONE_CMP(==, args)
|
||||||
|
|
Loading…
Reference in a new issue