diff options
author | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
---|---|---|
committer | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
commit | 06e5c21a835c0e923506c4ff27929f34e00761c2 (patch) | |
tree | 75efcbc6854ef9bd476eb8bf00cc5c900da436a2 /library/cpp/config/config.cpp | |
parent | 03f024c4412e3aa613bb543cf1660176320ba8f4 (diff) | |
download | ydb-06e5c21a835c0e923506c4ff27929f34e00761c2.tar.gz |
fix ya.make
Diffstat (limited to 'library/cpp/config/config.cpp')
-rw-r--r-- | library/cpp/config/config.cpp | 425 |
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); +} |