about summary refs log tree commit diff
path: root/third_party/nix/src/nix-store
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-05-18T15·39+0200
committerclbot <clbot@tvl.fyi>2022-05-19T14·08+0000
commitd127f9bd0e7b9b2e0df2de8a2227f77c0907468d (patch)
tree68455040d88b8e0c2817601db88ede450873ff8e /third_party/nix/src/nix-store
parentc85291c602ac666421627d6934ebc6d5be1b93e1 (diff)
chore(3p/nix): unvendor tvix 0.1 r/4098
Nothing is using this now, and we'll likely never pick this up again,
but we learned a lot in the process.

Every now and then this breaks in some bizarre way on channel bumps
and it's just a waste of time to maintain that.

Change-Id: Idcf2f5acd4ca7070ce18d7149cbfc0d967dc0a44
Reviewed-on: https://cl.tvl.fyi/c/depot/+/5632
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
Reviewed-by: lukegb <lukegb@tvl.fyi>
Autosubmit: tazjin <tazjin@tvl.su>
Diffstat (limited to 'third_party/nix/src/nix-store')
-rw-r--r--third_party/nix/src/nix-store/dotgraph.cc141
-rw-r--r--third_party/nix/src/nix-store/dotgraph.hh11
-rw-r--r--third_party/nix/src/nix-store/graphml.cc80
-rw-r--r--third_party/nix/src/nix-store/graphml.hh11
-rw-r--r--third_party/nix/src/nix-store/nix-store.cc1302
5 files changed, 0 insertions, 1545 deletions
diff --git a/third_party/nix/src/nix-store/dotgraph.cc b/third_party/nix/src/nix-store/dotgraph.cc
deleted file mode 100644
index 2500b8f4b07d..000000000000
--- a/third_party/nix/src/nix-store/dotgraph.cc
+++ /dev/null
@@ -1,141 +0,0 @@
-#include "nix-store/dotgraph.hh"
-
-#include <iostream>
-
-#include "libstore/store-api.hh"
-#include "libutil/util.hh"
-
-using std::cout;
-
-namespace nix {
-
-static std::string dotQuote(const std::string& s) { return "\"" + s + "\""; }
-
-static std::string nextColour() {
-  static int n = 0;
-  static std::string colours[] = {"black", "red",     "green",
-                                  "blue",  "magenta", "burlywood"};
-  return colours[n++ % (sizeof(colours) / sizeof(std::string))];
-}
-
-static std::string makeEdge(const std::string& src, const std::string& dst) {
-  format f = format("%1% -> %2% [color = %3%];\n") % dotQuote(src) %
-             dotQuote(dst) % dotQuote(nextColour());
-  return f.str();
-}
-
-static std::string makeNode(const std::string& id, const std::string& label,
-                            const std::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 std::string symbolicName(const std::string& path) {
-  std::string p = baseNameOf(path);
-  return std::string(p, p.find('-') + 1);
-}
-
-#if 0
-std::string pathLabel(const Path & nePath, const std::string & elemPath)
-{
-    return (std::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");
-        }
-    }
-}
-#endif
-
-void printDotGraph(const ref<Store>& store, const PathSet& roots) {
-  PathSet workList(roots);
-  PathSet doneSet;
-
-  cout << "digraph G {\n";
-
-  while (!workList.empty()) {
-    Path path = *(workList.begin());
-    workList.erase(path);
-
-    if (doneSet.find(path) != doneSet.end()) {
-      continue;
-    }
-    doneSet.insert(path);
-
-    cout << makeNode(path, symbolicName(path), "#ff0000");
-
-    for (auto& p : store->queryPathInfo(path)->references) {
-      if (p != path) {
-        workList.insert(p);
-        cout << makeEdge(p, path);
-      }
-    }
-
-#if 0
-        StoreExpr ne = storeExprFromPath(path);
-
-        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, path);
-            }
-
-            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(path, ne);
-        }
-
-        else abort();
-
-        cout << makeNode(path, label, colour);
-#endif
-  }
-
-  cout << "}\n";
-}
-
-}  // namespace nix
diff --git a/third_party/nix/src/nix-store/dotgraph.hh b/third_party/nix/src/nix-store/dotgraph.hh
deleted file mode 100644
index 40c268685494..000000000000
--- a/third_party/nix/src/nix-store/dotgraph.hh
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-
-#include "libutil/types.hh"
-
-namespace nix {
-
-class Store;
-
-void printDotGraph(const ref<Store>& store, const PathSet& roots);
-
-}  // namespace nix
diff --git a/third_party/nix/src/nix-store/graphml.cc b/third_party/nix/src/nix-store/graphml.cc
deleted file mode 100644
index ada4aaf6d048..000000000000
--- a/third_party/nix/src/nix-store/graphml.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-#include "nix-store/graphml.hh"
-
-#include <iostream>
-
-#include "libstore/derivations.hh"
-#include "libstore/store-api.hh"
-#include "libutil/util.hh"
-
-using std::cout;
-
-namespace nix {
-
-static inline const std::string& xmlQuote(const std::string& s) {
-  // Luckily, store paths shouldn't contain any character that needs to be
-  // quoted.
-  return s;
-}
-
-static std::string symbolicName(const std::string& path) {
-  std::string p = baseNameOf(path);
-  return std::string(p, p.find('-') + 1);
-}
-
-static std::string makeEdge(const std::string& src, const std::string& dst) {
-  return fmt("  <edge source=\"%1%\" target=\"%2%\"/>\n", xmlQuote(src),
-             xmlQuote(dst));
-}
-
-static std::string makeNode(const ValidPathInfo& info) {
-  return fmt(
-      "  <node id=\"%1%\">\n"
-      "    <data key=\"narSize\">%2%</data>\n"
-      "    <data key=\"name\">%3%</data>\n"
-      "    <data key=\"type\">%4%</data>\n"
-      "  </node>\n",
-      info.path, info.narSize, symbolicName(info.path),
-      (isDerivation(info.path) ? "derivation" : "output-path"));
-}
-
-void printGraphML(const ref<Store>& store, const PathSet& roots) {
-  PathSet workList(roots);
-  PathSet doneSet;
-  std::pair<PathSet::iterator, bool> ret;
-
-  cout << "<?xml version='1.0' encoding='utf-8'?>\n"
-       << "<graphml xmlns='http://graphml.graphdrawing.org/xmlns'\n"
-       << "    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n"
-       << "    "
-          "xsi:schemaLocation='http://graphml.graphdrawing.org/xmlns/1.0/"
-          "graphml.xsd'>\n"
-       << "<key id='narSize' for='node' attr.name='narSize' attr.type='int'/>"
-       << "<key id='name' for='node' attr.name='name' attr.type='string'/>"
-       << "<key id='type' for='node' attr.name='type' attr.type='string'/>"
-       << "<graph id='G' edgedefault='directed'>\n";
-
-  while (!workList.empty()) {
-    Path path = *(workList.begin());
-    workList.erase(path);
-
-    ret = doneSet.insert(path);
-    if (!ret.second) {
-      continue;
-    }
-
-    ValidPathInfo info = *(store->queryPathInfo(path));
-    cout << makeNode(info);
-
-    for (auto& p : store->queryPathInfo(path)->references) {
-      if (p != path) {
-        workList.insert(p);
-        cout << makeEdge(path, p);
-      }
-    }
-  }
-
-  cout << "</graph>\n";
-  cout << "</graphml>\n";
-}
-
-}  // namespace nix
diff --git a/third_party/nix/src/nix-store/graphml.hh b/third_party/nix/src/nix-store/graphml.hh
deleted file mode 100644
index be07904d0fc6..000000000000
--- a/third_party/nix/src/nix-store/graphml.hh
+++ /dev/null
@@ -1,11 +0,0 @@
-#pragma once
-
-#include "libutil/types.hh"
-
-namespace nix {
-
-class Store;
-
-void printGraphML(const ref<Store>& store, const PathSet& roots);
-
-}  // namespace nix
diff --git a/third_party/nix/src/nix-store/nix-store.cc b/third_party/nix/src/nix-store/nix-store.cc
deleted file mode 100644
index 532f60b7b7e3..000000000000
--- a/third_party/nix/src/nix-store/nix-store.cc
+++ /dev/null
@@ -1,1302 +0,0 @@
-#include <algorithm>
-#include <cstdio>
-#include <iostream>
-
-#include <absl/strings/escaping.h>
-#include <fcntl.h>
-#include <glog/logging.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "libmain/shared.hh"
-#include "libstore/derivations.hh"
-#include "libstore/globals.hh"
-#include "libstore/local-store.hh"
-#include "libstore/serve-protocol.hh"
-#include "libstore/worker-protocol.hh"
-#include "libutil/archive.hh"
-#include "libutil/monitor-fd.hh"
-#include "libutil/status.hh"
-#include "libutil/util.hh"
-#include "nix-store/dotgraph.hh"
-#include "nix-store/graphml.hh"
-#include "nix/legacy.hh"
-
-#if HAVE_SODIUM
-#include <sodium.h>
-#endif
-
-using namespace nix;
-using std::cin;
-using std::cout;
-
-// TODO(tazjin): clang-tidy's performance lints don't like this, but
-// the automatic fixes fail (it seems that some of the ops want to own
-// the args for whatever reason)
-using Operation = void (*)(Strings, Strings);
-
-static Path gcRoot;
-static int rootNr = 0;
-static bool indirectRoot = false;
-static bool noOutput = false;
-static std::shared_ptr<Store> store;
-
-ref<LocalStore> ensureLocalStore() {
-  auto store2 = std::dynamic_pointer_cast<LocalStore>(store);
-  if (!store2) {
-    throw Error("you don't have sufficient rights to use this command");
-  }
-  return ref<LocalStore>(store2);
-}
-
-static Path useDeriver(Path path) {
-  if (isDerivation(path)) {
-    return path;
-  }
-  Path drvPath = store->queryPathInfo(path)->deriver;
-  if (drvPath.empty()) {
-    throw Error(format("deriver of path '%1%' is not known") % path);
-  }
-  return drvPath;
-}
-
-/* Realise the given path.  For a derivation that means build it; for
-   other paths it means ensure their validity. */
-static PathSet realisePath(Path path, bool build = true) {
-  DrvPathWithOutputs p = parseDrvPathWithOutputs(path);
-
-  auto store2 = std::dynamic_pointer_cast<LocalFSStore>(store);
-
-  if (isDerivation(p.first)) {
-    if (build) {
-      util::OkOrThrow(store->buildPaths(std::cerr, {path}));
-    }
-    Derivation drv = store->derivationFromPath(p.first);
-    rootNr++;
-
-    if (p.second.empty()) {
-      for (auto& i : drv.outputs) {
-        p.second.insert(i.first);
-      }
-    }
-
-    PathSet outputs;
-    for (auto& j : p.second) {
-      auto i = drv.outputs.find(j);
-      if (i == drv.outputs.end()) {
-        throw Error(
-            format("derivation '%1%' does not have an output named '%2%'") %
-            p.first % j);
-      }
-      Path outPath = i->second.path;
-      if (store2) {
-        if (gcRoot.empty()) {
-          printGCWarning();
-        } else {
-          Path rootName = gcRoot;
-          if (rootNr > 1) {
-            rootName += "-" + std::to_string(rootNr);
-          }
-          if (i->first != "out") {
-            rootName += "-" + i->first;
-          }
-          outPath = store2->addPermRoot(outPath, rootName, indirectRoot);
-        }
-      }
-      outputs.insert(outPath);
-    }
-    return outputs;
-  }
-
-  if (build) {
-    store->ensurePath(path);
-  } else if (!store->isValidPath(path)) {
-    throw Error(format("path '%1%' does not exist and cannot be created") %
-                path);
-  }
-  if (store2) {
-    if (gcRoot.empty()) {
-      printGCWarning();
-    } else {
-      Path rootName = gcRoot;
-      rootNr++;
-      if (rootNr > 1) {
-        rootName += "-" + std::to_string(rootNr);
-      }
-      path = store2->addPermRoot(path, rootName, indirectRoot);
-    }
-  }
-  return {path};
-}
-
-/* Realise the given paths. */
-static void opRealise(Strings opFlags, Strings opArgs) {
-  bool dryRun = false;
-  BuildMode buildMode = bmNormal;
-  bool ignoreUnknown = false;
-
-  for (auto& i : opFlags) {
-    if (i == "--dry-run") {
-      dryRun = true;
-    } else if (i == "--repair") {
-      buildMode = bmRepair;
-    } else if (i == "--check") {
-      buildMode = bmCheck;
-    } else if (i == "--ignore-unknown") {
-      ignoreUnknown = true;
-    } else {
-      throw UsageError(format("unknown flag '%1%'") % i);
-    }
-  }
-
-  Paths paths;
-  for (auto& i : opArgs) {
-    DrvPathWithOutputs p = parseDrvPathWithOutputs(i);
-    paths.push_back(makeDrvPathWithOutputs(
-        store->followLinksToStorePath(p.first), p.second));
-  }
-
-  unsigned long long downloadSize;
-  unsigned long long narSize;
-  PathSet willBuild;
-  PathSet willSubstitute;
-  PathSet unknown;
-  store->queryMissing(PathSet(paths.begin(), paths.end()), willBuild,
-                      willSubstitute, unknown, downloadSize, narSize);
-
-  if (ignoreUnknown) {
-    Paths paths2;
-    for (auto& i : paths) {
-      if (unknown.find(i) == unknown.end()) {
-        paths2.push_back(i);
-      }
-    }
-    paths = paths2;
-    unknown = PathSet();
-  }
-
-  if (settings.printMissing) {
-    printMissing(ref<Store>(store), willBuild, willSubstitute, unknown,
-                 downloadSize, narSize);
-  }
-
-  if (dryRun) {
-    return;
-  }
-
-  /* Build all paths at the same time to exploit parallelism. */
-  util::OkOrThrow(store->buildPaths(
-      std::cerr, PathSet(paths.begin(), paths.end()), buildMode));
-
-  if (!ignoreUnknown) {
-    for (auto& i : paths) {
-      PathSet paths = realisePath(i, false);
-      if (!noOutput) {
-        for (auto& j : paths) {
-          cout << format("%1%\n") % j;
-        }
-      }
-    }
-  }
-}
-
-/* Add files to the Nix store and print the resulting paths. */
-static void opAdd(Strings opFlags, Strings opArgs) {
-  if (!opFlags.empty()) {
-    throw UsageError("unknown flag");
-  }
-
-  for (auto& i : opArgs) {
-    cout << format("%1%\n") % store->addToStore(baseNameOf(i), i);
-  }
-}
-
-/* Preload the output of a fixed-output derivation into the Nix
-   store. */
-static void opAddFixed(Strings opFlags, Strings opArgs) {
-  bool recursive = false;
-
-  for (auto& i : opFlags) {
-    if (i == "--recursive") {
-      recursive = true;
-    } else {
-      throw UsageError(format("unknown flag '%1%'") % i);
-    }
-  }
-
-  if (opArgs.empty()) {
-    throw UsageError("first argument must be hash algorithm");
-  }
-
-  HashType hashAlgo = parseHashType(opArgs.front());
-  opArgs.pop_front();
-
-  for (auto& i : opArgs) {
-    cout << format("%1%\n") %
-                store->addToStore(baseNameOf(i), i, recursive, hashAlgo);
-  }
-}
-
-/* Hack to support caching in `nix-prefetch-url'. */
-static void opPrintFixedPath(Strings opFlags, Strings opArgs) {
-  bool recursive = false;
-
-  for (auto i : opFlags) {
-    if (i == "--recursive") {
-      recursive = true;
-    } else {
-      throw UsageError(format("unknown flag '%1%'") % i);
-    }
-  }
-
-  if (opArgs.size() != 3) {
-    throw UsageError(format("'--print-fixed-path' requires three arguments"));
-  }
-
-  auto i = opArgs.begin();
-  HashType hashAlgo = parseHashType(*i++);
-  std::string hash = *i++;
-  std::string name = *i++;
-
-  auto hash_ = Hash::deserialize(hash, hashAlgo);
-  Hash::unwrap_throw(hash_);
-
-  cout << absl::StrCat(store->makeFixedOutputPath(recursive, *hash_, name),
-                       "\n");
-}
-
-static PathSet maybeUseOutputs(const Path& storePath, bool useOutput,
-                               bool forceRealise) {
-  if (forceRealise) {
-    realisePath(storePath);
-  }
-  if (useOutput && isDerivation(storePath)) {
-    Derivation drv = store->derivationFromPath(storePath);
-    PathSet outputs;
-    for (auto& i : drv.outputs) {
-      outputs.insert(i.second.path);
-    }
-    return outputs;
-  }
-  return {storePath};
-}
-
-/* Some code to print a tree representation of a derivation dependency
-   graph.  Topological sorting is used to keep the tree relatively
-   flat. */
-
-const std::string treeConn = "+---";
-const std::string treeLine = "|   ";
-const std::string treeNull = "    ";
-
-static void printTree(const Path& path, const std::string& firstPad,
-                      const std::string& tailPad, PathSet& done) {
-  if (done.find(path) != done.end()) {
-    cout << format("%1%%2% [...]\n") % firstPad % path;
-    return;
-  }
-  done.insert(path);
-
-  cout << format("%1%%2%\n") % firstPad % path;
-
-  auto references = store->queryPathInfo(path)->references;
-
-  /* Topologically sort under the relation A < B iff A \in
-     closure(B).  That is, if derivation A is an (possibly indirect)
-     input of B, then A is printed first.  This has the effect of
-     flattening the tree, preventing deeply nested structures.  */
-  Paths sorted = store->topoSortPaths(references);
-  reverse(sorted.begin(), sorted.end());
-
-  for (auto i = sorted.begin(); i != sorted.end(); ++i) {
-    auto j = i;
-    ++j;
-    printTree(*i, tailPad + treeConn,
-              j == sorted.end() ? tailPad + treeNull : tailPad + treeLine,
-              done);
-  }
-}
-
-/* Perform various sorts of queries. */
-static void opQuery(Strings opFlags, Strings opArgs) {
-  enum QueryType {
-    qDefault,
-    qOutputs,
-    qRequisites,
-    qReferences,
-    qReferrers,
-    qReferrersClosure,
-    qDeriver,
-    qBinding,
-    qHash,
-    qSize,
-    qTree,
-    qGraph,
-    qGraphML,
-    qResolve,
-    qRoots
-  };
-  QueryType query = qDefault;
-  bool useOutput = false;
-  bool includeOutputs = false;
-  bool forceRealise = false;
-  std::string bindingName;
-
-  for (auto& i : opFlags) {
-    QueryType prev = query;
-    if (i == "--outputs") {
-      query = qOutputs;
-    } else if (i == "--requisites" || i == "-R") {
-      query = qRequisites;
-    } else if (i == "--references") {
-      query = qReferences;
-    } else if (i == "--referrers" || i == "--referers") {
-      query = qReferrers;
-    } else if (i == "--referrers-closure" || i == "--referers-closure") {
-      query = qReferrersClosure;
-    } else if (i == "--deriver" || i == "-d") {
-      query = qDeriver;
-    } else if (i == "--binding" || i == "-b") {
-      if (opArgs.empty()) {
-        throw UsageError("expected binding name");
-      }
-      bindingName = opArgs.front();
-      opArgs.pop_front();
-      query = qBinding;
-    } else if (i == "--hash") {
-      query = qHash;
-    } else if (i == "--size") {
-      query = qSize;
-    } else if (i == "--tree") {
-      query = qTree;
-    } else if (i == "--graph") {
-      query = qGraph;
-    } else if (i == "--graphml") {
-      query = qGraphML;
-    } else if (i == "--resolve") {
-      query = qResolve;
-    } else if (i == "--roots") {
-      query = qRoots;
-    } else if (i == "--use-output" || i == "-u") {
-      useOutput = true;
-    } else if (i == "--force-realise" || i == "--force-realize" || i == "-f") {
-      forceRealise = true;
-    } else if (i == "--include-outputs") {
-      includeOutputs = true;
-    } else {
-      throw UsageError(format("unknown flag '%1%'") % i);
-    }
-    if (prev != qDefault && prev != query) {
-      throw UsageError(format("query type '%1%' conflicts with earlier flag") %
-                       i);
-    }
-  }
-
-  if (query == qDefault) {
-    query = qOutputs;
-  }
-
-  RunPager pager;
-
-  switch (query) {
-    case qOutputs: {
-      for (auto& i : opArgs) {
-        i = store->followLinksToStorePath(i);
-        if (forceRealise) {
-          realisePath(i);
-        }
-        Derivation drv = store->derivationFromPath(i);
-        for (auto& j : drv.outputs) {
-          cout << format("%1%\n") % j.second.path;
-        }
-      }
-      break;
-    }
-
-    case qRequisites:
-    case qReferences:
-    case qReferrers:
-    case qReferrersClosure: {
-      PathSet paths;
-      for (auto& i : opArgs) {
-        PathSet ps = maybeUseOutputs(store->followLinksToStorePath(i),
-                                     useOutput, forceRealise);
-        for (auto& j : ps) {
-          if (query == qRequisites) {
-            store->computeFSClosure(j, paths, false, includeOutputs);
-          } else if (query == qReferences) {
-            for (auto& p : store->queryPathInfo(j)->references) {
-              paths.insert(p);
-            }
-          } else if (query == qReferrers) {
-            store->queryReferrers(j, paths);
-          } else if (query == qReferrersClosure) {
-            store->computeFSClosure(j, paths, true);
-          }
-        }
-      }
-      Paths sorted = store->topoSortPaths(paths);
-      for (auto i = sorted.rbegin(); i != sorted.rend(); ++i) {
-        cout << format("%s\n") % *i;
-      }
-      break;
-    }
-
-    case qDeriver:
-      for (auto& i : opArgs) {
-        Path deriver =
-            store->queryPathInfo(store->followLinksToStorePath(i))->deriver;
-        cout << format("%1%\n") %
-                    (deriver.empty() ? "unknown-deriver" : deriver);
-      }
-      break;
-
-    case qBinding:
-      for (auto& i : opArgs) {
-        Path path = useDeriver(store->followLinksToStorePath(i));
-        Derivation drv = store->derivationFromPath(path);
-        auto j = drv.env.find(bindingName);
-        if (j == drv.env.end()) {
-          throw Error(
-              format(
-                  "derivation '%1%' has no environment binding named '%2%'") %
-              path % bindingName);
-        }
-        cout << format("%1%\n") % j->second;
-      }
-      break;
-
-    case qHash:
-    case qSize:
-      for (auto& i : opArgs) {
-        PathSet paths = maybeUseOutputs(store->followLinksToStorePath(i),
-                                        useOutput, forceRealise);
-        for (auto& j : paths) {
-          auto info = store->queryPathInfo(j);
-          if (query == qHash) {
-            assert(info->narHash.type == htSHA256);
-            cout << fmt("%s\n", info->narHash.to_string(Base32));
-          } else if (query == qSize) {
-            cout << fmt("%d\n", info->narSize);
-          }
-        }
-      }
-      break;
-
-    case qTree: {
-      PathSet done;
-      for (auto& i : opArgs) {
-        printTree(store->followLinksToStorePath(i), "", "", done);
-      }
-      break;
-    }
-
-    case qGraph: {
-      PathSet roots;
-      for (auto& i : opArgs) {
-        PathSet paths = maybeUseOutputs(store->followLinksToStorePath(i),
-                                        useOutput, forceRealise);
-        roots.insert(paths.begin(), paths.end());
-      }
-      printDotGraph(ref<Store>(store), roots);
-      break;
-    }
-
-    case qGraphML: {
-      PathSet roots;
-      for (auto& i : opArgs) {
-        PathSet paths = maybeUseOutputs(store->followLinksToStorePath(i),
-                                        useOutput, forceRealise);
-        roots.insert(paths.begin(), paths.end());
-      }
-      printGraphML(ref<Store>(store), roots);
-      break;
-    }
-
-    case qResolve: {
-      for (auto& i : opArgs) {
-        cout << format("%1%\n") % store->followLinksToStorePath(i);
-      }
-      break;
-    }
-
-    case qRoots: {
-      PathSet referrers;
-      for (auto& i : opArgs) {
-        store->computeFSClosure(
-            maybeUseOutputs(store->followLinksToStorePath(i), useOutput,
-                            forceRealise),
-            referrers, true, settings.gcKeepOutputs,
-            settings.gcKeepDerivations);
-      }
-      Roots roots = store->findRoots(false);
-      for (auto& [target, links] : roots) {
-        if (referrers.find(target) != referrers.end()) {
-          for (auto& link : links) {
-            cout << format("%1% -> %2%\n") % link % target;
-          }
-        }
-      }
-      break;
-    }
-
-    default:
-      abort();
-  }
-}
-
-static void opPrintEnv(Strings opFlags, Strings opArgs) {
-  if (!opFlags.empty()) {
-    throw UsageError("unknown flag");
-  }
-  if (opArgs.size() != 1) {
-    throw UsageError("'--print-env' requires one derivation store path");
-  }
-
-  Path drvPath = opArgs.front();
-  Derivation drv = store->derivationFromPath(drvPath);
-
-  /* Print each environment variable in the derivation in a format
-     that can be sourced by the shell. */
-  for (auto& i : drv.env) {
-    cout << format("export %1%; %1%=%2%\n") % i.first % shellEscape(i.second);
-  }
-
-  /* Also output the arguments.  This doesn't preserve whitespace in
-     arguments. */
-  cout << "export _args; _args='";
-  bool first = true;
-  for (auto& i : drv.args) {
-    if (!first) {
-      cout << ' ';
-    }
-    first = false;
-    cout << shellEscape(i);
-  }
-  cout << "'\n";
-}
-
-static void opReadLog(Strings opFlags, Strings opArgs) {
-  if (!opFlags.empty()) {
-    throw UsageError("unknown flag");
-  }
-
-  RunPager pager;
-
-  for (auto& i : opArgs) {
-    auto path = store->followLinksToStorePath(i);
-    auto log = store->getBuildLog(path);
-    if (!log) {
-      throw Error("build log of derivation '%s' is not available", path);
-    }
-    std::cout << *log;
-  }
-}
-
-static void opDumpDB(Strings opFlags, Strings opArgs) {
-  if (!opFlags.empty()) {
-    throw UsageError("unknown flag");
-  }
-  if (!opArgs.empty()) {
-    for (auto& i : opArgs) {
-      i = store->followLinksToStorePath(i);
-    }
-    for (auto& i : opArgs) {
-      cout << store->makeValidityRegistration({i}, true, true);
-    }
-  } else {
-    PathSet validPaths = store->queryAllValidPaths();
-    for (auto& i : validPaths) {
-      cout << store->makeValidityRegistration({i}, true, true);
-    }
-  }
-}
-
-static void registerValidity(bool reregister, bool hashGiven,
-                             bool canonicalise) {
-  ValidPathInfos infos;
-
-  while (true) {
-    ValidPathInfo info = decodeValidPathInfo(cin, hashGiven);
-    if (info.path.empty()) {
-      break;
-    }
-    if (!store->isValidPath(info.path) || reregister) {
-      /* !!! races */
-      if (canonicalise) {
-        canonicalisePathMetaData(info.path, -1);
-      }
-      if (!hashGiven) {
-        HashResult hash = hashPath(htSHA256, info.path);
-        info.narHash = hash.first;
-        info.narSize = hash.second;
-      }
-      infos.push_back(info);
-    }
-  }
-
-  ensureLocalStore()->registerValidPaths(infos);
-}
-
-static void opLoadDB(Strings opFlags, Strings opArgs) {
-  if (!opFlags.empty()) {
-    throw UsageError("unknown flag");
-  }
-  if (!opArgs.empty()) {
-    throw UsageError("no arguments expected");
-  }
-  registerValidity(true, true, false);
-}
-
-static void opRegisterValidity(Strings opFlags, Strings opArgs) {
-  bool reregister = false;  // !!! maybe this should be the default
-  bool hashGiven = false;
-
-  for (auto& i : opFlags) {
-    if (i == "--reregister") {
-      reregister = true;
-    } else if (i == "--hash-given") {
-      hashGiven = true;
-    } else {
-      throw UsageError(format("unknown flag '%1%'") % i);
-    }
-  }
-
-  if (!opArgs.empty()) {
-    throw UsageError("no arguments expected");
-  }
-
-  registerValidity(reregister, hashGiven, true);
-}
-
-static void opCheckValidity(Strings opFlags, Strings opArgs) {
-  bool printInvalid = false;
-
-  for (auto& i : opFlags) {
-    if (i == "--print-invalid") {
-      printInvalid = true;
-    } else {
-      throw UsageError(format("unknown flag '%1%'") % i);
-    }
-  }
-
-  for (auto& i : opArgs) {
-    Path path = store->followLinksToStorePath(i);
-    if (!store->isValidPath(path)) {
-      if (printInvalid) {
-        cout << format("%1%\n") % path;
-      } else {
-        throw Error(format("path '%1%' is not valid") % path);
-      }
-    }
-  }
-}
-
-static void opGC(Strings opFlags, Strings opArgs) {
-  bool printRoots = false;
-  GCOptions options;
-  options.action = GCOptions::gcDeleteDead;
-
-  GCResults results;
-
-  /* Do what? */
-  for (auto i = opFlags.begin(); i != opFlags.end(); ++i) {
-    if (*i == "--print-roots") {
-      printRoots = true;
-    } else if (*i == "--print-live") {
-      options.action = GCOptions::gcReturnLive;
-    } else if (*i == "--print-dead") {
-      options.action = GCOptions::gcReturnDead;
-    } else if (*i == "--delete") {
-      options.action = GCOptions::gcDeleteDead;
-    } else if (*i == "--max-freed") {
-      auto maxFreed = getIntArg<long long>(*i, i, opFlags.end(), true);
-      options.maxFreed = maxFreed >= 0 ? maxFreed : 0;
-    } else {
-      throw UsageError(format("bad sub-operation '%1%' in GC") % *i);
-    }
-  }
-
-  if (!opArgs.empty()) {
-    throw UsageError("no arguments expected");
-  }
-
-  if (printRoots) {
-    Roots roots = store->findRoots(false);
-    std::set<std::pair<Path, Path>> roots2;
-    // Transpose and sort the roots.
-    for (auto& [target, links] : roots) {
-      for (auto& link : links) {
-        roots2.emplace(link, target);
-      }
-    }
-    for (auto& [link, target] : roots2) {
-      std::cout << link << " -> " << target << "\n";
-    }
-  }
-
-  else {
-    PrintFreed freed(options.action == GCOptions::gcDeleteDead, results);
-    store->collectGarbage(options, results);
-
-    if (options.action != GCOptions::gcDeleteDead) {
-      for (auto& i : results.paths) {
-        cout << i << std::endl;
-      }
-    }
-  }
-}
-
-/* Remove paths from the Nix store if possible (i.e., if they do not
-   have any remaining referrers and are not reachable from any GC
-   roots). */
-static void opDelete(Strings opFlags, Strings opArgs) {
-  GCOptions options;
-  options.action = GCOptions::gcDeleteSpecific;
-
-  for (auto& i : opFlags) {
-    if (i == "--ignore-liveness") {
-      options.ignoreLiveness = true;
-    } else {
-      throw UsageError(format("unknown flag '%1%'") % i);
-    }
-  }
-
-  for (auto& i : opArgs) {
-    options.pathsToDelete.insert(store->followLinksToStorePath(i));
-  }
-
-  GCResults results;
-  PrintFreed freed(true, results);
-  store->collectGarbage(options, results);
-}
-
-/* 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");
-  }
-
-  FdSink sink(STDOUT_FILENO);
-  std::string path = *opArgs.begin();
-  dumpPath(path, sink);
-  sink.flush();
-}
-
-/* Restore a value from a Nix archive.  The archive is read from
-   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");
-  }
-
-  FdSource source(STDIN_FILENO);
-  restorePath(*opArgs.begin(), source);
-}
-
-static void opExport(Strings opFlags, Strings opArgs) {
-  for (auto& i : opFlags) {
-    throw UsageError(format("unknown flag '%1%'") % i);
-  }
-
-  for (auto& i : opArgs) {
-    i = store->followLinksToStorePath(i);
-  }
-
-  FdSink sink(STDOUT_FILENO);
-  store->exportPaths(opArgs, sink);
-  sink.flush();
-}
-
-static void opImport(Strings opFlags, Strings opArgs) {
-  for (auto& i : opFlags) {
-    throw UsageError(format("unknown flag '%1%'") % i);
-  }
-
-  if (!opArgs.empty()) {
-    throw UsageError("no arguments expected");
-  }
-
-  FdSource source(STDIN_FILENO);
-  Paths paths = store->importPaths(source, nullptr, NoCheckSigs);
-
-  for (auto& i : paths) {
-    cout << format("%1%\n") % i << std::flush;
-  }
-}
-
-/* Initialise the Nix databases. */
-static void opInit(Strings opFlags, Strings opArgs) {
-  if (!opFlags.empty()) {
-    throw UsageError("unknown flag");
-  }
-  if (!opArgs.empty()) {
-    throw UsageError("no arguments expected");
-  }
-  /* Doesn't do anything right now; database tables are initialised
-     automatically. */
-}
-
-/* Verify the consistency of the Nix environment. */
-static void opVerify(Strings opFlags, Strings opArgs) {
-  if (!opArgs.empty()) {
-    throw UsageError("no arguments expected");
-  }
-
-  bool checkContents = false;
-  RepairFlag repair = NoRepair;
-
-  for (auto& i : opFlags) {
-    if (i == "--check-contents") {
-      checkContents = true;
-    } else if (i == "--repair") {
-      repair = Repair;
-    } else {
-      throw UsageError(format("unknown flag '%1%'") % i);
-    }
-  }
-
-  if (store->verifyStore(checkContents, repair)) {
-    LOG(WARNING) << "not all errors were fixed";
-    throw Exit(1);
-  }
-}
-
-/* Verify whether the contents of the given store path have not changed. */
-static void opVerifyPath(Strings opFlags, Strings opArgs) {
-  if (!opFlags.empty()) {
-    throw UsageError("no flags expected");
-  }
-
-  int status = 0;
-
-  for (auto& i : opArgs) {
-    Path path = store->followLinksToStorePath(i);
-    LOG(INFO) << "checking path '" << path << "'...";
-    auto info = store->queryPathInfo(path);
-    HashSink sink(info->narHash.type);
-    store->narFromPath(path, sink);
-    auto current = sink.finish();
-    if (current.first != info->narHash) {
-      LOG(ERROR) << "path '" << path << "' was modified! expected hash '"
-                 << info->narHash.to_string() << "', got '"
-                 << current.first.to_string() << "'";
-      status = 1;
-    }
-  }
-
-  throw Exit(status);
-}
-
-/* Repair the contents of the given path by redownloading it using a
-   substituter (if available). */
-static void opRepairPath(Strings opFlags, Strings opArgs) {
-  if (!opFlags.empty()) {
-    throw UsageError("no flags expected");
-  }
-
-  for (auto& i : opArgs) {
-    Path path = store->followLinksToStorePath(i);
-    ensureLocalStore()->repairPath(path);
-  }
-}
-
-/* Optimise the disk space usage of the Nix store by hard-linking
-   files with the same contents. */
-static void opOptimise(Strings opFlags, Strings opArgs) {
-  if (!opArgs.empty() || !opFlags.empty()) {
-    throw UsageError("no arguments expected");
-  }
-
-  store->optimiseStore();
-}
-
-/* Serve the nix store in a way usable by a restricted ssh user. */
-static void opServe(Strings opFlags, Strings opArgs) {
-  bool writeAllowed = false;
-  for (auto& i : opFlags) {
-    if (i == "--write") {
-      writeAllowed = true;
-    } else {
-      throw UsageError(format("unknown flag '%1%'") % i);
-    }
-  }
-
-  if (!opArgs.empty()) {
-    throw UsageError("no arguments expected");
-  }
-
-  FdSource in(STDIN_FILENO);
-  FdSink out(STDOUT_FILENO);
-
-  /* Exchange the greeting. */
-  unsigned int magic = readInt(in);
-  if (magic != SERVE_MAGIC_1) {
-    throw Error("protocol mismatch");
-  }
-  out << SERVE_MAGIC_2 << SERVE_PROTOCOL_VERSION;
-  out.flush();
-  unsigned int clientVersion = readInt(in);
-
-  auto getBuildSettings = [&]() {
-    // FIXME: changing options here doesn't work if we're
-    // building through the daemon.
-    settings.keepLog = false;
-    settings.useSubstitutes = false;
-    settings.maxSilentTime = readInt(in);
-    settings.buildTimeout = readInt(in);
-    if (GET_PROTOCOL_MINOR(clientVersion) >= 2) {
-      settings.maxLogSize = readNum<unsigned long>(in);
-    }
-    if (GET_PROTOCOL_MINOR(clientVersion) >= 3) {
-      settings.buildRepeat = readInt(in);
-      settings.enforceDeterminism = readInt(in) != 0u;
-      settings.runDiffHook = true;
-    }
-    settings.printRepeatedBuilds = false;
-  };
-
-  while (true) {
-    ServeCommand cmd;
-    try {
-      cmd = static_cast<ServeCommand>(readInt(in));
-    } catch (EndOfFile& e) {
-      break;
-    }
-
-    switch (cmd) {
-      case cmdQueryValidPaths: {
-        bool lock = readInt(in) != 0u;
-        bool substitute = readInt(in) != 0u;
-        auto paths = readStorePaths<PathSet>(*store, in);
-        if (lock && writeAllowed) {
-          for (auto& path : paths) {
-            store->addTempRoot(path);
-          }
-        }
-
-        /* If requested, substitute missing paths. This
-           implements nix-copy-closure's --use-substitutes
-           flag. */
-        if (substitute && writeAllowed) {
-          /* Filter out .drv files (we don't want to build anything). */
-          PathSet paths2;
-          for (auto& path : paths) {
-            if (!isDerivation(path)) {
-              paths2.insert(path);
-            }
-          }
-          unsigned long long downloadSize;
-          unsigned long long narSize;
-          PathSet willBuild;
-          PathSet willSubstitute;
-          PathSet unknown;
-          store->queryMissing(PathSet(paths2.begin(), paths2.end()), willBuild,
-                              willSubstitute, unknown, downloadSize, narSize);
-          /* FIXME: should use ensurePath(), but it only
-             does one path at a time. */
-          if (!willSubstitute.empty()) {
-            try {
-              util::OkOrThrow(store->buildPaths(std::cerr, willSubstitute));
-            } catch (Error& e) {
-              LOG(WARNING) << e.msg();
-            }
-          }
-        }
-
-        out << store->queryValidPaths(paths);
-        break;
-      }
-
-      case cmdQueryPathInfos: {
-        auto paths = readStorePaths<PathSet>(*store, in);
-        // !!! Maybe we want a queryPathInfos?
-        for (auto& i : paths) {
-          try {
-            auto info = store->queryPathInfo(i);
-            out << info->path << info->deriver << info->references;
-            // !!! Maybe we want compression?
-            out << info->narSize  // downloadSize
-                << info->narSize;
-            if (GET_PROTOCOL_MINOR(clientVersion) >= 4) {
-              out << (info->narHash ? info->narHash.to_string() : "")
-                  << info->ca << info->sigs;
-            }
-          } catch (InvalidPath&) {
-          }
-        }
-        out << "";
-        break;
-      }
-
-      case cmdDumpStorePath:
-        store->narFromPath(readStorePath(*store, in), out);
-        break;
-
-      case cmdImportPaths: {
-        if (!writeAllowed) {
-          throw Error("importing paths is not allowed");
-        }
-        store->importPaths(in, nullptr,
-                           NoCheckSigs);  // FIXME: should we skip sig checking?
-        out << 1;                         // indicate success
-        break;
-      }
-
-      case cmdExportPaths: {
-        readInt(in);  // obsolete
-        store->exportPaths(readStorePaths<Paths>(*store, in), out);
-        break;
-      }
-
-      case cmdBuildPaths: {
-        if (!writeAllowed) {
-          throw Error("building paths is not allowed");
-        }
-        auto paths = readStorePaths<PathSet>(*store, in);
-
-        getBuildSettings();
-
-        try {
-          MonitorFdHup monitor(in.fd);
-          util::OkOrThrow(store->buildPaths(std::cerr, paths));
-          out << 0;
-        } catch (Error& e) {
-          assert(e.status);
-          out << e.status << e.msg();
-        }
-        break;
-      }
-
-      case cmdBuildDerivation: { /* Used by hydra-queue-runner. */
-
-        if (!writeAllowed) {
-          throw Error("building paths is not allowed");
-        }
-
-        Path drvPath = readStorePath(*store, in);  // informational only
-        BasicDerivation drv;
-        readDerivation(in, *store, drv);
-
-        getBuildSettings();
-
-        MonitorFdHup monitor(in.fd);
-        auto status = store->buildDerivation(std::cerr, drvPath, drv);
-
-        out << status.status << status.errorMsg;
-
-        if (GET_PROTOCOL_MINOR(clientVersion) >= 3) {
-          out << status.timesBuilt
-              << static_cast<uint64_t>(status.isNonDeterministic)
-              << status.startTime << status.stopTime;
-        }
-
-        break;
-      }
-
-      case cmdQueryClosure: {
-        bool includeOutputs = readInt(in) != 0u;
-        PathSet closure;
-        store->computeFSClosure(readStorePaths<PathSet>(*store, in), closure,
-                                false, includeOutputs);
-        out << closure;
-        break;
-      }
-
-      case cmdAddToStoreNar: {
-        if (!writeAllowed) {
-          throw Error("importing paths is not allowed");
-        }
-
-        ValidPathInfo info;
-        info.path = readStorePath(*store, in);
-        in >> info.deriver;
-        if (!info.deriver.empty()) {
-          store->assertStorePath(info.deriver);
-        }
-        auto hash_ = Hash::deserialize(readString(in), htSHA256);
-        info.narHash = Hash::unwrap_throw(hash_);
-        info.references = readStorePaths<PathSet>(*store, in);
-        in >> info.registrationTime >> info.narSize >> info.ultimate;
-        info.sigs = readStrings<StringSet>(in);
-        in >> info.ca;
-
-        if (info.narSize == 0) {
-          throw Error("narInfo is too old and missing the narSize field");
-        }
-
-        SizedSource sizedSource(in, info.narSize);
-
-        store->addToStore(info, sizedSource, NoRepair, NoCheckSigs);
-
-        // consume all the data that has been sent before continuing.
-        sizedSource.drainAll();
-
-        out << 1;  // indicate success
-
-        break;
-      }
-
-      default:
-        throw Error(format("unknown serve command %1%") % cmd);
-    }
-
-    out.flush();
-  }
-}
-
-static void opGenerateBinaryCacheKey(Strings opFlags, Strings opArgs) {
-  for (auto& i : opFlags) {
-    throw UsageError(format("unknown flag '%1%'") % i);
-  }
-
-  if (opArgs.size() != 3) {
-    throw UsageError("three arguments expected");
-  }
-  auto i = opArgs.begin();
-  std::string keyName = *i++;
-  std::string secretKeyFile = *i++;
-  std::string publicKeyFile = *i++;
-
-#if HAVE_SODIUM
-  if (sodium_init() == -1) {
-    throw Error("could not initialise libsodium");
-  }
-
-  unsigned char pk[crypto_sign_PUBLICKEYBYTES];
-  unsigned char sk[crypto_sign_SECRETKEYBYTES];
-  if (crypto_sign_keypair(pk, sk) != 0) {
-    throw Error("key generation failed");
-  }
-
-  writeFile(publicKeyFile,
-            keyName + ":" +
-                absl::Base64Escape(std::string(reinterpret_cast<char*>(pk),
-                                               crypto_sign_PUBLICKEYBYTES)));
-  umask(0077);
-  writeFile(secretKeyFile,
-            keyName + ":" +
-                absl::Base64Escape(std::string(reinterpret_cast<char*>(sk),
-                                               crypto_sign_SECRETKEYBYTES)));
-#else
-  throw Error(
-      "Nix was not compiled with libsodium, required for signed binary cache "
-      "support");
-#endif
-}
-
-static void opVersion(Strings opFlags, Strings opArgs) {
-  printVersion("nix-store");
-}
-
-/* Scan the arguments; find the operation, set global flags, put all
-   other flags in a list, and put all other arguments in another
-   list. */
-static int _main(int argc, char** argv) {
-  {
-    Strings opFlags;
-    Strings opArgs;
-    Operation op = nullptr;
-
-    parseCmdLine(argc, argv,
-                 [&](Strings::iterator& arg, const Strings::iterator& end) {
-                   Operation oldOp = op;
-
-                   if (*arg == "--help") {
-                     showManPage("nix-store");
-                   } else if (*arg == "--version") {
-                     op = opVersion;
-                   } else if (*arg == "--realise" || *arg == "--realize" ||
-                              *arg == "-r") {
-                     op = opRealise;
-                   } else if (*arg == "--add" || *arg == "-A") {
-                     op = opAdd;
-                   } else if (*arg == "--add-fixed") {
-                     op = opAddFixed;
-                   } else if (*arg == "--print-fixed-path") {
-                     op = opPrintFixedPath;
-                   } else if (*arg == "--delete") {
-                     op = opDelete;
-                   } else if (*arg == "--query" || *arg == "-q") {
-                     op = opQuery;
-                   } else if (*arg == "--print-env") {
-                     op = opPrintEnv;
-                   } else if (*arg == "--read-log" || *arg == "-l") {
-                     op = opReadLog;
-                   } else if (*arg == "--dump-db") {
-                     op = opDumpDB;
-                   } else if (*arg == "--load-db") {
-                     op = opLoadDB;
-                   } else if (*arg == "--register-validity") {
-                     op = opRegisterValidity;
-                   } else if (*arg == "--check-validity") {
-                     op = opCheckValidity;
-                   } else if (*arg == "--gc") {
-                     op = opGC;
-                   } else if (*arg == "--dump") {
-                     op = opDump;
-                   } else if (*arg == "--restore") {
-                     op = opRestore;
-                   } else if (*arg == "--export") {
-                     op = opExport;
-                   } else if (*arg == "--import") {
-                     op = opImport;
-                   } else if (*arg == "--init") {
-                     op = opInit;
-                   } else if (*arg == "--verify") {
-                     op = opVerify;
-                   } else if (*arg == "--verify-path") {
-                     op = opVerifyPath;
-                   } else if (*arg == "--repair-path") {
-                     op = opRepairPath;
-                   } else if (*arg == "--optimise" || *arg == "--optimize") {
-                     op = opOptimise;
-                   } else if (*arg == "--serve") {
-                     op = opServe;
-                   } else if (*arg == "--generate-binary-cache-key") {
-                     op = opGenerateBinaryCacheKey;
-                   } else if (*arg == "--add-root") {
-                     gcRoot = absPath(getArg(*arg, arg, end));
-                   } else if (*arg == "--indirect") {
-                     indirectRoot = true;
-                   } else if (*arg == "--no-output") {
-                     noOutput = true;
-                   } else if (*arg != "" && arg->at(0) == '-') {
-                     opFlags.push_back(*arg);
-                     if (*arg == "--max-freed" || *arg == "--max-links" ||
-                         *arg == "--max-atime") { /* !!! hack */
-                       opFlags.push_back(getArg(*arg, arg, end));
-                     }
-                   } else {
-                     opArgs.push_back(*arg);
-                   }
-
-                   if ((oldOp != nullptr) && oldOp != op) {
-                     throw UsageError("only one operation may be specified");
-                   }
-
-                   return true;
-                 });
-
-    if (op == nullptr) {
-      throw UsageError("no operation specified");
-    }
-
-    if (op != opDump && op != opRestore) { /* !!! hack */
-      store = openStore();
-    }
-
-    op(opFlags, opArgs);
-
-    return 0;
-  }
-}
-
-static RegisterLegacyCommand s1("nix-store", _main);