aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/eval.cc285
-rw-r--r--src/eval.hh4
-rw-r--r--src/test.cc22
-rw-r--r--src/util.cc11
-rw-r--r--src/util.hh9
-rw-r--r--src/values.cc15
-rw-r--r--src/values.hh2
7 files changed, 188 insertions, 160 deletions
diff --git a/src/eval.cc b/src/eval.cc
index 4f59bcc21..a1b8db6e0 100644
--- a/src/eval.cc
+++ b/src/eval.cc
@@ -18,7 +18,7 @@ typedef map<string, string> Environment;
/* Return true iff the given path exists. */
-bool pathExists(string path)
+bool pathExists(const string & path)
{
int res;
struct stat st;
@@ -30,158 +30,107 @@ bool pathExists(string path)
}
-#if 0
-/* Compute a derived value by running a program. */
-static Hash computeDerived(Hash sourceHash, string targetName,
- string platform, Hash prog, Environment env)
+/* Run a program. */
+static void runProgram(const string & program, Environment env)
{
- string targetPath = nixValues + "/" +
- (string) sourceHash + "-nf";
-
- /* Check whether the target already exists. */
- if (pathExists(targetPath))
- throw Error("derived value in " + targetPath + " already exists");
-
- /* Find the program corresponding to the hash `prog'. */
- string progPath = queryValuePath(prog);
-
- /* Finalize the environment. */
- env["out"] = targetPath;
-
/* Create a log file. */
- string logFileName =
- nixLogDir + "/" + baseNameOf(targetPath) + ".log";
+ string logFileName = nixLogDir + "/run.log";
/* !!! auto-pclose on exit */
FILE * logFile = popen(("tee " + logFileName + " >&2").c_str(), "w"); /* !!! escaping */
if (!logFile)
- throw SysError("unable to create log file " + logFileName);
-
- try {
+ throw SysError(format("unable to create log file %1%") % logFileName);
- /* Fork a child to build the package. */
- pid_t pid;
- switch (pid = fork()) {
+ /* Fork a child to build the package. */
+ pid_t pid;
+ switch (pid = fork()) {
- case -1:
- throw SysError("unable to fork");
+ case -1:
+ throw SysError("unable to fork");
- case 0:
+ case 0:
- try { /* child */
+ try { /* child */
#if 0
- /* Try to use a prebuilt. */
- string prebuiltHashS, prebuiltFile;
- if (queryDB(nixDB, dbPrebuilts, hash, prebuiltHashS)) {
-
- try {
- prebuiltFile = getFile(parseHash(prebuiltHashS));
- } catch (Error e) {
- cerr << "cannot obtain prebuilt (ignoring): " << e.what() << endl;
- goto build;
- }
+ /* Try to use a prebuilt. */
+ string prebuiltHashS, prebuiltFile;
+ if (queryDB(nixDB, dbPrebuilts, hash, prebuiltHashS)) {
+
+ try {
+ prebuiltFile = getFile(parseHash(prebuiltHashS));
+ } catch (Error e) {
+ cerr << "cannot obtain prebuilt (ignoring): " << e.what() << endl;
+ goto build;
+ }
- cerr << "substituting prebuilt " << prebuiltFile << endl;
+ cerr << "substituting prebuilt " << prebuiltFile << endl;
- int res = system(("tar xfj " + prebuiltFile + " 1>&2").c_str()); // !!! escaping
- if (WEXITSTATUS(res) != 0)
- /* This is a fatal error, because path may now
- have clobbered. */
- throw Error("cannot unpack " + prebuiltFile);
+ int res = system(("tar xfj " + prebuiltFile + " 1>&2").c_str()); // !!! escaping
+ if (WEXITSTATUS(res) != 0)
+ /* This is a fatal error, because path may now
+ have clobbered. */
+ throw Error("cannot unpack " + prebuiltFile);
- _exit(0);
- }
+ _exit(0);
+ }
#endif
-// build:
-
- /* Fill in the environment. We don't bother freeing
- the strings, since we'll exec or die soon
- anyway. */
- const char * env2[env.size() + 1];
- int i = 0;
- for (Environment::iterator it = env.begin();
- it != env.end(); it++, i++)
- env2[i] = (new string(it->first + "=" + it->second))->c_str();
- env2[i] = 0;
-
- /* Dup the log handle into stderr. */
- if (dup2(fileno(logFile), STDERR_FILENO) == -1)
- throw Error("cannot pipe standard error into log file: " + string(strerror(errno)));
+ // build:
+
+ /* Fill in the environment. We don't bother freeing
+ the strings, since we'll exec or die soon
+ anyway. */
+ const char * env2[env.size() + 1];
+ int i = 0;
+ for (Environment::iterator it = env.begin();
+ it != env.end(); it++, i++)
+ env2[i] = (new string(it->first + "=" + it->second))->c_str();
+ env2[i] = 0;
+
+ /* Dup the log handle into stderr. */
+ if (dup2(fileno(logFile), STDERR_FILENO) == -1)
+ throw SysError("cannot pipe standard error into log file");
- /* Dup stderr to stdin. */
- if (dup2(STDERR_FILENO, STDOUT_FILENO) == -1)
- throw Error("cannot dup stderr into stdout");
+ /* Dup stderr to stdin. */
+ if (dup2(STDERR_FILENO, STDOUT_FILENO) == -1)
+ throw SysError("cannot dup stderr into stdout");
- /* Make the program executable. !!! hack. */
- if (chmod(progPath.c_str(), 0755))
- throw Error("cannot make program executable");
+ /* Make the program executable. !!! hack. */
+ if (chmod(program.c_str(), 0755))
+ throw SysError("cannot make program executable");
- /* Execute the program. This should not return. */
- execle(progPath.c_str(), baseNameOf(progPath).c_str(), 0, env2);
+ /* Execute the program. This should not return. */
+ execle(program.c_str(), baseNameOf(program).c_str(), 0, env2);
- throw Error("unable to execute builder: " +
- string(strerror(errno)));
+ throw SysError(format("unable to execute %1%") % program);
- } catch (exception & e) {
- cerr << "build error: " << e.what() << endl;
- }
- _exit(1);
-
+ } catch (exception & e) {
+ cerr << "build error: " << e.what() << endl;
}
+ _exit(1);
- /* parent */
-
- /* Close the logging pipe. Note that this should not cause
- the logger to exit until builder exits (because the latter
- has an open file handle to the former). */
- pclose(logFile);
-
- /* Wait for the child to finish. */
- int status;
- if (waitpid(pid, &status, 0) != pid)
- throw Error("unable to wait for child");
-
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
- throw Error("unable to build package");
-
- /* Check whether the result was created. */
- if (!pathExists(targetPath))
- throw Error("program " + progPath +
- " failed to create a result in " + targetPath);
-
-#if 0
- /* Remove write permission from the value. */
- int res = system(("chmod -R -w " + targetPath).c_str()); // !!! escaping
- if (WEXITSTATUS(res) != 0)
- throw Error("cannot remove write permission from " + targetPath);
-#endif
-
- } catch (exception &) {
-// system(("rm -rf " + targetPath).c_str());
- throw;
}
- /* Hash the result. */
- Hash targetHash = hashPath(targetPath);
-
- /* Register targetHash -> targetPath. !!! this should be in
- values.cc. */
- setDB(nixDB, dbRefs, targetHash, targetName);
+ /* parent */
- /* Register that targetHash was produced by evaluating
- sourceHash; i.e., that targetHash is a normal form of
- sourceHash. !!! this shouldn't be here */
- setDB(nixDB, dbNFs, sourceHash, targetHash);
-
- return targetHash;
+ /* Close the logging pipe. Note that this should not cause
+ the logger to exit until builder exits (because the latter
+ has an open file handle to the former). */
+ pclose(logFile);
+
+ /* Wait for the child to finish. */
+ int status;
+ if (waitpid(pid, &status, 0) != pid)
+ throw Error("unable to wait for child");
+
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ throw Error("unable to build package");
}
-#endif
/* Throw an exception if the given platform string is not supported by
the platform we are executing on. */
-static void checkPlatform(string platform)
+static void checkPlatform(const string & platform)
{
if (platform != thisSystem)
throw Error(format("a `%1%' is required, but I am a `%2%'")
@@ -250,33 +199,39 @@ struct RStatus
};
-static void realise(RStatus & status, FState fs)
+static FState realise(RStatus & status, FState fs)
{
- char * s;
+ char * s1, * s2, * s3;
Content content;
- ATermList refs;
+ ATermList refs, ins, outs, bnds;
- if (ATmatch(fs, "File(<str>, <term>, [<list>])", &s, &content, &refs)) {
- string path(s);
+ if (ATmatch(fs, "File(<str>, <term>, [<list>])", &s1, &content, &refs)) {
+ string path(s1);
if (path[0] != '/') throw Error("absolute path expected: " + path);
/* Realise referenced paths. */
+ ATermList refs2 = ATempty;
while (!ATisEmpty(refs)) {
- realise(status, ATgetFirst(refs));
+ refs2 = ATappend(refs2, realise(status, ATgetFirst(refs)));
refs = ATgetNext(refs);
}
+ refs2 = ATreverse(refs2);
- if (!ATmatch(content, "Hash(<str>)", &s))
+ if (!ATmatch(content, "Hash(<str>)", &s1))
throw badTerm("hash expected", content);
- Hash hash = parseHash(s);
+ Hash hash = parseHash(s1);
+
+ /* Normal form. */
+ ATerm nf = ATmake("File(<str>, <term>, <list>)",
+ path.c_str(), content, refs2);
/* Perhaps the path already exists and has the right hash? */
if (pathExists(path)) {
if (hash == hashPath(path)) {
debug(format("path %1% already has hash %2%")
% path % (string) hash);
- return;
+ return nf;
}
throw Error(format("path %1% exists, but does not have hash %2%")
@@ -286,19 +241,79 @@ static void realise(RStatus & status, FState fs)
/* Do we know a path with that hash? If so, copy it. */
string path2 = queryFromStore(hash);
copyFile(path2, path);
+
+ return nf;
}
- else if (ATmatch(fs, "Derive()")) {
+ else if (ATmatch(fs, "Derive(<str>, <str>, [<list>], <str>, [<list>])",
+ &s1, &s2, &ins, &s3, &bnds))
+ {
+ string platform(s1), builder(s2), outPath(s3);
+
+ checkPlatform(platform);
+ /* Realise inputs. */
+ ATermList ins2 = ATempty;
+ while (!ATisEmpty(ins)) {
+ ins2 = ATappend(ins2, realise(status, ATgetFirst(ins)));
+ ins = ATgetNext(ins);
+ }
+ ins2 = ATreverse(ins2);
+
+ /* Build the environment. */
+ Environment env;
+ while (!ATisEmpty(bnds)) {
+ ATerm bnd = ATgetFirst(bnds);
+ if (!ATmatch(bnd, "(<str>, <str>)", &s1, &s2))
+ throw badTerm("string expected", bnd);
+ env[s1] = s2;
+ bnds = ATgetNext(bnds);
+ }
+
+ /* Check whether the target already exists. */
+ if (pathExists(outPath))
+ deleteFromStore(outPath);
+// throw Error(format("path %1% already exists") % outPath);
+
+ /* Run the builder. */
+ runProgram(builder, env);
+ /* Check whether the result was created. */
+ if (!pathExists(outPath))
+ throw Error(format("program %1% failed to create a result in %2%")
+ % builder % outPath);
+
+#if 0
+ /* Remove write permission from the value. */
+ int res = system(("chmod -R -w " + targetPath).c_str()); // !!! escaping
+ if (WEXITSTATUS(res) != 0)
+ throw Error("cannot remove write permission from " + targetPath);
+#endif
+
+ /* Hash the result. */
+ Hash outHash = hashPath(outPath);
+
+ /* Register targetHash -> targetPath. !!! this should be in
+ values.cc. */
+ setDB(nixDB, dbRefs, outHash, outPath);
+
+#if 0
+ /* Register that targetHash was produced by evaluating
+ sourceHash; i.e., that targetHash is a normal form of
+ sourceHash. !!! this shouldn't be here */
+ setDB(nixDB, dbNFs, sourceHash, targetHash);
+#endif
+
+ return ATmake("File(<str>, Hash(<str>), <list>)",
+ outPath.c_str(), ((string) outHash).c_str(), ins2);
}
- else throw badTerm("bad file system state expression", fs);
+ throw badTerm("bad file system state expression", fs);
}
-void realiseFState(FState fs)
+FState realiseFState(FState fs)
{
RStatus status;
- realise(status, fs);
+ return realise(status, fs);
}
diff --git a/src/eval.hh b/src/eval.hh
index f90d5ba02..553c7c40b 100644
--- a/src/eval.hh
+++ b/src/eval.hh
@@ -23,7 +23,7 @@ using namespace std;
self-referential. This prevents us from having to deal with
cycles.
- Derive : String * Path * [FState] * [Path] * [(String, String)] -> [FState]
+ Derive : String * Path * [FState] * Path * [(String, String)] -> FState
Derive(platform, builder, ins, outs, env) specifies the creation of
new file objects (in paths declared by `outs') by the execution of
@@ -61,7 +61,7 @@ typedef ATerm Content;
/* Realise a $f$-normalised expression in the file system. */
-void realiseFState(FState fs);
+FState realiseFState(FState fs);
/* Return a canonical textual representation of an expression. */
string printTerm(ATerm t);
diff --git a/src/test.cc b/src/test.cc
index aafae8ee3..639bd5ccf 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -13,7 +13,9 @@
void realise(FState fs)
{
- realiseFState(fs);
+ cout << format("%1% => %2%\n")
+ % printTerm(fs)
+ % printTerm(realiseFState(fs));
}
@@ -145,15 +147,25 @@ void runTests()
"File(<str>, Hash(<str>), [])",
builder1fn.c_str(),
((string) builder1h).c_str());
- realiseFState(fs1);
- realiseFState(fs1);
+ realise(fs1);
+ realise(fs1);
FState fs2 = ATmake(
"File(<str>, Hash(<str>), [])",
(builder1fn + "_bla").c_str(),
((string) builder1h).c_str());
- realiseFState(fs2);
- realiseFState(fs2);
+ realise(fs2);
+ realise(fs2);
+
+ string out1fn = nixStore + "/hello.txt";
+ FState fs3 = ATmake(
+ "Derive(<str>, <str>, [<term>], <str>, [(\"out\", <str>)])",
+ thisSystem.c_str(),
+ builder1fn.c_str(),
+ fs1,
+ out1fn.c_str(),
+ out1fn.c_str());
+ realise(fs3);
#if 0
Expr e1 = ATmake("Exec(Str(<str>), Hash(<str>), [])",
diff --git a/src/util.cc b/src/util.cc
index c6a0c1199..a042a65b0 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -11,10 +11,15 @@
string thisSystem = SYSTEM;
-SysError::SysError(string msg)
+Error::Error(const format & f)
+{
+ err = f.str();
+}
+
+
+SysError::SysError(const format & f)
+ : Error(format("%1%: %2%") % f.str() % strerror(errno))
{
- char * sysMsg = strerror(errno);
- err = msg + ": " + sysMsg;
}
diff --git a/src/util.hh b/src/util.hh
index 3efac928b..cf6f7d0c1 100644
--- a/src/util.hh
+++ b/src/util.hh
@@ -18,22 +18,21 @@ class Error : public exception
protected:
string err;
public:
- Error() { }
- Error(format f) { err = f.str(); }
- ~Error() throw () { }
+ Error(const format & f);
+ ~Error() throw () { };
const char * what() const throw () { return err.c_str(); }
};
class SysError : public Error
{
public:
- SysError(string msg);
+ SysError(const format & f);
};
class UsageError : public Error
{
public:
- UsageError(string _err) : Error(_err) { };
+ UsageError(const format & f) : Error(f) { };
};
diff --git a/src/values.cc b/src/values.cc
index e23624ce5..fe65b977e 100644
--- a/src/values.cc
+++ b/src/values.cc
@@ -127,16 +127,13 @@ string fetchURL(string url)
#endif
-void deleteFromStore(Hash hash)
+void deleteFromStore(const string & path)
{
- string fn;
- if (queryDB(nixDB, dbRefs, hash, fn)) {
- string prefix = nixStore + "/";
- if (string(fn, prefix.size()) != prefix)
- throw Error("path " + fn + " is not in the store");
- deletePath(fn);
- delDB(nixDB, dbRefs, hash);
- }
+ string prefix = nixStore + "/";
+ if (string(path, 0, prefix.size()) != prefix)
+ throw Error(format("path %1% is not in the store") % path);
+ deletePath(path);
+// delDB(nixDB, dbRefs, hash);
}
diff --git a/src/values.hh b/src/values.hh
index 1bb00a9dd..79ef48671 100644
--- a/src/values.hh
+++ b/src/values.hh
@@ -15,7 +15,7 @@ void copyFile(string src, string dst);
void addToStore(string srcPath, string & dstPath, Hash & hash);
/* Delete a value from the nixStore directory. */
-void deleteFromStore(Hash hash);
+void deleteFromStore(const string & path);
/* !!! */
string queryFromStore(Hash hash);