forked from lix-project/lix
* nix-store --dump-db / --load-db to dump/load the Nix DB.
* nix-store --register-validity: option to supply the content hash of each path. * Removed compatibility with Nix <= 0.7 stores.
This commit is contained in:
parent
5b5a3af983
commit
66c51dc215
|
@ -6,6 +6,19 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--==================================================================-->
|
||||||
|
|
||||||
|
<section xml:id="ssec-relnotes-0.12"><title>Release 0.12 (TBA)</title>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
|
||||||
|
<listitem><para><command>nix-store --dump-db / --load-db</command>.</para></listitem>
|
||||||
|
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<!--==================================================================-->
|
<!--==================================================================-->
|
||||||
|
|
||||||
<section xml:id="ssec-relnotes-0.11"><title>Release 0.11 (December 31,
|
<section xml:id="ssec-relnotes-0.11"><title>Release 0.11 (December 31,
|
||||||
|
|
|
@ -1263,34 +1263,6 @@ string showPaths(const PathSet & paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return a string accepted by `nix-store --register-validity' that
|
|
||||||
registers the specified paths as valid. Note: it's the
|
|
||||||
responsibility of the caller to provide a closure. */
|
|
||||||
static string makeValidityRegistration(const PathSet & paths,
|
|
||||||
bool showDerivers)
|
|
||||||
{
|
|
||||||
string s = "";
|
|
||||||
|
|
||||||
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
|
|
||||||
s += *i + "\n";
|
|
||||||
|
|
||||||
Path deriver = showDerivers ? store->queryDeriver(*i) : "";
|
|
||||||
s += deriver + "\n";
|
|
||||||
|
|
||||||
PathSet references;
|
|
||||||
store->queryReferences(*i, references);
|
|
||||||
|
|
||||||
s += (format("%1%\n") % references.size()).str();
|
|
||||||
|
|
||||||
for (PathSet::iterator j = references.begin();
|
|
||||||
j != references.end(); ++j)
|
|
||||||
s += *j + "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DerivationGoal::HookReply DerivationGoal::tryBuildHook()
|
DerivationGoal::HookReply DerivationGoal::tryBuildHook()
|
||||||
{
|
{
|
||||||
if (!useBuildHook) return rpDecline;
|
if (!useBuildHook) return rpDecline;
|
||||||
|
@ -1417,7 +1389,7 @@ DerivationGoal::HookReply DerivationGoal::tryBuildHook()
|
||||||
/* The `references' file has exactly the format accepted by
|
/* The `references' file has exactly the format accepted by
|
||||||
`nix-store --register-validity'. */
|
`nix-store --register-validity'. */
|
||||||
writeStringToFile(referencesFN,
|
writeStringToFile(referencesFN,
|
||||||
makeValidityRegistration(allInputs, true));
|
makeValidityRegistration(allInputs, true, false));
|
||||||
|
|
||||||
/* Tell the hook to proceed. */
|
/* Tell the hook to proceed. */
|
||||||
writeLine(toHook.writeSide, "okay");
|
writeLine(toHook.writeSide, "okay");
|
||||||
|
@ -1662,7 +1634,7 @@ void DerivationGoal::startBuilder()
|
||||||
/* !!! in secure Nix, the writing should be done on the
|
/* !!! in secure Nix, the writing should be done on the
|
||||||
build uid for security (maybe). */
|
build uid for security (maybe). */
|
||||||
writeStringToFile(tmpDir + "/" + fileName,
|
writeStringToFile(tmpDir + "/" + fileName,
|
||||||
makeValidityRegistration(refs, false));
|
makeValidityRegistration(refs, false, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// The same for derivations
|
// The same for derivations
|
||||||
|
@ -1701,7 +1673,7 @@ void DerivationGoal::startBuilder()
|
||||||
/* !!! in secure Nix, the writing should be done on the
|
/* !!! in secure Nix, the writing should be done on the
|
||||||
build uid for security (maybe). */
|
build uid for security (maybe). */
|
||||||
writeStringToFile(tmpDir + "/" + fileName,
|
writeStringToFile(tmpDir + "/" + fileName,
|
||||||
makeValidityRegistration(refs, false));
|
makeValidityRegistration(refs, false, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,6 @@ static TableId dbReferrers = 0;
|
||||||
static TableId dbDerivers = 0;
|
static TableId dbDerivers = 0;
|
||||||
|
|
||||||
|
|
||||||
static void upgradeStore07();
|
|
||||||
static void upgradeStore09();
|
static void upgradeStore09();
|
||||||
static void upgradeStore11();
|
static void upgradeStore11();
|
||||||
|
|
||||||
|
@ -128,12 +127,12 @@ LocalStore::LocalStore(bool reserveSpace)
|
||||||
% curSchema % nixSchemaVersion);
|
% curSchema % nixSchemaVersion);
|
||||||
|
|
||||||
if (curSchema < nixSchemaVersion) {
|
if (curSchema < nixSchemaVersion) {
|
||||||
|
if (curSchema == 0) /* new store */
|
||||||
|
curSchema = nixSchemaVersion;
|
||||||
if (curSchema <= 1)
|
if (curSchema <= 1)
|
||||||
upgradeStore07();
|
throw Error("your Nix store is no longer supported");
|
||||||
if (curSchema == 2)
|
if (curSchema <= 2) upgradeStore09();
|
||||||
upgradeStore09();
|
if (curSchema <= 3) upgradeStore11();
|
||||||
if (curSchema == 3)
|
|
||||||
upgradeStore11();
|
|
||||||
writeFile(schemaFN, (format("%1%") % nixSchemaVersion).str());
|
writeFile(schemaFN, (format("%1%") % nixSchemaVersion).str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,6 +260,14 @@ bool LocalStore::isValidPath(const Path & path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PathSet LocalStore::queryValidPaths()
|
||||||
|
{
|
||||||
|
Paths paths;
|
||||||
|
nixDB.enumTable(noTxn, dbValidPaths, paths);
|
||||||
|
return PathSet(paths.begin(), paths.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static string addPrefix(const string & prefix, const string & s)
|
static string addPrefix(const string & prefix, const string & s)
|
||||||
{
|
{
|
||||||
return prefix + string(1, (char) 0) + s;
|
return prefix + string(1, (char) 0) + s;
|
||||||
|
@ -1069,93 +1076,6 @@ void LocalStore::optimiseStore(bool dryRun, OptimiseStats & stats)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Upgrade from schema 1 (Nix <= 0.7) to schema 2 (Nix >= 0.8). */
|
|
||||||
static void upgradeStore07()
|
|
||||||
{
|
|
||||||
printMsg(lvlError, "upgrading Nix store to new schema (this may take a while)...");
|
|
||||||
|
|
||||||
Transaction txn(nixDB);
|
|
||||||
|
|
||||||
Paths validPaths2;
|
|
||||||
nixDB.enumTable(txn, dbValidPaths, validPaths2);
|
|
||||||
PathSet validPaths(validPaths2.begin(), validPaths2.end());
|
|
||||||
|
|
||||||
std::cerr << "hashing paths...";
|
|
||||||
int n = 0;
|
|
||||||
for (PathSet::iterator i = validPaths.begin(); i != validPaths.end(); ++i) {
|
|
||||||
checkInterrupt();
|
|
||||||
string s;
|
|
||||||
nixDB.queryString(txn, dbValidPaths, *i, s);
|
|
||||||
if (s == "") {
|
|
||||||
Hash hash = hashPath(htSHA256, *i);
|
|
||||||
setHash(txn, *i, hash);
|
|
||||||
std::cerr << ".";
|
|
||||||
if (++n % 1000 == 0) {
|
|
||||||
txn.commit();
|
|
||||||
txn.begin(nixDB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cerr << std::endl;
|
|
||||||
|
|
||||||
txn.commit();
|
|
||||||
|
|
||||||
txn.begin(nixDB);
|
|
||||||
|
|
||||||
std::cerr << "processing closures...";
|
|
||||||
for (PathSet::iterator i = validPaths.begin(); i != validPaths.end(); ++i) {
|
|
||||||
checkInterrupt();
|
|
||||||
if (i->size() > 6 && string(*i, i->size() - 6) == ".store") {
|
|
||||||
ATerm t = ATreadFromNamedFile(i->c_str());
|
|
||||||
if (!t) throw Error(format("cannot read aterm from `%1%'") % *i);
|
|
||||||
|
|
||||||
ATermList roots, elems;
|
|
||||||
if (!matchOldClosure(t, roots, elems)) continue;
|
|
||||||
|
|
||||||
for (ATermIterator j(elems); j; ++j) {
|
|
||||||
|
|
||||||
ATerm path2;
|
|
||||||
ATermList references2;
|
|
||||||
if (!matchOldClosureElem(*j, path2, references2)) continue;
|
|
||||||
|
|
||||||
Path path = aterm2String(path2);
|
|
||||||
if (validPaths.find(path) == validPaths.end())
|
|
||||||
/* Skip this path; it's invalid. This is a normal
|
|
||||||
condition (Nix <= 0.7 did not enforce closure
|
|
||||||
on closure store expressions). */
|
|
||||||
continue;
|
|
||||||
|
|
||||||
PathSet references;
|
|
||||||
for (ATermIterator k(references2); k; ++k) {
|
|
||||||
Path reference = aterm2String(*k);
|
|
||||||
if (validPaths.find(reference) == validPaths.end())
|
|
||||||
/* Bad reference. Set it anyway and let the
|
|
||||||
user fix it. */
|
|
||||||
printMsg(lvlError, format("closure `%1%' contains reference from `%2%' "
|
|
||||||
"to invalid path `%3%' (run `nix-store --verify')")
|
|
||||||
% *i % path % reference);
|
|
||||||
references.insert(reference);
|
|
||||||
}
|
|
||||||
|
|
||||||
PathSet prevReferences;
|
|
||||||
queryReferences(txn, path, prevReferences);
|
|
||||||
if (prevReferences.size() > 0 && references != prevReferences)
|
|
||||||
printMsg(lvlError, format("warning: conflicting references for `%1%'") % path);
|
|
||||||
|
|
||||||
if (references != prevReferences)
|
|
||||||
setReferences(txn, path, references);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cerr << ".";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cerr << std::endl;
|
|
||||||
|
|
||||||
/* !!! maybe this transaction is way too big */
|
|
||||||
txn.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Upgrade from schema 2 (0.8 <= Nix <= 0.9) to schema 3 (Nix >=
|
/* Upgrade from schema 2 (0.8 <= Nix <= 0.9) to schema 3 (Nix >=
|
||||||
0.10). The only thing to do here is to upgrade the old `referer'
|
0.10). The only thing to do here is to upgrade the old `referer'
|
||||||
table (which causes quadratic complexity in some cases) to the new
|
table (which causes quadratic complexity in some cases) to the new
|
||||||
|
|
|
@ -59,6 +59,8 @@ public:
|
||||||
|
|
||||||
bool isValidPath(const Path & path);
|
bool isValidPath(const Path & path);
|
||||||
|
|
||||||
|
PathSet queryValidPaths();
|
||||||
|
|
||||||
Hash queryPathHash(const Path & path);
|
Hash queryPathHash(const Path & path);
|
||||||
|
|
||||||
void queryReferences(const Path & path, PathSet & references);
|
void queryReferences(const Path & path, PathSet & references);
|
||||||
|
|
|
@ -185,6 +185,12 @@ bool RemoteStore::isValidPath(const Path & path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PathSet RemoteStore::queryValidPaths()
|
||||||
|
{
|
||||||
|
throw Error("not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool RemoteStore::hasSubstitutes(const Path & path)
|
bool RemoteStore::hasSubstitutes(const Path & path)
|
||||||
{
|
{
|
||||||
writeInt(wopHasSubstitutes, to);
|
writeInt(wopHasSubstitutes, to);
|
||||||
|
|
|
@ -27,6 +27,8 @@ public:
|
||||||
|
|
||||||
bool isValidPath(const Path & path);
|
bool isValidPath(const Path & path);
|
||||||
|
|
||||||
|
PathSet queryValidPaths();
|
||||||
|
|
||||||
Hash queryPathHash(const Path & path);
|
Hash queryPathHash(const Path & path);
|
||||||
|
|
||||||
void queryReferences(const Path & path, PathSet & references);
|
void queryReferences(const Path & path, PathSet & references);
|
||||||
|
|
|
@ -151,11 +151,47 @@ Path computeStorePathForText(const string & suffix, const string & s,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ValidPathInfo decodeValidPathInfo(std::istream & str)
|
/* Return a string accepted by decodeValidPathInfo() that
|
||||||
|
registers the specified paths as valid. Note: it's the
|
||||||
|
responsibility of the caller to provide a closure. */
|
||||||
|
string makeValidityRegistration(const PathSet & paths,
|
||||||
|
bool showDerivers, bool showHash)
|
||||||
|
{
|
||||||
|
string s = "";
|
||||||
|
|
||||||
|
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
|
||||||
|
s += *i + "\n";
|
||||||
|
|
||||||
|
if (showHash)
|
||||||
|
s += printHash(store->queryPathHash(*i)) + "\n";
|
||||||
|
|
||||||
|
Path deriver = showDerivers ? store->queryDeriver(*i) : "";
|
||||||
|
s += deriver + "\n";
|
||||||
|
|
||||||
|
PathSet references;
|
||||||
|
store->queryReferences(*i, references);
|
||||||
|
|
||||||
|
s += (format("%1%\n") % references.size()).str();
|
||||||
|
|
||||||
|
for (PathSet::iterator j = references.begin();
|
||||||
|
j != references.end(); ++j)
|
||||||
|
s += *j + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValidPathInfo decodeValidPathInfo(std::istream & str, bool hashGiven)
|
||||||
{
|
{
|
||||||
ValidPathInfo info;
|
ValidPathInfo info;
|
||||||
getline(str, info.path);
|
getline(str, info.path);
|
||||||
if (str.eof()) { info.path = ""; return info; }
|
if (str.eof()) { info.path = ""; return info; }
|
||||||
|
if (hashGiven) {
|
||||||
|
string s;
|
||||||
|
getline(str, s);
|
||||||
|
info.hash = parseHash(htSHA256, s);
|
||||||
|
}
|
||||||
getline(str, info.deriver);
|
getline(str, info.deriver);
|
||||||
string s; int n;
|
string s; int n;
|
||||||
getline(str, s);
|
getline(str, s);
|
||||||
|
|
|
@ -35,6 +35,9 @@ public:
|
||||||
/* Checks whether a path is valid. */
|
/* Checks whether a path is valid. */
|
||||||
virtual bool isValidPath(const Path & path) = 0;
|
virtual bool isValidPath(const Path & path) = 0;
|
||||||
|
|
||||||
|
/* Query the set of valid paths. */
|
||||||
|
virtual PathSet queryValidPaths() = 0;
|
||||||
|
|
||||||
/* Queries the hash of a valid path. */
|
/* Queries the hash of a valid path. */
|
||||||
virtual Hash queryPathHash(const Path & path) = 0;
|
virtual Hash queryPathHash(const Path & path) = 0;
|
||||||
|
|
||||||
|
@ -249,6 +252,9 @@ extern boost::shared_ptr<StoreAPI> store;
|
||||||
boost::shared_ptr<StoreAPI> openStore(bool reserveSpace = true);
|
boost::shared_ptr<StoreAPI> openStore(bool reserveSpace = true);
|
||||||
|
|
||||||
|
|
||||||
|
string makeValidityRegistration(const PathSet & paths,
|
||||||
|
bool showDerivers, bool showHash);
|
||||||
|
|
||||||
struct ValidPathInfo
|
struct ValidPathInfo
|
||||||
{
|
{
|
||||||
Path path;
|
Path path;
|
||||||
|
@ -257,7 +263,8 @@ struct ValidPathInfo
|
||||||
PathSet references;
|
PathSet references;
|
||||||
};
|
};
|
||||||
|
|
||||||
ValidPathInfo decodeValidPathInfo(std::istream & str);
|
ValidPathInfo decodeValidPathInfo(std::istream & str,
|
||||||
|
bool hashGiven = false);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -401,26 +401,31 @@ static void opReadLog(Strings opFlags, Strings opArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void opRegisterValidity(Strings opFlags, Strings opArgs)
|
static void opDumpDB(Strings opFlags, Strings opArgs)
|
||||||
{
|
{
|
||||||
bool reregister = false; // !!! maybe this should be the default
|
if (!opFlags.empty()) throw UsageError("unknown flag");
|
||||||
|
if (!opArgs.empty())
|
||||||
|
throw UsageError("no arguments expected");
|
||||||
|
PathSet validPaths = store->queryValidPaths();
|
||||||
|
/* !!! this isn't streamy; makeValidityRegistration() builds a
|
||||||
|
potentially gigantic string. */
|
||||||
|
cout << makeValidityRegistration(validPaths, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
for (Strings::iterator i = opFlags.begin();
|
|
||||||
i != opFlags.end(); ++i)
|
|
||||||
if (*i == "--reregister") reregister = true;
|
|
||||||
else throw UsageError(format("unknown flag `%1%'") % *i);
|
|
||||||
|
|
||||||
if (!opArgs.empty()) throw UsageError("no arguments expected");
|
|
||||||
|
|
||||||
|
static void registerValidity(bool reregister, bool hashGiven, bool canonicalise)
|
||||||
|
{
|
||||||
ValidPathInfos infos;
|
ValidPathInfos infos;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
ValidPathInfo info = decodeValidPathInfo(cin);
|
ValidPathInfo info = decodeValidPathInfo(cin, hashGiven);
|
||||||
if (info.path == "") break;
|
if (info.path == "") break;
|
||||||
if (!store->isValidPath(info.path) || reregister) {
|
if (!store->isValidPath(info.path) || reregister) {
|
||||||
/* !!! races */
|
/* !!! races */
|
||||||
canonicalisePathMetaData(info.path);
|
if (canonicalise)
|
||||||
info.hash = hashPath(htSHA256, info.path);
|
canonicalisePathMetaData(info.path);
|
||||||
|
if (!hashGiven)
|
||||||
|
info.hash = hashPath(htSHA256, info.path);
|
||||||
infos.push_back(info);
|
infos.push_back(info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -432,6 +437,32 @@ static void opRegisterValidity(Strings opFlags, Strings opArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void opLoadDB(Strings opFlags, Strings opArgs)
|
||||||
|
{
|
||||||
|
if (!opFlags.empty()) throw UsageError("unknown flag");
|
||||||
|
if (!opArgs.empty())
|
||||||
|
throw UsageError("no arguments expected");
|
||||||
|
registerValidity(true, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void opRegisterValidity(Strings opFlags, Strings opArgs)
|
||||||
|
{
|
||||||
|
bool reregister = false; // !!! maybe this should be the default
|
||||||
|
bool hashGiven = false;
|
||||||
|
|
||||||
|
for (Strings::iterator i = opFlags.begin();
|
||||||
|
i != opFlags.end(); ++i)
|
||||||
|
if (*i == "--reregister") reregister = true;
|
||||||
|
else if (*i == "--hash-given") hashGiven = true;
|
||||||
|
else throw UsageError(format("unknown flag `%1%'") % *i);
|
||||||
|
|
||||||
|
if (!opArgs.empty()) throw UsageError("no arguments expected");
|
||||||
|
|
||||||
|
registerValidity(reregister, hashGiven, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void opCheckValidity(Strings opFlags, Strings opArgs)
|
static void opCheckValidity(Strings opFlags, Strings opArgs)
|
||||||
{
|
{
|
||||||
bool printInvalid = false;
|
bool printInvalid = false;
|
||||||
|
@ -681,6 +712,10 @@ void run(Strings args)
|
||||||
op = opQuery;
|
op = opQuery;
|
||||||
else if (arg == "--read-log" || arg == "-l")
|
else if (arg == "--read-log" || arg == "-l")
|
||||||
op = opReadLog;
|
op = opReadLog;
|
||||||
|
else if (arg == "--dump-db")
|
||||||
|
op = opDumpDB;
|
||||||
|
else if (arg == "--load-db")
|
||||||
|
op = opLoadDB;
|
||||||
else if (arg == "--register-validity")
|
else if (arg == "--register-validity")
|
||||||
op = opRegisterValidity;
|
op = opRegisterValidity;
|
||||||
else if (arg == "--check-validity")
|
else if (arg == "--check-validity")
|
||||||
|
|
Loading…
Reference in a new issue