mirror of
https://github.com/NixOS/nix.git
synced 2025-11-08 19:46:02 +01:00
Merge pull request #14097 from obsidiansystems/light-realisation-improvements
Realisation improvements, dummy store support, unit testing
This commit is contained in:
commit
dc8c1461da
32 changed files with 424 additions and 255 deletions
|
|
@ -117,10 +117,11 @@ RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const
|
|||
"the derivation '%s' has unrealised output '%s' (derived-path.cc/toRealisedPaths)",
|
||||
store.printStorePath(p.drvPath->outPath()),
|
||||
outputName);
|
||||
auto thisRealisation = store.queryRealisation(DrvOutput{*drvOutput, outputName});
|
||||
DrvOutput key{*drvOutput, outputName};
|
||||
auto thisRealisation = store.queryRealisation(key);
|
||||
assert(thisRealisation); // We’ve built it, so we must
|
||||
// have the realisation
|
||||
res.insert(*thisRealisation);
|
||||
res.insert(Realisation{*thisRealisation, std::move(key)});
|
||||
} else {
|
||||
res.insert(outputPath);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,32 +112,34 @@ CHARACTERIZATION_TEST(
|
|||
"realisation",
|
||||
(std::tuple<Realisation, Realisation>{
|
||||
Realisation{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
|
||||
.outputName = "baz",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
.signatures = {"asdf", "qwer"},
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
.signatures = {"asdf", "qwer"},
|
||||
},
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
|
||||
.outputName = "baz",
|
||||
},
|
||||
},
|
||||
Realisation{
|
||||
.id =
|
||||
{
|
||||
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
|
||||
.outputName = "baz",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
.signatures = {"asdf", "qwer"},
|
||||
.dependentRealisations =
|
||||
{
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
.signatures = {"asdf", "qwer"},
|
||||
.dependentRealisations =
|
||||
{
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "quux",
|
||||
{
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "quux",
|
||||
},
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
|
||||
.outputName = "baz",
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "nix/store/dummy-store.hh"
|
||||
#include "nix/store/dummy-store-impl.hh"
|
||||
#include "nix/store/globals.hh"
|
||||
#include "nix/store/realisation.hh"
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ TEST(DummyStore, realisation_read)
|
|||
auto store = [] {
|
||||
auto cfg = make_ref<DummyStoreConfig>(StoreReference::Params{});
|
||||
cfg->readOnly = false;
|
||||
return cfg->openStore();
|
||||
return cfg->openDummyStore();
|
||||
}();
|
||||
|
||||
auto drvHash = Hash::parseExplicitFormatUnprefixed(
|
||||
|
|
@ -22,6 +22,17 @@ TEST(DummyStore, realisation_read)
|
|||
auto outputName = "foo";
|
||||
|
||||
EXPECT_EQ(store->queryRealisation({drvHash, outputName}), nullptr);
|
||||
|
||||
UnkeyedRealisation value{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
|
||||
};
|
||||
|
||||
store->buildTrace.insert({drvHash, {{outputName, make_ref<UnkeyedRealisation>(value)}}});
|
||||
|
||||
auto value2 = store->queryRealisation({drvHash, outputName});
|
||||
|
||||
ASSERT_TRUE(value2);
|
||||
EXPECT_EQ(*value2, value);
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
|||
|
|
@ -49,16 +49,16 @@ INSTANTIATE_TEST_SUITE_P(
|
|||
RealisationJsonTest,
|
||||
([] {
|
||||
Realisation simple{
|
||||
|
||||
.id =
|
||||
{
|
||||
.drvHash = Hash::parseExplicitFormatUnprefixed(
|
||||
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
|
||||
HashAlgorithm::SHA256,
|
||||
HashFormat::Base16),
|
||||
.outputName = "foo",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
|
||||
},
|
||||
{
|
||||
.drvHash = Hash::parseExplicitFormatUnprefixed(
|
||||
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
|
||||
HashAlgorithm::SHA256,
|
||||
HashFormat::Base16),
|
||||
.outputName = "foo",
|
||||
},
|
||||
};
|
||||
return ::testing::Values(
|
||||
std::pair{
|
||||
|
|
|
|||
|
|
@ -95,32 +95,34 @@ VERSIONED_CHARACTERIZATION_TEST(
|
|||
defaultVersion,
|
||||
(std::tuple<Realisation, Realisation>{
|
||||
Realisation{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
|
||||
.outputName = "baz",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
.signatures = {"asdf", "qwer"},
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
.signatures = {"asdf", "qwer"},
|
||||
},
|
||||
{
|
||||
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
|
||||
.outputName = "baz",
|
||||
},
|
||||
},
|
||||
Realisation{
|
||||
.id =
|
||||
{
|
||||
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
|
||||
.outputName = "baz",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
.signatures = {"asdf", "qwer"},
|
||||
.dependentRealisations =
|
||||
{
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
.signatures = {"asdf", "qwer"},
|
||||
.dependentRealisations =
|
||||
{
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "quux",
|
||||
{
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "quux",
|
||||
},
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
|
||||
.outputName = "baz",
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
|
|
@ -196,25 +198,27 @@ VERSIONED_CHARACTERIZATION_TEST(
|
|||
{
|
||||
"foo",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"bar",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
},
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -148,32 +148,34 @@ VERSIONED_CHARACTERIZATION_TEST(
|
|||
defaultVersion,
|
||||
(std::tuple<Realisation, Realisation>{
|
||||
Realisation{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
|
||||
.outputName = "baz",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
.signatures = {"asdf", "qwer"},
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
.signatures = {"asdf", "qwer"},
|
||||
},
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
|
||||
.outputName = "baz",
|
||||
},
|
||||
},
|
||||
Realisation{
|
||||
.id =
|
||||
{
|
||||
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
|
||||
.outputName = "baz",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
.signatures = {"asdf", "qwer"},
|
||||
.dependentRealisations =
|
||||
{
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
.signatures = {"asdf", "qwer"},
|
||||
.dependentRealisations =
|
||||
{
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "quux",
|
||||
{
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "quux",
|
||||
},
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
},
|
||||
},
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
|
||||
.outputName = "baz",
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
|
|
@ -214,25 +216,25 @@ VERSIONED_CHARACTERIZATION_TEST(
|
|||
{
|
||||
"foo",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"bar",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
},
|
||||
DrvOutput{
|
||||
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -267,25 +269,27 @@ VERSIONED_CHARACTERIZATION_TEST(
|
|||
{
|
||||
"foo",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"bar",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
},
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -324,25 +328,27 @@ VERSIONED_CHARACTERIZATION_TEST(
|
|||
{
|
||||
"foo",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
|
||||
},
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"bar",
|
||||
{
|
||||
.id =
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
{
|
||||
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
|
||||
},
|
||||
DrvOutput{
|
||||
.drvHash =
|
||||
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
|
||||
.outputName = "bar",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -502,10 +502,15 @@ StorePath BinaryCacheStore::addToStore(
|
|||
->path;
|
||||
}
|
||||
|
||||
void BinaryCacheStore::queryRealisationUncached(
|
||||
const DrvOutput & id, Callback<std::shared_ptr<const Realisation>> callback) noexcept
|
||||
std::string BinaryCacheStore::makeRealisationPath(const DrvOutput & id)
|
||||
{
|
||||
auto outputInfoFilePath = realisationsPrefix + "/" + id.to_string() + ".doi";
|
||||
return realisationsPrefix + "/" + id.to_string() + ".doi";
|
||||
}
|
||||
|
||||
void BinaryCacheStore::queryRealisationUncached(
|
||||
const DrvOutput & id, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept
|
||||
{
|
||||
auto outputInfoFilePath = makeRealisationPath(id);
|
||||
|
||||
auto callbackPtr = std::make_shared<decltype(callback)>(std::move(callback));
|
||||
|
||||
|
|
@ -515,11 +520,12 @@ void BinaryCacheStore::queryRealisationUncached(
|
|||
if (!data)
|
||||
return (*callbackPtr)({});
|
||||
|
||||
std::shared_ptr<const Realisation> realisation;
|
||||
std::shared_ptr<const UnkeyedRealisation> realisation;
|
||||
try {
|
||||
realisation = std::make_shared<const Realisation>(nlohmann::json::parse(*data));
|
||||
realisation = std::make_shared<const UnkeyedRealisation>(nlohmann::json::parse(*data));
|
||||
} catch (Error & e) {
|
||||
e.addTrace({}, "while parsing file '%s' as a realisation", outputInfoFilePath);
|
||||
e.addTrace(
|
||||
{}, "while parsing file '%s' as a realisation for key '%s'", outputInfoFilePath, id.to_string());
|
||||
throw;
|
||||
}
|
||||
return (*callbackPtr)(std::move(realisation));
|
||||
|
|
@ -535,8 +541,7 @@ void BinaryCacheStore::registerDrvOutput(const Realisation & info)
|
|||
{
|
||||
if (diskCache)
|
||||
diskCache->upsertRealisation(config.getReference().render(/*FIXME withParams=*/false), info);
|
||||
auto filePath = realisationsPrefix + "/" + info.id.to_string() + ".doi";
|
||||
upsertFile(filePath, static_cast<nlohmann::json>(info).dump(), "application/json");
|
||||
upsertFile(makeRealisationPath(info.id), static_cast<nlohmann::json>(info).dump(), "application/json");
|
||||
}
|
||||
|
||||
ref<RemoteFSAccessor> BinaryCacheStore::getRemoteFSAccessor(bool requireValidPath)
|
||||
|
|
|
|||
|
|
@ -1092,13 +1092,22 @@ DerivationBuildingGoal::checkPathValidity(std::map<std::string, InitialOutput> &
|
|||
// without the `ca-derivations` experimental flag).
|
||||
worker.store.registerDrvOutput(
|
||||
Realisation{
|
||||
{
|
||||
.outPath = info.known->path,
|
||||
},
|
||||
drvOutput,
|
||||
info.known->path,
|
||||
});
|
||||
}
|
||||
}
|
||||
if (info.known && info.known->isValid())
|
||||
validOutputs.emplace(i.first, Realisation{drvOutput, info.known->path});
|
||||
validOutputs.emplace(
|
||||
i.first,
|
||||
Realisation{
|
||||
{
|
||||
.outPath = info.known->path,
|
||||
},
|
||||
drvOutput,
|
||||
});
|
||||
}
|
||||
|
||||
bool allValid = true;
|
||||
|
|
|
|||
|
|
@ -190,13 +190,17 @@ Goal::Co DerivationGoal::haveDerivation(bool storeDerivation)
|
|||
auto realisation = [&] {
|
||||
auto take1 = get(success.builtOutputs, wantedOutput);
|
||||
if (take1)
|
||||
return *take1;
|
||||
return static_cast<UnkeyedRealisation>(*take1);
|
||||
|
||||
/* The above `get` should work. But stateful tracking of
|
||||
outputs in resolvedResult, this can get out of sync with the
|
||||
store, which is our actual source of truth. For now we just
|
||||
check the store directly if it fails. */
|
||||
auto take2 = worker.evalStore.queryRealisation(DrvOutput{*resolvedHash, wantedOutput});
|
||||
auto take2 = worker.evalStore.queryRealisation(
|
||||
DrvOutput{
|
||||
.drvHash = *resolvedHash,
|
||||
.outputName = wantedOutput,
|
||||
});
|
||||
if (take2)
|
||||
return *take2;
|
||||
|
||||
|
|
@ -207,8 +211,12 @@ Goal::Co DerivationGoal::haveDerivation(bool storeDerivation)
|
|||
}();
|
||||
|
||||
if (!drv->type().isImpure()) {
|
||||
auto newRealisation = realisation;
|
||||
newRealisation.id = DrvOutput{*outputHash, wantedOutput};
|
||||
Realisation newRealisation{
|
||||
realisation,
|
||||
{
|
||||
.drvHash = *outputHash,
|
||||
.outputName = wantedOutput,
|
||||
}};
|
||||
newRealisation.signatures.clear();
|
||||
if (!drv->type().isFixed()) {
|
||||
auto & drvStore = worker.evalStore.isValidPath(drvPath) ? worker.evalStore : worker.store;
|
||||
|
|
@ -258,7 +266,16 @@ Goal::Co DerivationGoal::haveDerivation(bool storeDerivation)
|
|||
/* In checking mode, the builder will not register any outputs.
|
||||
So we want to make sure the ones that we wanted to check are
|
||||
properly there. */
|
||||
success.builtOutputs = {{wantedOutput, assertPathValidity()}};
|
||||
success.builtOutputs = {{
|
||||
wantedOutput,
|
||||
{
|
||||
assertPathValidity(),
|
||||
{
|
||||
.drvHash = outputHash,
|
||||
.outputName = wantedOutput,
|
||||
},
|
||||
},
|
||||
}};
|
||||
} else {
|
||||
/* Otherwise the builder will give us info for out output, but
|
||||
also for other outputs. Filter down to just our output so as
|
||||
|
|
@ -373,18 +390,20 @@ Goal::Co DerivationGoal::repairClosure()
|
|||
co_return doneSuccess(BuildResult::Success::AlreadyValid, assertPathValidity());
|
||||
}
|
||||
|
||||
std::optional<std::pair<Realisation, PathStatus>> DerivationGoal::checkPathValidity()
|
||||
std::optional<std::pair<UnkeyedRealisation, PathStatus>> DerivationGoal::checkPathValidity()
|
||||
{
|
||||
if (drv->type().isImpure())
|
||||
return std::nullopt;
|
||||
|
||||
auto drvOutput = DrvOutput{outputHash, wantedOutput};
|
||||
|
||||
std::optional<Realisation> mRealisation;
|
||||
std::optional<UnkeyedRealisation> mRealisation;
|
||||
|
||||
if (auto * mOutput = get(drv->outputs, wantedOutput)) {
|
||||
if (auto mPath = mOutput->path(worker.store, drv->name, wantedOutput)) {
|
||||
mRealisation = Realisation{drvOutput, std::move(*mPath)};
|
||||
mRealisation = UnkeyedRealisation{
|
||||
.outPath = std::move(*mPath),
|
||||
};
|
||||
}
|
||||
} else {
|
||||
throw Error(
|
||||
|
|
@ -412,7 +431,14 @@ std::optional<std::pair<Realisation, PathStatus>> DerivationGoal::checkPathValid
|
|||
// derivation, and the output path is valid, but we don't have
|
||||
// its realisation stored (probably because it has been built
|
||||
// without the `ca-derivations` experimental flag).
|
||||
worker.store.registerDrvOutput(*mRealisation);
|
||||
worker.store.registerDrvOutput(
|
||||
Realisation{
|
||||
*mRealisation,
|
||||
{
|
||||
.drvHash = outputHash,
|
||||
.outputName = wantedOutput,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return {{*mRealisation, status}};
|
||||
|
|
@ -420,7 +446,7 @@ std::optional<std::pair<Realisation, PathStatus>> DerivationGoal::checkPathValid
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
Realisation DerivationGoal::assertPathValidity()
|
||||
UnkeyedRealisation DerivationGoal::assertPathValidity()
|
||||
{
|
||||
auto checkResult = checkPathValidity();
|
||||
if (!(checkResult && checkResult->second == PathStatus::Valid))
|
||||
|
|
@ -428,11 +454,20 @@ Realisation DerivationGoal::assertPathValidity()
|
|||
return checkResult->first;
|
||||
}
|
||||
|
||||
Goal::Done DerivationGoal::doneSuccess(BuildResult::Success::Status status, Realisation builtOutput)
|
||||
Goal::Done DerivationGoal::doneSuccess(BuildResult::Success::Status status, UnkeyedRealisation builtOutput)
|
||||
{
|
||||
buildResult.inner = BuildResult::Success{
|
||||
.status = status,
|
||||
.builtOutputs = {{wantedOutput, std::move(builtOutput)}},
|
||||
.builtOutputs = {{
|
||||
wantedOutput,
|
||||
{
|
||||
std::move(builtOutput),
|
||||
DrvOutput{
|
||||
.drvHash = outputHash,
|
||||
.outputName = wantedOutput,
|
||||
},
|
||||
},
|
||||
}},
|
||||
};
|
||||
|
||||
mcExpectedBuilds.reset();
|
||||
|
|
|
|||
|
|
@ -43,10 +43,10 @@ Goal::Co DrvOutputSubstitutionGoal::init()
|
|||
outPipe->createAsyncPipe(worker.ioport.get());
|
||||
#endif
|
||||
|
||||
auto promise = std::make_shared<std::promise<std::shared_ptr<const Realisation>>>();
|
||||
auto promise = std::make_shared<std::promise<std::shared_ptr<const UnkeyedRealisation>>>();
|
||||
|
||||
sub->queryRealisation(
|
||||
id, {[outPipe(outPipe), promise(promise)](std::future<std::shared_ptr<const Realisation>> res) {
|
||||
id, {[outPipe(outPipe), promise(promise)](std::future<std::shared_ptr<const UnkeyedRealisation>> res) {
|
||||
try {
|
||||
Finally updateStats([&]() { outPipe->writeSide.close(); });
|
||||
promise->set_value(res.get());
|
||||
|
|
@ -75,7 +75,7 @@ Goal::Co DrvOutputSubstitutionGoal::init()
|
|||
* The realisation corresponding to the given output id.
|
||||
* Will be filled once we can get it.
|
||||
*/
|
||||
std::shared_ptr<const Realisation> outputInfo;
|
||||
std::shared_ptr<const UnkeyedRealisation> outputInfo;
|
||||
|
||||
try {
|
||||
outputInfo = promise->get_future().get();
|
||||
|
|
@ -132,7 +132,7 @@ Goal::Co DrvOutputSubstitutionGoal::init()
|
|||
}
|
||||
|
||||
Goal::Co DrvOutputSubstitutionGoal::realisationFetched(
|
||||
Goals waitees, std::shared_ptr<const Realisation> outputInfo, nix::ref<nix::Store> sub)
|
||||
Goals waitees, std::shared_ptr<const UnkeyedRealisation> outputInfo, nix::ref<nix::Store> sub)
|
||||
{
|
||||
waitees.insert(worker.makePathSubstitutionGoal(outputInfo->outPath));
|
||||
|
||||
|
|
@ -145,7 +145,7 @@ Goal::Co DrvOutputSubstitutionGoal::realisationFetched(
|
|||
co_return amDone(nrNoSubstituters > 0 ? ecNoSubstituters : ecFailed);
|
||||
}
|
||||
|
||||
worker.store.registerDrvOutput(*outputInfo);
|
||||
worker.store.registerDrvOutput({*outputInfo, id});
|
||||
|
||||
trace("finished");
|
||||
co_return amDone(ecSuccess);
|
||||
|
|
|
|||
|
|
@ -964,7 +964,7 @@ static void performOp(
|
|||
if (GET_PROTOCOL_MINOR(conn.protoVersion) < 31) {
|
||||
auto outputId = DrvOutput::parse(readString(conn.from));
|
||||
auto outputPath = StorePath(readString(conn.from));
|
||||
store->registerDrvOutput(Realisation{.id = outputId, .outPath = outputPath});
|
||||
store->registerDrvOutput(Realisation{{.outPath = outputPath}, outputId});
|
||||
} else {
|
||||
auto realisation = WorkerProto::Serialise<Realisation>::read(*store, rconn);
|
||||
store->registerDrvOutput(realisation);
|
||||
|
|
@ -986,7 +986,7 @@ static void performOp(
|
|||
} else {
|
||||
std::set<Realisation> realisations;
|
||||
if (info)
|
||||
realisations.insert(*info);
|
||||
realisations.insert({*info, outputId});
|
||||
WorkerProto::write(*store, wconn, realisations);
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "nix/util/callback.hh"
|
||||
#include "nix/util/memory-source-accessor.hh"
|
||||
#include "nix/store/dummy-store-impl.hh"
|
||||
#include "nix/store/realisation.hh"
|
||||
|
||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||
|
||||
|
|
@ -251,7 +252,10 @@ struct DummyStoreImpl : DummyStore
|
|||
|
||||
void registerDrvOutput(const Realisation & output) override
|
||||
{
|
||||
unsupported("registerDrvOutput");
|
||||
auto ref = make_ref<UnkeyedRealisation>(output);
|
||||
buildTrace.insert_or_visit({output.id.drvHash, {{output.id.outputName, ref}}}, [&](auto & kv) {
|
||||
kv.second.insert_or_assign(output.id.outputName, make_ref<UnkeyedRealisation>(output));
|
||||
});
|
||||
}
|
||||
|
||||
void narFromPath(const StorePath & path, Sink & sink) override
|
||||
|
|
@ -266,10 +270,19 @@ struct DummyStoreImpl : DummyStore
|
|||
throw Error("path '%s' is not valid", printStorePath(path));
|
||||
}
|
||||
|
||||
void
|
||||
queryRealisationUncached(const DrvOutput &, Callback<std::shared_ptr<const Realisation>> callback) noexcept override
|
||||
void queryRealisationUncached(
|
||||
const DrvOutput & drvOutput, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept override
|
||||
{
|
||||
callback(nullptr);
|
||||
bool visited = false;
|
||||
buildTrace.cvisit(drvOutput.drvHash, [&](const auto & kv) {
|
||||
if (auto it = kv.second.find(drvOutput.outputName); it != kv.second.end()) {
|
||||
visited = true;
|
||||
callback(it->second.get_ptr());
|
||||
}
|
||||
});
|
||||
|
||||
if (!visited)
|
||||
callback(nullptr);
|
||||
}
|
||||
|
||||
std::shared_ptr<SourceAccessor> getFSAccessor(const StorePath & path, bool requireValidPath) override
|
||||
|
|
|
|||
|
|
@ -95,13 +95,22 @@ private:
|
|||
|
||||
protected:
|
||||
|
||||
// The prefix under which realisation infos will be stored
|
||||
const std::string realisationsPrefix = "realisations";
|
||||
/**
|
||||
* The prefix under which realisation infos will be stored
|
||||
*/
|
||||
constexpr const static std::string realisationsPrefix = "realisations";
|
||||
|
||||
const std::string cacheInfoFile = "nix-cache-info";
|
||||
constexpr const static std::string cacheInfoFile = "nix-cache-info";
|
||||
|
||||
BinaryCacheStore(Config &);
|
||||
|
||||
/**
|
||||
* Compute the path to the given realisation
|
||||
*
|
||||
* It's `${realisationsPrefix}/${drvOutput}.doi`.
|
||||
*/
|
||||
std::string makeRealisationPath(const DrvOutput & id);
|
||||
|
||||
public:
|
||||
|
||||
virtual bool fileExists(const std::string & path) = 0;
|
||||
|
|
@ -190,7 +199,7 @@ public:
|
|||
void registerDrvOutput(const Realisation & info) override;
|
||||
|
||||
void queryRealisationUncached(
|
||||
const DrvOutput &, Callback<std::shared_ptr<const Realisation>> callback) noexcept override;
|
||||
const DrvOutput &, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept override;
|
||||
|
||||
void narFromPath(const StorePath & path, Sink & sink) override;
|
||||
|
||||
|
|
|
|||
|
|
@ -93,17 +93,17 @@ private:
|
|||
* of the wanted output, and a `PathStatus` with the
|
||||
* current status of that output.
|
||||
*/
|
||||
std::optional<std::pair<Realisation, PathStatus>> checkPathValidity();
|
||||
std::optional<std::pair<UnkeyedRealisation, PathStatus>> checkPathValidity();
|
||||
|
||||
/**
|
||||
* Aborts if any output is not valid or corrupt, and otherwise
|
||||
* returns a 'Realisation' for the wanted output.
|
||||
*/
|
||||
Realisation assertPathValidity();
|
||||
UnkeyedRealisation assertPathValidity();
|
||||
|
||||
Co repairClosure();
|
||||
|
||||
Done doneSuccess(BuildResult::Success::Status status, Realisation builtOutput);
|
||||
Done doneSuccess(BuildResult::Success::Status status, UnkeyedRealisation builtOutput);
|
||||
|
||||
Done doneFailure(BuildError ex);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ public:
|
|||
GoalState state;
|
||||
|
||||
Co init();
|
||||
Co realisationFetched(Goals waitees, std::shared_ptr<const Realisation> outputInfo, nix::ref<nix::Store> sub);
|
||||
Co
|
||||
realisationFetched(Goals waitees, std::shared_ptr<const UnkeyedRealisation> outputInfo, nix::ref<nix::Store> sub);
|
||||
|
||||
void timedOut(Error && ex) override
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,6 +30,18 @@ struct DummyStore : virtual Store
|
|||
*/
|
||||
boost::concurrent_flat_map<StorePath, PathInfoAndContents> contents;
|
||||
|
||||
/**
|
||||
* The build trace maps the pair of a content-addressing (fixed or
|
||||
* floating) derivations an one of its output to a
|
||||
* (content-addressed) store object.
|
||||
*
|
||||
* It is [curried](https://en.wikipedia.org/wiki/Currying), so we
|
||||
* instead having a single output with a `DrvOutput` key, we have an
|
||||
* outer map for the derivation, and inner maps for the outputs of a
|
||||
* given derivation.
|
||||
*/
|
||||
boost::concurrent_flat_map<Hash, std::map<std::string, ref<UnkeyedRealisation>>> buildTrace;
|
||||
|
||||
DummyStore(ref<const Config> config)
|
||||
: Store{*config}
|
||||
, config(config)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "nix/store/store-api.hh"
|
||||
|
||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||
|
||||
namespace nix {
|
||||
|
||||
struct DummyStore;
|
||||
|
|
|
|||
|
|
@ -208,8 +208,8 @@ public:
|
|||
*/
|
||||
std::optional<TrustedFlag> isTrustedClient() override;
|
||||
|
||||
void
|
||||
queryRealisationUncached(const DrvOutput &, Callback<std::shared_ptr<const Realisation>> callback) noexcept override
|
||||
void queryRealisationUncached(
|
||||
const DrvOutput &, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept override
|
||||
// TODO: Implement
|
||||
{
|
||||
unsupported("queryRealisation");
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ private:
|
|||
* Check lower store if upper DB does not have.
|
||||
*/
|
||||
void queryRealisationUncached(
|
||||
const DrvOutput &, Callback<std::shared_ptr<const Realisation>> callback) noexcept override;
|
||||
const DrvOutput &, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept override;
|
||||
|
||||
/**
|
||||
* Call `remountIfNecessary` after collecting garbage normally.
|
||||
|
|
|
|||
|
|
@ -385,10 +385,10 @@ public:
|
|||
void cacheDrvOutputMapping(
|
||||
State & state, const uint64_t deriver, const std::string & outputName, const StorePath & output);
|
||||
|
||||
std::optional<const Realisation> queryRealisation_(State & state, const DrvOutput & id);
|
||||
std::optional<std::pair<int64_t, Realisation>> queryRealisationCore_(State & state, const DrvOutput & id);
|
||||
std::optional<const UnkeyedRealisation> queryRealisation_(State & state, const DrvOutput & id);
|
||||
std::optional<std::pair<int64_t, UnkeyedRealisation>> queryRealisationCore_(State & state, const DrvOutput & id);
|
||||
void queryRealisationUncached(
|
||||
const DrvOutput &, Callback<std::shared_ptr<const Realisation>> callback) noexcept override;
|
||||
const DrvOutput &, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept override;
|
||||
|
||||
std::optional<std::string> getVersion() override;
|
||||
|
||||
|
|
|
|||
|
|
@ -46,12 +46,12 @@ struct DrvOutput
|
|||
|
||||
static DrvOutput parse(const std::string &);
|
||||
|
||||
GENERATE_CMP(DrvOutput, me->drvHash, me->outputName);
|
||||
bool operator==(const DrvOutput &) const = default;
|
||||
auto operator<=>(const DrvOutput &) const = default;
|
||||
};
|
||||
|
||||
struct Realisation
|
||||
struct UnkeyedRealisation
|
||||
{
|
||||
DrvOutput id;
|
||||
StorePath outPath;
|
||||
|
||||
StringSet signatures;
|
||||
|
|
@ -64,22 +64,35 @@ struct Realisation
|
|||
*/
|
||||
std::map<DrvOutput, StorePath> dependentRealisations;
|
||||
|
||||
std::string fingerprint() const;
|
||||
void sign(const Signer &);
|
||||
bool checkSignature(const PublicKeys & publicKeys, const std::string & sig) const;
|
||||
size_t checkSignatures(const PublicKeys & publicKeys) const;
|
||||
std::string fingerprint(const DrvOutput & key) const;
|
||||
|
||||
static std::set<Realisation> closure(Store &, const std::set<Realisation> &);
|
||||
static void closure(Store &, const std::set<Realisation> &, std::set<Realisation> & res);
|
||||
void sign(const DrvOutput & key, const Signer &);
|
||||
|
||||
bool isCompatibleWith(const Realisation & other) const;
|
||||
bool checkSignature(const DrvOutput & key, const PublicKeys & publicKeys, const std::string & sig) const;
|
||||
|
||||
StorePath getPath() const
|
||||
size_t checkSignatures(const DrvOutput & key, const PublicKeys & publicKeys) const;
|
||||
|
||||
const StorePath & getPath() const
|
||||
{
|
||||
return outPath;
|
||||
}
|
||||
|
||||
GENERATE_CMP(Realisation, me->id, me->outPath);
|
||||
// TODO sketchy that it avoids signatures
|
||||
GENERATE_CMP(UnkeyedRealisation, me->outPath);
|
||||
};
|
||||
|
||||
struct Realisation : UnkeyedRealisation
|
||||
{
|
||||
DrvOutput id;
|
||||
|
||||
bool isCompatibleWith(const UnkeyedRealisation & other) const;
|
||||
|
||||
static std::set<Realisation> closure(Store &, const std::set<Realisation> &);
|
||||
|
||||
static void closure(Store &, const std::set<Realisation> &, std::set<Realisation> & res);
|
||||
|
||||
bool operator==(const Realisation &) const = default;
|
||||
auto operator<=>(const Realisation &) const = default;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -103,12 +116,13 @@ struct OpaquePath
|
|||
{
|
||||
StorePath path;
|
||||
|
||||
StorePath getPath() const
|
||||
const StorePath & getPath() const
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
GENERATE_CMP(OpaquePath, me->path);
|
||||
bool operator==(const OpaquePath &) const = default;
|
||||
auto operator<=>(const OpaquePath &) const = default;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -116,7 +130,7 @@ struct OpaquePath
|
|||
*/
|
||||
struct RealisedPath
|
||||
{
|
||||
/*
|
||||
/**
|
||||
* A path is either the result of the realisation of a derivation or
|
||||
* an opaque blob that has been directly added to the store
|
||||
*/
|
||||
|
|
@ -138,13 +152,14 @@ struct RealisedPath
|
|||
/**
|
||||
* Get the raw store path associated to this
|
||||
*/
|
||||
StorePath path() const;
|
||||
const StorePath & path() const;
|
||||
|
||||
void closure(Store & store, Set & ret) const;
|
||||
static void closure(Store & store, const Set & startPaths, Set & ret);
|
||||
Set closure(Store & store) const;
|
||||
|
||||
GENERATE_CMP(RealisedPath, me->raw);
|
||||
bool operator==(const RealisedPath &) const = default;
|
||||
auto operator<=>(const RealisedPath &) const = default;
|
||||
};
|
||||
|
||||
class MissingRealisation : public Error
|
||||
|
|
@ -167,4 +182,5 @@ public:
|
|||
|
||||
} // namespace nix
|
||||
|
||||
JSON_IMPL(nix::UnkeyedRealisation)
|
||||
JSON_IMPL(nix::Realisation)
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ struct RemoteStore : public virtual Store, public virtual GcStore, public virtua
|
|||
void registerDrvOutput(const Realisation & info) override;
|
||||
|
||||
void queryRealisationUncached(
|
||||
const DrvOutput &, Callback<std::shared_ptr<const Realisation>> callback) noexcept override;
|
||||
const DrvOutput &, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept override;
|
||||
|
||||
void
|
||||
buildPaths(const std::vector<DerivedPath> & paths, BuildMode buildMode, std::shared_ptr<Store> evalStore) override;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ MakeError(SubstituterDisabled, Error);
|
|||
|
||||
MakeError(InvalidStoreReference, Error);
|
||||
|
||||
struct UnkeyedRealisation;
|
||||
struct Realisation;
|
||||
struct RealisedPath;
|
||||
struct DrvOutput;
|
||||
|
|
@ -398,12 +399,12 @@ public:
|
|||
/**
|
||||
* Query the information about a realisation.
|
||||
*/
|
||||
std::shared_ptr<const Realisation> queryRealisation(const DrvOutput &);
|
||||
std::shared_ptr<const UnkeyedRealisation> queryRealisation(const DrvOutput &);
|
||||
|
||||
/**
|
||||
* Asynchronous version of queryRealisation().
|
||||
*/
|
||||
void queryRealisation(const DrvOutput &, Callback<std::shared_ptr<const Realisation>> callback) noexcept;
|
||||
void queryRealisation(const DrvOutput &, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept;
|
||||
|
||||
/**
|
||||
* Check whether the given valid path info is sufficiently attested, by
|
||||
|
|
@ -430,8 +431,8 @@ protected:
|
|||
|
||||
virtual void
|
||||
queryPathInfoUncached(const StorePath & path, Callback<std::shared_ptr<const ValidPathInfo>> callback) noexcept = 0;
|
||||
virtual void
|
||||
queryRealisationUncached(const DrvOutput &, Callback<std::shared_ptr<const Realisation>> callback) noexcept = 0;
|
||||
virtual void queryRealisationUncached(
|
||||
const DrvOutput &, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept = 0;
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ void LocalOverlayStore::registerDrvOutput(const Realisation & info)
|
|||
// First do queryRealisation on lower layer to populate DB
|
||||
auto res = lowerStore->queryRealisation(info.id);
|
||||
if (res)
|
||||
LocalStore::registerDrvOutput(*res);
|
||||
LocalStore::registerDrvOutput({*res, info.id});
|
||||
|
||||
LocalStore::registerDrvOutput(info);
|
||||
}
|
||||
|
|
@ -108,12 +108,12 @@ void LocalOverlayStore::queryPathInfoUncached(
|
|||
}
|
||||
|
||||
void LocalOverlayStore::queryRealisationUncached(
|
||||
const DrvOutput & drvOutput, Callback<std::shared_ptr<const Realisation>> callback) noexcept
|
||||
const DrvOutput & drvOutput, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept
|
||||
{
|
||||
auto callbackPtr = std::make_shared<decltype(callback)>(std::move(callback));
|
||||
|
||||
LocalStore::queryRealisationUncached(
|
||||
drvOutput, {[this, drvOutput, callbackPtr](std::future<std::shared_ptr<const Realisation>> fut) {
|
||||
drvOutput, {[this, drvOutput, callbackPtr](std::future<std::shared_ptr<const UnkeyedRealisation>> fut) {
|
||||
try {
|
||||
auto info = fut.get();
|
||||
if (info)
|
||||
|
|
@ -123,7 +123,7 @@ void LocalOverlayStore::queryRealisationUncached(
|
|||
}
|
||||
// If we don't have it, check lower store
|
||||
lowerStore->queryRealisation(
|
||||
drvOutput, {[callbackPtr](std::future<std::shared_ptr<const Realisation>> fut) {
|
||||
drvOutput, {[callbackPtr](std::future<std::shared_ptr<const UnkeyedRealisation>> fut) {
|
||||
try {
|
||||
(*callbackPtr)(fut.get());
|
||||
} catch (...) {
|
||||
|
|
|
|||
|
|
@ -1036,7 +1036,7 @@ bool LocalStore::pathInfoIsUntrusted(const ValidPathInfo & info)
|
|||
|
||||
bool LocalStore::realisationIsUntrusted(const Realisation & realisation)
|
||||
{
|
||||
return config->requireSigs && !realisation.checkSignatures(getPublicKeys());
|
||||
return config->requireSigs && !realisation.checkSignatures(realisation.id, getPublicKeys());
|
||||
}
|
||||
|
||||
void LocalStore::addToStore(const ValidPathInfo & info, Source & source, RepairFlag repair, CheckSigsFlag checkSigs)
|
||||
|
|
@ -1586,7 +1586,7 @@ void LocalStore::addSignatures(const StorePath & storePath, const StringSet & si
|
|||
});
|
||||
}
|
||||
|
||||
std::optional<std::pair<int64_t, Realisation>>
|
||||
std::optional<std::pair<int64_t, UnkeyedRealisation>>
|
||||
LocalStore::queryRealisationCore_(LocalStore::State & state, const DrvOutput & id)
|
||||
{
|
||||
auto useQueryRealisedOutput(state.stmts->QueryRealisedOutput.use()(id.strHash())(id.outputName));
|
||||
|
|
@ -1598,14 +1598,13 @@ LocalStore::queryRealisationCore_(LocalStore::State & state, const DrvOutput & i
|
|||
|
||||
return {
|
||||
{realisationDbId,
|
||||
Realisation{
|
||||
.id = id,
|
||||
UnkeyedRealisation{
|
||||
.outPath = outputPath,
|
||||
.signatures = signatures,
|
||||
}}};
|
||||
}
|
||||
|
||||
std::optional<const Realisation> LocalStore::queryRealisation_(LocalStore::State & state, const DrvOutput & id)
|
||||
std::optional<const UnkeyedRealisation> LocalStore::queryRealisation_(LocalStore::State & state, const DrvOutput & id)
|
||||
{
|
||||
auto maybeCore = queryRealisationCore_(state, id);
|
||||
if (!maybeCore)
|
||||
|
|
@ -1631,13 +1630,13 @@ std::optional<const Realisation> LocalStore::queryRealisation_(LocalStore::State
|
|||
}
|
||||
|
||||
void LocalStore::queryRealisationUncached(
|
||||
const DrvOutput & id, Callback<std::shared_ptr<const Realisation>> callback) noexcept
|
||||
const DrvOutput & id, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept
|
||||
{
|
||||
try {
|
||||
auto maybeRealisation =
|
||||
retrySQLite<std::optional<const Realisation>>([&]() { return queryRealisation_(*_state->lock(), id); });
|
||||
auto maybeRealisation = retrySQLite<std::optional<const UnkeyedRealisation>>(
|
||||
[&]() { return queryRealisation_(*_state->lock(), id); });
|
||||
if (maybeRealisation)
|
||||
callback(std::make_shared<const Realisation>(maybeRealisation.value()));
|
||||
callback(std::make_shared<const UnkeyedRealisation>(maybeRealisation.value()));
|
||||
else
|
||||
callback(nullptr);
|
||||
|
||||
|
|
|
|||
|
|
@ -360,11 +360,12 @@ drvOutputReferences(Store & store, const Derivation & drv, const StorePath & out
|
|||
if (!outputHash)
|
||||
throw Error(
|
||||
"output '%s' of derivation '%s' isn't realised", outputName, store.printStorePath(inputDrv));
|
||||
auto thisRealisation = store.queryRealisation(DrvOutput{*outputHash, outputName});
|
||||
DrvOutput key{*outputHash, outputName};
|
||||
auto thisRealisation = store.queryRealisation(key);
|
||||
if (!thisRealisation)
|
||||
throw Error(
|
||||
"output '%s' of derivation '%s' isn’t built", outputName, store.printStorePath(inputDrv));
|
||||
inputRealisations.insert(*thisRealisation);
|
||||
inputRealisations.insert({*thisRealisation, std::move(key)});
|
||||
}
|
||||
}
|
||||
if (!inputNode.value.empty()) {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ void Realisation::closure(Store & store, const std::set<Realisation> & startOutp
|
|||
std::set<Realisation> res;
|
||||
for (auto & [currentDep, _] : current.dependentRealisations) {
|
||||
if (auto currentRealisation = store.queryRealisation(currentDep))
|
||||
res.insert(*currentRealisation);
|
||||
res.insert({*currentRealisation, currentDep});
|
||||
else
|
||||
throw Error("Unrealised derivation '%s'", currentDep.to_string());
|
||||
}
|
||||
|
|
@ -61,24 +61,25 @@ void Realisation::closure(Store & store, const std::set<Realisation> & startOutp
|
|||
});
|
||||
}
|
||||
|
||||
std::string Realisation::fingerprint() const
|
||||
std::string UnkeyedRealisation::fingerprint(const DrvOutput & key) const
|
||||
{
|
||||
nlohmann::json serialized = *this;
|
||||
nlohmann::json serialized = Realisation{*this, key};
|
||||
serialized.erase("signatures");
|
||||
return serialized.dump();
|
||||
}
|
||||
|
||||
void Realisation::sign(const Signer & signer)
|
||||
void UnkeyedRealisation::sign(const DrvOutput & key, const Signer & signer)
|
||||
{
|
||||
signatures.insert(signer.signDetached(fingerprint()));
|
||||
signatures.insert(signer.signDetached(fingerprint(key)));
|
||||
}
|
||||
|
||||
bool Realisation::checkSignature(const PublicKeys & publicKeys, const std::string & sig) const
|
||||
bool UnkeyedRealisation::checkSignature(
|
||||
const DrvOutput & key, const PublicKeys & publicKeys, const std::string & sig) const
|
||||
{
|
||||
return verifyDetached(fingerprint(), sig, publicKeys);
|
||||
return verifyDetached(fingerprint(key), sig, publicKeys);
|
||||
}
|
||||
|
||||
size_t Realisation::checkSignatures(const PublicKeys & publicKeys) const
|
||||
size_t UnkeyedRealisation::checkSignatures(const DrvOutput & key, const PublicKeys & publicKeys) const
|
||||
{
|
||||
// FIXME: Maybe we should return `maxSigs` if the realisation corresponds to
|
||||
// an input-addressed one − because in that case the drv is enough to check
|
||||
|
|
@ -86,19 +87,18 @@ size_t Realisation::checkSignatures(const PublicKeys & publicKeys) const
|
|||
|
||||
size_t good = 0;
|
||||
for (auto & sig : signatures)
|
||||
if (checkSignature(publicKeys, sig))
|
||||
if (checkSignature(key, publicKeys, sig))
|
||||
good++;
|
||||
return good;
|
||||
}
|
||||
|
||||
StorePath RealisedPath::path() const
|
||||
const StorePath & RealisedPath::path() const
|
||||
{
|
||||
return std::visit([](auto && arg) { return arg.getPath(); }, raw);
|
||||
return std::visit([](auto && arg) -> auto & { return arg.getPath(); }, raw);
|
||||
}
|
||||
|
||||
bool Realisation::isCompatibleWith(const Realisation & other) const
|
||||
bool Realisation::isCompatibleWith(const UnkeyedRealisation & other) const
|
||||
{
|
||||
assert(id == other.id);
|
||||
if (outPath == other.outPath) {
|
||||
if (dependentRealisations.empty() != other.dependentRealisations.empty()) {
|
||||
warn(
|
||||
|
|
@ -144,7 +144,7 @@ namespace nlohmann {
|
|||
|
||||
using namespace nix;
|
||||
|
||||
Realisation adl_serializer<Realisation>::from_json(const json & json0)
|
||||
UnkeyedRealisation adl_serializer<UnkeyedRealisation>::from_json(const json & json0)
|
||||
{
|
||||
auto json = getObject(json0);
|
||||
|
||||
|
|
@ -157,25 +157,39 @@ Realisation adl_serializer<Realisation>::from_json(const json & json0)
|
|||
for (auto & [jsonDepId, jsonDepOutPath] : getObject(*jsonDependencies))
|
||||
dependentRealisations.insert({DrvOutput::parse(jsonDepId), jsonDepOutPath});
|
||||
|
||||
return Realisation{
|
||||
.id = DrvOutput::parse(valueAt(json, "id")),
|
||||
return UnkeyedRealisation{
|
||||
.outPath = valueAt(json, "outPath"),
|
||||
.signatures = signatures,
|
||||
.dependentRealisations = dependentRealisations,
|
||||
};
|
||||
}
|
||||
|
||||
void adl_serializer<Realisation>::to_json(json & json, const Realisation & r)
|
||||
void adl_serializer<UnkeyedRealisation>::to_json(json & json, const UnkeyedRealisation & r)
|
||||
{
|
||||
auto jsonDependentRealisations = nlohmann::json::object();
|
||||
for (auto & [depId, depOutPath] : r.dependentRealisations)
|
||||
jsonDependentRealisations.emplace(depId.to_string(), depOutPath);
|
||||
json = {
|
||||
{"id", r.id.to_string()},
|
||||
{"outPath", r.outPath},
|
||||
{"signatures", r.signatures},
|
||||
{"dependentRealisations", jsonDependentRealisations},
|
||||
};
|
||||
}
|
||||
|
||||
Realisation adl_serializer<Realisation>::from_json(const json & json0)
|
||||
{
|
||||
auto json = getObject(json0);
|
||||
|
||||
return Realisation{
|
||||
static_cast<UnkeyedRealisation>(json0),
|
||||
DrvOutput::parse(valueAt(json, "id")),
|
||||
};
|
||||
}
|
||||
|
||||
void adl_serializer<Realisation>::to_json(json & json, const Realisation & r)
|
||||
{
|
||||
json = static_cast<const UnkeyedRealisation &>(r);
|
||||
json["id"] = r.id.to_string();
|
||||
}
|
||||
|
||||
} // namespace nlohmann
|
||||
|
|
|
|||
|
|
@ -501,7 +501,7 @@ void RemoteStore::registerDrvOutput(const Realisation & info)
|
|||
}
|
||||
|
||||
void RemoteStore::queryRealisationUncached(
|
||||
const DrvOutput & id, Callback<std::shared_ptr<const Realisation>> callback) noexcept
|
||||
const DrvOutput & id, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept
|
||||
{
|
||||
try {
|
||||
auto conn(getConnection());
|
||||
|
|
@ -515,21 +515,21 @@ void RemoteStore::queryRealisationUncached(
|
|||
conn->to << id.to_string();
|
||||
conn.processStderr();
|
||||
|
||||
auto real = [&]() -> std::shared_ptr<const Realisation> {
|
||||
auto real = [&]() -> std::shared_ptr<const UnkeyedRealisation> {
|
||||
if (GET_PROTOCOL_MINOR(conn->protoVersion) < 31) {
|
||||
auto outPaths = WorkerProto::Serialise<std::set<StorePath>>::read(*this, *conn);
|
||||
if (outPaths.empty())
|
||||
return nullptr;
|
||||
return std::make_shared<const Realisation>(Realisation{.id = id, .outPath = *outPaths.begin()});
|
||||
return std::make_shared<const UnkeyedRealisation>(UnkeyedRealisation{.outPath = *outPaths.begin()});
|
||||
} else {
|
||||
auto realisations = WorkerProto::Serialise<std::set<Realisation>>::read(*this, *conn);
|
||||
if (realisations.empty())
|
||||
return nullptr;
|
||||
return std::make_shared<const Realisation>(*realisations.begin());
|
||||
return std::make_shared<const UnkeyedRealisation>(*realisations.begin());
|
||||
}
|
||||
}();
|
||||
|
||||
callback(std::shared_ptr<const Realisation>(real));
|
||||
callback(std::shared_ptr<const UnkeyedRealisation>(real));
|
||||
} catch (...) {
|
||||
return callback.rethrow();
|
||||
}
|
||||
|
|
@ -626,13 +626,15 @@ std::vector<KeyedBuildResult> RemoteStore::buildPathsWithResults(
|
|||
auto realisation = queryRealisation(outputId);
|
||||
if (!realisation)
|
||||
throw MissingRealisation(outputId);
|
||||
success.builtOutputs.emplace(output, *realisation);
|
||||
success.builtOutputs.emplace(output, Realisation{*realisation, outputId});
|
||||
} else {
|
||||
success.builtOutputs.emplace(
|
||||
output,
|
||||
Realisation{
|
||||
.id = outputId,
|
||||
.outPath = outputPath,
|
||||
UnkeyedRealisation{
|
||||
.outPath = outputPath,
|
||||
},
|
||||
outputId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ struct RestrictedStore : public virtual IndirectRootStore, public virtual GcStor
|
|||
void registerDrvOutput(const Realisation & info) override;
|
||||
|
||||
void queryRealisationUncached(
|
||||
const DrvOutput & id, Callback<std::shared_ptr<const Realisation>> callback) noexcept override;
|
||||
const DrvOutput & id, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept override;
|
||||
|
||||
void
|
||||
buildPaths(const std::vector<DerivedPath> & paths, BuildMode buildMode, std::shared_ptr<Store> evalStore) override;
|
||||
|
|
@ -244,7 +244,7 @@ void RestrictedStore::registerDrvOutput(const Realisation & info)
|
|||
}
|
||||
|
||||
void RestrictedStore::queryRealisationUncached(
|
||||
const DrvOutput & id, Callback<std::shared_ptr<const Realisation>> callback) noexcept
|
||||
const DrvOutput & id, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept
|
||||
// XXX: This should probably be allowed if the realisation corresponds to
|
||||
// an allowed derivation
|
||||
{
|
||||
|
|
|
|||
|
|
@ -598,7 +598,8 @@ void Store::queryPathInfo(const StorePath & storePath, Callback<ref<const ValidP
|
|||
}});
|
||||
}
|
||||
|
||||
void Store::queryRealisation(const DrvOutput & id, Callback<std::shared_ptr<const Realisation>> callback) noexcept
|
||||
void Store::queryRealisation(
|
||||
const DrvOutput & id, Callback<std::shared_ptr<const UnkeyedRealisation>> callback) noexcept
|
||||
{
|
||||
|
||||
try {
|
||||
|
|
@ -624,20 +625,20 @@ void Store::queryRealisation(const DrvOutput & id, Callback<std::shared_ptr<cons
|
|||
|
||||
auto callbackPtr = std::make_shared<decltype(callback)>(std::move(callback));
|
||||
|
||||
queryRealisationUncached(id, {[this, id, callbackPtr](std::future<std::shared_ptr<const Realisation>> fut) {
|
||||
queryRealisationUncached(id, {[this, id, callbackPtr](std::future<std::shared_ptr<const UnkeyedRealisation>> fut) {
|
||||
try {
|
||||
auto info = fut.get();
|
||||
|
||||
if (diskCache) {
|
||||
if (info)
|
||||
diskCache->upsertRealisation(
|
||||
config.getReference().render(/*FIXME withParams=*/false), *info);
|
||||
config.getReference().render(/*FIXME withParams=*/false), {*info, id});
|
||||
else
|
||||
diskCache->upsertAbsentRealisation(
|
||||
config.getReference().render(/*FIXME withParams=*/false), id);
|
||||
}
|
||||
|
||||
(*callbackPtr)(std::shared_ptr<const Realisation>(info));
|
||||
(*callbackPtr)(std::shared_ptr<const UnkeyedRealisation>(info));
|
||||
|
||||
} catch (...) {
|
||||
callbackPtr->rethrow();
|
||||
|
|
@ -645,9 +646,9 @@ void Store::queryRealisation(const DrvOutput & id, Callback<std::shared_ptr<cons
|
|||
}});
|
||||
}
|
||||
|
||||
std::shared_ptr<const Realisation> Store::queryRealisation(const DrvOutput & id)
|
||||
std::shared_ptr<const UnkeyedRealisation> Store::queryRealisation(const DrvOutput & id)
|
||||
{
|
||||
using RealPtr = std::shared_ptr<const Realisation>;
|
||||
using RealPtr = std::shared_ptr<const UnkeyedRealisation>;
|
||||
std::promise<RealPtr> promise;
|
||||
|
||||
queryRealisation(id, {[&](std::future<RealPtr> result) {
|
||||
|
|
@ -910,11 +911,12 @@ std::map<StorePath, StorePath> copyPaths(
|
|||
std::set<Realisation> toplevelRealisations;
|
||||
for (auto & path : paths) {
|
||||
storePaths.insert(path.path());
|
||||
if (auto realisation = std::get_if<Realisation>(&path.raw)) {
|
||||
if (auto * realisation = std::get_if<Realisation>(&path.raw)) {
|
||||
experimentalFeatureSettings.require(Xp::CaDerivations);
|
||||
toplevelRealisations.insert(*realisation);
|
||||
}
|
||||
}
|
||||
|
||||
auto pathsMap = copyPaths(srcStore, dstStore, storePaths, repair, checkSigs, substitute);
|
||||
|
||||
try {
|
||||
|
|
@ -931,7 +933,7 @@ std::map<StorePath, StorePath> copyPaths(
|
|||
"dependency of '%s' but isn't registered",
|
||||
drvOutput.to_string(),
|
||||
current.id.to_string());
|
||||
children.insert(*currentChild);
|
||||
children.insert({*currentChild, drvOutput});
|
||||
}
|
||||
return children;
|
||||
},
|
||||
|
|
@ -1199,7 +1201,7 @@ void Store::signRealisation(Realisation & realisation)
|
|||
for (auto & secretKeyFile : secretKeyFiles.get()) {
|
||||
SecretKey secretKey(readFile(secretKeyFile));
|
||||
LocalSigner signer(std::move(secretKey));
|
||||
realisation.sign(signer);
|
||||
realisation.sign(realisation.id, signer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1830,7 +1830,12 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
|
|||
for (auto & [outputName, newInfo] : infos) {
|
||||
auto oldinfo = get(initialOutputs, outputName);
|
||||
assert(oldinfo);
|
||||
auto thisRealisation = Realisation{.id = DrvOutput{oldinfo->outputHash, outputName}, .outPath = newInfo.path};
|
||||
auto thisRealisation = Realisation{
|
||||
{
|
||||
.outPath = newInfo.path,
|
||||
},
|
||||
DrvOutput{oldinfo->outputHash, outputName},
|
||||
};
|
||||
if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations) && !drv.type().isImpure()) {
|
||||
store.signRealisation(thisRealisation);
|
||||
store.registerDrvOutput(thisRealisation);
|
||||
|
|
|
|||
|
|
@ -222,3 +222,22 @@ public:
|
|||
};
|
||||
|
||||
} // namespace nix
|
||||
|
||||
template<>
|
||||
struct std::hash<nix::Hash>
|
||||
{
|
||||
std::size_t operator()(const nix::Hash & hash) const noexcept
|
||||
{
|
||||
assert(hash.hashSize > sizeof(size_t));
|
||||
return *reinterpret_cast<const std::size_t *>(&hash.hash);
|
||||
}
|
||||
};
|
||||
|
||||
namespace nix {
|
||||
|
||||
inline std::size_t hash_value(const Hash & hash)
|
||||
{
|
||||
return std::hash<Hash>{}(hash);
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue