forked from lix-project/lix
* Cleanup.
This commit is contained in:
parent
207ff2caf0
commit
01b34fe584
36
src/eval.cc
36
src/eval.cc
|
@ -106,7 +106,7 @@ static void runProgram(const string & program, Environment env)
|
||||||
|
|
||||||
} catch (exception & e) {
|
} catch (exception & e) {
|
||||||
cerr << format("build error: %1%\n") % e.what();
|
cerr << format("build error: %1%\n") % e.what();
|
||||||
}
|
}
|
||||||
_exit(1);
|
_exit(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -159,38 +159,6 @@ Hash hashTerm(ATerm t)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Evaluate a list of arguments into normal form. */
|
|
||||||
void evalArgs(ATermList args, ATermList & argsNF, Environment & env)
|
|
||||||
{
|
|
||||||
argsNF = ATempty;
|
|
||||||
|
|
||||||
while (!ATisEmpty(args)) {
|
|
||||||
ATerm eName, eVal, arg = ATgetFirst(args);
|
|
||||||
if (!ATmatch(arg, "Tup(<term>, <term>)", &eName, &eVal))
|
|
||||||
throw badTerm("invalid argument", arg);
|
|
||||||
|
|
||||||
string name = evalString(eName);
|
|
||||||
eVal = evalValue(eVal);
|
|
||||||
|
|
||||||
char * s;
|
|
||||||
if (ATmatch(eVal, "Str(<str>)", &s)) {
|
|
||||||
env[name] = s;
|
|
||||||
} else if (ATmatch(eVal, "Hash(<str>)", &s)) {
|
|
||||||
env[name] = queryValuePath(parseHash(s));
|
|
||||||
} else throw badTerm("invalid argument value", eVal);
|
|
||||||
|
|
||||||
argsNF = ATinsert(argsNF,
|
|
||||||
ATmake("Tup(Str(<str>), <term>)", name.c_str(), eVal));
|
|
||||||
|
|
||||||
args = ATgetNext(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
argsNF = ATreverse(argsNF);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
struct RStatus
|
struct RStatus
|
||||||
{
|
{
|
||||||
/* !!! the comparator of this hash should match the semantics of
|
/* !!! the comparator of this hash should match the semantics of
|
||||||
|
@ -362,7 +330,7 @@ static FState realise(RStatus & status, FState fs)
|
||||||
return nf;
|
return nf;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw badTerm("bad file system state expression", fs);
|
throw badTerm("bad fstate expression", fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
368
src/fix.cc
368
src/fix.cc
|
@ -1,368 +0,0 @@
|
||||||
#include <iostream>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include <aterm2.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "util.hh"
|
|
||||||
#include "hash.hh"
|
|
||||||
|
|
||||||
|
|
||||||
static string nixDescriptorDir;
|
|
||||||
|
|
||||||
|
|
||||||
static bool verbose = false;
|
|
||||||
|
|
||||||
|
|
||||||
/* Mapping of Fix file names to the hashes of the resulting Nix
|
|
||||||
descriptors. */
|
|
||||||
typedef map<string, Hash> DescriptorMap;
|
|
||||||
|
|
||||||
|
|
||||||
void registerFile(string filename)
|
|
||||||
{
|
|
||||||
int res = system(("nix regfile " + filename).c_str());
|
|
||||||
/* !!! escape */
|
|
||||||
if (WEXITSTATUS(res) != 0)
|
|
||||||
throw Error("cannot register " + filename + " with Nix");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void registerURL(Hash hash, string url)
|
|
||||||
{
|
|
||||||
int res = system(("nix regurl " + (string) hash + " " + url).c_str());
|
|
||||||
/* !!! escape */
|
|
||||||
if (WEXITSTATUS(res) != 0)
|
|
||||||
throw Error("cannot register " +
|
|
||||||
(string) hash + " -> " + url + " with Nix");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Error badTerm(const string & msg, ATerm e)
|
|
||||||
{
|
|
||||||
char * s = ATwriteToString(e);
|
|
||||||
return Error(msg + ", in `" + s + "'");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Term evaluation. */
|
|
||||||
|
|
||||||
typedef map<string, ATerm> BindingsMap;
|
|
||||||
|
|
||||||
struct EvalContext
|
|
||||||
{
|
|
||||||
string dir;
|
|
||||||
DescriptorMap * done;
|
|
||||||
BindingsMap * vars;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
ATerm evaluate(ATerm e, EvalContext ctx);
|
|
||||||
Hash instantiateDescriptor(string filename, EvalContext ctx);
|
|
||||||
|
|
||||||
|
|
||||||
string evaluateStr(ATerm e, EvalContext ctx)
|
|
||||||
{
|
|
||||||
e = evaluate(e, ctx);
|
|
||||||
char * s;
|
|
||||||
if (ATmatch(e, "Str(<str>)", &s))
|
|
||||||
return s;
|
|
||||||
else throw badTerm("string value expected", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool evaluateBool(ATerm e, EvalContext ctx)
|
|
||||||
{
|
|
||||||
e = evaluate(e, ctx);
|
|
||||||
if (ATmatch(e, "Bool(True)"))
|
|
||||||
return true;
|
|
||||||
else if (ATmatch(e, "Bool(False)"))
|
|
||||||
return false;
|
|
||||||
else throw badTerm("boolean value expected", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ATerm evaluate(ATerm e, EvalContext ctx)
|
|
||||||
{
|
|
||||||
char * s;
|
|
||||||
ATerm e2, e3;
|
|
||||||
ATerm eCond, eTrue, eFalse;
|
|
||||||
|
|
||||||
/* Check for normal forms first. */
|
|
||||||
|
|
||||||
if (ATmatch(e, "Str(<str>)", &s) ||
|
|
||||||
ATmatch(e, "Bool(True)") || ATmatch(e, "Bool(False)"))
|
|
||||||
return e;
|
|
||||||
|
|
||||||
else if (
|
|
||||||
ATmatch(e, "Pkg(<str>)", &s) ||
|
|
||||||
ATmatch(e, "File(<str>)", &s))
|
|
||||||
{
|
|
||||||
parseHash(s);
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Short-hands. */
|
|
||||||
|
|
||||||
else if (ATmatch(e, "<str>", &s))
|
|
||||||
return ATmake("Str(<str>)", s);
|
|
||||||
|
|
||||||
else if (ATmatch(e, "True", &s))
|
|
||||||
return ATmake("Bool(True)", s);
|
|
||||||
|
|
||||||
else if (ATmatch(e, "False", &s))
|
|
||||||
return ATmake("Bool(False)", s);
|
|
||||||
|
|
||||||
/* Functions. */
|
|
||||||
|
|
||||||
/* `Var' looks up a variable. */
|
|
||||||
else if (ATmatch(e, "Var(<str>)", &s)) {
|
|
||||||
string name(s);
|
|
||||||
ATerm e2 = (*ctx.vars)[name];
|
|
||||||
if (!e2) throw Error("undefined variable " + name);
|
|
||||||
return evaluate(e2, ctx); /* !!! update binding */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* `Fix' recursively instantiates a Fix descriptor, returning the
|
|
||||||
hash of the generated Nix descriptor. */
|
|
||||||
else if (ATmatch(e, "Fix(<term>)", &e2)) {
|
|
||||||
string filename = absPath(evaluateStr(e2, ctx), ctx.dir); /* !!! */
|
|
||||||
return ATmake("Pkg(<str>)",
|
|
||||||
((string) instantiateDescriptor(filename, ctx)).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* `Source' copies the specified file to nixSourcesDir, registers
|
|
||||||
it with Nix, and returns the hash of the file. */
|
|
||||||
else if (ATmatch(e, "Source(<term>)", &e2)) {
|
|
||||||
string source = absPath(evaluateStr(e2, ctx), ctx.dir); /* !!! */
|
|
||||||
string target = nixSourcesDir + "/" + baseNameOf(source);
|
|
||||||
|
|
||||||
// Don't copy if filename is already in nixSourcesDir.
|
|
||||||
if (source != target) {
|
|
||||||
if (verbose)
|
|
||||||
cerr << "copying source " << source << endl;
|
|
||||||
string cmd = "cp -p " + source + " " + target;
|
|
||||||
int res = system(cmd.c_str());
|
|
||||||
if (WEXITSTATUS(res) != 0)
|
|
||||||
throw Error("cannot copy " + source + " to " + target);
|
|
||||||
}
|
|
||||||
|
|
||||||
registerFile(target);
|
|
||||||
return ATmake("File(<str>)", hashFile(target).c_str());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* `Local' registers a file with Nix, and returns the file's
|
|
||||||
hash. */
|
|
||||||
else if (ATmatch(e, "Local(<term>)", &e2)) {
|
|
||||||
string filename = absPath(evaluateStr(e2, ctx), ctx.dir); /* !!! */
|
|
||||||
Hash hash = hashFile(filename);
|
|
||||||
registerFile(filename); /* !!! */
|
|
||||||
return ATmake("File(<str>)", ((string) hash).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* `Url' registers a mapping from a hash to an url with Nix, and
|
|
||||||
returns the hash. */
|
|
||||||
else if (ATmatch(e, "Url(<term>, <term>)", &e2, &e3)) {
|
|
||||||
Hash hash = parseHash(evaluateStr(e2, ctx));
|
|
||||||
string url = evaluateStr(e3, ctx);
|
|
||||||
registerURL(hash, url);
|
|
||||||
return ATmake("File(<str>)", ((string) hash).c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
/* `If' provides conditional evaluation. */
|
|
||||||
else if (ATmatch(e, "If(<term>, <term>, <term>)",
|
|
||||||
&eCond, &eTrue, &eFalse))
|
|
||||||
return evaluate(evaluateBool(eCond, ctx) ? eTrue : eFalse, ctx);
|
|
||||||
|
|
||||||
else throw badTerm("invalid expression", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
string getStringFromMap(BindingsMap & bindingsMap,
|
|
||||||
const string & name)
|
|
||||||
{
|
|
||||||
ATerm e = bindingsMap[name];
|
|
||||||
if (!e) throw Error("binding " + name + " is not set");
|
|
||||||
char * s;
|
|
||||||
if (ATmatch(e, "Str(<str>)", &s))
|
|
||||||
return s;
|
|
||||||
else
|
|
||||||
throw Error("binding " + name + " is not a string");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Instantiate a Fix descriptors into a Nix descriptor, recursively
|
|
||||||
instantiating referenced descriptors as well. */
|
|
||||||
Hash instantiateDescriptor(string filename, EvalContext ctx)
|
|
||||||
{
|
|
||||||
/* Already done? */
|
|
||||||
DescriptorMap::iterator isInMap = ctx.done->find(filename);
|
|
||||||
if (isInMap != ctx.done->end()) return isInMap->second;
|
|
||||||
|
|
||||||
/* No. */
|
|
||||||
ctx.dir = dirOf(filename);
|
|
||||||
|
|
||||||
/* Read the Fix descriptor as an ATerm. */
|
|
||||||
ATerm inTerm = ATreadFromNamedFile(filename.c_str());
|
|
||||||
if (!inTerm) throw Error("cannot read aterm " + filename);
|
|
||||||
|
|
||||||
ATerm bindings;
|
|
||||||
if (!ATmatch(inTerm, "Descr(<term>)", &bindings))
|
|
||||||
throw Error("invalid term in " + filename);
|
|
||||||
|
|
||||||
/* Iterate over the bindings and evaluate them to normal form. */
|
|
||||||
BindingsMap bindingsMap; /* the normal forms */
|
|
||||||
ctx.vars = &bindingsMap;
|
|
||||||
|
|
||||||
char * cname;
|
|
||||||
ATerm value;
|
|
||||||
while (ATmatch(bindings, "[Bind(<str>, <term>), <list>]",
|
|
||||||
&cname, &value, &bindings))
|
|
||||||
{
|
|
||||||
string name(cname);
|
|
||||||
ATerm e = evaluate(value, ctx);
|
|
||||||
bindingsMap[name] = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Construct a descriptor identifier by concatenating the package
|
|
||||||
and release ids. */
|
|
||||||
string pkgId = getStringFromMap(bindingsMap, "pkgId");
|
|
||||||
string releaseId = getStringFromMap(bindingsMap, "releaseId");
|
|
||||||
string id = pkgId + "-" + releaseId;
|
|
||||||
bindingsMap["id"] = ATmake("Str(<str>)", id.c_str());
|
|
||||||
|
|
||||||
/* Add a system name. */
|
|
||||||
bindingsMap["system"] = ATmake("Str(<str>)", thisSystem.c_str());
|
|
||||||
|
|
||||||
/* Construct the resulting ATerm. Note that iterating over the
|
|
||||||
map yields the bindings in sorted order, which is exactly the
|
|
||||||
canonical form for Nix descriptors. */
|
|
||||||
ATermList bindingsList = ATempty;
|
|
||||||
for (BindingsMap::iterator it = bindingsMap.begin();
|
|
||||||
it != bindingsMap.end(); it++)
|
|
||||||
/* !!! O(n^2) */
|
|
||||||
bindingsList = ATappend(bindingsList,
|
|
||||||
ATmake("Bind(<str>, <term>)", it->first.c_str(), it->second));
|
|
||||||
ATerm outTerm = ATmake("Descr(<term>)", bindingsList);
|
|
||||||
|
|
||||||
/* Write out the resulting ATerm. */
|
|
||||||
string tmpFilename = nixDescriptorDir + "/tmp";
|
|
||||||
if (!ATwriteToNamedTextFile(outTerm, tmpFilename.c_str()))
|
|
||||||
throw Error("cannot write aterm to " + tmpFilename);
|
|
||||||
|
|
||||||
Hash outHash = hashFile(tmpFilename);
|
|
||||||
string outFilename = nixDescriptorDir + "/" +
|
|
||||||
id + "-" + (string) outHash + ".nix";
|
|
||||||
if (rename(tmpFilename.c_str(), outFilename.c_str()))
|
|
||||||
throw Error("cannot rename " + tmpFilename + " to " + outFilename);
|
|
||||||
|
|
||||||
/* Register it with Nix. */
|
|
||||||
registerFile(outFilename);
|
|
||||||
|
|
||||||
if (verbose)
|
|
||||||
cerr << "instantiated " << (string) outHash
|
|
||||||
<< " from " << filename << endl;
|
|
||||||
|
|
||||||
(*ctx.done)[filename] = outHash;
|
|
||||||
return outHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Instantiate a set of Fix descriptors into Nix descriptors. */
|
|
||||||
void instantiateDescriptors(Strings filenames)
|
|
||||||
{
|
|
||||||
DescriptorMap done;
|
|
||||||
|
|
||||||
EvalContext ctx;
|
|
||||||
ctx.done = &done;
|
|
||||||
|
|
||||||
for (Strings::iterator it = filenames.begin();
|
|
||||||
it != filenames.end(); it++)
|
|
||||||
{
|
|
||||||
string filename = absPath(*it);
|
|
||||||
cout << (string) instantiateDescriptor(filename, ctx) << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Print help. */
|
|
||||||
void printUsage()
|
|
||||||
{
|
|
||||||
cerr <<
|
|
||||||
"Usage: fix ...\n\
|
|
||||||
";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Parse the command-line arguments, call the right operation. */
|
|
||||||
void run(Strings::iterator argCur, Strings::iterator argEnd)
|
|
||||||
{
|
|
||||||
umask(0022);
|
|
||||||
|
|
||||||
Strings extraArgs;
|
|
||||||
enum { cmdUnknown, cmdInstantiate } command = cmdUnknown;
|
|
||||||
|
|
||||||
char * homeDir = getenv(nixHomeDirEnvVar.c_str());
|
|
||||||
if (homeDir) nixHomeDir = homeDir;
|
|
||||||
|
|
||||||
nixDescriptorDir = nixHomeDir + "/var/nix/descriptors";
|
|
||||||
|
|
||||||
for ( ; argCur != argEnd; argCur++) {
|
|
||||||
string arg(*argCur);
|
|
||||||
if (arg == "-h" || arg == "--help") {
|
|
||||||
printUsage();
|
|
||||||
return;
|
|
||||||
} else if (arg == "-v" || arg == "--verbose") {
|
|
||||||
verbose = true;
|
|
||||||
} else if (arg == "--instantiate" || arg == "-i") {
|
|
||||||
command = cmdInstantiate;
|
|
||||||
} else if (arg[0] == '-')
|
|
||||||
throw UsageError("invalid option `" + arg + "'");
|
|
||||||
else
|
|
||||||
extraArgs.push_back(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (command) {
|
|
||||||
|
|
||||||
case cmdInstantiate:
|
|
||||||
instantiateDescriptors(extraArgs);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw UsageError("no operation specified");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char * * argv)
|
|
||||||
{
|
|
||||||
ATerm bottomOfStack;
|
|
||||||
ATinit(argc, argv, &bottomOfStack);
|
|
||||||
|
|
||||||
/* Put the arguments in a vector. */
|
|
||||||
Strings args;
|
|
||||||
while (argc--) args.push_back(*argv++);
|
|
||||||
Strings::iterator argCur = args.begin(), argEnd = args.end();
|
|
||||||
|
|
||||||
argCur++;
|
|
||||||
|
|
||||||
try {
|
|
||||||
run(argCur, argEnd);
|
|
||||||
} catch (UsageError & e) {
|
|
||||||
cerr << "error: " << e.what() << endl
|
|
||||||
<< "Try `fix -h' for more information.\n";
|
|
||||||
return 1;
|
|
||||||
} catch (exception & e) {
|
|
||||||
cerr << "error: " << e.what() << endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -21,7 +21,13 @@ extern string dbRefs;
|
||||||
with hash h2.
|
with hash h2.
|
||||||
|
|
||||||
Note that a term $y$ is successor of $x$ iff there exists a
|
Note that a term $y$ is successor of $x$ iff there exists a
|
||||||
sequence of rewrite steps that rewrites $x$ into $y$. */
|
sequence of rewrite steps that rewrites $x$ into $y$.
|
||||||
|
|
||||||
|
Also note that instead of a successor, $y$ can be any term
|
||||||
|
equivalent to $x$, that is, reducing to the same result, as long as
|
||||||
|
$x$ is equal to or a successor of $y$. (This is useful, e.g., for
|
||||||
|
shared derivate caching over the network).
|
||||||
|
*/
|
||||||
extern string dbSuccessors;
|
extern string dbSuccessors;
|
||||||
|
|
||||||
/* dbNetSources :: Hash -> URL
|
/* dbNetSources :: Hash -> URL
|
||||||
|
|
Loading…
Reference in a new issue