aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/backport.yml2
-rw-r--r--docker.nix12
-rw-r--r--src/libcmd/repl.cc1
-rw-r--r--src/libexpr/eval.cc154
-rw-r--r--src/libexpr/primops.cc13
-rw-r--r--src/libexpr/value-to-json.cc50
-rw-r--r--src/libexpr/value-to-json.hh7
-rw-r--r--src/libexpr/value.hh6
-rw-r--r--src/libstore/binary-cache-store.cc18
-rw-r--r--src/libstore/build/derivation-goal.cc1
-rw-r--r--src/libstore/build/local-derivation-goal.cc2
-rw-r--r--src/libstore/gc.cc3
-rw-r--r--src/libstore/nar-accessor.cc30
-rw-r--r--src/libstore/nar-accessor.hh6
-rw-r--r--src/libstore/parsed-derivations.cc16
-rw-r--r--src/libstore/remote-fs-accessor.cc8
-rw-r--r--src/libstore/store-api.cc48
-rw-r--r--src/libstore/store-api.hh4
-rw-r--r--src/libutil/json.cc203
-rw-r--r--src/libutil/json.hh185
-rw-r--r--src/libutil/tests/json.cc193
-rw-r--r--src/nix-env/nix-env.cc35
-rw-r--r--src/nix/eval.cc7
-rw-r--r--src/nix/flake.cc37
-rw-r--r--src/nix/ls.cc5
-rw-r--r--src/nix/make-content-addressed.cc12
-rw-r--r--src/nix/path-info.cc8
-rw-r--r--src/nix/search.cc19
-rw-r--r--src/nix/show-derivation.cc67
-rw-r--r--src/nix/why-depends.cc39
-rw-r--r--tests/ca/why-depends.sh5
31 files changed, 323 insertions, 873 deletions
diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml
index 75be788ef..7568145b6 100644
--- a/.github/workflows/backport.yml
+++ b/.github/workflows/backport.yml
@@ -21,7 +21,7 @@ jobs:
fetch-depth: 0
- name: Create backport PRs
# should be kept in sync with `version`
- uses: zeebe-io/backport-action@v0.0.8
+ uses: zeebe-io/backport-action@v0.0.9
with:
# Config README: https://github.com/zeebe-io/backport-action#backport-action
github_token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/docker.nix b/docker.nix
index bb2b4e7ff..203a06b53 100644
--- a/docker.nix
+++ b/docker.nix
@@ -36,6 +36,17 @@ let
shell = "${pkgs.bashInteractive}/bin/bash";
home = "/root";
gid = 0;
+ groups = [ "root" ];
+ description = "System administrator";
+ };
+
+ nobody = {
+ uid = 65534;
+ shell = "${pkgs.shadow}/bin/nologin";
+ home = "/var/empty";
+ gid = 65534;
+ groups = [ "nobody" ];
+ description = "Unprivileged account (don't use!)";
};
} // lib.listToAttrs (
@@ -57,6 +68,7 @@ let
groups = {
root.gid = 0;
nixbld.gid = 30000;
+ nobody.gid = 65534;
};
userToPasswd = (
diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc
index bb254ff8d..557952277 100644
--- a/src/libcmd/repl.cc
+++ b/src/libcmd/repl.cc
@@ -270,6 +270,7 @@ void NixRepl::mainLoop()
// ctrl-D should exit the debugger.
state->debugStop = false;
state->debugQuit = true;
+ logger->cout("");
break;
}
try {
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 563f24e48..c759acc10 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -7,7 +7,6 @@
#include "globals.hh"
#include "eval-inline.hh"
#include "filetransfer.hh"
-#include "json.hh"
#include "function-trace.hh"
#include <algorithm>
@@ -21,6 +20,7 @@
#include <functional>
#include <sys/resource.h>
+#include <nlohmann/json.hpp>
#if HAVE_BOEHMGC
@@ -35,6 +35,8 @@
#endif
+using json = nlohmann::json;
+
namespace nix {
static char * allocString(size_t size)
@@ -69,15 +71,11 @@ static char * dupString(const char * s)
// empty string.
static const char * makeImmutableStringWithLen(const char * s, size_t size)
{
- char * t;
if (size == 0)
return "";
-#if HAVE_BOEHMGC
- t = GC_STRNDUP(s, size);
-#else
- t = strndup(s, size);
-#endif
- if (!t) throw std::bad_alloc();
+ auto t = allocString(size + 1);
+ memcpy(t, s, size);
+ t[size] = 0;
return t;
}
@@ -2441,97 +2439,97 @@ void EvalState::printStats()
std::fstream fs;
if (outPath != "-")
fs.open(outPath, std::fstream::out);
- JSONObject topObj(outPath == "-" ? std::cerr : fs, true);
- topObj.attr("cpuTime",cpuTime);
- {
- auto envs = topObj.object("envs");
- envs.attr("number", nrEnvs);
- envs.attr("elements", nrValuesInEnvs);
- envs.attr("bytes", bEnvs);
- }
- {
- auto lists = topObj.object("list");
- lists.attr("elements", nrListElems);
- lists.attr("bytes", bLists);
- lists.attr("concats", nrListConcats);
- }
- {
- auto values = topObj.object("values");
- values.attr("number", nrValues);
- values.attr("bytes", bValues);
- }
- {
- auto syms = topObj.object("symbols");
- syms.attr("number", symbols.size());
- syms.attr("bytes", symbols.totalSize());
- }
- {
- auto sets = topObj.object("sets");
- sets.attr("number", nrAttrsets);
- sets.attr("bytes", bAttrsets);
- sets.attr("elements", nrAttrsInAttrsets);
- }
- {
- auto sizes = topObj.object("sizes");
- sizes.attr("Env", sizeof(Env));
- sizes.attr("Value", sizeof(Value));
- sizes.attr("Bindings", sizeof(Bindings));
- sizes.attr("Attr", sizeof(Attr));
- }
- topObj.attr("nrOpUpdates", nrOpUpdates);
- topObj.attr("nrOpUpdateValuesCopied", nrOpUpdateValuesCopied);
- topObj.attr("nrThunks", nrThunks);
- topObj.attr("nrAvoided", nrAvoided);
- topObj.attr("nrLookups", nrLookups);
- topObj.attr("nrPrimOpCalls", nrPrimOpCalls);
- topObj.attr("nrFunctionCalls", nrFunctionCalls);
+ json topObj = json::object();
+ topObj["cpuTime"] = cpuTime;
+ topObj["envs"] = {
+ {"number", nrEnvs},
+ {"elements", nrValuesInEnvs},
+ {"bytes", bEnvs},
+ };
+ topObj["list"] = {
+ {"elements", nrListElems},
+ {"bytes", bLists},
+ {"concats", nrListConcats},
+ };
+ topObj["values"] = {
+ {"number", nrValues},
+ {"bytes", bValues},
+ };
+ topObj["symbols"] = {
+ {"number", symbols.size()},
+ {"bytes", symbols.totalSize()},
+ };
+ topObj["sets"] = {
+ {"number", nrAttrsets},
+ {"bytes", bAttrsets},
+ {"elements", nrAttrsInAttrsets},
+ };
+ topObj["sizes"] = {
+ {"Env", sizeof(Env)},
+ {"Value", sizeof(Value)},
+ {"Bindings", sizeof(Bindings)},
+ {"Attr", sizeof(Attr)},
+ };
+ topObj["nrOpUpdates"] = nrOpUpdates;
+ topObj["nrOpUpdateValuesCopied"] = nrOpUpdateValuesCopied;
+ topObj["nrThunks"] = nrThunks;
+ topObj["nrAvoided"] = nrAvoided;
+ topObj["nrLookups"] = nrLookups;
+ topObj["nrPrimOpCalls"] = nrPrimOpCalls;
+ topObj["nrFunctionCalls"] = nrFunctionCalls;
#if HAVE_BOEHMGC
- {
- auto gc = topObj.object("gc");
- gc.attr("heapSize", heapSize);
- gc.attr("totalBytes", totalBytes);
- }
+ topObj["gc"] = {
+ {"heapSize", heapSize},
+ {"totalBytes", totalBytes},
+ };
#endif
if (countCalls) {
+ topObj["primops"] = primOpCalls;
{
- auto obj = topObj.object("primops");
- for (auto & i : primOpCalls)
- obj.attr(i.first, i.second);
- }
- {
- auto list = topObj.list("functions");
+ auto& list = topObj["functions"];
+ list = json::array();
for (auto & [fun, count] : functionCalls) {
- auto obj = list.object();
+ json obj = json::object();
if (fun->name)
- obj.attr("name", (std::string_view) symbols[fun->name]);
+ obj["name"] = (std::string_view) symbols[fun->name];
else
- obj.attr("name", nullptr);
+ obj["name"] = nullptr;
if (auto pos = positions[fun->pos]) {
- obj.attr("file", (std::string_view) pos.file);
- obj.attr("line", pos.line);
- obj.attr("column", pos.column);
+ obj["file"] = (std::string_view) pos.file;
+ obj["line"] = pos.line;
+ obj["column"] = pos.column;
}
- obj.attr("count", count);
+ obj["count"] = count;
+ list.push_back(obj);
}
}
{
- auto list = topObj.list("attributes");
+ auto list = topObj["attributes"];
+ list = json::array();
for (auto & i : attrSelects) {
- auto obj = list.object();
+ json obj = json::object();
if (auto pos = positions[i.first]) {
- obj.attr("file", (const std::string &) pos.file);
- obj.attr("line", pos.line);
- obj.attr("column", pos.column);
+ obj["file"] = (const std::string &) pos.file;
+ obj["line"] = pos.line;
+ obj["column"] = pos.column;
}
- obj.attr("count", i.second);
+ obj["count"] = i.second;
+ list.push_back(obj);
}
}
}
if (getEnv("NIX_SHOW_SYMBOLS").value_or("0") != "0") {
- auto list = topObj.list("symbols");
- symbols.dump([&](const std::string & s) { list.elem(s); });
+ // XXX: overrides earlier assignment
+ topObj["symbols"] = json::array();
+ auto &list = topObj["symbols"];
+ symbols.dump([&](const std::string & s) { list.emplace_back(s); });
+ }
+ if (outPath == "-") {
+ std::cerr << topObj.dump(2) << std::endl;
+ } else {
+ fs << topObj.dump(2) << std::endl;
}
}
}
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 22f6ad3cc..05265411c 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -8,12 +8,12 @@
#include "references.hh"
#include "store-api.hh"
#include "util.hh"
-#include "json.hh"
#include "value-to-json.hh"
#include "value-to-xml.hh"
#include "primops.hh"
#include <boost/container/small_vector.hpp>
+#include <nlohmann/json.hpp>
#include <sys/types.h>
#include <sys/stat.h>
@@ -1011,6 +1011,7 @@ static void prim_second(EvalState & state, const PosIdx pos, Value * * args, Val
derivation. */
static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{
+ using nlohmann::json;
state.forceAttrs(*args[0], pos);
/* Figure out the name first (for stack backtraces). */
@@ -1032,11 +1033,10 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * *
}
/* Check whether attributes should be passed as a JSON file. */
- std::ostringstream jsonBuf;
- std::unique_ptr<JSONObject> jsonObject;
+ std::optional<json> jsonObject;
attr = args[0]->attrs->find(state.sStructuredAttrs);
if (attr != args[0]->attrs->end() && state.forceBool(*attr->value, pos))
- jsonObject = std::make_unique<JSONObject>(jsonBuf);
+ jsonObject = json::object();
/* Check whether null attributes should be ignored. */
bool ignoreNulls = false;
@@ -1138,8 +1138,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * *
if (i->name == state.sStructuredAttrs) continue;
- auto placeholder(jsonObject->placeholder(key));
- printValueAsJSON(state, true, *i->value, pos, placeholder, context);
+ (*jsonObject)[key] = printValueAsJSON(state, true, *i->value, pos, context);
if (i->name == state.sBuilder)
drv.builder = state.forceString(*i->value, context, posDrvName);
@@ -1183,8 +1182,8 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * *
}
if (jsonObject) {
+ drv.env.emplace("__json", jsonObject->dump());
jsonObject.reset();
- drv.env.emplace("__json", jsonBuf.str());
}
/* Everything in the context of the strings in the derivation
diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc
index 4d63d8b49..5dc453b2e 100644
--- a/src/libexpr/value-to-json.cc
+++ b/src/libexpr/value-to-json.cc
@@ -1,84 +1,82 @@
#include "value-to-json.hh"
-#include "json.hh"
#include "eval-inline.hh"
#include "util.hh"
#include <cstdlib>
#include <iomanip>
+#include <nlohmann/json.hpp>
namespace nix {
-
-void printValueAsJSON(EvalState & state, bool strict,
- Value & v, const PosIdx pos, JSONPlaceholder & out, PathSet & context, bool copyToStore)
+using json = nlohmann::json;
+json printValueAsJSON(EvalState & state, bool strict,
+ Value & v, const PosIdx pos, PathSet & context, bool copyToStore)
{
checkInterrupt();
if (strict) state.forceValue(v, pos);
+ json out;
+
switch (v.type()) {
case nInt:
- out.write(v.integer);
+ out = v.integer;
break;
case nBool:
- out.write(v.boolean);
+ out = v.boolean;
break;
case nString:
copyContext(v, context);
- out.write(v.string.s);
+ out = v.string.s;
break;
case nPath:
if (copyToStore)
- out.write(state.copyPathToStore(context, v.path));
+ out = state.copyPathToStore(context, v.path);
else
- out.write(v.path);
+ out = v.path;
break;
case nNull:
- out.write(nullptr);
break;
case nAttrs: {
auto maybeString = state.tryAttrsToString(pos, v, context, false, false);
if (maybeString) {
- out.write(*maybeString);
+ out = *maybeString;
break;
}
auto i = v.attrs->find(state.sOutPath);
if (i == v.attrs->end()) {
- auto obj(out.object());
+ out = json::object();
StringSet names;
for (auto & j : *v.attrs)
names.emplace(state.symbols[j.name]);
for (auto & j : names) {
Attr & a(*v.attrs->find(state.symbols.create(j)));
- auto placeholder(obj.placeholder(j));
- printValueAsJSON(state, strict, *a.value, a.pos, placeholder, context, copyToStore);
+ out[j] = printValueAsJSON(state, strict, *a.value, a.pos, context, copyToStore);
}
} else
- printValueAsJSON(state, strict, *i->value, i->pos, out, context, copyToStore);
+ return printValueAsJSON(state, strict, *i->value, i->pos, context, copyToStore);
break;
}
case nList: {
- auto list(out.list());
- for (auto elem : v.listItems()) {
- auto placeholder(list.placeholder());
- printValueAsJSON(state, strict, *elem, pos, placeholder, context, copyToStore);
- }
+ out = json::array();
+ for (auto elem : v.listItems())
+ out.push_back(printValueAsJSON(state, strict, *elem, pos, context, copyToStore));
break;
}
case nExternal:
- v.external->printValueAsJSON(state, strict, out, context, copyToStore);
+ return v.external->printValueAsJSON(state, strict, context, copyToStore);
break;
case nFloat:
- out.write(v.fpoint);
+ out = v.fpoint;
break;
case nThunk:
@@ -91,17 +89,17 @@ void printValueAsJSON(EvalState & state, bool strict,
state.debugThrowLastTrace(e);
throw e;
}
+ return out;
}
void printValueAsJSON(EvalState & state, bool strict,
Value & v, const PosIdx pos, std::ostream & str, PathSet & context, bool copyToStore)
{
- JSONPlaceholder out(str);
- printValueAsJSON(state, strict, v, pos, out, context, copyToStore);
+ str << printValueAsJSON(state, strict, v, pos, context, copyToStore);
}
-void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
- JSONPlaceholder & out, PathSet & context, bool copyToStore) const
+json ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
+ PathSet & context, bool copyToStore) const
{
state.debugThrowLastTrace(TypeError("cannot convert %1% to JSON", showType()));
}
diff --git a/src/libexpr/value-to-json.hh b/src/libexpr/value-to-json.hh
index 7ddc8a5b1..22f26b790 100644
--- a/src/libexpr/value-to-json.hh
+++ b/src/libexpr/value-to-json.hh
@@ -5,13 +5,12 @@
#include <string>
#include <map>
+#include <nlohmann/json_fwd.hpp>
namespace nix {
-class JSONPlaceholder;
-
-void printValueAsJSON(EvalState & state, bool strict,
- Value & v, const PosIdx pos, JSONPlaceholder & out, PathSet & context, bool copyToStore = true);
+nlohmann::json printValueAsJSON(EvalState & state, bool strict,
+ Value & v, const PosIdx pos, PathSet & context, bool copyToStore = true);
void printValueAsJSON(EvalState & state, bool strict,
Value & v, const PosIdx pos, std::ostream & str, PathSet & context, bool copyToStore = true);
diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh
index 590ba7783..5adac72f8 100644
--- a/src/libexpr/value.hh
+++ b/src/libexpr/value.hh
@@ -7,6 +7,7 @@
#if HAVE_BOEHMGC
#include <gc/gc_allocator.h>
#endif
+#include <nlohmann/json_fwd.hpp>
namespace nix {
@@ -62,7 +63,6 @@ class StorePath;
class Store;
class EvalState;
class XMLWriter;
-class JSONPlaceholder;
typedef int64_t NixInt;
@@ -98,8 +98,8 @@ class ExternalValueBase
virtual bool operator ==(const ExternalValueBase & b) const;
/* Print the value as JSON. Defaults to unconvertable, i.e. throws an error */
- virtual void printValueAsJSON(EvalState & state, bool strict,
- JSONPlaceholder & out, PathSet & context, bool copyToStore = true) const;
+ virtual nlohmann::json printValueAsJSON(EvalState & state, bool strict,
+ PathSet & context, bool copyToStore = true) const;
/* Print the value as XML. Defaults to unevaluated */
virtual void printValueAsXML(EvalState & state, bool strict, bool location,
diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc
index a26770c79..12d0c32fb 100644
--- a/src/libstore/binary-cache-store.cc
+++ b/src/libstore/binary-cache-store.cc
@@ -9,7 +9,6 @@
#include "remote-fs-accessor.hh"
#include "nar-info-disk-cache.hh"
#include "nar-accessor.hh"
-#include "json.hh"
#include "thread-pool.hh"
#include "callback.hh"
@@ -194,19 +193,12 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
/* Optionally write a JSON file containing a listing of the
contents of the NAR. */
if (writeNARListing) {
- std::ostringstream jsonOut;
-
- {
- JSONObject jsonRoot(jsonOut);
- jsonRoot.attr("version", 1);
-
- {
- auto res = jsonRoot.placeholder("root");
- listNar(res, ref<FSAccessor>(narAccessor), "", true);
- }
- }
+ nlohmann::json j = {
+ {"version", 1},
+ {"root", listNar(ref<FSAccessor>(narAccessor), "", true)},
+ };
- upsertFile(std::string(info.path.hashPart()) + ".ls", jsonOut.str(), "application/json");
+ upsertFile(std::string(info.path.hashPart()) + ".ls", j.dump(), "application/json");
}
/* Optionally maintain an index of DWARF debug info files
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index 4211e620b..67cfc38af 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -7,7 +7,6 @@
#include "finally.hh"
#include "util.hh"
#include "archive.hh"
-#include "json.hh"
#include "compression.hh"
#include "worker-protocol.hh"
#include "topo-sort.hh"
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index 359966288..c9b7b24f3 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -8,7 +8,6 @@
#include "finally.hh"
#include "util.hh"
#include "archive.hh"
-#include "json.hh"
#include "compression.hh"
#include "daemon.hh"
#include "worker-protocol.hh"
@@ -57,6 +56,7 @@
#include <pwd.h>
#include <grp.h>
+#include <iostream>
namespace nix {
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 9ef8972f3..5d91829f1 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -147,7 +147,7 @@ void LocalStore::addTempRoot(const StorePath & path)
} catch (SysError & e) {
/* The garbage collector may have exited, so we need to
restart. */
- if (e.errNo == EPIPE) {
+ if (e.errNo == EPIPE || e.errNo == ECONNRESET) {
debug("GC socket disconnected");
state->fdRootsSocket.close();
goto restart;
@@ -506,6 +506,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
Finally cleanup([&]() {
debug("GC roots server shutting down");
+ fdServer.close();
while (true) {
auto item = remove_begin(*connections.lock());
if (!item) break;
diff --git a/src/libstore/nar-accessor.cc b/src/libstore/nar-accessor.cc
index 398147fc3..9a0003588 100644
--- a/src/libstore/nar-accessor.cc
+++ b/src/libstore/nar-accessor.cc
@@ -1,6 +1,5 @@
#include "nar-accessor.hh"
#include "archive.hh"
-#include "json.hh"
#include <map>
#include <stack>
@@ -243,42 +242,43 @@ ref<FSAccessor> makeLazyNarAccessor(const std::string & listing,
return make_ref<NarAccessor>(listing, getNarBytes);
}
-void listNar(JSONPlaceholder & res, ref<FSAccessor> accessor,
- const Path & path, bool recurse)
+using nlohmann::json;
+json listNar(ref<FSAccessor> accessor, const Path & path, bool recurse)
{
auto st = accessor->stat(path);
- auto obj = res.object();
+ json obj = json::object();
switch (st.type) {
case FSAccessor::Type::tRegular:
- obj.attr("type", "regular");
- obj.attr("size", st.fileSize);
+ obj["type"] = "regular";
+ obj["size"] = st.fileSize;
if (st.isExecutable)
- obj.attr("executable", true);
+ obj["executable"] = true;
if (st.narOffset)
- obj.attr("narOffset", st.narOffset);
+ obj["narOffset"] = st.narOffset;
break;
case FSAccessor::Type::tDirectory:
- obj.attr("type", "directory");
+ obj["type"] = "directory";
{
- auto res2 = obj.object("entries");
+ obj["entries"] = json::object();
+ json &res2 = obj["entries"];
for (auto & name : accessor->readDirectory(path)) {
if (recurse) {
- auto res3 = res2.placeholder(name);
- listNar(res3, accessor, path + "/" + name, true);
+ res2[name] = listNar(accessor, path + "/" + name, true);
} else
- res2.object(name);
+ res2[name] = json::object();
}
}
break;
case FSAccessor::Type::tSymlink:
- obj.attr("type", "symlink");
- obj.attr("target", accessor->readLink(path));
+ obj["type"] = "symlink";
+ obj["target"] = accessor->readLink(path);
break;
default:
throw Error("path '%s' does not exist in NAR", path);
}
+ return obj;
}
}
diff --git a/src/libstore/nar-accessor.hh b/src/libstore/nar-accessor.hh
index c2241a04c..7d998ae0b 100644
--- a/src/libstore/nar-accessor.hh
+++ b/src/libstore/nar-accessor.hh
@@ -2,6 +2,7 @@
#include <functional>
+#include <nlohmann/json_fwd.hpp>
#include "fs-accessor.hh"
namespace nix {
@@ -24,11 +25,8 @@ ref<FSAccessor> makeLazyNarAccessor(
const std::string & listing,
GetNarBytes getNarBytes);
-class JSONPlaceholder;
-
/* Write a JSON representation of the contents of a NAR (except file
contents). */
-void listNar(JSONPlaceholder & res, ref<FSAccessor> accessor,
- const Path & path, bool recurse);
+nlohmann::json listNar(ref<FSAccessor> accessor, const Path & path, bool recurse);
}
diff --git a/src/libstore/parsed-derivations.cc b/src/libstore/parsed-derivations.cc
index 487dbcfbb..cc4a94fab 100644
--- a/src/libstore/parsed-derivations.cc
+++ b/src/libstore/parsed-derivations.cc
@@ -2,7 +2,6 @@
#include <nlohmann/json.hpp>
#include <regex>
-#include "json.hh"
namespace nix {
@@ -150,16 +149,11 @@ std::optional<nlohmann::json> ParsedDerivation::prepareStructuredAttrs(Store & s
auto e = json.find("exportReferencesGraph");
if (e != json.end() && e->is_object()) {
for (auto i = e->begin(); i != e->end(); ++i) {
- std::ostringstream str;
- {
- JSONPlaceholder jsonRoot(str, true);
- StorePathSet storePaths;
- for (auto & p : *i)
- storePaths.insert(store.parseStorePath(p.get<std::string>()));
- store.pathInfoToJSON(jsonRoot,
- store.exportReferences(storePaths, inputPaths), false, true);
- }
- json[i.key()] = nlohmann::json::parse(str.str()); // urgh
+ StorePathSet storePaths;
+ for (auto & p : *i)
+ storePaths.insert(store.parseStorePath(p.get<std::string>()));
+ json[i.key()] = store.pathInfoToJSON(
+ store.exportReferences(storePaths, inputPaths), false, true);
}
}
diff --git a/src/libstore/remote-fs-accessor.cc b/src/libstore/remote-fs-accessor.cc
index 0ce335646..fcfb527f5 100644
--- a/src/libstore/remote-fs-accessor.cc
+++ b/src/libstore/remote-fs-accessor.cc
@@ -1,6 +1,6 @@
+#include <nlohmann/json.hpp>
#include "remote-fs-accessor.hh"
#include "nar-accessor.hh"
-#include "json.hh"
#include <sys/types.h>
#include <sys/stat.h>
@@ -38,10 +38,8 @@ ref<FSAccessor> RemoteFSAccessor::addToCache(std::string_view hashPart, std::str
if (cacheDir != "") {
try {
- std::ostringstream str;
- JSONPlaceholder jsonRoot(str);
- listNar(jsonRoot, narAccessor, "", true);
- writeFile(makeCacheFile(hashPart, "ls"), str.str());
+ nlohmann::json j = listNar(narAccessor, "", true);
+ writeFile(makeCacheFile(hashPart, "ls"), j.dump());
} catch (...) {
ignoreException();
}
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 06a9758fc..8811ab578 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -6,14 +6,16 @@
#include "util.hh"
#include "nar-info-disk-cache.hh"
#include "thread-pool.hh"
-#include "json.hh"
#include "url.hh"
#include "archive.hh"
#include "callback.hh"
#include "remote-store.hh"
+#include <nlohmann/json.hpp>
#include <regex>
+using json = nlohmann::json;
+
namespace nix {
@@ -838,56 +840,53 @@ StorePathSet Store::exportReferences(const StorePathSet & storePaths, const Stor
return paths;
}
-
-void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & storePaths,
+json Store::pathInfoToJSON(const StorePathSet & storePaths,
bool includeImpureInfo, bool showClosureSize,
Base hashBase,
AllowInvalidFlag allowInvalid)
{
- auto jsonList = jsonOut.list();
+ json::array_t jsonList = json::array();
for (auto & storePath : storePaths) {
- auto jsonPath = jsonList.object();
+ auto& jsonPath = jsonList.emplace_back(json::object());
try {
auto info = queryPathInfo(storePath);
- jsonPath.attr("path", printStorePath(info->path));
- jsonPath
- .attr("narHash", info->narHash.to_string(hashBase, true))
- .attr("narSize", info->narSize);
+ jsonPath["path"] = printStorePath(info->path);
+ jsonPath["narHash"] = info->narHash.to_string(hashBase, true);
+ jsonPath["narSize"] = info->narSize;
{
- auto jsonRefs = jsonPath.list("references");
+ auto& jsonRefs = (jsonPath["references"] = json::array());
for (auto & ref : info->references)
- jsonRefs.elem(printStorePath(ref));
+ jsonRefs.emplace_back(printStorePath(ref));
}
if (info->ca)
- jsonPath.attr("ca", renderContentAddress(info->ca));
+ jsonPath["ca"] = renderContentAddress(info->ca);
std::pair<uint64_t, uint64_t> closureSizes;
if (showClosureSize) {
closureSizes = getClosureSize(info->path);
- jsonPath.attr("closureSize", closureSizes.first);
+ jsonPath["closureSize"] = closureSizes.first;
}
if (includeImpureInfo) {
if (info->deriver)
- jsonPath.attr("deriver", printStorePath(*info->deriver));
+ jsonPath["deriver"] = printStorePath(*info->deriver);
if (info->registrationTime)
- jsonPath.attr("registrationTime", info->registrationTime);
+ jsonPath["registrationTime"] = info->registrationTime;
if (info->ultimate)
- jsonPath.attr("ultimate", info->ultimate);
+ jsonPath["ultimate"] = info->ultimate;
if (!info->sigs.empty()) {
- auto jsonSigs = jsonPath.list("signatures");
for (auto & sig : info->sigs)
- jsonSigs.elem(sig);
+ jsonPath["signatures"].push_back(sig);
}
auto narInfo = std::dynamic_pointer_cast<const NarInfo>(
@@ -895,21 +894,22 @@ void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & store
if (narInfo) {
if (!narInfo->url.empty())
- jsonPath.attr("url", narInfo->url);
+ jsonPath["url"] = narInfo->url;
if (narInfo->fileHash)
- jsonPath.attr("downloadHash", narInfo->fileHash->to_string(hashBase, true));
+ jsonPath["downloadHash"] = narInfo->fileHash->to_string(hashBase, true);
if (narInfo->fileSize)
- jsonPath.attr("downloadSize", narInfo->fileSize);
+ jsonPath["downloadSize"] = narInfo->fileSize;
if (showClosureSize)
- jsonPath.attr("closureDownloadSize", closureSizes.second);
+ jsonPath["closureDownloadSize"] = closureSizes.second;
}
}
} catch (InvalidPath &) {
- jsonPath.attr("path", printStorePath(storePath));
- jsonPath.attr("valid", false);
+ jsonPath["path"] = printStorePath(storePath);
+ jsonPath["valid"] = false;
}
}
+ return jsonList;
}
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index c8a667c6d..151ec10d6 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -14,6 +14,7 @@
#include "path-info.hh"
#include "repair-flag.hh"
+#include <nlohmann/json_fwd.hpp>
#include <atomic>
#include <limits>
#include <map>
@@ -68,7 +69,6 @@ struct Derivation;
class FSAccessor;
class NarInfoDiskCache;
class Store;
-class JSONPlaceholder;
enum CheckSigsFlag : bool { NoCheckSigs = false, CheckSigs = true };
@@ -512,7 +512,7 @@ public:
variable elements such as the registration time are
included. If ‘showClosureSize’ is true, the closure size of
each path is included. */
- void pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & storePaths,
+ nlohmann::json pathInfoToJSON(const StorePathSet & storePaths,
bool includeImpureInfo, bool showClosureSize,
Base hashBase = Base32,
AllowInvalidFlag allowInvalid = DisallowInvalid);
diff --git a/src/libutil/json.cc b/src/libutil/json.cc
deleted file mode 100644
index 2f9e97ff5..000000000
--- a/src/libutil/json.cc
+++ /dev/null
@@ -1,203 +0,0 @@
-#include "json.hh"
-
-#include <iomanip>
-#include <cstdint>
-#include <cstring>
-
-namespace nix {
-
-template<>
-void toJSON<std::string_view>(std::ostream & str, const std::string_view & s)
-{
- constexpr size_t BUF_SIZE = 4096;
- char buf[BUF_SIZE + 7]; // BUF_SIZE + largest single sequence of puts
- size_t bufPos = 0;
-
- const auto flush = [&] {
- str.write(buf, bufPos);
- bufPos = 0;
- };
- const auto put = [&] (char c) {
- buf[bufPos++] = c;
- };
-
- put('"');
- for (auto i = s.begin(); i != s.end(); i++) {
- if (bufPos >= BUF_SIZE) flush();
- if (*i == '\"' || *i == '\\') { put('\\'); put(*i); }
- else if (*i == '\n') { put('\\'); put('n'); }
- else if (*i == '\r') { put('\\'); put('r'); }
- else if (*i == '\t') { put('\\'); put('t'); }
- else if (*i >= 0 && *i < 32) {
- const char hex[17] = "0123456789abcdef";
- put('\\');
- put('u');
- put(hex[(uint16_t(*i) >> 12) & 0xf]);
- put(hex[(uint16_t(*i) >> 8) & 0xf]);
- put(hex[(uint16_t(*i) >> 4) & 0xf]);
- put(hex[(uint16_t(*i) >> 0) & 0xf]);
- }
- else put(*i);
- }
- put('"');
- flush();
-}
-
-void toJSON(std::ostream & str, const char * s)
-{
- if (!s) str << "null"; else toJSON(str, std::string_view(s));
-}
-
-template<> void toJSON<int>(std::ostream & str, const int & n) { str << n; }
-template<> void toJSON<unsigned int>(std::ostream & str, const unsigned int & n) { str << n; }
-template<> void toJSON<long>(std::ostream & str, const long & n) { str << n; }
-template<> void toJSON<unsigned long>(std::ostream & str, const unsigned long & n) { str << n; }
-template<> void toJSON<long long>(std::ostream & str, const long long & n) { str << n; }
-template<> void toJSON<unsigned long long>(std::ostream & str, const unsigned long long & n) { str << n; }
-template<> void toJSON<float>(std::ostream & str, const float & n) { str << n; }
-template<> void toJSON<double>(std::ostream & str, const double & n) { str << n; }
-template<> void toJSON<std::string>(std::ostream & str, const std::string & s) { toJSON(str, (std::string_view) s); }
-
-template<> void toJSON<bool>(std::ostream & str, const bool & b)
-{
- str << (b ? "true" : "false");
-}
-
-template<> void toJSON<std::nullptr_t>(std::ostream & str, const std::nullptr_t & b)
-{
- str << "null";
-}
-
-JSONWriter::JSONWriter(std::ostream & str, bool indent)
- : state(new JSONState(str, indent))
-{
- state->stack++;
-}
-
-JSONWriter::JSONWriter(JSONState * state)
- : state(state)
-{
- state->stack++;
-}
-
-JSONWriter::~JSONWriter()
-{
- if (state) {
- assertActive();
- state->stack--;
- if (state->stack == 0) delete state;
- }
-}
-
-void JSONWriter::comma()
-{
- assertActive();
- if (first) {
- first = false;
- } else {
- state->str << ',';
- }
- if (state->indent) indent();
-}
-
-void JSONWriter::indent()
-{
- state->str << '\n' << std::string(state->depth * 2, ' ');
-}
-
-void JSONList::open()
-{
- state->depth++;
- state->str << '[';
-}
-
-JSONList::~JSONList()
-{
- state->depth--;
- if (state->indent && !first) indent();
- state->str << "]";
-}
-
-JSONList JSONList::list()
-{
- comma();
- return JSONList(state);
-}
-
-JSONObject JSONList::object()
-{
- comma();
- return JSONObject(state);
-}
-
-JSONPlaceholder JSONList::placeholder()
-{
- comma();
- return JSONPlaceholder(state);
-}
-
-void JSONObject::open()
-{
- state->depth++;
- state->str << '{';
-}
-
-JSONObject::~JSONObject()
-{
- if (state) {
- state->depth--;
- if (state->indent && !first) indent();
- state->str << "}";
- }
-}
-
-void JSONObject::attr(std::string_view s)
-{
- comma();
- toJSON(state->str, s);
- state->str << ':';
- if (state->indent) state->str << ' ';
-}
-
-JSONList JSONObject::list(std::string_view name)
-{
- attr(name);
- return JSONList(state);
-}
-
-JSONObject JSONObject::object(std::string_view name)
-{
- attr(name);
- return JSONObject(state);
-}
-
-JSONPlaceholder JSONObject::placeholder(std::string_view name)
-{
- attr(name);
- return JSONPlaceholder(state);
-}
-
-JSONList JSONPlaceholder::list()
-{
- assertValid();
- first = false;
- return JSONList(state);
-}
-
-JSONObject JSONPlaceholder::object()
-{
- assertValid();
- first = false;
- return JSONObject(state);
-}
-
-JSONPlaceholder::~JSONPlaceholder()
-{
- if (first) {
- assert(std::uncaught_exceptions());
- if (state->stack != 0)
- write(nullptr);
- }
-}
-
-}
diff --git a/src/libutil/json.hh b/src/libutil/json.hh
deleted file mode 100644
index 3790b1a2e..000000000
--- a/src/libutil/json.hh
+++ /dev/null
@@ -1,185 +0,0 @@
-#pragma once
-
-#include <iostream>
-#include <vector>
-#include <cassert>
-
-namespace nix {
-
-void toJSON(std::ostream & str, const char * s);
-
-template<typename T>
-void toJSON(std::ostream & str, const T & n);
-
-class JSONWriter
-{
-protected:
-
- struct JSONState
- {
- std::ostream & str;
- bool indent;
- size_t depth = 0;
- size_t stack = 0;
- JSONState(std::ostream & str, bool indent) : str(str), indent(indent) { }
- ~JSONState()
- {
- assert(stack == 0);
- }
- };
-
- JSONState * state;
-
- bool first = true;
-
- JSONWriter(std::ostream & str, bool indent);
-
- JSONWriter(JSONState * state);
-
- ~JSONWriter();
-
- void assertActive()
- {
- assert(state->stack != 0);
- }
-
- void comma();
-
- void indent();
-};
-
-class JSONObject;
-class JSONPlaceholder;
-
-class JSONList : JSONWriter
-{
-private:
-
- friend class JSONObject;
- friend class JSONPlaceholder;
-
- void open();
-
- JSONList(JSONState * state)
- : JSONWriter(state)
- {
- open();
- }
-
-public:
-
- JSONList(std::ostream & str, bool indent = false)
- : JSONWriter(str, indent)
- {
- open();
- }
-
- ~JSONList();
-
- template<typename T>
- JSONList & elem(const T & v)
- {
- comma();
- toJSON(state->str, v);
- return *this;
- }
-
- JSONList list();
-
- JSONObject object();
-
- JSONPlaceholder placeholder();
-};
-
-class JSONObject : JSONWriter
-{
-private:
-
- friend class JSONList;
- friend class JSONPlaceholder;
-
- void open();
-
- JSONObject(JSONState * state)
- : JSONWriter(state)
- {
- open();
- }
-
- void attr(std::string_view s);
-
-public:
-
- JSONObject(std::ostream & str, bool indent = false)
- : JSONWriter(str, indent)
- {
- open();
- }
-
- JSONObject(const JSONObject & obj) = delete;
-
- JSONObject(JSONObject && obj)
- : JSONWriter(obj.state)
- {
- obj.state = 0;
- }
-
- ~JSONObject();
-
- template<typename T>
- JSONObject & attr(std::string_view name, const T & v)
- {
- attr(name);
- toJSON(state->str, v);
- return *this;
- }
-
- JSONList list(std::string_view name);
-
- JSONObject object(std::string_view name);
-
- JSONPlaceholder placeholder(std::string_view name);
-};
-
-class JSONPlaceholder : JSONWriter
-{
-
-private:
-
- friend class JSONList;
- friend class JSONObject;
-
- JSONPlaceholder(JSONState * state)
- : JSONWriter(state)
- {
- }
-
- void assertValid()
- {
- assertActive();
- assert(first);
- }
-
-public:
-
- JSONPlaceholder(std::ostream & str, bool indent = false)
- : JSONWriter(str, indent)
- {
- }
-
- ~JSONPlaceholder();
-
- template<typename T>
- void write(const T & v)
- {
- assertValid();
- first = false;
- toJSON(state->str, v);
- }
-
- JSONList list();
-
- JSONObject object();
-};
-
-}
diff --git a/src/libutil/tests/json.cc b/src/libutil/tests/json.cc
deleted file mode 100644
index 156286999..000000000
--- a/src/libutil/tests/json.cc
+++ /dev/null
@@ -1,193 +0,0 @@
-#include "json.hh"
-#include <gtest/gtest.h>
-#include <sstream>
-
-namespace nix {
-
- /* ----------------------------------------------------------------------------
- * toJSON
- * --------------------------------------------------------------------------*/
-
- TEST(toJSON, quotesCharPtr) {
- const char* input = "test";
- std::stringstream out;
- toJSON(out, input);
-
- ASSERT_EQ(out.str(), "\"test\"");
- }
-
- TEST(toJSON, quotesStdString) {
- std::string input = "test";
- std::stringstream out;
- toJSON(out, input);
-
- ASSERT_EQ(out.str(), "\"test\"");
- }
-
- TEST(toJSON, convertsNullptrtoNull) {
- auto input = nullptr;
- std::stringstream out;
- toJSON(out, input);
-
- ASSERT_EQ(out.str(), "null");
- }
-
- TEST(toJSON, convertsNullToNull) {
- const char* input = 0;
- std::stringstream out;
- toJSON(out, input);
-
- ASSERT_EQ(out.str(), "null");
- }
-
-
- TEST(toJSON, convertsFloat) {
- auto input = 1.024f;
- std::stringstream out;
- toJSON(out, input);
-
- ASSERT_EQ(out.str(), "1.024");
- }
-
- TEST(toJSON, convertsDouble) {
- const double input = 1.024;
- std::stringstream out;
- toJSON(out, input);
-
- ASSERT_EQ(out.str(), "1.024");
- }
-
- TEST(toJSON, convertsBool) {
- auto input = false;
- std::stringstream out;
- toJSON(out, input);
-
- ASSERT_EQ(out.str(), "false");
- }
-
- TEST(toJSON, quotesTab) {
- std::stringstream out;
- toJSON(out, "\t");
-
- ASSERT_EQ(out.str(), "\"\\t\"");
- }
-
- TEST(toJSON, quotesNewline) {
- std::stringstream out;
- toJSON(out, "\n");
-
- ASSERT_EQ(out.str(), "\"\\n\"");
- }
-
- TEST(toJSON, quotesCreturn) {
- std::stringstream out;
- toJSON(out, "\r");
-
- ASSERT_EQ(out.str(), "\"\\r\"");
- }
-
- TEST(toJSON, quotesCreturnNewLine) {
- std::stringstream out;
- toJSON(out, "\r\n");
-
- ASSERT_EQ(out.str(), "\"\\r\\n\"");
- }
-
- TEST(toJSON, quotesDoublequotes) {
- std::stringstream out;
- toJSON(out, "\"");
-
- ASSERT_EQ(out.str(), "\"\\\"\"");
- }
-
- TEST(toJSON, substringEscape) {
- std::stringstream out;
- std::string_view s = "foo\t";
- toJSON(out, s.substr(3));
-
- ASSERT_EQ(out.str(), "\"\\t\"");
- }
-
- /* ----------------------------------------------------------------------------
- * JSONObject
- * --------------------------------------------------------------------------*/
-
- TEST(JSONObject, emptyObject) {
- std::stringstream out;
- {
- JSONObject t(out);
- }
- ASSERT_EQ(out.str(), "{}");
- }
-
- TEST(JSONObject, objectWithList) {
- std::stringstream out;
- {
- JSONObject t(out);
- auto l = t.list("list");
- l.elem("element");
- }
- ASSERT_EQ(out.str(), R"#({"list":["element"]})#");
- }
-
- TEST(JSONObject, objectWithListIndent) {
- std::stringstream out;
- {
- JSONObject t(out, true);
- auto l = t.list("list");
- l.elem("element");
- }
- ASSERT_EQ(out.str(),
-R"#({
- "list": [
- "element"
- ]
-})#");
- }
-
- TEST(JSONObject, objectWithPlaceholderAndList) {
- std::stringstream out;
- {
- JSONObject t(out);
- auto l = t.placeholder("list");
- l.list().elem("element");
- }
-
- ASSERT_EQ(out.str(), R"#({"list":["element"]})#");
- }
-
- TEST(JSONObject, objectWithPlaceholderAndObject) {
- std::stringstream out;
- {
- JSONObject t(out);
- auto l = t.placeholder("object");
- l.object().attr("key", "value");
- }
-
- ASSERT_EQ(out.str(), R"#({"object":{"key":"value"}})#");
- }
-
- /* ----------------------------------------------------------------------------
- * JSONList
- * --------------------------------------------------------------------------*/
-
- TEST(JSONList, empty) {
- std::stringstream out;
- {
- JSONList l(out);
- }
- ASSERT_EQ(out.str(), R"#([])#");
- }
-
- TEST(JSONList, withElements) {
- std::stringstream out;
- {
- JSONList l(out);
- l.elem("one");
- l.object();
- l.placeholder().write("three");
- }
- ASSERT_EQ(out.str(), R"#(["one",{},"three"])#");
- }
-}
-
diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc
index fdd66220a..776c5f6db 100644
--- a/src/nix-env/nix-env.cc
+++ b/src/nix-env/nix-env.cc
@@ -12,7 +12,6 @@
#include "local-fs-store.hh"
#include "user-env.hh"
#include "util.hh"
-#include "json.hh"
#include "value-to-json.hh"
#include "xml-writer.hh"
#include "legacy.hh"
@@ -26,6 +25,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
+#include <nlohmann/json.hpp>
using namespace nix;
using std::cout;
@@ -911,43 +911,47 @@ static VersionDiff compareVersionAgainstSet(
static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool printOutPath, bool printMeta)
{
- JSONObject topObj(cout, true);
+ using nlohmann::json;
+ json topObj = json::object();
for (auto & i : elems) {
try {
if (i.hasFailed()) continue;
- JSONObject pkgObj = topObj.object(i.attrPath);
auto drvName = DrvName(i.queryName());
- pkgObj.attr("name", drvName.fullName);
- pkgObj.attr("pname", drvName.name);
- pkgObj.attr("version", drvName.version);
- pkgObj.attr("system", i.querySystem());
- pkgObj.attr("outputName", i.queryOutputName());
+ json &pkgObj = topObj[i.attrPath];
+ pkgObj = {
+ {"name", drvName.fullName},
+ {"pname", drvName.name},
+ {"version", drvName.version},
+ {"system", i.querySystem()},
+ {"outputName", i.queryOutputName()},
+ };
{
DrvInfo::Outputs outputs = i.queryOutputs(printOutPath);
- JSONObject outputObj = pkgObj.object("outputs");
+ json &outputObj = pkgObj["outputs"];
+ outputObj = json::object();
for (auto & j : outputs) {
if (j.second)
- outputObj.attr(j.first, globals.state->store->printStorePath(*j.second));
+ outputObj[j.first] = globals.state->store->printStorePath(*j.second);
else
- outputObj.attr(j.first, nullptr);
+ outputObj[j.first] = nullptr;
}
}
if (printMeta) {
- JSONObject metaObj = pkgObj.object("meta");
+ json &metaObj = pkgObj["meta"];
+ metaObj = json::object();
StringSet metaNames = i.queryMetaNames();
for (auto & j : metaNames) {
Value * v = i.queryMeta(j);
if (!v) {
printError("derivation '%s' has invalid meta attribute '%s'", i.queryName(), j);
- metaObj.attr(j, nullptr);
+ metaObj[j] = nullptr;
} else {
- auto placeholder = metaObj.placeholder(j);
PathSet context;
- printValueAsJSON(*globals.state, true, *v, noPos, placeholder, context);
+ metaObj[j] = printValueAsJSON(*globals.state, true, *v, noPos, context);
}
}
}
@@ -958,6 +962,7 @@ static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool prin
throw;
}
}
+ std::cout << topObj.dump(2);
}
diff --git a/src/nix/eval.cc b/src/nix/eval.cc
index ddd2790c6..ba82b5772 100644
--- a/src/nix/eval.cc
+++ b/src/nix/eval.cc
@@ -4,10 +4,11 @@
#include "store-api.hh"
#include "eval.hh"
#include "eval-inline.hh"
-#include "json.hh"
#include "value-to-json.hh"
#include "progress-bar.hh"
+#include <nlohmann/json.hpp>
+
using namespace nix;
struct CmdEval : MixJSON, InstallableCommand
@@ -115,9 +116,7 @@ struct CmdEval : MixJSON, InstallableCommand
}
else if (json) {
- JSONPlaceholder jsonOut(std::cout);
- printValueAsJSON(*state, true, *v, pos, jsonOut, context, false);
- std::cout << std::endl;
+ std::cout << printValueAsJSON(*state, true, *v, pos, context, false).dump() << std::endl;
}
else {
diff --git a/src/nix/flake.cc b/src/nix/flake.cc
index 3967f1102..336f6723a 100644
--- a/src/nix/flake.cc
+++ b/src/nix/flake.cc
@@ -11,7 +11,6 @@
#include "attr-path.hh"
#include "fetchers.hh"
#include "registry.hh"
-#include "json.hh"
#include "eval-cache.hh"
#include "markdown.hh"
@@ -21,6 +20,7 @@
using namespace nix;
using namespace nix::flake;
+using json = nlohmann::json;
class FlakeCommand : virtual Args, public MixFlakeOptions
{
@@ -917,35 +917,44 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun
{
auto flake = lockFlake();
- auto jsonRoot = json ? std::optional<JSONObject>(std::cout) : std::nullopt;
-
StorePathSet sources;
sources.insert(flake.flake.sourceInfo->storePath);
- if (jsonRoot)
- jsonRoot->attr("path", store->printStorePath(flake.flake.sourceInfo->storePath));
// FIXME: use graph output, handle cycles.
- std::function<void(const Node & node, std::optional<JSONObject> & jsonObj)> traverse;
- traverse = [&](const Node & node, std::optional<JSONObject> & jsonObj)
+ std::function<nlohmann::json(const Node & node)> traverse;
+ traverse = [&](const Node & node)
{
- auto jsonObj2 = jsonObj ? jsonObj->object("inputs") : std::optional<JSONObject>();
+ nlohmann::json jsonObj2 = json ? json::object() : nlohmann::json(nullptr);
for (auto & [inputName, input] : node.inputs) {
if (auto inputNode = std::get_if<0>(&input)) {
- auto jsonObj3 = jsonObj2 ? jsonObj2->object(inputName) : std::optional<JSONObject>();
auto storePath =
dryRun
? (*inputNode)->lockedRef.input.computeStorePath(*store)
: (*inputNode)->lockedRef.input.fetch(store).first.storePath;
- if (jsonObj3)
- jsonObj3->attr("path", store->printStorePath(storePath));
- sources.insert(std::move(storePath));
- traverse(**inputNode, jsonObj3);
+ if (json) {
+ auto& jsonObj3 = jsonObj2[inputName];
+ jsonObj3["path"] = store->printStorePath(storePath);
+ sources.insert(std::move(storePath));
+ jsonObj3["inputs"] = traverse(**inputNode);
+ } else {
+ sources.insert(std::move(storePath));
+ traverse(**inputNode);
+ }
}
}
+ return jsonObj2;
};
- traverse(*flake.lockFile.root, jsonRoot);
+ if (json) {
+ nlohmann::json jsonRoot = {
+ {"path", store->printStorePath(flake.flake.sourceInfo->storePath)},
+ {"inputs", traverse(*flake.lockFile.root)},
+ };
+ std::cout << jsonRoot.dump() << std::endl;
+ } else {
+ traverse(*flake.lockFile.root);
+ }
if (!dryRun && !dstUri.empty()) {
ref<Store> dstStore = dstUri.empty() ? openStore() : openStore(dstUri);
diff --git a/src/nix/ls.cc b/src/nix/ls.cc
index 07554994b..e964b01b3 100644
--- a/src/nix/ls.cc
+++ b/src/nix/ls.cc
@@ -3,7 +3,7 @@
#include "fs-accessor.hh"
#include "nar-accessor.hh"
#include "common-args.hh"
-#include "json.hh"
+#include <nlohmann/json.hpp>
using namespace nix;
@@ -91,10 +91,9 @@ struct MixLs : virtual Args, MixJSON
if (path == "/") path = "";
if (json) {
- JSONPlaceholder jsonRoot(std::cout);
if (showDirectory)
throw UsageError("'--directory' is useless with '--json'");
- listNar(jsonRoot, accessor, path, recursive);
+ std::cout << listNar(accessor, path, recursive);
} else
listText(accessor);
}
diff --git a/src/nix/make-content-addressed.cc b/src/nix/make-content-addressed.cc
index 34860c38f..f2e4cefbe 100644
--- a/src/nix/make-content-addressed.cc
+++ b/src/nix/make-content-addressed.cc
@@ -2,10 +2,13 @@
#include "store-api.hh"
#include "make-content-addressed.hh"
#include "common-args.hh"
-#include "json.hh"
+
+#include <nlohmann/json.hpp>
using namespace nix;
+using nlohmann::json;
+
struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand, MixJSON
{
CmdMakeContentAddressed()
@@ -25,6 +28,7 @@ struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand,
;
}
+ using StorePathsCommand::run;
void run(ref<Store> srcStore, StorePaths && storePaths) override
{
auto dstStore = dstUri.empty() ? openStore() : openStore(dstUri);
@@ -33,13 +37,13 @@ struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand,
StorePathSet(storePaths.begin(), storePaths.end()));
if (json) {
- JSONObject jsonRoot(std::cout);
- JSONObject jsonRewrites(jsonRoot.object("rewrites"));
+ nlohmann::json jsonRewrites = json::object();
for (auto & path : storePaths) {
auto i = remappings.find(path);
assert(i != remappings.end());
- jsonRewrites.attr(srcStore->printStorePath(path), srcStore->printStorePath(i->second));
+ jsonRewrites[srcStore->printStorePath(path)] = srcStore->printStorePath(i->second);
}
+ std::cout << json::object({"rewrites", jsonRewrites}).dump();
} else {
for (auto & path : storePaths) {
auto i = remappings.find(path);
diff --git a/src/nix/path-info.cc b/src/nix/path-info.cc
index d690fe594..613c5b191 100644
--- a/src/nix/path-info.cc
+++ b/src/nix/path-info.cc
@@ -1,12 +1,13 @@
#include "command.hh"
#include "shared.hh"
#include "store-api.hh"
-#include "json.hh"
#include "common-args.hh"
#include <algorithm>
#include <array>
+#include <nlohmann/json.hpp>
+
using namespace nix;
struct CmdPathInfo : StorePathsCommand, MixJSON
@@ -86,11 +87,10 @@ struct CmdPathInfo : StorePathsCommand, MixJSON
pathLen = std::max(pathLen, store->printStorePath(storePath).size());
if (json) {
- JSONPlaceholder jsonRoot(std::cout);
- store->pathInfoToJSON(jsonRoot,
+ std::cout << store->pathInfoToJSON(
// FIXME: preserve order?
StorePathSet(storePaths.begin(), storePaths.end()),
- true, showClosureSize, SRI, AllowInvalid);
+ true, showClosureSize, SRI, AllowInvalid).dump();
}
else {
diff --git a/src/nix/search.cc b/src/nix/search.cc
index bdd45cbed..d2a31607d 100644
--- a/src/nix/search.cc
+++ b/src/nix/search.cc
@@ -5,7 +5,6 @@
#include "names.hh"
#include "get-drvs.hh"
#include "common-args.hh"
-#include "json.hh"
#include "shared.hh"
#include "eval-cache.hh"
#include "attr-path.hh"
@@ -13,8 +12,10 @@
#include <regex>
#include <fstream>
+#include <nlohmann/json.hpp>
using namespace nix;
+using json = nlohmann::json;
std::string wrap(std::string prefix, std::string s)
{
@@ -84,7 +85,8 @@ struct CmdSearch : InstallableCommand, MixJSON
auto state = getEvalState();
- auto jsonOut = json ? std::make_unique<JSONObject>(std::cout) : nullptr;
+ std::optional<nlohmann::json> jsonOut;
+ if (json) jsonOut = json::object();
uint64_t results = 0;
@@ -151,10 +153,11 @@ struct CmdSearch : InstallableCommand, MixJSON
{
results++;
if (json) {
- auto jsonElem = jsonOut->object(attrPath2);
- jsonElem.attr("pname", name.name);
- jsonElem.attr("version", name.version);
- jsonElem.attr("description", description);
+ (*jsonOut)[attrPath2] = {
+ {"pname", name.name},
+ {"version", name.version},
+ {"description", description},
+ };
} else {
auto name2 = hiliteMatches(name.name, nameMatches, ANSI_GREEN, "\e[0;2m");
if (results > 1) logger->cout("");
@@ -193,6 +196,10 @@ struct CmdSearch : InstallableCommand, MixJSON
for (auto & cursor : installable->getCursors(*state))
visit(*cursor, cursor->getAttrPath(), true);
+ if (json) {
+ std::cout << jsonOut->dump() << std::endl;
+ }
+
if (!json && !results)
throw Error("no results for the given search term(s)!");
}
diff --git a/src/nix/show-derivation.cc b/src/nix/show-derivation.cc
index fb46b4dbf..af2e676a4 100644
--- a/src/nix/show-derivation.cc
+++ b/src/nix/show-derivation.cc
@@ -5,10 +5,11 @@
#include "common-args.hh"
#include "store-api.hh"
#include "archive.hh"
-#include "json.hh"
#include "derivations.hh"
+#include <nlohmann/json.hpp>
using namespace nix;
+using json = nlohmann::json;
struct CmdShowDerivation : InstallablesCommand
{
@@ -48,77 +49,63 @@ struct CmdShowDerivation : InstallablesCommand
drvPaths = std::move(closure);
}
- {
-
- JSONObject jsonRoot(std::cout, true);
+ json jsonRoot = json::object();
for (auto & drvPath : drvPaths) {
if (!drvPath.isDerivation()) continue;
- auto drvObj(jsonRoot.object(store->printStorePath(drvPath)));
+ json& drvObj = jsonRoot[store->printStorePath(drvPath)];
auto drv = store->readDerivation(drvPath);
{
- auto outputsObj(drvObj.object("outputs"));
+ json& outputsObj = drvObj["outputs"];
+ outputsObj = json::object();
for (auto & [_outputName, output] : drv.outputs) {
auto & outputName = _outputName; // work around clang bug
- auto outputObj { outputsObj.object(outputName) };
+ auto& outputObj = outputsObj[outputName];
+ outputObj = json::object();
std::visit(overloaded {
[&](const DerivationOutput::InputAddressed & doi) {
- outputObj.attr("path", store->printStorePath(doi.path));
+ outputObj["path"] = store->printStorePath(doi.path);
},
[&](const DerivationOutput::CAFixed & dof) {
- outputObj.attr("path", store->printStorePath(dof.path(*store, drv.name, outputName)));
- outputObj.attr("hashAlgo", dof.hash.printMethodAlgo());
- outputObj.attr("hash", dof.hash.hash.to_string(Base16, false));
+ outputObj["path"] = store->printStorePath(dof.path(*store, drv.name, outputName));
+ outputObj["hashAlgo"] = dof.hash.printMethodAlgo();
+ outputObj["hash"] = dof.hash.hash.to_string(Base16, false);
},
[&](const DerivationOutput::CAFloating & dof) {
- outputObj.attr("hashAlgo", makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType));
+ outputObj["hashAlgo"] = makeFileIngestionPrefix(dof.method) + printHashType(dof.hashType);
},
[&](const DerivationOutput::Deferred &) {},
[&](const DerivationOutput::Impure & doi) {
- outputObj.attr("hashAlgo", makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType));
- outputObj.attr("impure", true);
+ outputObj["hashAlgo"] = makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType);
+ outputObj["impure"] = true;
},
}, output.raw());
}
}
{
- auto inputsList(drvObj.list("inputSrcs"));
+ auto& inputsList = drvObj["inputSrcs"];
+ inputsList = json::array();
for (auto & input : drv.inputSrcs)
- inputsList.elem(store->printStorePath(input));
- }
-
- {
- auto inputDrvsObj(drvObj.object("inputDrvs"));
- for (auto & input : drv.inputDrvs) {
- auto inputList(inputDrvsObj.list(store->printStorePath(input.first)));
- for (auto & outputId : input.second)
- inputList.elem(outputId);
- }
+ inputsList.emplace_back(store->printStorePath(input));
}
- drvObj.attr("system", drv.platform);
- drvObj.attr("builder", drv.builder);
-
{
- auto argsList(drvObj.list("args"));
- for (auto & arg : drv.args)
- argsList.elem(arg);
+ auto& inputDrvsObj = drvObj["inputDrvs"];
+ inputDrvsObj = json::object();
+ for (auto & input : drv.inputDrvs)
+ inputDrvsObj[store->printStorePath(input.first)] = input.second;
}
- {
- auto envObj(drvObj.object("env"));
- for (auto & var : drv.env)
- envObj.attr(var.first, var.second);
- }
+ drvObj["system"] = drv.platform;
+ drvObj["builder"] = drv.builder;
+ drvObj["args"] = drv.args;
+ drvObj["env"] = drv.env;
}
-
- }
-
- std::cout << "\n";
+ std::cout << jsonRoot.dump(2) << std::endl;
}
};
diff --git a/src/nix/why-depends.cc b/src/nix/why-depends.cc
index 1d9ab28ba..723017497 100644
--- a/src/nix/why-depends.cc
+++ b/src/nix/why-depends.cc
@@ -83,20 +83,47 @@ struct CmdWhyDepends : SourceExprCommand
{
auto package = parseInstallable(store, _package);
auto packagePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, package);
+
+ /* We don't need to build `dependency`. We try to get the store
+ * path if it's already known, and if not, then it's not a dependency.
+ *
+ * Why? If `package` does depends on `dependency`, then getting the
+ * store path of `package` above necessitated having the store path
+ * of `dependency`. The contrapositive is, if the store path of
+ * `dependency` is not already known at this point (i.e. it's a CA
+ * derivation which hasn't been built), then `package` did not need it
+ * to build.
+ */
auto dependency = parseInstallable(store, _dependency);
- auto dependencyPath = Installable::toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency);
- auto dependencyPathHash = dependencyPath.hashPart();
+ auto derivedDependency = dependency->toDerivedPath();
+ auto optDependencyPath = std::visit(overloaded {
+ [](const DerivedPath::Opaque & nodrv) -> std::optional<StorePath> {
+ return { nodrv.path };
+ },
+ [&](const DerivedPath::Built & hasdrv) -> std::optional<StorePath> {
+ if (hasdrv.outputs.size() != 1) {
+ throw Error("argument '%s' should evaluate to one store path", dependency->what());
+ }
+ auto outputMap = store->queryPartialDerivationOutputMap(hasdrv.drvPath);
+ auto maybePath = outputMap.find(*hasdrv.outputs.begin());
+ if (maybePath == outputMap.end()) {
+ throw Error("unexpected end of iterator");
+ }
+ return maybePath->second;
+ },
+ }, derivedDependency.raw());
StorePathSet closure;
store->computeFSClosure({packagePath}, closure, false, false);
- if (!closure.count(dependencyPath)) {
- printError("'%s' does not depend on '%s'",
- store->printStorePath(packagePath),
- store->printStorePath(dependencyPath));
+ if (!optDependencyPath.has_value() || !closure.count(*optDependencyPath)) {
+ printError("'%s' does not depend on '%s'", package->what(), dependency->what());
return;
}
+ auto dependencyPath = *optDependencyPath;
+ auto dependencyPathHash = dependencyPath.hashPart();
+
stopProgressBar(); // FIXME
auto accessor = store->getFSAccessor();
diff --git a/tests/ca/why-depends.sh b/tests/ca/why-depends.sh
new file mode 100644
index 000000000..0c079f63b
--- /dev/null
+++ b/tests/ca/why-depends.sh
@@ -0,0 +1,5 @@
+source common.sh
+
+export NIX_TESTS_CA_BY_DEFAULT=1
+
+cd .. && source why-depends.sh