1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-27 04:30:59 +01:00

Merged trunk back in: 10154->10531.

This commit is contained in:
Wouter den Breejen 2008-02-06 23:58:00 +00:00
parent a34a198006
commit 2bf4fcb7cd
15 changed files with 250 additions and 43 deletions

View file

@ -124,7 +124,7 @@ inherit { return INHERIT; }
<STRING>. return yytext[0]; /* just in case: shouldn't be reached */
\'\'(\ *\n)? { BEGIN(IND_STRING); return IND_STRING_OPEN; }
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'])+ {
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
yylval->t = makeIndStr(toATerm(yytext));
return IND_STR;
}
@ -142,6 +142,10 @@ inherit { return INHERIT; }
}
<IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
<IND_STRING>\'\' { BEGIN(INITIAL); return IND_STRING_CLOSE; }
<IND_STRING>\' {
yylval->t = makeIndStr(toATerm("'"));
return IND_STR;
}
<IND_STRING>. return yytext[0]; /* just in case: shouldn't be reached */
{PATH} { yylval->t = toATerm(yytext); return PATH; /* !!! alloc */ }

View file

@ -8,6 +8,7 @@
#include "expr-to-xml.hh"
#include "nixexpr-ast.hh"
#include "local-store.hh"
#include "parser.hh"
#include <sys/types.h>
#include <sys/stat.h>
@ -368,8 +369,8 @@ static Hash hashDerivationModulo(EvalState & state, Derivation drv)
}
/* If we have a state derivation, we clear state paramters because they (sometimes) can affect the outPath:
* If this drv has runtime paramters: The state indentifier and thus statepath may change, but the componentPath (outPath) can stay the same
* If this drv doesnt have runtime paramters: The state indentifier and thus statepath may change, and thus the componentPath changes since it is build with another identifier
* If this drv has runtime paramters: The state indentifier and statepath may change, but the componentPath (outPath) can stay the same
* If this drv doesnt have runtime paramters: The state indentifier and statepath may change, but the componentPath changes since it is build with another identifier
* In both cases: Other runtime state parameters like stateDirs, synchronisation and shareState never change the out or statepath so always need to be out of the hash
*/
if(isStateDrv(drv)){
@ -1097,6 +1098,22 @@ static Expr prim_unsafeDiscardStringContext(EvalState & state, const ATermVector
return makeStr(s, PathSet());
}
/* Expression serialization/deserialization */
static Expr prim_ExprToString ( EvalState & state, const ATermVector & args)
{
return makeStr ( atPrint ( evalExpr ( state, args [ 0 ] ) ) );
}
static Expr prim_StringToExpr ( EvalState & state, const ATermVector & args)
{
string s;
PathSet l;
if (! matchStr ( evalExpr ( state, args[0] ), s, l )) {
throw EvalError("__stringToExpr needs string argument!");
}
return ATreadFromString(s.c_str());
}
/*************************************************************
* Primop registration
@ -1123,6 +1140,10 @@ void EvalState::addPrimOps()
addPrimOp("throw", 1, prim_throw);
addPrimOp("__getEnv", 1, prim_getEnv);
addPrimOp("__trace", 2, prim_trace);
// Expr <-> String
addPrimOp("__exprToString", 1, prim_ExprToString);
addPrimOp("__stringToExpr", 1, prim_StringToExpr);
addPrimOp("relativise", 2, prim_relativise);

View file

@ -102,6 +102,7 @@ protected:
{
nrFailed = 0;
exitCode = ecBusy;
forceInputs = false;
}
virtual ~Goal()
@ -109,6 +110,8 @@ protected:
trace("goal destroyed");
}
bool forceInputs;
public:
virtual void work() = 0;
@ -143,6 +146,11 @@ public:
(important!), etc. */
virtual void cancel() = 0;
void setForceInputs(bool x)
{
forceInputs = x;
}
protected:
void amDone(ExitCode result);
};
@ -757,7 +765,7 @@ public:
{
return drvPath;
}
private:
/* The states. */
void init();
@ -824,7 +832,6 @@ DerivationGoal::DerivationGoal(const Path & drvPath, Worker & worker)
trace("created");
}
DerivationGoal::~DerivationGoal()
{
/* Careful: we should never ever throw an exception from a
@ -837,7 +844,6 @@ DerivationGoal::~DerivationGoal()
}
}
void DerivationGoal::killChild()
{
if (pid != -1) {
@ -919,8 +925,10 @@ void DerivationGoal::haveDerivation()
/* If they are all valid, then we're done. */
if (invalidOutputs.size() == 0) {
amDone(ecSuccess);
return;
if(! forceInputs) {
amDone(ecSuccess);
return;
}
}
/* If this is a fixed-output derivation, it is possible that some
@ -964,8 +972,10 @@ void DerivationGoal::outputsSubstituted()
nrFailed = 0;
if (checkPathValidity(false).size() == 0) {
amDone(ecSuccess);
return;
if (! forceInputs){
amDone(ecSuccess);
return;
}
}
/* Otherwise, at least one of the output paths could not be
@ -974,13 +984,43 @@ void DerivationGoal::outputsSubstituted()
/* The inputs must be built before we can build this goal. */
/* !!! but if possible, only install the paths that we need */
for (DerivationInputs::iterator i = drv.inputDrvs.begin();
i != drv.inputDrvs.end(); ++i)
addWaitee(worker.makeDerivationGoal(i->first));
i != drv.inputDrvs.end(); ++i){
GoalPtr newGoal = worker.makeDerivationGoal(i->first);
newGoal->setForceInputs(forceInputs);
addWaitee(newGoal);
}
for (PathSet::iterator i = drv.inputSrcs.begin();
i != drv.inputSrcs.end(); ++i)
addWaitee(worker.makeSubstitutionGoal(*i));
/* Actually, I do some work twice just to be on the safe side */
string s = drv.env["exportBuildReferencesGraph"];
Strings ss = tokenizeString(s);
if (ss.size() % 2 !=0)
throw BuildError(format("odd number of tokens in `exportBuildReferencesGraph': `%1%'") % s);
for (Strings::iterator i = ss.begin(); i != ss.end(); ) {
string fileName = *i++;
Path storePath=*i++;
if (!isInStore(storePath))
throw BuildError(format("`exportBuildReferencesGraph' contains a non-store path `%1%'")
% storePath);
storePath = toStorePath(storePath);
if (!store->isValidPath(storePath))
throw BuildError(format("`exportBuildReferencesGraph' contains an invalid path `%1%'")
% storePath);
/* Build-time closure should be in dependencies
* We really want just derivation, its closure
* and outputs. Looks like we should build it.
* */
GoalPtr newGoal = worker.makeDerivationGoal(storePath);
newGoal->setForceInputs(true);
addWaitee(newGoal);
}
state = &DerivationGoal::inputsRealised;
}
@ -998,6 +1038,12 @@ void DerivationGoal::inputsRealised()
return;
}
/* Maybe we just wanted to force build of inputs */
if (checkPathValidity(false).size() == 0) {
amDone(ecSuccess);
return;
}
/* Okay, try to build. Note that here we don't wait for a build
slot to become available, since we don't need one if there is a
build hook. */
@ -1279,7 +1325,6 @@ static string makeValidityRegistration(const PathSet & paths,
return s;
}
DerivationGoal::HookReply DerivationGoal::tryBuildHook()
{
if (!useBuildHook) return rpDecline;
@ -1406,7 +1451,7 @@ DerivationGoal::HookReply DerivationGoal::tryBuildHook()
/* The `references' file has exactly the format accepted by
`nix-store --register-validity'. */
writeStringToFile(referencesFN,
makeValidityRegistration(allInputs, true));
makeValidityRegistration(allInputs, true, false));
/* Tell the hook to proceed. */
writeLine(toHook.writeSide, "okay");
@ -1668,14 +1713,14 @@ void DerivationGoal::startBuilder()
/* !!! in secure Nix, the writing should be done on the
build uid for security (maybe). */
writeStringToFile(tmpDir + "/" + fileName,
makeValidityRegistration(refs, false));
makeValidityRegistration(refs, false, false));
}
// The same for derivations
s = drv.env["exportBuildReferencesGraph"];
ss = tokenizeString(s);
if (ss.size() % 2 != 0)
throw BuildError(format("odd number of tokens in `exportReferencesGraph': `%1%'") % s);
throw BuildError(format("odd number of tokens in `exportBuildReferencesGraph': `%1%'") % s);
for (Strings::iterator i = ss.begin(); i != ss.end(); ) {
string fileName = *i++;
checkStoreName(fileName); /* !!! abuse of this function */
@ -1683,11 +1728,11 @@ void DerivationGoal::startBuilder()
/* Check that the store path is valid. */
Path storePath = *i++;
if (!isInStore(storePath))
throw BuildError(format("`exportReferencesGraph' contains a non-store path `%1%'")
throw BuildError(format("`exportBuildReferencesGraph' contains a non-store path `%1%'")
% storePath);
storePath = toStorePath(storePath);
if (!store->isValidPath(storePath))
throw BuildError(format("`exportReferencesGraph' contains an invalid path `%1%'")
throw BuildError(format("`exportBuildReferencesGraph' contains an invalid path `%1%'")
% storePath);
/* Write closure info to `fileName'. */
@ -1700,13 +1745,14 @@ void DerivationGoal::startBuilder()
for (DerivationOutputs::iterator k=deriv.outputs.begin();
k != deriv.outputs.end(); k++) {
refs.insert(k->second.path);
}
}
}
/* !!! in secure Nix, the writing should be done on the
build uid for security (maybe). */
writeStringToFile(tmpDir + "/" + fileName,
makeValidityRegistration(refs, false));
makeValidityRegistration(refs, false, false));
}

View file

@ -246,12 +246,12 @@ LocalStore::LocalStore(bool reserveSpace)
% curSchema % nixSchemaVersion);
if (curSchema < nixSchemaVersion) {
if (curSchema == 0) /* new store */
curSchema = nixSchemaVersion;
if (curSchema <= 1)
upgradeStore07();
if (curSchema == 2)
upgradeStore09();
if (curSchema == 3)
upgradeStore11();
throw Error("your Nix store is no longer supported");
if (curSchema <= 2) upgradeStore09();
if (curSchema <= 3) upgradeStore11();
writeFile(schemaFN, (format("%1%") % nixSchemaVersion).str());
}
}
@ -377,6 +377,31 @@ bool LocalStore::isValidPath(const Path & path)
return isValidPathTxn(noTxn, 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)
{
return prefix + string(1, (char) 0) + s;
}
static string stripPrefix(const string & prefix, const string & s)
{
if (s.size() <= prefix.size() ||
string(s, 0, prefix.size()) != prefix ||
s[prefix.size()] != 0)
throw Error(format("string `%1%' is missing prefix `%2%'")
% s % prefix);
return string(s, prefix.size() + 1);
}
bool isValidStatePathTxn(const Transaction & txn, const Path & path)
{
string s;

View file

@ -63,6 +63,8 @@ public:
bool isValidComponentOrStatePath(const Path & path);
PathSet queryValidPaths();
Hash queryPathHash(const Path & path);
Path queryStatePathDrv(const Path & statePath);

View file

@ -236,6 +236,12 @@ bool RemoteStore::isValidComponentOrStatePath(const Path & path)
return reply != 0;
}
PathSet RemoteStore::queryValidPaths()
{
throw Error("not implemented");
}
bool RemoteStore::hasSubstitutes(const Path & path)
{
writeInt(wopHasSubstitutes, to);

View file

@ -31,6 +31,8 @@ public:
bool isValidComponentOrStatePath(const Path & path);
PathSet queryValidPaths();
Hash queryPathHash(const Path & path);
Path queryStatePathDrv(const Path & statePath);

View file

@ -234,13 +234,50 @@ Path computeStorePathForText(const string & suffix, const string & s,
return makeStorePath(type, hash, suffix);
}
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;
getline(str, info.path);
if (str.eof()) { info.path = ""; return info; }
if (hashGiven) {
string s;
getline(str, s);
info.hash = parseHash(htSHA256, s);
}
getline(str, info.deriver);
string s; int n;

View file

@ -43,6 +43,9 @@ public:
/* TODO */
virtual bool isValidComponentOrStatePath(const Path & path) = 0;
/* Query the set of valid paths. */
virtual PathSet queryValidPaths() = 0;
/* Queries the hash of a valid path. */
virtual Hash queryPathHash(const Path & path) = 0;
@ -339,6 +342,9 @@ extern boost::shared_ptr<StoreAPI> store;
boost::shared_ptr<StoreAPI> openStore(bool reserveSpace = true);
string makeValidityRegistration(const PathSet & paths,
bool showDerivers, bool showHash);
/* OLD TODO REMOVE
struct ValidPathInfo
@ -359,7 +365,8 @@ struct ValidPathInfo
int unsigned revision;
};
ValidPathInfo decodeValidPathInfo(std::istream & str);
ValidPathInfo decodeValidPathInfo(std::istream & str,
bool hashGiven = false);
}

View file

@ -424,26 +424,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
for (Strings::iterator i = opFlags.begin();
i != opFlags.end(); ++i)
if (*i == "--reregister") reregister = true;
else throw UsageError(format("unknown flag `%1%'") % *i);
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);
}
if (!opArgs.empty()) throw UsageError("no arguments expected");
static void registerValidity(bool reregister, bool hashGiven, bool canonicalise)
{
ValidPathInfos infos;
while (1) {
ValidPathInfo info = decodeValidPathInfo(cin);
ValidPathInfo info = decodeValidPathInfo(cin, hashGiven);
if (info.path == "") break;
if (!store->isValidPath(info.path) || reregister) {
/* !!! races */
canonicalisePathMetaData(info.path);
info.hash = hashPath(htSHA256, info.path);
if (canonicalise)
canonicalisePathMetaData(info.path);
if (!hashGiven)
info.hash = hashPath(htSHA256, info.path);
infos.push_back(info);
}
}
@ -455,6 +460,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)
{
bool printInvalid = false;
@ -704,6 +735,10 @@ void run(Strings args)
op = opQuery;
else if (arg == "--read-log" || arg == "-l")
op = opReadLog;
else if (arg == "--dump-db")
op = opDumpDB;
else if (arg == "--load-db")
op = opLoadDB;
else if (arg == "--register-validity")
op = opRegisterValidity;
else if (arg == "--check-validity")