mirror of
https://github.com/NixOS/nix.git
synced 2025-11-26 04:00:59 +01:00
Merged trunk back in: 10154->10531.
This commit is contained in:
parent
a34a198006
commit
2bf4fcb7cd
15 changed files with 250 additions and 43 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ fi
|
|||
--prefix=$nixstatepath \
|
||||
--with-store-dir=/nix/store \
|
||||
--with-store-state-dir=/nix/state \
|
||||
--with-ext3cow-header=/nix/store/v95qf520d6972pshykrah1dz3z53rkmj-linux-2.6.21.7/lib/modules/2.6.21.7-default/build/include/linux/ext3cow_fs.h \
|
||||
--with-ext3cow-header=/nix/store/2sm0h2xd1zsm5had53q1pvzmnsn8fy8k-linux-2.6.21/lib/modules/2.6.21-ck1-default/build/include/linux/ext3cow_fs.h \
|
||||
--localstatedir=/nix/var
|
||||
|
||||
#Options from the nix expr
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
svn merge -r 9751:10133 https://svn.cs.uu.nl:12443/repos/trace/nix/trunk
|
||||
svn merge -r 10154:10531 https://svn.cs.uu.nl:12443/repos/trace/nix/trunk
|
||||
|
||||
#already done:
|
||||
# 8628
|
||||
|
|
@ -28,4 +28,6 @@ svn merge -r 9751:10133 https://svn.cs.uu.nl:12443/repos/trace/nix/trunk
|
|||
# 9561
|
||||
# 9584
|
||||
# 9751
|
||||
# 10133 TODO
|
||||
# 10133
|
||||
# 10154
|
||||
# 10531
|
||||
|
|
|
|||
|
|
@ -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 */ }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -1124,6 +1141,10 @@ void EvalState::addPrimOps()
|
|||
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);
|
||||
|
||||
// Derivations
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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,9 +925,11 @@ void DerivationGoal::haveDerivation()
|
|||
|
||||
/* If they are all valid, then we're done. */
|
||||
if (invalidOutputs.size() == 0) {
|
||||
if(! forceInputs) {
|
||||
amDone(ecSuccess);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is a fixed-output derivation, it is possible that some
|
||||
other goal is already building the output paths. (The case
|
||||
|
|
@ -964,9 +972,11 @@ void DerivationGoal::outputsSubstituted()
|
|||
nrFailed = 0;
|
||||
|
||||
if (checkPathValidity(false).size() == 0) {
|
||||
if (! forceInputs){
|
||||
amDone(ecSuccess);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, at least one of the output paths could not be
|
||||
produced using a substitute. So we have to build instead. */
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ public:
|
|||
|
||||
bool isValidComponentOrStatePath(const Path & path);
|
||||
|
||||
PathSet queryValidPaths();
|
||||
|
||||
Hash queryPathHash(const Path & path);
|
||||
|
||||
Path queryStatePathDrv(const Path & statePath);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ public:
|
|||
|
||||
bool isValidComponentOrStatePath(const Path & path);
|
||||
|
||||
PathSet queryValidPaths();
|
||||
|
||||
Hash queryPathHash(const Path & path);
|
||||
|
||||
Path queryStatePathDrv(const Path & statePath);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -424,25 +424,30 @@ 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;
|
||||
|
||||
while (1) {
|
||||
ValidPathInfo info = decodeValidPathInfo(cin);
|
||||
ValidPathInfo info = decodeValidPathInfo(cin, hashGiven);
|
||||
if (info.path == "") break;
|
||||
if (!store->isValidPath(info.path) || reregister) {
|
||||
/* !!! races */
|
||||
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")
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Str("This is an indented multi-line string\nliteral. An amount of whitespace at\nthe start of each line matching the minimum\nindentation of all lines in the string\nliteral together will be removed. Thus,\nin this case four spaces will be\nstripped from each line, even though\n THIS LINE is indented six spaces.\n\nAlso, empty lines don't count in the\ndetermination of the indentation level (the\nprevious empty line has indentation 0, but\nit doesn't matter).\nIf the string starts with whitespace\n followed by a newline, it's stripped, but\n that's not the case here. Two spaces are\n stripped because of the \" \" at the start. \nThis line is indented\na bit further.\nAnti-quotations, like so, are\nalso allowed.\n The \\ is not special here.\n' can be followed by any character except another ', e.g. 'x'.\nLikewise for $, e.g. $$ or $varName.\nBut ' followed by ' is special, as is $ followed by {.\nIf you want them, use anti-quotations: '', ${.\n Tabs are not interpreted as whitespace (since we can't guess\n what tab settings are intended), so don't use them.\n\tThis line starts with a space and a tab, so only one\n space will be stripped from each line.\nAlso note that if the last line (just before the closing ' ')\nconsists only of whitespace, it's ignored. But here there is\nsome non-whitespace stuff, so the line isn't removed. \nThis shows a hacky way to preserve an empty line after the start.\nBut there's no reason to do so: you could just repeat the empty\nline.\n Similarly you can force an indentation level,\n in this case to 2 spaces. This works because the anti-quote\n is significant (not whitespace).\nstart on network-interfaces\n\nstart script\n\n rm -f /var/run/opengl-driver\n ln -sf 123 /var/run/opengl-driver\n\n rm -f /var/log/slim.log\n \nend script\n\nenv SLIM_CFGFILE=abc\nenv SLIM_THEMESDIR=def\nenv FONTCONFIG_FILE=/etc/fonts/fonts.conf \t\t\t\t# !!! cleanup\nenv XKB_BINDIR=foo/bin \t\t\t\t# Needed for the Xkb extension.\nenv LD_LIBRARY_PATH=libX11/lib:libXext/lib:/usr/lib/ # related to xorg-sys-opengl - needed to load libglx for (AI)GLX support (for compiz)\n\nenv XORG_DRI_DRIVER_PATH=nvidiaDrivers/X11R6/lib/modules/drivers/ \n\nexec slim/bin/slim\nEscaping of ' followed by ': ''\nEscaping of $ followed by {: ${\nAnd finally to interpret \\n etc. as in a string: \n, \r, \t.\n",[])
|
||||
Str("This is an indented multi-line string\nliteral. An amount of whitespace at\nthe start of each line matching the minimum\nindentation of all lines in the string\nliteral together will be removed. Thus,\nin this case four spaces will be\nstripped from each line, even though\n THIS LINE is indented six spaces.\n\nAlso, empty lines don't count in the\ndetermination of the indentation level (the\nprevious empty line has indentation 0, but\nit doesn't matter).\nIf the string starts with whitespace\n followed by a newline, it's stripped, but\n that's not the case here. Two spaces are\n stripped because of the \" \" at the start. \nThis line is indented\na bit further.\nAnti-quotations, like so, are\nalso allowed.\n The \\ is not special here.\n' can be followed by any character except another ', e.g. 'x'.\nLikewise for $, e.g. $$ or $varName.\nBut ' followed by ' is special, as is $ followed by {.\nIf you want them, use anti-quotations: '', ${.\n Tabs are not interpreted as whitespace (since we can't guess\n what tab settings are intended), so don't use them.\n\tThis line starts with a space and a tab, so only one\n space will be stripped from each line.\nAlso note that if the last line (just before the closing ' ')\nconsists only of whitespace, it's ignored. But here there is\nsome non-whitespace stuff, so the line isn't removed. \nThis shows a hacky way to preserve an empty line after the start.\nBut there's no reason to do so: you could just repeat the empty\nline.\n Similarly you can force an indentation level,\n in this case to 2 spaces. This works because the anti-quote\n is significant (not whitespace).\nstart on network-interfaces\n\nstart script\n\n rm -f /var/run/opengl-driver\n ln -sf 123 /var/run/opengl-driver\n\n rm -f /var/log/slim.log\n \nend script\n\nenv SLIM_CFGFILE=abc\nenv SLIM_THEMESDIR=def\nenv FONTCONFIG_FILE=/etc/fonts/fonts.conf \t\t\t\t# !!! cleanup\nenv XKB_BINDIR=foo/bin \t\t\t\t# Needed for the Xkb extension.\nenv LD_LIBRARY_PATH=libX11/lib:libXext/lib:/usr/lib/ # related to xorg-sys-opengl - needed to load libglx for (AI)GLX support (for compiz)\n\nenv XORG_DRI_DRIVER_PATH=nvidiaDrivers/X11R6/lib/modules/drivers/ \n\nexec slim/bin/slim\nEscaping of ' followed by ': ''\nEscaping of $ followed by {: ${\nAnd finally to interpret \\n etc. as in a string: \n, \r, \t.\nfoo\n'bla'\nbar\n",[])
|
||||
|
|
|
|||
|
|
@ -110,4 +110,11 @@ let
|
|||
And finally to interpret \n etc. as in a string: ''\n, ''\r, ''\t.
|
||||
'';
|
||||
|
||||
in s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14
|
||||
# Regression test: antiquotation in '${x}' should work, but didn't.
|
||||
s15 = let x = "bla"; in ''
|
||||
foo
|
||||
'${x}'
|
||||
bar
|
||||
'';
|
||||
|
||||
in s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue