From f5b6fa5256efce5f7a963386cd16e441446f5746 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 15 Jul 2003 16:28:54 +0000 Subject: * Basic work on allowing derive expressions to build multiple paths. This is not entirely trivial since this introduces the possibility of mutual recursion. * Made normal forms self-contained. * Use unique ids, not content hashes, for content referencing. --- src/fstate.cc | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 210 insertions(+), 28 deletions(-) (limited to 'src/fstate.cc') diff --git a/src/fstate.cc b/src/fstate.cc index 36f7482acf9d..596d63a5f406 100644 --- a/src/fstate.cc +++ b/src/fstate.cc @@ -154,55 +154,47 @@ FState hash2fstate(Hash hash) } -ATerm termFromHash(const Hash & hash, string * p) +ATerm termFromId(const FSId & id, string * p) { - string path = expandHash(hash); + string path = expandId(id); if (p) *p = path; ATerm t = ATreadFromNamedFile(path.c_str()); - if (!t) throw Error(format("cannot read aterm %1%") % path); + if (!t) throw Error(format("cannot read aterm from `%1%'") % path); return t; } -Hash writeTerm(ATerm t, const string & suffix, string * p) +FSId writeTerm(ATerm t, const string & suffix, string * p) { - string path = nixStore + "/tmp.nix"; /* !!! */ + 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); - Hash hash = hashPath(path); - string path2 = canonPath(nixStore + "/" + - (string) hash + suffix + ".nix"); - if (rename(path.c_str(), path2.c_str()) == -1) - throw SysError(format("renaming %1% to %2%") % path % path2); - registerPath(path2, hash); - if (p) *p = path2; - return hash; + + registerPath(path, id); + if (p) *p = path; + + return id; } -void registerSuccessor(const Hash & fsHash, const Hash & scHash) +void registerSuccessor(const FSId & id1, const FSId & id2) { - setDB(nixDB, dbSuccessors, fsHash, scHash); + setDB(nixDB, dbSuccessors, id1, id2); } -FState storeSuccessor(FState fs, FState sc, StringSet & paths) +static FSId storeSuccessor(const FSId & id1, FState sc) { - if (fs == sc) return sc; - - string path; - Hash fsHash = hashTerm(fs); - Hash scHash = writeTerm(sc, "-s-" + (string) fsHash, &path); - registerSuccessor(fsHash, scHash); - paths.insert(path); - -#if 0 - return ATmake("Include()", ((string) scHash).c_str()); -#endif - return sc; + FSId id2 = writeTerm(sc, "-s-" + (string) id1, 0); + registerSuccessor(id1, id2); + return id2; } +#if 0 static FState realise(FState fs, StringSet & paths) { char * s1, * s2, * s3; @@ -421,3 +413,193 @@ void fstateRefs(FState fs, StringSet & paths) { fstateRefs2(fs, paths); } +#endif + + +static void parseIds(ATermList ids, FSIds & out) +{ + while (!ATisEmpty(ids)) { + char * s; + ATerm id = ATgetFirst(ids); + if (!ATmatch(id, "", &s)) + throw badTerm("not an id", id); + out.push_back(parseHash(s)); + debug(s); + ids = ATgetNext(ids); + } +} + + +/* Parse a slice. */ +static Slice parseSlice(FState fs) +{ + Slice slice; + ATermList roots, elems; + + if (!ATmatch(fs, "Slice([], [])", &roots, &elems)) + throw badTerm("not a slice", fs); + + parseIds(roots, slice.roots); + + while (!ATisEmpty(elems)) { + char * s1, * s2; + ATermList refs; + ATerm t = ATgetFirst(elems); + if (!ATmatch(t, "(, , [])", &s1, &s2, &refs)) + throw badTerm("not a slice element", t); + SliceElem elem; + elem.path = s1; + elem.id = parseHash(s2); + parseIds(refs, elem.refs); + slice.elems.push_back(elem); + elems = ATgetNext(elems); + } + + return slice; +} + + +Slice normaliseFState(FSId id) +{ + debug(format("normalising fstate")); + Nest nest(true); + + /* Try to substitute $id$ by any known successors in order to + speed up the rewrite process. */ + string idSucc; + while (queryDB(nixDB, dbSuccessors, id, idSucc)) { + debug(format("successor %1% -> %2%") % (string) id % idSucc); + id = parseHash(idSucc); + } + + /* Get the fstate expression. */ + FState fs = termFromId(id); + + /* Already in normal form (i.e., a slice)? */ + if (ATgetType(fs) == AT_APPL && + (string) ATgetName(ATgetAFun(fs)) == "Slice") + return parseSlice(fs); + + /* Then we it's a Derive node. */ + ATermList outs, ins, bnds; + char * builder; + char * platform; + if (!ATmatch(fs, "Derive([], [], , , [])", + &outs, &ins, &builder, &platform, &bnds)) + throw badTerm("not a derive", fs); + + /* Right platform? */ + checkPlatform(platform); + + /* Realise inputs (and remember all input paths). */ + FSIds inIds; + parseIds(ins, inIds); + + SliceElems inElems; /* !!! duplicates */ + StringSet inPathsSet; + for (FSIds::iterator i = inIds.begin(); i != inIds.end(); i++) { + Slice slice = normaliseFState(*i); + realiseSlice(slice); + + for (SliceElems::iterator j = slice.elems.begin(); + j != slice.elems.end(); j++) + { + inElems.push_back(*j); + inPathsSet.insert(j->path); + } + } + + Strings inPaths; + copy(inPathsSet.begin(), inPathsSet.end(), + inserter(inPaths, inPaths.begin())); + + /* Build the environment. */ + Environment env; + while (!ATisEmpty(bnds)) { + char * s1, * s2; + ATerm bnd = ATgetFirst(bnds); + if (!ATmatch(bnd, "(, )", &s1, &s2)) + throw badTerm("tuple of strings expected", bnd); + env[s1] = s2; + bnds = ATgetNext(bnds); + } + + /* Check that none of the output paths exist. */ + typedef pair OutPath; + list outPaths; + while (!ATisEmpty(outs)) { + ATerm t = ATgetFirst(outs); + char * s1, * s2; + if (!ATmatch(t, "(, )", &s1, &s2)) + throw badTerm("string expected", t); + outPaths.push_back(OutPath(s1, parseHash(s2))); + outs = ATgetNext(outs); + } + + for (list::iterator i = outPaths.begin(); + i != outPaths.end(); i++) + if (pathExists(i->first)) + throw Error(format("path `%1%' exists") % i->first); + + /* Run the builder. */ + runProgram(builder, env); + + Slice slice; + + /* Check whether the output paths were created, and register each + one. */ + for (list::iterator i = outPaths.begin(); + i != outPaths.end(); i++) + { + string path = i->first; + if (!pathExists(path)) + throw Error(format("path `%1%' does not exist") % path); + registerPath(path, i->second); + slice.roots.push_back(i->second); + + Strings outPaths = filterReferences(path, inPaths); + } + + return slice; +} + + +void realiseSlice(Slice slice) +{ + debug(format("realising slice")); + Nest nest(true); + + if (slice.elems.size() == 0) + throw Error("empty slice"); + + /* Perhaps all paths already contain the right id? */ + + bool missing = false; + for (SliceElems::iterator i = slice.elems.begin(); + i != slice.elems.end(); i++) + { + SliceElem elem = *i; + string id; + if (!queryDB(nixDB, dbPath2Id, elem.path, id)) { + if (pathExists(elem.path)) + throw Error(format("path `%1%' obstructed") % elem.path); + missing = true; + break; + } + if (parseHash(id) != elem.id) + throw Error(format("path `%1%' obstructed") % elem.path); + } + + if (!missing) { + debug(format("already installed")); + return; + } + + /* For each element, expand its id at its path. */ + for (SliceElems::iterator i = slice.elems.begin(); + i != slice.elems.end(); i++) + { + SliceElem elem = *i; + expandId(elem.id, elem.path); + } +} -- cgit 1.4.1