* The new normaliser now passes the unit tests.

This commit is contained in:
Eelco Dolstra 2003-07-15 21:24:05 +00:00
parent f5b6fa5256
commit 7b3f44e05b
7 changed files with 179 additions and 34 deletions

View file

@ -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("<str>", ((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("(<str>, <str>, <term>)",
i->path.c_str(),
((string) i->id).c_str(),
unparseIds(i->refs)));
return ATmake("Slice(<term>, <term>)", roots, elems);
}
typedef set<FSId> FSIdSet;
Slice normaliseFState(FSId id) Slice normaliseFState(FSId id)
{ {
debug(format("normalising fstate")); debug(format("normalising fstate"));
@ -495,23 +526,22 @@ Slice normaliseFState(FSId id)
FSIds inIds; FSIds inIds;
parseIds(ins, inIds); parseIds(ins, inIds);
SliceElems inElems; /* !!! duplicates */ typedef map<string, SliceElem> ElemMap;
StringSet inPathsSet;
ElemMap inMap;
for (FSIds::iterator i = inIds.begin(); i != inIds.end(); i++) { for (FSIds::iterator i = inIds.begin(); i != inIds.end(); i++) {
Slice slice = normaliseFState(*i); Slice slice = normaliseFState(*i);
realiseSlice(slice); realiseSlice(slice);
for (SliceElems::iterator j = slice.elems.begin(); for (SliceElems::iterator j = slice.elems.begin();
j != slice.elems.end(); j++) j != slice.elems.end(); j++)
{ inMap[j->path] = *j;
inElems.push_back(*j);
inPathsSet.insert(j->path);
}
} }
Strings inPaths; Strings inPaths;
copy(inPathsSet.begin(), inPathsSet.end(), for (ElemMap::iterator i = inMap.begin(); i != inMap.end(); i++)
inserter(inPaths, inPaths.begin())); inPaths.push_back(i->second.path);
/* Build the environment. */ /* Build the environment. */
Environment env; Environment env;
@ -533,6 +563,7 @@ Slice normaliseFState(FSId id)
if (!ATmatch(t, "(<str>, <str>)", &s1, &s2)) if (!ATmatch(t, "(<str>, <str>)", &s1, &s2))
throw badTerm("string expected", t); throw badTerm("string expected", t);
outPaths.push_back(OutPath(s1, parseHash(s2))); outPaths.push_back(OutPath(s1, parseHash(s2)));
inPaths.push_back(s1);
outs = ATgetNext(outs); outs = ATgetNext(outs);
} }
@ -548,6 +579,7 @@ Slice normaliseFState(FSId id)
/* Check whether the output paths were created, and register each /* Check whether the output paths were created, and register each
one. */ one. */
FSIdSet used;
for (list<OutPath>::iterator i = outPaths.begin(); for (list<OutPath>::iterator i = outPaths.begin();
i != outPaths.end(); i++) i != outPaths.end(); i++)
{ {
@ -557,25 +589,81 @@ Slice normaliseFState(FSId id)
registerPath(path, i->second); registerPath(path, i->second);
slice.roots.push_back(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; 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")); debug(format("realising slice"));
Nest nest(true); Nest nest(true);
if (slice.elems.size() == 0) checkSlice(slice);
throw Error("empty slice");
/* Perhaps all paths already contain the right id? */ /* Perhaps all paths already contain the right id? */
bool missing = false; bool missing = false;
for (SliceElems::iterator i = slice.elems.begin(); for (SliceElems::const_iterator i = slice.elems.begin();
i != slice.elems.end(); i++) i != slice.elems.end(); i++)
{ {
SliceElem elem = *i; SliceElem elem = *i;
@ -596,7 +684,7 @@ void realiseSlice(Slice slice)
} }
/* For each element, expand its id at its path. */ /* 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++) i != slice.elems.end(); i++)
{ {
SliceElem elem = *i; SliceElem elem = *i;

View file

@ -113,7 +113,7 @@ void registerSuccessor(const FSId & id1, const FSId & id2);
Slice normaliseFState(FSId id); Slice normaliseFState(FSId id);
/* Realise a Slice in the file system. */ /* Realise a Slice in the file system. */
void realiseSlice(Slice slice); void realiseSlice(const Slice & slice);
#endif /* !__FSTATE_H */ #endif /* !__FSTATE_H */

View file

@ -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 Hash::operator string() const
{ {
ostringstream str; ostringstream str;

View file

@ -22,6 +22,9 @@ struct Hash
/* Check whether two hash are not equal. */ /* Check whether two hash are not equal. */
bool operator != (Hash h2); bool operator != (Hash h2);
/* For sorting. */
bool operator < (const Hash & h) const;
/* Convert a hash code into a hexadecimal representation. */ /* Convert a hash code into a hexadecimal representation. */
operator string() const; operator string() const;
}; };

View file

@ -1,3 +1,5 @@
#include <map>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
@ -9,24 +11,24 @@
static void search(const string & s, static void search(const string & s,
Strings & refs, Strings & seen) Strings & ids, Strings & seen)
{ {
for (Strings::iterator i = refs.begin(); for (Strings::iterator i = ids.begin();
i != refs.end(); ) i != ids.end(); )
{ {
if (s.find(*i) == string::npos) if (s.find(*i) == string::npos)
i++; i++;
else { else {
debug(format("found reference to `%1%'") % *i); debug(format("found reference to `%1%'") % *i);
seen.push_back(*i); seen.push_back(*i);
i = refs.erase(i); i = ids.erase(i);
} }
} }
} }
void checkPath(const string & path, void checkPath(const string & path,
Strings & refs, Strings & seen) Strings & ids, Strings & seen)
{ {
struct stat st; struct stat st;
if (lstat(path.c_str(), &st)) if (lstat(path.c_str(), &st))
@ -39,8 +41,8 @@ void checkPath(const string & path,
while (errno = 0, dirent = readdir(dir)) { while (errno = 0, dirent = readdir(dir)) {
string name = dirent->d_name; string name = dirent->d_name;
if (name == "." || name == "..") continue; if (name == "." || name == "..") continue;
search(name, refs, seen); search(name, ids, seen);
checkPath(path + "/" + name, refs, seen); checkPath(path + "/" + name, ids, seen);
} }
closedir(dir); /* !!! close on exception */ closedir(dir); /* !!! close on exception */
@ -58,7 +60,7 @@ void checkPath(const string & path,
if (read(fd, buf, st.st_size) != st.st_size) if (read(fd, buf, st.st_size) != st.st_size)
throw SysError(format("reading file %1%") % path); 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 */ delete buf; /* !!! autodelete */
@ -69,30 +71,40 @@ void checkPath(const string & path,
char buf[st.st_size]; char buf[st.st_size];
if (readlink(path.c_str(), buf, st.st_size) != st.st_size) if (readlink(path.c_str(), buf, st.st_size) != st.st_size)
throw SysError(format("reading symbolic link `%1%'") % path); 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); 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<string, string> backMap;
Strings ids;
Strings seen; Strings seen;
/* For efficiency (and a higher hit rate), just search for the /* For efficiency (and a higher hit rate), just search for the
hash part of the file name. (This assumes that all references hash part of the file name. (This assumes that all references
have the form `HASH-bla'). */ have the form `HASH-bla'). */
for (Strings::const_iterator i = _refs.begin(); for (Strings::const_iterator i = paths.begin();
i != _refs.end(); i++) i != paths.end(); i++)
{ {
string s = string(baseNameOf(*i), 0, 32); string s = string(baseNameOf(*i), 0, 32);
parseHash(s); 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<string, string>::iterator j;
if ((j = backMap.find(*i)) == backMap.end()) abort();
found.push_back(j->second);
}
return found;
} }

View file

@ -5,4 +5,4 @@ echo "builder 2"
mkdir $out || exit 1 mkdir $out || exit 1
cd $out || exit 1 cd $out || exit 1
echo "Hallo Wereld" > bla echo "Hallo Wereld" > bla
cat $src >> bla echo $builder >> bla

View file

@ -137,8 +137,8 @@ void runTests()
realise(fs2id); realise(fs2id);
realise(fs2id); realise(fs2id);
string out1fn = nixStore + "/hello.txt";
string out1id = hashString("foo"); /* !!! bad */ string out1id = hashString("foo"); /* !!! bad */
string out1fn = nixStore + "/" + (string) out1id + "-hello.txt";
FState fs3 = ATmake( FState fs3 = ATmake(
"Derive([(<str>, <str>)], [<str>], <str>, <str>, [(\"out\", <str>)])", "Derive([(<str>, <str>)], [<str>], <str>, <str>, [(\"out\", <str>)])",
out1fn.c_str(), out1fn.c_str(),
@ -153,6 +153,38 @@ void runTests()
realise(fs3id); realise(fs3id);
realise(fs3id); realise(fs3id);
FSId builder4id;
string builder4fn;
addToStore("./test-builder-2.sh", builder4fn, builder4id);
FState fs4 = ATmake(
"Slice([<str>], [(<str>, <str>, [])])",
((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([(<str>, <str>)], [<str>], <str>, <str>, [(\"out\", <str>), (\"builder\", <str>)])",
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 #if 0
FState fs2 = ATmake( FState fs2 = ATmake(
"Path(<str>, Hash(<str>), [])", "Path(<str>, Hash(<str>), [])",