aboutsummaryrefslogtreecommitdiff
path: root/src/nix-env
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2003-11-19 17:27:16 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2003-11-19 17:27:16 +0000
commit9898746ef3732979bf30e9048021b6232ddf15ac (patch)
tree77f1391387f0e28f5495104fed3e4227bbeb4af3 /src/nix-env
parentfd7ac09f1073179d9ac439c3e9fb12a1bf00a7d5 (diff)
* nix-env: a tool to manage user environments.
* Replace all directory reading code by a generic readDirectory() function.
Diffstat (limited to 'src/nix-env')
-rw-r--r--src/nix-env/Makefile.am11
-rw-r--r--src/nix-env/main.cc270
2 files changed, 281 insertions, 0 deletions
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";