mirror of
https://github.com/Icinga/icinga2.git
synced 2025-04-08 17:05:25 +02:00
Implement support for namespaces
This commit is contained in:
parent
9d513d8f05
commit
1a8692d972
@ -203,6 +203,38 @@ to dereference a reference:
|
||||
*p = "Hi!"
|
||||
log(value) // Prints "Hi!" because the variable was changed
|
||||
|
||||
### Namespaces <a id="namespaces"></a>
|
||||
|
||||
Namespaces can be used to organize variables and functions. They are used to avoid name conflicts. The `namespace`
|
||||
keyword is used to create a new namespace:
|
||||
|
||||
namespace Utils {
|
||||
function calculate() {
|
||||
return 2 + 2
|
||||
}
|
||||
}
|
||||
|
||||
The namespace is made available as a global variable which has the namespace's name (e.g. `Utils`):
|
||||
|
||||
Utils.calculate()
|
||||
|
||||
The `using` keyword can be used to make all attributes in a namespace available to a script without having to
|
||||
explicitly specify the namespace's name for each access:
|
||||
|
||||
using Utils
|
||||
calculate()
|
||||
|
||||
The `using` keyword only has an effect for the current file and only for code that follows the keyword:
|
||||
|
||||
calculate() // This will not work.
|
||||
using Utils
|
||||
|
||||
The following namespaces are automatically imported as if by using the `using` keyword:
|
||||
|
||||
* System
|
||||
* Types
|
||||
* Icinga
|
||||
|
||||
### Function Calls <a id="function-calls"></a>
|
||||
|
||||
Functions can be called using the `()` operator:
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "config/configcompilercontext.hpp"
|
||||
#include "config/configcompiler.hpp"
|
||||
#include "config/configitembuilder.hpp"
|
||||
#include "config/expression.hpp"
|
||||
#include "base/application.hpp"
|
||||
#include "base/logger.hpp"
|
||||
#include "base/timer.hpp"
|
||||
@ -440,7 +441,24 @@ static int Main()
|
||||
key = define;
|
||||
value = "1";
|
||||
}
|
||||
ScriptGlobal::Set(key, value);
|
||||
|
||||
std::vector<String> keyTokens = key.Split(".");
|
||||
|
||||
std::unique_ptr<Expression> expr;
|
||||
std::unique_ptr<VariableExpression> varExpr{new VariableExpression(keyTokens[0], {}, DebugInfo())};
|
||||
expr = std::move(varExpr);
|
||||
|
||||
for (size_t i = 1; i < keyTokens.size(); i++) {
|
||||
std::unique_ptr<IndexerExpression> indexerExpr{new IndexerExpression(std::move(expr), MakeLiteral(keyTokens[i]))};
|
||||
indexerExpr->SetOverrideFrozen();
|
||||
expr = std::move(indexerExpr);
|
||||
}
|
||||
|
||||
std::unique_ptr<SetExpression> setExpr{new SetExpression(std::move(expr), OpSetLiteral, MakeLiteral(value))};
|
||||
setExpr->SetOverrideFrozen();
|
||||
|
||||
ScriptFrame frame(true);
|
||||
setExpr->Evaluate(frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,8 @@
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
if (!globals.irc) {
|
||||
globals.irc = globals.log
|
||||
if (!globals.contains("irc")) {
|
||||
globals.irc = log
|
||||
}
|
||||
|
||||
hm = {
|
||||
|
@ -54,6 +54,7 @@ set(base_SOURCES
|
||||
math-script.cpp
|
||||
netstring.cpp netstring.hpp
|
||||
networkstream.cpp networkstream.hpp
|
||||
namespace.cpp namespace.hpp namespace-script.cpp
|
||||
number.cpp number.hpp number-script.cpp
|
||||
object.cpp object.hpp object-script.cpp
|
||||
objectlock.cpp objectlock.hpp
|
||||
|
@ -75,13 +75,29 @@ private:
|
||||
#define REGISTER_FUNCTION(ns, name, callback, args) \
|
||||
INITIALIZE_ONCE_WITH_PRIORITY([]() { \
|
||||
Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), false); \
|
||||
ScriptGlobal::Set(#ns "." #name, sf); \
|
||||
Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \
|
||||
nsp->SetAttribute(#name, std::make_shared<ConstEmbeddedNamespaceValue>(sf)); \
|
||||
}, 10)
|
||||
|
||||
#define REGISTER_SAFE_FUNCTION(ns, name, callback, args) \
|
||||
INITIALIZE_ONCE_WITH_PRIORITY([]() { \
|
||||
Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), true); \
|
||||
ScriptGlobal::Set(#ns "." #name, sf); \
|
||||
Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \
|
||||
nsp->SetAttribute(#name, std::make_shared<ConstEmbeddedNamespaceValue>(sf)); \
|
||||
}, 10)
|
||||
|
||||
#define REGISTER_FUNCTION_NONCONST(ns, name, callback, args) \
|
||||
INITIALIZE_ONCE_WITH_PRIORITY([]() { \
|
||||
Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), false); \
|
||||
Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \
|
||||
nsp->SetAttribute(#name, std::make_shared<EmbeddedNamespaceValue>(sf)); \
|
||||
}, 10)
|
||||
|
||||
#define REGISTER_SAFE_FUNCTION_NONCONST(ns, name, callback, args) \
|
||||
INITIALIZE_ONCE_WITH_PRIORITY([]() { \
|
||||
Function::Ptr sf = new icinga::Function(#ns "#" #name, callback, String(args).Split(":"), true); \
|
||||
Namespace::Ptr nsp = ScriptGlobal::Get(#ns); \
|
||||
nsp->SetAttribute(#name, std::make_shared<EmbeddedNamespaceValue>(sf)); \
|
||||
}, 10)
|
||||
|
||||
}
|
||||
|
@ -32,11 +32,15 @@ static String JsonEncodeShim(const Value& value)
|
||||
}
|
||||
|
||||
INITIALIZE_ONCE([]() {
|
||||
Dictionary::Ptr jsonObj = new Dictionary({
|
||||
/* Methods */
|
||||
{ "encode", new Function("Json#encode", JsonEncodeShim, { "value" }, true) },
|
||||
{ "decode", new Function("Json#decode", JsonDecode, { "value" }, true) }
|
||||
});
|
||||
auto jsonNSBehavior = new ConstNamespaceBehavior();
|
||||
Namespace::Ptr jsonNS = new Namespace(jsonNSBehavior);
|
||||
|
||||
ScriptGlobal::Set("Json", jsonObj);
|
||||
/* Methods */
|
||||
jsonNS->Set("encode", new Function("Json#encode", JsonEncodeShim, { "value" }, true));
|
||||
jsonNS->Set("decode", new Function("Json#decode", JsonDecode, { "value" }, true));
|
||||
|
||||
jsonNSBehavior->Freeze();
|
||||
|
||||
Namespace::Ptr systemNS = ScriptGlobal::Get("System");
|
||||
systemNS->SetAttribute("Json", std::make_shared<ConstEmbeddedNamespaceValue>(jsonNS));
|
||||
});
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "base/json.hpp"
|
||||
#include "base/debug.hpp"
|
||||
#include "base/namespace.hpp"
|
||||
#include "base/dictionary.hpp"
|
||||
#include "base/array.hpp"
|
||||
#include "base/objectlock.hpp"
|
||||
@ -39,6 +40,19 @@ typedef unsigned int yajl_size;
|
||||
typedef size_t yajl_size;
|
||||
#endif /* YAJL_MAJOR */
|
||||
|
||||
static void EncodeNamespace(yajl_gen handle, const Namespace::Ptr& ns)
|
||||
{
|
||||
yajl_gen_map_open(handle);
|
||||
|
||||
ObjectLock olock(ns);
|
||||
for (const Namespace::Pair& kv : ns) {
|
||||
yajl_gen_string(handle, reinterpret_cast<const unsigned char *>(kv.first.CStr()), kv.first.GetLength());
|
||||
Encode(handle, kv.second->Get());
|
||||
}
|
||||
|
||||
yajl_gen_map_close(handle);
|
||||
}
|
||||
|
||||
static void EncodeDictionary(yajl_gen handle, const Dictionary::Ptr& dict)
|
||||
{
|
||||
yajl_gen_map_open(handle);
|
||||
@ -83,6 +97,13 @@ static void Encode(yajl_gen handle, const Value& value)
|
||||
case ValueObject:
|
||||
{
|
||||
const Object::Ptr& obj = value.Get<Object::Ptr>();
|
||||
Namespace::Ptr ns = dynamic_pointer_cast<Namespace>(obj);
|
||||
|
||||
if (ns) {
|
||||
EncodeNamespace(handle, ns);
|
||||
break;
|
||||
}
|
||||
|
||||
Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(obj);
|
||||
|
||||
if (dict) {
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "base/functionwrapper.hpp"
|
||||
#include "base/scriptframe.hpp"
|
||||
#include "base/initialize.hpp"
|
||||
#include "base/namespace.hpp"
|
||||
#include <boost/math/special_functions/round.hpp>
|
||||
#include <cmath>
|
||||
|
||||
@ -158,40 +159,44 @@ static double MathSign(double x)
|
||||
}
|
||||
|
||||
INITIALIZE_ONCE([]() {
|
||||
Dictionary::Ptr mathObj = new Dictionary({
|
||||
/* Constants */
|
||||
{ "E", 2.71828182845904523536 },
|
||||
{ "LN2", 0.693147180559945309417 },
|
||||
{ "LN10", 2.30258509299404568402 },
|
||||
{ "LOG2E", 1.44269504088896340736 },
|
||||
{ "LOG10E", 0.434294481903251827651 },
|
||||
{ "PI", 3.14159265358979323846 },
|
||||
{ "SQRT1_2", 0.707106781186547524401 },
|
||||
{ "SQRT2", 1.41421356237309504880 },
|
||||
auto mathNSBehavior = new ConstNamespaceBehavior();
|
||||
Namespace::Ptr mathNS = new Namespace(mathNSBehavior);
|
||||
|
||||
/* Methods */
|
||||
{ "abs", new Function("Math#abs", MathAbs, { "x" }, true) },
|
||||
{ "acos", new Function("Math#acos", MathAcos, { "x" }, true) },
|
||||
{ "asin", new Function("Math#asin", MathAsin, { "x" }, true) },
|
||||
{ "atan", new Function("Math#atan", MathAtan, { "x" }, true) },
|
||||
{ "atan2", new Function("Math#atan2", MathAtan2, { "x", "y" }, true) },
|
||||
{ "ceil", new Function("Math#ceil", MathCeil, { "x" }, true) },
|
||||
{ "cos", new Function("Math#cos", MathCos, { "x" }, true) },
|
||||
{ "exp", new Function("Math#exp", MathExp, { "x" }, true) },
|
||||
{ "floor", new Function("Math#floor", MathFloor, { "x" }, true) },
|
||||
{ "log", new Function("Math#log", MathLog, { "x" }, true) },
|
||||
{ "max", new Function("Math#max", MathMax, {}, true) },
|
||||
{ "min", new Function("Math#min", MathMin, {}, true) },
|
||||
{ "pow", new Function("Math#pow", MathPow, { "x", "y" }, true) },
|
||||
{ "random", new Function("Math#random", MathRandom, {}, true) },
|
||||
{ "round", new Function("Math#round", MathRound, { "x" }, true) },
|
||||
{ "sin", new Function("Math#sin", MathSin, { "x" }, true) },
|
||||
{ "sqrt", new Function("Math#sqrt", MathSqrt, { "x" }, true) },
|
||||
{ "tan", new Function("Math#tan", MathTan, { "x" }, true) },
|
||||
{ "isnan", new Function("Math#isnan", MathIsnan, { "x" }, true) },
|
||||
{ "isinf", new Function("Math#isinf", MathIsinf, { "x" }, true) },
|
||||
{ "sign", new Function("Math#sign", MathSign, { "x" }, true) }
|
||||
});
|
||||
/* Constants */
|
||||
mathNS->Set("E", 2.71828182845904523536);
|
||||
mathNS->Set("LN2", 0.693147180559945309417);
|
||||
mathNS->Set("LN10", 2.30258509299404568402);
|
||||
mathNS->Set("LOG2E", 1.44269504088896340736);
|
||||
mathNS->Set("LOG10E", 0.434294481903251827651);
|
||||
mathNS->Set("PI", 3.14159265358979323846);
|
||||
mathNS->Set("SQRT1_2", 0.707106781186547524401);
|
||||
mathNS->Set("SQRT2", 1.41421356237309504880);
|
||||
|
||||
ScriptGlobal::Set("Math", mathObj);
|
||||
/* Methods */
|
||||
mathNS->Set("abs", new Function("Math#abs", MathAbs, { "x" }, true));
|
||||
mathNS->Set("acos", new Function("Math#acos", MathAcos, { "x" }, true));
|
||||
mathNS->Set("asin", new Function("Math#asin", MathAsin, { "x" }, true));
|
||||
mathNS->Set("atan", new Function("Math#atan", MathAtan, { "x" }, true));
|
||||
mathNS->Set("atan2", new Function("Math#atan2", MathAtan2, { "x", "y" }, true));
|
||||
mathNS->Set("ceil", new Function("Math#ceil", MathCeil, { "x" }, true));
|
||||
mathNS->Set("cos", new Function("Math#cos", MathCos, { "x" }, true));
|
||||
mathNS->Set("exp", new Function("Math#exp", MathExp, { "x" }, true));
|
||||
mathNS->Set("floor", new Function("Math#floor", MathFloor, { "x" }, true));
|
||||
mathNS->Set("log", new Function("Math#log", MathLog, { "x" }, true));
|
||||
mathNS->Set("max", new Function("Math#max", MathMax, {}, true));
|
||||
mathNS->Set("min", new Function("Math#min", MathMin, {}, true));
|
||||
mathNS->Set("pow", new Function("Math#pow", MathPow, { "x", "y" }, true));
|
||||
mathNS->Set("random", new Function("Math#random", MathRandom, {}, true));
|
||||
mathNS->Set("round", new Function("Math#round", MathRound, { "x" }, true));
|
||||
mathNS->Set("sin", new Function("Math#sin", MathSin, { "x" }, true));
|
||||
mathNS->Set("sqrt", new Function("Math#sqrt", MathSqrt, { "x" }, true));
|
||||
mathNS->Set("tan", new Function("Math#tan", MathTan, { "x" }, true));
|
||||
mathNS->Set("isnan", new Function("Math#isnan", MathIsnan, { "x" }, true));
|
||||
mathNS->Set("isinf", new Function("Math#isinf", MathIsinf, { "x" }, true));
|
||||
mathNS->Set("sign", new Function("Math#sign", MathSign, { "x" }, true));
|
||||
|
||||
mathNSBehavior->Freeze();
|
||||
|
||||
Namespace::Ptr systemNS = ScriptGlobal::Get("System");
|
||||
systemNS->SetAttribute("Math", std::make_shared<ConstEmbeddedNamespaceValue>(mathNS));
|
||||
});
|
||||
|
101
lib/base/namespace-script.cpp
Normal file
101
lib/base/namespace-script.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "base/namespace.hpp"
|
||||
#include "base/function.hpp"
|
||||
#include "base/functionwrapper.hpp"
|
||||
#include "base/scriptframe.hpp"
|
||||
#include "base/array.hpp"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
static void NamespaceSet(const String& key, const Value& value)
|
||||
{
|
||||
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
|
||||
Namespace::Ptr self = static_cast<Namespace::Ptr>(vframe->Self);
|
||||
REQUIRE_NOT_NULL(self);
|
||||
self->Set(key, value);
|
||||
}
|
||||
|
||||
static Value NamespaceGet(const String& key)
|
||||
{
|
||||
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
|
||||
Namespace::Ptr self = static_cast<Namespace::Ptr>(vframe->Self);
|
||||
REQUIRE_NOT_NULL(self);
|
||||
return self->Get(key);
|
||||
}
|
||||
|
||||
static void NamespaceRemove(const String& key)
|
||||
{
|
||||
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
|
||||
Namespace::Ptr self = static_cast<Namespace::Ptr>(vframe->Self);
|
||||
REQUIRE_NOT_NULL(self);
|
||||
self->Remove(key);
|
||||
}
|
||||
|
||||
static bool NamespaceContains(const String& key)
|
||||
{
|
||||
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
|
||||
Namespace::Ptr self = static_cast<Namespace::Ptr>(vframe->Self);
|
||||
REQUIRE_NOT_NULL(self);
|
||||
return self->Contains(key);
|
||||
}
|
||||
|
||||
static Array::Ptr NamespaceKeys()
|
||||
{
|
||||
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
|
||||
Namespace::Ptr self = static_cast<Namespace::Ptr>(vframe->Self);
|
||||
REQUIRE_NOT_NULL(self);
|
||||
|
||||
ArrayData keys;
|
||||
ObjectLock olock(self);
|
||||
for (const Namespace::Pair& kv : self) {
|
||||
keys.push_back(kv.first);
|
||||
}
|
||||
return new Array(std::move(keys));
|
||||
}
|
||||
|
||||
static Array::Ptr NamespaceValues()
|
||||
{
|
||||
ScriptFrame *vframe = ScriptFrame::GetCurrentFrame();
|
||||
Namespace::Ptr self = static_cast<Namespace::Ptr>(vframe->Self);
|
||||
REQUIRE_NOT_NULL(self);
|
||||
|
||||
ArrayData values;
|
||||
ObjectLock olock(self);
|
||||
for (const Namespace::Pair& kv : self) {
|
||||
values.push_back(kv.second->Get());
|
||||
}
|
||||
return new Array(std::move(values));
|
||||
}
|
||||
|
||||
Object::Ptr Namespace::GetPrototype()
|
||||
{
|
||||
static Dictionary::Ptr prototype = new Dictionary({
|
||||
{ "set", new Function("Namespace#set", NamespaceSet, { "key", "value" }) },
|
||||
{ "get", new Function("Namespace#get", NamespaceGet, { "key" }) },
|
||||
{ "remove", new Function("Namespace#remove", NamespaceRemove, { "key" }) },
|
||||
{ "contains", new Function("Namespace#contains", NamespaceContains, { "key" }, true) },
|
||||
{ "keys", new Function("Namespace#keys", NamespaceKeys, {}, true) },
|
||||
{ "values", new Function("Namespace#values", NamespaceValues, {}, true) },
|
||||
});
|
||||
|
||||
return prototype;
|
||||
}
|
||||
|
223
lib/base/namespace.cpp
Normal file
223
lib/base/namespace.cpp
Normal file
@ -0,0 +1,223 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#include "base/namespace.hpp"
|
||||
#include "base/objectlock.hpp"
|
||||
#include "base/debug.hpp"
|
||||
#include "base/primitivetype.hpp"
|
||||
#include "base/debuginfo.hpp"
|
||||
#include "base/exception.hpp"
|
||||
#include <sstream>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
template class std::map<icinga::String, std::shared_ptr<icinga::NamespaceValue> >;
|
||||
|
||||
REGISTER_PRIMITIVE_TYPE(Namespace, Object, Namespace::GetPrototype());
|
||||
|
||||
Namespace::Namespace(NamespaceBehavior *behavior)
|
||||
: m_Behavior(std::unique_ptr<NamespaceBehavior>(behavior))
|
||||
{ }
|
||||
|
||||
Value Namespace::Get(const String& field) const
|
||||
{
|
||||
Value value;
|
||||
if (!GetOwnField(field, &value))
|
||||
BOOST_THROW_EXCEPTION(ScriptError("Namespace does not contain field '" + field + "'"));
|
||||
return value;
|
||||
}
|
||||
|
||||
bool Namespace::Get(const String& field, Value *value) const
|
||||
{
|
||||
auto nsVal = GetAttribute(field);
|
||||
|
||||
if (!nsVal)
|
||||
return false;
|
||||
|
||||
*value = nsVal->Get(DebugInfo());
|
||||
return true;
|
||||
}
|
||||
|
||||
void Namespace::Set(const String& field, const Value& value, bool overrideFrozen)
|
||||
{
|
||||
return SetFieldByName(field, value, overrideFrozen, DebugInfo());
|
||||
}
|
||||
|
||||
bool Namespace::Contains(const String& field) const
|
||||
{
|
||||
return HasOwnField(field);
|
||||
}
|
||||
|
||||
void Namespace::Remove(const String& field, bool overrideFrozen)
|
||||
{
|
||||
m_Behavior->Remove(this, field, overrideFrozen);
|
||||
}
|
||||
|
||||
void Namespace::RemoveAttribute(const String& field)
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
|
||||
Namespace::Iterator it;
|
||||
it = m_Data.find(field);
|
||||
|
||||
if (it == m_Data.end())
|
||||
return;
|
||||
|
||||
m_Data.erase(it);
|
||||
}
|
||||
|
||||
std::shared_ptr<NamespaceValue> Namespace::GetAttribute(const String& key) const
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
|
||||
auto it = m_Data.find(key);
|
||||
|
||||
if (it == m_Data.end())
|
||||
return nullptr;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void Namespace::SetAttribute(const String& key, const std::shared_ptr<NamespaceValue>& nsVal)
|
||||
{
|
||||
ObjectLock olock(this);
|
||||
|
||||
m_Data[key] = nsVal;
|
||||
}
|
||||
|
||||
Value Namespace::GetFieldByName(const String& field, bool, const DebugInfo& debugInfo) const
|
||||
{
|
||||
auto nsVal = GetAttribute(field);
|
||||
|
||||
if (nsVal)
|
||||
return nsVal->Get(debugInfo);
|
||||
else
|
||||
return GetPrototypeField(const_cast<Namespace *>(this), field, true, debugInfo);
|
||||
}
|
||||
|
||||
void Namespace::SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo)
|
||||
{
|
||||
auto nsVal = GetAttribute(field);
|
||||
|
||||
if (!nsVal)
|
||||
m_Behavior->Register(this, field, value, overrideFrozen, debugInfo);
|
||||
else
|
||||
nsVal->Set(value, overrideFrozen, debugInfo);
|
||||
}
|
||||
|
||||
bool Namespace::HasOwnField(const String& field) const
|
||||
{
|
||||
return GetAttribute(field) != nullptr;
|
||||
}
|
||||
|
||||
bool Namespace::GetOwnField(const String& field, Value *result) const
|
||||
{
|
||||
auto nsVal = GetAttribute(field);
|
||||
|
||||
if (!nsVal)
|
||||
return false;
|
||||
|
||||
*result = nsVal->Get(DebugInfo());
|
||||
return true;
|
||||
}
|
||||
|
||||
EmbeddedNamespaceValue::EmbeddedNamespaceValue(const Value& value)
|
||||
: m_Value(value)
|
||||
{ }
|
||||
|
||||
Value EmbeddedNamespaceValue::Get(const DebugInfo& debugInfo) const
|
||||
{
|
||||
return m_Value;
|
||||
}
|
||||
|
||||
void EmbeddedNamespaceValue::Set(const Value& value, bool, const DebugInfo&)
|
||||
{
|
||||
m_Value = value;
|
||||
}
|
||||
|
||||
void ConstEmbeddedNamespaceValue::Set(const Value& value, bool overrideFrozen, const DebugInfo& debugInfo)
|
||||
{
|
||||
if (!overrideFrozen)
|
||||
BOOST_THROW_EXCEPTION(ScriptError("Constant must not be modified.", debugInfo));
|
||||
|
||||
EmbeddedNamespaceValue::Set(value, overrideFrozen, debugInfo);
|
||||
}
|
||||
|
||||
void NamespaceBehavior::Register(const Namespace::Ptr& ns, const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) const
|
||||
{
|
||||
ns->SetAttribute(field, std::make_shared<EmbeddedNamespaceValue>(value));
|
||||
}
|
||||
|
||||
void NamespaceBehavior::Remove(const Namespace::Ptr& ns, const String& field, bool overrideFrozen)
|
||||
{
|
||||
if (!overrideFrozen) {
|
||||
auto attr = ns->GetAttribute(field);
|
||||
|
||||
if (dynamic_pointer_cast<ConstEmbeddedNamespaceValue>(attr))
|
||||
BOOST_THROW_EXCEPTION(ScriptError("Constants must not be removed."));
|
||||
}
|
||||
|
||||
ns->RemoveAttribute(field);
|
||||
}
|
||||
|
||||
void ConstNamespaceBehavior::Register(const Namespace::Ptr& ns, const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) const
|
||||
{
|
||||
if (m_Frozen && !overrideFrozen)
|
||||
BOOST_THROW_EXCEPTION(ScriptError("Namespace is read-only and must not be modified.", debugInfo));
|
||||
|
||||
ns->SetAttribute(field, std::make_shared<ConstEmbeddedNamespaceValue>(value));
|
||||
}
|
||||
|
||||
void ConstNamespaceBehavior::Remove(const Namespace::Ptr& ns, const String& field, bool overrideFrozen)
|
||||
{
|
||||
if (m_Frozen && !overrideFrozen)
|
||||
BOOST_THROW_EXCEPTION(ScriptError("Namespace is read-only and must not be modified."));
|
||||
|
||||
NamespaceBehavior::Remove(ns, field, overrideFrozen);
|
||||
}
|
||||
|
||||
void ConstNamespaceBehavior::Freeze()
|
||||
{
|
||||
m_Frozen = true;
|
||||
}
|
||||
|
||||
Namespace::Iterator Namespace::Begin()
|
||||
{
|
||||
ASSERT(OwnsLock());
|
||||
|
||||
return m_Data.begin();
|
||||
}
|
||||
|
||||
Namespace::Iterator Namespace::End()
|
||||
{
|
||||
ASSERT(OwnsLock());
|
||||
|
||||
return m_Data.end();
|
||||
}
|
||||
|
||||
Namespace::Iterator icinga::begin(const Namespace::Ptr& x)
|
||||
{
|
||||
return x->Begin();
|
||||
}
|
||||
|
||||
Namespace::Iterator icinga::end(const Namespace::Ptr& x)
|
||||
{
|
||||
return x->End();
|
||||
}
|
||||
|
123
lib/base/namespace.hpp
Normal file
123
lib/base/namespace.hpp
Normal file
@ -0,0 +1,123 @@
|
||||
/******************************************************************************
|
||||
* Icinga 2 *
|
||||
* Copyright (C) 2012-2018 Icinga Development Team (https://www.icinga.com/) *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU General Public License *
|
||||
* as published by the Free Software Foundation; either version 2 *
|
||||
* of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the Free Software Foundation *
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef NAMESPACE_H
|
||||
#define NAMESPACE_H
|
||||
|
||||
#include "base/i2-base.hpp"
|
||||
#include "base/object.hpp"
|
||||
#include "base/value.hpp"
|
||||
#include "base/debuginfo.hpp"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
|
||||
struct NamespaceValue
|
||||
{
|
||||
virtual Value Get(const DebugInfo& debugInfo = DebugInfo()) const = 0;
|
||||
virtual void Set(const Value& value, bool overrideFrozen, const DebugInfo& debugInfo = DebugInfo()) = 0;
|
||||
};
|
||||
|
||||
struct EmbeddedNamespaceValue : public NamespaceValue
|
||||
{
|
||||
EmbeddedNamespaceValue(const Value& value);
|
||||
|
||||
Value Get(const DebugInfo& debugInfo) const override;
|
||||
void Set(const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) override;
|
||||
|
||||
private:
|
||||
Value m_Value;
|
||||
};
|
||||
|
||||
struct ConstEmbeddedNamespaceValue : public EmbeddedNamespaceValue
|
||||
{
|
||||
using EmbeddedNamespaceValue::EmbeddedNamespaceValue;
|
||||
|
||||
void Set(const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) override;
|
||||
};
|
||||
|
||||
class Namespace;
|
||||
|
||||
struct NamespaceBehavior
|
||||
{
|
||||
virtual void Register(const boost::intrusive_ptr<Namespace>& ns, const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) const;
|
||||
virtual void Remove(const boost::intrusive_ptr<Namespace>& ns, const String& field, bool overrideFrozen);
|
||||
};
|
||||
|
||||
struct ConstNamespaceBehavior : public NamespaceBehavior
|
||||
{
|
||||
void Register(const boost::intrusive_ptr<Namespace>& ns, const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) const override;
|
||||
void Remove(const boost::intrusive_ptr<Namespace>& ns, const String& field, bool overrideFrozen) override;
|
||||
void Freeze();
|
||||
|
||||
private:
|
||||
bool m_Frozen;
|
||||
};
|
||||
|
||||
/**
|
||||
* A namespace.
|
||||
*
|
||||
* @ingroup base
|
||||
*/
|
||||
class Namespace final : public Object
|
||||
{
|
||||
public:
|
||||
DECLARE_OBJECT(Namespace);
|
||||
|
||||
typedef std::map<String, std::shared_ptr<NamespaceValue> >::iterator Iterator;
|
||||
|
||||
typedef std::map<String, std::shared_ptr<NamespaceValue> >::value_type Pair;
|
||||
|
||||
Namespace(NamespaceBehavior *behavior = new NamespaceBehavior);
|
||||
|
||||
Value Get(const String& field) const;
|
||||
bool Get(const String& field, Value *value) const;
|
||||
void Set(const String& field, const Value& value, bool overrideFrozen = false);
|
||||
bool Contains(const String& field) const;
|
||||
void Remove(const String& field, bool overrideFrozen = false);
|
||||
|
||||
std::shared_ptr<NamespaceValue> GetAttribute(const String& field) const;
|
||||
void SetAttribute(const String& field, const std::shared_ptr<NamespaceValue>& nsVal);
|
||||
void RemoveAttribute(const String& field);
|
||||
|
||||
Iterator Begin();
|
||||
Iterator End();
|
||||
|
||||
Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override;
|
||||
void SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) override;
|
||||
bool HasOwnField(const String& field) const override;
|
||||
bool GetOwnField(const String& field, Value *result) const override;
|
||||
|
||||
static Object::Ptr GetPrototype();
|
||||
|
||||
private:
|
||||
std::map<String, std::shared_ptr<NamespaceValue> > m_Data;
|
||||
std::unique_ptr<NamespaceBehavior> m_Behavior;
|
||||
};
|
||||
|
||||
Namespace::Iterator begin(const Namespace::Ptr& x);
|
||||
Namespace::Iterator end(const Namespace::Ptr& x);
|
||||
|
||||
}
|
||||
|
||||
extern template class std::map<icinga::String, std::shared_ptr<icinga::NamespaceValue> >;
|
||||
|
||||
#endif /* NAMESPACE_H */
|
@ -26,11 +26,12 @@
|
||||
#include "base/convert.hpp"
|
||||
#include "base/objectlock.hpp"
|
||||
#include "base/exception.hpp"
|
||||
#include "base/namespace.hpp"
|
||||
#include <fstream>
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
Dictionary::Ptr ScriptGlobal::m_Globals = new Dictionary();
|
||||
Namespace::Ptr ScriptGlobal::m_Globals = new Namespace();
|
||||
|
||||
Value ScriptGlobal::Get(const String& name, const Value *defaultValue)
|
||||
{
|
||||
@ -46,7 +47,7 @@ Value ScriptGlobal::Get(const String& name, const Value *defaultValue)
|
||||
return result;
|
||||
}
|
||||
|
||||
void ScriptGlobal::Set(const String& name, const Value& value)
|
||||
void ScriptGlobal::Set(const String& name, const Value& value, bool overrideFrozen)
|
||||
{
|
||||
std::vector<String> tokens = name.Split(".");
|
||||
|
||||
@ -56,7 +57,7 @@ void ScriptGlobal::Set(const String& name, const Value& value)
|
||||
{
|
||||
ObjectLock olock(m_Globals);
|
||||
|
||||
Dictionary::Ptr parent = m_Globals;
|
||||
Namespace::Ptr parent = m_Globals;
|
||||
|
||||
for (std::vector<String>::size_type i = 0; i < tokens.size(); i++) {
|
||||
const String& token = tokens[i];
|
||||
@ -65,7 +66,7 @@ void ScriptGlobal::Set(const String& name, const Value& value)
|
||||
Value vparent;
|
||||
|
||||
if (!parent->Get(token, &vparent)) {
|
||||
Dictionary::Ptr dict = new Dictionary();
|
||||
Namespace::Ptr dict = new Namespace();
|
||||
parent->Set(token, dict);
|
||||
parent = dict;
|
||||
} else {
|
||||
@ -74,16 +75,21 @@ void ScriptGlobal::Set(const String& name, const Value& value)
|
||||
}
|
||||
}
|
||||
|
||||
parent->Set(tokens[tokens.size() - 1], value);
|
||||
parent->SetFieldByName(tokens[tokens.size() - 1], value, overrideFrozen, DebugInfo());
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptGlobal::SetConst(const String& name, const Value& value)
|
||||
{
|
||||
GetGlobals()->SetAttribute(name, std::make_shared<ConstEmbeddedNamespaceValue>(value));
|
||||
}
|
||||
|
||||
bool ScriptGlobal::Exists(const String& name)
|
||||
{
|
||||
return m_Globals->Contains(name);
|
||||
}
|
||||
|
||||
Dictionary::Ptr ScriptGlobal::GetGlobals()
|
||||
Namespace::Ptr ScriptGlobal::GetGlobals()
|
||||
{
|
||||
return m_Globals;
|
||||
}
|
||||
@ -102,8 +108,8 @@ void ScriptGlobal::WriteToFile(const String& filename)
|
||||
StdioStream::Ptr sfp = new StdioStream(&fp, false);
|
||||
|
||||
ObjectLock olock(m_Globals);
|
||||
for (const Dictionary::Pair& kv : m_Globals) {
|
||||
Value value = kv.second;
|
||||
for (const Namespace::Pair& kv : m_Globals) {
|
||||
Value value = kv.second->Get();
|
||||
|
||||
if (value.IsObject())
|
||||
value = Convert::ToString(value);
|
||||
|
@ -21,7 +21,7 @@
|
||||
#define SCRIPTGLOBAL_H
|
||||
|
||||
#include "base/i2-base.hpp"
|
||||
#include "base/dictionary.hpp"
|
||||
#include "base/namespace.hpp"
|
||||
|
||||
namespace icinga
|
||||
{
|
||||
@ -35,15 +35,16 @@ class ScriptGlobal
|
||||
{
|
||||
public:
|
||||
static Value Get(const String& name, const Value *defaultValue = nullptr);
|
||||
static void Set(const String& name, const Value& value);
|
||||
static void Set(const String& name, const Value& value, bool overrideFrozen = false);
|
||||
static void SetConst(const String& name, const Value& value);
|
||||
static bool Exists(const String& name);
|
||||
|
||||
static void WriteToFile(const String& filename);
|
||||
|
||||
static Dictionary::Ptr GetGlobals();
|
||||
static Namespace::Ptr GetGlobals();
|
||||
|
||||
private:
|
||||
static Dictionary::Ptr m_Globals;
|
||||
static Namespace::Ptr m_Globals;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -83,11 +83,11 @@ enum MatchType
|
||||
|
||||
void ScriptUtils::StaticInitialize()
|
||||
{
|
||||
ScriptGlobal::Set("MatchAll", MatchAll);
|
||||
ScriptGlobal::Set("MatchAny", MatchAny);
|
||||
ScriptGlobal::Set("MatchAll", MatchAll, true);
|
||||
ScriptGlobal::Set("MatchAny", MatchAny, true);
|
||||
|
||||
ScriptGlobal::Set("GlobFile", GlobFile);
|
||||
ScriptGlobal::Set("GlobDirectory", GlobDirectory);
|
||||
ScriptGlobal::Set("GlobFile", GlobFile, true);
|
||||
ScriptGlobal::Set("GlobDirectory", GlobDirectory, true);
|
||||
}
|
||||
|
||||
String ScriptUtils::CastString(const Value& value)
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "base/objectlock.hpp"
|
||||
#include "base/convert.hpp"
|
||||
#include "base/exception.hpp"
|
||||
#include "base/namespace.hpp"
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <deque>
|
||||
|
||||
@ -119,6 +120,22 @@ static Dictionary::Ptr SerializeDictionary(const Dictionary::Ptr& input, int att
|
||||
return new Dictionary(std::move(result));
|
||||
}
|
||||
|
||||
static Dictionary::Ptr SerializeNamespace(const Namespace::Ptr& input, int attributeTypes, SerializeStack& stack)
|
||||
{
|
||||
DictionaryData result;
|
||||
|
||||
ObjectLock olock(input);
|
||||
|
||||
for (const Namespace::Pair& kv : input) {
|
||||
Value val = kv.second->Get();
|
||||
stack.Push(kv.first, val);
|
||||
result.emplace_back(kv.first, Serialize(val, attributeTypes));
|
||||
stack.Pop();
|
||||
}
|
||||
|
||||
return new Dictionary(std::move(result));
|
||||
}
|
||||
|
||||
static Object::Ptr SerializeObject(const Object::Ptr& input, int attributeTypes, SerializeStack& stack)
|
||||
{
|
||||
Type::Ptr type = input->GetReflectionType();
|
||||
@ -243,6 +260,11 @@ static Value SerializeInternal(const Value& value, int attributeTypes, Serialize
|
||||
if (dict)
|
||||
return SerializeDictionary(dict, attributeTypes, stack);
|
||||
|
||||
Namespace::Ptr ns = dynamic_pointer_cast<Namespace>(input);
|
||||
|
||||
if (ns)
|
||||
return SerializeNamespace(ns, attributeTypes, stack);
|
||||
|
||||
return SerializeObject(input, attributeTypes, stack);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "base/type.hpp"
|
||||
#include "base/scriptglobal.hpp"
|
||||
#include "base/namespace.hpp"
|
||||
#include "base/objectlock.hpp"
|
||||
|
||||
using namespace icinga;
|
||||
@ -39,19 +40,19 @@ String Type::ToString() const
|
||||
|
||||
void Type::Register(const Type::Ptr& type)
|
||||
{
|
||||
VERIFY(!GetByName(type->GetName()));
|
||||
|
||||
ScriptGlobal::Set("Types." + type->GetName(), type);
|
||||
ScriptGlobal::Set("Types." + type->GetName(), type, true);
|
||||
}
|
||||
|
||||
Type::Ptr Type::GetByName(const String& name)
|
||||
{
|
||||
Dictionary::Ptr typesNS = ScriptGlobal::Get("Types", &Empty);
|
||||
Namespace::Ptr typesNS = ScriptGlobal::Get("Types", &Empty);
|
||||
|
||||
if (!typesNS)
|
||||
return nullptr;
|
||||
|
||||
Value ptype = typesNS->Get(name);
|
||||
Value ptype;
|
||||
if (!typesNS->Get(name, &ptype))
|
||||
return nullptr;
|
||||
|
||||
if (!ptype.IsObjectType<Type>())
|
||||
return nullptr;
|
||||
@ -63,14 +64,16 @@ std::vector<Type::Ptr> Type::GetAllTypes()
|
||||
{
|
||||
std::vector<Type::Ptr> types;
|
||||
|
||||
Dictionary::Ptr typesNS = ScriptGlobal::Get("Types", &Empty);
|
||||
Namespace::Ptr typesNS = ScriptGlobal::Get("Types", &Empty);
|
||||
|
||||
if (typesNS) {
|
||||
ObjectLock olock(typesNS);
|
||||
|
||||
for (const Dictionary::Pair& kv : typesNS) {
|
||||
if (kv.second.IsObjectType<Type>())
|
||||
types.push_back(kv.second);
|
||||
for (const Namespace::Pair& kv : typesNS) {
|
||||
Value value = kv.second->Get();
|
||||
|
||||
if (value.IsObjectType<Type>())
|
||||
types.push_back(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -648,7 +648,7 @@ lterm: T_LIBRARY rterm
|
||||
}
|
||||
| T_CONST T_IDENTIFIER T_SET rterm
|
||||
{
|
||||
$$ = new SetExpression(MakeIndexer(ScopeGlobal, *$2), OpSetLiteral, std::unique_ptr<Expression>($4));
|
||||
$$ = new SetConstExpression(*$2, std::unique_ptr<Expression>($4), @$);
|
||||
delete $2;
|
||||
}
|
||||
| T_VAR rterm
|
||||
|
@ -31,6 +31,7 @@ ConfigItemBuilder::ConfigItemBuilder(const DebugInfo& debugInfo)
|
||||
|
||||
void ConfigItemBuilder::SetType(const Type::Ptr& type)
|
||||
{
|
||||
ASSERT(type);
|
||||
m_Type = type;
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "base/scriptglobal.hpp"
|
||||
#include "base/loader.hpp"
|
||||
#include "base/reference.hpp"
|
||||
#include "base/namespace.hpp"
|
||||
#include <boost/exception_ptr.hpp>
|
||||
#include <boost/exception/errinfo_nested_exception.hpp>
|
||||
|
||||
@ -625,6 +626,28 @@ void SetExpression::SetOverrideFrozen()
|
||||
m_OverrideFrozen = true;
|
||||
}
|
||||
|
||||
ExpressionResult SetConstExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
|
||||
{
|
||||
auto globals = ScriptGlobal::GetGlobals();
|
||||
|
||||
auto attr = globals->GetAttribute(m_Name);
|
||||
|
||||
if (dynamic_pointer_cast<ConstEmbeddedNamespaceValue>(attr)) {
|
||||
std::ostringstream msgbuf;
|
||||
msgbuf << "Value for constant '" << m_Name << "' was modified. This behaviour is deprecated.\n";
|
||||
ShowCodeLocation(msgbuf, GetDebugInfo(), false);
|
||||
Log(LogWarning, msgbuf.str());
|
||||
}
|
||||
|
||||
ExpressionResult operandres = m_Operand->Evaluate(frame);
|
||||
CHECK_RESULT(operandres);
|
||||
Value operand = operandres.GetValue();
|
||||
|
||||
globals->SetAttribute(m_Name, std::make_shared<ConstEmbeddedNamespaceValue>(operand));
|
||||
|
||||
return Empty;
|
||||
}
|
||||
|
||||
ExpressionResult ConditionalExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
|
||||
{
|
||||
ExpressionResult condition = m_Condition->Evaluate(frame, dhint);
|
||||
@ -701,7 +724,16 @@ bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value *
|
||||
|
||||
if (m_Operand1->GetReference(frame, init_dict, &vparent, &vindex, &psdhint)) {
|
||||
if (init_dict) {
|
||||
Value old_value = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_Operand1->GetDebugInfo());
|
||||
Value old_value;
|
||||
bool has_field = true;
|
||||
|
||||
if (vparent.IsObject()) {
|
||||
Object::Ptr oparent = vparent;
|
||||
has_field = oparent->HasOwnField(vindex);
|
||||
}
|
||||
|
||||
if (has_field)
|
||||
old_value = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_Operand1->GetDebugInfo());
|
||||
|
||||
if (old_value.IsEmpty() && !old_value.IsString())
|
||||
VMOps::SetField(vparent, vindex, new Dictionary(), m_OverrideFrozen, m_Operand1->GetDebugInfo());
|
||||
|
@ -637,6 +637,19 @@ private:
|
||||
friend void BindToScope(std::unique_ptr<Expression>& expr, ScopeSpecifier scopeSpec);
|
||||
};
|
||||
|
||||
class SetConstExpression final : public UnaryExpression
|
||||
{
|
||||
public:
|
||||
SetConstExpression(const String& name, std::unique_ptr<Expression> operand, const DebugInfo& debugInfo = DebugInfo())
|
||||
: UnaryExpression(std::move(operand), debugInfo), m_Name(name)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
String m_Name;
|
||||
|
||||
ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override;
|
||||
};
|
||||
|
||||
class SetExpression final : public BinaryExpression
|
||||
{
|
||||
public:
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "base/debuginfo.hpp"
|
||||
#include "base/array.hpp"
|
||||
#include "base/dictionary.hpp"
|
||||
#include "base/namespace.hpp"
|
||||
#include "base/function.hpp"
|
||||
#include "base/scriptglobal.hpp"
|
||||
#include "base/exception.hpp"
|
||||
@ -225,6 +226,26 @@ public:
|
||||
ExpressionResult res = expression->Evaluate(frame);
|
||||
CHECK_RESULT_LOOP(res);
|
||||
}
|
||||
} else if (value.IsObjectType<Namespace>()) {
|
||||
if (fvvar.IsEmpty())
|
||||
BOOST_THROW_EXCEPTION(ScriptError("Cannot use array iterator for namespace.", debugInfo));
|
||||
|
||||
Namespace::Ptr ns = value;
|
||||
std::vector<String> keys;
|
||||
|
||||
{
|
||||
ObjectLock olock(ns);
|
||||
for (const Namespace::Pair& kv : ns) {
|
||||
keys.push_back(kv.first);
|
||||
}
|
||||
}
|
||||
|
||||
for (const String& key : keys) {
|
||||
frame.Locals->Set(fkvar, key);
|
||||
frame.Locals->Set(fvvar, ns->Get(key));
|
||||
ExpressionResult res = expression->Evaluate(frame);
|
||||
CHECK_RESULT_LOOP(res);
|
||||
}
|
||||
} else
|
||||
BOOST_THROW_EXCEPTION(ScriptError("Invalid type in for expression: " + value.GetTypeName(), debugInfo));
|
||||
|
||||
|
@ -18,10 +18,8 @@
|
||||
******************************************************************************/
|
||||
|
||||
System.assert(Internal.run_with_activation_context(function() {
|
||||
var _Internal = Internal.clone()
|
||||
|
||||
template CheckCommand "ido-check-command" use (_Internal) {
|
||||
execute = _Internal.IdoCheck
|
||||
template CheckCommand "ido-check-command" use (checkFunc = Internal.IdoCheck) {
|
||||
execute = checkFunc
|
||||
}
|
||||
|
||||
object CheckCommand "ido" {
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, IdoCheck, &IdoCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, IdoCheck, &IdoCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
|
||||
void IdoCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
|
||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
|
||||
|
@ -268,13 +268,13 @@ std::pair<Dictionary::Ptr, Array::Ptr> CIB::GetFeatureStats()
|
||||
Dictionary::Ptr status = new Dictionary();
|
||||
Array::Ptr perfdata = new Array();
|
||||
|
||||
Dictionary::Ptr statsFunctions = ScriptGlobal::Get("StatsFunctions", &Empty);
|
||||
Namespace::Ptr statsFunctions = ScriptGlobal::Get("StatsFunctions", &Empty);
|
||||
|
||||
if (statsFunctions) {
|
||||
ObjectLock olock(statsFunctions);
|
||||
|
||||
for (const Dictionary::Pair& kv : statsFunctions)
|
||||
static_cast<Function::Ptr>(kv.second)->Invoke({ status, perfdata });
|
||||
for (const Namespace::Pair& kv : statsFunctions)
|
||||
static_cast<Function::Ptr>(kv.second->Get())->Invoke({ status, perfdata });
|
||||
}
|
||||
|
||||
return std::make_pair(status, perfdata);
|
||||
|
@ -18,10 +18,8 @@
|
||||
******************************************************************************/
|
||||
|
||||
System.assert(Internal.run_with_activation_context(function() {
|
||||
var _Internal = Internal.clone()
|
||||
|
||||
template TimePeriod "legacy-timeperiod" use (_Internal) default {
|
||||
update = _Internal.LegacyTimePeriod
|
||||
template TimePeriod "legacy-timeperiod" use (LegacyTimePeriod = Internal.LegacyTimePeriod) default {
|
||||
update = LegacyTimePeriod
|
||||
}
|
||||
}))
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, LegacyTimePeriod, &LegacyTimePeriod::ScriptFunc, "tp:begin:end");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, LegacyTimePeriod, &LegacyTimePeriod::ScriptFunc, "tp:begin:end");
|
||||
|
||||
bool LegacyTimePeriod::IsInTimeRange(tm *begin, tm *end, int stride, tm *reference)
|
||||
{
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, ClusterCheck, &ClusterCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, ClusterCheck, &ClusterCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
|
||||
void ClusterCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
|
||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, ClusterZoneCheck, &ClusterZoneCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, ClusterZoneCheck, &ClusterZoneCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
|
||||
void ClusterZoneCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
|
||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, DummyCheck, &DummyCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, DummyCheck, &DummyCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
|
||||
void DummyCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
|
||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, ExceptionCheck, &ExceptionCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, ExceptionCheck, &ExceptionCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
|
||||
void ExceptionCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
|
||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
|
||||
|
@ -34,7 +34,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, IcingaCheck, &IcingaCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, IcingaCheck, &IcingaCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
|
||||
void IcingaCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
|
||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
|
||||
|
@ -18,68 +18,58 @@
|
||||
******************************************************************************/
|
||||
|
||||
System.assert(Internal.run_with_activation_context(function() {
|
||||
var _Internal = Internal.clone()
|
||||
|
||||
template CheckCommand "icinga-check-command" use (_Internal) {
|
||||
execute = _Internal.IcingaCheck
|
||||
template CheckCommand "icinga-check-command" use (IcingaCheck = Internal.IcingaCheck) {
|
||||
execute = IcingaCheck
|
||||
|
||||
vars.icinga_min_version = ""
|
||||
}
|
||||
|
||||
template CheckCommand "cluster-check-command" use (_Internal) {
|
||||
execute = _Internal.ClusterCheck
|
||||
template CheckCommand "cluster-check-command" use (ClusterCheck = Internal.ClusterCheck) {
|
||||
execute = ClusterCheck
|
||||
}
|
||||
|
||||
template CheckCommand "cluster-zone-check-command" use (_Internal) {
|
||||
execute = _Internal.ClusterZoneCheck
|
||||
template CheckCommand "cluster-zone-check-command" use (ClusterZoneCheck = Internal.ClusterZoneCheck) {
|
||||
execute = ClusterZoneCheck
|
||||
}
|
||||
|
||||
template CheckCommand "plugin-check-command" use (_Internal) default {
|
||||
execute = _Internal.PluginCheck
|
||||
template CheckCommand "plugin-check-command" use (PluginCheck = Internal.PluginCheck) default {
|
||||
execute = PluginCheck
|
||||
}
|
||||
|
||||
template CheckCommand "clr-check-command" use (_Internal) {
|
||||
if (_Internal.ClrCheck) {
|
||||
execute = _Internal.ClrCheck
|
||||
} else {
|
||||
execute = _Internal.NullCheck
|
||||
}
|
||||
template NotificationCommand "plugin-notification-command" use (PluginNotification = Internal.PluginNotification) default {
|
||||
execute = PluginNotification
|
||||
}
|
||||
|
||||
template NotificationCommand "plugin-notification-command" use (_Internal) default {
|
||||
execute = _Internal.PluginNotification
|
||||
template EventCommand "plugin-event-command" use (PluginEvent = Internal.PluginEvent) default {
|
||||
execute = PluginEvent
|
||||
}
|
||||
|
||||
template EventCommand "plugin-event-command" use (_Internal) default {
|
||||
execute = _Internal.PluginEvent
|
||||
template CheckCommand "dummy-check-command" use (DummyCheck = Internal.DummyCheck) {
|
||||
execute = DummyCheck
|
||||
}
|
||||
|
||||
template CheckCommand "dummy-check-command" use (_Internal) {
|
||||
execute = _Internal.DummyCheck
|
||||
template CheckCommand "random-check-command" use (RandomCheck = Internal.RandomCheck) {
|
||||
execute = RandomCheck
|
||||
}
|
||||
|
||||
template CheckCommand "random-check-command" use (_Internal) {
|
||||
execute = _Internal.RandomCheck
|
||||
template CheckCommand "exception-check-command" use (ExceptionCheck = Internal.ExceptionCheck) {
|
||||
execute = ExceptionCheck
|
||||
}
|
||||
|
||||
template CheckCommand "exception-check-command" use (_Internal) {
|
||||
execute = _Internal.ExceptionCheck
|
||||
template CheckCommand "null-check-command" use (NullCheck = Internal.NullCheck) {
|
||||
execute = NullCheck
|
||||
}
|
||||
|
||||
template CheckCommand "null-check-command" use (_Internal) {
|
||||
execute = _Internal.NullCheck
|
||||
template EventCommand "null-event-command" use (NullEvent = Internal.NullEvent) {
|
||||
execute = NullEvent
|
||||
}
|
||||
|
||||
template EventCommand "null-event-command" use (_Internal) {
|
||||
execute = _Internal.NullEvent
|
||||
template TimePeriod "empty-timeperiod" use (EmptyTimePeriod = Internal.EmptyTimePeriod) {
|
||||
update = EmptyTimePeriod
|
||||
}
|
||||
|
||||
template TimePeriod "empty-timeperiod" use (_Internal) {
|
||||
update = _Internal.EmptyTimePeriod
|
||||
}
|
||||
|
||||
template TimePeriod "even-minutes-timeperiod" use (_Internal) {
|
||||
update = _Internal.EvenMinutesTimePeriod
|
||||
template TimePeriod "even-minutes-timeperiod" use (EvenMinutesTimePeriod = Internal.EvenMinutesTimePeriod) {
|
||||
update = EvenMinutesTimePeriod
|
||||
}
|
||||
}))
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, NullCheck, &NullCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, NullCheck, &NullCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
|
||||
void NullCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
|
||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, NullEvent, &NullEventTask::ScriptFunc, "checkable:resolvedMacros:useResolvedMacros");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, NullEvent, &NullEventTask::ScriptFunc, "checkable:resolvedMacros:useResolvedMacros");
|
||||
|
||||
void NullEventTask::ScriptFunc(const Checkable::Ptr& checkable, const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
|
||||
{
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, PluginCheck, &PluginCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, PluginCheck, &PluginCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
|
||||
void PluginCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
|
||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, PluginEvent, &PluginEventTask::ScriptFunc, "checkable:resolvedMacros:useResolvedMacros");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, PluginEvent, &PluginEventTask::ScriptFunc, "checkable:resolvedMacros:useResolvedMacros");
|
||||
|
||||
void PluginEventTask::ScriptFunc(const Checkable::Ptr& checkable,
|
||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, PluginNotification, &PluginNotificationTask::ScriptFunc, "notification:user:cr:itype:author:comment:resolvedMacros:useResolvedMacros");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, PluginNotification, &PluginNotificationTask::ScriptFunc, "notification:user:cr:itype:author:comment:resolvedMacros:useResolvedMacros");
|
||||
|
||||
void PluginNotificationTask::ScriptFunc(const Notification::Ptr& notification,
|
||||
const User::Ptr& user, const CheckResult::Ptr& cr, int itype,
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, RandomCheck, &RandomCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, RandomCheck, &RandomCheckTask::ScriptFunc, "checkable:cr:resolvedMacros:useResolvedMacros");
|
||||
|
||||
void RandomCheckTask::ScriptFunc(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr,
|
||||
const Dictionary::Ptr& resolvedMacros, bool useResolvedMacros)
|
||||
|
@ -22,8 +22,8 @@
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
REGISTER_FUNCTION(Internal, EmptyTimePeriod, &TimePeriodTask::EmptyTimePeriodUpdate, "tp:begin:end");
|
||||
REGISTER_FUNCTION(Internal, EvenMinutesTimePeriod, &TimePeriodTask::EvenMinutesTimePeriodUpdate, "tp:begin:end");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, EmptyTimePeriod, &TimePeriodTask::EmptyTimePeriodUpdate, "tp:begin:end");
|
||||
REGISTER_FUNCTION_NONCONST(Internal, EvenMinutesTimePeriod, &TimePeriodTask::EvenMinutesTimePeriodUpdate, "tp:begin:end");
|
||||
|
||||
Array::Ptr TimePeriodTask::EmptyTimePeriodUpdate(const TimePeriod::Ptr& tp, double, double)
|
||||
{
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "base/logger.hpp"
|
||||
#include "base/serializer.hpp"
|
||||
#include "base/timer.hpp"
|
||||
#include "base/namespace.hpp"
|
||||
#include "base/initialize.hpp"
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <set>
|
||||
@ -233,6 +234,15 @@ static void AddSuggestions(std::vector<String>& matches, const String& word, con
|
||||
}
|
||||
}
|
||||
|
||||
if (value.IsObjectType<Namespace>()) {
|
||||
Namespace::Ptr ns = value;
|
||||
|
||||
ObjectLock olock(ns);
|
||||
for (const Namespace::Pair& kv : ns) {
|
||||
AddSuggestion(matches, word, prefix + kv.first);
|
||||
}
|
||||
}
|
||||
|
||||
if (withFields) {
|
||||
Type::Ptr type = value.GetReflectionType();
|
||||
|
||||
@ -275,7 +285,7 @@ std::vector<String> ConsoleHandler::GetAutocompletionSuggestions(const String& w
|
||||
|
||||
{
|
||||
ObjectLock olock(ScriptGlobal::GetGlobals());
|
||||
for (const Dictionary::Pair& kv : ScriptGlobal::GetGlobals()) {
|
||||
for (const Namespace::Pair& kv : ScriptGlobal::GetGlobals()) {
|
||||
AddSuggestion(matches, word, kv.first);
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ static bool GetDebugJsonRpcCached()
|
||||
|
||||
debugJsonRpc = false;
|
||||
|
||||
Dictionary::Ptr internal = ScriptGlobal::Get("Internal", &Empty);
|
||||
Namespace::Ptr internal = ScriptGlobal::Get("Internal", &Empty);
|
||||
|
||||
if (!internal)
|
||||
return false;
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "remote/filterutility.hpp"
|
||||
#include "base/serializer.hpp"
|
||||
#include "base/statsfunction.hpp"
|
||||
#include "base/namespace.hpp"
|
||||
|
||||
using namespace icinga;
|
||||
|
||||
@ -35,24 +36,29 @@ public:
|
||||
void FindTargets(const String& type,
|
||||
const std::function<void (const Value&)>& addTarget) const override
|
||||
{
|
||||
Dictionary::Ptr statsFunctions = ScriptGlobal::Get("StatsFunctions", &Empty);
|
||||
Namespace::Ptr statsFunctions = ScriptGlobal::Get("StatsFunctions", &Empty);
|
||||
|
||||
if (statsFunctions) {
|
||||
ObjectLock olock(statsFunctions);
|
||||
|
||||
for (const Dictionary::Pair& kv : statsFunctions)
|
||||
for (const Namespace::Pair& kv : statsFunctions)
|
||||
addTarget(GetTargetByName("Status", kv.first));
|
||||
}
|
||||
}
|
||||
|
||||
Value GetTargetByName(const String& type, const String& name) const override
|
||||
{
|
||||
Dictionary::Ptr statsFunctions = ScriptGlobal::Get("StatsFunctions", &Empty);
|
||||
Namespace::Ptr statsFunctions = ScriptGlobal::Get("StatsFunctions", &Empty);
|
||||
|
||||
if (!statsFunctions)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("No status functions are available."));
|
||||
|
||||
Function::Ptr func = statsFunctions->Get(name);
|
||||
Value vfunc;
|
||||
|
||||
if (!statsFunctions->Get(name, &vfunc))
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid status function name."));
|
||||
|
||||
Function::Ptr func = vfunc;
|
||||
|
||||
if (!func)
|
||||
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid status function name."));
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "base/scriptglobal.hpp"
|
||||
#include "base/logger.hpp"
|
||||
#include "base/serializer.hpp"
|
||||
#include "base/namespace.hpp"
|
||||
#include <set>
|
||||
|
||||
using namespace icinga;
|
||||
@ -48,10 +49,10 @@ public:
|
||||
const std::function<void (const Value&)>& addTarget) const override
|
||||
{
|
||||
{
|
||||
Dictionary::Ptr globals = ScriptGlobal::GetGlobals();
|
||||
Namespace::Ptr globals = ScriptGlobal::GetGlobals();
|
||||
ObjectLock olock(globals);
|
||||
for (const Dictionary::Pair& kv : globals) {
|
||||
addTarget(GetTargetForVar(kv.first, kv.second));
|
||||
for (const Namespace::Pair& kv : globals) {
|
||||
addTarget(GetTargetForVar(kv.first, kv.second->Get()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user