aboutsummaryrefslogtreecommitdiff
path: root/src/normalise.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/normalise.cc')
-rw-r--r--src/normalise.cc265
1 files changed, 265 insertions, 0 deletions
diff --git a/src/normalise.cc b/src/normalise.cc
new file mode 100644
index 000000000..bdeddf08d
--- /dev/null
+++ b/src/normalise.cc
@@ -0,0 +1,265 @@
+#include <map>
+
+#include "normalise.hh"
+#include "references.hh"
+#include "db.hh"
+#include "exec.hh"
+#include "globals.hh"
+
+
+void registerSuccessor(const FSId & id1, const FSId & id2)
+{
+ setDB(nixDB, dbSuccessors, id1, id2);
+}
+
+
+static FSId storeSuccessor(const FSId & id1, ATerm sc)
+{
+ FSId id2 = writeTerm(sc, "-s-" + (string) id1);
+ registerSuccessor(id1, id2);
+ return id2;
+}
+
+
+typedef set<FSId> FSIdSet;
+
+
+Slice normaliseFState(FSId id)
+{
+ debug(format("normalising fstate %1%") % (string) id);
+ 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 = parseFState(termFromId(id));
+
+ /* It this is a normal form (i.e., a slice) we are done. */
+ if (fs.type == FState::fsSlice) return fs.slice;
+
+ /* Otherwise, it's a derivation. */
+
+ /* Right platform? */
+ if (fs.derive.platform != thisSystem)
+ throw Error(format("a `%1%' is required, but I am a `%2%'")
+ % fs.derive.platform % thisSystem);
+
+ /* Realise inputs (and remember all input paths). */
+ typedef map<string, SliceElem> ElemMap;
+
+ ElemMap inMap;
+
+ for (FSIds::iterator i = fs.derive.inputs.begin();
+ i != fs.derive.inputs.end(); i++) {
+ Slice slice = normaliseFState(*i);
+ realiseSlice(slice);
+
+ for (SliceElems::iterator j = slice.elems.begin();
+ j != slice.elems.end(); j++)
+ inMap[j->path] = *j;
+ }
+
+ Strings inPaths;
+ for (ElemMap::iterator i = inMap.begin(); i != inMap.end(); i++)
+ inPaths.push_back(i->second.path);
+
+ /* Build the environment. */
+ Environment env;
+ for (StringPairs::iterator i = fs.derive.env.begin();
+ i != fs.derive.env.end(); i++)
+ env[i->first] = i->second;
+
+ /* Parse the outputs. */
+ typedef map<string, FSId> OutPaths;
+ OutPaths outPaths;
+ for (DeriveOutputs::iterator i = fs.derive.outputs.begin();
+ i != fs.derive.outputs.end(); i++)
+ {
+ debug(format("building %1% in %2%") % (string) i->second % i->first);
+ outPaths[i->first] = i->second;
+ inPaths.push_back(i->first);
+ }
+
+ /* We can skip running the builder if we can expand all output
+ paths from their ids. */
+ bool fastBuild = false;
+#if 0
+ for (OutPaths::iterator i = outPaths.begin();
+ i != outPaths.end(); i++)
+ {
+ try {
+ expandId(i->second, i->first);
+ } catch (...) {
+ fastBuild = false;
+ break;
+ }
+ }
+#endif
+
+ if (!fastBuild) {
+
+ /* Check that none of the outputs exist. */
+ for (OutPaths::iterator i = outPaths.begin();
+ i != outPaths.end(); i++)
+ if (pathExists(i->first))
+ throw Error(format("path `%1%' exists") % i->first);
+
+ /* Run the builder. */
+ debug(format("building..."));
+ runProgram(fs.derive.builder, env);
+ debug(format("build completed"));
+
+ } else
+ debug(format("skipping build"));
+
+ /* Check whether the output paths were created, and register each
+ one. */
+ FSIdSet used;
+ for (OutPaths::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);
+ fs.slice.roots.push_back(i->second);
+
+ Strings refs = filterReferences(path, inPaths);
+
+ SliceElem elem;
+ elem.path = path;
+ elem.id = i->second;
+
+ for (Strings::iterator j = refs.begin(); j != refs.end(); j++) {
+ ElemMap::iterator k;
+ OutPaths::iterator l;
+ if ((k = inMap.find(*j)) != inMap.end()) {
+ elem.refs.push_back(k->second.id);
+ used.insert(k->second.id);
+ for (FSIds::iterator m = k->second.refs.begin();
+ m != k->second.refs.end(); m++)
+ used.insert(*m);
+ } else if ((l = outPaths.find(*j)) != outPaths.end()) {
+ elem.refs.push_back(l->second);
+ used.insert(l->second);
+ } else
+ throw Error(format("unknown referenced path `%1%'") % *j);
+ }
+
+ fs.slice.elems.push_back(elem);
+ }
+
+ for (ElemMap::iterator i = inMap.begin();
+ i != inMap.end(); i++)
+ {
+ FSIdSet::iterator j = used.find(i->second.id);
+ if (j == used.end())
+ debug(format("NOT referenced: `%1%'") % i->second.path);
+ else {
+ debug(format("referenced: `%1%'") % i->second.path);
+ fs.slice.elems.push_back(i->second);
+ }
+ }
+
+ fs.type = FState::fsSlice;
+ ATerm nf = unparseFState(fs);
+ debug(format("normal form: %1%") % printTerm(nf));
+ storeSuccessor(id, nf);
+
+ return fs.slice;
+}
+
+
+void realiseSlice(const Slice & slice)
+{
+ debug(format("realising slice"));
+ Nest nest(true);
+
+ /* Perhaps all paths already contain the right id? */
+
+ bool missing = false;
+ for (SliceElems::const_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::const_iterator i = slice.elems.begin();
+ i != slice.elems.end(); i++)
+ {
+ SliceElem elem = *i;
+ debug(format("expanding %1% in %2%") % (string) elem.id % elem.path);
+ expandId(elem.id, elem.path);
+ }
+}
+
+
+Strings fstatePaths(const FSId & id, bool normalise)
+{
+ Strings paths;
+
+ FState fs;
+
+ if (normalise) {
+ fs.slice = normaliseFState(id);
+ fs.type = FState::fsSlice;
+ } else
+ fs = parseFState(termFromId(id));
+
+ if (fs.type == FState::fsSlice) {
+ /* !!! fix complexity */
+ for (FSIds::const_iterator i = fs.slice.roots.begin();
+ i != fs.slice.roots.end(); i++)
+ for (SliceElems::const_iterator j = fs.slice.elems.begin();
+ j != fs.slice.elems.end(); j++)
+ if (*i == j->id) paths.push_back(j->path);
+ }
+
+ else if (fs.type == FState::fsDerive) {
+ for (DeriveOutputs::iterator i = fs.derive.outputs.begin();
+ i != fs.derive.outputs.end(); i++)
+ paths.push_back(i->first);
+ }
+
+ else abort();
+
+ return paths;
+}
+
+
+StringSet fstateRefs(const FSId & id)
+{
+ StringSet paths;
+ Slice slice = normaliseFState(id);
+ for (SliceElems::const_iterator i = slice.elems.begin();
+ i != slice.elems.end(); i++)
+ paths.insert(i->path);
+ return paths;
+}
+
+
+void findGenerators(const FSIds & ids)
+{
+
+}