aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fix.cc30
-rw-r--r--src/fstate.cc148
-rw-r--r--src/fstate.hh13
-rw-r--r--src/nix.cc90
-rw-r--r--src/util.cc12
-rw-r--r--src/util.hh2
6 files changed, 198 insertions, 97 deletions
diff --git a/src/fix.cc b/src/fix.cc
index 87ce7c775..508a44116 100644
--- a/src/fix.cc
+++ b/src/fix.cc
@@ -13,29 +13,6 @@ typedef ATerm Expr;
static Expr evalFile(string fileName);
-static bool isFState(Expr e, string & path)
-{
- char * s1, * s2, * s3;
- Expr e1, e2;
- if (ATmatch(e, "Path(<str>, <term>, [<list>])", &s1, &e1, &e2)) {
- path = s1;
- return true;
- }
- else if (ATmatch(e, "Derive(<str>, <str>, [<list>], <str>, [<list>])",
- &s1, &s2, &e1, &s3, &e2))
- {
- path = s3;
- return true;
- }
- else if (ATmatch(e, "Include(<str>)", &s1))
- {
- string fn = queryPathByHash(parseHash(s1));
- return isFState(evalFile(fn), path);
- }
- else return false;
-}
-
-
static Expr substExpr(string x, Expr rep, Expr e)
{
char * s;
@@ -113,8 +90,7 @@ static Expr evalExpr(Expr e)
ATmatch(e, "Function([<list>], <term>)", &e1, &e2))
return e;
- string dummy;
- if (isFState(e, dummy)) return e;
+ if (fstatePath(e) != "") return e; /* !!! hack */
/* Application. */
if (ATmatch(e, "App(<term>, [<list>])", &e1, &e2)) {
@@ -165,8 +141,8 @@ static Expr evalExpr(Expr e)
string key = it->first;
ATerm value = it->second;
- string path;
- if (isFState(value, path)) {
+ string path = fstatePath(value);
+ if (path != "") {
ins = ATinsert(ins, value);
env = ATinsert(env, ATmake("(<str>, <str>)",
key.c_str(), path.c_str()));
diff --git a/src/fstate.cc b/src/fstate.cc
index 2e3ffd639..fa677a257 100644
--- a/src/fstate.cc
+++ b/src/fstate.cc
@@ -1,4 +1,5 @@
#include <map>
+#include <set>
#include <iostream>
#include <sys/types.h>
@@ -17,17 +18,20 @@
typedef map<string, string> Environment;
-/* Return true iff the given path exists. */
-bool pathExists(const string & path)
+class AutoDelete
{
- int res;
- struct stat st;
- res = stat(path.c_str(), &st);
- if (!res) return true;
- if (errno != ENOENT)
- throw SysError(format("getting status of %1%") % path);
- return false;
-}
+ string path;
+public:
+
+ AutoDelete(const string & p) : path(p)
+ {
+ }
+
+ ~AutoDelete()
+ {
+ deletePath(path);
+ }
+};
/* Run a program. */
@@ -36,9 +40,19 @@ static void runProgram(const string & program, Environment env)
/* Create a log file. */
string logFileName = nixLogDir + "/run.log";
/* !!! auto-pclose on exit */
- FILE * logFile = popen(("tee " + logFileName + " >&2").c_str(), "w"); /* !!! escaping */
+ FILE * logFile = popen(("tee -a " + logFileName + " >&2").c_str(), "w"); /* !!! escaping */
if (!logFile)
- throw SysError(format("unable to create log file %1%") % logFileName);
+ throw SysError(format("creating log file `%1%'") % logFileName);
+
+ /* Create a temporary directory where the build will take
+ place. */
+ static int counter = 0;
+ string tmpDir = (format("/tmp/nix-%1%-%2%") % getpid() % counter++).str();
+
+ if (mkdir(tmpDir.c_str(), 0777) == -1)
+ throw SysError(format("creating directory `%1%'") % tmpDir);
+
+ AutoDelete delTmpDir(tmpDir);
/* Fork a child to build the package. */
pid_t pid;
@@ -51,31 +65,8 @@ static void runProgram(const string & program, Environment env)
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;
- }
-
- 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);
-
- _exit(0);
- }
-#endif
-
- // build:
+ if (chdir(tmpDir.c_str()) == -1)
+ throw SysError(format("changing into to `%1%'") % tmpDir);
/* Fill in the environment. We don't bother freeing
the strings, since we'll exec or die soon
@@ -157,15 +148,7 @@ Hash hashTerm(ATerm t)
}
-struct RStatus
-{
- /* !!! the comparator of this hash should match the semantics of
- the file system */
-// map<string, Hash> paths;
-};
-
-
-static ATerm termFromHash(const Hash & hash)
+ATerm termFromHash(const Hash & hash)
{
string path = queryPathByHash(hash);
ATerm t = ATreadFromNamedFile(path.c_str());
@@ -188,7 +171,7 @@ Hash writeTerm(ATerm t)
}
-static FState realise(RStatus & status, FState fs)
+static FState realise(FState fs)
{
char * s1, * s2, * s3;
Content content;
@@ -212,7 +195,7 @@ static FState realise(RStatus & status, FState fs)
/* Fall through. */
if (ATmatch(fs, "Include(<str>)", &s1)) {
- return realise(status, termFromHash(parseHash(s1)));
+ return realise(termFromHash(parseHash(s1)));
}
else if (ATmatch(fs, "Path(<str>, <term>, [<list>])", &s1, &content, &refs)) {
@@ -227,7 +210,7 @@ static FState realise(RStatus & status, FState fs)
/* Realise referenced paths. */
ATermList refs2 = ATempty;
while (!ATisEmpty(refs)) {
- refs2 = ATinsert(refs2, realise(status, ATgetFirst(refs)));
+ refs2 = ATinsert(refs2, realise(ATgetFirst(refs)));
refs = ATgetNext(refs);
}
refs2 = ATreverse(refs2);
@@ -278,7 +261,7 @@ static FState realise(RStatus & status, FState fs)
/* Realise inputs. */
ATermList ins2 = ATempty;
while (!ATisEmpty(ins)) {
- ins2 = ATinsert(ins2, realise(status, ATgetFirst(ins)));
+ ins2 = ATinsert(ins2, realise(ATgetFirst(ins)));
ins = ATgetNext(ins);
}
ins2 = ATreverse(ins2);
@@ -335,6 +318,67 @@ static FState realise(RStatus & status, FState fs)
FState realiseFState(FState fs)
{
- RStatus status;
- return realise(status, fs);
+ return realise(fs);
+}
+
+
+string fstatePath(FState fs)
+{
+ char * s1, * s2, * s3;
+ FState e1, e2;
+ if (ATmatch(fs, "Path(<str>, <term>, [<list>])", &s1, &e1, &e2))
+ return s1;
+ else if (ATmatch(fs, "Derive(<str>, <str>, [<list>], <str>, [<list>])",
+ &s1, &s2, &e1, &s3, &e2))
+ return s3;
+ else if (ATmatch(fs, "Include(<str>)", &s1))
+ return fstatePath(termFromHash(parseHash(s1)));
+ else
+ return "";
+}
+
+
+typedef set<string> StringSet;
+
+
+void fstateRefs2(FState fs, StringSet & paths)
+{
+ char * s1, * s2, * s3;
+ FState e1, e2;
+ ATermList refs, ins;
+
+ if (ATmatch(fs, "Path(<str>, <term>, [<list>])", &s1, &e1, &refs)) {
+ paths.insert(s1);
+
+ while (!ATisEmpty(refs)) {
+ fstateRefs2(ATgetFirst(refs), paths);
+ refs = ATgetNext(refs);
+ }
+ }
+
+ else if (ATmatch(fs, "Derive(<str>, <str>, [<list>], <str>, [<list>])",
+ &s1, &s2, &ins, &s3, &e2))
+ {
+ paths.insert(s3);
+
+ while (!ATisEmpty(ins)) {
+ fstateRefs2(ATgetFirst(ins), paths);
+ ins = ATgetNext(ins);
+ }
+ }
+
+ else if (ATmatch(fs, "Include(<str>)", &s1))
+ fstateRefs2(termFromHash(parseHash(s1)), paths);
+
+ else throw badTerm("bad fstate expression", fs);
+}
+
+
+Strings fstateRefs(FState fs)
+{
+ StringSet paths;
+ fstateRefs2(fs, paths);
+ Strings paths2(paths.size());
+ copy(paths.begin(), paths.end(), paths2.begin());
+ return paths2;
}
diff --git a/src/fstate.hh b/src/fstate.hh
index b04588e7b..de6303dca 100644
--- a/src/fstate.hh
+++ b/src/fstate.hh
@@ -60,9 +60,17 @@ typedef ATerm FState;
typedef ATerm Content;
-/* Realise a $f$-normalised expression in the file system. */
+/* Realise an fstate expression in the file system. This requires
+ execution of all Derive() nodes. */
FState realiseFState(FState fs);
+/* Return the path of an fstate expression. An empty string is
+ returned if the term is not a valid fstate expression. (!!!) */
+string fstatePath(FState fs);
+
+/* Return the paths referenced by fstate expression. */
+Strings fstateRefs(FState fs);
+
/* Return a canonical textual representation of an expression. */
string printTerm(ATerm t);
@@ -73,6 +81,9 @@ Error badTerm(const format & f, ATerm t);
/* Hash an aterm. */
Hash hashTerm(ATerm t);
+/* Read an aterm from disk, given its hash. */
+ATerm termFromHash(const Hash & hash);
+
/* Write an aterm to the Nix store directory, and return its hash. */
Hash writeTerm(ATerm t);
diff --git a/src/nix.cc b/src/nix.cc
index 0e5154572..ec4c91788 100644
--- a/src/nix.cc
+++ b/src/nix.cc
@@ -21,9 +21,10 @@ static ArgType argType = atpUnknown;
Operations:
- --install / -i: realise a Nix expression
+ --install / -i: realise an fstate
--delete / -d: delete paths from the Nix store
--add / -A: copy a path to the Nix store
+ --query / -q: query information
--dump: dump a path as a Nix archive
--restore: restore a path from a Nix archive
@@ -39,6 +40,11 @@ static ArgType argType = atpUnknown;
--file / -f: by file name
--hash / -h: by hash
+ Query flags:
+
+ --path / -p: query the path of an fstate
+ --refs / -r: query paths referenced by an fstate
+
Options:
--verbose / -v: verbose operation
@@ -54,10 +60,8 @@ static void getArgType(Strings & flags)
{
string arg = *it;
ArgType tp;
- if (arg == "--hash" || arg == "-h")
- tp = atpHash;
- else if (arg == "--file" || arg == "-f")
- tp = atpPath;
+ if (arg == "--hash" || arg == "-h") tp = atpHash;
+ else if (arg == "--file" || arg == "-f") tp = atpPath;
else { it++; continue; }
if (argType != atpUnknown)
throw UsageError("only one argument type specified may be specified");
@@ -69,6 +73,20 @@ static void getArgType(Strings & flags)
}
+static Hash argToHash(const string & arg)
+{
+ if (argType == atpHash)
+ return parseHash(arg);
+ else if (argType == atpPath) {
+ string path;
+ Hash hash;
+ addToStore(arg, path, hash);
+ return hash;
+ }
+ else abort();
+}
+
+
/* Realise (or install) paths from the given Nix fstate
expressions. */
static void opInstall(Strings opFlags, Strings opArgs)
@@ -78,20 +96,11 @@ static void opInstall(Strings opFlags, Strings opArgs)
for (Strings::iterator it = opArgs.begin();
it != opArgs.end(); it++)
- {
- Hash hash;
- if (argType == atpHash)
- hash = parseHash(*it);
- else if (argType == atpPath) {
- string path;
- addToStore(*it, path, hash);
- }
- FState fs = ATmake("Include(<str>)", ((string) hash).c_str());
- realiseFState(fs);
- }
+ realiseFState(termFromHash(argToHash(*it)));
}
+/* Delete a path in the Nix store directory. */
static void opDelete(Strings opFlags, Strings opArgs)
{
if (!opFlags.empty()) throw UsageError("unknown flag");
@@ -120,6 +129,51 @@ static void opAdd(Strings opFlags, Strings opArgs)
}
+/* Perform various sorts of queries. */
+static void opQuery(Strings opFlags, Strings opArgs)
+{
+ enum { qPath, qRefs, qUnknown } query = qPath;
+
+ for (Strings::iterator it = opFlags.begin();
+ it != opFlags.end(); )
+ {
+ string arg = *it;
+ if (arg == "--path" || arg == "-p") query = qPath;
+ else if (arg == "--refs" || arg == "-r") query = qRefs;
+ else { it++; continue; }
+ it = opFlags.erase(it);
+ }
+
+ getArgType(opFlags);
+ if (!opFlags.empty()) throw UsageError("unknown flag");
+
+ for (Strings::iterator it = opArgs.begin();
+ it != opArgs.end(); it++)
+ {
+ Hash hash = argToHash(*it);
+
+ switch (query) {
+
+ case qPath:
+ cout << format("%s\n") %
+ (string) fstatePath(termFromHash(hash));
+ break;
+
+ case qRefs: {
+ Strings refs = fstateRefs(termFromHash(hash));
+ for (Strings::iterator j = refs.begin();
+ j != refs.end(); j++)
+ cout << format("%s\n") % *j;
+ break;
+ }
+
+ default:
+ abort();
+ }
+ }
+}
+
+
/* A sink that writes dump output to stdout. */
struct StdoutSink : DumpSink
{
@@ -208,8 +262,10 @@ void run(Strings args)
op = opInstall;
else if (arg == "--delete" || arg == "-d")
op = opDelete;
- else if (arg == "--add")
+ else if (arg == "--add" || arg == "-A")
op = opAdd;
+ else if (arg == "--query" || arg == "-q")
+ op = opQuery;
else if (arg == "--dump")
op = opDump;
else if (arg == "--restore")
diff --git a/src/util.cc b/src/util.cc
index 2f9c43e55..8ccd3c152 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -66,6 +66,18 @@ string baseNameOf(string path)
}
+bool pathExists(const string & path)
+{
+ int res;
+ struct stat st;
+ res = stat(path.c_str(), &st);
+ if (!res) return true;
+ if (errno != ENOENT)
+ throw SysError(format("getting status of %1%") % path);
+ return false;
+}
+
+
void deletePath(string path)
{
struct stat st;
diff --git a/src/util.hh b/src/util.hh
index a8f801b30..684bafbb5 100644
--- a/src/util.hh
+++ b/src/util.hh
@@ -60,6 +60,8 @@ string dirOf(string path);
the final `/'. */
string baseNameOf(string path);
+/* Return true iff the given path exists. */
+bool pathExists(const string & path);
/* Delete a path; i.e., in the case of a directory, it is deleted
recursively. Don't use this at home, kids. */