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:
parent
80da7a6375
commit
d0f5719c2a
|
@ -170,6 +170,9 @@ public:
|
|||
|
||||
ref<FSAccessor> getFSAccessor() override;
|
||||
|
||||
void addSignatures(const Path & storePath, const StringSet & sigs)
|
||||
{ notImpl(); }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -312,7 +312,7 @@ void LocalStore::openDB(bool create)
|
|||
stmtRegisterValidPath.create(db,
|
||||
"insert into ValidPaths (path, hash, registrationTime, deriver, narSize, ultimate) values (?, ?, ?, ?, ?, ?);");
|
||||
stmtUpdatePathInfo.create(db,
|
||||
"update ValidPaths set narSize = ?, hash = ?, ultimate = ? where path = ?;");
|
||||
"update ValidPaths set narSize = ?, hash = ?, ultimate = ?, sigs = ? where path = ?;");
|
||||
stmtAddReference.create(db,
|
||||
"insert or replace into Refs (referrer, reference) values (?, ?);");
|
||||
stmtQueryPathInfo.create(db,
|
||||
|
@ -683,14 +683,14 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path)
|
|||
}
|
||||
|
||||
|
||||
/* Update path info in the database. Currently only updates the
|
||||
narSize field. */
|
||||
/* Update path info in the database. */
|
||||
void LocalStore::updatePathInfo(const ValidPathInfo & info)
|
||||
{
|
||||
stmtUpdatePathInfo.use()
|
||||
(info.narSize, info.narSize != 0)
|
||||
("sha256:" + printHash(info.narHash))
|
||||
(info.ultimate ? 1 : 0, info.ultimate)
|
||||
(concatStringsSep(" ", info.sigs), !info.sigs.empty())
|
||||
(info.path)
|
||||
.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();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -182,6 +182,8 @@ public:
|
|||
|
||||
void setSubstituterEnv();
|
||||
|
||||
void addSignatures(const Path & storePath, const StringSet & sigs) override;
|
||||
|
||||
private:
|
||||
|
||||
Path schemaPath;
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
try {
|
||||
|
|
|
@ -93,6 +93,8 @@ public:
|
|||
|
||||
bool verifyStore(bool checkContents, bool repair) override;
|
||||
|
||||
void addSignatures(const Path & storePath, const StringSet & sigs) override;
|
||||
|
||||
private:
|
||||
|
||||
struct Connection
|
||||
|
|
|
@ -346,6 +346,10 @@ public:
|
|||
/* Return an object to access files in the Nix store. */
|
||||
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. */
|
||||
|
||||
/* Read a derivation, after ensuring its existence through
|
||||
|
|
|
@ -45,6 +45,7 @@ typedef enum {
|
|||
wopOptimiseStore = 34,
|
||||
wopVerifyStore = 35,
|
||||
wopBuildDerivation = 36,
|
||||
wopAddSignatures = 37,
|
||||
} WorkerOp;
|
||||
|
||||
|
||||
|
|
|
@ -543,6 +543,18 @@ static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVe
|
|||
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:
|
||||
throw Error(format("invalid operation %1%") % op);
|
||||
}
|
||||
|
|
133
src/nix/sigs.cc
Normal file
133
src/nix/sigs.cc
Normal 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>());
|
Loading…
Reference in a new issue