Skip to content

Commit fdbf219

Browse files
Ericson2314amaanq
andcommitted
Make DerivationBuilder not require a Store
The hope is to make `DerivationBuilder` easier to use with much less of libnixstore. Co-authored-by: Amaan Qureshi <git@amaanq.com>
1 parent f1973b6 commit fdbf219

17 files changed

Lines changed: 212 additions & 113 deletions

src/libstore/build/derivation-builder-impl.cc

Lines changed: 87 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "build/derivation-check.hh"
33
#include "nix/store/globals.hh"
44
#include "nix/store/local-store.hh"
5+
#include "nix/store/restricted-store.hh"
56
#include "nix/store/path-references.hh"
67
#include "nix/store/posix-fs-canonicalise.hh"
78
#include "nix/util/archive.hh"
@@ -100,7 +101,7 @@ static void replaceValidPath(const std::filesystem::path & storePath, const std:
100101
deletePath(oldPath);
101102
}
102103

103-
SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
104+
SingleDrvOutputs DerivationBuilderImpl::registerOutputs(LocalStore & localStore)
104105
{
105106
std::map<std::string, ValidPathInfo> infos;
106107

@@ -326,7 +327,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
326327
/* Put the temporary copy in a directory inaccessible to the builder.
327328
actualPath might point inside the build chroot, which is controlled
328329
by the derivation builder. */
329-
auto [rewriteTempDir, rewriteTempDirFd] = store.createTempDirInStore();
330+
auto [rewriteTempDir, rewriteTempDirFd] = localStore.createTempDirInStore();
330331
AutoDelete delRewriteTempDir(rewriteTempDir);
331332
std::filesystem::path tmpPath = rewriteTempDir / "x";
332333
restorePath(tmpPath, *source);
@@ -410,7 +411,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
410411
}();
411412

412413
auto newInfo0 = ValidPathInfo::makeFromCA(
413-
store,
414+
storeDirConfig,
414415
outputPathName(drv.name, outputName),
415416
ContentAddressWithReferences::fromParts(outputHash.method, std::move(got), rewriteRefs()),
416417
Hash::dummy);
@@ -438,15 +439,15 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
438439

439440
auto moveOutputToTempDir = [&]() -> void {
440441
std::filesystem::path tempDir;
441-
std::tie(tempDir, tempDirFd) = store.createTempDirInStore();
442+
std::tie(tempDir, tempDirFd) = localStore.createTempDirInStore();
442443
delTempDir = AutoDelete(tempDir);
443444

444445
auto tmpOutput = tempDir / "x";
445446

446447
/* Copy files to break stale file descriptors. copyRecursive below will use
447448
reflinking to optimise the copying overhead. */
448449
auto pathAccessor = makeFSSourceAccessor(actualPath);
449-
RestoreSink restoreSink{store.config->getLocalSettings().fsyncStorePaths};
450+
RestoreSink restoreSink{store->getLocalSettings().fsyncStorePaths};
450451
restoreSink.dstPath = tmpOutput;
451452
copyRecursive(*pathAccessor, CanonPath::root, restoreSink, CanonPath::root);
452453
/* This makes it slightly harder to make sense of the control flow. The rule
@@ -471,7 +472,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
471472
{makeFSSourceAccessor(actualPath), CanonPath::root},
472473
FileSerialisationMethod::NixArchive,
473474
HashAlgorithm::SHA256);
474-
ValidPathInfo newInfo0{requiredFinalPath, {store, narHashAndSize.hash}};
475+
ValidPathInfo newInfo0{requiredFinalPath, {storeDirConfig, narHashAndSize.hash}};
475476
newInfo0.narSize = narHashAndSize.numBytesDigested;
476477
auto refs = rewriteRefs();
477478
newInfo0.references = std::move(refs.others);
@@ -532,44 +533,44 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
532533
derivations. */
533534
PathLocks dynamicOutputLock;
534535
dynamicOutputLock.setDeletion(true);
535-
auto optFixedPath = output->path(store, drv.name, outputName);
536+
auto optFixedPath = output->path(storeDirConfig, drv.name, outputName);
536537
if (!optFixedPath || storeDirConfig.printStorePath(*optFixedPath) != finalDestPath) {
537538
assert(newInfo.ca);
538539

539540
/* Don't wait on lock for the hash-mismatching fixed-output
540541
derivation case, to avoid a deadlock in the case where a build
541542
with the correct hash is in progress. */
542-
bool locked = dynamicOutputLock.lockPaths({store.toRealPath(newInfo.path)}, "", !optFixedPath);
543+
bool locked = dynamicOutputLock.lockPaths({store->toRealPath(newInfo.path)}, "", !optFixedPath);
543544

544545
/* If we can't lock the correct path, clean up and bail now. */
545546
if (!locked) {
546547
debug(
547548
"failed to lock correct output path of %s, namely %s, not moving output",
548549
storeDirConfig.printStorePath(drvPath),
549-
PathFmt(store.toRealPath(newInfo.path)));
550+
PathFmt(store->toRealPath(newInfo.path)));
550551
deletePath(actualPath);
551552
/* Trigger the hash-mismatch error. */
552-
checkCAOutput(store, drvPath, *output, newInfo, outputName);
553+
checkCAOutput(storeDirConfig, drvPath, *output, newInfo, outputName);
553554
unreachable();
554555
}
555556
}
556557

557558
/* Move files, if needed */
558-
if (store.toRealPath(newInfo.path) != actualPath) {
559+
if (store->toRealPath(newInfo.path) != actualPath) {
559560
if (buildMode == bmRepair) {
560561
/* Path already exists, need to replace it */
561-
replaceValidPath(store.toRealPath(newInfo.path), actualPath);
562+
replaceValidPath(store->toRealPath(newInfo.path), actualPath);
562563
} else if (buildMode == bmCheck) {
563564
/* Path already exists, and we want to compare, so we leave out
564565
new path in place. */
565-
} else if (store.isValidPath(newInfo.path)) {
566+
} else if (localStore.isValidPath(newInfo.path)) {
566567
/* Path already exists because CA path produced by something
567568
else. No moving needed. */
568569
assert(newInfo.ca);
569570
/* Can delete our scratch copy now. */
570571
deletePath(actualPath);
571572
} else {
572-
auto destPath = store.toRealPath(newInfo.path);
573+
auto destPath = store->toRealPath(newInfo.path);
573574
deletePath(destPath);
574575
movePath(actualPath, destPath);
575576
}
@@ -578,12 +579,12 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
578579
if (buildMode == bmCheck) {
579580
/* Check against already registered outputs */
580581

581-
if (store.isValidPath(newInfo.path)) {
582-
ValidPathInfo oldInfo(*store.queryPathInfo(newInfo.path));
582+
if (localStore.isValidPath(newInfo.path)) {
583+
ValidPathInfo oldInfo(*localStore.queryPathInfo(newInfo.path));
583584
if (newInfo.narHash != oldInfo.narHash) {
584585
auto * diffHook = localSettings.getDiffHook();
585586
if (diffHook || settings.keepFailed) {
586-
auto dst = store.toRealPath(newInfo.path);
587+
auto dst = store->toRealPath(newInfo.path);
587588
dst += ".check";
588589
deletePath(dst);
589590
movePath(actualPath, dst);
@@ -604,20 +605,20 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
604605
throw NotDeterministic(
605606
"derivation '%s' may not be deterministic: output %s differs from %s",
606607
storeDirConfig.printStorePath(drvPath),
607-
PathFmt(store.toRealPath(newInfo.path)),
608+
PathFmt(store->toRealPath(newInfo.path)),
608609
PathFmt(dst));
609610
} else
610611
throw NotDeterministic(
611612
"derivation '%s' may not be deterministic: output %s differs",
612613
storeDirConfig.printStorePath(drvPath),
613-
PathFmt(store.toRealPath(newInfo.path)));
614+
PathFmt(store->toRealPath(newInfo.path)));
614615
}
615616

616617
/* Since we verified the build, it's now ultimately trusted. */
617618
if (!oldInfo.ultimate) {
618619
oldInfo.ultimate = true;
619-
store.signPathInfo(oldInfo);
620-
store.registerValidPaths({{oldInfo.path, oldInfo}});
620+
localStore.signPathInfo(oldInfo);
621+
localStore.registerValidPaths({{oldInfo.path, oldInfo}});
621622
}
622623
}
623624
} else {
@@ -631,12 +632,13 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
631632
debug("unreferenced input: '%1%'", storeDirConfig.printStorePath(i));
632633
}
633634

634-
if (!store.isValidPath(newInfo.path))
635-
store.optimisePath(store.toRealPath(newInfo.path), NoRepair); // FIXME: combine with scanForReferences()
635+
if (!localStore.isValidPath(newInfo.path))
636+
localStore.optimisePath(
637+
store->toRealPath(newInfo.path), NoRepair); // FIXME: combine with scanForReferences()
636638

637639
newInfo.deriver = drvPath;
638640
newInfo.ultimate = true;
639-
store.signPathInfo(newInfo);
641+
localStore.signPathInfo(newInfo);
640642

641643
finish(newInfo.path);
642644

@@ -651,7 +653,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
651653
possibly quite slow thing it was) doesn't have to be done
652654
again. */
653655
if (newInfo.ca)
654-
store.registerValidPaths({{newInfo.path, newInfo}});
656+
localStore.registerValidPaths({{newInfo.path, newInfo}});
655657
}
656658

657659
/* Do this in both the check and non-check cases, because we
@@ -662,7 +664,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
662664

663665
/* Apply output checks. This includes checking of the wanted vs got
664666
hash of fixed-outputs. */
665-
checkOutputs(store, drvPath, drv, drvOptions.outputChecks, infos);
667+
checkOutputs(localStore, drvPath, drv, drvOptions.outputChecks, infos);
666668

667669
if (buildMode == bmCheck) {
668670
return {};
@@ -676,7 +678,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
676678
for (auto & [outputName, newInfo] : infos) {
677679
infos2.insert_or_assign(newInfo.path, newInfo);
678680
}
679-
store.registerValidPaths(infos2);
681+
localStore.registerValidPaths(infos2);
680682
}
681683

682684
/* If we made it this far, we are sure the output matches the
@@ -699,16 +701,16 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
699701
},
700702
};
701703
if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations) && !type(drv).isImpure()) {
702-
store.signRealisation(thisRealisation);
703-
store.registerDrvOutput(thisRealisation, NoCheckSigs);
704+
localStore.signRealisation(thisRealisation);
705+
localStore.registerDrvOutput(thisRealisation, NoCheckSigs);
704706
}
705707
builtOutputs.emplace(outputName, thisRealisation);
706708
}
707709

708710
return builtOutputs;
709711
}
710712

711-
SingleDrvOutputs DerivationBuilderImpl::checkSubmittedOutputs()
713+
SingleDrvOutputs DerivationBuilderImpl::checkSubmittedOutputs(LocalStore & localStore)
712714
{
713715
// Submitted outputs from the recursive nix daemon
714716
// It's fine to lock here since all other threads with the reference have been shut down.
@@ -719,12 +721,12 @@ SingleDrvOutputs DerivationBuilderImpl::checkSubmittedOutputs()
719721
std::map<std::string, ValidPathInfo> infos;
720722

721723
for (auto & [outputName, outputPath] : *submittedOutputs) {
722-
infos.emplace(outputName, *store.queryPathInfo(outputPath));
724+
infos.emplace(outputName, *localStore.queryPathInfo(outputPath));
723725
}
724726

725727
// checkOutputs only performs checks that make sense for both submitting and non-submitting derivations,
726728
// more verification steps needed afterward
727-
checkOutputs(store, drvPath, drv, drvOptions.outputChecks, infos);
729+
checkOutputs(localStore, drvPath, drv, drvOptions.outputChecks, infos);
728730

729731
for (auto & [outputName, output] : drv.outputs) {
730732
// For some reason cannot be moved to checkOutputs, needs debugging
@@ -754,8 +756,8 @@ SingleDrvOutputs DerivationBuilderImpl::checkSubmittedOutputs()
754756
},
755757
};
756758

757-
store.signRealisation(realisation);
758-
store.registerDrvOutput(realisation, NoCheckSigs);
759+
localStore.signRealisation(realisation);
760+
localStore.registerDrvOutput(realisation, NoCheckSigs);
759761
builtOutputs.emplace(outputName, realisation);
760762

761763
// TODO: handle --check
@@ -764,4 +766,55 @@ SingleDrvOutputs DerivationBuilderImpl::checkSubmittedOutputs()
764766
return builtOutputs;
765767
}
766768

769+
BuildingStore::~BuildingStore() = default;
770+
771+
namespace {
772+
773+
struct LocalBuildingStore : BuildingStore
774+
{
775+
LocalStore & localStore;
776+
777+
LocalBuildingStore(LocalStore & localStore)
778+
: BuildingStore{localStore.storeDir}
779+
, localStore{localStore}
780+
{
781+
}
782+
783+
std::filesystem::path getRealStoreDir() const override
784+
{
785+
return localStore.config->realStoreDir.get();
786+
}
787+
788+
std::filesystem::path getBuildDir() const override
789+
{
790+
return localStore.config->getBuildDir();
791+
}
792+
793+
const LocalSettings & getLocalSettings() const override
794+
{
795+
return localStore.config->getLocalSettings();
796+
}
797+
798+
ref<Store> makeRecursiveNixStore(RestrictionContext & ctx) override
799+
{
800+
return makeRestrictedStore(
801+
[&] {
802+
auto config = make_ref<LocalStore::Config>(*localStore.config);
803+
config->pathInfoCacheSize = 0;
804+
config->stateDir = "/no-such-path";
805+
config->logDir = "/no-such-path";
806+
return config;
807+
}(),
808+
ref<LocalStore>(std::dynamic_pointer_cast<LocalStore>(localStore.shared_from_this())),
809+
ctx);
810+
}
811+
};
812+
813+
} // namespace
814+
815+
std::unique_ptr<BuildingStore> makeBuildingStoreFromLocalStore(LocalStore & localStore)
816+
{
817+
return std::make_unique<LocalBuildingStore>(localStore);
818+
}
819+
767820
} // namespace nix

src/libstore/build/derivation-builder-impl.hh

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ protected:
3636
*/
3737
Pid pid;
3838

39-
LocalStore & store;
39+
std::shared_ptr<BuildingStore> store;
4040

4141
/**
4242
* Just the store layout, for FFI: a `StoreDirConfig` can be made
@@ -58,7 +58,7 @@ protected:
5858
*/
5959
const derivation::Type derivationType;
6060

61-
const LocalSettings & localSettings = store.config->getLocalSettings();
61+
const LocalSettings & localSettings = store->getLocalSettings();
6262

6363
#ifndef _WIN32
6464
/**
@@ -98,32 +98,34 @@ protected:
9898
*/
9999
virtual std::filesystem::path realPathInHost(const std::filesystem::path & p)
100100
{
101-
return store.toRealPath(storeDirConfig.parseStorePath(p.string()));
101+
return store->toRealPath(storeDirConfig.parseStorePath(p.string()));
102102
}
103103

104104

105105
public:
106106

107107
DerivationBuilderImpl(
108-
LocalStore & store, std::shared_ptr<DerivationBuilderCallbacks> miscMethods, DerivationBuilderParams params)
108+
std::shared_ptr<BuildingStore> store,
109+
std::shared_ptr<DerivationBuilderCallbacks> miscMethods,
110+
DerivationBuilderParams params)
109111
: DerivationBuilderParams{std::move(params)}
110-
, store{store}
111-
, storeDirConfig{*store.config}
112+
, store{std::move(store)}
113+
, storeDirConfig{*this->store}
112114
, miscMethods{std::move(miscMethods)}
113115
, derivationType{derivation::type(drv)}
114116
{
115117
}
116118

117119
public:
118120

119-
SingleDrvOutputs registerOutputs() override;
121+
SingleDrvOutputs registerOutputs(LocalStore & localStore) override;
120122

121123
/**
122124
* Output paths from the `SubmitOutput` store command
123125
*/
124126
Sync<OutputPathMap> submittedOutputs;
125127

126-
SingleDrvOutputs checkSubmittedOutputs() override;
128+
SingleDrvOutputs checkSubmittedOutputs(LocalStore & localStore) override;
127129
};
128130

129131
} // namespace nix

src/libstore/build/derivation-building-goal.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -967,13 +967,13 @@ Goal::Co DerivationBuildingGoal::buildLocally(
967967
throw UnimplementedError("external builders are not yet supported on Windows")
968968
#else
969969
makeExternalDerivationBuilder(
970-
localBuildCap.localStore,
970+
makeBuildingStoreFromLocalStore(localBuildCap.localStore),
971971
std::make_shared<DerivationBuildingGoalCallbacks>(*this, openLogFile, closeLogFile),
972972
std::move(params),
973973
*localBuildCap.externalBuilder)
974974
#endif
975975
: makeDerivationBuilder(
976-
localBuildCap.localStore,
976+
makeBuildingStoreFromLocalStore(localBuildCap.localStore),
977977
std::make_shared<DerivationBuildingGoalCallbacks>(*this, openLogFile, closeLogFile),
978978
std::move(params)
979979
#ifdef _WIN32
@@ -1052,9 +1052,11 @@ Goal::Co DerivationBuildingGoal::buildLocally(
10521052
/* Compute the FS closure of the outputs and register them as
10531053
being valid. With builder-rpc-v0 the builder already submitted
10541054
the outputs, so check those instead. */
1055+
auto * localStoreP = dynamic_cast<LocalStore *>(&worker.store);
1056+
assert(localStoreP);
10551057
builtOutputs = drvOptions.getRequiredSystemFeatures(*drv).count(std::string{drvFeatureBuilderRpcV0})
1056-
? builder->checkSubmittedOutputs()
1057-
: builder->registerOutputs();
1058+
? builder->checkSubmittedOutputs(*localStoreP)
1059+
: builder->registerOutputs(*localStoreP);
10581060
builder->cleanupBuild(true);
10591061
} catch (BuilderFailureError & e) {
10601062
builder.reset();

src/libstore/build/derivation-check.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
namespace nix {
1111

1212
void checkCAOutput(
13-
StoreDirConfig & store,
13+
const StoreDirConfig & store,
1414
const StorePath & drvPath,
1515
const DerivationOutput & outputSpec,
1616
const ValidPathInfo & info,

0 commit comments

Comments
 (0)