aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/config/config.cpp
diff options
context:
space:
mode:
authormonster <monster@ydb.tech>2022-07-07 14:41:37 +0300
committermonster <monster@ydb.tech>2022-07-07 14:41:37 +0300
commit06e5c21a835c0e923506c4ff27929f34e00761c2 (patch)
tree75efcbc6854ef9bd476eb8bf00cc5c900da436a2 /library/cpp/config/config.cpp
parent03f024c4412e3aa613bb543cf1660176320ba8f4 (diff)
downloadydb-06e5c21a835c0e923506c4ff27929f34e00761c2.tar.gz
fix ya.make
Diffstat (limited to 'library/cpp/config/config.cpp')
-rw-r--r--library/cpp/config/config.cpp425
1 files changed, 425 insertions, 0 deletions
diff --git a/library/cpp/config/config.cpp b/library/cpp/config/config.cpp
new file mode 100644
index 0000000000..e8271af661
--- /dev/null
+++ b/library/cpp/config/config.cpp
@@ -0,0 +1,425 @@
+#include "config.h"
+#include "markup.h"
+#include "ini.h"
+
+#include <library/cpp/archive/yarchive.h>
+
+#include <library/cpp/json/json_reader.h>
+#include <library/cpp/json/json_writer.h>
+
+#include <library/cpp/lua/eval.h>
+
+#include <util/string/cast.h>
+#include <util/string/strip.h>
+#include <util/string/type.h>
+
+#include <util/stream/output.h>
+#include <util/stream/file.h>
+#include <util/memory/blob.h>
+
+#include <util/generic/singleton.h>
+#include <util/stream/str.h>
+
+using namespace NConfig;
+using namespace NJson;
+
+namespace {
+ const unsigned char CODE[] = {
+#include "code.inc"
+ };
+
+ struct TCode: public TArchiveReader {
+ inline TCode()
+ : TArchiveReader(TBlob::NoCopy(CODE, sizeof(CODE)))
+ {
+ }
+
+ static inline TCode& Instance() {
+ return *Singleton<TCode>();
+ }
+ };
+
+ class TPreprocessor: public IInputStream {
+ public:
+ inline TPreprocessor(const TGlobals& g, IInputStream* in)
+ : I_(nullptr, 0)
+ , S_(in)
+ {
+ E_.SetVars(g);
+ }
+
+ size_t DoRead(void* ptr, size_t len) override {
+ while (true) {
+ const size_t read = I_.Read(ptr, len);
+
+ if (read) {
+ return read;
+ }
+
+ do {
+ if (!S_.ReadLine(C_)) {
+ return 0;
+ }
+ } while (IsComment(C_));
+
+ C_ = E_.Preprocess(C_);
+ C_.append('\n');
+ I_.Reset(C_.data(), C_.size());
+ }
+ }
+
+ static inline bool IsComment(TStringBuf s) {
+ s = StripString(s);
+
+ return !s.empty() && s[0] == '#';
+ }
+
+ private:
+ TMemoryInput I_;
+ TBufferedInput S_;
+ TLuaEval E_;
+ TString C_;
+ };
+}
+
+void TConfig::DumpJson(IOutputStream& out) const {
+ TString tmp;
+
+ {
+ TStringOutput out2(tmp);
+
+ ToJson(out2);
+ }
+
+ {
+ TJsonValue v;
+ TStringInput in(tmp);
+
+ ReadJsonTree(&in, &v);
+ WriteJson(&out, &v, true, true);
+ }
+}
+
+TConfig TConfig::FromJson(IInputStream& in, const TGlobals& g) {
+ class TJSONReader: public TJsonCallbacks {
+ public:
+ inline TJSONReader()
+ : Cur(nullptr)
+ {
+ }
+
+ inline bool OnBoolean(bool b) override {
+ *Next() = ConstructValue(b);
+
+ return true;
+ }
+
+ inline bool OnInteger(long long i) override {
+ *Next() = ConstructValue((i64)i);
+
+ return true;
+ }
+
+ inline bool OnUInteger(unsigned long long i) override {
+ *Next() = ConstructValue((ui64)i);
+
+ return true;
+ }
+
+ inline bool OnDouble(double d) override {
+ *Next() = ConstructValue(d);
+
+ return true;
+ }
+
+ inline bool OnString(const TStringBuf& s) override {
+ *Next() = ConstructValue(ToString(s));
+
+ return true;
+ }
+
+ inline bool OnOpenMap() override {
+ Push(ConstructValue(TDict()));
+
+ return true;
+ }
+
+ inline bool OnCloseMap() override {
+ Pop();
+
+ return true;
+ }
+
+ inline bool OnOpenArray() override {
+ Push(ConstructValue(TArray()));
+
+ return true;
+ }
+
+ inline bool OnCloseArray() override {
+ Pop();
+
+ return true;
+ }
+
+ inline bool OnMapKey(const TStringBuf& k) override {
+ if (S.empty()) {
+ ythrow yexception() << "shit happen";
+ }
+
+ Cur = &S.back().GetNonConstant<TDict>()[ToString(k)];
+
+ return true;
+ }
+
+ inline void Push(const TConfig& el) {
+ *Next() = el;
+ S.push_back(el);
+ }
+
+ inline void Pop() {
+ if (S.empty()) {
+ ythrow yexception() << "shit happen";
+ }
+
+ S.pop_back();
+ }
+
+ inline TConfig* Next() {
+ if (S.empty()) {
+ return &Root;
+ }
+
+ TConfig& top = S.back();
+
+ if (top.IsA<TArray>()) {
+ TArray& arr = top.GetNonConstant<TArray>();
+
+ arr.emplace_back();
+
+ return &arr.back();
+ }
+
+ if (top.IsA<TDict>()) {
+ if (Cur) {
+ TConfig* ret = Cur;
+
+ Cur = nullptr;
+
+ return ret;
+ }
+ }
+
+ ythrow yexception() << "shit happen";
+ }
+
+ inline void OnError(size_t off, TStringBuf reason) override {
+ Y_UNUSED(off);
+ if (!FirstErrorReason) {
+ FirstErrorReason = reason;
+ }
+ }
+
+ TConfig Root;
+ TConfig* Cur;
+ TVector<TConfig> S;
+ TString FirstErrorReason;
+ };
+
+ TJSONReader r;
+ TString data = in.ReadAll();
+ TMemoryInput mi(data.data(), data.size());
+ TPreprocessor p(g, &mi);
+
+ if (!NJson::ReadJson(&p, false, true, &r)) {
+ if (!!r.FirstErrorReason) {
+ ythrow TConfigParseError() << "Error parsing json: " << r.FirstErrorReason;
+ } else {
+ ythrow TConfigParseError() << "Could not parse json " << data.Quote();
+ }
+ }
+
+ return r.Root;
+}
+
+namespace {
+ struct TData {
+ const char* Prologue;
+ const char* Epilogue;
+ };
+
+ const TData DATA[] = {
+ {"", "\nassert(not (instance == nil))\nreturn instance\n"},
+ {"", "\nassert(not (main == nil))\nreturn main\n"},
+ {"return ", "\n"},
+ {"", "\n"},
+ };
+}
+
+TConfig TConfig::FromLua(IInputStream& in, const TGlobals& g) {
+ const TString& data = in.ReadAll();
+ TString json;
+
+ for (size_t i = 0; i < Y_ARRAY_SIZE(DATA); ++i) {
+ TStringStream ss;
+
+ ss << TStringBuf("local function configgen()")
+ << DATA[i].Prologue << data << DATA[i].Epilogue
+ << TStringBuf("end\n\nreturn require('json').encode(configgen())\n");
+
+ try {
+ json = TLuaEval().SetVars(g).EvalRaw(ss.Str());
+
+ break;
+ } catch (...) {
+ if (i == (Y_ARRAY_SIZE(DATA) - 1)) {
+ throw;
+ }
+ }
+ }
+
+ TMemoryInput mi(json.data(), json.size());
+
+ return FromJson(mi);
+}
+
+TConfig TConfig::FromMarkup(IInputStream& in, const TGlobals& g) {
+ TPreprocessor pin(g, &in);
+
+ return ParseRawMarkup(pin);
+}
+
+TConfig TConfig::FromIni(IInputStream& in, const TGlobals& g) {
+ TPreprocessor pin(g, &in);
+
+ return ParseIni(pin);
+}
+
+void TConfig::DumpLua(IOutputStream& out) const {
+ TLuaEval e;
+ TStringStream ss;
+
+ ToJson(ss);
+
+ e.SetVariable("jsonval", ss.Str());
+
+ out << "return " << e.EvalRaw(TCode::Instance().ObjectByKey("/pp.lua")->ReadAll() + "\nreturn prettify(require('json').decode(jsonval))\n");
+}
+
+TConfig TConfig::FromStream(IInputStream& in, const TGlobals& g) {
+ const TString& tmp = in.ReadAll();
+ TString luaParsingError = "";
+
+ try {
+ TMemoryInput mi(tmp.data(), tmp.size());
+
+ return FromLua(mi, g);
+ } catch (const yexception& e) {
+ luaParsingError = e.AsStrBuf();
+ } catch (...) {
+ luaParsingError = "unknown error";
+ }
+
+ TMemoryInput mi(tmp.data(), tmp.size());
+
+ try {
+ return FromJson(mi, g);
+ } catch (const yexception& e) {
+ const TStringBuf& jsonParsingError = e.AsStrBuf();
+ ythrow yexception() << "Could not parse config:\nParsing as lua: " << luaParsingError << "\nParsing as json: " << jsonParsingError;
+ }
+}
+
+TConfig TConfig::ReadJson(TStringBuf in, const TGlobals& g) {
+ TMemoryInput mi(in.data(), in.size());
+
+ return FromJson(mi, g);
+}
+
+TConfig TConfig::ReadLua(TStringBuf in, const TGlobals& g) {
+ TMemoryInput mi(in.data(), in.size());
+
+ return FromLua(mi, g);
+}
+
+TConfig TConfig::ReadMarkup(TStringBuf in, const TGlobals& g) {
+ TMemoryInput mi(in.data(), in.size());
+
+ return FromMarkup(mi, g);
+}
+
+TConfig TConfig::ReadIni(TStringBuf in, const TGlobals& g) {
+ TMemoryInput mi(in.data(), in.size());
+
+ return FromIni(mi, g);
+}
+
+void TConfig::Load(IInputStream* input) {
+ TString string;
+ ::Load(input, string);
+ TStringInput stream(string);
+ *this = FromJson(stream);
+}
+
+void TConfig::Save(IOutputStream* output) const {
+ TString result;
+ TStringOutput stream(result);
+ DumpJson(stream);
+ ::Save(output, result);
+}
+
+bool TConfig::Has(const TStringBuf& key) const {
+ return !operator[](key).IsNull();
+}
+
+const TConfig& TConfig::operator[](const TStringBuf& key) const {
+ return Get<TDict>().Find(key);
+}
+
+const TConfig& TConfig::At(const TStringBuf& key) const {
+ return Get<TDict>().At(key);
+}
+
+const TConfig& TConfig::operator[](size_t index) const {
+ return Get<TArray>().Index(index);
+}
+
+size_t TConfig::GetArraySize() const {
+ return Get<TArray>().size();
+}
+
+const TConfig& TDict::Find(const TStringBuf& key) const {
+ const_iterator it = find(key);
+
+ if (it == end()) {
+ return Default<TConfig>();
+ }
+
+ return it->second;
+}
+
+const TConfig& TDict::At(const TStringBuf& key) const {
+ const_iterator it = find(key);
+
+ Y_ENSURE_BT(it != end(), "missing key '" << key << "'");
+
+ return it->second;
+}
+
+const TConfig& TArray::Index(size_t index) const {
+ if (index < size()) {
+ return (*this)[index];
+ }
+
+ return Default<TConfig>();
+}
+
+const TConfig& TArray::At(size_t index) const {
+ Y_ENSURE_BT(index < size(), "index " << index << " is out of bounds");
+
+ return (*this)[index];
+}
+
+THolder<IInputStream> NConfig::CreatePreprocessor(const TGlobals& g, IInputStream& in) {
+ return MakeHolder<TPreprocessor>(g, &in);
+}