diff --git a/src/fstate.cc b/src/fstate.cc index 596d63a5f4..aad961ef58 100644 --- a/src/fstate.cc +++ b/src/fstate.cc @@ -459,6 +459,37 @@ static Slice parseSlice(FState fs) } +static ATermList unparseIds(const FSIds & ids) +{ + ATermList l = ATempty; + for (FSIds::const_iterator i = ids.begin(); + i != ids.end(); i++) + l = ATinsert(l, + ATmake("", ((string) *i).c_str())); + return ATreverse(l); +} + + +static FState unparseSlice(const Slice & slice) +{ + ATermList roots = unparseIds(slice.roots); + + ATermList elems = ATempty; + for (SliceElems::const_iterator i = slice.elems.begin(); + i != slice.elems.end(); i++) + elems = ATinsert(elems, + ATmake("(, , )", + i->path.c_str(), + ((string) i->id).c_str(), + unparseIds(i->refs))); + + return ATmake("Slice(, )", roots, elems); +} + + +typedef set FSIdSet; + + Slice normaliseFState(FSId id) { debug(format("normalising fstate")); @@ -494,24 +525,23 @@ Slice normaliseFState(FSId id) /* Realise inputs (and remember all input paths). */ FSIds inIds; parseIds(ins, inIds); - - SliceElems inElems; /* !!! duplicates */ - StringSet inPathsSet; + + typedef map ElemMap; + + ElemMap inMap; + 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); - } + inMap[j->path] = *j; } Strings inPaths; - copy(inPathsSet.begin(), inPathsSet.end(), - inserter(inPaths, inPaths.begin())); + for (ElemMap::iterator i = inMap.begin(); i != inMap.end(); i++) + inPaths.push_back(i->second.path); /* Build the environment. */ Environment env; @@ -533,6 +563,7 @@ Slice normaliseFState(FSId id) if (!ATmatch(t, "(, )", &s1, &s2)) throw badTerm("string expected", t); outPaths.push_back(OutPath(s1, parseHash(s2))); + inPaths.push_back(s1); outs = ATgetNext(outs); } @@ -548,6 +579,7 @@ Slice normaliseFState(FSId id) /* Check whether the output paths were created, and register each one. */ + FSIdSet used; for (list::iterator i = outPaths.begin(); i != outPaths.end(); i++) { @@ -557,25 +589,81 @@ Slice normaliseFState(FSId id) registerPath(path, i->second); slice.roots.push_back(i->second); - Strings outPaths = filterReferences(path, inPaths); + 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; + if ((k = inMap.find(*j)) != inMap.end()) { + elem.refs.push_back(k->second.id); + used.insert(k->second.id); + } else abort(); /* fix! check in created paths */ + } + + 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); + slice.elems.push_back(i->second); + } + } + + FState nf = unparseSlice(slice); + debug(printTerm(nf)); + storeSuccessor(id, nf); + return slice; } -void realiseSlice(Slice slice) +static void checkSlice(const Slice & slice) +{ + if (slice.elems.size() == 0) + throw Error("empty slice"); + + FSIdSet decl; + for (SliceElems::const_iterator i = slice.elems.begin(); + i != slice.elems.end(); i++) + { + debug((string) i->id); + decl.insert(i->id); + } + + for (FSIds::const_iterator i = slice.roots.begin(); + i != slice.roots.end(); i++) + if (decl.find(*i) == decl.end()) + throw Error(format("undefined id: %1%") % (string) *i); + + for (SliceElems::const_iterator i = slice.elems.begin(); + i != slice.elems.end(); i++) + for (FSIds::const_iterator j = i->refs.begin(); + j != i->refs.end(); j++) + if (decl.find(*j) == decl.end()) + throw Error(format("undefined id: %1%") % (string) *j); +} + + +void realiseSlice(const Slice & slice) { debug(format("realising slice")); Nest nest(true); - if (slice.elems.size() == 0) - throw Error("empty slice"); + checkSlice(slice); /* Perhaps all paths already contain the right id? */ bool missing = false; - for (SliceElems::iterator i = slice.elems.begin(); + for (SliceElems::const_iterator i = slice.elems.begin(); i != slice.elems.end(); i++) { SliceElem elem = *i; @@ -596,7 +684,7 @@ void realiseSlice(Slice slice) } /* For each element, expand its id at its path. */ - for (SliceElems::iterator i = slice.elems.begin(); + for (SliceElems::const_iterator i = slice.elems.begin(); i != slice.elems.end(); i++) { SliceElem elem = *i; diff --git a/src/fstate.hh b/src/fstate.hh index f06a4807ef..a195281646 100644 --- a/src/fstate.hh +++ b/src/fstate.hh @@ -113,7 +113,7 @@ void registerSuccessor(const FSId & id1, const FSId & id2); Slice normaliseFState(FSId id); /* Realise a Slice in the file system. */ -void realiseSlice(Slice slice); +void realiseSlice(const Slice & slice); #endif /* !__FSTATE_H */ diff --git a/src/hash.cc b/src/hash.cc index 72dcd790c7..97bf8f7856 100644 --- a/src/hash.cc +++ b/src/hash.cc @@ -28,6 +28,16 @@ bool Hash::operator != (Hash h2) } +bool Hash::operator < (const Hash & h) const +{ + for (unsigned int i = 0; i < hashSize; i++) { + if (hash[i] < h.hash[i]) return true; + if (hash[i] > h.hash[i]) return false; + } + return false; +} + + Hash::operator string() const { ostringstream str; diff --git a/src/hash.hh b/src/hash.hh index 509a27912a..5ae5dc22ae 100644 --- a/src/hash.hh +++ b/src/hash.hh @@ -22,6 +22,9 @@ struct Hash /* Check whether two hash are not equal. */ bool operator != (Hash h2); + /* For sorting. */ + bool operator < (const Hash & h) const; + /* Convert a hash code into a hexadecimal representation. */ operator string() const; }; diff --git a/src/references.cc b/src/references.cc index de7a4b339c..a42c1aed02 100644 --- a/src/references.cc +++ b/src/references.cc @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -9,24 +11,24 @@ static void search(const string & s, - Strings & refs, Strings & seen) + Strings & ids, Strings & seen) { - for (Strings::iterator i = refs.begin(); - i != refs.end(); ) + for (Strings::iterator i = ids.begin(); + i != ids.end(); ) { if (s.find(*i) == string::npos) i++; else { debug(format("found reference to `%1%'") % *i); seen.push_back(*i); - i = refs.erase(i); + i = ids.erase(i); } } } void checkPath(const string & path, - Strings & refs, Strings & seen) + Strings & ids, Strings & seen) { struct stat st; if (lstat(path.c_str(), &st)) @@ -39,8 +41,8 @@ void checkPath(const string & path, while (errno = 0, dirent = readdir(dir)) { string name = dirent->d_name; if (name == "." || name == "..") continue; - search(name, refs, seen); - checkPath(path + "/" + name, refs, seen); + search(name, ids, seen); + checkPath(path + "/" + name, ids, seen); } closedir(dir); /* !!! close on exception */ @@ -58,7 +60,7 @@ void checkPath(const string & path, if (read(fd, buf, st.st_size) != st.st_size) throw SysError(format("reading file %1%") % path); - search(string(buf, st.st_size), refs, seen); + search(string(buf, st.st_size), ids, seen); delete buf; /* !!! autodelete */ @@ -69,30 +71,40 @@ void checkPath(const string & path, char buf[st.st_size]; if (readlink(path.c_str(), buf, st.st_size) != st.st_size) throw SysError(format("reading symbolic link `%1%'") % path); - search(string(buf, st.st_size), refs, seen); + search(string(buf, st.st_size), ids, seen); } else throw Error(format("unknown file type: %1%") % path); } -Strings filterReferences(const string & path, const Strings & _refs) +Strings filterReferences(const string & path, const Strings & paths) { - Strings refs; + map backMap; + Strings ids; Strings seen; /* For efficiency (and a higher hit rate), just search for the hash part of the file name. (This assumes that all references have the form `HASH-bla'). */ - for (Strings::const_iterator i = _refs.begin(); - i != _refs.end(); i++) + for (Strings::const_iterator i = paths.begin(); + i != paths.end(); i++) { string s = string(baseNameOf(*i), 0, 32); parseHash(s); - refs.push_back(s); + ids.push_back(s); + backMap[s] = *i; } - checkPath(path, refs, seen); + checkPath(path, ids, seen); - return seen; + Strings found; + for (Strings::iterator i = seen.begin(); i != seen.end(); i++) + { + map::iterator j; + if ((j = backMap.find(*i)) == backMap.end()) abort(); + found.push_back(j->second); + } + + return found; } diff --git a/src/test-builder-2.sh b/src/test-builder-2.sh index 010e1c8057..a12fa27a67 100644 --- a/src/test-builder-2.sh +++ b/src/test-builder-2.sh @@ -5,4 +5,4 @@ echo "builder 2" mkdir $out || exit 1 cd $out || exit 1 echo "Hallo Wereld" > bla -cat $src >> bla \ No newline at end of file +echo $builder >> bla diff --git a/src/test.cc b/src/test.cc index 3437650ac2..219281c8be 100644 --- a/src/test.cc +++ b/src/test.cc @@ -137,8 +137,8 @@ void runTests() realise(fs2id); realise(fs2id); - string out1fn = nixStore + "/hello.txt"; string out1id = hashString("foo"); /* !!! bad */ + string out1fn = nixStore + "/" + (string) out1id + "-hello.txt"; FState fs3 = ATmake( "Derive([(, )], [], , , [(\"out\", )])", out1fn.c_str(), @@ -153,6 +153,38 @@ void runTests() realise(fs3id); realise(fs3id); + + FSId builder4id; + string builder4fn; + addToStore("./test-builder-2.sh", builder4fn, builder4id); + + FState fs4 = ATmake( + "Slice([], [(, , [])])", + ((string) builder4id).c_str(), + builder4fn.c_str(), + ((string) builder4id).c_str()); + FSId fs4id = writeTerm(fs4, "", 0); + + realise(fs4id); + + string out5id = hashString("bar"); /* !!! bad */ + string out5fn = nixStore + "/" + (string) out5id + "-hello2"; + FState fs5 = ATmake( + "Derive([(, )], [], , , [(\"out\", ), (\"builder\", )])", + out5fn.c_str(), + ((string) out5id).c_str(), + ((string) fs4id).c_str(), + ((string) builder4fn).c_str(), + thisSystem.c_str(), + out5fn.c_str(), + ((string) builder4fn).c_str()); + debug(printTerm(fs5)); + FSId fs5id = writeTerm(fs5, "", 0); + + realise(fs5id); + realise(fs5id); + + #if 0 FState fs2 = ATmake( "Path(, Hash(), [])",