Replace src/libutil/json.cc with nlohmann json generation

This commit is contained in:
Yorick 2022-11-16 16:49:49 +01:00
parent 62960f3291
commit 09f00dd4d0
No known key found for this signature in database
GPG key ID: A36E70F9DC014A15
25 changed files with 266 additions and 858 deletions

View file

@ -7,7 +7,6 @@
#include "globals.hh" #include "globals.hh"
#include "eval-inline.hh" #include "eval-inline.hh"
#include "filetransfer.hh" #include "filetransfer.hh"
#include "json.hh"
#include "function-trace.hh" #include "function-trace.hh"
#include <algorithm> #include <algorithm>
@ -21,6 +20,7 @@
#include <functional> #include <functional>
#include <sys/resource.h> #include <sys/resource.h>
#include <nlohmann/json.hpp>
#if HAVE_BOEHMGC #if HAVE_BOEHMGC
@ -35,6 +35,8 @@
#endif #endif
using json = nlohmann::json;
namespace nix { namespace nix {
static char * allocString(size_t size) static char * allocString(size_t size)
@ -2441,97 +2443,97 @@ void EvalState::printStats()
std::fstream fs; std::fstream fs;
if (outPath != "-") if (outPath != "-")
fs.open(outPath, std::fstream::out); fs.open(outPath, std::fstream::out);
JSONObject topObj(outPath == "-" ? std::cerr : fs, true); json topObj = json::object();
topObj.attr("cpuTime",cpuTime); topObj["cpuTime"] = cpuTime;
{ topObj["envs"] = {
auto envs = topObj.object("envs"); {"number", nrEnvs},
envs.attr("number", nrEnvs); {"elements", nrValuesInEnvs},
envs.attr("elements", nrValuesInEnvs); {"bytes", bEnvs},
envs.attr("bytes", bEnvs); };
} topObj["list"] = {
{ {"elements", nrListElems},
auto lists = topObj.object("list"); {"bytes", bLists},
lists.attr("elements", nrListElems); {"concats", nrListConcats},
lists.attr("bytes", bLists); };
lists.attr("concats", nrListConcats); topObj["values"] = {
} {"number", nrValues},
{ {"bytes", bValues},
auto values = topObj.object("values"); };
values.attr("number", nrValues); topObj["symbols"] = {
values.attr("bytes", bValues); {"number", symbols.size()},
} {"bytes", symbols.totalSize()},
{ };
auto syms = topObj.object("symbols"); topObj["sets"] = {
syms.attr("number", symbols.size()); {"number", nrAttrsets},
syms.attr("bytes", symbols.totalSize()); {"bytes", bAttrsets},
} {"elements", nrAttrsInAttrsets},
{ };
auto sets = topObj.object("sets"); topObj["sizes"] = {
sets.attr("number", nrAttrsets); {"Env", sizeof(Env)},
sets.attr("bytes", bAttrsets); {"Value", sizeof(Value)},
sets.attr("elements", nrAttrsInAttrsets); {"Bindings", sizeof(Bindings)},
} {"Attr", sizeof(Attr)},
{ };
auto sizes = topObj.object("sizes"); topObj["nrOpUpdates"] = nrOpUpdates;
sizes.attr("Env", sizeof(Env)); topObj["nrOpUpdateValuesCopied"] = nrOpUpdateValuesCopied;
sizes.attr("Value", sizeof(Value)); topObj["nrThunks"] = nrThunks;
sizes.attr("Bindings", sizeof(Bindings)); topObj["nrAvoided"] = nrAvoided;
sizes.attr("Attr", sizeof(Attr)); topObj["nrLookups"] = nrLookups;
} topObj["nrPrimOpCalls"] = nrPrimOpCalls;
topObj.attr("nrOpUpdates", nrOpUpdates); topObj["nrFunctionCalls"] = nrFunctionCalls;
topObj.attr("nrOpUpdateValuesCopied", nrOpUpdateValuesCopied);
topObj.attr("nrThunks", nrThunks);
topObj.attr("nrAvoided", nrAvoided);
topObj.attr("nrLookups", nrLookups);
topObj.attr("nrPrimOpCalls", nrPrimOpCalls);
topObj.attr("nrFunctionCalls", nrFunctionCalls);
#if HAVE_BOEHMGC #if HAVE_BOEHMGC
{ topObj["gc"] = {
auto gc = topObj.object("gc"); {"heapSize", heapSize},
gc.attr("heapSize", heapSize); {"totalBytes", totalBytes},
gc.attr("totalBytes", totalBytes); };
}
#endif #endif
if (countCalls) { if (countCalls) {
topObj["primops"] = primOpCalls;
{ {
auto obj = topObj.object("primops"); auto& list = topObj["functions"];
for (auto & i : primOpCalls) list = json::array();
obj.attr(i.first, i.second);
}
{
auto list = topObj.list("functions");
for (auto & [fun, count] : functionCalls) { for (auto & [fun, count] : functionCalls) {
auto obj = list.object(); json obj = json::object();
if (fun->name) if (fun->name)
obj.attr("name", (std::string_view) symbols[fun->name]); obj["name"] = (std::string_view) symbols[fun->name];
else else
obj.attr("name", nullptr); obj["name"] = nullptr;
if (auto pos = positions[fun->pos]) { if (auto pos = positions[fun->pos]) {
obj.attr("file", (std::string_view) pos.file); obj["file"] = (std::string_view) pos.file;
obj.attr("line", pos.line); obj["line"] = pos.line;
obj.attr("column", pos.column); 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) { for (auto & i : attrSelects) {
auto obj = list.object(); json obj = json::object();
if (auto pos = positions[i.first]) { if (auto pos = positions[i.first]) {
obj.attr("file", (const std::string &) pos.file); obj["file"] = (const std::string &) pos.file;
obj.attr("line", pos.line); obj["line"] = pos.line;
obj.attr("column", pos.column); 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") { if (getEnv("NIX_SHOW_SYMBOLS").value_or("0") != "0") {
auto list = topObj.list("symbols"); // XXX: overrides earlier assignment
symbols.dump([&](const std::string & s) { list.elem(s); }); 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;
} }
} }
} }

View file

@ -8,12 +8,12 @@
#include "references.hh" #include "references.hh"
#include "store-api.hh" #include "store-api.hh"
#include "util.hh" #include "util.hh"
#include "json.hh"
#include "value-to-json.hh" #include "value-to-json.hh"
#include "value-to-xml.hh" #include "value-to-xml.hh"
#include "primops.hh" #include "primops.hh"
#include <boost/container/small_vector.hpp> #include <boost/container/small_vector.hpp>
#include <nlohmann/json.hpp>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -1011,6 +1011,7 @@ static void prim_second(EvalState & state, const PosIdx pos, Value * * args, Val
derivation. */ derivation. */
static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * args, Value & v) static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * * args, Value & v)
{ {
using nlohmann::json;
state.forceAttrs(*args[0], pos); state.forceAttrs(*args[0], pos);
/* Figure out the name first (for stack backtraces). */ /* 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. */ /* Check whether attributes should be passed as a JSON file. */
std::ostringstream jsonBuf; std::optional<json> jsonObject;
std::unique_ptr<JSONObject> jsonObject;
attr = args[0]->attrs->find(state.sStructuredAttrs); attr = args[0]->attrs->find(state.sStructuredAttrs);
if (attr != args[0]->attrs->end() && state.forceBool(*attr->value, pos)) 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. */ /* Check whether null attributes should be ignored. */
bool ignoreNulls = false; bool ignoreNulls = false;
@ -1138,8 +1138,7 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * *
if (i->name == state.sStructuredAttrs) continue; if (i->name == state.sStructuredAttrs) continue;
auto placeholder(jsonObject->placeholder(key)); (*jsonObject)[key] = printValueAsJSON(state, true, *i->value, pos, context);
printValueAsJSON(state, true, *i->value, pos, placeholder, context);
if (i->name == state.sBuilder) if (i->name == state.sBuilder)
drv.builder = state.forceString(*i->value, context, posDrvName); drv.builder = state.forceString(*i->value, context, posDrvName);
@ -1183,8 +1182,8 @@ static void prim_derivationStrict(EvalState & state, const PosIdx pos, Value * *
} }
if (jsonObject) { if (jsonObject) {
drv.env.emplace("__json", jsonObject->dump());
jsonObject.reset(); jsonObject.reset();
drv.env.emplace("__json", jsonBuf.str());
} }
/* Everything in the context of the strings in the derivation /* Everything in the context of the strings in the derivation

View file

@ -1,84 +1,82 @@
#include "value-to-json.hh" #include "value-to-json.hh"
#include "json.hh"
#include "eval-inline.hh" #include "eval-inline.hh"
#include "util.hh" #include "util.hh"
#include <cstdlib> #include <cstdlib>
#include <iomanip> #include <iomanip>
#include <nlohmann/json.hpp>
namespace nix { namespace nix {
using json = nlohmann::json;
void printValueAsJSON(EvalState & state, bool strict, json printValueAsJSON(EvalState & state, bool strict,
Value & v, const PosIdx pos, JSONPlaceholder & out, PathSet & context, bool copyToStore) Value & v, const PosIdx pos, PathSet & context, bool copyToStore)
{ {
checkInterrupt(); checkInterrupt();
if (strict) state.forceValue(v, pos); if (strict) state.forceValue(v, pos);
json out;
switch (v.type()) { switch (v.type()) {
case nInt: case nInt:
out.write(v.integer); out = v.integer;
break; break;
case nBool: case nBool:
out.write(v.boolean); out = v.boolean;
break; break;
case nString: case nString:
copyContext(v, context); copyContext(v, context);
out.write(v.string.s); out = v.string.s;
break; break;
case nPath: case nPath:
if (copyToStore) if (copyToStore)
out.write(state.copyPathToStore(context, v.path)); out = state.copyPathToStore(context, v.path);
else else
out.write(v.path); out = v.path;
break; break;
case nNull: case nNull:
out.write(nullptr);
break; break;
case nAttrs: { case nAttrs: {
auto maybeString = state.tryAttrsToString(pos, v, context, false, false); auto maybeString = state.tryAttrsToString(pos, v, context, false, false);
if (maybeString) { if (maybeString) {
out.write(*maybeString); out = *maybeString;
break; break;
} }
auto i = v.attrs->find(state.sOutPath); auto i = v.attrs->find(state.sOutPath);
if (i == v.attrs->end()) { if (i == v.attrs->end()) {
auto obj(out.object()); out = json::object();
StringSet names; StringSet names;
for (auto & j : *v.attrs) for (auto & j : *v.attrs)
names.emplace(state.symbols[j.name]); names.emplace(state.symbols[j.name]);
for (auto & j : names) { for (auto & j : names) {
Attr & a(*v.attrs->find(state.symbols.create(j))); Attr & a(*v.attrs->find(state.symbols.create(j)));
auto placeholder(obj.placeholder(j)); out[j] = printValueAsJSON(state, strict, *a.value, a.pos, context, copyToStore);
printValueAsJSON(state, strict, *a.value, a.pos, placeholder, context, copyToStore);
} }
} else } else
printValueAsJSON(state, strict, *i->value, i->pos, out, context, copyToStore); return printValueAsJSON(state, strict, *i->value, i->pos, context, copyToStore);
break; break;
} }
case nList: { case nList: {
auto list(out.list()); out = json::array();
for (auto elem : v.listItems()) { for (auto elem : v.listItems())
auto placeholder(list.placeholder()); out.push_back(printValueAsJSON(state, strict, *elem, pos, context, copyToStore));
printValueAsJSON(state, strict, *elem, pos, placeholder, context, copyToStore);
}
break; break;
} }
case nExternal: case nExternal:
v.external->printValueAsJSON(state, strict, out, context, copyToStore); return v.external->printValueAsJSON(state, strict, context, copyToStore);
break; break;
case nFloat: case nFloat:
out.write(v.fpoint); out = v.fpoint;
break; break;
case nThunk: case nThunk:
@ -91,17 +89,17 @@ void printValueAsJSON(EvalState & state, bool strict,
state.debugThrowLastTrace(e); state.debugThrowLastTrace(e);
throw e; throw e;
} }
return out;
} }
void printValueAsJSON(EvalState & state, bool strict, void printValueAsJSON(EvalState & state, bool strict,
Value & v, const PosIdx pos, std::ostream & str, PathSet & context, bool copyToStore) Value & v, const PosIdx pos, std::ostream & str, PathSet & context, bool copyToStore)
{ {
JSONPlaceholder out(str); str << printValueAsJSON(state, strict, v, pos, context, copyToStore);
printValueAsJSON(state, strict, v, pos, out, context, copyToStore);
} }
void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict, json ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
JSONPlaceholder & out, PathSet & context, bool copyToStore) const PathSet & context, bool copyToStore) const
{ {
state.debugThrowLastTrace(TypeError("cannot convert %1% to JSON", showType())); state.debugThrowLastTrace(TypeError("cannot convert %1% to JSON", showType()));
} }

View file

@ -5,13 +5,12 @@
#include <string> #include <string>
#include <map> #include <map>
#include <nlohmann/json_fwd.hpp>
namespace nix { namespace nix {
class JSONPlaceholder; 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, JSONPlaceholder & out, PathSet & context, bool copyToStore = true);
void printValueAsJSON(EvalState & state, bool strict, void printValueAsJSON(EvalState & state, bool strict,
Value & v, const PosIdx pos, std::ostream & str, PathSet & context, bool copyToStore = true); Value & v, const PosIdx pos, std::ostream & str, PathSet & context, bool copyToStore = true);

View file

@ -7,6 +7,7 @@
#if HAVE_BOEHMGC #if HAVE_BOEHMGC
#include <gc/gc_allocator.h> #include <gc/gc_allocator.h>
#endif #endif
#include <nlohmann/json_fwd.hpp>
namespace nix { namespace nix {
@ -62,7 +63,6 @@ class StorePath;
class Store; class Store;
class EvalState; class EvalState;
class XMLWriter; class XMLWriter;
class JSONPlaceholder;
typedef int64_t NixInt; typedef int64_t NixInt;
@ -98,8 +98,8 @@ class ExternalValueBase
virtual bool operator ==(const ExternalValueBase & b) const; virtual bool operator ==(const ExternalValueBase & b) const;
/* Print the value as JSON. Defaults to unconvertable, i.e. throws an error */ /* Print the value as JSON. Defaults to unconvertable, i.e. throws an error */
virtual void printValueAsJSON(EvalState & state, bool strict, virtual nlohmann::json printValueAsJSON(EvalState & state, bool strict,
JSONPlaceholder & out, PathSet & context, bool copyToStore = true) const; PathSet & context, bool copyToStore = true) const;
/* Print the value as XML. Defaults to unevaluated */ /* Print the value as XML. Defaults to unevaluated */
virtual void printValueAsXML(EvalState & state, bool strict, bool location, virtual void printValueAsXML(EvalState & state, bool strict, bool location,

View file

@ -9,7 +9,6 @@
#include "remote-fs-accessor.hh" #include "remote-fs-accessor.hh"
#include "nar-info-disk-cache.hh" #include "nar-info-disk-cache.hh"
#include "nar-accessor.hh" #include "nar-accessor.hh"
#include "json.hh"
#include "thread-pool.hh" #include "thread-pool.hh"
#include "callback.hh" #include "callback.hh"
@ -194,19 +193,12 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
/* Optionally write a JSON file containing a listing of the /* Optionally write a JSON file containing a listing of the
contents of the NAR. */ contents of the NAR. */
if (writeNARListing) { if (writeNARListing) {
std::ostringstream jsonOut; nlohmann::json j = {
{"version", 1},
{"root", listNar(ref<FSAccessor>(narAccessor), "", true)},
};
{ upsertFile(std::string(info.path.hashPart()) + ".ls", j.dump(), "application/json");
JSONObject jsonRoot(jsonOut);
jsonRoot.attr("version", 1);
{
auto res = jsonRoot.placeholder("root");
listNar(res, ref<FSAccessor>(narAccessor), "", true);
}
}
upsertFile(std::string(info.path.hashPart()) + ".ls", jsonOut.str(), "application/json");
} }
/* Optionally maintain an index of DWARF debug info files /* Optionally maintain an index of DWARF debug info files

View file

@ -7,7 +7,6 @@
#include "finally.hh" #include "finally.hh"
#include "util.hh" #include "util.hh"
#include "archive.hh" #include "archive.hh"
#include "json.hh"
#include "compression.hh" #include "compression.hh"
#include "worker-protocol.hh" #include "worker-protocol.hh"
#include "topo-sort.hh" #include "topo-sort.hh"

View file

@ -8,7 +8,6 @@
#include "finally.hh" #include "finally.hh"
#include "util.hh" #include "util.hh"
#include "archive.hh" #include "archive.hh"
#include "json.hh"
#include "compression.hh" #include "compression.hh"
#include "daemon.hh" #include "daemon.hh"
#include "worker-protocol.hh" #include "worker-protocol.hh"
@ -56,6 +55,7 @@
#include <pwd.h> #include <pwd.h>
#include <grp.h> #include <grp.h>
#include <iostream>
namespace nix { namespace nix {

View file

@ -1,6 +1,5 @@
#include "nar-accessor.hh" #include "nar-accessor.hh"
#include "archive.hh" #include "archive.hh"
#include "json.hh"
#include <map> #include <map>
#include <stack> #include <stack>
@ -243,42 +242,43 @@ ref<FSAccessor> makeLazyNarAccessor(const std::string & listing,
return make_ref<NarAccessor>(listing, getNarBytes); return make_ref<NarAccessor>(listing, getNarBytes);
} }
void listNar(JSONPlaceholder & res, ref<FSAccessor> accessor, using nlohmann::json;
const Path & path, bool recurse) json listNar(ref<FSAccessor> accessor, const Path & path, bool recurse)
{ {
auto st = accessor->stat(path); auto st = accessor->stat(path);
auto obj = res.object(); json obj = json::object();
switch (st.type) { switch (st.type) {
case FSAccessor::Type::tRegular: case FSAccessor::Type::tRegular:
obj.attr("type", "regular"); obj["type"] = "regular";
obj.attr("size", st.fileSize); obj["size"] = st.fileSize;
if (st.isExecutable) if (st.isExecutable)
obj.attr("executable", true); obj["executable"] = true;
if (st.narOffset) if (st.narOffset)
obj.attr("narOffset", st.narOffset); obj["narOffset"] = st.narOffset;
break; break;
case FSAccessor::Type::tDirectory: 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)) { for (auto & name : accessor->readDirectory(path)) {
if (recurse) { if (recurse) {
auto res3 = res2.placeholder(name); res2[name] = listNar(accessor, path + "/" + name, true);
listNar(res3, accessor, path + "/" + name, true);
} else } else
res2.object(name); res2[name] = json::object();
} }
} }
break; break;
case FSAccessor::Type::tSymlink: case FSAccessor::Type::tSymlink:
obj.attr("type", "symlink"); obj["type"] = "symlink";
obj.attr("target", accessor->readLink(path)); obj["target"] = accessor->readLink(path);
break; break;
default: default:
throw Error("path '%s' does not exist in NAR", path); throw Error("path '%s' does not exist in NAR", path);
} }
return obj;
} }
} }

View file

@ -2,6 +2,7 @@
#include <functional> #include <functional>
#include <nlohmann/json_fwd.hpp>
#include "fs-accessor.hh" #include "fs-accessor.hh"
namespace nix { namespace nix {
@ -24,11 +25,8 @@ ref<FSAccessor> makeLazyNarAccessor(
const std::string & listing, const std::string & listing,
GetNarBytes getNarBytes); GetNarBytes getNarBytes);
class JSONPlaceholder;
/* Write a JSON representation of the contents of a NAR (except file /* Write a JSON representation of the contents of a NAR (except file
contents). */ contents). */
void listNar(JSONPlaceholder & res, ref<FSAccessor> accessor, nlohmann::json listNar(ref<FSAccessor> accessor, const Path & path, bool recurse);
const Path & path, bool recurse);
} }

View file

@ -2,7 +2,6 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <regex> #include <regex>
#include "json.hh"
namespace nix { namespace nix {
@ -144,17 +143,12 @@ std::optional<nlohmann::json> ParsedDerivation::prepareStructuredAttrs(Store & s
auto e = json.find("exportReferencesGraph"); auto e = json.find("exportReferencesGraph");
if (e != json.end() && e->is_object()) { if (e != json.end() && e->is_object()) {
for (auto i = e->begin(); i != e->end(); ++i) { for (auto i = e->begin(); i != e->end(); ++i) {
std::ostringstream str;
{
JSONPlaceholder jsonRoot(str, true);
StorePathSet storePaths; StorePathSet storePaths;
for (auto & p : *i) for (auto & p : *i)
storePaths.insert(store.parseStorePath(p.get<std::string>())); storePaths.insert(store.parseStorePath(p.get<std::string>()));
store.pathInfoToJSON(jsonRoot, json[i.key()] = store.pathInfoToJSON(
store.exportReferences(storePaths, inputPaths), false, true); store.exportReferences(storePaths, inputPaths), false, true);
} }
json[i.key()] = nlohmann::json::parse(str.str()); // urgh
}
} }
return json; return json;

View file

@ -1,6 +1,6 @@
#include <nlohmann/json.hpp>
#include "remote-fs-accessor.hh" #include "remote-fs-accessor.hh"
#include "nar-accessor.hh" #include "nar-accessor.hh"
#include "json.hh"
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -38,10 +38,8 @@ ref<FSAccessor> RemoteFSAccessor::addToCache(std::string_view hashPart, std::str
if (cacheDir != "") { if (cacheDir != "") {
try { try {
std::ostringstream str; nlohmann::json j = listNar(narAccessor, "", true);
JSONPlaceholder jsonRoot(str); writeFile(makeCacheFile(hashPart, "ls"), j.dump());
listNar(jsonRoot, narAccessor, "", true);
writeFile(makeCacheFile(hashPart, "ls"), str.str());
} catch (...) { } catch (...) {
ignoreException(); ignoreException();
} }

View file

@ -6,14 +6,16 @@
#include "util.hh" #include "util.hh"
#include "nar-info-disk-cache.hh" #include "nar-info-disk-cache.hh"
#include "thread-pool.hh" #include "thread-pool.hh"
#include "json.hh"
#include "url.hh" #include "url.hh"
#include "archive.hh" #include "archive.hh"
#include "callback.hh" #include "callback.hh"
#include "remote-store.hh" #include "remote-store.hh"
#include <nlohmann/json.hpp>
#include <regex> #include <regex>
using json = nlohmann::json;
namespace nix { namespace nix {
@ -838,56 +840,53 @@ StorePathSet Store::exportReferences(const StorePathSet & storePaths, const Stor
return paths; return paths;
} }
json Store::pathInfoToJSON(const StorePathSet & storePaths,
void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & storePaths,
bool includeImpureInfo, bool showClosureSize, bool includeImpureInfo, bool showClosureSize,
Base hashBase, Base hashBase,
AllowInvalidFlag allowInvalid) AllowInvalidFlag allowInvalid)
{ {
auto jsonList = jsonOut.list(); json::array_t jsonList = json::array();
for (auto & storePath : storePaths) { for (auto & storePath : storePaths) {
auto jsonPath = jsonList.object(); auto& jsonPath = jsonList.emplace_back(json::object());
try { try {
auto info = queryPathInfo(storePath); auto info = queryPathInfo(storePath);
jsonPath.attr("path", printStorePath(info->path)); jsonPath["path"] = printStorePath(info->path);
jsonPath jsonPath["narHash"] = info->narHash.to_string(hashBase, true);
.attr("narHash", info->narHash.to_string(hashBase, true)) jsonPath["narSize"] = info->narSize;
.attr("narSize", info->narSize);
{ {
auto jsonRefs = jsonPath.list("references"); auto& jsonRefs = (jsonPath["references"] = json::array());
for (auto & ref : info->references) for (auto & ref : info->references)
jsonRefs.elem(printStorePath(ref)); jsonRefs.emplace_back(printStorePath(ref));
} }
if (info->ca) if (info->ca)
jsonPath.attr("ca", renderContentAddress(info->ca)); jsonPath["ca"] = renderContentAddress(info->ca);
std::pair<uint64_t, uint64_t> closureSizes; std::pair<uint64_t, uint64_t> closureSizes;
if (showClosureSize) { if (showClosureSize) {
closureSizes = getClosureSize(info->path); closureSizes = getClosureSize(info->path);
jsonPath.attr("closureSize", closureSizes.first); jsonPath["closureSize"] = closureSizes.first;
} }
if (includeImpureInfo) { if (includeImpureInfo) {
if (info->deriver) if (info->deriver)
jsonPath.attr("deriver", printStorePath(*info->deriver)); jsonPath["deriver"] = printStorePath(*info->deriver);
if (info->registrationTime) if (info->registrationTime)
jsonPath.attr("registrationTime", info->registrationTime); jsonPath["registrationTime"] = info->registrationTime;
if (info->ultimate) if (info->ultimate)
jsonPath.attr("ultimate", info->ultimate); jsonPath["ultimate"] = info->ultimate;
if (!info->sigs.empty()) { if (!info->sigs.empty()) {
auto jsonSigs = jsonPath.list("signatures");
for (auto & sig : info->sigs) for (auto & sig : info->sigs)
jsonSigs.elem(sig); jsonPath["signatures"].push_back(sig);
} }
auto narInfo = std::dynamic_pointer_cast<const NarInfo>( auto narInfo = std::dynamic_pointer_cast<const NarInfo>(
@ -895,21 +894,22 @@ void Store::pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & store
if (narInfo) { if (narInfo) {
if (!narInfo->url.empty()) if (!narInfo->url.empty())
jsonPath.attr("url", narInfo->url); jsonPath["url"] = narInfo->url;
if (narInfo->fileHash) if (narInfo->fileHash)
jsonPath.attr("downloadHash", narInfo->fileHash->to_string(hashBase, true)); jsonPath["downloadHash"] = narInfo->fileHash->to_string(hashBase, true);
if (narInfo->fileSize) if (narInfo->fileSize)
jsonPath.attr("downloadSize", narInfo->fileSize); jsonPath["downloadSize"] = narInfo->fileSize;
if (showClosureSize) if (showClosureSize)
jsonPath.attr("closureDownloadSize", closureSizes.second); jsonPath["closureDownloadSize"] = closureSizes.second;
} }
} }
} catch (InvalidPath &) { } catch (InvalidPath &) {
jsonPath.attr("path", printStorePath(storePath)); jsonPath["path"] = printStorePath(storePath);
jsonPath.attr("valid", false); jsonPath["valid"] = false;
} }
} }
return jsonList;
} }

View file

@ -14,6 +14,7 @@
#include "path-info.hh" #include "path-info.hh"
#include "repair-flag.hh" #include "repair-flag.hh"
#include <nlohmann/json_fwd.hpp>
#include <atomic> #include <atomic>
#include <limits> #include <limits>
#include <map> #include <map>
@ -68,7 +69,6 @@ struct Derivation;
class FSAccessor; class FSAccessor;
class NarInfoDiskCache; class NarInfoDiskCache;
class Store; class Store;
class JSONPlaceholder;
enum CheckSigsFlag : bool { NoCheckSigs = false, CheckSigs = true }; enum CheckSigsFlag : bool { NoCheckSigs = false, CheckSigs = true };
@ -512,7 +512,7 @@ public:
variable elements such as the registration time are variable elements such as the registration time are
included. If showClosureSize is true, the closure size of included. If showClosureSize is true, the closure size of
each path is included. */ each path is included. */
void pathInfoToJSON(JSONPlaceholder & jsonOut, const StorePathSet & storePaths, nlohmann::json pathInfoToJSON(const StorePathSet & storePaths,
bool includeImpureInfo, bool showClosureSize, bool includeImpureInfo, bool showClosureSize,
Base hashBase = Base32, Base hashBase = Base32,
AllowInvalidFlag allowInvalid = DisallowInvalid); AllowInvalidFlag allowInvalid = DisallowInvalid);

View file

@ -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);
}
}
}

View file

@ -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();
};
}

View file

@ -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"])#");
}
}

View file

@ -12,7 +12,6 @@
#include "local-fs-store.hh" #include "local-fs-store.hh"
#include "user-env.hh" #include "user-env.hh"
#include "util.hh" #include "util.hh"
#include "json.hh"
#include "value-to-json.hh" #include "value-to-json.hh"
#include "xml-writer.hh" #include "xml-writer.hh"
#include "legacy.hh" #include "legacy.hh"
@ -26,6 +25,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <nlohmann/json.hpp>
using namespace nix; using namespace nix;
using std::cout; using std::cout;
@ -911,43 +911,47 @@ static VersionDiff compareVersionAgainstSet(
static void queryJSON(Globals & globals, std::vector<DrvInfo> & elems, bool printOutPath, bool printMeta) 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) { for (auto & i : elems) {
try { try {
if (i.hasFailed()) continue; if (i.hasFailed()) continue;
JSONObject pkgObj = topObj.object(i.attrPath);
auto drvName = DrvName(i.queryName()); auto drvName = DrvName(i.queryName());
pkgObj.attr("name", drvName.fullName); json &pkgObj = topObj[i.attrPath];
pkgObj.attr("pname", drvName.name); pkgObj = {
pkgObj.attr("version", drvName.version); {"name", drvName.fullName},
pkgObj.attr("system", i.querySystem()); {"pname", drvName.name},
pkgObj.attr("outputName", i.queryOutputName()); {"version", drvName.version},
{"system", i.querySystem()},
{"outputName", i.queryOutputName()},
};
{ {
DrvInfo::Outputs outputs = i.queryOutputs(printOutPath); DrvInfo::Outputs outputs = i.queryOutputs(printOutPath);
JSONObject outputObj = pkgObj.object("outputs"); json &outputObj = pkgObj["outputs"];
outputObj = json::object();
for (auto & j : outputs) { for (auto & j : outputs) {
if (j.second) if (j.second)
outputObj.attr(j.first, globals.state->store->printStorePath(*j.second)); outputObj[j.first] = globals.state->store->printStorePath(*j.second);
else else
outputObj.attr(j.first, nullptr); outputObj[j.first] = nullptr;
} }
} }
if (printMeta) { if (printMeta) {
JSONObject metaObj = pkgObj.object("meta"); json &metaObj = pkgObj["meta"];
metaObj = json::object();
StringSet metaNames = i.queryMetaNames(); StringSet metaNames = i.queryMetaNames();
for (auto & j : metaNames) { for (auto & j : metaNames) {
Value * v = i.queryMeta(j); Value * v = i.queryMeta(j);
if (!v) { if (!v) {
printError("derivation '%s' has invalid meta attribute '%s'", i.queryName(), j); printError("derivation '%s' has invalid meta attribute '%s'", i.queryName(), j);
metaObj.attr(j, nullptr); metaObj[j] = nullptr;
} else { } else {
auto placeholder = metaObj.placeholder(j);
PathSet context; 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; throw;
} }
} }
std::cout << topObj.dump(2);
} }

View file

@ -4,10 +4,11 @@
#include "store-api.hh" #include "store-api.hh"
#include "eval.hh" #include "eval.hh"
#include "eval-inline.hh" #include "eval-inline.hh"
#include "json.hh"
#include "value-to-json.hh" #include "value-to-json.hh"
#include "progress-bar.hh" #include "progress-bar.hh"
#include <nlohmann/json.hpp>
using namespace nix; using namespace nix;
struct CmdEval : MixJSON, InstallableCommand struct CmdEval : MixJSON, InstallableCommand
@ -115,9 +116,7 @@ struct CmdEval : MixJSON, InstallableCommand
} }
else if (json) { else if (json) {
JSONPlaceholder jsonOut(std::cout); std::cout << printValueAsJSON(*state, true, *v, pos, context, false).dump() << std::endl;
printValueAsJSON(*state, true, *v, pos, jsonOut, context, false);
std::cout << std::endl;
} }
else { else {

View file

@ -11,7 +11,6 @@
#include "attr-path.hh" #include "attr-path.hh"
#include "fetchers.hh" #include "fetchers.hh"
#include "registry.hh" #include "registry.hh"
#include "json.hh"
#include "eval-cache.hh" #include "eval-cache.hh"
#include "markdown.hh" #include "markdown.hh"
@ -21,6 +20,7 @@
using namespace nix; using namespace nix;
using namespace nix::flake; using namespace nix::flake;
using json = nlohmann::json;
class FlakeCommand : virtual Args, public MixFlakeOptions class FlakeCommand : virtual Args, public MixFlakeOptions
{ {
@ -917,35 +917,44 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun
{ {
auto flake = lockFlake(); auto flake = lockFlake();
auto jsonRoot = json ? std::optional<JSONObject>(std::cout) : std::nullopt;
StorePathSet sources; StorePathSet sources;
sources.insert(flake.flake.sourceInfo->storePath); sources.insert(flake.flake.sourceInfo->storePath);
if (jsonRoot)
jsonRoot->attr("path", store->printStorePath(flake.flake.sourceInfo->storePath));
// FIXME: use graph output, handle cycles. // FIXME: use graph output, handle cycles.
std::function<void(const Node & node, std::optional<JSONObject> & jsonObj)> traverse; std::function<nlohmann::json(const Node & node)> traverse;
traverse = [&](const Node & node, std::optional<JSONObject> & jsonObj) 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) { for (auto & [inputName, input] : node.inputs) {
if (auto inputNode = std::get_if<0>(&input)) { if (auto inputNode = std::get_if<0>(&input)) {
auto jsonObj3 = jsonObj2 ? jsonObj2->object(inputName) : std::optional<JSONObject>();
auto storePath = auto storePath =
dryRun dryRun
? (*inputNode)->lockedRef.input.computeStorePath(*store) ? (*inputNode)->lockedRef.input.computeStorePath(*store)
: (*inputNode)->lockedRef.input.fetch(store).first.storePath; : (*inputNode)->lockedRef.input.fetch(store).first.storePath;
if (jsonObj3) if (json) {
jsonObj3->attr("path", store->printStorePath(storePath)); auto& jsonObj3 = jsonObj2[inputName];
jsonObj3["path"] = store->printStorePath(storePath);
sources.insert(std::move(storePath)); sources.insert(std::move(storePath));
traverse(**inputNode, jsonObj3); 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()) { if (!dryRun && !dstUri.empty()) {
ref<Store> dstStore = dstUri.empty() ? openStore() : openStore(dstUri); ref<Store> dstStore = dstUri.empty() ? openStore() : openStore(dstUri);

View file

@ -3,7 +3,7 @@
#include "fs-accessor.hh" #include "fs-accessor.hh"
#include "nar-accessor.hh" #include "nar-accessor.hh"
#include "common-args.hh" #include "common-args.hh"
#include "json.hh" #include <nlohmann/json.hpp>
using namespace nix; using namespace nix;
@ -91,10 +91,9 @@ struct MixLs : virtual Args, MixJSON
if (path == "/") path = ""; if (path == "/") path = "";
if (json) { if (json) {
JSONPlaceholder jsonRoot(std::cout);
if (showDirectory) if (showDirectory)
throw UsageError("'--directory' is useless with '--json'"); throw UsageError("'--directory' is useless with '--json'");
listNar(jsonRoot, accessor, path, recursive); std::cout << listNar(accessor, path, recursive);
} else } else
listText(accessor); listText(accessor);
} }

View file

@ -2,10 +2,13 @@
#include "store-api.hh" #include "store-api.hh"
#include "make-content-addressed.hh" #include "make-content-addressed.hh"
#include "common-args.hh" #include "common-args.hh"
#include "json.hh"
#include <nlohmann/json.hpp>
using namespace nix; using namespace nix;
using nlohmann::json;
struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand, MixJSON struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand, MixJSON
{ {
CmdMakeContentAddressed() CmdMakeContentAddressed()
@ -25,6 +28,7 @@ struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand,
; ;
} }
using StorePathsCommand::run;
void run(ref<Store> srcStore, StorePaths && storePaths) override void run(ref<Store> srcStore, StorePaths && storePaths) override
{ {
auto dstStore = dstUri.empty() ? openStore() : openStore(dstUri); auto dstStore = dstUri.empty() ? openStore() : openStore(dstUri);
@ -33,13 +37,13 @@ struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand,
StorePathSet(storePaths.begin(), storePaths.end())); StorePathSet(storePaths.begin(), storePaths.end()));
if (json) { if (json) {
JSONObject jsonRoot(std::cout); nlohmann::json jsonRewrites = json::object();
JSONObject jsonRewrites(jsonRoot.object("rewrites"));
for (auto & path : storePaths) { for (auto & path : storePaths) {
auto i = remappings.find(path); auto i = remappings.find(path);
assert(i != remappings.end()); 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 { } else {
for (auto & path : storePaths) { for (auto & path : storePaths) {
auto i = remappings.find(path); auto i = remappings.find(path);

View file

@ -1,12 +1,13 @@
#include "command.hh" #include "command.hh"
#include "shared.hh" #include "shared.hh"
#include "store-api.hh" #include "store-api.hh"
#include "json.hh"
#include "common-args.hh" #include "common-args.hh"
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <nlohmann/json.hpp>
using namespace nix; using namespace nix;
struct CmdPathInfo : StorePathsCommand, MixJSON struct CmdPathInfo : StorePathsCommand, MixJSON
@ -86,11 +87,10 @@ struct CmdPathInfo : StorePathsCommand, MixJSON
pathLen = std::max(pathLen, store->printStorePath(storePath).size()); pathLen = std::max(pathLen, store->printStorePath(storePath).size());
if (json) { if (json) {
JSONPlaceholder jsonRoot(std::cout); std::cout << store->pathInfoToJSON(
store->pathInfoToJSON(jsonRoot,
// FIXME: preserve order? // FIXME: preserve order?
StorePathSet(storePaths.begin(), storePaths.end()), StorePathSet(storePaths.begin(), storePaths.end()),
true, showClosureSize, SRI, AllowInvalid); true, showClosureSize, SRI, AllowInvalid).dump();
} }
else { else {

View file

@ -5,7 +5,6 @@
#include "names.hh" #include "names.hh"
#include "get-drvs.hh" #include "get-drvs.hh"
#include "common-args.hh" #include "common-args.hh"
#include "json.hh"
#include "shared.hh" #include "shared.hh"
#include "eval-cache.hh" #include "eval-cache.hh"
#include "attr-path.hh" #include "attr-path.hh"
@ -13,8 +12,10 @@
#include <regex> #include <regex>
#include <fstream> #include <fstream>
#include <nlohmann/json.hpp>
using namespace nix; using namespace nix;
using json = nlohmann::json;
std::string wrap(std::string prefix, std::string s) std::string wrap(std::string prefix, std::string s)
{ {
@ -84,7 +85,8 @@ struct CmdSearch : InstallableCommand, MixJSON
auto state = getEvalState(); 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; uint64_t results = 0;
@ -151,10 +153,11 @@ struct CmdSearch : InstallableCommand, MixJSON
{ {
results++; results++;
if (json) { if (json) {
auto jsonElem = jsonOut->object(attrPath2); (*jsonOut)[attrPath2] = {
jsonElem.attr("pname", name.name); {"pname", name.name},
jsonElem.attr("version", name.version); {"version", name.version},
jsonElem.attr("description", description); {"description", description},
};
} else { } else {
auto name2 = hiliteMatches(name.name, nameMatches, ANSI_GREEN, "\e[0;2m"); auto name2 = hiliteMatches(name.name, nameMatches, ANSI_GREEN, "\e[0;2m");
if (results > 1) logger->cout(""); if (results > 1) logger->cout("");
@ -193,6 +196,10 @@ struct CmdSearch : InstallableCommand, MixJSON
for (auto & cursor : installable->getCursors(*state)) for (auto & cursor : installable->getCursors(*state))
visit(*cursor, cursor->getAttrPath(), true); visit(*cursor, cursor->getAttrPath(), true);
if (json) {
std::cout << jsonOut->dump() << std::endl;
}
if (!json && !results) if (!json && !results)
throw Error("no results for the given search term(s)!"); throw Error("no results for the given search term(s)!");
} }

View file

@ -5,10 +5,11 @@
#include "common-args.hh" #include "common-args.hh"
#include "store-api.hh" #include "store-api.hh"
#include "archive.hh" #include "archive.hh"
#include "json.hh"
#include "derivations.hh" #include "derivations.hh"
#include <nlohmann/json.hpp>
using namespace nix; using namespace nix;
using json = nlohmann::json;
struct CmdShowDerivation : InstallablesCommand struct CmdShowDerivation : InstallablesCommand
{ {
@ -48,77 +49,63 @@ struct CmdShowDerivation : InstallablesCommand
drvPaths = std::move(closure); drvPaths = std::move(closure);
} }
{ json jsonRoot = json::object();
JSONObject jsonRoot(std::cout, true);
for (auto & drvPath : drvPaths) { for (auto & drvPath : drvPaths) {
if (!drvPath.isDerivation()) continue; if (!drvPath.isDerivation()) continue;
auto drvObj(jsonRoot.object(store->printStorePath(drvPath))); json& drvObj = jsonRoot[store->printStorePath(drvPath)];
auto drv = store->readDerivation(drvPath); auto drv = store->readDerivation(drvPath);
{ {
auto outputsObj(drvObj.object("outputs")); json& outputsObj = drvObj["outputs"];
outputsObj = json::object();
for (auto & [_outputName, output] : drv.outputs) { for (auto & [_outputName, output] : drv.outputs) {
auto & outputName = _outputName; // work around clang bug auto & outputName = _outputName; // work around clang bug
auto outputObj { outputsObj.object(outputName) }; auto& outputObj = outputsObj[outputName];
outputObj = json::object();
std::visit(overloaded { std::visit(overloaded {
[&](const DerivationOutput::InputAddressed & doi) { [&](const DerivationOutput::InputAddressed & doi) {
outputObj.attr("path", store->printStorePath(doi.path)); outputObj["path"] = store->printStorePath(doi.path);
}, },
[&](const DerivationOutput::CAFixed & dof) { [&](const DerivationOutput::CAFixed & dof) {
outputObj.attr("path", store->printStorePath(dof.path(*store, drv.name, outputName))); outputObj["path"] = store->printStorePath(dof.path(*store, drv.name, outputName));
outputObj.attr("hashAlgo", dof.hash.printMethodAlgo()); outputObj["hashAlgo"] = dof.hash.printMethodAlgo();
outputObj.attr("hash", dof.hash.hash.to_string(Base16, false)); outputObj["hash"] = dof.hash.hash.to_string(Base16, false);
}, },
[&](const DerivationOutput::CAFloating & dof) { [&](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::Deferred &) {},
[&](const DerivationOutput::Impure & doi) { [&](const DerivationOutput::Impure & doi) {
outputObj.attr("hashAlgo", makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType)); outputObj["hashAlgo"] = makeFileIngestionPrefix(doi.method) + printHashType(doi.hashType);
outputObj.attr("impure", true); outputObj["impure"] = true;
}, },
}, output.raw()); }, output.raw());
} }
} }
{ {
auto inputsList(drvObj.list("inputSrcs")); auto& inputsList = drvObj["inputSrcs"];
inputsList = json::array();
for (auto & input : drv.inputSrcs) for (auto & input : drv.inputSrcs)
inputsList.elem(store->printStorePath(input)); inputsList.emplace_back(store->printStorePath(input));
} }
{ {
auto inputDrvsObj(drvObj.object("inputDrvs")); auto& inputDrvsObj = drvObj["inputDrvs"];
for (auto & input : drv.inputDrvs) { inputDrvsObj = json::object();
auto inputList(inputDrvsObj.list(store->printStorePath(input.first))); for (auto & input : drv.inputDrvs)
for (auto & outputId : input.second) inputDrvsObj[store->printStorePath(input.first)] = input.second;
inputList.elem(outputId);
}
} }
drvObj.attr("system", drv.platform); drvObj["system"] = drv.platform;
drvObj.attr("builder", drv.builder); drvObj["builder"] = drv.builder;
drvObj["args"] = drv.args;
{ drvObj["env"] = drv.env;
auto argsList(drvObj.list("args"));
for (auto & arg : drv.args)
argsList.elem(arg);
} }
std::cout << jsonRoot.dump(2) << std::endl;
{
auto envObj(drvObj.object("env"));
for (auto & var : drv.env)
envObj.attr(var.first, var.second);
}
}
}
std::cout << "\n";
} }
}; };