* Don't use the ATerm library for parsing/printing .drv files.

This commit is contained in:
Eelco Dolstra 2010-04-19 13:46:58 +00:00
parent 55b5ddd3ca
commit efc7a579e8
14 changed files with 174 additions and 330 deletions

View file

@ -262,7 +262,7 @@ static Hash hashDerivationModulo(EvalState & state, Derivation drv)
} }
drv.inputDrvs = inputs2; drv.inputDrvs = inputs2;
return hashTerm(unparseDerivation(drv)); return hashString(htSHA256, unparseDerivation(drv));
} }

View file

@ -87,9 +87,6 @@ static void setLogType(string lt)
} }
void initDerivationsHelpers();
static void closeStore() static void closeStore()
{ {
try { try {
@ -176,9 +173,6 @@ static void initAndRun(int argc, char * * argv)
string lt = getEnv("NIX_LOG_TYPE"); string lt = getEnv("NIX_LOG_TYPE");
if (lt != "") setLogType(lt); if (lt != "") setLogType(lt);
/* ATerm stuff. !!! find a better place to put this */
initDerivationsHelpers();
/* Put the arguments in a vector. */ /* Put the arguments in a vector. */
Strings args, remaining; Strings args, remaining;
while (argc--) args.push_back(*argv++); while (argc--) args.push_back(*argv++);
@ -333,10 +327,6 @@ int main(int argc, char * * argv)
if (argc == 0) abort(); if (argc == 0) abort();
setuidInit(); setuidInit();
/* ATerm setup. */
ATerm bottomOfStack;
ATinit(argc, argv, &bottomOfStack);
/* Turn on buffering for cerr. */ /* Turn on buffering for cerr. */
#if HAVE_PUBSETBUF #if HAVE_PUBSETBUF
std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf)); std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));

View file

@ -12,12 +12,5 @@ pkginclude_HEADERS = \
libstore_la_LIBADD = ../libutil/libutil.la ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@ libstore_la_LIBADD = ../libutil/libutil.la ../boost/format/libformat.la @ADDITIONAL_NETWORK_LIBS@
BUILT_SOURCES = derivations-ast.cc derivations-ast.hh
EXTRA_DIST = derivations-ast.def derivations-ast.cc
AM_CXXFLAGS = -Wall \ AM_CXXFLAGS = -Wall \
-I$(srcdir)/.. ${aterm_include} -I$(srcdir)/../libutil -I$(srcdir)/.. ${aterm_include} -I$(srcdir)/../libutil
derivations-ast.cc derivations-ast.hh: ../aterm-helper.pl derivations-ast.def
$(perl) $(srcdir)/../aterm-helper.pl derivations-ast.hh derivations-ast.cc < $(srcdir)/derivations-ast.def

View file

@ -1,10 +0,0 @@
init initDerivationsHelpers
Derive | ATermList ATermList ATermList string string ATermList ATermList | ATerm |
| string string | ATerm | EnvBinding |
| string ATermList | ATerm | DerivationInput |
| string string string string | ATerm | DerivationOutput |
Closure | ATermList ATermList | ATerm | OldClosure |
| string ATermList | ATerm | OldClosureElem |

View file

@ -1,22 +1,12 @@
#include "derivations.hh" #include "derivations.hh"
#include "store-api.hh" #include "store-api.hh"
#include "aterm.hh"
#include "globals.hh" #include "globals.hh"
#include "util.hh" #include "util.hh"
#include "derivations-ast.hh"
#include "derivations-ast.cc"
namespace nix { namespace nix {
Hash hashTerm(ATerm t)
{
return hashString(htSHA256, atPrint(t));
}
Path writeDerivation(const Derivation & drv, const string & name) Path writeDerivation(const Derivation & drv, const string & name)
{ {
PathSet references; PathSet references;
@ -27,137 +17,150 @@ Path writeDerivation(const Derivation & drv, const string & name)
(that can be missing (of course) and should not necessarily be (that can be missing (of course) and should not necessarily be
held during a garbage collection). */ held during a garbage collection). */
string suffix = name + drvExtension; string suffix = name + drvExtension;
string contents = atPrint(unparseDerivation(drv)); string contents = unparseDerivation(drv);
return readOnlyMode return readOnlyMode
? computeStorePathForText(suffix, contents, references) ? computeStorePathForText(suffix, contents, references)
: store->addTextToStore(suffix, contents, references); : store->addTextToStore(suffix, contents, references);
} }
static void checkPath(const string & s) static Path parsePath(std::istream & str)
{ {
string s = parseString(str);
if (s.size() == 0 || s[0] != '/') if (s.size() == 0 || s[0] != '/')
throw Error(format("bad path `%1%' in derivation") % s); throw Error(format("bad path `%1%' in derivation") % s);
return s;
} }
static void parseStrings(ATermList paths, StringSet & out, bool arePaths) static StringSet parseStrings(std::istream & str, bool arePaths)
{ {
for (ATermIterator i(paths); i; ++i) { StringSet res;
if (ATgetType(*i) != AT_APPL) while (!endOfList(str))
throw badTerm("not a path", *i); res.insert(arePaths ? parsePath(str) : parseString(str));
string s = aterm2String(*i); return res;
if (arePaths) checkPath(s);
out.insert(s);
}
} }
Derivation parseDerivation(const string & 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; Derivation drv;
ATermList outs, inDrvs, inSrcs, args, bnds; std::istringstream str(s);
ATerm builder, platform; expect(str, "Derive([");
if (!matchDerive(t, outs, inDrvs, inSrcs, platform, builder, args, bnds)) /* Parse the list of outputs. */
throwBadDrv(t); while (!endOfList(str)) {
for (ATermIterator i(outs); i; ++i) {
ATerm id, path, hashAlgo, hash;
if (!matchDerivationOutput(*i, id, path, hashAlgo, hash))
throwBadDrv(t);
DerivationOutput out; DerivationOutput out;
out.path = aterm2String(path); expect(str, "("); string id = parseString(str);
checkPath(out.path); expect(str, ","); out.path = parsePath(str);
out.hashAlgo = aterm2String(hashAlgo); expect(str, ","); out.hashAlgo = parseString(str);
out.hash = aterm2String(hash); expect(str, ","); out.hash = parseString(str);
drv.outputs[aterm2String(id)] = out; expect(str, ")");
drv.outputs[id] = out;
} }
for (ATermIterator i(inDrvs); i; ++i) { /* Parse the list of input derivations. */
ATerm drvPath; expect(str, ",[");
ATermList ids; while (!endOfList(str)) {
if (!matchDerivationInput(*i, drvPath, ids)) expect(str, "(");
throwBadDrv(t); Path drvPath = parsePath(str);
Path drvPath2 = aterm2String(drvPath); expect(str, ",[");
checkPath(drvPath2); drv.inputDrvs[drvPath] = parseStrings(str, false);
StringSet ids2; expect(str, ")");
parseStrings(ids, ids2, false); }
drv.inputDrvs[drvPath2] = ids2;
expect(str, ",["); drv.inputSrcs = parseStrings(str, true);
expect(str, ","); drv.platform = parseString(str);
expect(str, ","); drv.builder = parseString(str);
/* Parse the builder arguments. */
expect(str, ",[");
while (!endOfList(str))
drv.args.push_back(parseString(str));
/* Parse the environment variables. */
expect(str, ",[");
while (!endOfList(str)) {
expect(str, "("); string name = parseString(str);
expect(str, ","); string value = parseString(str);
expect(str, ")");
drv.env[name] = value;
} }
parseStrings(inSrcs, drv.inputSrcs, true); expect(str, ")");
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; return drv;
} }
ATerm unparseDerivation(const Derivation & drv) void printString(std::ostream & str, const string & s)
{ {
ATermList outputs = ATempty; str << "\"";
for (DerivationOutputs::const_reverse_iterator i = drv.outputs.rbegin(); for (const char * i = s.c_str(); *i; i++)
i != drv.outputs.rend(); ++i) if (*i == '\"' || *i == '\\') str << "\\" << *i;
outputs = ATinsert(outputs, else if (*i == '\n') str << "\\n";
makeDerivationOutput( else if (*i == '\r') str << "\\r";
toATerm(i->first), else if (*i == '\t') str << "\\t";
toATerm(i->second.path), else str << *i;
toATerm(i->second.hashAlgo), str << "\"";
toATerm(i->second.hash))); }
ATermList inDrvs = ATempty;
for (DerivationInputs::const_reverse_iterator i = drv.inputDrvs.rbegin(); template<class ForwardIterator>
i != drv.inputDrvs.rend(); ++i) void printStrings(std::ostream & str, ForwardIterator i, ForwardIterator j)
inDrvs = ATinsert(inDrvs, {
makeDerivationInput( str << "[";
toATerm(i->first), bool first = true;
toATermList(i->second))); for ( ; i != j; ++i) {
if (first) first = false; else str << ",";
printString(str, *i);
}
str << "]";
}
string unparseDerivation(const Derivation & drv)
{
std::ostringstream str;
str << "Derive([";
bool first = true;
foreach (DerivationOutputs::const_iterator, i, drv.outputs) {
if (first) first = false; else str << ",";
str << "("; printString(str, i->first);
str << ","; printString(str, i->second.path);
str << ","; printString(str, i->second.hashAlgo);
str << ","; printString(str, i->second.hash);
str << ")";
}
str << "],[";
first = true;
foreach (DerivationInputs::const_iterator, i, drv.inputDrvs) {
if (first) first = false; else str << ",";
str << "("; printString(str, i->first);
str << ","; printStrings(str, i->second.begin(), i->second.end());
str << ")";
}
str << "],";
printStrings(str, drv.inputSrcs.begin(), drv.inputSrcs.end());
ATermList args = ATempty; str << ","; printString(str, drv.platform);
for (Strings::const_reverse_iterator i = drv.args.rbegin(); str << ","; printString(str, drv.builder);
i != drv.args.rend(); ++i) str << ","; printStrings(str, drv.args.begin(), drv.args.end());
args = ATinsert(args, toATerm(*i));
ATermList env = ATempty; str << ",[";
for (StringPairs::const_reverse_iterator i = drv.env.rbegin(); first = true;
i != drv.env.rend(); ++i) foreach (StringPairs::const_iterator, i, drv.env) {
env = ATinsert(env, if (first) first = false; else str << ",";
makeEnvBinding( str << "("; printString(str, i->first);
toATerm(i->first), str << ","; printString(str, i->second);
toATerm(i->second))); str << ")";
}
return makeDerive(
outputs, str << "])";
inDrvs,
toATermList(drv.inputSrcs), return str.str();
toATerm(drv.platform),
toATerm(drv.builder),
args,
env);
} }

View file

@ -1,8 +1,6 @@
#ifndef __DERIVATIONS_H #ifndef __DERIVATIONS_H
#define __DERIVATIONS_H #define __DERIVATIONS_H
#include <aterm1.h>
#include "hash.hh" #include "hash.hh"
#include <map> #include <map>
@ -53,17 +51,14 @@ struct Derivation
}; };
/* Hash an aterm. */
Hash hashTerm(ATerm t);
/* Write a derivation to the Nix store, and return its path. */ /* Write a derivation to the Nix store, and return its path. */
Path writeDerivation(const Derivation & drv, const string & name); Path writeDerivation(const Derivation & drv, const string & name);
/* Parse a derivation. */ /* Parse a derivation. */
Derivation parseDerivation(ATerm t); Derivation parseDerivation(const string & s);
/* Parse a derivation. */ /* Print a derivation. */
ATerm unparseDerivation(const Derivation & drv); string unparseDerivation(const Derivation & drv);
/* Check whether a file name ends with the extensions for /* Check whether a file name ends with the extensions for
derivations. */ derivations. */

View file

@ -3,8 +3,6 @@
#include "globals.hh" #include "globals.hh"
#include "archive.hh" #include "archive.hh"
#include "pathlocks.hh" #include "pathlocks.hh"
#include "aterm.hh"
#include "derivations-ast.hh"
#include "worker-protocol.hh" #include "worker-protocol.hh"
#include <iostream> #include <iostream>

View file

@ -2,8 +2,6 @@
#include "store-api.hh" #include "store-api.hh"
#include "local-store.hh" #include "local-store.hh"
#include <aterm2.h>
namespace nix { namespace nix {
@ -12,9 +10,7 @@ Derivation derivationFromPath(const Path & drvPath)
{ {
assertStorePath(drvPath); assertStorePath(drvPath);
store->ensurePath(drvPath); store->ensurePath(drvPath);
ATerm t = ATreadFromNamedFile(drvPath.c_str()); return parseDerivation(readFile(drvPath));
if (!t) throw Error(format("cannot read aterm from `%1%'") % drvPath);
return parseDerivation(t);
} }

View file

@ -1,16 +1,16 @@
pkglib_LTLIBRARIES = libutil.la pkglib_LTLIBRARIES = libutil.la
libutil_la_SOURCES = util.cc hash.cc serialise.cc \ libutil_la_SOURCES = util.cc hash.cc serialise.cc \
archive.cc aterm.cc xml-writer.cc archive.cc xml-writer.cc
libutil_la_LIBADD = ../boost/format/libformat.la libutil_la_LIBADD = ../boost/format/libformat.la
pkginclude_HEADERS = util.hh hash.hh serialise.hh \ pkginclude_HEADERS = util.hh hash.hh serialise.hh \
archive.hh aterm.hh xml-writer.hh types.hh archive.hh xml-writer.hh types.hh
if !HAVE_OPENSSL if !HAVE_OPENSSL
libutil_la_SOURCES += \ libutil_la_SOURCES += \
md5.c md5.h sha1.c sha1.h sha256.c sha256.h md32_common.h md5.c md5.h sha1.c sha1.h sha256.c sha256.h md32_common.h
endif endif
AM_CXXFLAGS = -Wall -I$(srcdir)/.. ${aterm_include} AM_CXXFLAGS = -Wall -I$(srcdir)/..

View file

@ -1,55 +0,0 @@
#include "aterm.hh"
#include <cstring>
using std::string;
string nix::atPrint(ATerm t)
{
if (!t) throw Error("attempt to print null aterm");
char * s = ATwriteToString(t);
if (!s) throw Error("cannot print term");
return s;
}
std::ostream & operator << (std::ostream & stream, ATerm e)
{
return stream << nix::atPrint(e);
}
nix::Error nix::badTerm(const format & f, ATerm t)
{
char * s = ATwriteToString(t);
if (!s) throw Error("cannot print term");
if (strlen(s) > 1000) {
int len;
s = ATwriteToSharedString(t, &len);
if (!s) throw Error("cannot print term");
}
return Error(format("%1%, in `%2%'") % f.str() % (string) s);
}
ATerm nix::toATerm(const char * s)
{
return (ATerm) ATmakeAppl0(ATmakeAFun((char *) s, 0, ATtrue));
}
ATerm nix::toATerm(const string & s)
{
return toATerm(s.c_str());
}
ATermList nix::toATermList(const StringSet & ss)
{
ATermList l = ATempty;
for (StringSet::const_reverse_iterator i = ss.rbegin();
i != ss.rend(); ++i)
l = ATinsert(l, toATerm(*i));
return l;
}

View file

@ -1,55 +0,0 @@
#ifndef __ATERM_H
#define __ATERM_H
#include <aterm2.h>
#include "types.hh"
namespace nix {
/* Print an ATerm. */
string atPrint(ATerm t);
class ATermIterator
{
ATermList t;
public:
ATermIterator(ATermList _t) : t(_t) { }
ATermIterator & operator ++ ()
{
t = ATgetNext(t);
return *this;
}
ATerm operator * ()
{
return ATgetFirst(t);
}
operator bool ()
{
return t != ATempty;
}
};
/* Throw an exception with an error message containing the given
aterm. */
Error badTerm(const format & f, ATerm t);
/* Convert strings to ATerms. */
ATerm toATerm(const char * s);
ATerm toATerm(const string & s);
ATermList toATermList(const StringSet & ss);
}
/* Write an ATerm to an output stream. */
std::ostream & operator << (std::ostream & stream, ATerm e);
#endif /* !__ATERM_H */

View file

@ -1006,6 +1006,47 @@ bool hasSuffix(const string & s, const string & suffix)
} }
void expect(std::istream & str, const string & s)
{
char s2[s.size()];
str.read(s2, s.size());
if (string(s2, s.size()) != s)
throw Error(format("expected string `%1%'") % s);
}
string parseString(std::istream & str)
{
string res;
expect(str, "\"");
int c;
while ((c = str.get()) != '"')
if (c == '\\') {
c = str.get();
if (c == 'n') res += '\n';
else if (c == 'r') res += '\r';
else if (c == 't') res += '\t';
else res += c;
}
else res += c;
return res;
}
bool endOfList(std::istream & str)
{
if (str.peek() == ',') {
str.get();
return false;
}
if (str.peek() == ']') {
str.get();
return true;
}
return false;
}
void ignoreException() void ignoreException()
{ {
try { try {

View file

@ -302,34 +302,23 @@ string int2String(int n);
bool hasSuffix(const string & s, const string & suffix); bool hasSuffix(const string & s, const string & suffix);
/* Read string `s' from stream `str'. */
void expect(std::istream & str, const string & s);
/* Read a C-style string from stream `str'. */
string parseString(std::istream & str);
/* Utility function used to parse legacy ATerms. */
bool endOfList(std::istream & str);
/* Exception handling in destructors: print an error message, then /* Exception handling in destructors: print an error message, then
ignore the exception. */ ignore the exception. */
void ignoreException(); void ignoreException();
/* STL functions such as sort() pass a binary function object around
by value, so it gets cloned a lot. This is bad if the function
object has state or is simply large. This adapter wraps the
function object to simulate passing by reference. */
template<class F>
struct binary_function_ref_adapter
{
F * p;
binary_function_ref_adapter(F * _p)
{
p = _p;
}
typename F::result_type operator () (
const typename F::first_argument_type & x,
const typename F::second_argument_type & y)
{
return (*p)(x, y);
}
};
} }

View file

@ -25,33 +25,6 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
/* Code for parsing manifests in the old textual ATerm format. */ /* Code for parsing manifests in the old textual ATerm format. */
static void expect(std::istream & str, const string & s)
{
char s2[s.size()];
str.read(s2, s.size());
if (string(s2, s.size()) != s)
throw Error(format("expected string `%1%'") % s);
}
static string parseString(std::istream & str)
{
string res;
expect(str, "\"");
int c;
while ((c = str.get()) != '"')
if (c == '\\') {
c = str.get();
if (c == 'n') res += '\n';
else if (c == 'r') res += '\r';
else if (c == 't') res += '\t';
else res += c;
}
else res += c;
return res;
}
static string parseStr(std::istream & str) static string parseStr(std::istream & str)
{ {
expect(str, "Str("); expect(str, "Str(");
@ -70,20 +43,6 @@ static string parseWord(std::istream & str)
} }
static bool endOfList(std::istream & str)
{
if (str.peek() == ',') {
str.get();
return false;
}
if (str.peek() == ']') {
str.get();
return true;
}
return false;
}
static MetaInfo parseMeta(std::istream & str) static MetaInfo parseMeta(std::istream & str)
{ {
MetaInfo meta; MetaInfo meta;