nix-gh/src/nix/sigs.cc
Eelco Dolstra e0204f8d46 Move path info caching from BinaryCacheStore to Store
Caching path info is generally useful. For instance, it speeds up "nix
path-info -rS /run/current-system" (i.e. showing the closure sizes of
all paths in the closure of the current system) from 5.6s to 0.15s.

This also eliminates some APIs like Store::queryDeriver() and
Store::queryReferences().
2016-04-19 18:52:53 +02:00

184 lines
4.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "affinity.hh" // FIXME
#include "command.hh"
#include "progress-bar.hh"
#include "shared.hh"
#include "store-api.hh"
#include "thread-pool.hh"
#include <atomic>
using namespace nix;
struct CmdCopySigs : StorePathsCommand
{
Strings substituterUris;
CmdCopySigs()
{
mkFlag('s', "substituter", {"store-uri"}, "use signatures from specified store", 1,
[&](Strings ss) { substituterUris.push_back(ss.front()); });
}
std::string name() override
{
return "copy-sigs";
}
std::string description() override
{
return "copy path signatures from substituters (like binary caches)";
}
void run(ref<Store> store, Paths storePaths) override
{
restoreAffinity(); // FIXME
if (substituterUris.empty())
throw UsageError("you must specify at least one substituter using -s");
// FIXME: factor out commonality with MixVerify.
std::vector<ref<Store>> substituters;
for (auto & s : substituterUris)
substituters.push_back(openStoreAt(s));
ProgressBar progressBar;
ThreadPool pool;
std::atomic<size_t> done{0};
std::atomic<size_t> added{0};
auto showProgress = [&]() {
return (format("[%d/%d done]") % done % storePaths.size()).str();
};
progressBar.updateStatus(showProgress());
auto doPath = [&](const Path & storePath) {
auto activity(progressBar.startActivity(format("getting signatures for %s") % storePath));
checkInterrupt();
auto info = store->queryPathInfo(storePath);
StringSet newSigs;
for (auto & store2 : substituters) {
try {
auto info2 = store2->queryPathInfo(storePath);
/* Don't import signatures that don't match this
binary. */
if (info->narHash != info2->narHash ||
info->narSize != info2->narSize ||
info->references != info2->references)
continue;
for (auto & sig : info2->sigs)
if (!info->sigs.count(sig))
newSigs.insert(sig);
} catch (InvalidPath &) {
}
}
if (!newSigs.empty()) {
store->addSignatures(storePath, newSigs);
added += newSigs.size();
}
done++;
progressBar.updateStatus(showProgress());
};
for (auto & storePath : storePaths)
pool.enqueue(std::bind(doPath, storePath));
pool.process();
progressBar.done();
printMsg(lvlInfo, format("imported %d signatures") % added);
}
};
static RegisterCommand r1(make_ref<CmdCopySigs>());
struct CmdQueryPathSigs : StorePathsCommand
{
CmdQueryPathSigs()
{
}
std::string name() override
{
return "query-path-sigs";
}
std::string description() override
{
return "print store path signatures";
}
void run(ref<Store> store, Paths storePaths) override
{
for (auto & storePath : storePaths) {
auto info = store->queryPathInfo(storePath);
std::cout << storePath << " ";
if (info->ultimate) std::cout << "ultimate ";
for (auto & sig : info->sigs)
std::cout << sig << " ";
std::cout << "\n";
}
}
};
static RegisterCommand r2(make_ref<CmdQueryPathSigs>());
struct CmdSignPaths : StorePathsCommand
{
Path secretKeyFile;
CmdSignPaths()
{
mkFlag('k', "key-file", {"file"}, "file containing the secret signing key", &secretKeyFile);
}
std::string name() override
{
return "sign-paths";
}
std::string description() override
{
return "sign the specified paths";
}
void run(ref<Store> store, Paths storePaths) override
{
if (secretKeyFile.empty())
throw UsageError("you must specify a secret key file using -k");
SecretKey secretKey(readFile(secretKeyFile));
size_t added{0};
for (auto & storePath : storePaths) {
auto info = store->queryPathInfo(storePath);
auto info2(*info);
info2.sigs.clear();
info2.sign(secretKey);
assert(!info2.sigs.empty());
if (!info->sigs.count(*info2.sigs.begin())) {
store->addSignatures(storePath, info2.sigs);
added++;
}
}
printMsg(lvlInfo, format("added %d signatures") % added);
}
};
static RegisterCommand r3(make_ref<CmdSignPaths>());