aboutsummaryrefslogtreecommitdiff
path: root/src/nix-store
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2003-11-18 11:38:25 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2003-11-18 11:38:25 +0000
commitb1117ef29d35822647bda32f8cd3887f4f6eaede (patch)
tree1635a7fd961930104c56aef2fa20ecb3e29d9798 /src/nix-store
parentce92d1bf1434562f5b80320c503768c4d06f1f8d (diff)
* nix -> nix-store, fix -> nix-instantiate.
Diffstat (limited to 'src/nix-store')
-rw-r--r--src/nix-store/Makefile.am27
-rw-r--r--src/nix-store/dotgraph.cc135
-rw-r--r--src/nix-store/dotgraph.hh8
-rw-r--r--src/nix-store/nix-help.txt34
-rw-r--r--src/nix-store/nix.cc304
5 files changed, 508 insertions, 0 deletions
diff --git a/src/nix-store/Makefile.am b/src/nix-store/Makefile.am
new file mode 100644
index 000000000..a39d1e2ad
--- /dev/null
+++ b/src/nix-store/Makefile.am
@@ -0,0 +1,27 @@
+bin_PROGRAMS = nix-store
+
+nix_store_SOURCES = nix.cc dotgraph.cc
+nix_store_LDADD = ../libmain/libmain.a ../libstore/libstore.a ../libutil/libutil.a \
+ ../boost/format/libformat.a -L../../externals/inst/lib -ldb_cxx -lATerm
+
+nix.o: nix-help.txt.hh
+
+%.hh: %
+ echo -n '"' > $@
+ sed 's|\(.*\)|\1\\n\\|' < $< >> $@
+ echo '"' >> $@
+
+AM_CXXFLAGS = \
+ -I.. -I../../externals/inst/include -I../libutil -I../libstore -I../libmain
+
+install-data-local:
+ $(INSTALL) -d $(localstatedir)/nix
+ $(INSTALL) -d $(localstatedir)/nix/db
+ $(INSTALL) -d $(localstatedir)/nix/links
+ rm -f $(prefix)/current
+ ln -sf $(localstatedir)/nix/links/current $(prefix)/current
+ $(INSTALL) -d $(localstatedir)/log/nix
+ $(INSTALL) -d $(prefix)/store
+ $(bindir)/nix-store --init
+
+EXTRA_DIST = *.hh
diff --git a/src/nix-store/dotgraph.cc b/src/nix-store/dotgraph.cc
new file mode 100644
index 000000000..c670bf19e
--- /dev/null
+++ b/src/nix-store/dotgraph.cc
@@ -0,0 +1,135 @@
+#include "dotgraph.hh"
+#include "normalise.hh"
+
+
+static string dotQuote(const string & s)
+{
+ return "\"" + s + "\"";
+}
+
+
+static string nextColour()
+{
+ static int n = 0;
+ static string colours[] =
+ { "black", "red", "green", "blue"
+ , "magenta", "burlywood" };
+ return colours[n++ % (sizeof(colours) / sizeof(string))];
+}
+
+
+static string makeEdge(const string & src, const string & dst)
+{
+ format f = format("%1% -> %2% [color = %3%];\n")
+ % dotQuote(src) % dotQuote(dst) % dotQuote(nextColour());
+ return f.str();
+}
+
+
+static string makeNode(const string & id, const string & label,
+ const string & colour)
+{
+ format f = format("%1% [label = %2%, shape = box, "
+ "style = filled, fillcolor = %3%];\n")
+ % dotQuote(id) % dotQuote(label) % dotQuote(colour);
+ return f.str();
+}
+
+
+static string symbolicName(const string & path)
+{
+ string p = baseNameOf(path);
+ if (isHash(string(p, 0, Hash::hashSize * 2)) &&
+ p[Hash::hashSize * 2] == '-')
+ p = string(p, Hash::hashSize * 2 + 1);
+ return p;
+}
+
+
+string pathLabel(const Path & nePath, const string & elemPath)
+{
+ return (string) nePath + "-" + elemPath;
+}
+
+
+void printClosure(const Path & nePath, const StoreExpr & fs)
+{
+ PathSet workList(fs.closure.roots);
+ PathSet doneSet;
+
+ for (PathSet::iterator i = workList.begin(); i != workList.end(); i++) {
+ cout << makeEdge(pathLabel(nePath, *i), nePath);
+ }
+
+ while (!workList.empty()) {
+ Path path = *(workList.begin());
+ workList.erase(path);
+
+ if (doneSet.find(path) == doneSet.end()) {
+ doneSet.insert(path);
+
+ ClosureElems::const_iterator elem = fs.closure.elems.find(path);
+ if (elem == fs.closure.elems.end())
+ throw Error(format("bad closure, missing path `%1%'") % path);
+
+ for (StringSet::const_iterator i = elem->second.refs.begin();
+ i != elem->second.refs.end(); i++)
+ {
+ workList.insert(*i);
+ cout << makeEdge(pathLabel(nePath, *i), pathLabel(nePath, path));
+ }
+
+ cout << makeNode(pathLabel(nePath, path),
+ symbolicName(path), "#ff0000");
+ }
+ }
+}
+
+
+void printDotGraph(const PathSet & roots)
+{
+ PathSet workList(roots);
+ PathSet doneSet;
+
+ cout << "digraph G {\n";
+
+ while (!workList.empty()) {
+ Path nePath = *(workList.begin());
+ workList.erase(nePath);
+
+ if (doneSet.find(nePath) == doneSet.end()) {
+ doneSet.insert(nePath);
+
+ StoreExpr ne = storeExprFromPath(nePath);
+
+ string label, colour;
+
+ if (ne.type == StoreExpr::neDerivation) {
+ for (PathSet::iterator i = ne.derivation.inputs.begin();
+ i != ne.derivation.inputs.end(); i++)
+ {
+ workList.insert(*i);
+ cout << makeEdge(*i, nePath);
+ }
+
+ label = "derivation";
+ colour = "#00ff00";
+ for (StringPairs::iterator i = ne.derivation.env.begin();
+ i != ne.derivation.env.end(); i++)
+ if (i->first == "name") label = i->second;
+ }
+
+ else if (ne.type == StoreExpr::neClosure) {
+ label = "<closure>";
+ colour = "#00ffff";
+ printClosure(nePath, ne);
+ }
+
+ else abort();
+
+ cout << makeNode(nePath, label, colour);
+ }
+ }
+
+ cout << "}\n";
+}
diff --git a/src/nix-store/dotgraph.hh b/src/nix-store/dotgraph.hh
new file mode 100644
index 000000000..ef389b30d
--- /dev/null
+++ b/src/nix-store/dotgraph.hh
@@ -0,0 +1,8 @@
+#ifndef __DOTGRAPH_H
+#define __DOTGRAPH_H
+
+#include "storeexpr.hh"
+
+void printDotGraph(const PathSet & roots);
+
+#endif /* !__DOTGRAPH_H */
diff --git a/src/nix-store/nix-help.txt b/src/nix-store/nix-help.txt
new file mode 100644
index 000000000..d7f977025
--- /dev/null
+++ b/src/nix-store/nix-help.txt
@@ -0,0 +1,34 @@
+nix-store [OPTIONS...] [ARGUMENTS...]
+
+`nix-store' is a tool to manipulate the Nix store.
+
+Operations:
+
+ --realise / -r: realise a Nix expression
+ --delete / -d: delete paths from the Nix store
+ --add / -A: copy a path to the Nix store
+ --query / -q: query information
+
+ --successor: register a successor expression
+ --substitute: register a substitute expression
+
+ --dump: dump a path as a Nix archive
+ --restore: restore a path from a Nix archive
+
+ --init: initialise the Nix database
+ --verify: verify Nix structures
+
+ --version: output version information
+ --help: display help
+
+Query flags:
+
+ --list / -l: query the output paths (roots) of a Nix expression (default)
+ --requisites / -R: print all paths necessary to realise expression
+ --predecessors: print predecessors of a Nix expression
+ --graph: print a dot graph rooted at given ids
+
+Options:
+
+ --verbose / -v: verbose operation (may be repeated)
+ --keep-failed / -K: keep temporary directories of failed builds
diff --git a/src/nix-store/nix.cc b/src/nix-store/nix.cc
new file mode 100644
index 000000000..d1766de39
--- /dev/null
+++ b/src/nix-store/nix.cc
@@ -0,0 +1,304 @@
+#include <iostream>
+#include <sstream>
+
+#include "globals.hh"
+#include "normalise.hh"
+#include "archive.hh"
+#include "shared.hh"
+#include "dotgraph.hh"
+
+
+typedef void (* Operation) (Strings opFlags, Strings opArgs);
+
+
+static void printHelp()
+{
+ cout <<
+#include "nix-help.txt.hh"
+ ;
+ exit(0);
+}
+
+
+
+static Path checkPath(const Path & arg)
+{
+ return arg; /* !!! check that arg is in the store */
+}
+
+
+/* Realise paths from the given store expressions. */
+static void opRealise(Strings opFlags, Strings opArgs)
+{
+ if (!opFlags.empty()) throw UsageError("unknown flag");
+
+ for (Strings::iterator i = opArgs.begin();
+ i != opArgs.end(); i++)
+ {
+ Path nfPath = normaliseStoreExpr(checkPath(*i));
+ realiseClosure(nfPath);
+ cout << format("%1%\n") % (string) nfPath;
+ }
+}
+
+
+/* Delete a path in the Nix store directory. */
+static void opDelete(Strings opFlags, Strings opArgs)
+{
+ if (!opFlags.empty()) throw UsageError("unknown flag");
+
+ for (Strings::iterator it = opArgs.begin();
+ it != opArgs.end(); it++)
+ deleteFromStore(checkPath(*it));
+}
+
+
+/* Add paths to the Nix values directory and print the hashes of those
+ paths. */
+static void opAdd(Strings opFlags, Strings opArgs)
+{
+ if (!opFlags.empty()) throw UsageError("unknown flag");
+
+ for (Strings::iterator i = opArgs.begin(); i != opArgs.end(); i++)
+ cout << format("%1%\n") % addToStore(*i);
+}
+
+
+Path maybeNormalise(const Path & ne, bool normalise)
+{
+ return normalise ? normaliseStoreExpr(ne) : ne;
+}
+
+
+/* Perform various sorts of queries. */
+static void opQuery(Strings opFlags, Strings opArgs)
+{
+ enum { qList, qRequisites, qPredecessors, qGraph
+ } query = qList;
+ bool normalise = false;
+ bool includeExprs = true;
+ bool includeSuccessors = false;
+
+ for (Strings::iterator i = opFlags.begin();
+ i != opFlags.end(); i++)
+ if (*i == "--list" || *i == "-l") query = qList;
+ else if (*i == "--requisites" || *i == "-R") query = qRequisites;
+ else if (*i == "--predecessors") query = qPredecessors;
+ else if (*i == "--graph") query = qGraph;
+ else if (*i == "--normalise" || *i == "-n") normalise = true;
+ else if (*i == "--exclude-exprs") includeExprs = false;
+ else if (*i == "--include-successors") includeSuccessors = true;
+ else throw UsageError(format("unknown flag `%1%'") % *i);
+
+ switch (query) {
+
+ case qList: {
+ for (Strings::iterator i = opArgs.begin();
+ i != opArgs.end(); i++)
+ {
+ StringSet paths = storeExprRoots(
+ maybeNormalise(checkPath(*i), normalise));
+ for (StringSet::iterator j = paths.begin();
+ j != paths.end(); j++)
+ cout << format("%s\n") % *j;
+ }
+ break;
+ }
+
+ case qRequisites: {
+ StringSet paths;
+ for (Strings::iterator i = opArgs.begin();
+ i != opArgs.end(); i++)
+ {
+ StringSet paths2 = storeExprRequisites(
+ maybeNormalise(checkPath(*i), normalise),
+ includeExprs, includeSuccessors);
+ paths.insert(paths2.begin(), paths2.end());
+ }
+ for (StringSet::iterator i = paths.begin();
+ i != paths.end(); i++)
+ cout << format("%s\n") % *i;
+ break;
+ }
+
+ case qPredecessors: {
+ for (Strings::iterator i = opArgs.begin();
+ i != opArgs.end(); i++)
+ {
+ Paths preds = queryPredecessors(checkPath(*i));
+ for (Paths::iterator j = preds.begin();
+ j != preds.end(); j++)
+ cout << format("%s\n") % *j;
+ }
+ break;
+ }
+
+ case qGraph: {
+ PathSet roots;
+ for (Strings::iterator i = opArgs.begin();
+ i != opArgs.end(); i++)
+ roots.insert(maybeNormalise(checkPath(*i), normalise));
+ printDotGraph(roots);
+ break;
+ }
+
+ default:
+ abort();
+ }
+}
+
+
+static void opSuccessor(Strings opFlags, Strings opArgs)
+{
+ if (!opFlags.empty()) throw UsageError("unknown flag");
+ if (opArgs.size() % 2) throw UsageError("expecting even number of arguments");
+
+ Transaction txn;
+ createStoreTransaction(txn);
+ for (Strings::iterator i = opArgs.begin();
+ i != opArgs.end(); )
+ {
+ Path path1 = checkPath(*i++);
+ Path path2 = checkPath(*i++);
+ registerSuccessor(txn, path1, path2);
+ }
+ txn.commit();
+}
+
+
+static void opSubstitute(Strings opFlags, Strings opArgs)
+{
+ if (!opFlags.empty()) throw UsageError("unknown flag");
+ if (opArgs.size() % 2) throw UsageError("expecting even number of arguments");
+
+ for (Strings::iterator i = opArgs.begin();
+ i != opArgs.end(); )
+ {
+ Path src = checkPath(*i++);
+ Path sub = checkPath(*i++);
+ registerSubstitute(src, sub);
+ }
+}
+
+
+/* A sink that writes dump output to stdout. */
+struct StdoutSink : DumpSink
+{
+ virtual void operator ()
+ (const unsigned char * data, unsigned int len)
+ {
+ writeFull(STDOUT_FILENO, data, len);
+ }
+};
+
+
+/* Dump a path as a Nix archive. The archive is written to standard
+ output. */
+static void opDump(Strings opFlags, Strings opArgs)
+{
+ if (!opFlags.empty()) throw UsageError("unknown flag");
+ if (opArgs.size() != 1) throw UsageError("only one argument allowed");
+
+ StdoutSink sink;
+ string path = *opArgs.begin();
+ dumpPath(path, sink);
+}
+
+
+/* A source that read restore intput to stdin. */
+struct StdinSource : RestoreSource
+{
+ virtual void operator () (unsigned char * data, unsigned int len)
+ {
+ readFull(STDIN_FILENO, data, len);
+ }
+};
+
+
+/* Restore a value from a Nix archive. The archive is written to
+ standard input. */
+static void opRestore(Strings opFlags, Strings opArgs)
+{
+ if (!opFlags.empty()) throw UsageError("unknown flag");
+ if (opArgs.size() != 1) throw UsageError("only one argument allowed");
+
+ StdinSource source;
+ restorePath(*opArgs.begin(), source);
+}
+
+
+/* Initialise the Nix databases. */
+static void opInit(Strings opFlags, Strings opArgs)
+{
+ if (!opFlags.empty()) throw UsageError("unknown flag");
+ if (!opArgs.empty())
+ throw UsageError("--init does not have arguments");
+ initDB();
+}
+
+
+/* Verify the consistency of the Nix environment. */
+static void opVerify(Strings opFlags, Strings opArgs)
+{
+ verifyStore();
+}
+
+
+/* Scan the arguments; find the operation, set global flags, put all
+ other flags in a list, and put all other arguments in another
+ list. */
+void run(Strings args)
+{
+ Strings opFlags, opArgs;
+ Operation op = 0;
+
+ for (Strings::iterator it = args.begin(); it != args.end(); )
+ {
+ string arg = *it++;
+
+ Operation oldOp = op;
+
+ if (arg == "--realise" || arg == "-r")
+ op = opRealise;
+ else if (arg == "--delete" || arg == "-d")
+ op = opDelete;
+ else if (arg == "--add" || arg == "-A")
+ op = opAdd;
+ else if (arg == "--query" || arg == "-q")
+ op = opQuery;
+ else if (arg == "--successor")
+ op = opSuccessor;
+ else if (arg == "--substitute")
+ op = opSubstitute;
+ else if (arg == "--dump")
+ op = opDump;
+ else if (arg == "--restore")
+ op = opRestore;
+ else if (arg == "--init")
+ op = opInit;
+ else if (arg == "--verify")
+ op = opVerify;
+ else if (arg == "--verbose" || arg == "-v")
+ verbosity = (Verbosity) ((int) verbosity + 1);
+ else if (arg == "--keep-failed" || arg == "-K")
+ keepFailed = true;
+ else if (arg == "--help")
+ printHelp();
+ 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(opFlags, opArgs);
+}
+
+
+string programId = "nix";