#include "fstate.hh" #include "globals.hh" #include "store.hh" string printTerm(ATerm t) { char * s = ATwriteToString(t); return s; } Error badTerm(const format & f, ATerm t) { return Error(format("%1%, in `%2%'") % f.str() % printTerm(t)); } Hash hashTerm(ATerm t) { return hashString(printTerm(t)); } ATerm termFromId(const FSId & id) { string path = expandId(id); ATerm t = ATreadFromNamedFile(path.c_str()); if (!t) throw Error(format("cannot read aterm from `%1%'") % path); return t; } FSId writeTerm(ATerm t, const string & suffix, FSId id) { /* By default, the id of a term is its hash. */ if (id == FSId()) id = hashTerm(t); string path = canonPath(nixStore + "/" + (string) id + suffix + ".nix"); if (!ATwriteToNamedTextFile(t, path.c_str())) throw Error(format("cannot write aterm %1%") % path); // debug(format("written term %1% = %2%") % (string) id % // printTerm(t)); Transaction txn(nixDB); registerPath(txn, path, id); txn.commit(); return id; } static void parsePaths(ATermList paths, Strings & out) { while (!ATisEmpty(paths)) { char * s; ATerm t = ATgetFirst(paths); if (!ATmatch(t, "<str>", &s)) throw badTerm("not a path", t); out.push_back(s); paths = ATgetNext(paths); } } static void checkSlice(const Slice & slice) { if (slice.elems.size() == 0) throw Error("empty slice"); StringSet decl; for (SliceElems::const_iterator i = slice.elems.begin(); i != slice.elems.end(); i++) decl.insert(i->path); for (Strings::const_iterator i = slice.roots.begin(); i != slice.roots.end(); i++) if (decl.find(*i) == decl.end()) throw Error(format("undefined root path `%1%'") % *i); for (SliceElems::const_iterator i = slice.elems.begin(); i != slice.elems.end(); i++) for (Strings::const_iterator j = i->refs.begin(); j != i->refs.end(); j++) if (decl.find(*j) == decl.end()) throw Error( format("undefined path `%1%' referenced by `%2%'") % *j % i->path); } /* Parse a slice. */ static bool parseSlice(ATerm t, Slice & slice) { ATermList roots, elems; if (!ATmatch(t, "Slice([<list>], [<list>])", &roots, &elems)) return false; parsePaths(roots, slice.roots); while (!ATisEmpty(elems)) { char * s1, * s2; ATermList refs; ATerm t = ATgetFirst(elems); if (!ATmatch(t, "(<str>, <str>, [<list>])", &s1, &s2, &refs)) throw badTerm("not a slice element", t); SliceElem elem; elem.path = s1; elem.id = parseHash(s2); parsePaths(refs, elem.refs); slice.elems.push_back(elem); elems = ATgetNext(elems); } checkSlice(slice); return true; } static bool parseDerive(ATerm t, Derive & derive) { ATermList outs, ins, args, bnds; char * builder; char * platform; if (!ATmatch(t, "Derive([<list>], [<list>], <str>, <str>, [<list>], [<list>])", &outs, &ins, &platform, &builder, &args, &bnds)) { /* !!! compatibility -> remove eventually */ if (!ATmatch(t, "Derive([<list>], [<list>], <str>, <str>, [<list>])", &outs, &ins, &builder, &platform, &bnds)) return false; args = ATempty; } while (!ATisEmpty(outs)) { char * s1, * s2; ATerm t = ATgetFirst(outs); if (!ATmatch(t, "(<str>, <str>)", &s1, &s2)) throw badTerm("not a derive output", t); derive.outputs.push_back(DeriveOutput(s1, parseHash(s2))); outs = ATgetNext(outs); } while (!ATisEmpty(ins)) { char * s; ATerm t = ATgetFirst(ins); if (!ATmatch(t, "<str>", &s)) throw badTerm("not an id", t); derive.inputs.push_back(parseHash(s)); ins = ATgetNext(ins); } derive.builder = builder; derive.platform = platform; while (!ATisEmpty(args)) { char * s; ATerm arg = ATgetFirst(args); if (!ATmatch(arg, "<str>", &s)) throw badTerm("string expected", arg); derive.args.push_back(s); args = ATgetNext(args); } while (!ATisEmpty(bnds)) { char * s1, * s2; ATerm bnd = ATgetFirst(bnds); if (!ATmatch(bnd, "(<str>, <str>)", &s1, &s2)) throw badTerm("tuple of strings expected", bnd); derive.env.push_back(StringPair(s1, s2)); bnds = ATgetNext(bnds); } return true; } FState parseFState(ATerm t) { FState fs; if (parseSlice(t, fs.slice)) fs.type = FState::fsSlice; else if (parseDerive(t, fs.derive)) fs.type = FState::fsDerive; else throw badTerm("not an fstate-expression", t); return fs; } static ATermList unparsePaths(const Strings & paths) { ATermList l = ATempty; for (Strings::const_iterator i = paths.begin(); i != paths.end(); i++) l = ATinsert(l, ATmake("<str>", i->c_str())); return ATreverse(l); } static ATerm unparseSlice(const Slice & slice) { ATermList roots = unparsePaths(slice.roots); ATermList elems = ATempty; for (SliceElems::const_iterator i = slice.elems.begin(); i != slice.elems.end(); i++) elems = ATinsert(elems, ATmake("(<str>, <str>, <term>)", i->path.c_str(), ((string) i->id).c_str(), unparsePaths(i->refs))); return ATmake("Slice(<term>, <term>)", roots, elems); } static ATerm unparseDerive(const Derive & derive) { ATermList outs = ATempty; for (DeriveOutputs::const_iterator i = derive.outputs.begin(); i != derive.outputs.end(); i++) outs = ATinsert(outs, ATmake("(<str>, <str>)", i->first.c_str(), ((string) i->second).c_str())); ATermList ins = ATempty; for (FSIds::const_iterator i = derive.inputs.begin(); i != derive.inputs.end(); i++) ins = ATinsert(ins, ATmake("<str>", ((string) *i).c_str())); ATermList args = ATempty; for (Strings::const_iterator i = derive.args.begin(); i != derive.args.end(); i++) args = ATinsert(args, ATmake("<str>", i->c_str())); ATermList env = ATempty; for (StringPairs::const_iterator i = derive.env.begin(); i != derive.env.end(); i++) env = ATinsert(env, ATmake("(<str>, <str>)", i->first.c_str(), i->second.c_str())); return ATmake("Derive(<term>, <term>, <str>, <str>, <term>, <term>)", ATreverse(outs), ATreverse(ins), derive.platform.c_str(), derive.builder.c_str(), ATreverse(args), ATreverse(env)); } ATerm unparseFState(const FState & fs) { if (fs.type == FState::fsSlice) return unparseSlice(fs.slice); else if (fs.type == FState::fsDerive) return unparseDerive(fs.derive); else abort(); }