mirror of
https://github.com/NixOS/nix.git
synced 2025-11-27 12:41:00 +01:00
265 lines
8.6 KiB
C++
265 lines
8.6 KiB
C++
#include "derivations.hh"
|
|
#include "store-api.hh"
|
|
#include "aterm.hh"
|
|
#include "globals.hh"
|
|
#include "util.hh"
|
|
|
|
#include "derivations-ast.hh"
|
|
#include "derivations-ast.cc"
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
|
Hash hashTerm(ATerm t)
|
|
{
|
|
return hashString(htSHA256, atPrint(t));
|
|
}
|
|
|
|
|
|
Path writeDerivation(const Derivation & drv, const string & name)
|
|
{
|
|
PathSet references;
|
|
references.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
|
|
for (DerivationInputs::const_iterator i = drv.inputDrvs.begin(); i != drv.inputDrvs.end(); ++i)
|
|
references.insert(i->first);
|
|
/* Note that the outputs of a derivation are *not* references
|
|
(that can be missing (of course) and should not necessarily be
|
|
held during a garbage collection). */
|
|
|
|
string suffix = name + drvExtension;
|
|
string contents = atPrint(unparseDerivation(drv));
|
|
return readOnlyMode
|
|
? computeStorePathForText(suffix, contents, references)
|
|
: store->addTextToStore(suffix, contents, references);
|
|
}
|
|
|
|
|
|
static void checkPath(const string & s)
|
|
{
|
|
if (s.size() == 0 || s[0] != '/')
|
|
throw Error(format("bad path `%1%' in derivation") % s);
|
|
}
|
|
|
|
|
|
static void parseStrings(ATermList paths, StringSet & out, bool arePaths)
|
|
{
|
|
for (ATermIterator i(paths); i; ++i) {
|
|
if (ATgetType(*i) != AT_APPL)
|
|
throw badTerm("not a path", *i);
|
|
string s = aterm2String(*i);
|
|
if (arePaths) checkPath(s);
|
|
out.insert(s);
|
|
}
|
|
}
|
|
|
|
|
|
/* Shut up warnings. */
|
|
void throwBadDrv(ATerm t) __attribute__ ((noreturn));
|
|
|
|
void throwBadDrv(ATerm t)
|
|
{
|
|
throw badTerm("not a valid derivation", t);
|
|
}
|
|
|
|
|
|
Derivation parseDerivation(ATerm t)
|
|
{
|
|
Derivation drv;
|
|
ATermList outs, inDrvs, inSrcs, args, bnds;
|
|
ATermList stateOuts = ATempty, stateOutDirs = ATempty;
|
|
|
|
ATerm builder, platform;
|
|
|
|
bool withState;
|
|
if (matchDerive(t, outs, stateOuts, stateOutDirs, inDrvs, inSrcs, platform, builder, args, bnds) ) { withState = true; }
|
|
else if (matchDeriveWithOutState(t, outs, inDrvs, inSrcs, platform, builder, args, bnds) ) { withState = false; }
|
|
else
|
|
throwBadDrv(t);
|
|
|
|
for (ATermIterator i(outs); i; ++i) {
|
|
ATerm id, path, hashAlgo, hash;
|
|
if (!matchDerivationOutput(*i, id, path, hashAlgo, hash))
|
|
throwBadDrv(t);
|
|
DerivationOutput out;
|
|
out.path = aterm2String(path);
|
|
checkPath(out.path);
|
|
out.hashAlgo = aterm2String(hashAlgo);
|
|
out.hash = aterm2String(hash);
|
|
drv.outputs[aterm2String(id)] = out;
|
|
}
|
|
|
|
if(withState){
|
|
//parse state part
|
|
for (ATermIterator i(stateOuts); i; ++i) {
|
|
ATerm id, statepath, componentHash, hashAlgo, hash, stateIdentifier, enabled, shared, synchronization, createDirsBeforeInstall, runtimeStateParamters, username;
|
|
if (!matchDerivationStateOutput(*i, id, statepath, componentHash, hashAlgo, hash, stateIdentifier, enabled, shared, synchronization, createDirsBeforeInstall, runtimeStateParamters, username))
|
|
throwBadDrv(t);
|
|
DerivationStateOutput stateOut;
|
|
stateOut.statepath = aterm2String(statepath);
|
|
stateOut.componentHash = aterm2String(componentHash);
|
|
//checkPath(stateOut.path); //should we check the statpath .... ???
|
|
stateOut.hashAlgo = aterm2String(hashAlgo);
|
|
stateOut.hash = aterm2String(hash);
|
|
stateOut.stateIdentifier = aterm2String(stateIdentifier);
|
|
stateOut.enabled = aterm2String(enabled);
|
|
stateOut.shared = aterm2String(shared);
|
|
stateOut.synchronization = aterm2String(synchronization);
|
|
stateOut.createDirsBeforeInstall = aterm2String(createDirsBeforeInstall);
|
|
stateOut.runtimeStateParamters = aterm2String(runtimeStateParamters);
|
|
stateOut.username = aterm2String(username);
|
|
drv.stateOutputs[aterm2String(id)] = stateOut;
|
|
}
|
|
}
|
|
|
|
if(withState){
|
|
//parse state dirs part
|
|
for (ATermIterator i(stateOutDirs); i; ++i) {
|
|
ATerm id, path, type, interval;
|
|
if (!matchDerivationStateOutputDir(*i, id, type, interval))
|
|
throwBadDrv(t);
|
|
path = id; //We prevent duplication since the key is also the path
|
|
DerivationStateOutputDir stateOutDirs;
|
|
stateOutDirs.path = aterm2String(path);
|
|
stateOutDirs.type = aterm2String(type);
|
|
stateOutDirs.interval = aterm2String(interval);
|
|
drv.stateOutputDirs[aterm2String(id)] = stateOutDirs;
|
|
}
|
|
}
|
|
|
|
for (ATermIterator i(inDrvs); i; ++i) {
|
|
ATerm drvPath;
|
|
ATermList ids;
|
|
if (!matchDerivationInput(*i, drvPath, ids))
|
|
throwBadDrv(t);
|
|
Path drvPath2 = aterm2String(drvPath);
|
|
checkPath(drvPath2);
|
|
StringSet ids2;
|
|
parseStrings(ids, ids2, false);
|
|
drv.inputDrvs[drvPath2] = ids2;
|
|
}
|
|
|
|
parseStrings(inSrcs, drv.inputSrcs, true);
|
|
|
|
drv.builder = aterm2String(builder);
|
|
drv.platform = aterm2String(platform);
|
|
|
|
for (ATermIterator i(args); i; ++i) {
|
|
if (ATgetType(*i) != AT_APPL)
|
|
throw badTerm("string expected", *i);
|
|
drv.args.push_back(aterm2String(*i));
|
|
}
|
|
|
|
for (ATermIterator i(bnds); i; ++i) {
|
|
ATerm s1, s2;
|
|
if (!matchEnvBinding(*i, s1, s2))
|
|
throw badTerm("tuple of strings expected", *i);
|
|
drv.env[aterm2String(s1)] = aterm2String(s2);
|
|
}
|
|
|
|
return drv;
|
|
}
|
|
|
|
|
|
ATerm unparseDerivation(const Derivation & drv)
|
|
{
|
|
ATermList outputs = ATempty;
|
|
for (DerivationOutputs::const_reverse_iterator i = drv.outputs.rbegin(); i != drv.outputs.rend(); ++i)
|
|
outputs = ATinsert(outputs,
|
|
makeDerivationOutput(
|
|
toATerm(i->first),
|
|
toATerm(i->second.path),
|
|
toATerm(i->second.hashAlgo),
|
|
toATerm(i->second.hash)));
|
|
|
|
//decide if we need to add state to the derivation
|
|
bool createState = false;
|
|
|
|
ATermList stateOutputs = ATempty;
|
|
for (DerivationStateOutputs::const_reverse_iterator i = drv.stateOutputs.rbegin(); i != drv.stateOutputs.rend(); ++i){
|
|
if(i->second.enabled == "true"){
|
|
createState = true;
|
|
}
|
|
stateOutputs = ATinsert(stateOutputs,
|
|
makeDerivationStateOutput(
|
|
toATerm(i->first),
|
|
toATerm(i->second.statepath),
|
|
toATerm(i->second.componentHash),
|
|
toATerm(i->second.hashAlgo),
|
|
toATerm(i->second.hash),
|
|
toATerm(i->second.stateIdentifier),
|
|
toATerm(i->second.enabled),
|
|
toATerm(i->second.shared),
|
|
toATerm(i->second.synchronization),
|
|
toATerm(i->second.createDirsBeforeInstall),
|
|
toATerm(i->second.runtimeStateParamters),
|
|
toATerm(i->second.username)
|
|
));
|
|
}
|
|
|
|
ATermList stateOutputDirs = ATempty;
|
|
for (DerivationStateOutputDirs::const_reverse_iterator i = drv.stateOutputDirs.rbegin(); i != drv.stateOutputDirs.rend(); ++i)
|
|
stateOutputDirs = ATinsert(stateOutputDirs,
|
|
makeDerivationStateOutputDir(
|
|
toATerm(i->first),
|
|
//toATerm(i->second.path), //removed to prevent duplication since the key is also the path
|
|
toATerm(i->second.type),
|
|
toATerm(i->second.interval)
|
|
));
|
|
|
|
|
|
ATermList inDrvs = ATempty;
|
|
for (DerivationInputs::const_reverse_iterator i = drv.inputDrvs.rbegin();
|
|
i != drv.inputDrvs.rend(); ++i)
|
|
inDrvs = ATinsert(inDrvs,
|
|
makeDerivationInput(
|
|
toATerm(i->first),
|
|
toATermList(i->second)));
|
|
|
|
ATermList args = ATempty;
|
|
for (Strings::const_reverse_iterator i = drv.args.rbegin();
|
|
i != drv.args.rend(); ++i)
|
|
args = ATinsert(args, toATerm(*i));
|
|
|
|
ATermList env = ATempty;
|
|
for (StringPairs::const_reverse_iterator i = drv.env.rbegin();
|
|
i != drv.env.rend(); ++i)
|
|
env = ATinsert(env,
|
|
makeEnvBinding(
|
|
toATerm(i->first),
|
|
toATerm(i->second)));
|
|
|
|
if(createState){
|
|
return makeDerive(
|
|
outputs,
|
|
stateOutputs,
|
|
stateOutputDirs,
|
|
inDrvs,
|
|
toATermList(drv.inputSrcs),
|
|
toATerm(drv.platform),
|
|
toATerm(drv.builder),
|
|
args,
|
|
env);
|
|
}
|
|
else{
|
|
return makeDeriveWithOutState(
|
|
outputs,
|
|
inDrvs,
|
|
toATermList(drv.inputSrcs),
|
|
toATerm(drv.platform),
|
|
toATerm(drv.builder),
|
|
args,
|
|
env);
|
|
}
|
|
}
|
|
|
|
|
|
bool isDerivation(const string & fileName)
|
|
{
|
|
return
|
|
fileName.size() >= drvExtension.size() &&
|
|
string(fileName, fileName.size() - drvExtension.size()) == drvExtension;
|
|
}
|
|
|
|
|
|
}
|