Add "nix copy-sigs" command

This imports signatures from one store into another. E.g.

  $ nix copy-sigs -r /run/current-system -s https://cache.nixos.org/
  imported 595 signatures
This commit is contained in:
Eelco Dolstra 2016-04-05 15:30:22 +02:00
parent 80da7a6375
commit d0f5719c2a
9 changed files with 185 additions and 3 deletions

View file

@ -170,6 +170,9 @@ public:
ref<FSAccessor> getFSAccessor() override; ref<FSAccessor> getFSAccessor() override;
void addSignatures(const Path & storePath, const StringSet & sigs)
{ notImpl(); }
}; };
} }

View file

@ -312,7 +312,7 @@ void LocalStore::openDB(bool create)
stmtRegisterValidPath.create(db, stmtRegisterValidPath.create(db,
"insert into ValidPaths (path, hash, registrationTime, deriver, narSize, ultimate) values (?, ?, ?, ?, ?, ?);"); "insert into ValidPaths (path, hash, registrationTime, deriver, narSize, ultimate) values (?, ?, ?, ?, ?, ?);");
stmtUpdatePathInfo.create(db, stmtUpdatePathInfo.create(db,
"update ValidPaths set narSize = ?, hash = ?, ultimate = ? where path = ?;"); "update ValidPaths set narSize = ?, hash = ?, ultimate = ?, sigs = ? where path = ?;");
stmtAddReference.create(db, stmtAddReference.create(db,
"insert or replace into Refs (referrer, reference) values (?, ?);"); "insert or replace into Refs (referrer, reference) values (?, ?);");
stmtQueryPathInfo.create(db, stmtQueryPathInfo.create(db,
@ -683,14 +683,14 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path)
} }
/* Update path info in the database. Currently only updates the /* Update path info in the database. */
narSize field. */
void LocalStore::updatePathInfo(const ValidPathInfo & info) void LocalStore::updatePathInfo(const ValidPathInfo & info)
{ {
stmtUpdatePathInfo.use() stmtUpdatePathInfo.use()
(info.narSize, info.narSize != 0) (info.narSize, info.narSize != 0)
("sha256:" + printHash(info.narHash)) ("sha256:" + printHash(info.narHash))
(info.ultimate ? 1 : 0, info.ultimate) (info.ultimate ? 1 : 0, info.ultimate)
(concatStringsSep(" ", info.sigs), !info.sigs.empty())
(info.path) (info.path)
.exec(); .exec();
} }
@ -1694,4 +1694,20 @@ void LocalStore::vacuumDB()
} }
void LocalStore::addSignatures(const Path & storePath, const StringSet & sigs)
{
retrySQLite<void>([&]() {
SQLiteTxn txn(db);
auto info = queryPathInfo(storePath);
info.sigs.insert(sigs.begin(), sigs.end());
updatePathInfo(info);
txn.commit();
});
}
} }

View file

@ -182,6 +182,8 @@ public:
void setSubstituterEnv(); void setSubstituterEnv();
void addSignatures(const Path & storePath, const StringSet & sigs) override;
private: private:
Path schemaPath; Path schemaPath;

View file

@ -554,6 +554,15 @@ bool RemoteStore::verifyStore(bool checkContents, bool repair)
} }
void RemoteStore::addSignatures(const Path & storePath, const StringSet & sigs)
{
auto conn(connections->get());
conn->to << wopAddSignatures << storePath << sigs;
conn->processStderr();
readInt(conn->from);
}
RemoteStore::Connection::~Connection() RemoteStore::Connection::~Connection()
{ {
try { try {

View file

@ -93,6 +93,8 @@ public:
bool verifyStore(bool checkContents, bool repair) override; bool verifyStore(bool checkContents, bool repair) override;
void addSignatures(const Path & storePath, const StringSet & sigs) override;
private: private:
struct Connection struct Connection

View file

@ -346,6 +346,10 @@ public:
/* Return an object to access files in the Nix store. */ /* Return an object to access files in the Nix store. */
virtual ref<FSAccessor> getFSAccessor() = 0; virtual ref<FSAccessor> getFSAccessor() = 0;
/* Add signatures to the specified store path. The signatures are
not verified. */
virtual void addSignatures(const Path & storePath, const StringSet & sigs) = 0;
/* Utility functions. */ /* Utility functions. */
/* Read a derivation, after ensuring its existence through /* Read a derivation, after ensuring its existence through

View file

@ -45,6 +45,7 @@ typedef enum {
wopOptimiseStore = 34, wopOptimiseStore = 34,
wopVerifyStore = 35, wopVerifyStore = 35,
wopBuildDerivation = 36, wopBuildDerivation = 36,
wopAddSignatures = 37,
} WorkerOp; } WorkerOp;

View file

@ -543,6 +543,18 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
break; break;
} }
case wopAddSignatures: {
Path path = readStorePath(from);
StringSet sigs = readStrings<StringSet>(from);
startWork();
if (!trusted)
throw Error("you are not privileged to add signatures");
store->addSignatures(path, sigs);
stopWork();
to << 1;
break;
}
default: default:
throw Error(format("invalid operation %1%") % op); throw Error(format("invalid operation %1%") % op);
} }

133
src/nix/sigs.cc Normal file
View file

@ -0,0 +1,133 @@
#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 subtituter 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) {
if (!store2->isValidPath(storePath)) continue;
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);
}
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>());