aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/libexpr/parser.cc2
-rw-r--r--src/libmain/shared.cc1
-rw-r--r--src/libstore/db.cc4
-rw-r--r--src/libstore/globals.cc1
-rw-r--r--src/libstore/globals.hh3
-rw-r--r--src/libstore/references.cc12
-rw-r--r--src/libutil/archive.cc21
-rw-r--r--src/libutil/util.cc45
-rw-r--r--src/libutil/util.hh4
-rw-r--r--src/nix-env/Makefile.am11
-rw-r--r--src/nix-env/main.cc270
-rw-r--r--src/nix-store/main.cc5
13 files changed, 330 insertions, 51 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index fe8cbf1e3..0f1273426 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,2 +1,2 @@
SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \
- libexpr nix-instantiate
+ libexpr nix-instantiate nix-env
diff --git a/src/libexpr/parser.cc b/src/libexpr/parser.cc
index 22d76c263..e3c863a55 100644
--- a/src/libexpr/parser.cc
+++ b/src/libexpr/parser.cc
@@ -68,6 +68,8 @@ struct Cleanup : TermFun
Expr parseExprFromFile(Path path)
{
+ assert(path[0] == '/');
+
#if 0
/* Perhaps this is already an imploded parse tree? */
Expr e = ATreadFromNamedFile(path.c_str());
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index b06f5eb8b..632794db3 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -19,6 +19,7 @@ static void initAndRun(int argc, char * * argv)
nixStore = NIX_STORE_DIR;
nixDataDir = NIX_DATA_DIR;
nixLogDir = NIX_LOG_DIR;
+ nixStateDir = (string) NIX_STATE_DIR;
nixDBPath = (string) NIX_STATE_DIR + "/db";
/* Put the arguments in a vector. */
diff --git a/src/libstore/db.cc b/src/libstore/db.cc
index 63ec2724f..a97111a3a 100644
--- a/src/libstore/db.cc
+++ b/src/libstore/db.cc
@@ -166,7 +166,7 @@ void Database::open(const string & path)
/* The following code provides automatic recovery of the
database environment. Recovery is necessary when a process
dies while it has the database open. To detect this,
- processes atomically increment a counter when the open the
+ processes atomically increment a counter when they open the
database, and decrement it when they close it. If we see
that counter is > 0 but no processes are accessing the
database---determined by attempting to obtain a write lock
@@ -199,7 +199,7 @@ void Database::open(const string & path)
other readers or writers. */
int n = getAccessorCount(fdAccessors);
- setAccessorCount(fdAccessors, 1);
+ setAccessorCount(fdAccessors, 1);
if (n != 0) {
printMsg(lvlTalkative,
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index a292b49ae..e5d76ff48 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -3,6 +3,7 @@
string nixStore = "/UNINIT";
string nixDataDir = "/UNINIT";
string nixLogDir = "/UNINIT";
+string nixStateDir = "/UNINIT";
string nixDBPath = "/UNINIT";
bool keepFailed = false;
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 1b4d0bde3..3da294cc8 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -16,6 +16,9 @@ extern string nixDataDir; /* !!! fix */
/* nixLogDir is the directory where we log various operations. */
extern string nixLogDir;
+/* nixStateDir is the directory where state is stored. */
+extern string nixStateDir;
+
/* nixDBPath is the path name of our Berkeley DB environment. */
extern string nixDBPath;
diff --git a/src/libstore/references.cc b/src/libstore/references.cc
index ab743f76d..2bea44131 100644
--- a/src/libstore/references.cc
+++ b/src/libstore/references.cc
@@ -36,14 +36,10 @@ void checkPath(const string & path,
throw SysError(format("getting attributes of path `%1%'") % path);
if (S_ISDIR(st.st_mode)) {
- AutoCloseDir dir = opendir(path.c_str());
-
- struct dirent * dirent;
- while (errno = 0, dirent = readdir(dir)) {
- string name = dirent->d_name;
- if (name == "." || name == "..") continue;
- search(name, ids, seen);
- checkPath(path + "/" + name, ids, seen);
+ Strings names = readDirectory(path);
+ for (Strings::iterator i = names.begin(); i != names.end(); i++) {
+ search(*i, ids, seen);
+ checkPath(path + "/" + *i, ids, seen);
}
}
diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc
index ed57df4c9..f605e8b61 100644
--- a/src/libutil/archive.cc
+++ b/src/libutil/archive.cc
@@ -51,23 +51,12 @@ static void dump(const string & path, DumpSink & sink);
static void dumpEntries(const Path & path, DumpSink & sink)
{
- AutoCloseDir dir = opendir(path.c_str());
- if (!dir) throw SysError("opening directory " + path);
+ Strings names = readDirectory(path);
+ vector<string> names2(names.begin(), names.end());
+ sort(names2.begin(), names2.end());
- vector<string> names;
-
- struct dirent * dirent;
- while (errno = 0, dirent = readdir(dir)) {
- string name = dirent->d_name;
- if (name == "." || name == "..") continue;
- names.push_back(name);
- }
- if (errno) throw SysError("reading directory " + path);
-
- sort(names.begin(), names.end());
-
- for (vector<string>::iterator it = names.begin();
- it != names.end(); it++)
+ for (vector<string>::iterator it = names2.begin();
+ it != names2.end(); it++)
{
writeString("entry", sink);
writeString("(", sink);
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 299a37f6c..6a032a3f1 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -108,6 +108,25 @@ bool pathExists(const Path & path)
}
+Strings readDirectory(const Path & path)
+{
+ Strings names;
+
+ AutoCloseDir dir = opendir(path.c_str());
+ if (!dir) throw SysError(format("opening directory `%1%'") % path);
+
+ struct dirent * dirent;
+ while (errno = 0, dirent = readdir(dir)) { /* sic */
+ string name = dirent->d_name;
+ if (name == "." || name == "..") continue;
+ names.push_back(name);
+ }
+ if (errno) throw SysError(format("reading directory `%1%'") % path);
+
+ return names;
+}
+
+
void deletePath(const Path & path)
{
printMsg(lvlVomit, format("deleting path `%1%'") % path);
@@ -117,18 +136,7 @@ void deletePath(const Path & path)
throw SysError(format("getting attributes of path `%1%'") % path);
if (S_ISDIR(st.st_mode)) {
- Strings names;
-
- {
- AutoCloseDir dir = opendir(path.c_str());
-
- struct dirent * dirent;
- while (errno = 0, dirent = readdir(dir)) {
- string name = dirent->d_name;
- if (name == "." || name == "..") continue;
- names.push_back(name);
- }
- } /* scoped to ensure that dir is closed at this point */
+ Strings names = readDirectory(path);
/* Make the directory writable. */
if (!(st.st_mode & S_IWUSR)) {
@@ -136,7 +144,7 @@ void deletePath(const Path & path)
throw SysError(format("making `%1%' writable"));
}
- for (Strings::iterator i = names.begin(); i != names.end(); i++)
+ for (Strings::iterator i = names.begin(); i != names.end(); ++i)
deletePath(path + "/" + *i);
}
@@ -157,14 +165,9 @@ void makePathReadOnly(const Path & path)
}
if (S_ISDIR(st.st_mode)) {
- AutoCloseDir dir = opendir(path.c_str());
-
- struct dirent * dirent;
- while (errno = 0, dirent = readdir(dir)) {
- string name = dirent->d_name;
- if (name == "." || name == "..") continue;
- makePathReadOnly(path + "/" + name);
- }
+ Strings names = readDirectory(path);
+ for (Strings::iterator i = names.begin(); i != names.end(); ++i)
+ makePathReadOnly(path + "/" + *i);
}
}
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index e6b600eff..d0e7b3ada 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -73,6 +73,10 @@ string baseNameOf(const Path & path);
/* Return true iff the given path exists. */
bool pathExists(const Path & path);
+/* Read the contents of a directory. The entries `.' and `..' are
+ removed. */
+Strings readDirectory(const Path & path);
+
/* Delete a path; i.e., in the case of a directory, it is deleted
recursively. Don't use this at home, kids. */
void deletePath(const Path & path);
diff --git a/src/nix-env/Makefile.am b/src/nix-env/Makefile.am
new file mode 100644
index 000000000..add54581b
--- /dev/null
+++ b/src/nix-env/Makefile.am
@@ -0,0 +1,11 @@
+bin_PROGRAMS = nix-env
+
+nix_env_SOURCES = main.cc
+nix_env_LDADD = ../libmain/libmain.a ../libexpr/libexpr.a \
+ ../libstore/libstore.a ../libutil/libutil.a \
+ ../boost/format/libformat.a -L../../externals/inst/lib -ldb_cxx \
+ -lsglr -lATB -lconversion -lasfix2 -lmept -lATerm
+
+AM_CXXFLAGS = \
+ -I.. -I../../externals/inst/include -I../libutil -I../libstore \
+ -I../libexpr -I../libmain
diff --git a/src/nix-env/main.cc b/src/nix-env/main.cc
new file mode 100644
index 000000000..4296ce509
--- /dev/null
+++ b/src/nix-env/main.cc
@@ -0,0 +1,270 @@
+#include "globals.hh"
+#include "normalise.hh"
+#include "shared.hh"
+#include "parser.hh"
+#include "eval.hh"
+
+
+typedef void (* Operation) (EvalState & state,
+ Strings opFlags, Strings opArgs);
+
+
+struct DrvInfo
+{
+ string name;
+ Path drvPath;
+ Path outPath;
+};
+
+typedef map<string, DrvInfo> DrvInfos;
+
+
+bool parseDerivation(EvalState & state, Expr e, DrvInfo & drv)
+{
+ ATMatcher m;
+
+ e = evalExpr(state, e);
+ if (!(atMatch(m, e) >> "Attrs")) return false;
+ Expr a = queryAttr(e, "type");
+ if (!a || evalString(state, a) != "derivation") return false;
+
+ a = queryAttr(e, "name");
+ if (!a) throw badTerm("derivation name missing", e);
+ drv.name = evalString(state, a);
+
+ a = queryAttr(e, "drvPath");
+ if (!a) throw badTerm("derivation path missing", e);
+ drv.drvPath = evalPath(state, a);
+
+ a = queryAttr(e, "outPath");
+ if (!a) throw badTerm("output path missing", e);
+ drv.outPath = evalPath(state, a);
+
+ return true;
+}
+
+
+bool parseDerivations(EvalState & state, Expr e, DrvInfos & drvs)
+{
+ e = evalExpr(state, e);
+
+ ATermMap drvMap;
+ queryAllAttrs(e, drvMap);
+
+ for (ATermIterator i(drvMap.keys()); i; ++i) {
+ DrvInfo drv;
+ debug(format("evaluating attribute `%1%'") % *i);
+ if (parseDerivation(state, drvMap.get(*i), drv))
+ drvs[drv.name] = drv;
+ }
+
+ return true;
+}
+
+
+void loadDerivations(EvalState & state, Path nePath, DrvInfos & drvs)
+{
+ Expr e = parseExprFromFile(absPath(nePath));
+ if (!parseDerivations(state, e, drvs))
+ throw badTerm("expected set of derivations", e);
+}
+
+
+static Path getLinksDir()
+{
+ return canonPath(nixStateDir + "/links");
+}
+
+
+Path createLink(Path outPath, Path drvPath)
+{
+ Path linksDir = getLinksDir();
+
+ unsigned int num = 0;
+
+ Strings names = readDirectory(linksDir);
+ for (Strings::iterator i = names.begin(); i != names.end(); ++i) {
+ istringstream s(*i);
+ unsigned int n;
+ if (s >> n && s.eof() && n > num) num = n + 1;
+ }
+
+ Path linkPath = (format("%1%/%2%") % linksDir % num).str();
+
+ if (symlink(outPath.c_str(), linkPath.c_str()) != 0)
+ throw SysError(format("creating symlink `%1%'") % linkPath);
+
+ return linkPath;
+}
+
+
+void installDerivations(EvalState & state,
+ Path nePath, Strings drvNames)
+{
+ debug(format("installing derivations from `%1%'") % nePath);
+
+ /* Fetch all derivations from the input file. */
+ DrvInfos availDrvs;
+ loadDerivations(state, nePath, availDrvs);
+
+ /* Filter out the ones we're not interested in. */
+ DrvInfos selectedDrvs;
+ for (Strings::iterator i = drvNames.begin();
+ i != drvNames.end(); ++i)
+ {
+ DrvInfos::iterator j = availDrvs.find(*i);
+ if (j == availDrvs.end())
+ throw Error(format("unknown derivation `%1%'") % *i);
+ else
+ selectedDrvs[j->first] = j->second;
+ }
+
+ /* Get the environment builder expression. */
+ Expr envBuilder = parseExprFromFile("/home/eelco/nix/corepkgs/buildenv"); /* !!! */
+
+ /* Construct the whole top level derivation. */
+ ATermList inputs = ATempty;
+ for (DrvInfos::iterator i = selectedDrvs.begin();
+ i != selectedDrvs.end(); ++i)
+ {
+ ATerm t = ATmake(
+ "Attrs(["
+ "Bind(\"type\", Str(\"derivation\")), "
+ "Bind(\"name\", Str(<str>)), "
+ "Bind(\"drvPath\", Path(<str>)), "
+ "Bind(\"outPath\", Path(<str>))"
+ "])",
+ i->second.name.c_str(),
+ i->second.drvPath.c_str(),
+ i->second.outPath.c_str());
+ inputs = ATinsert(inputs, t);
+ }
+
+ ATerm inputs2 = ATmake("List(<term>)", ATreverse(inputs));
+
+ /* Also write a copy of the list of inputs to the store; we need
+ it for future modifications of the environment. */
+ Path inputsFile = writeTerm(inputs2, "-env-inputs");
+
+ Expr topLevel = ATmake(
+ "Call(<term>, Attrs(["
+ "Bind(\"system\", Str(<str>)), "
+ "Bind(\"derivations\", <term>), " // !!! redundant
+ "Bind(\"manifest\", Path(<str>))"
+ "]))",
+ envBuilder, thisSystem.c_str(), inputs2, inputsFile.c_str());
+
+ /* Instantiate it. */
+ debug(format("evaluating builder expression `%1%'") % topLevel);
+ DrvInfo topLevelDrv;
+ if (!parseDerivation(state, topLevel, topLevelDrv))
+ abort();
+
+ /* Realise the resulting store expression. */
+ debug(format("realising user environment"));
+ Path nfPath = normaliseStoreExpr(topLevelDrv.drvPath);
+ realiseClosure(nfPath);
+
+ /* Switch the current user environment to the output path. */
+ debug(format("switching to new user environment"));
+ Path linkPath = createLink(topLevelDrv.outPath, topLevelDrv.drvPath);
+// switchLink(current"), link);
+}
+
+
+static void opInstall(EvalState & state,
+ Strings opFlags, Strings opArgs)
+{
+ if (opArgs.size() < 1) throw UsageError("Nix expression expected");
+
+ Path nePath = opArgs.front();
+ opArgs.pop_front();
+
+ installDerivations(state, nePath,
+ Strings(opArgs.begin(), opArgs.end()));
+}
+
+
+static void opQuery(EvalState & state,
+ Strings opFlags, Strings opArgs)
+{
+ enum { qName } query = qName;
+ enum { sInstalled, sAvailable } source = sInstalled;
+
+ for (Strings::iterator i = opFlags.begin();
+ i != opFlags.end(); ++i)
+ if (*i == "--name") query = qName;
+ else if (*i == "--installed") source = sInstalled;
+ else if (*i == "--available" || *i == "-f") source = sAvailable;
+ else throw UsageError(format("unknown flag `%1%'") % *i);
+
+ /* Obtain derivation information from the specified source. */
+ DrvInfos drvs;
+
+ switch (source) {
+
+ case sInstalled:
+ break;
+
+ case sAvailable: {
+ Path nePath = opArgs.front();
+ opArgs.pop_front();
+ loadDerivations(state, nePath, drvs);
+ break;
+ }
+
+ default: abort();
+ }
+
+ /* Perform the specified query on the derivations. */
+ switch (query) {
+
+ case qName: {
+ if (opArgs.size() != 0) throw UsageError("no arguments expected");
+ for (DrvInfos::iterator i = drvs.begin(); i != drvs.end(); ++i)
+ cout << format("%1%\n") % i->second.name;
+ break;
+ }
+
+ default: abort();
+ }
+}
+
+
+void run(Strings args)
+{
+ EvalState state;
+ Strings opFlags, opArgs;
+ Operation op = 0;
+
+ for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
+ string arg = *i;
+
+ Operation oldOp = op;
+
+ if (arg == "--install" || arg == "-i")
+ op = opInstall;
+ if (arg == "--query" || arg == "-q")
+ op = opQuery;
+ else if (arg == "--verbose" || arg == "-v")
+ verbosity = (Verbosity) ((int) verbosity + 1);
+ else if (arg[0] == '-')
+ opFlags.push_back(arg);
+ else
+ opArgs.push_back(arg);
+
+ if (oldOp && oldOp != op)
+ throw UsageError("only one operation may be specified");
+ }
+
+ if (!op) throw UsageError("no operation specified");
+
+ openDB();
+
+ op(state, opFlags, opArgs);
+
+ printEvalStats(state);
+}
+
+
+string programId = "nix-env";
diff --git a/src/nix-store/main.cc b/src/nix-store/main.cc
index 0d87db9df..c73de5289 100644
--- a/src/nix-store/main.cc
+++ b/src/nix-store/main.cc
@@ -251,9 +251,8 @@ void run(Strings args)
Strings opFlags, opArgs;
Operation op = 0;
- for (Strings::iterator it = args.begin(); it != args.end(); )
- {
- string arg = *it++;
+ for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
+ string arg = *i;
Operation oldOp = op;