forked from lix-project/lix
nix path-info: Add --json flag
Also, factor out JSON generation from value-to-json.{cc,hh}, and support producing indented JSON.
This commit is contained in:
parent
9fa21765e7
commit
c0a7b84748
|
@ -1,4 +1,5 @@
|
||||||
#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"
|
||||||
|
|
||||||
|
@ -8,24 +9,8 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
void escapeJSON(std::ostream & str, const string & s)
|
|
||||||
{
|
|
||||||
str << "\"";
|
|
||||||
for (auto & i : s)
|
|
||||||
if (i == '\"' || i == '\\') str << "\\" << i;
|
|
||||||
else if (i == '\n') str << "\\n";
|
|
||||||
else if (i == '\r') str << "\\r";
|
|
||||||
else if (i == '\t') str << "\\t";
|
|
||||||
else if (i >= 0 && i < 32)
|
|
||||||
str << "\\u" << std::setfill('0') << std::setw(4) << std::hex << (uint16_t) i << std::dec;
|
|
||||||
else str << i;
|
|
||||||
str << "\"";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void printValueAsJSON(EvalState & state, bool strict,
|
void printValueAsJSON(EvalState & state, bool strict,
|
||||||
Value & v, std::ostream & str, PathSet & context)
|
Value & v, JSONPlaceholder & out, PathSet & context)
|
||||||
{
|
{
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
|
||||||
|
@ -34,58 +19,58 @@ void printValueAsJSON(EvalState & state, bool strict,
|
||||||
switch (v.type) {
|
switch (v.type) {
|
||||||
|
|
||||||
case tInt:
|
case tInt:
|
||||||
str << v.integer;
|
out.write(v.integer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tBool:
|
case tBool:
|
||||||
str << (v.boolean ? "true" : "false");
|
out.write(v.boolean);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tString:
|
case tString:
|
||||||
copyContext(v, context);
|
copyContext(v, context);
|
||||||
escapeJSON(str, v.string.s);
|
out.write(v.string.s);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tPath:
|
case tPath:
|
||||||
escapeJSON(str, state.copyPathToStore(context, v.path));
|
out.write(state.copyPathToStore(context, v.path));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tNull:
|
case tNull:
|
||||||
str << "null";
|
out.write(nullptr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tAttrs: {
|
case tAttrs: {
|
||||||
Bindings::iterator i = v.attrs->find(state.sOutPath);
|
Bindings::iterator i = v.attrs->find(state.sOutPath);
|
||||||
if (i == v.attrs->end()) {
|
if (i == v.attrs->end()) {
|
||||||
JSONObject json(str);
|
auto obj(out.object());
|
||||||
StringSet names;
|
StringSet names;
|
||||||
for (auto & j : *v.attrs)
|
for (auto & j : *v.attrs)
|
||||||
names.insert(j.name);
|
names.insert(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)));
|
||||||
json.attr(j);
|
auto placeholder(obj.placeholder(j));
|
||||||
printValueAsJSON(state, strict, *a.value, str, context);
|
printValueAsJSON(state, strict, *a.value, placeholder, context);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
printValueAsJSON(state, strict, *i->value, str, context);
|
printValueAsJSON(state, strict, *i->value, out, context);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case tList1: case tList2: case tListN: {
|
case tList1: case tList2: case tListN: {
|
||||||
JSONList json(str);
|
auto list(out.list());
|
||||||
for (unsigned int n = 0; n < v.listSize(); ++n) {
|
for (unsigned int n = 0; n < v.listSize(); ++n) {
|
||||||
json.elem();
|
auto placeholder(list.placeholder());
|
||||||
printValueAsJSON(state, strict, *v.listElems()[n], str, context);
|
printValueAsJSON(state, strict, *v.listElems()[n], placeholder, context);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case tExternal:
|
case tExternal:
|
||||||
v.external->printValueAsJSON(state, strict, str, context);
|
v.external->printValueAsJSON(state, strict, out, context);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case tFloat:
|
case tFloat:
|
||||||
str << v.fpoint;
|
out.write(v.fpoint);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -93,9 +78,15 @@ void printValueAsJSON(EvalState & state, bool strict,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void printValueAsJSON(EvalState & state, bool strict,
|
||||||
|
Value & v, std::ostream & str, PathSet & context)
|
||||||
|
{
|
||||||
|
JSONPlaceholder out(str);
|
||||||
|
printValueAsJSON(state, strict, v, out, context);
|
||||||
|
}
|
||||||
|
|
||||||
void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
|
void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
|
||||||
std::ostream & str, PathSet & context) const
|
JSONPlaceholder & out, PathSet & context) const
|
||||||
{
|
{
|
||||||
throw TypeError(format("cannot convert %1% to JSON") % showType());
|
throw TypeError(format("cannot convert %1% to JSON") % showType());
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,73 +8,12 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
class JSONPlaceholder;
|
||||||
|
|
||||||
void printValueAsJSON(EvalState & state, bool strict,
|
void printValueAsJSON(EvalState & state, bool strict,
|
||||||
Value & v, std::ostream & out, PathSet & context);
|
Value & v, JSONPlaceholder & out, PathSet & context);
|
||||||
|
|
||||||
void escapeJSON(std::ostream & str, const string & s);
|
void printValueAsJSON(EvalState & state, bool strict,
|
||||||
|
Value & v, std::ostream & str, PathSet & context);
|
||||||
struct JSONObject
|
|
||||||
{
|
|
||||||
std::ostream & str;
|
|
||||||
bool first;
|
|
||||||
JSONObject(std::ostream & str) : str(str), first(true)
|
|
||||||
{
|
|
||||||
str << "{";
|
|
||||||
}
|
|
||||||
~JSONObject()
|
|
||||||
{
|
|
||||||
str << "}";
|
|
||||||
}
|
|
||||||
void attr(const string & s)
|
|
||||||
{
|
|
||||||
if (!first) str << ","; else first = false;
|
|
||||||
escapeJSON(str, s);
|
|
||||||
str << ":";
|
|
||||||
}
|
|
||||||
void attr(const string & s, const string & t)
|
|
||||||
{
|
|
||||||
attr(s);
|
|
||||||
escapeJSON(str, t);
|
|
||||||
}
|
|
||||||
void attr(const string & s, const char * t)
|
|
||||||
{
|
|
||||||
attr(s);
|
|
||||||
escapeJSON(str, t);
|
|
||||||
}
|
|
||||||
void attr(const string & s, bool b)
|
|
||||||
{
|
|
||||||
attr(s);
|
|
||||||
str << (b ? "true" : "false");
|
|
||||||
}
|
|
||||||
template<typename T>
|
|
||||||
void attr(const string & s, const T & n)
|
|
||||||
{
|
|
||||||
attr(s);
|
|
||||||
str << n;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct JSONList
|
|
||||||
{
|
|
||||||
std::ostream & str;
|
|
||||||
bool first;
|
|
||||||
JSONList(std::ostream & str) : str(str), first(true)
|
|
||||||
{
|
|
||||||
str << "[";
|
|
||||||
}
|
|
||||||
~JSONList()
|
|
||||||
{
|
|
||||||
str << "]";
|
|
||||||
}
|
|
||||||
void elem()
|
|
||||||
{
|
|
||||||
if (!first) str << ","; else first = false;
|
|
||||||
}
|
|
||||||
void elem(const string & s)
|
|
||||||
{
|
|
||||||
elem();
|
|
||||||
escapeJSON(str, s);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ class Symbol;
|
||||||
struct Pos;
|
struct Pos;
|
||||||
class EvalState;
|
class EvalState;
|
||||||
class XMLWriter;
|
class XMLWriter;
|
||||||
|
class JSONPlaceholder;
|
||||||
|
|
||||||
|
|
||||||
typedef long NixInt;
|
typedef long NixInt;
|
||||||
|
@ -73,7 +74,7 @@ class ExternalValueBase
|
||||||
|
|
||||||
/* 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 void printValueAsJSON(EvalState & state, bool strict,
|
||||||
std::ostream & str, PathSet & context) const;
|
JSONPlaceholder & out, PathSet & context) 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,
|
||||||
|
|
171
src/libutil/json.cc
Normal file
171
src/libutil/json.cc
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
#include "json.hh"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
void toJSON(std::ostream & str, const char * start, const char * end)
|
||||||
|
{
|
||||||
|
str << '"';
|
||||||
|
for (auto i = start; i != end; i++)
|
||||||
|
if (*i == '\"' || *i == '\\') str << '\\' << *i;
|
||||||
|
else if (*i == '\n') str << "\\n";
|
||||||
|
else if (*i == '\r') str << "\\r";
|
||||||
|
else if (*i == '\t') str << "\\t";
|
||||||
|
else if (*i >= 0 && *i < 32)
|
||||||
|
str << "\\u" << std::setfill('0') << std::setw(4) << std::hex << (uint16_t) *i << std::dec;
|
||||||
|
else str << *i;
|
||||||
|
str << '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
void toJSON(std::ostream & str, const std::string & s)
|
||||||
|
{
|
||||||
|
toJSON(str, s.c_str(), s.c_str() + s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void toJSON(std::ostream & str, const char * s)
|
||||||
|
{
|
||||||
|
if (!s) str << "null"; else toJSON(str, s, s + strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
void toJSON(std::ostream & str, unsigned long n)
|
||||||
|
{
|
||||||
|
str << n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void toJSON(std::ostream & str, long n)
|
||||||
|
{
|
||||||
|
str << n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void toJSON(std::ostream & str, double f)
|
||||||
|
{
|
||||||
|
str << f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void toJSON(std::ostream & str, bool b)
|
||||||
|
{
|
||||||
|
str << (b ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONWriter::JSONWriter(std::ostream & str, bool indent)
|
||||||
|
: state(new JSONState(str, indent))
|
||||||
|
{
|
||||||
|
state->stack.push_back(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONWriter::JSONWriter(JSONState * state)
|
||||||
|
: state(state)
|
||||||
|
{
|
||||||
|
state->stack.push_back(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONWriter::~JSONWriter()
|
||||||
|
{
|
||||||
|
assertActive();
|
||||||
|
state->stack.pop_back();
|
||||||
|
if (state->stack.empty()) 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()
|
||||||
|
{
|
||||||
|
state->depth--;
|
||||||
|
if (state->indent && !first) indent();
|
||||||
|
state->str << "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSONObject::attr(const std::string & s)
|
||||||
|
{
|
||||||
|
comma();
|
||||||
|
toJSON(state->str, s);
|
||||||
|
state->str << ':';
|
||||||
|
if (state->indent) state->str << ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONList JSONObject::list(const std::string & name)
|
||||||
|
{
|
||||||
|
attr(name);
|
||||||
|
return JSONList(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject JSONObject::object(const std::string & name)
|
||||||
|
{
|
||||||
|
attr(name);
|
||||||
|
return JSONObject(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONPlaceholder JSONObject::placeholder(const std::string & name)
|
||||||
|
{
|
||||||
|
attr(name);
|
||||||
|
return JSONPlaceholder(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONList JSONPlaceholder::list()
|
||||||
|
{
|
||||||
|
assertValid();
|
||||||
|
first = false;
|
||||||
|
return JSONList(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject JSONPlaceholder::object()
|
||||||
|
{
|
||||||
|
assertValid();
|
||||||
|
first = false;
|
||||||
|
return JSONObject(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
183
src/libutil/json.hh
Normal file
183
src/libutil/json.hh
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
void toJSON(std::ostream & str, const char * start, const char * end);
|
||||||
|
void toJSON(std::ostream & str, const std::string & s);
|
||||||
|
void toJSON(std::ostream & str, const char * s);
|
||||||
|
void toJSON(std::ostream & str, unsigned long n);
|
||||||
|
void toJSON(std::ostream & str, long n);
|
||||||
|
void toJSON(std::ostream & str, double f);
|
||||||
|
void toJSON(std::ostream & str, bool b);
|
||||||
|
|
||||||
|
class JSONWriter
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
|
||||||
|
struct JSONState
|
||||||
|
{
|
||||||
|
std::ostream & str;
|
||||||
|
bool indent;
|
||||||
|
size_t depth = 0;
|
||||||
|
std::vector<JSONWriter *> stack;
|
||||||
|
JSONState(std::ostream & str, bool indent) : str(str), indent(indent) { }
|
||||||
|
~JSONState()
|
||||||
|
{
|
||||||
|
assert(stack.empty());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JSONState * state;
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
|
JSONWriter(std::ostream & str, bool indent);
|
||||||
|
|
||||||
|
JSONWriter(JSONState * state);
|
||||||
|
|
||||||
|
~JSONWriter();
|
||||||
|
|
||||||
|
void assertActive()
|
||||||
|
{
|
||||||
|
assert(!state->stack.empty() && state->stack.back() == this);
|
||||||
|
}
|
||||||
|
|
||||||
|
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(const std::string & s);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
JSONObject(std::ostream & str, bool indent = false)
|
||||||
|
: JSONWriter(str, indent)
|
||||||
|
{
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
|
||||||
|
~JSONObject();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
JSONObject & attr(const std::string & name, const T & v)
|
||||||
|
{
|
||||||
|
attr(name);
|
||||||
|
toJSON(state->str, v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONList list(const std::string & name);
|
||||||
|
|
||||||
|
JSONObject object(const std::string & name);
|
||||||
|
|
||||||
|
JSONPlaceholder placeholder(const std::string & 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()
|
||||||
|
{
|
||||||
|
assert(!first || std::uncaught_exception());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void write(const T & v)
|
||||||
|
{
|
||||||
|
assertValid();
|
||||||
|
first = false;
|
||||||
|
toJSON(state->str, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONList list();
|
||||||
|
|
||||||
|
JSONObject object();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -10,6 +10,7 @@
|
||||||
#include "store-api.hh"
|
#include "store-api.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"
|
||||||
|
|
||||||
|
@ -860,26 +861,24 @@ static VersionDiff compareVersionAgainstSet(
|
||||||
|
|
||||||
static void queryJSON(Globals & globals, vector<DrvInfo> & elems)
|
static void queryJSON(Globals & globals, vector<DrvInfo> & elems)
|
||||||
{
|
{
|
||||||
JSONObject topObj(cout);
|
JSONObject topObj(cout, true);
|
||||||
for (auto & i : elems) {
|
for (auto & i : elems) {
|
||||||
topObj.attr(i.attrPath);
|
JSONObject pkgObj = topObj.object(i.attrPath);
|
||||||
JSONObject pkgObj(cout);
|
|
||||||
|
|
||||||
pkgObj.attr("name", i.name);
|
pkgObj.attr("name", i.name);
|
||||||
pkgObj.attr("system", i.system);
|
pkgObj.attr("system", i.system);
|
||||||
|
|
||||||
pkgObj.attr("meta");
|
JSONObject metaObj = pkgObj.object("meta");
|
||||||
JSONObject metaObj(cout);
|
|
||||||
StringSet metaNames = i.queryMetaNames();
|
StringSet metaNames = i.queryMetaNames();
|
||||||
for (auto & j : metaNames) {
|
for (auto & j : metaNames) {
|
||||||
metaObj.attr(j);
|
auto placeholder = metaObj.placeholder(j);
|
||||||
Value * v = i.queryMeta(j);
|
Value * v = i.queryMeta(j);
|
||||||
if (!v) {
|
if (!v) {
|
||||||
printMsg(lvlError, format("derivation ‘%1%’ has invalid meta attribute ‘%2%’") % i.name % j);
|
printMsg(lvlError, format("derivation ‘%1%’ has invalid meta attribute ‘%2%’") % i.name % j);
|
||||||
cout << "null";
|
placeholder.write(nullptr);
|
||||||
} else {
|
} else {
|
||||||
PathSet context;
|
PathSet context;
|
||||||
printValueAsJSON(*globals.state, true, *v, cout, context);
|
printValueAsJSON(*globals.state, true, *v, placeholder, context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
#include "shared.hh"
|
#include "shared.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
|
||||||
|
|
||||||
|
#include "json.hh"
|
||||||
|
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
@ -12,12 +16,14 @@ struct CmdPathInfo : StorePathsCommand
|
||||||
bool showSize = false;
|
bool showSize = false;
|
||||||
bool showClosureSize = false;
|
bool showClosureSize = false;
|
||||||
bool showSigs = false;
|
bool showSigs = false;
|
||||||
|
bool json = false;
|
||||||
|
|
||||||
CmdPathInfo()
|
CmdPathInfo()
|
||||||
{
|
{
|
||||||
mkFlag('s', "size", "print size of the NAR dump of each path", &showSize);
|
mkFlag('s', "size", "print size of the NAR dump of each path", &showSize);
|
||||||
mkFlag('S', "closure-size", "print sum size of the NAR dumps of the closure of each path", &showClosureSize);
|
mkFlag('S', "closure-size", "print sum size of the NAR dumps of the closure of each path", &showClosureSize);
|
||||||
mkFlag(0, "sigs", "show signatures", &showSigs);
|
mkFlag(0, "sigs", "show signatures", &showSigs);
|
||||||
|
mkFlag(0, "json", "produce JSON output", &json);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name() override
|
std::string name() override
|
||||||
|
@ -41,6 +47,10 @@ struct CmdPathInfo : StorePathsCommand
|
||||||
"To check the existence of a path in a binary cache:",
|
"To check the existence of a path in a binary cache:",
|
||||||
"nix path-info -r /nix/store/7qvk5c91...-geeqie-1.1 --store https://cache.nixos.org/"
|
"nix path-info -r /nix/store/7qvk5c91...-geeqie-1.1 --store https://cache.nixos.org/"
|
||||||
},
|
},
|
||||||
|
Example{
|
||||||
|
"To print the 10 most recently added paths (using --json and the jq(1) command):",
|
||||||
|
"nix path-info --all --json | jq -r 'sort_by(.registrationTime)[-11:-1][].path'"
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,36 +60,85 @@ struct CmdPathInfo : StorePathsCommand
|
||||||
for (auto & storePath : storePaths)
|
for (auto & storePath : storePaths)
|
||||||
pathLen = std::max(pathLen, storePath.size());
|
pathLen = std::max(pathLen, storePath.size());
|
||||||
|
|
||||||
for (auto storePath : storePaths) {
|
auto getClosureSize = [&](const Path & storePath) {
|
||||||
auto info = store->queryPathInfo(storePath);
|
size_t totalSize = 0;
|
||||||
storePath = info->path; // FIXME: screws up padding
|
PathSet closure;
|
||||||
|
store->computeFSClosure(storePath, closure, false, false);
|
||||||
|
for (auto & p : closure)
|
||||||
|
totalSize += store->queryPathInfo(p)->narSize;
|
||||||
|
return totalSize;
|
||||||
|
};
|
||||||
|
|
||||||
std::cout << storePath << std::string(std::max(0, (int) pathLen - (int) storePath.size()), ' ');
|
if (json) {
|
||||||
|
JSONList jsonRoot(std::cout, true);
|
||||||
|
|
||||||
if (showSize) {
|
for (auto storePath : storePaths) {
|
||||||
std::cout << '\t' << std::setw(11) << info->narSize;
|
auto info = store->queryPathInfo(storePath);
|
||||||
|
storePath = info->path;
|
||||||
|
|
||||||
|
auto jsonPath = jsonRoot.object();
|
||||||
|
jsonPath
|
||||||
|
.attr("path", storePath)
|
||||||
|
.attr("narHash", info->narHash.to_string())
|
||||||
|
.attr("narSize", info->narSize);
|
||||||
|
|
||||||
|
if (showClosureSize)
|
||||||
|
jsonPath.attr("closureSize", getClosureSize(storePath));
|
||||||
|
|
||||||
|
if (info->deriver != "")
|
||||||
|
jsonPath.attr("deriver", info->deriver);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto jsonRefs = jsonPath.list("references");
|
||||||
|
for (auto & ref : info->references)
|
||||||
|
jsonRefs.elem(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->registrationTime)
|
||||||
|
jsonPath.attr("registrationTime", info->registrationTime);
|
||||||
|
|
||||||
|
if (info->ultimate)
|
||||||
|
jsonPath.attr("ultimate", info->ultimate);
|
||||||
|
|
||||||
|
if (info->ca != "")
|
||||||
|
jsonPath.attr("ca", info->ca);
|
||||||
|
|
||||||
|
if (!info->sigs.empty()) {
|
||||||
|
auto jsonSigs = jsonPath.list("signatures");
|
||||||
|
for (auto & sig : info->sigs)
|
||||||
|
jsonSigs.elem(sig);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showClosureSize) {
|
|
||||||
size_t totalSize = 0;
|
|
||||||
PathSet closure;
|
|
||||||
store->computeFSClosure(storePath, closure, false, false);
|
|
||||||
for (auto & p : closure)
|
|
||||||
totalSize += store->queryPathInfo(p)->narSize;
|
|
||||||
std::cout << '\t' << std::setw(11) << totalSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showSigs) {
|
|
||||||
std::cout << '\t';
|
|
||||||
Strings ss;
|
|
||||||
if (info->ultimate) ss.push_back("ultimate");
|
|
||||||
if (info->ca != "") ss.push_back("ca:" + info->ca);
|
|
||||||
for (auto & sig : info->sigs) ss.push_back(sig);
|
|
||||||
std::cout << concatStringsSep(" ", ss);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
|
||||||
|
for (auto storePath : storePaths) {
|
||||||
|
auto info = store->queryPathInfo(storePath);
|
||||||
|
storePath = info->path; // FIXME: screws up padding
|
||||||
|
|
||||||
|
std::cout << storePath << std::string(std::max(0, (int) pathLen - (int) storePath.size()), ' ');
|
||||||
|
|
||||||
|
if (showSize)
|
||||||
|
std::cout << '\t' << std::setw(11) << info->narSize;
|
||||||
|
|
||||||
|
if (showClosureSize)
|
||||||
|
std::cout << '\t' << std::setw(11) << getClosureSize(storePath);
|
||||||
|
|
||||||
|
if (showSigs) {
|
||||||
|
std::cout << '\t';
|
||||||
|
Strings ss;
|
||||||
|
if (info->ultimate) ss.push_back("ultimate");
|
||||||
|
if (info->ca != "") ss.push_back("ca:" + info->ca);
|
||||||
|
for (auto & sig : info->sigs) ss.push_back(sig);
|
||||||
|
std::cout << concatStringsSep(" ", ss);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue