Factor out a LogStore interface

Continue progress on #5729.

Just as I hoped, this uncovered an issue: the daemon protocol is missing
a way to query build logs. This doesn't effect `unix://`, but does
effect `ssh://`. A FIXME is left for this, so we come back to it later.
This commit is contained in:
John Ericson 2022-03-08 18:20:39 +00:00
parent 89effe9d4a
commit 678d1c2aa0
13 changed files with 92 additions and 22 deletions

View file

@ -2,6 +2,7 @@
#include "crypto.hh"
#include "store-api.hh"
#include "log-store.hh"
#include "pool.hh"
@ -28,7 +29,9 @@ struct BinaryCacheStoreConfig : virtual StoreConfig
"other than -1 which we reserve to indicate Nix defaults should be used"};
};
class BinaryCacheStore : public virtual BinaryCacheStoreConfig, public virtual Store
class BinaryCacheStore : public virtual BinaryCacheStoreConfig,
public virtual Store,
public virtual LogStore
{
private:

View file

@ -1340,6 +1340,12 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
next->queryMissing(allowed, willBuild, willSubstitute,
unknown, downloadSize, narSize);
}
virtual std::optional<std::string> getBuildLog(const StorePath & path) override
{ return std::nullopt; }
virtual void addBuildLog(const StorePath & path, std::string_view log) override
{ unsupported("addBuildLog"); }
};

View file

@ -4,6 +4,7 @@
#include "build-result.hh"
#include "store-api.hh"
#include "gc-store.hh"
#include "log-store.hh"
#include "path-with-outputs.hh"
#include "finally.hh"
#include "archive.hh"
@ -953,11 +954,12 @@ static void performOp(TunnelLogger * logger, ref<Store> store,
logger->startWork();
if (!trusted)
throw Error("you are not privileged to add logs");
auto & logStore = LogStore::require(*store);
{
FramedSource source(from);
StringSink sink;
source.drainInto(sink);
store->addBuildLog(path, sink.s);
logStore.addBuildLog(path, sink.s);
}
logger->stopWork();
to << 1;

View file

@ -2,6 +2,7 @@
#include "store-api.hh"
#include "gc-store.hh"
#include "log-store.hh"
namespace nix {
@ -24,7 +25,10 @@ struct LocalFSStoreConfig : virtual StoreConfig
"physical path to the Nix store"};
};
class LocalFSStore : public virtual LocalFSStoreConfig, public virtual Store, virtual GcStore
class LocalFSStore : public virtual LocalFSStoreConfig,
public virtual Store,
public virtual GcStore,
public virtual LogStore
{
public:

13
src/libstore/log-store.cc Normal file
View file

@ -0,0 +1,13 @@
#include "log-store.hh"
namespace nix {
LogStore & LogStore::require(Store & store)
{
auto * gcStore = dynamic_cast<LogStore *>(&store);
if (!gcStore)
throw UsageError("Build log storage and retrieval not supported by store '%s'", store.getUri());
return *gcStore;
}
}

19
src/libstore/log-store.hh Normal file
View file

@ -0,0 +1,19 @@
#pragma once
#include "store-api.hh"
namespace nix {
struct LogStore : public virtual Store
{
/* Return the build log of the specified store path, if available,
or null otherwise. */
virtual std::optional<std::string> getBuildLog(const StorePath & path) = 0;
virtual void addBuildLog(const StorePath & path, std::string_view log) = 0;
static LogStore & require(Store & store);
};
}

View file

@ -5,6 +5,7 @@
#include "store-api.hh"
#include "gc-store.hh"
#include "log-store.hh"
namespace nix {
@ -30,7 +31,10 @@ struct RemoteStoreConfig : virtual StoreConfig
/* FIXME: RemoteStore is a misnomer - should be something like
DaemonStore. */
class RemoteStore : public virtual RemoteStoreConfig, public virtual Store, public virtual GcStore
class RemoteStore : public virtual RemoteStoreConfig,
public virtual Store,
public virtual GcStore,
public virtual LogStore
{
public:

View file

@ -52,6 +52,10 @@ public:
bool sameMachine() override
{ return false; }
// FIXME extend daemon protocol, move implementation to RemoteStore
std::optional<std::string> getBuildLog(const StorePath & path) override
{ unsupported("getBuildLog"); }
private:
struct Connection : RemoteStore::Connection

View file

@ -605,14 +605,6 @@ public:
*/
StorePathSet exportReferences(const StorePathSet & storePaths, const StorePathSet & inputPaths);
/* Return the build log of the specified store path, if available,
or null otherwise. */
virtual std::optional<std::string> getBuildLog(const StorePath & path)
{ return std::nullopt; }
virtual void addBuildLog(const StorePath & path, std::string_view log)
{ unsupported("addBuildLog"); }
/* Hack to allow long-running processes like hydra-queue-runner to
occasionally flush their path info cache. */
void clearPathInfoCache()

View file

@ -4,6 +4,7 @@
#include "globals.hh"
#include "build-result.hh"
#include "gc-store.hh"
#include "log-store.hh"
#include "local-store.hh"
#include "monitor-fd.hh"
#include "serve-protocol.hh"
@ -474,13 +475,15 @@ static void opReadLog(Strings opFlags, Strings opArgs)
{
if (!opFlags.empty()) throw UsageError("unknown flag");
auto & logStore = LogStore::require(*store);
RunPager pager;
for (auto & i : opArgs) {
auto path = store->followLinksToStorePath(i);
auto log = store->getBuildLog(path);
auto path = logStore.followLinksToStorePath(i);
auto log = logStore.getBuildLog(path);
if (!log)
throw Error("build log of derivation '%s' is not available", store->printStorePath(path));
throw Error("build log of derivation '%s' is not available", logStore.printStorePath(path));
std::cout << *log;
}
}

View file

@ -2,6 +2,7 @@
#include "common-args.hh"
#include "shared.hh"
#include "store-api.hh"
#include "log-store.hh"
#include "progress-bar.hh"
using namespace nix;
@ -34,17 +35,24 @@ struct CmdLog : InstallableCommand
RunPager pager;
for (auto & sub : subs) {
auto * logSubP = dynamic_cast<LogStore *>(&*sub);
if (!logSubP) {
printInfo("Skipped '%s' which does not support retrieving build logs", sub->getUri());
continue;
}
auto & logSub = *logSubP;
auto log = std::visit(overloaded {
[&](const DerivedPath::Opaque & bo) {
return sub->getBuildLog(bo.path);
return logSub.getBuildLog(bo.path);
},
[&](const DerivedPath::Built & bfd) {
return sub->getBuildLog(bfd.drvPath);
return logSub.getBuildLog(bfd.drvPath);
},
}, b.raw());
if (!log) continue;
stopProgressBar();
printInfo("got build log for '%s' from '%s'", installable->what(), sub->getUri());
printInfo("got build log for '%s' from '%s'", installable->what(), logSub.getUri());
std::cout << *log;
return;
}

View file

@ -25,6 +25,7 @@ extern "C" {
#include "eval-inline.hh"
#include "attr-path.hh"
#include "store-api.hh"
#include "log-store.hh"
#include "common-eval-args.hh"
#include "get-drvs.hh"
#include "derivations.hh"
@ -526,9 +527,16 @@ bool NixRepl::processLine(std::string line)
bool foundLog = false;
RunPager pager;
for (auto & sub : subs) {
auto log = sub->getBuildLog(drvPath);
auto * logSubP = dynamic_cast<LogStore *>(&*sub);
if (!logSubP) {
printInfo("Skipped '%s' which does not support retrieving build logs", sub->getUri());
continue;
}
auto & logSub = *logSubP;
auto log = logSub.getBuildLog(drvPath);
if (log) {
printInfo("got build log for '%s' from '%s'", drvPathRaw, sub->getUri());
printInfo("got build log for '%s' from '%s'", drvPathRaw, logSub.getUri());
logger->writeToStdout(*log);
foundLog = true;
break;

View file

@ -1,6 +1,7 @@
#include "command.hh"
#include "shared.hh"
#include "store-api.hh"
#include "log-store.hh"
#include "sync.hh"
#include "thread-pool.hh"
@ -26,7 +27,10 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand
void run(ref<Store> srcStore) override
{
auto & srcLogStore = LogStore::require(*srcStore);
auto dstStore = getDstStore();
auto & dstLogStore = LogStore::require(*dstStore);
StorePathSet drvPaths;
@ -35,8 +39,8 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand
drvPaths.insert(drvPath);
for (auto & drvPath : drvPaths) {
if (auto log = srcStore->getBuildLog(drvPath))
dstStore->addBuildLog(drvPath, *log);
if (auto log = srcLogStore.getBuildLog(drvPath))
dstLogStore.addBuildLog(drvPath, *log);
else
throw Error("build log for '%s' is not available", srcStore->printStorePath(drvPath));
}